linux 内存管理之内核分页机制(PAGING_INIT)初始化

发布时间 2023-06-10 22:00:08作者: 流水灯
 
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 = .
这个代码段的功能是啥