• 非连续内存区缺页异常处理


        在进入正题之前先看看vmalloc是怎么申请内存的(虽然在前面的文章中已经说过了)。管理vmalloc分配空间用到的数据结构是vm_struct。首先用slab分配一个vm_struct实例,然后从vm_struct链表中找到一个合适的位置准备插入这个实例。这个实例只是用来管理这块内存的,那下面就开始申请这些内存,也就是一页一页地从buddy system中分配单页来填充一个page数组(这就是vmalloc分配得到的内存)。那怎么访问这些分配的内存呢?下面就逐层地建立pgd、pmd、pte结构中的值。释放vmalloc申请的空间的过程就是逆过来的。

        下面进入正题!

        在逐层建立pgd、pmd、pte的时候并不触及当前进程的页表,因此当内核态的进程在访问非连续内存区时就会发生缺页(进程页表中的表项为空)。处理程序先检查这个缺页线性地址是否在主内核页表中(init_mm.pgd),如果发现就把对应的值拷贝到进程的页表项中,然后恢复进程的执行。

    static int vmalloc_fault(unsigned long address)
    {
    unsigned
    long pgd_paddr;
    pmd_t
    *pmd_k;
    pte_t
    *pte_k;
    pgd_paddr
    = read_cr3();
    pmd_k
    = vmalloc_sync_one(__va(pgd_paddr), address);
    if (!pmd_k)
    return -1;
    pte_k
    = pte_offset_kernel(pmd_k, address);
    if (!pte_present(*pte_k))
    return -1;
    return 0;
    }

        通过read_cr3函数可以获得当前进程页全局目录的物理地址。然后调用vmalloc_sync_one获得pmd_k,下面看一下这个函数的实现:

    static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
    {
    unsigned index
    = pgd_index(address);
    pgd_t
    *pgd_k;
    pud_t
    *pud, *pud_k;
    pmd_t
    *pmd, *pmd_k;
    pgd
    += index;
    pgd_k
    = init_mm.pgd + index;
    if (!pgd_present(*pgd_k))
    return NULL;
    pud
    = pud_offset(pgd, address);
    pud_k
    = pud_offset(pgd_k, address);
    if (!pud_present(*pud_k))
    return NULL;
    pmd
    = pmd_offset(pud, address);
    pmd_k
    = pmd_offset(pud_k, address);
    if (!pmd_present(*pmd_k))
    return NULL;
    if (!pmd_present(*pmd)) {
    set_pmd(pmd,
    *pmd_k);
    arch_flush_lazy_mmu_mode();
    }
    else
    BUG_ON(pmd_page(
    *pmd) != pmd_page(*pmd_k));
    return pmd_k;
    }

        从init_mm.pgd中取得对应的项,这样开始逐层检查address对应的项是否存在。直到检查到pmd的时候如果还存在的话就设置pmd然后返回。刚开始看的时候这里有点不明白:为什么只是设置pmd?pgd、pud就不管了吗?如果仔细想一想内核中多层页表的结构就清楚了,设置这些只是一些冗余的操作。但是再返回来想一下,如果设置了pgd的话还需要设置pmd吗?因为设置了pgd后找到的pmd也不是过去所能找到的那个pmd了。感慨一下自己的逻辑思维的漏洞百出。看完缺页处理之后对vmalloc分配内存的利用也有了进一步地理解。:)

        然后检查一下pte,返回对应的结果。

    ------------------------------------

    个人理解,欢迎拍砖。

  • 相关阅读:
    vue --- 脚手架初始化项目中配置文件webpack.base.conf.js代码含义
    Chrome
    es8 --- 新特性
    es7 --- 新特性
    vue --- 关于多个router-view视图组件,渲染同一页面
    vue ---- 组件传值之间使用 v-model
    vue --- watch 高级用法
    js --- 递归结构图
    es6 --- Generator 函数
    es6 -- set 数据结构
  • 原文地址:https://www.cnblogs.com/ggzwtj/p/2145067.html
Copyright © 2020-2023  润新知