分类:
2013-01-06 11:36:56
原文地址:ARMv7 linux的启动过程 作者:stanleymiao
VMLINUX
arch/arm/kernel/head.S
59 /*
60 * Kernel startup entry point.
61 * ---------------------------
62 *
63 * This is normally called from the decompressor code. The requirements
64 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
65 * r1 = machine nr, r2 = atags pointer.
66 *
67 * This code is mostly position independent, so if you link the kernel at
68 * 0xc0008000, you call this at __pa(0xc0008000).
69 *
70 * See linux/arch/arm/tools/mach-types for the complete list of machine
71 * numbers for r1.
72 *
73 * We're trying to keep crap to a minimum; DO NOT add any machine specific
74 * crap here - that's what the boot loader (or in extreme, well justified
75 * circumstances, zImage) is for.
76 */
77 __HEAD
78 ENTRY(stext)
79 setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
80 @ and irqs disabled
arch/arm/include/asm/assembler.h
170 #ifdef CONFIG_THUMB2_KERNEL
171 .macro setmode, mode, reg
172 mov \reg, #\mode
173 msr cpsr_c, \reg
174 .endm
175 #else
176 .macro setmode, mode, reg
177 msr cpsr_c, #\mode
178 .endm
179 #endif
81 mrc p15, 0, r9, c0, c0 @ get processor id
82 bl __lookup_processor_type @ r5=procinfo r9=cpuid
arch/arm/kernel/head-common.S
147 /*
148 * Read processor ID register (CP#15, CR0), and look up in the linker-built
149 * supported processor list. Note that we can't use the absolute addresses
150 * for the __proc_info lists since we aren't running with the MMU on
151 * (and therefore, we are not in the correct address space). We have to
152 * calculate the offset.
153 *
154 * r9 = cpuid
155 * Returns:
156 * r3, r4, r6 corrupted
157 * r5 = proc_info pointer in physical address space
158 * r9 = cpuid (preserved)
159 */
160 __lookup_processor_type:
161 adr r3, 3f
162 ldmia r3, {r5 - r7}
163 add r3, r3, #8
164 sub r3, r3, r7 @ get offset between virt&phys
165 add r5, r5, r3 @ convert virt addresses to
166 add r6, r6, r3 @ physical address space
167 1: ldmia r5, {r3, r4} @ value, mask
168 and r4, r4, r9 @ mask wanted bits
169 teq r3, r4
170 beq 2f
171 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
172 cmp r5, r6
173 blo 1b
174 mov r5, #0 @ unknown processor
175 2: mov pc, lr
176 ENDPROC(__lookup_processor_type)
189 /*
190
* Look in
191 * more information about the __proc_info and __arch_info structures.
192 */
193 .align 2
194 3: .long __proc_info_begin
195 .long __proc_info_end
196 4: .long .
arch/arm/kernel/vmlinux.lds.S
38 __proc_info_begin = .;
39 *(.proc.info.init)
40 __proc_info_end = .;
arch/arm/mm/proc-v7.S
327 .section ".proc.info.init", #alloc, #execinstr
328
329 /*
330 * Match any ARMv7 processor core.
331 */
332 .type __v7_proc_info, #object
333 __v7_proc_info:
334 .long 0x000f0000 @ Required ID value
335 .long 0x000f0000 @ Mask for ID
336 .long PMD_TYPE_SECT | \
337 PMD_SECT_AP_WRITE | \
338 PMD_SECT_AP_READ | \
339 PMD_FLAGS
340 .long PMD_TYPE_SECT | \
341 PMD_SECT_XN | \
342 PMD_SECT_AP_WRITE | \
343 PMD_SECT_AP_READ
344 b __v7_setup
345 .long cpu_arch_name
346 .long cpu_elf_name
347 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
348 .long cpu_v7_name
349 .long v7_processor_functions
350 .long v7wbi_tlb_fns
351 .long v6_user_fns
352 .long v7_cache_fns
353 .size __v7_proc_info, . - __v7_proc_info
arch/arm/include/asm/procinfo.h
29 struct proc_info_list {
30 unsigned int cpu_val;
31 unsigned int cpu_mask;
32 unsigned long __cpu_mm_mmu_flags; /* used by head.S */
33 unsigned long __cpu_io_mmu_flags; /* used by head.S */
34 unsigned long __cpu_flush; /* used by head.S */
35 const char *arch_name;
36 const char *elf_name;
37 unsigned int elf_hwcap;
38 const char *cpu_name;
39 struct processor *proc;
40 struct cpu_tlb_fns *tlb;
41 struct cpu_user_fns *user;
42 struct cpu_cache_fns *cache;
43 };
83 movs r10, r5 @ invalid processor (r5=0)?
84 beq __error_p @ yes, error 'p'
85 bl __lookup_machine_type @ r5=machinfo
arch/arm/kernel/head-common.S
196 4: .long .
197 .long __arch_info_begin
198 .long __arch_info_end
arch/arm/kernel/vmlinux.lds.S
41 __arch_info_begin = .;
42 *(.arch.info.init)
43 __arch_info_end = .;
arch/arm/include/asm/mach/arch.h
17 struct machine_desc {
18 /*
19 * Note! The first four elements are used
20 * by assembler code in head.S, head-common.S
21 */
22 unsigned int nr; /* architecture number */
23 unsigned int phys_io; /* start of physical io */
24 unsigned int io_pg_offst; /* byte offset for io
25 * page tabe entry */
26
27 const char *name; /* architecture name */
28 unsigned long boot_params; /* tagged list */
29
30 unsigned int video_start; /* start of video RAM */
31 unsigned int video_end; /* end of video RAM */
32
33 unsigned int reserve_lp0 :1; /* never has lp0 */
34 unsigned int reserve_lp1 :1; /* never has lp1 */
35 unsigned int reserve_lp2 :1; /* never has lp2 */
36 unsigned int soft_reboot :1; /* soft reboot */
37 void (*fixup)(struct machine_desc *,
38 struct tag *, char **,
39 struct meminfo *);
40 void (*map_io)(void);/* IO mapping function */
41 void (*init_irq)(void);
42 struct sys_timer *timer; /* system tick timer */
43 void (*init_machine)(void);
44 };
45
46 /*
47 * Set of macros to define architecture features. This is built into
48 * a table by the linker.
49 */
50 #define MACHINE_START(_type,_name) \
51 static const struct machine_desc __mach_desc_##_type \
52 __used \
53 __attribute__((__section__(".arch.info.init"))) = { \
54 .nr = MACH_TYPE_##_type, \
55 .name = _name,
56
57 #define MACHINE_END
58 };
arch/arm/include/asm/assembler.h
749 MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
750 .phys_io = 0x48000000,
751 .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
752 .boot_params = 0x80000100,
753 .map_io = am3517_evm_map_io,
754 .init_irq = am3517_evm_init_irq,
755 .init_machine = am3517_evm_init,
756 .timer = &omap_timer,
757 MACHINE_END
200 /*
201 * Lookup machine architecture in the linker-build list of architectures.
202 * Note that we can't use the absolute addresses for the __arch_info
203 * lists since we aren't running with the MMU on (and therefore, we are
204 * not in the correct address space). We have to calculate the offset.
205 *
206 * r1 = machine architecture number
207 * Returns:
208 * r3, r4, r6 corrupted
209 * r5 = mach_info pointer in physical address space
210 */
211 __lookup_machine_type:
212 adr r3, 4b
213 ldmia r3, {r4, r5, r6}
214 sub r3, r3, r4 @ get offset between virt&phys
215 add r5, r5, r3 @ convert virt addresses to
216 add r6, r6, r3 @ physical address space
217 1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
arch/arm/kernel/asm-offsets.c
99 DEFINE(SIZEOF_MACHINE_DESC, sizeof(struct machine_desc));
100 DEFINE(MACHINFO_TYPE, offsetof(struct machine_desc, nr));
101 DEFINE(MACHINFO_NAME, offsetof(struct machine_desc, name));
218 teq r3, r1 @ matches loader number?
219 beq 2f @ found
220 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
221 cmp r5, r6
222 blo 1b
223 mov r5, #0 @ unknown machine
224 2: mov pc, lr
225 ENDPROC(__lookup_machine_type)
86 movs r8, r5 @ invalid machine (r5=0)?
87 beq __error_a @ yes, error 'a'
88 bl __vet_atags
89 bl __create_page_tables
arch/arm/kernel/head.S
206 /*
207 * Setup the initial page tables. We only setup the barest
208 * amount which are required to get the kernel running, which
209 * generally means mapping in the kernel code.
210 *
211 * r8 = machinfo
212 * r9 = cpuid
213 * r10 = procinfo
214 *
215 * Returns:
216 * r0, r3, r6, r7 corrupted
217 * r4 = physical page table address
218 */
219 __create_page_tables:
220 pgtbl r4 @ page table address
arch/arm/kernel/head.S
33 /*
34 * swapper_pg_dir is the virtual address of the initial page table.
35 * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must
36 * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect
37 * the least significant 16 bits to be 0x8000, but we could probably
38 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
39 */
40 #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
41 #error KERNEL_RAM_VADDR must start at 0xXXXX8000
42 #endif
43
44 .globl swapper_pg_dir
45 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
46
47 .macro pgtbl, rd
48 ldr \rd, =(KERNEL_RAM_PADDR - 0x4000)
49 .endm
29 #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
30 #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
arch/arm/plat-omap/include/plat/memory.h
36 /*
37 * Physical DRAM offset.
38 */
39 #if defined(CONFIG_ARCH_OMAP1)
40 #define PHYS_OFFSET UL(0x10000000)
41 #else
42 #define PHYS_OFFSET UL(0x80000000)
43 #endif
arch/arm/Makefile
204 # The byte offset of the kernel image in RAM from the start of RAM.
205 TEXT_OFFSET := $(textofs-y)
112 textofs-y := 0x00008000
222 /*
223 * Clear the 16K level 1 swapper page table
224 */
225 mov r0, r4
226 mov r3, #0
227 add r6, r0, #0x4000
228 1: str r3, [r0], #4
229 str r3, [r0], #4
230 str r3, [r0], #4
231 str r3, [r0], #4
232 teq r0, r6
233 bne 1b
234
235 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
236
237 /*
238 * Create identity mapping for first MB of kernel to
239 * cater for the MMU enable. This identity mapping
240 * will be removed by paging_init(). We use our current program
241 * counter to determine corresponding section base address.
242 */
243 mov r6, pc
244 mov r6, r6, lsr #20 @ start of kernel section
245 orr r3, r7, r6, lsl #20 @ flags + kernel base
246 str r3, [r4, r6, lsl #2] @ identity mapping
247
248 /*
249 * Now setup the pagetables for our kernel direct
250 * mapped region.
251 */
252 add r0, r4, #(KERNEL_START & 0xff000000) >> 18
253 str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
55 #define KERNEL_START KERNEL_RAM_VADDR
56 #define KERNEL_END _end
254 ldr r6, =(KERNEL_END - 1)
255 add r0, r0, #4
256 add r6, r4, r6, lsr #18
257 1: cmp r0, r6
258 add r3, r3, #1 << 20
259 strls r3, [r0], #4
260 bls 1b
281 /*
282 * Then map first 1MB of ram in case it contains our boot params.
283 */
284 add r0, r4, #PAGE_OFFSET >> 18
285 orr r6, r7, #(PHYS_OFFSET & 0xff000000)
286 .if (PHYS_OFFSET & 0x00f00000)
287 orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
288 .endif
289 str r6, [r0]
334 mov pc, lr
335 ENDPROC(__create_page_tables)
91 /*
92 * The following calls CPU specific code in a position independent
93 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of
94 * xxx_proc_info structure selected by __lookup_machine_type
95 * above. On return, the CPU will be ready for the MMU to be
96 * turned on, and r0 will hold the CPU control register value.
97 */
98 ldr r13, __switch_data @ address to jump to after
99 @ mmu has been enabled
100 adr lr, BSYM(__enable_mmu) @ return (PIC) address
101 ARM( add pc, r10, #PROCINFO_INITFUNC )
arch/arm/kernel/asm-offsets.c
106 DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush));
102 THUMB( add r12, r10, #PROCINFO_INITFUNC )
103 THUMB( mov pc, r12 )
104 ENDPROC(stext)
First, PROCINFO_INITFUNC will be called. Take ARMV7 as an example.
arch/arm/mm/proc-v7.S
177 /*
178 * __v7_setup
179 *
180 * Initialise TLB, Caches, and MMU state ready to switch the MMU
181 * on. Return in r0 the new CP15 C1 control register setting.
182 *
183 * We automatically detect if we have a Harvard cache, and use the
184 * Harvard cache control instructions insead of the unified cache
185 * control instructions.
186 *
187 * This should be able to cover all ARMv7 cores.
188 *
189 * It is assumed that:
190 * - cache type register is implemented
191 */
192 __v7_setup:
193 #ifdef CONFIG_SMP
194 mrc p15, 0, r0, c1, c0, 1
195 tst r0, #(1 << 6) @ SMP/nAMP mode enabled?
196 orreq r0, r0, #(1 << 6) | (1 << 0) @ Enable SMP/nAMP mode and
197 mcreq p15, 0, r0, c1, c0, 1 @ TLB ops broadcasting
198 #endif
199 adr r12, __v7_setup_stack @ the local stack
300 __v7_setup_stack:
301 .space 4 * 11 @ 11 registers
200 stmia r12, {r0-r5, r7, r9, r11, lr}
201 bl v7_flush_dcache_all
arch/arm/mm/cache-v7.S
20 /*
21 * v7_flush_dcache_all()
22 *
23 * Flush the whole D-cache.
24 *
25 * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
26 *
27 * - mm - mm_struct describing address space
28 */
29 ENTRY(v7_flush_dcache_all)
30 dmb @ ensure ordering with previous memory accesses
31 mrc p15, 1, r0, c0, c0, 1 @ read clidr
The Cache Level ID Register, which is introduced in ARMv7, identifies the type of cache, or caches, implemented at each level, up to a maximum of eight levels, and the Level of Coherency and Level of Unification for the cache hierarchy. See page B3-92 in armv7_arm.
32 ands r3, r0, #0x7000000 @ extract loc from clidr
LoC, bits [26:24], Level of Coherency for the cache hierarchy, see Clean, Invalidate, and Clean and Invalidate on page B2-11 in armv7_arm.
33 mov r3, r3, lsr #23 @ left align loc bit field
34 beq finished @ if loc is 0, then no need to clean
35 mov r10, #0 @ start clean at cache level 0
36 loop1:
37 add r2, r10, r10, lsr #1 @ work out 3x current cache level
38 mov r1, r0, lsr r2 @ extract cache type bits from clidr
39 and r1, r1, #7 @ mask of the bits for current cache only
40 cmp r1, #2 @ see what cache we have at this level
CtypeX value | Meaning, cache implemented at this level
000 No cache
001 Instruction cache only
010 Data cache only
011 Separate instruction and data caches
100 Unified cache
101, 11X Reserved
41 blt skip @ skip if no cache, or just i-cache
42 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
Cache Size Selection Register, CSSELR. See page B3-95 in armv7_arm.
43 isb @ isb to sych the new cssr&csidr
An ISB instruction flushes the pipeline in the processor, so that all instructions that come after the ISB instruction in program order are fetched from cache or memory only after the ISB instruction has completed. Using an ISB ensures that the effects of context altering operations executed before the ISB are visible to the instructions fetched after the ISB instruction. See A3-49 in armv7_arm
44 mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
The Cache Size ID Registers, CCSIDR, provide information about the architecture of the caches. See page B3-91 in armv7_arm.
45 and r2, r1, #7 @ extract the length of the cache lines
LineSize, bits [2:0], (Log2(Number of words in cache line)) -2. For example:
• For a line length of 4 words: Log2(4) = 2, LineSize entry = 0. This is the minimum line length.
• For a line length of 8 words: Log2(8) = 3, LineSize entry = 1.
46 add r2, r2, #4 @ add 4 (line length offset)
47 ldr r4, =0x3ff
48 ands r4, r4, r1, lsr #3 @ find maximum number on the way size
Associativity, bits [12:3], (Associativity of cache) - 1, therefore a value of 0 indicates an associativity of 1. The associativity does not have to be a power of 2.
49 clz r5, r4 @ find bit position of way size increment
Count Leading Zeros returns the number of binary zero bits before the first binary one bit in a value. See page A8-72 in armv7_arm.
50 ldr r7, =0x7fff
51 ands r7, r7, r1, lsr #13 @ extract max number of the index size
NumSets, bits [27:13], (Number of sets in cache) - 1, therefore a value of 0 indicates 1 set in the cache. The number of sets does not have to be a power of 2.
52 loop2:
53 mov r9, r4 @ create working copy of max way size
54 loop3:
55 ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11
r10, the cache level. From 0 to 7.
r9, Associativity of cache.
r5, The number of binary zero bits before the first binary one bit in r9.
56 THUMB( lsl r6, r9, r5 )
57 THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
58 ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11
r7, Number of sets in cache.
r2, Log2(Number of words in cache line)
r11, Associativity of cache & the cache level
59 THUMB( lsl r6, r7, r2 )
60 THUMB( orr r11, r11, r6 ) @ factor index number into r11
61 mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
62 subs r9, r9, #1 @ decrement the way
63 bge loop3
64 subs r7, r7, #1 @ decrement the index
65 bge loop2
66 skip:
67 add r10, r10, #2 @ increment cache number
68 cmp r3, r10
69 bgt loop1
70 finished:
71 mov r10, #0 @ swith back to cache level 0
72 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
73 dsb
74 isb
75 mov pc, lr
76 ENDPROC(v7_flush_dcache_all)
202 ldmia r12, {r0-r5, r7, r9, r11, lr}
203
204 mrc p15, 0, r0, c0, c0, 0 @ read main ID register
The Main ID Register, MIDR, provides identification information for the processor, including an implementer code for the device and a device ID number. See page B3-81 in armv7_arm.
205 and r10, r0, #0xff000000 @ ARM?
206 teq r10, #0x41000000
Bits [31:24] ASCII character Implementer
0x41 A ARM Limited
0x44 D Digital Equipment Corporation
0x4D M Motorola, Freescale Semiconductor Inc.
0x51 Q QUALCOMM Inc.
0x56 V Marvell Semiconductor Inc.
0x69 i Intel Corporation
207 bne 2f
208 and r5, r0, #0x00f00000 @ variant
Bits [23:20] Major revision number
209 and r6, r0, #0x0000000f @ revision
Bits [3:0] Minor revision number,
210 orr r0, r6, r5, lsr #20-4 @ combine variant and revision
233 2: mov r10, #0
234 #ifdef HARVARD_CACHE
235 mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
236 #endif
237 dsb
Data Synchronization Barrier. See page A3-49 in armv7_arm.
238 #ifdef CONFIG_MMU
239 mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs
240 mcr p15, 0, r10, c2, c0, 2 @ TTB control register
241 orr r4, r4, #TTB_FLAGS
r4 is page table address.
arch/arm/mm/proc-v7.S
33 #ifndef CONFIG_SMP
34 /* PTWs cacheable, inner WB not shareable, outer WB not shareable */
35 #define TTB_FLAGS TTB_IRGN_WB|TTB_RGN_OC_WB
36 #define PMD_FLAGS PMD_SECT_WB
37 #else
38 /* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
39 #define TTB_FLAGS TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
40 #define PMD_FLAGS PMD_SECT_WBWA|PMD_SECT_S
41 #endif
242 mcr p15, 0, r4, c2, c0, 1 @ load TTB1
Translation Table Base Register 1. See page B3-116 in armv7_arm.
243 mov r10, #0x1f @ domains 0, 1 = manager
244 mcr p15, 0, r10, c3, c0, 0 @ load domain access register
The Domain Access Control Register, DACR, defines the access permission for each of the sixteen memory domains. See page B3-119 in armv7_arm.
245 /*
246 * Memory region attributes with SCTLR.TRE=1
247 *
248 * n = TEX[0],C,B
249 * TR = PRRR[2n+1:2n] - memory type
250 * IR = NMRR[2n+1:2n] - inner cacheable property
251 * OR = NMRR[2n+17:2n+16] - outer cacheable property
252 *
253 * n TR IR OR
254 * UNCACHED 000 00
255 * BUFFERABLE 001 10 00 00
256 * WRITETHROUGH 010 10 10 10
257 * WRITEBACK 011 10 11 11
258 * reserved 110
259 * WRITEALLOC 111 10 01 01
260 * DEV_SHARED 100 01
261 * DEV_NONSHARED 100 01
262 * DEV_WC 001 10
263 * DEV_CACHED 011 10
264 *
265 * Other attributes:
266 *
267 * DS0 = PRRR[16] = 0 - device shareable property
268 * DS1 = PRRR[17] = 1 - device shareable property
269 * NS0 = PRRR[18] = 0 - normal shareable property
270 * NS1 = PRRR[19] = 1 - normal shareable property
271 * NOS = PRRR[24+n] = 1 - not outer shareable
272 */
273 ldr r5, =0xff0a81a8 @ PRRR
274 ldr r6, =0x40e040e0 @ NMRR
275 mcr p15, 0, r5, c10, c2, 0 @ write PRRR
276 mcr p15, 0, r6, c10, c2, 1 @ write NMRR
277 #endif
278 adr r5, v7_crval
290 /* AT
291 * TFR EV X F I D LR S
292 * .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM
293 * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced
294 * 1 0 110 0011 1100 .111 1101 < we want
295 */
296 .type v7_crval, #object
297 v7_crval:
298 crval clear=0x0120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c
279 ldmia r5, {r5, r6}
280 #ifdef CONFIG_CPU_ENDIAN_BE8
281 orr r6, r6, #1 << 25 @ big-endian page tables
282 #endif
EE, bit [25] Exception Endianness bit
283 mrc p15, 0, r0, c1, c0, 0 @ read control register
System Control Register, See page B3-96 in armv7_arm.
284 bic r0, r0, r5 @ clear bits them
285 orr r0, r0, r6 @ set them
286 THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions
287 mov pc, lr @ return to head.S:__ret
288 ENDPROC(__v7_setup)
__enable_mmu was stored in the register lr.
arch/arm/kernel/head.S
155 /*
156 * Setup common bits before finally enabling the MMU. Essentially
157 * this is just loading the page table pointer and domain access
158 * registers.
159 */
160 __enable_mmu:
161 #ifdef CONFIG_ALIGNMENT_TRAP
162 orr r0, r0, #CR_A
163 #else
164 bic r0, r0, #CR_A
165 #endif
166 #ifdef CONFIG_CPU_DCACHE_DISABLE
167 bic r0, r0, #CR_C
168 #endif
Cache enable bit: This is a global enable bit for data and unified caches.
169 #ifdef CONFIG_CPU_BPREDICT_DISABLE
170 bic r0, r0, #CR_Z
171 #endif
Branch prediction enable bit.
172 #ifdef CONFIG_CPU_ICACHE_DISABLE
173 bic r0, r0, #CR_I
174 #endif
Instruction cache enable bit: This is a global enable bit for instruction caches.
175 mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
176 domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
177 domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
178 domain_val(DOMAIN_IO, DOMAIN_CLIENT))
arch/arm/include/asm/domain.h
13 /*
14 * Domain numbers
15 *
16 * DOMAIN_IO - domain 2 includes all IO only
17 * DOMAIN_USER - domain 1 includes all user memory only
18 * DOMAIN_KERNEL - domain 0 includes all kernel memory only
19 *
20 * The domain numbering depends on whether we support 36 physical
21 * address for I/O or not. Addresses above the 32 bit boundary can
22 * only be mapped using supersections and supersections can only
23 * be set for domain 0. We could just default to DOMAIN_IO as zero,
24 * but there may be systems with supersection support and no 36-bit
25 * addressing. In such cases, we want to map system memory with
26 * supersections to reduce TLB misses and footprint.
27 *
28 * 36-bit addressing and supersections are only available on
29 * CPUs based on ARMv6+ or the Intel XSC3 core.
30 */
31 #ifndef CONFIG_IO_36
32 #define DOMAIN_KERNEL 0
33 #define DOMAIN_TABLE 0
34 #define DOMAIN_USER 1
35 #define DOMAIN_IO 2
36 #else
37 #define DOMAIN_KERNEL 2
38 #define DOMAIN_TABLE 2
39 #define DOMAIN_USER 1
40 #define DOMAIN_IO 0
41 #endif
42
43 /*
44 * Domain types
45 */
46 #define DOMAIN_NOACCESS 0
47 #define DOMAIN_CLIENT 1
48 #define DOMAIN_MANAGER 3
49
50 #define domain_val(dom,type) ((type) << (2*(dom)))
179 mcr p15, 0, r5, c3, c0, 0 @ load domain access register
180 mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
Translation Table Base Register 0. See page B3-113 in armv7_arm.
181 b __turn_mmu_on
182 ENDPROC(__enable_mmu)
183
184 /*
185 * Enable the MMU. This completely changes the structure of the visible
186 * memory space. You will not be able to trace execution through this.
187 * If you have an enquiry about this, *please* check the linux-arm-kernel
188 * mailing list archives BEFORE sending another post to the list.
189 *
190 * r0 = cp#15 control register
191 * r13 = *virtual* address to jump to upon completion
192 *
193 * other registers depend on the function called upon completion
194 */
195 .align 5
196 __turn_mmu_on:
197 mov r0, r0
198 mcr p15, 0, r0, c1, c0, 0 @ write control reg
199 mrc p15, 0, r3, c0, c0, 0 @ read id reg
200 mov r3, r3
201 mov r3, r13
202 mov pc, r3
203 ENDPROC(__turn_mmu_on)
__switch_data was stored in the register r13.
arch/arm/kernel/head-common.S
18 .align 2
19 .type __switch_data, %object
20 __switch_data:
21 .long __mmap_switched
22 .long __data_loc @ r4
23 .long _data @ r5
24 .long __bss_start @ r6
25 .long _end @ r7
26 .long processor_id @ r4
27 .long __machine_arch_type @ r5
28 .long __atags_pointer @ r6
29 .long cr_alignment @ r7
30 .long init_thread_union + THREAD_START_SP @ sp
arch/arm/kernel/init_task.c
17 /*
18 * Initial thread structure.
19 *
20 * We need to make sure that this is 8192-byte aligned due to the
21 * way process stacks are handled. This is done by making sure
22 * the linker maps this in the .text segment right after head.S,
23 * and making head.S ensure the proper alignment.
24 *
25 * The things we do for performance..
26 */
27 union thread_union init_thread_union __init_task_data =
28 { INIT_THREAD_INFO(init_task) };
We created the first thread manually!
arch/arm/include/asm/thread_info.h
71 #define INIT_THREAD_INFO(tsk) \
72 { \
73 .task = &tsk, \
74 .exec_domain = &default_exec_domain, \
75 .flags = 0, \
76 .preempt_count = INIT_PREEMPT_COUNT, \
77 .addr_limit = KERNEL_DS, \
78 .cpu_domain = domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
79 domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
80 domain_val(DOMAIN_IO, DOMAIN_CLIENT), \
81 .restart_block = { \
82 .fn = do_no_restart_syscall, \
83 }, \
84 }
include/linux/init_task.h
106 /*
107 * INIT_TASK is used to set up the first task table, touch at
108 * your own risk!. Base=0, limit=0x1fffff (=2MB)
109 */
110 #define INIT_TASK(tsk) \
111 { \
112 .state = 0, \
113 .stack = &init_thread_info, \
114 .usage = ATOMIC_INIT(2), \
115 .flags = PF_KTHREAD, \
116 .lock_depth = -1, \
117 .prio = MAX_PRIO-20, \
118 .static_prio = MAX_PRIO-20, \
119 .normal_prio = MAX_PRIO-20, \
120 .policy = SCHED_NORMAL, \
121 .cpus_allowed = CPU_MASK_ALL, \
122 .mm = NULL, \
123 .active_mm = &init_mm, \
124 .se = { \
125 .group_node = LIST_HEAD_INIT(tsk.se.group_node), \
126 }, \
127 .rt = { \
128 .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \
129 .time_slice = HZ, \
130 .nr_cpus_allowed = NR_CPUS, \
131 }, \
132 .tasks = LIST_HEAD_INIT(tsk.tasks), \
133 .pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO), \
134 .ptraced = LIST_HEAD_INIT(tsk.ptraced), \
135 .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \
136 .real_parent = &tsk, \
137 .parent = &tsk, \
138 .children = LIST_HEAD_INIT(tsk.children), \
139 .sibling = LIST_HEAD_INIT(tsk.sibling), \
140 .group_leader = &tsk, \
141 .real_cred = &init_cred, \
142 .cred = &init_cred, \
143 .cred_guard_mutex = \
144 __MUTEX_INITIALIZER(tsk.cred_guard_mutex), \
145 .comm = "swapper", \
146 .thread = INIT_THREAD, \
147 .fs = &init_fs, \
148 .files = &init_files, \
149 .signal = &init_signals, \
150 .sighand = &init_sighand, \
151 .nsproxy = &init_nsproxy, \
152 .pending = { \
153 .list = LIST_HEAD_INIT(tsk.pending.list), \
154 .signal = {{0}}}, \
155 .blocked = {{0}}, \
156 .alloc_lock = __SPIN_LOCK_UNLOCKED(tsk.alloc_lock), \
157 .journal_info = NULL, \
158 .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
159 .fs_excl = ATOMIC_INIT(0), \
160 .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \
161 .timer_slack_ns = 50000, /* 50 usec default slack */ \
162 .pids = { \
163 [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \
164 [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \
165 [PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID), \
166 }, \
167 .dirties = INIT_PROP_LOCAL_SINGLE(dirties), \
168 INIT_IDS \
169 INIT_PERF_EVENTS(tsk) \
170 INIT_TRACE_IRQFLAGS \
171 INIT_LOCKDEP \
172 INIT_FTRACE_GRAPH \
173 INIT_TRACE_RECURSION \
174 INIT_TASK_RCU_PREEMPT(tsk) \
175 }
31
32 /*
33 * The following fragment of code is executed with the MMU on in MMU mode,
34 * and uses absolute addresses; this is not position independent.
35 *
36 * r0 = cp#15 control register
37 * r1 = machine ID
38 * r2 = atags pointer
39 * r9 = processor ID
40 */
41 __mmap_switched:
42 adr r3, __switch_data + 4
43
44 ldmia r3!, {r4, r5, r6, r7}
45 cmp r4, r5 @ Copy data segment if needed
46 1: cmpne r5, r6
47 ldrne fp, [r4], #4
48 strne fp, [r5], #4
49 bne 1b
50
51 mov fp, #0 @ Clear BSS (and zero fp)
52 1: cmp r6, r7
53 strcc fp, [r6],#4
54 bcc 1b
55
56 ARM( ldmia r3, {r4, r5, r6, r7, sp})
We got the sp. It means we are in the thread 0 now, because the macro “current” returns task 0.
arch/arm/include/asm/thread_info.h
94 static inline struct thread_info *current_thread_info(void)
95 {
96 register unsigned long sp asm ("sp");
97 return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
98 }
arch/arm/include/asm/current.h
8 static inline struct task_struct *get_current(void)
9 {
10 return current_thread_info()->task;
11 }
12
13 #define current (get_current())
57 THUMB( ldmia r3, {r4, r5, r6, r7} )
58 THUMB( ldr sp, [r3, #16] )
59 str r9, [r4] @ Save processor ID
60 str r1, [r5] @ Save machine type
61 str r2, [r6] @ Save atags pointer
62 bic r4, r0, #CR_A @ Clear 'A' bit
63 stmia r7, {r0, r4} @ Save control register values
64 b start_kernel
65 ENDPROC(__mmap_switched)
Now we enter the C code finally.