arm linux kernel 从入口到start_kernel 的代码分析
3. 创建页表
通过前面的两步,我们已经确定了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 来实现的.
这里,我们使用的是arm的L1主页表,L1主页表也称为段页表(section page table)
L1 主页表将4 GB 的地址空间分成若干个1 MB的段(section),因此L1页表包含4096个页表项(section entry). 每个页表项是32 bits(4 bytes)
因而L1主页表占用 4096 *4 = 16k的内存空间.
对于ARM926,其L1 section entry的格式为
可参考arm926EJS TRM):
(一级描述符的格式 可以参考《ARM体系结构与编程》P180)
下面我们来分析 __create_page_tables 函数:
在 arch/arm/kernel/head.S 中:
00206: .type __create_page_tables, %function
00207: __create_page_tables:
00208: pgtbl r4 @ page table address
00209:
00210: /*
00211: * Clear the 16K level 1 swapper page table
00212: */
00213: mov r0, r4
00214: mov r3, #0
00215: add r6, r0, #0x4
00216: 1: str r3, [r0], #4
00217: str r3, [r0], #4
00218: str r3, [r0], #4
00219: str r3, [r0], #4
00220: teq r0, r6
00221: bne 1b
00:
00223: ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
00224:
00225: /*
00226: * Create identity mapping for first MB of kernel to
00227: * cater for the MMU enable. This identity mapping
00228: * will be removed by paging_init(). We use our current program
00229: * counter to determine corresponding section base address.
00230: */
00231: mov r6, pc, lsr #20 @ start of kernel section
00232: orr r3, r7, r6, lsl #20 @ flags + kernel base
00233: str r3, [r4, r6, lsl #2] @ identity mapping
00234:
00235: /*
00236: * Now setup the pagetables for our kernel direct
00237: * mapped region.
00238: */
00239: add r0, r4, #(TEXTADDR & 0xff) >> 18 @ start of kernel
00240: str r3, [r0, #(TEXTADDR & 0x00f00) >> 18]!
00241:
00242: ldr r6, =(_end - PAGE_OFFSET - 1) @ r6 = number of sections
00243: mov r6, r6, lsr #20 @ needed for kernel minus 1
00244:
00245: 1: add r3, r3, #1 < 20
00246: str r3, [r0, #4]!
00247: subs r6, r6, #1
00248: bgt 1b
00249:
00250: /*
00251: * Then map first 1MB of ram in case it contains our boot params.
00252: */
00253: add r0, r4, #PAGE_OFFSET >> 18
00254: orr r6, r7, #PHYS_OFFSET
00255: str r6, [r0]
...
00314: mov pc, lr
00315: .ltorg
206, 207行: 函数声明
208行: 通过宏 pgtbl 将r4设置成页表的基地址(物理地址)
宏pgtbl 在 arch/arm/kernel/head.S 中:
42: .macro pgtbl, rd
43: ldr \rd, =(__virt_to_phys(KERNEL_RAM_ADDR - 0x4))
44: .endm
可以看到,页表是位于 KERNEL_RAM_ADDR 下面 16k 的位置
宏 __virt_to_phys 是在incude/asm-arm/memory.h 中:
00125: #ifndef __virt_to_phys
00126: #define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
00127: #define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
00128: #endif
下面从213行 - 221行, 是将这16k 的页表清0.
213行: r0 = r4, 将页表基地址存在r0中
214行: 将 r3 置成0
215行: r6 = 页表基地址 + 16k, 可以看到这是页表的尾地址
216 - 221 行: 循环,从 r0 到 r6 将这16k页表用0填充.
223行: 获得proc_info_list的__cpu_mm_mmu_flags的值,并存储到 r7中. (宏PROCINFO_MM_MMUFLAGS是在arch/arm/kernel/asm-offset.c中定义,值为8)(可以参考《嵌入式Linux应用完全开发手册》P118)(r7的值就是设置这个段描述符的权限、域字段,)
在arch/arm/mm/proc-arm926.S 中:
00464: .section ".proc.info.init", #alloc, #execinstr
00465:
00466: .type __arm926_proc_info,#object
00467: __arm926_proc_info:
00468: .long 0x41069260 @ ARM926EJ-S (v5TEJ)
00469: .long 0xff0ffff0
00470: .long PMD_TYPE_SECT \
00471: PMD_SECT_BUFFERABLE \
00472: PMD_SECT_CACHEABLE \
00473: PMD_BIT4 \
00474: PMD_SECT_AP_WRITE \
00475: PMD_SECT_AP_READ
00476: .long PMD_TYPE_SECT \
00477: PMD_BIT4 \
00478: PMD_SECT_AP_WRITE \
00479: PMD_SECT_AP_READ
00480: b __arm926_setup
00481: .long cpu_arch_name
00482: .long cpu_elf_name
00483: .long HWCAP_SWPHWCAP_HALFHWCAP_THUMBHWCAP_FAST_MULTHWCAP_VFPHWCAP_EDSPHWCAP_JAVA
00484: .long cpu_arm926_name
00485: .long arm926_processor_functions
00486: .long v4wbi_tlb_fns
00487: .long v4wb_user_fns
00488: .long arm926_cache_fns
00489: .size __arm926_proc_info, . - __arm926_proc_info
armlinuxkernel代码分 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)