TEXT_OFFSET = 0x00008000 KERNEL_OFFSET = 0x80000000 PG_DIR_SIZE = 0x4000 kernel 代码起始链接地址如下:
PHYS_OFFSET = 0x80000000 r10 指向 proc_info_list 结构体类型数据__create_page_tables: pgtbl r4, r8 @ page table address // r4 = 0x80004000,swapper page table 起始地址 /* * Clear the swapper page table */ mov r0, r4 mov r3, #0 add r6, r0, #PG_DIR_SIZE
// r6 = 0x80008000,是 swapper page table 结束地址 1: str r3, [r0], #4
// r3 = [r0], r0 += 4 str r3, [r0], #4 str r3, [r0], #4 str r3, [r0], #4 teq r0, r6 bne 1b // 上面代码作用:把内存地址 0x80004000~0x80008000 的内容清零 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags // r7 = [r10 + PROCINFO_MM_MMUFLAGS],即 r7 = __cpu_mm_mmu_flags /* * Create identity mapping to cater for __enable_mmu. * This identity mapping will be removed by paging_init(). */ adr_l r5, __turn_mmu_on @ _pa(__turn_mmu_on) adr_l r6, __turn_mmu_on_end @ _pa(__turn_mmu_on_end) mov r5, r5, lsr #SECTION_SHIFT
// r5 = r5 >> 20, 2级页表是20,打开MMU代码的起始一级页表项 mov r6, r6, lsr #SECTION_SHIFT // r6 是打开MMU代码的结束一级页表项 1: orr r3, r7, r5, lsl #SECTION_SHIFT @ r3 = 页表项 | mmu_flags str r3, [r4, r5, lsl #PMD_ORDER] @ identity mapping
// [r4 + (r5 << 2)] = r3,一次性写入4个字节 cmp r5, r6
// r5<r6时,CPSR.C=0 addlo r5, r5, #1 @ next section
// lo表示CPSR.C==0时执行add
// r5 += 1,使用的时候左移2,相当于每次地址加4, 0<<2=0, 1<<2=4, 2<<2=8,3<<2=12, 4<<4=16, 5<<2=20 blo 1b // 上面代码作用:为“打开MMU的代码”的内存地址建立页表项,填入swapper page table某个的偏移位置(__turn_mmu_on << 2) /* * The main matter: map in the kernel using section mappings, and * set two variables to indicate the physical start and end of the * kernel. */ add r0, r4, #KERNEL_OFFSET >> (SECTION_SHIFT - PMD_ORDER)
// r0 = 0x80004000 + 0x80000000的高14位,作为页表项的起始地址 ldr r6, =(_end - 1)
// _end是kernel代码结束位置 adr_l r5, kernel_sec_start @ _pa(kernel_sec_start) str r8, [r5] @ Save physical start of kernel (LE)
// [kernel_sec_start] = 0x80000000 orr r3, r8, r7 @ Add the MMU flags
// r3 = 0x80000000 | mmu_flags add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
// r6 = 0x80004000 + kernel代码结束位置的高14位,作为页表项的结束地址 1: str r3, [r0], #1 << PMD_ORDER
// [r0] = r3, r0 += 4 add r3, r3, #1 << SECTION_SHIFT
// r3作为页表项,更新其地址信息 cmp r0, r6
//和上面一段代码不同,这里是判断“当前页表项所在地址”是否等于“页表项结束地址” bls 1b eor r3, r3, r7 @ Remove the MMU flags adr_l r5, kernel_sec_end @ _pa(kernel_sec_end) str r3, [r5] @ Save physical end of kernel (LE) // [kernel_sec_end] = kernel结束代码位置(低位被置零)
// 上面代码作用:为0x80000000 ~ kernel结束代码位置之间的内存地址建立页表项,填入swapper page table的某个偏移位置(KERNEL_OFFSET >> (SECTION_SHIFT - PMD_ORDER)) /* * Then map boot params address in r2 if specified. * We map 2 sections in case the ATAGs/DTB crosses a section boundary. */ mov r0, r2, lsr #SECTION_SHIFT cmp r2, #0 ldrne r3, =FDT_FIXED_BASE >> (SECTION_SHIFT - PMD_ORDER) addne r3, r3, r4 orrne r6, r7, r0, lsl #SECTION_SHIFT strne r6, [r3], #1 << PMD_ORDER addne r6, r6, #1 << SECTION_SHIFT strne r6, [r3] // 上面代码作用:为dtb的内存地址建立页表项
// 以上三个都是只有一级页表项
ret lr ENDPROC(__create_page_tables)
stext __create_page_tables
struct mm_struct init_mm = { .mm_rb = RB_ROOT, .pgd = swapper_pg_dir, .mm_users = ATOMIC_INIT(2), .mm_count = ATOMIC_INIT(1), .write_protect_seq = SEQCNT_ZERO(init_mm.write_protect_seq), MMAP_LOCK_INITIALIZER(init_mm) .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock), .arg_lock = __SPIN_LOCK_UNLOCKED(init_mm.arg_lock), .mmlist = LIST_HEAD_INIT(init_mm.mmlist), .user_ns = &init_user_ns, .cpu_bitmap = CPU_BITS_NONE, I
#define KERNEL_RAM_VADDR (KERNEL_OFFSET + TEXT_OFFSET) 内核 image 是放在 KERNEL_RAM_VADDR 之后的地址,(KERNEL_RAM_VADDR - PG_DIR_SIZE) ~ KERNEL_RAM_VADDR 是存放初始页表 swapper_pg_dir
__idmap_text_start = .; *(.idmap.text) __idmap_text_end = . 这个代码段的功能是啥 标签:__,kernel,r6,r0,r3,PAGING,INIT,linux,r5 From: https://www.cnblogs.com/god-of-death/p/17472036.html