设为首页 加入收藏

TOP

Linux-3.14.12内存管理笔记【建立内核页表(2)】-低端内存的建立(一)
2019-09-30 16:44:13 】 浏览:99
Tags:Linux-3.14.12 内存 管理 笔记 建立 内核 低端

前面的前奏已经分析介绍了建立内核页表相关变量的设置准备,接下来转入正题分析内核页表的建立。

建立内核页表的关键函数init_mem_mapping():

【file:/arch/x86/mm/init.c】
void __init init_mem_mapping(void)
{
    unsigned long end;
 
    probe_page_size_mask();
 
#ifdef CONFIG_X86_64
    end = max_pfn << PAGE_SHIFT;
#else
    end = max_low_pfn << PAGE_SHIFT;
#endif
 
    /* the ISA range is always mapped regardless of memory holes */
    init_memory_mapping(0, ISA_END_ADDRESS);
 
    /*
     * If the allocation is in bottom-up direction, we setup direct mapping
     * in bottom-up, otherwise we setup direct mapping in top-down.
     */
    if (memblock_bottom_up()) {
        unsigned long kernel_end = __pa_symbol(_end);
 
        /*
         * we need two separate calls here. This is because we want to
         * allocate page tables above the kernel. So we first map
         * [kernel_end, end) to make memory above the kernel be mapped
         * as soon as possible. And then use page tables allocated above
         * the kernel to map [ISA_END_ADDRESS, kernel_end).
         */
        memory_map_bottom_up(kernel_end, end);
        memory_map_bottom_up(ISA_END_ADDRESS, kernel_end);
    } else {
        memory_map_top_down(ISA_END_ADDRESS, end);
    }
 
#ifdef CONFIG_X86_64
    if (max_pfn > max_low_pfn) {
        /* can we preseve max_low_pfn ?*/
        max_low_pfn = max_pfn;
    }
#else
    early_ioremap_page_table_range_init();
#endif
 
    load_cr3(swapper_pg_dir);
    __flush_tlb_all();
 
    early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
}

其中probe_page_size_mask()实现:

【file:/arch/x86/mm/init.c】
static void __init probe_page_size_mask(void)
{
    init_gbpages();
 
#if !defined(CONFIG_DEBUG_PAGEALLOC) && !defined(CONFIG_KMEMCHECK)
    /*
     * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
     * This will simplify cpa(), which otherwise needs to support splitting
     * large pages into small in interrupt context, etc.
     */
    if (direct_gbpages)
        page_size_mask |= 1 << PG_LEVEL_1G;
    if (cpu_has_pse)
        page_size_mask |= 1 << PG_LEVEL_2M;
#endif
 
    /* 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);
        __supported_pte_mask |= _PAGE_GLOBAL;
    }
}

probe_page_size_mask()主要作用是初始化直接映射变量(在init_gbpages()里面)和对page_size_mask变量进行设置,以及根据配置来控制CR4寄存器的置位,用于后面分页时的页面大小情况判定。

回到init_mem_mapping()继续往下走,接着是init_memory_mapping(),其中入参ISA_END_ADDRESS表示ISA总线上设备的地址末尾。

init_mem_mapping()实现:

【file:/arch/x86/mm/init.c】
/*
 * Setup the direct mapping of the physical memory at PAGE_OFFSET.
 * This runs before bootmem is initialized and gets pages directly from
 * the physical memory. To access them they are temporarily mapped.
 */
unsigned long __init_refok init_memory_mapping(unsigned long start,
                           unsigned long end)
{
    struct map_range mr[NR_RANGE_MR];
    unsigned long ret = 0;
    int nr_range, i;
 
    pr_info("init_memory_mapping: [mem %#010lx-%#010lx]\n",
           start, end - 1);
 
    memset(mr, 0, sizeof(mr));
    nr_range = split_mem_range(mr, 0, start, end);
 
    for (i = 0; i < nr_range; i++)
        ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
                           mr[i].page_size_mask);
 
    add_pfn_range_mapped(start >> PAGE_SHIFT, ret >> PAGE_SHIFT);
 
    return ret >> PAGE_SHIFT;
}

init_mem_mapping()里面关键操作有三个split_mem_range()、kernel_physical_mapping_init()和add_pfn_range_mapped()函数。

首先分析一下split_mem_range():

【file:/arch/x86/mm/init.c】
static int __meminit split_mem_range(struct map_ran
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇USART_FLAG_TXE和USART_FLAG_TC 下一篇嵌入式02 STM32 实验06 按键

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目