linux内存管理之页表

什么是页表

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

为何需要多级页表

目前在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中。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值