1. The whole process
crash> dis stext
0xc0008000 <stext>: msr CPSR_c, #211 ; 0xd3
0xc0008004 <stext+4>: mrc 15, 0, r9, cr0, cr0, {0}
0xc0008008 <stext+8>: bl 0xc044c880 <__lookup_processor_type>
0xc000800c <stext+12>: movs r10, r5
0xc0008010 <stext+16>: beq 0xc044c8c4 <__error>
0xc0008014 <stext+20>: add r3, pc, #44 ; 0x2c
0xc0008018 <stext+24>: ldm r3, {r4, r8}
0xc000801c <stext+28>: sub r4, r3, r4
0xc0008020 <stext+32>: add r8, r8, r4
0xc0008024 <stext+36>: bl 0xc0008110 <__vet_atags>
0xc0008028 <stext+40>: bl 0xc058d000 <__fixup_smp>
0xc000802c <stext+44>: bl 0xc0008050 <__create_page_tables>
0xc0008030 <stext+48>: ldr sp, [pc, #12] ; 0xc0008044
0xc0008034 <stext+52>: add lr, pc, #4
0xc0008038 <stext+56>: mov r8, r4
0xc000803c <stext+60>: add pc, r10, #16
0xc0008040 <stext+64>: b 0xc044c854 <__enable_mmu>
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
2. __lookup_processor_type
/*
* Read processor ID register (CP#15, CR0), and look up in the linker-built
* supported processor list. Note that we can't use the absolute addresses
* for the __proc_info lists since we aren't running with the MMU on
* (and therefore, we are not in the correct address space). We have to
* calculate the offset.
*
* r9 = cpuid
* Returns:
* r3, r4, r6 corrupted
* r5 = proc_info pointer in physical address space
* r9 = cpuid (preserved)
*/
crash> dis __lookup_processor_type
/*此时pc的内容是物理地址,而不是这里显示的标号 0xc044c880【该值是静态编译生成的,不是运行是决定的】
*而PC时运行时决定的。
*r3的内容也是物理地址,间接寻址把内容load 到r4,5,6
*r4的内容是当前地址的虚拟地址, r3是当前地址的物理地址
*/
0xc044c880 <__lookup_processor_type>: add r3, pc, #48 ; 0x30
0xc044c884 <__lookup_processor_type+4>: ldm r3, {r4, r5, r6}
/*mean: r3-r4 not r4-r3
*convert virt addresses to physical address space
*/
0xc044c888 <__lookup_processor_type+8>: sub r3, r3, r4
0xc044c88c <__lookup_processor_type+12>: add r5, r5, r3
0xc044c890 <__lookup_processor_type+16>: add r6, r6, r3
0xc044c894 <__lookup_processor_type+20>: ldm r5, {r3, r4}
0xc044c898 <__lookup_processor_type+24>: and r4, r4, r9
0xc044c89c <__lookup_processor_type+28>: teq r3, r4
0xc044c8a0 <__lookup_processor_type+32>: beq 0xc044c8b4 <__lookup_processor_type+52>
0xc044c8a4 <__lookup_processor_type+36>: add r5, r5, #52 ; 0x34
0xc044c8a8 <__lookup_processor_type+40>: cmp r5, r6
0xc044c8ac <__lookup_processor_type+44>: bcc 0xc044c894 <__lookup_processor_type+20>
0xc044c8b0 <__lookup_processor_type+48>: mov r5, #0
0xc044c8b4 <__lookup_processor_type+52>: mov pc, lr
/*具体细节不再关注,这个代码的意思是:
*1】此时是物理地址,而不是这些的虚拟地址,如果寻址此时只能使用PC寻址;
*2】此函数的输入值r5 = proc_info pointer in physical address space
*3】此函数的返回值r9 = cpuid
*4】至于,cpuid和proc_info的对应关系,不再关注。
*/
3. __vet_atags
r2 = atags or dtb pointer.
/* Determine validity of the r2 atags pointer. The heuristic requires
* that the pointer be aligned, in the first 16k of physical RAM and
* that the ATAG_CORE marker is first and present. If CONFIG_OF_FLATTREE
* is selected, then it will also accept a dtb pointer. Future revisions
* of this function may be more lenient with the physical address and
* may also be able to move the ATAGS block if necessary.
*
* Returns:
* r2 either valid atags pointer, valid dtb pointer, or zero
* r5, r6 corrupted
* 该函数只是判断r2的有效性,并没有做其他处理
*/
crash> dis __vet_atags
0xc0008110 <__vet_atags>: tst r2, #3
0xc0008114 <__vet_atags+4>: bne 0xc000813c <__vet_atags+44>
0xc0008118 <__vet_atags+8>: ldr r5, [r2]
0xc000811c <__vet_atags+12>: cmp r5, #5
0xc0008120 <__vet_atags+16>: cmpne r5, #2
0xc0008124 <__vet_atags+20>: bne 0xc000813c <__vet_atags+44>
0xc0008128 <__vet_atags+24>: ldr r5, [r2, #4]
0xc000812c <__vet_atags+28>: ldr r6, [pc, #16] ; 0xc0008144
0xc0008130 <__vet_atags+32>: cmp r5, r6
0xc0008134 <__vet_atags+36>: bne 0xc000813c <__vet_atags+44>
0xc0008138 <__vet_atags+40>: mov pc, lr
0xc000813c <__vet_atags+44>: mov r2, #0
0xc0008140 <__vet_atags+48>: mov pc, lr
4. __fixup_smp
/*
*what about the __fixup_smp??
*/
__fixup_smp:
and r3, r9, #0x000f0000 @ architecture version
teq r3, #0x000f0000 @ CPU ID supported?
bne __fixup_smp_on_up @ no, assume UP
bic r3, r9, #0x00ff0000
bic r3, r3, #0x0000000f @ mask 0xff00fff0
mov r4, #0x41000000
orr r4, r4, #0x0000b000
orr r4, r4, #0x00000020 @ val 0x4100b020
teq r3, r4 @ ARM 11MPCore?
moveq pc, lr @ yes, assume SMP
mrc p15, 0, r0, c0, c0, 5 @ read MPIDR
and r0, r0, #0xc0000000 @ multiprocessing extensions and
teq r0, #0x80000000 @ not part of a uniprocessor system?
moveq pc, lr @ yes, assume SMP
5. __create_page_tables
/*
* Setup the initial page tables. We only setup the barest
* amount which are required to get the kernel running, which
* generally means mapping in the kernel code.
*
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*
* Returns:
* r0, r3, r5-r7 corrupted
* r4 = physical page table address
*/
crash> dis __create_page_tables
/*
* make the region of [phys_offset+0x4000, phys_offset+0x4000+0x4000] clean
* Clear the swapper page table
*/
0xc0008050 <__create_page_tables>: add r4, r8, #16384 ; 0x4000
0xc0008054 <__create_page_tables+0x4>: mov r0, r4
0xc0008058 <__create_page_tables+0x8>: mov r3, #0
0xc000805c <__create_page_tables+0xc>: add r6, r0, #16384 ; 0x4000
0xc0008060 <__create_page_tables+0x10>: str r3, [r0], #4
0xc0008064 <__create_page_tables+0x14>: str r3, [r0], #4
0xc0008068 <__create_page_tables+0x18>: str r3, [r0], #4
0xc000806c <__create_page_tables+0x1c>: str r3, [r0], #4
0xc0008070 <__create_page_tables+0x20>: teq r0, r6
0xc0008074 <__create_page_tables+0x24>: bne 0xc0008060 <__create_page_tables+16>
5.1 Create identity mapping to cater for __enable_mmu
/* r10 = procinfo, mm_mmuflags
*/
0xc0008078 <__create_page_tables+0x28>: ldr r7, [r10, #8]
/*
* Create identity mapping to cater for __enable_mmu.
* This identity mapping will be removed by paging_init().
*/
0xc000807c <__create_page_tables+0x2c>: add r0, pc, #128 ; 0x80
0xc0008080 <__create_page_tables+0x30>: ldm r0, {r3, r5, r6}
0xc0008084 <__create_page_tables+0x34>: sub r0, r0, r3
0xc0008088 <__create_page_tables+0x38>: add r5, r5, r0
0xc000808c <__create_page_tables+0x3c>: add r6, r6, r0
/*
*r5,r6寄存器的内容分别是代码__turn_mmu_on的开始,结束地址
*r5,r6寄存器的内容右移20位:SECTION_SHIFT
*/
0xc0008090 <__create_page_tables+0x40>: lsr r5, r5, #20
0xc0008094 <__create_page_tables+0x44>: lsr r6, r6, #20
/*
*r5右移20位后,再左移20位,然后和procinfo中的mm_mmuflags逻辑或操作
*把r3的内容存放在位置PHY_OFFSET + address >> 20 << 20 << 2
*物理地址的来源当前PC和相对地址,它的内容的前20位在 pte中;
*怎样得到个表项那?虚拟地址的高12位再左移2位,这14位形成index和18位的基地址,形成表项的虚拟地址
*注意每个表项占2*2=4个字节,每个pte也是用4个字节描述;14形成的index: 2的14次幂就是16K:0x4000
*#define PG_DIR_SIZE 0x4000
*#define PMD_ORDER 2
*/
0xc0008098 <__create_page_tables+0x48>: orr r3, r7, r5, lsl #20
0xc000809c <__create_page_tables+0x4c>: str r3, [r4, r5, lsl #2]
0xc00080a0 <__create_page_tables+0x50>: cmp r5, r6
0xc00080a4 <__create_page_tables+0x54>: addcc r5, r5, #1
0xc00080a8 <__create_page_tables+0x58>: bcc 0xc0008098 <__create_page_tables+72>
5.2 setup the pagetables for our kernel direct mapped region
/*
* Now setup the pagetables for our kernel direct
* mapped region.
*/
0xc00080ac <__create_page_tables+0x5c>: mov r3, pc
0xc00080b0 <__create_page_tables+0x60>: lsr r3, r3, #20
0xc00080b4 <__create_page_tables+0x64>: orr r3, r7, r3, lsl #20
0xc00080b8 <__create_page_tables+0x68>: add r0, r4, #12288 ; 0x3000
0xc00080bc <__create_page_tables+0x6c>: str r3, [r0, #0]!
0xc00080c0 <__create_page_tables+0x70>: ldr r6, [pc, #56] ; 0xc0008100
0xc00080c4 <__create_page_tables+0x74>: add r0, r0, #4
0xc00080c8 <__create_page_tables+0x78>: add r6, r4, r6, lsr #18
0xc00080cc <__create_page_tables+0x7c>: cmp r0, r6
0xc00080d0 <__create_page_tables+0x80>: add r3, r3, #1048576 ; 0x100000
0xc00080d4 <__create_page_tables+0x84>: strls r3, [r0], #4
0xc00080d8 <__create_page_tables+0x88>: bls 0xc00080cc <__create_page_tables+124>
5.3 map boot params address
/*
* Then map boot params address in r2 or the first 1MB (2MB with LPAE)
* of ram if boot params address is not specified.
*/
0xc00080dc <__create_page_tables+0x8c>: lsr r0, r2, #20
0xc00080e0 <__create_page_tables+0x90>: lsls r0, r0, #20
0xc00080e4 <__create_page_tables+0x94>: moveq r0, r8
0xc00080e8 <__create_page_tables+0x98>: sub r3, r0, r8
0xc00080ec <__create_page_tables+0x9c>: add r3, r3, #-1073741824 ; 0xc0000000
0xc00080f0 <__create_page_tables+0xa0>: add r3, r4, r3, lsr #18
0xc00080f4 <__create_page_tables+0xa4>: orr r6, r7, r0
0xc00080f8 <__create_page_tables+0xa8>: str r6, [r3]
0xc00080fc <__create_page_tables+0xac>: mov pc, lr
__turn_mmu_on_loc:
.long .
.long __turn_mmu_on
.long __turn_mmu_on_end
6 __enable_mmu
/*
* Setup common bits before finally enabling the MMU. Essentially
* this is just loading the page table pointer and domain access
* registers.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags or dtb pointer
* r4 = page table pointer
* r9 = processor ID
* r13 = *virtual* address to jump to upon completion
*/
crash> dis __enable_mmu
0xc044c854 <__enable_mmu>: bic r0, r0, #2
0xc044c858 <__enable_mmu+0x4>: mov r5, #21
/*
*@ load domain access register, load page table pointer
*/
0xc044c85c <__enable_mmu+0x8>: mcr 15, 0, r5, cr3, cr0, {0}
0xc044c860 <__enable_mmu+0xc>: mcr 15, 0, r4, cr2, cr0, {0}
0xc044c864 <__enable_mmu+0x10>: b 0xc0452870 <__turn_mmu_on>
7__turn_mmu_on
/*
* Enable the MMU. This completely changes the structure of the visible
* memory space. You will not be able to trace execution through this.
* If you have an enquiry about this, *please* check the linux-arm-kernel
* mailing list archives BEFORE sending another post to the list.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags or dtb pointer
* r9 = processor ID
* r13 = *virtual* address to jump to upon completion
*
* other registers depend on the function called upon completion
*/
crash> dis __turn_mmu_on
0xc0452870 <__idmap_text_start>: nop ; (mov r0, r0)
0xc0452874 <__turn_mmu_on+0x4>: isb sy
0xc0452878 <__turn_mmu_on+0x8>: mcr 15, 0, r0, cr1, cr0, {0}
0xc045287c <__turn_mmu_on+0xc>: mrc 15, 0, r3, cr0, cr0, {0}
0xc0452880 <__turn_mmu_on+0x10>: isb sy
0xc0452884 <__turn_mmu_on+0x14>: mov r3, r3
0xc0452888 <__turn_mmu_on+0x18>: mov r3, sp
0xc045288c <__turn_mmu_on+0x1c>: mov pc, r3
8 __mmap_switched
/*
* The following fragment of code is executed with the MMU on in MMU mode,
* and uses absolute addresses; this is not position independent.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags/dtb pointer
* r9 = processor ID
*/
__INIT
__mmap_switched:
adr r3, __mmap_switched_data
ldmia r3!, {r4, r5, r6, r7}
cmp r4, r5 @ Copy data segment if needed
1: cmpne r5, r6
ldrne fp, [r4], #4
strne fp, [r5], #4
bne 1b
mov fp, #0 @ Clear BSS (and zero fp)
1: cmp r6, r7
strcc fp, [r6],#4
bcc 1b
ARM( ldmia r3, {r4, r5, r6, r7, sp})
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
str r2, [r6] @ Save atags pointer
bic r4, r0, #CR_A @ Clear 'A' bit
stmia r7, {r0, r4} @ Save control register values
b start_kernel