红联Linux门户
Linux帮助

linux内核-__create_page_tables分析

发布时间:2016-01-09 10:00:13来源:linux网站作者:Abe_119

前言:

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:

/*
*宏定义
*.macropgtbl, 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汇编立即数可以参考相关文章
*
* 下面这段代码就是存储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分析