linux内核在启动分页机制时就已经有了一个可用的页表,这个最初的页表是手工创建了,而且仅有为数不多的几个页面,进入start_kernel()以后需要把原来的页表完善一下,具体工作在start_kernel() --> setup_arch() --> paging_init()函数中。paing_init()函数定义在arch/x86/mm/init_32.c中。

void __init paging_init(void)
{
#ifdef CONFIG_X86_PAE
    set_nx();
    if (nx_enabled)
        printk("NX (Execute Disable) protection: active\n");
#endif
    pagetable_init();
    load_cr3(swapper_pg_dir);
#ifdef CONFIG_X86_PAE
    if (cpu_has_pae)
        set_in_cr4(X86_CR4_PAE);
#endif
    __flush_tlb_all();
    kmap_init();

}

页表初始化的工作由pagetable_init()函数完成,load_cr3()的功能是装载页表。

static void __init pagetable_init (void)
{
    unsigned long vaddr, end;
    pgd_t *pgd_base = swapper_pg_dir;
    paravirt_pagetable_setup_start(pgd_base); //?什么用?
     /* Enable PSE if available */
    if (cpu_has_pse)
        set_in_cr4(X86_CR4_PSE);
    /* Enable PGE if available */
    if (cpu_has_pge) {
        set_in_cr4(X86_CR4_PGE);
        __PAGE_KERNEL |= _PAGE_GLOBAL;
        __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
    }
    /*  把0~896M的物理页框映射到3G~3G+896M,在这个过程中会通过
     * bootmem_allocator申请新的内存页,用以存放页表。  */
    kernel_physical_mapping_init(pgd_base);
    remap_numa_kva(); // null function

/*  Fixed mappings, only the page table structure has to be
     * created - mappings will be set by set_fixmap()   */
    vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
    end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
    page_table_range_init(vaddr, end, pgd_base);
    /* 把固定映射内存区映射到页目录中 */
    permanent_kmaps_init(pgd_base);
    paravirt_pagetable_setup_done(pgd_base);

}

kernel_physical_mapping_init()函数把0~896M的物理地址映射到3G以上的虚拟空间。在这个过程中回向bootmem allocator申请需要的内存页(参考bootmem的初始化)。该函数定义在:arch/x86/mm/init_32.c,定义内容如下。

static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
{
    unsigned long pfn;
    pgd_t *pgd;
    pmd_t *pmd;
    pte_t *pte;
    int pgd_idx, pmd_idx, pte_ofs;
    pgd_idx = pgd_index(PAGE_OFFSET);  // get the index of pgd
    pgd = pgd_base + pgd_idx;          // get the pgd entry
    pfn = 0;
    for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
        /* pmd is just pgd in x86 architecture's default config*/
        pmd = one_md_table_init(pgd);
        if (pfn >= max_low_pfn)//这个判断可以保证不建立高端内存对应的页表
            continue;  /* why not break ? 当where pfn >= max_low_pfn时,
                         * 虽然不用建立相应的页表,但是pmd这一层次的目录是需要建立的,
                         * 所以使用continue而不是break */
        /* 下面这个for语句循环的次数取决于 PTRS_PER_PMD宏.
         * PTRS_PER_PMD的定义在include/asm-generic/pgtable-nopmd.h中,被定义为1*/
        for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
            unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET;
        /* Map with big pages if possible, otherwise create normal page tables. */
            if (cpu_has_pse) {

unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1;

if (is_kernel_text(address) || is_kernel_text(address2))
                    set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC));
                else
                    set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
                pfn += PTRS_PER_PTE;
            } else {
               /* 如果没有与该pmd entry相对应的page table,
                 * 则为该pmd entry申请一个新的页面作为page table,
                 * one_page_table_init()的返回值即是page table的首地址 */
                pte = one_page_table_init(pmd);
                /* 初始化每个pte的值*/
                for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn;
                     pte++, pfn++, pte_ofs++, address += PAGE_SIZE) {
                    if (is_kernel_text(address))
                        set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
                    else
                        set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
                }
            }
        }
    }

}

函数中使用pmd作为过渡,是为了能够支持3级页表,而linux的x86默认配置是2级页表,所以pmd的存在代码的兼容性。linux在2.6.24中的页表是4级的,从顶到底分别是pgd, pud, pmd和pte,内核在默认配置下屏蔽了pud和pmd。pud的全称是page upper directory, pmd的全程是page middle directory。

linux 内核 内存管理 初始化 页表相关推荐

  1. Linux内核内存管理(1):内存块 - memblock

    Linux内核内存管理 内存块 - memblock rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. 简介 内存管理是操作系统内核中最复杂的部分之 ...

  2. Linux内核内存管理(2):固定映射地址(fixmap)和输入输出重映射(ioremap)

    Linux内核内存管理 固定映射地址(fixmap)和输入输出重映射(ioremap) rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. Print ke ...

  3. linux 内核内存管理

    物理内存 相关数据结构 page(页) Linux 内核内存管理的实现以 page 数据结构为核心,其他的内存管理设施都基于 page 数据结构,如 VMA 管理.缺页中断.RMAP.页面分配与回收等 ...

  4. 【Linux 内核 内存管理】虚拟地址空间布局架构 ③ ( 内存描述符 mm_struct 结构体成员分析 | mmap | mm_rb | task_size | pgd | mm_users )

    文章目录 一.mm_struct 结构体成员分析 1.mmap 成员 2.mm_rb 成员 3.get_unmapped_area 函数指针 4.task_size 成员 5.pgd 成员 6.mm_ ...

  5. pae扩展内存 linux,浅析linux内核内存管理之PAE

    浅析linux内核内存管理之PAE 早期Intel处理器从80386到Pentium使用32位物理地址,理论上,这样可以访问4GB的RAM.然而,大型服务器需要大于4GB的RAM来同时运行数以千计的进 ...

  6. Linux内核内存管理(3):kmemcheck介绍

    Linux内核内存管理 kmemcheck介绍 rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 5.10.13不存在kmemcheck的概念,取代的是k ...

  7. 【Linux 内核 内存管理】内存映射原理 ① ( 物理地址空间 | 外围设备寄存器 | 外围设备寄存器的物理地址 映射到 虚拟地址空间 )

    文章目录 一.物理地址空间 二.外围设备寄存器 三.外围设备寄存器物理地址 映射到 虚拟地址空间 一.物理地址空间 " 物理地址空间 " 是 CPU 处理器 在 " 总线 ...

  8. Linux内核内存管理:地址转换和MMU

    地址转换和MMU 虚拟内存是一个概念,是给进程的一种错觉,因此它认为自己拥有巨大的.几乎无限的内存,有时甚至比系统实际拥有的内存还要多.每次访问内存位置时,由CPU将虚拟地址转换为物理地址.这种机制称 ...

  9. 【Linux 内核 内存管理】内存管理架构 ④ ( 内存分配系统调用过程 | 用户层 malloc free | 系统调用层 brk mmap | 内核层 kmalloc | 内存管理流程 )

    文章目录 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) 二.内存管理流程 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) " 堆内存 " ...

  10. 【Linux 内核 内存管理】内存管理架构 ② ( 用户空间内存管理 | malloc | ptmalloc | 内核空间内存管理 | sys_brk | sys_mmap | sys_munmap)

    文章目录 一.用户空间内存管理 ( malloc / free / ptmalloc / jemalloc / tcmalloc ) 二.内核空间内存管理 1.内核内存管理系统调用 ( sys_brk ...

最新文章

  1. 1. 写出一个能创建多级目录的 PHP 函数(新浪网技术部)
  2. 关于搭建haddoop分布式系统的全部过程复习
  3. boost::hana::metafunction_class用法的测试程序
  4. Perl文件及目录操作
  5. vux 地图插件_基于vue的移动端组件vux的安装及使用
  6. CSS3图片跳动效果
  7. 没有找到站点_为了在家Coding,我搜集了海量的远程站点,然而...
  8. 【Java从0到架构师】日志处理 - SLF4J、Logback、Log4j 2.x
  9. 国产手机的安全漏洞或比勒索病毒还可怕?
  10. winform 通过驱动注册ID检测是否已安装驱动
  11. Vue源码:mustache模板引擎学习
  12. datatables java 分页_DataTables后台分页的使用
  13. visio2013找到密钥以后但是未激活状态
  14. HTML5-jqUI----EasyUI
  15. 光纤通信是不是计算机类的,光纤通信专业属于什么门类
  16. 腰围尺寸2尺1、2、3、4、5、6、7、8寸分别等于是多少厘米/英寸(对照参考表)
  17. 结对开发项目--石家庄地铁web版
  18. 依赖计算机英语作文,2011年高考英语卷写作表达题目范文汇总(39):过度依赖电脑的弊端...
  19. Ubuntu下Meshlab无法链接obj文件或者无法打开外挂硬盘的obj文件
  20. 离人愁用计算机来弹,抖音计算机乐谱有哪些?计算机歌曲乐谱汇总

热门文章

  1. python3.7升级pip_完美解决python3.7 pip升级 拒绝访问问题
  2. python常用的库介绍_Python的标准库介绍与常用的第三方库
  3. 常用html元素的取值和赋值方法总结
  4. spring mvc 页面跳转 携带数据的两种方式
  5. 【BZOJ】1052: [HAOI2007]覆盖问题(贪心)
  6. asp.net连接mssql server的方式
  7. SpringMVC 的运行流程
  8. 51Talk2019战略升级,发布互动教学产品妖果AI
  9. 试炼之石:Performance
  10. SQL Server 两个时间段的差and时间截取到时分