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
http://blog.chinaunix.net/uid-28263175-id-3842638.html
http://blog.csdn.net/skyflying2012/article/details/41447843