linux内核学习笔记【二】最终内核页表 Final kernel Page Table
2013-08-30 16:29
405 查看
之前建立了临时页表,现在要建立最终内核页表,内核必须首先要建立一个完整的页表才能继续运行,因为内存寻址是内核继续运行的前提。下面就对主要函数kernel_physical_mapping_init(),进行分析。这个函数的掉用关系为:head.S->start_kernel()->setup_arch()->paging_init()->pagetable_init()->kernel_physical_mapping_init.
这样,内核空间的线性地址0xc0000000-0xffffffff已经都映射了整块物理内存。即pgd[0x300]-pgd[0x400]都有了值,同时下面的每个pte[0-1024]也都有了值,不知道理解的对不对,希望高手指点。还有一个疑问就是,用户空间的线性地址0x00000000 - 0xbfffffff这段地址是在什么时候映射的,可能还没有看到吧,继续学习。。。
转自:/article/5536066.html
1 static void __init kernel_physical_mapping_init(pgd_t *pgd_base) 2 { 3 unsigned long pfn; 4 pgd_t *pgd; 5 pmd_t *pmd; 6 pte_t *pte; 7 int pgd_idx, pmd_idx, pte_ofs; 8 9 pgd_idx = pgd_index(PAGE_OFFSET); 10 //#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) in inculde/pagetable.h 11 //so pgd_index = (0xc0000000 >> 22) & (1024 - 1) = 0x300 & 0x3ff = 0x300 = 768 12 pgd = pgd_base + pgd_idx; 13 //pgd_t *pgd_base = swapper_pg_dir; 14 //pgd = swapper_pg_dir[0x300] 15 pfn = 0; 16 17 //for(pgd_idx = 768; pgd_idx < 1024; pgd++,pgd_indx++) 18 for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { 19 pmd = one_md_table_init(pgd); 20 //pmd = pgd 21 if (pfn >= max_low_pfn) //max_low_pfn = 1024 * 1024? 22 continue; 23 for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { 24 //only have 2 level directory, so PTRS_PER_PMD = 1 25 unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET; 26 //address = 0 * 4096 + 0xc0000000 = 0xc0000000 27 // 1 * 4096 = 0xc0001000 28 // ... 29 30 /* Map with big pages if possible, otherwise create normal page tables. */ 31 if (cpu_has_pse) { 32 unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; 33 34 if (is_kernel_text(address) || is_kernel_text(address2)) 35 set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); 36 else 37 set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); 38 pfn += PTRS_PER_PTE; 39 } else { 40 pte = one_page_table_init(pmd); 41 //then we have mapped one page table 42 43 for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) { 44 if (is_kernel_text(address)) 45 set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); 46 else 47 set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); 48 //set every page table entry PAGE_KERNEL_EXEC or PAGE_KERNEL depend onthe address 49 } 50 } 51 } 52 } 53 } 54 55 static pmd_t * __init one_md_table_init(pgd_t *pgd) 56 { 57 pud_t *pud; 58 pmd_t *pmd_table; 59 60 #ifdef CONFIG_X86_PAE 61 //... 62 #else 63 pud = pud_offset(pgd, 0); 64 //#define pud_offset(pgd, start) (pgd) ;in include/generic/4level-fixup.h 65 //so pud = pgd; 66 pmd_table = pmd_offset(pud, 0); 67 //#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + pmd_index(address)) ; in /include/asm-i386/pgtable-3level.h 68 //so pmd_table = pgd 69 #endif 70 71 return pmd_table; 72 } 73 74 /* 75 * Create a page table and place a pointer to it in a middle page 76 * directory entry. 77 */ 78 static pte_t * __init one_page_table_init(pmd_t *pmd) 79 { 80 if (pmd_none(*pmd)) { 81 //check if the pmd so as pgd has value 82 pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); 83 //alloc physical memory, size = 4096 84 set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); 85 //set parameters 86 if (page_table != pte_offset_kernel(pmd, 0)) 87 BUG(); 88 89 return page_table; 90 } 91 92 return pte_offset_kernel(pmd, 0); 93 } 94 95 static inline int is_kernel_text(unsigned long addr) 96 { 97 if (addr >= (unsigned long)_stext && addr <= (unsigned long)__init_end) 98 return 1; 99 return 0; 100 } 101 102 //_stext, __init_end是个内核符号, 在内核链接的时候生成的, 分别表示内核代码段的开始和终止地址. 103 //如果address属于内核代码段, 那么在设置页表项的时候就要加个PAGE_KERNEL_EXEC属性,如果不是,则加个PAGE_KERNEL属性. 104 //#define _PAGE_KERNEL_EXEC \ 105 // (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) 106 107 //#define _PAGE_KERNEL \ 108 // (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
这样,内核空间的线性地址0xc0000000-0xffffffff已经都映射了整块物理内存。即pgd[0x300]-pgd[0x400]都有了值,同时下面的每个pte[0-1024]也都有了值,不知道理解的对不对,希望高手指点。还有一个疑问就是,用户空间的线性地址0x00000000 - 0xbfffffff这段地址是在什么时候映射的,可能还没有看到吧,继续学习。。。
转自:/article/5536066.html
相关文章推荐
- linux内核学习笔记【二】最终内核页表 Final kernel Page Table
- linux内核学习笔记【一】临时内核页表 Provisional kernel Page Tables
- linux内核学习笔记【一】临时内核页表 Provisional kernel Page Tables
- linux内核学习笔记【一】临时内核页表 Provisional kernel Page Tables
- linux学习笔记-读《Linux设备驱动开发详解》~第三章 Linux内核及内核编程
- Linux内核学习笔记九——内核内存管理方式
- linux内核学习笔记-Linux 内核系统体系结构
- 【学习笔记】编译Linux内核(上)--编译基于x86平台的Linux内核的过程
- 【学习笔记】编译Linux内核(中)--安装内核时易出现的问题和解决方案
- linux内核分析学习笔记:用gdb跟踪linux内核启动过程
- Linux内核学习笔记九——内核内存管理方式
- windbg学习笔记 FOR 内核调试(三) --进程句柄表HANDLE_TABLE
- Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程
- windbg 学习笔记 FOR 内核调试(三) --进程句柄表HANDLE_TABLE
- Linux内核设计与实现 学习笔记(8)内核调试
- Linux内核学习笔记——内核内存管理方式
- Linux Kernel 学习笔记9:内核与用户层通信之netlink
- 【Linux学习笔记②】Linux系统内核Kernel和GNU计划
- arm-linux内存管理学习笔记(2)-内核临时页表的建立
- Linux内核学习笔记:内核同步