freshtree 1.4 __create_page_tables() __create_page_tables()函數同樣也是位于arch/arm/kernel/head.S中,代碼如下: __create_page_tables: pgtbl r4 @ page table address /* * Clear the 16K level 1 swapper page table */ 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 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags /* * Create identity mapping for first MB of kernel to * cater for the MMU enable. This identity mapping * will be removed by paging_init(). We use our current program * counter to determine corresponding section base address. */ 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 /* * Now setup the pagetables for our kernel direct * mapped region. */ 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 #ifdef CONFIG_XIP_KERNEL /* * Map some ram to cover our .data and .bss areas. */ 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 /* * Then map first 1MB of ram in case it contains our boot params. */ 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] #ifdef CONFIG_DEBUG_LL ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags /* * Map in IO space for serial debugging. * This allows debug messages to be output * via a serial console before paging_init. */ ldr r3, [r8, #MACHINFO_PGOFFIO] add r0, r4, r3 rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long) cmp r3, #0x0800 @ limit to 512MB movhi r3, #0x0800 add r6, r0, r3 ldr r3, [r8, #MACHINFO_PHYSIO] orr r3, r3, r7 1: str r3, [r0], #4 add r3, r3, #1 << 20 teq r0, r6 bne 1b #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) /* * If we're using the NetWinder or CATS, we also need to map * in the 16550-type serial port for the debug messages */ add r0, r4, #0xff000000 >> 18 orr r3, r7, #0x7c000000 str r3, [r0] #endif #ifdef CONFIG_ARCH_RPC add r0, r4, #0x02000000 >> 18 orr r3, r7, #0x02000000 str r3, [r0] add r0, r4, #0xd8000000 >> 18 str r3, [r0] #endif #endif mov pc, lr ENDPROC(__create_page_tables) 這段代碼是用來建立一級頁表的。這個初始頁表是給接下來要運行的kernel代碼用的。因為內核代碼用的都是虛擬地址,在使用之前我們必須要建立MMU。這里的MMU只需要建立的頁表能識別內核代碼這部分的虛擬地址就夠了,也就是從KERNEL_START到KERNEL_END部分。 #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 #error KERNEL_RAM_VADDR must start at 0xXXXX8000 #endif .globl swapper_pg_dir .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 .macro pgtbl, rd ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) .endm #ifdef CONFIG_XIP_KERNEL #define KERNEL_START XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR) #define KERNEL_END _edata_loc #else #define KERNEL_START KERNEL_RAM_VADDR #define KERNEL_END _end #endif 從上述代碼我們可以看出,KERNEL_START就是c0008000,KERNEL_END等于_end。_end我們可以從vmlinux.lds.S中找到蹤跡。 另外需要強調的是,這里建立的MMU 頁表是一級頁表的,是以1M為單位的;二級頁表(4K)不是在這里建立的。Arm一級頁表的轉換關系如下: 從上圖可以看出,一級頁表描述符的內容是物理地址段(物理地址前12位)和一些MMU管理位合成的;一級頁表描述符的地址是由頁表地址基地址(31-14位)和虛擬地址前12位(31-20)合成的,它的最后兩位都是零,滿足32位地址對齊的方式。 建立一級頁表的過程就是將每一個一級頁表描述符(1M為單位)填入到每一個一級頁表描述符的地址。 |