linux内核-__create_page_tables分析

前言

linux-arm架构

kernel版本:2.6.22.6

head.S首先确定了processor type和 machine type,之后就是创建页表。

通过前面的两步,我们已经确定了processor type 和 machine type。

此时,一些特定寄存器的值如下所示:

r8 = machine info       (struct machine_desc的基地址)
r9 = cpu id             (通过cp15协处理器获得的cpu id)
r10 = procinfo          (struct proc_info_list的基地址)

接下来就是通过__create_page_tables建立页表了。

bl  __create_page_tables

函数中出现的宏,及其解释

宏                       默认值                 定义
KERNEL_RAM_VADDR        0xC0008000      内核在内存中的虚拟地址
PAGE_OFFSET             0xC0000000      内核虚拟地址空间的起始地址
TEXT_OFFSET             0x00008000      内核起始位置相对于内存起始位置的偏移
PHYS_OFFSET             构架相关            物理内存的起始地址

代码分析

bl __create_page_tables会跳转到下面代码段中,建立表单

    .type   __create_page_tables, %function
__create_page_tables:

    /* *宏定义 *.macro pgtbl, rd *ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) *.endm * *分析:内存为 4G = 4*1024 MB;需要4096个表单表示,每一页表单为4bytes;因此需要16K内存,即0x4000; * 根据 =(KERNEL_RAM_PADDR - 0x4000)得,页表存放于-内核在内存中的物理地址之前。 */
    pgtbl   r4              @ page table address


    /* * 按16个bytes一次,将页表清空 */
    mov r0, r4
    mov r3, #0
    add r6, r0, #0x4000
1:  str r3, [r0], #4
    str r3, [r0], #4
    str r3, [r0], #4
    str r3, [r0], #4
    teq r0, r6
    bne 1b

    /* *r10 = proc_info_list类型结构体的基地址 *PROCINFO_MM_MMUFLAGS 8 /* offsetof(struct proc_info_list, __cpu_mm_mmu_flags) @ */
     *
     *因此,r7为结构体中__cpu_mm_mmu_flags的数值
    */
    ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags 

    /* *下面代码建立kernel对应的section页表项。 * *1. 通过PC值的高12位(右移20位),得到kernel的section,并存储在r6中。 *2. 获取32bit的页表表单值 *3. 将页表表单值存放在页表内存区中。 * *注意点: *a. lsr 20 因为虚拟地址分区中,后20位为相对地址,前12位为段地址 *b. lsl 2 因为每一个页表项为4字节,所以需要左移2位 */
    mov r6, pc, lsr #20 @ start of kernel section
    orr r3, r7, r6, lsl #20 @ flags + kernel base
    str r3, [r4, r6, lsl #2] @ identity mapping

    /* * 下面的 add r0, r4, #(KERNEL_START & 0xff000000) >> 18 涉及到一个立即数的概念: * 关于arm汇编立即数,可以参考下面网站:http://blog.csdn.net/a99778800/article/details/6759825 * * 下面这段代码就是存储kernel物理地址。建立页表,虚拟地址和物理地址之间建立连接。 * 即:将内核中所有的物理地址(1M为单位)都存放到了页表中,与虚拟地址一一对应。 */
    add r0, r4,  #(KERNEL_START & 0xff000000) >> 18
    str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
    ldr r6, =(KERNEL_END - 1)
    add r0, r0, #4
    add r6, r4, r6, lsr #18
1:  cmp r0, r6
    add r3, r3, #1 << 20
    strls   r3, [r0], #4
    bls 1b


    /* * XIP介绍: * XIP是指 (EXECUTE IN PLACE) 是指直接从存放代码的位置上启动运行。 * 非XIP方式是指在运行之前需对代码进行重定位。该类型的内核以非压缩方式存放在Flash中,启动时由Bootloader加载到内存后运行。 * * 如果是XIP技术的内核,上面的映射只能映射内核代码和只读数据部分 * 这里我们再映射一些RAM来作为.data and .bss空间。 */
#ifdef CONFIG_XIP_KERNEL
    orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
    .if (KERNEL_RAM_PADDR & 0x00f00000)
    orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
    .endif
    add r0, r4,  #(KERNEL_RAM_VADDR & 0xff000000) >> 18
    str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
    ldr r6, =(_end - 1)
    add r0, r0, #4
    add r6, r4, r6, lsr #18
1:  cmp r0, r6
    add r3, r3, #1 << 20
    strls   r3, [r0], #4
    bls 1b
#endif

    /* * 下面的代码用来设置RAM中大小为1M虚拟地址的页表。之所以要设置这个页表项的原因是该区域存储着boot params。 * 因此需要为它建立map,这样开启MMU后就可以访问 */
    add r0, r4, #PAGE_OFFSET >> 18
    orr r6, r7, #(PHYS_OFFSET & 0xff000000)
    .if (PHYS_OFFSET & 0x00f00000)
    orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
    .endif
    str r6, [r0]

    /* * 结束 */
    mov pc, lr
    .ltorg

结果图

linux内核-__create_page_tables分析_第1张图片

参考:

http://blog.chinaunix.net/uid-28263175-id-3842638.html

http://blog.csdn.net/skyflying2012/article/details/41447843

你可能感兴趣的:(linux,kernel,kernel,mmu)