linux内存管理之页表

来源:互联网 发布:淘宝联盟佣金怎么算的 编辑:程序博客网 时间:2024/06/05 21:14

什么是页表

页表就是用于将虚拟地址转换为物理地址的转换关系表。访问虚拟地址时,计算机通过页表找到对应的实际物理地址访问。

为何需要多级页表

目前在linux中采用4级页表,ARM32采用2级页表,ARM64采用4级页表。但linux是一个通用性的系统,当ARM32时2级页表也是使用linux的4级页表机制,只是将其它两级页表转换不做任何处理。
那么为什么需要多级页表呢?节省内存空间。二级页表可以在需要的时候才建立。

ARM32页表映射

页表查询

这里写图片描述

内核内存布局

Linux内核在启动的的时候会打印出内核内存空间的布局图。
ARM32内核的内存布局图如下所示。
这里写图片描述

页表建立分析

linux中使用map_desc数据结构完整地描述一个内存空间:

struct map_desc {    unsigned long virtual; //虚拟地址    unsigned long pfn; //页框号    unsigned long length;     unsigned int type;};

建立内核页表的过程

static void __init create_mapping(struct map_desc *md, bool force_pages){    unsigned long addr, length, end;    phys_addr_t phys;    const struct mem_type *type;    pgd_t *pgd;    if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {        printk(KERN_WARNING "BUG: not creating mapping for 0x%08llx"               " at 0x%08lx in user region\n",               (long long)__pfn_to_phys((u64)md->pfn), md->virtual);        return;    }    if ((md->type == MT_DEVICE || md->type == MT_ROM) &&        md->virtual >= PAGE_OFFSET &&        (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {        printk(KERN_WARNING "BUG: mapping for 0x%08llx"               " at 0x%08lx out of vmalloc space\n",               (long long)__pfn_to_phys((u64)md->pfn), md->virtual);    }    type = &mem_types[md->type];//根据mem_types建立页表#ifndef CONFIG_ARM_LPAE    /*     * Catch 36-bit addresses     */    if (md->pfn >= 0x100000) {        create_36bit_mapping(md, type);        return;    }#endif    addr = md->virtual & PAGE_MASK;    phys = __pfn_to_phys(md->pfn);    length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));    if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {        printk(KERN_WARNING "BUG: map for 0x%08llx at 0x%08lx can not "               "be mapped using pages, ignoring.\n",               (long long)__pfn_to_phys(md->pfn), addr);        return;    }    pgd = pgd_offset_k(addr);//计算出pgd    end = addr + length;    do {        unsigned long next = pgd_addr_end(addr, end);        alloc_init_pud(pgd, addr, next, phys, type, force_pages); //建立页表        phys += next - addr;        addr = next;    } while (pgd++, addr != end);}

ARM64页表映射

ARM64一般配置4KB大小页面,48位地址宽度,4级页表映射。

页表查询

这里写图片描述

内核内存布局

64位Linux已经没有了高端内存这个概念了。因为48位的寻址空间已经足够 大。用户空间和内核空间大小均可达256TB。
这里写图片描述

页表建立分析

类似于ARM32.不再描述。

内核页表与进程页表存放

内核页表

内核页表存放于init_mm结构体中的pgd中。其值由swapper_pg_dir决定。
swapper_pg_dir对于ARM32与ARM64值的计算方法不一样。
如ARM32时:

.globl  swapper_pg_dir    .equ    swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE

即kernel运行地址的前16k( PG_DIR_SIZE)

进程页表

每个进程都有自己的页表,存放于task_struct结构体中的pgd中。

原创粉丝点击