设为首页 加入收藏

TOP

Linux-3.14.12内存管理笔记【构建内存管理框架(2)】(一)
2019-10-09 20:00:12 】 浏览:136
Tags:Linux-3.14.12 内存 管理 笔记 构建 框架

前面构建内存管理框架,已经将内存管理node节点设置完毕,接下来将是管理区和页面管理的构建。此处代码实现主要在于setup_arch()下的一处钩子:x86_init.paging.pagetable_init()。据前面分析可知x86_init结构体内该钩子实际上挂接的是native_pagetable_init()函数。

native_pagetable_init():

【file:/arch/x86/mm/init_32.c】
void __init native_pagetable_init(void)
{
    unsigned long pfn, va;
    pgd_t *pgd, *base = swapper_pg_dir;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *pte;
 
    /*
     * Remove any mappings which extend past the end of physical
     * memory from the boot time page table.
     * In virtual address space, we should have at least two pages
     * from VMALLOC_END to pkmap or fixmap according to VMALLOC_END
     * definition. And max_low_pfn is set to VMALLOC_END physical
     * address. If initial memory mapping is doing right job, we
     * should have pte used near max_low_pfn or one pmd is not present.
     */
    for (pfn = max_low_pfn; pfn < 1<<(32-PAGE_SHIFT); pfn++) {
        va = PAGE_OFFSET + (pfn<<PAGE_SHIFT);
        pgd = base + pgd_index(va);
        if (!pgd_present(*pgd))
            break;
 
        pud = pud_offset(pgd, va);
        pmd = pmd_offset(pud, va);
        if (!pmd_present(*pmd))
            break;
 
        /* should not be large page here */
        if (pmd_large(*pmd)) {
            pr_warn("try to clear pte for ram above max_low_pfn: pfn: %lx pmd: %p pmd phys: %lx, but pmd is big page and is not using pte !\n",
                pfn, pmd, __pa(pmd));
            BUG_ON(1);
        }
 
        pte = pte_offset_kernel(pmd, va);
        if (!pte_present(*pte))
            break;
 
        printk(KERN_DEBUG "clearing pte for ram above max_low_pfn: pfn: %lx pmd: %p pmd phys: %lx pte: %p pte phys: %lx\n",
                pfn, pmd, __pa(pmd), pte, __pa(pte));
        pte_clear(NULL, va, pte);
    }
    paravirt_alloc_pmd(&init_mm, __pa(base) >> PAGE_SHIFT);
    paging_init();
}

该函数的for循环主要是用于检测max_low_pfn直接映射空间后面的物理内存是否存在系统启动引导时创建的页表,如果存在,则使用pte_clear()将其清除。

接下来的paravirt_alloc_pmd()主要是用于准虚拟化,主要是使用钩子函数的方式替换x86环境中多种多样的指令实现。

再往下的paging_init():

【file:/arch/x86/mm/init_32.c】
/*
 * paging_init() sets up the page tables - note that the first 8MB are
 * already mapped by head.S.
 *
 * This routines also unmaps the page at virtual kernel address 0, so
 * that we can trap those pesky NULL-reference errors in the kernel.
 */
void __init paging_init(void)
{
    pagetable_init();
 
    __flush_tlb_all();
 
    kmap_init();
 
    /*
     * NOTE: at this point the bootmem allocator is fully available.
     */
    olpc_dt_build_devicetree();
    sparse_memory_present_with_active_regions(MAX_NUMNODES);
    sparse_init();
    zone_sizes_init();
}

paging_init()主要都是函数调用,现在逐一分析各个函数功能,先看pagetable_init():

【file:/arch/x86/mm/init_32.c】
static void __init pagetable_init(void)
{
    pgd_t *pgd_base = swapper_pg_dir;
 
    permanent_kmaps_init(pgd_base);
}

其中kmap_get_fixmap_pte():

【file:/arch/x86/mm/init_32.c】
static inline pte_t *kmap_get_fixmap_pte(unsigned long vaddr)
{
    return pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr),
            vaddr), vaddr), vaddr);
}

可以很容易看到kmap_init()主要是获取到临时映射区间的起始页表并往临时映射页表变量kmap_pte置值,并置页表属性kmap_prot为PAGE_KERNEL。

paging_init()中,由于没有开启CONFIG_OLPC配置,故olpc_dt_build_devicetree()为空函数,暂不分析。同样,前面提及的sparse_memory_present_with_active_regions()和sparse_init()也暂不分析。

最后看一下zone_sizes_init():

【file:/arch/x86/mm/init.c】
void __init zone_sizes_init(void)
{
    unsigned long max_zone_pfns[MAX_NR_ZONES];
 
    memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
 
#ifdef CONFIG_ZONE_DMA
    max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
#endif
#ifdef CONFIG_ZONE_DMA32
    max_z
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇嵌入式 02 STM32 07串口通信 下一篇Linux-3.14.12内存管理笔记【构建..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目