精华内容
下载资源
问答
  • 内核页表和进程页表

    2021-05-10 06:07:21
    2015 May 28 pagetable,kernel,userspace内核页表和进程页表内核页表和进程页表最近在看vmalloc()分配代码,我们知道当通过alloc_page()分配出来page后,需要将这些分散的物理页框page映射到vmalloc区,这里我们就要...

    2015 May 28 pagetable,kernel,userspace

    内核页表和进程页表

    内核页表和进程页表

    最近在看vmalloc()分配代码,我们知道当通过alloc_page()分配出来page后,需要将这些分散的物理页框page映射到vmalloc区,这里我们就要修改内核页表,以前我学页表是把内核空间与用户空间割裂学习的,导致二者无法很好地衔接,这里我会把两个概念重新解释清楚。

    下面代码映射到vmalloc区的关键就是map_vm_area()函数,for (i = 0; i < area->nr_pages; i++) {

    struct page *page;

    if (node == NUMA_NO_NODE)

    page = alloc_page(alloc_mask);

    else

    page = alloc_pages_node(node, alloc_mask, order);

    ...

    }

    if (map_vm_area(area, prot, pages))

    goto fail;

    return area->addr;

    拿IA32架构的虚拟地址来说,0~3GB属于用户空间,用户空间是由每个进程的task_struct.mm_struct.pgd的成员变量,这个指向的就是进程页表。而3G~4GB属于内核空间,这个页表是由内核页目录表管理,存放在主内核页全局目录init_mm.pgd(swapper_pg_dir)中struct mm_struct init_mm = {

    .mm_rb = RB_ROOT,

    .pgd = swapper_pg_dir,

    .mm_users = ATOMIC_INIT(2),

    .mm_count = ATOMIC_INIT(1),

    .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem),

    .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),

    .mmlist = LIST_HEAD_INIT(init_mm.mmlist),

    INIT_MM_CONTEXT(init_mm)

    };

    进程切换切换的是进程页表:即将新进程的pgd(页目录)加载到CR3寄存器中。而内核页表是所有进程共享的,每个进程的“进程页表”中内核态地址相关的页表项都是“内核页表”的一个拷贝。

    ###vmalloc区发生page fault

    在vmalloc区发生page fault时,将“内核页表”同步到“进程页表”中。这部分区域对应的线性地址在内核使用vmalloc分配内存时,其实就已经分配了相应的物理内存,并做了相应的映射,建立了相应的页表项,但相关页表项仅写入了“内核页表”,并没有实时更新到“进程页表中”,内核在这里使用了“延迟更新”的策略,将“进程页表”真正更新推迟到第一次访问相关线性地址,发生page fault时,此时在page fault的处理流程中进行“进程页表”的更新。

    所以linux中,只有进程的页表是时刻在更换的,而内核页表全局只有一份,所有进程共享内核页表!

    展开全文
  • 初学内核时,经常被“内核页表进程页表”搞晕,不知道这到底是个啥东东,跟我们平时理解的页表有什么关系。内核页表:即书上说的主内核页表,在内核中其实就是一段内存,存放在主内核页全局目录init_mm.pgd...

    初学内核时,经常被“内核页表”和“进程页表”搞晕,不知道这到底是个啥东东,跟我们平时理解的页表有什么关系。

    内核页表:即书上说的主内核页表,在内核中其实就是一段内存,存放在主内核页全局目录init_mm.pgd(swapper_pg_dir)中,硬件并不直接使用。

    进程页表:每个进程自己的页表,放在进程自身的页目录task_struct.pgd中。

    在保护模式下,从硬件角度看,其运行的基本对象为“进程”(或线程),而寻址则依赖于“进程页表”,在进程调度而进行上下文切换时,会进行页表的切换:即将新进程的pgd(页目录)加载到CR3寄存器中。从这个角度看,其实是完全没有用到“内核页表”的,那么“内核页表”有什么用呢?跟“进程页表”有什么关系呢?

    1、内核页表中的内容为所有进程共享,每个进程都有自己的“进程页表”,“进程页表”中映射的线性地址包括两部分:

    用户态

    内核态

    其中,内核态地址对应的相关页表项,对于所有进程来说都是相同的(因为内核空间对所有进程来说都是共享的),而这部分页表内容其实就来源于“内核页表”,即每个进程的“进程页表”中内核态地址相关的页表项都是“内核页表”的一个拷贝。

    2、“内核页表”由内核自己维护并更新,在vmalloc区发生page fault时,将“内核页表”同步到“进程页表”中。以32位系统为例,内核页表主要包含两部分:

    线性映射区

    vmalloc区

    其中,线性映射区即通过TASK_SIZE偏移进行映射的区域,对32系统来说就是0-896M这部分区域,映射对应的虚拟地址区域为TASK_SIZE-TASK_SIZE+896M。这部分区域在内核初始化时就已经完成映射,并创建好相应的页表,即这部分虚拟内存区域不会发生page fault。

    vmalloc区,为896M-896M+128M,这部分区域用于映射高端内存,有三种映射方式:vmalloc、固定、临时,这里就不像述了。

    以vmalloc为例(最常使用),这部分区域对应的线性地址在内核使用vmalloc分配内存时,其实就已经分配了相应的物理内存,并做了相应的映射,建立了相应的页表项,但相关页表项仅写入了“内核页表”,并没有实时更新到“进程页表中”,内核在这里使用了“延迟更新”的策略,将“进程页表”真正更新推迟到第一次访问相关线性地址,发生page fault时,此时在page fault的处理流程中进行“进程页表”的更新:

    /*

    * 缺页地址位于内核空间。并不代表异常发生于内核空间,有可能是用户

    * 态访问了内核空间的地址。

    */

    if (unlikely(fault_in_kernel_space(address))) {

    if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) {

    //检查发生缺页的地址是否在vmalloc区,是则进行相应的处理

    if (vmalloc_fault(address) >= 0)

    return;

    /*

    * 对于发生缺页异常的指针位于vmalloc区情况的处理,主要是将

    * 主内核页表向当前进程的内核页表同步。

    */

    static noinline __kprobes int vmalloc_fault(unsigned long address)

    {

    unsigned long pgd_paddr;

    pmd_t *pmd_k;

    pte_t *pte_k;

    /* Make sure we are in vmalloc area: */

    /* 区域检查 */

    if (!(address >= VMALLOC_START && address 

    return -1;

    WARN_ON_ONCE(in_nmi());

    /*

    * Synchronize this task's top level page-table

    * with the 'reference' page table.

    *

    * Do _not_ use "current" here. We might be inside

    * an interrupt in the middle of a task switch..

    */

    /*获取pgd(最顶级页目录)地址,直接从CR3寄存器中读取。

    *不要通过current获取,因为缺页异常可能在上下文切换的过程中发生,

    *此时如果通过current获取,则可能会出问题*/

    pgd_paddr = read_cr3();

    //从主内核页表中,同步vmalloc区发生缺页异常地址对应的页表

    pmd_k = vmalloc_sync_one(__va(pgd_paddr), address);

    if (!pmd_k)

    return -1;

    //如果同步后,相应的PTE还不存在,则说明该地址有问题了

    pte_k = pte_offset_kernel(pmd_k, address);

    if (!pte_present(*pte_k))

    return -1;

    return 0;

    }

    来源:humjb_1983

    链接:http://blog.chinaunix.net/uid-14528823-id-4334619.html

    展开全文
  • 初始化内核页表

    2021-05-13 07:37:35
    内核维持着一组自己使用的页表,驻留在...)内核页表的初始化化分为2个阶段:第一阶段:在还未启动分页机制下初始化化一个寻址范围在0---8M的内核页表,这个最小限度的地址空间仅能内核装载到RAM对其初始化核心数据...

    内核维持着一组自己使用的页表,驻留在主内核全局目录中,主内核页全局目录的最高目录项部分作为参考模型,为系统中每个普通进程对应的页全局目录项提供参考模型(进程的内核态从oxc0000000-----oxffffffff的线性地址!)

    内核页表的初始化化分为2个阶段:

    第一阶段:在还未启动分页机制下初始化化一个寻址范围在0---8M的内核页表,这个最小限度的地址空间仅能内核装载到RAM和对其初始化核心数据结构。该部分是由startup_32()汇编语言函数实现的(arch/i386/kernel/head.s)以下是startup_32中初始化内核页表的代码片段及其解析:

    page_pde_offset = (__PAGE_OFFSET >> 20);

    movl $(pg0 - __PAGE_OFFSET), %edi

    movl $(swapper_pg_dir - __PAGE_OFFSET), %edx

    movl $0x007, %eax   /* 0x007 = PRESENT+RW+USER */

    10:  /*初始化页目录表*/

    leal 0x007(%edi),%ecx   /* Create PDE entry */

    movl %ecx,(%edx)   /* Store identity PDE entry */

    movl %ecx,page_pde_offset(%edx)  /* Store kernel PDE entry */

    addl $4,%edx

    movl $1024, %ecx   /*设置循环次数*/

    11:              /*初始化页表*/

    stosl

    addl $0x1000,%eax

    loop 11b

    /* End condition: we must map up to and including INIT_MAP_BEYOND_END */

    /* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */

    leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp

    cmpl %ebp,%eax

    jb 10b

    movl %edi,(init_pg_tables_end - __PAGE_OFFSET) /*此时的edi中存放pg0+0x2000,将此值存入init_pg_tables_end中,表示页表初始化结束*/

    .......................................................

    /*

    * Enable paging              启用分页机制

    */

    movl $swapper_pg_dir-__PAGE_OFFSET,%eax

    movl %eax,%cr3  /* set the page table pointer.. */

    movl %cr0,%eax

    orl $0x80000000,%eax

    movl %eax,%cr0  /* ..and set paging (PG) bit */

    注意代码中的子针变量都减去一个线性偏移_PAGE_OFFSET。这是因为在编译内核时。这些变量引用的是启用分页后线性空间的地址。所以为得到实际的物理地址应减去这个线性偏移量。

    第二阶段:初始化最终内核页表,注意此时分页机制已启动。初始化使得从oxc0000000开始的线性地址转化为从0开始的物理地址。

    初始化发生在paging_init()函数中,而该函数位于setup_arch()中,而setup_arch()在start_kernel函数中被调用。

    paging_init()函数执行步骤:

    1:调用pagetable_init建立内核页表;

    2:把swapper_pg_dir的物理地址写道cr3寄存器中;

    3:根据CPU能力及编译内核时的配置,正确的设置cr4的PAE标志位;

    4:调用__flush_tlb_all使得TLB(转换后援缓冲器)的所用项无效。

    重点来看pagetable_init函数:

    该函数首先获得页全局目录的线性地址,然后将其传入kernel_physical_mapping_init函数,该函数最终建立线性地址到物理地址的线性映射关系。kernel_physical_mapping_init代码及解析如下:

    static void __init kernel_physical_mapping_init(pgd_t *pgd_base)

    {

    unsigned long pfn;

    pgd_t *pgd;

    pmd_t *pmd;

    pte_t *pte;

    int pgd_idx, pmd_idx, pte_ofs;

    pgd_idx = pgd_index(PAGE_OFFSET);

    pgd = pgd_base + pgd_idx;

    pfn = 0;

    for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {

    pmd = one_md_table_init(pgd);

    if (pfn >= max_low_pfn)

    continue;

    for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {

    unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET;

    /* Map with big pages if possible, otherwise create normal page tables. */

    if (cpu_has_pse) {

    unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1;

    if (is_kernel_text(address) || is_kernel_text(address2))

    set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC));

    else

    set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));

    pfn += PTRS_PER_PTE;

    } else {

    pte = one_page_table_init(pmd);

    for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) {

    if (is_kernel_text(address))

    set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));

    else

    set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));

    }

    }

    }

    }

    }

    调用结束后还要初始化固定地址映射的线性地址页表代码如下:

    vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;    //将固定地址映射页表放在页全局目录的1023项(最后一项)

    page_table_range_init(vaddr, 0, pgd_base);

    最后为了初始化高地址内存而调用permanent_kmaps_init方法。

    展开全文
  • 进程页表创建详解

    2021-05-09 05:39:43
    copy_mm()(如果是fork一个内核线程kernel thread的话,内核线程将会直接使用当前普通进程页表集,内核线程并不拥有自己的页表集)->dup_mm()->mm_init()->mm_alloc_pgd()->pgd_all...

    [那么每个进程的页表是怎么创建的呢?]

    进程的内核页全局目录的装载过程

    do_fork()->copy_process()->copy_mm()(如果是fork一个内核线程kernel thread的话,内核线程将会直接使用当前普通进程的页表集,内核线程并不拥有自己的页表集)->dup_mm()->mm_init()->mm_alloc_pgd()->pgd_alloc

    pgd_alloc()

    {

    pgd = (pgd_t *)__get_free_page(PGALLOC_GFP)   //为pgd分为一个物理页

    preallocate_pmds(pmds)     //为pmd 页中间目录预先分配页请参考下面的 分析

    preallocate_pmds(pmd_t *pmds[])

    {

    int i;

    bool failed = false;

    for(i = 0; i < PREALLOCATED_PMDS; i++) {  //PREALLOCATED 该宏只有在定义了 CONFIG_X86_PAE即PAE模式时才有用,否则该宏为0,即32位系统在没有开启PAE模式时只使用三级页表机制

    pmd_t *pmd = (pmd_t *)__get_free_page(PGALLOC_GFP);

    if (pmd == NULL)

    failed = true;

    pmds[i] = pmd;

    }

    return 0;

    }     pgd_ctor(mm, pgd)   //将swapper_pg_dir全局页目录(部分后256项--即内核最后1G的虚拟地址,这里指的是内核的页表)拷到pgd里,则可以看出,linux下所有进程的内核页全局目录是一样的,都是swapper_pg_dir里最后的1/4的内容,而每个进程的用户态的页表确是不同的,所以在dup_mmap会去将父进程的页表一项一项的爬出来设置为当前进程的页表。

    pgd_ctor{

    clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,swapper_pg_dir + KERNEL_PGD_BOUNDARY,KERNEL_PGD_PTRS);

    //KERNEL_PGD_BOUNDARY=768,  KERNEL_PGD_PTRS=256    //具体的值见下面的macro

    //将swapper_pg_dir 中的768到1024项拷到pgd里,即所有的进程的内核页是相同的。

    pgd_set_mm(pgd, mm);  pgd->index = mm    建立反向映射吧

    pgd_list_add(pgd);   将pgd加入到pgd_list中去

    }

    进程的用户态地址页拷贝

    dup_mmap()函数实现页表映射的拷贝

    dup_mmap()

    {

    struct vm_area_struct *mpnt,

    for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { //遍历父进程的所有的虚拟地址空间

    tmp = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); //分配一个新的虚拟地址空间

    *tmp = *mpnt;   //将父进程的虚拟地址空间拷贝到新分配的虚拟地址空间中去,并将新分配的虚拟地址空间插入到新进程内存空间中去,这里有两种数据结构,一种是链表用于方便的遍历所有的虚拟地址空间,另一种是红黑树,用来快速的找出适合的虚拟地址空间块

    *pprev = tmp;

    pprev = &tmp->vm_next;

    tmp->vm_prev = prev;

    prev = tmp;

    __vma_link_rb(mm, tmp, rb_link, rb_parent); //插入红黑树中去

    rb_link = &tmp->vm_rb.rb_right;

    rb_parent = &tmp->vm_rb;                retval = copy_page_range(mm, oldmm, mpnt); //最后进行重新映射,要是没有这项(页表复制)的话,即使有合法访问的虚拟存储区域,但是没有正确的页表,不能访问到具体的物理内存,所以为了能建立正确的页映射,使进程能够访问到具体的物理页。

    }

    }

    页表的复制

    copy_page_range()

    {

    dst_pgd = pgd_offset(dst_mm, addr);  //取得pgd

    src_pgd = pgd_offset(src_mm, addr); //取得pgd

    do {

    copy_pud_range();  //拷贝页上级目录

    } while (...)

    }

    copy_pud_range()

    {

    dst_pud = pud_alloc(dst_mm, dst_pgd, addr); //分配一页内存做为页上级表,如果是32位没有开启PAE的话,pud就等于pgd

    src_pud = pud_offset(src_pgd, addr);

    do {

    copy_pmd_range();  //拷贝页中间目录

    } while (...)

    }

    copy_pud_range()

    {

    dst_pmd = pmd_alloc(dst_mm, dst_pud, addr); //分配一页内存做为页中间目录,如果是32位没有开启PAE的话,pud就等于pgd

    src_pmd = pmd_offset(src_pud, addr);

    do {

    copy_pte_range();  //拷贝页表项

    } while (...)

    }

    copy_pte_range

    {

    dst_pte = pte_alloc_map_lock(); //分配大小为一页的页表

    do {

    copy_one_pte() //具体的实现是set_pte_at(dst_mm, addr, dst_pte, pte) 即native_set_pte中的 *dst_pte = pte

    }

    }

    //分配pmd

    static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)

    {

    return (unlikely(pud_none(*pud)) && __pmd_alloc(mm, pud, address))? NULL: pmd_offset(pud, address);

    }

    在32位的non-pae里__pmd_alloc直接返回0,否则__pmd_alloc()分配一页做为pmd

    int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)

    {

    pmd_t *new = pmd_alloc_one(mm, address);  //直接分配一页

    if (!new)

    return -ENOMEM;

    smp_wmb(); /* See comment in __pte_alloc */

    spin_lock(&mm->page_table_lock);

    #ifndef __ARCH_HAS_4LEVEL_HACK

    if (pud_present(*pud))          /* Another has populated it */

    pmd_free(mm, new);

    else

    pud_populate(mm, pud, new);

    #else

    if (pgd_present(*pud))          /* Another has populated it */

    pmd_free(mm, new);

    else

    pgd_populate(mm, pud, new);

    #endif /* __ARCH_HAS_4LEVEL_HACK */

    spin_unlock(&mm->page_table_lock);

    printk (KERN_INFO "wangbo in __pmd_alloc\n");

    return 0;

    }

    [some macro definition]

    #define PAGE_OFFSET 0xc0000000

    #define PGDIR_SHIFT     22

    #define PTRS_PER_PGD    1024

    #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))

    #define KERNEL_PGD_BOUNDARY     pgd_index(PAGE_OFFSET) // 768

    #define KERNEL_PGD_PTRS         (PTRS_PER_PGD - KERNEL_PGD_BOUNDARY) //256

    mm_alloc_pgd() 函数会调用pgd_alloc()会为该进程分配一页(4K)的页全局目录的线性地址并保存在 task_struct->mm_struct->pgd中

    具体的实现是通过__get_free_pages((gfp_mask), 0)实现的,该函数通过alloc_pages()在低端内存里( 小于896M的空间里)分配一个页描述符(struct page *page),并将该页的页描述符通过page_address()转换成虚拟地址。实际上就是通过__va(PFN_PHYS(page_to_pfn(page)))先将页描述符转换成实际物理地址((page - mem_map) << 12 )(所有的物理页描述符存放在mem_map数组里,左移12是一页4K的大小),然后再将物理地址通过__va转换成虚拟地址,也即将得到的低端物理内存地址直接加上PAGE_OFFSET即可 (unsigned long )(x)+PAGE_OFFSET

    到现在可以得知进程描述符里的mm_struct->pgd是线性地址,而且属于内核空间的地址(大于0xc0000000)。

    pte的映射(写时复制机制)

    dup_mm()->dup_mmap 中完成中间页表pmd到页表pte的映射从而建立起页表,并将每一个pte页表,置为只读,以便激发起写时复制技术dup_mmap执行,继续复制pte页表项,使子进程的每个中间页表pmd的每个页表项pte=父进程对应的该pte,并且将该pte最后几个标志位中的只读位置1,从而完成写时复制的准备工作

    cr3寄存器的加载

    cr3寄存器的加载是在进程调度的时候更新的,具体如下

    schedule()->context_switch()->switch_mm()->load_cr3(next->pgd)

    load_cr3加载的是mm_struct->pgd,即线性地址,而实际上加裁到cr3寄存器的是实际的物理地址write_cr3(__pa(pgdir));在装载cr3寄存器时将线性地址通过__pa转换成了物理地址了,所以cr3寄存器是装的是实实在在的物理地址。

    uid-26772137-id-3357318.html

    正在使用的页目录的物理地址存在cr3控制寄存器中

    当要fork一个新的进程时,会先去分配一个物理页(4K)(copy_mm()->dup_mm()->mm_init()中实现)作为该进程的页目录

    32位机器时 4K页里可用1024项,而页目录里的每一项指向一个页表(4K),4K的页表也只有1024项可用,而页表中的每一项又指向具体的一页,所以一个进程的理论可用的空间是1024( 页目录)x1024(页表)x4Kb(每页4K)= 4G(物理页)

    上述说的cr3寄存器装载的是普通进程的页目录首地址,而内核线程使用的是swapper_pg_dir页目录地址

    内核态访问的是线性地址空间,没有线性地址的物理内存是不能被内核访问的,因此,映射就是指将物理内存地址映射到内核线性地址上。这样内核才能访问。

    转载出处:

    展开全文
  • 1.开场白环境:处理器架构:arm64内核源码:linux-5.11ubuntu版本:20.04.1代码阅读工具:vim+ctags+cscope通用操作系统,通常都会开启mmu来支持虚拟...
  • 每个进程共享内核页面目录内容假设三个句子是正确的,让我们说一些进程进入内核模式并更新他的内核页面目录内容(地址映射,访问权限等......)题。由于内核地址空间是在进程之间全局共享的,因此这个更新必须与其他...
  • Motivation:当内核被解压到线性地址0x100000后,为了继续启动内核,即启动内核的第一个swapper进程内核需要建立一张临时页表供其使用。当内核从16位的实模式进入保护模式(通过在汇编代码中的setup函数中设置linux...
  • 内核页表

    2020-12-28 08:14:54
    ng —此page是否全局有效(对所有进程有效)or 只对一个进程有效。 共享内存会进行设置? S — shareable设置, 此page是否让所有cpu共享 apx ap —控制page读写权限 tex c b —控制cache 访问类型 (包括cach
  • linux内核页表

    2021-05-11 01:18:36
    曾 几何时,我一直被迷惑着,我知道所有进程和所有内核线程共享内核页表,也就是在页全局目录的768项以上的目录项指向的页表,我一直以为在创建新的进程的 时候创建新进程的页全局目录的时候会连带的把内核的基础...
  • Linux arm进程内核空间页表同步机制进程创建内核页表修改页表项同步   本文针对ARM32处理器进行说明。...  进程创建,frok时会拷贝内核页表到当前进程页表中。 调用关系: do_dork->copy_process->copy_m
  • Motivation:当内核被解压到线性地址0x100000后,为了继续启动内核,即启动内核的第一个swapper进程内核需要建立一张临时页表供其使用。当内核从16位的实模式进入保护模式(通过在汇编代码中的setup函数中设置linux...
  • CodingNow..17以下讨论基于32位ARM Linux,内核源代码版本为3.9如果您完成设置初始页面表(稍后将被功能覆盖paging_init)转向的过程,则可以解决所有问题.在MMU上.当bootloader首次启动内核时,Assembly函数stext(在...
  • Linux mem 2.3 内核页表隔离 (KPTI) 详解

    千次阅读 2021-01-15 20:12:11
    文章目录1. 背景介绍1.1 Meltdown & Spectre 漏洞1.2 KPTI补丁2. KPTI原理2.1 页表隔离2.2 TLB刷新策略3....KPTI(Kernel page-table isolation)内核页表隔离,把进程页表按照成用户态、内核态独立的
  • 内核空间的页目录表的基地址为swapper_pg_dir,在内核初始化的时候,建立了swapper_pg_dir为基地址的页表,用于fixmap的永久映射区,获取早期的物理地址设备比如设备树等。而后面的线性映射的页表是临时的,在每级...
  • 我在understanding the linux kernel中看到 As a general rule, any process switch implies changing the set of active page ... | 是的,我觉得可能是fork出来的进程,COW机制下,PGD是一样的。
  • 页表的主要作用是完成虚拟地址到物理...但是实际上并不是全部64bit都是用来寻址的,其中一部分bit会基于架构的不同有一样的作用,但是一个最基本的应用是区分当前地址是用户态和内核态的地址。内核可以通过宏CONFIG_A
  • Linux在进程退出的时候,会调用mmput,mmput再调用exit_mmap。先调用unmap_vmas去回收物理页框。unmap_vmas调用unmap_page_range。unmap_page_range使用依次释放pud,pmdpte。相关函数是zap_pud_range,zap_pmd_...
  • 1.开场白本文主要从内存管理和进程管理两个维度来窥探一下fork背后隐藏的技术细节,希望能够通过本文让大家站在一个高度去看进程创建。全文分为两部分讲解:fork的内存管理部分和进程管理部分...
  • Linux下ARM64内核空间分布及页表查询 下面的ko模块可用于查询内核空间及用户程序空间虚拟地址分布及属性,以及查询对应虚拟地址的物理地址。 github地址https://github.com/MaybeYoc/pid_page_tables 在git根目录...
  • 在虚拟内存概念中 – 每个进程都维护自己的页表.此页表将虚拟地址映射到内核虚拟地址.此内核虚拟地址将地址转换为物理RAM.我知道有一个Kernel Virtual adddres – vm area struct.此vm区域结构最终将此地址映射到...
  • 专利名称::操作Linux内核页表加速模拟PowerPC体系结构的方法技术领域::本发明涉及计算机虚拟技术,特别是涉及一种操作Linux内核页表加速模拟PowerPC体系结构的方法。背景技术::随着嵌入式设备普及,例如个人...
  • 进程切换分析(2):TLB处理作者:linuxer 发布于:2017-2-9 12:05分类:进程管理一、前言进程切换是一个复杂的过程,本文不准备详细描述整个进程切换的方方面面,而是关注进程切换中一个小小的知识点:TLB的处理。...
  • 页表

    2021-05-03 11:10:18
    内核要考虑将实际内存划分给进程需要的地址空间,最可取的一个方法就是加一个页表页表来为物理地址分配虚拟地址,进程的地址空间则用虚拟地址表示。如下图所示,不同进程的同一个虚拟地址可能会映射到同一个物理...
  • 对PTE的操作最后一级页表中的项不仅包含了指向页的内存位置的指针,还在上述的多于比特位包含了与页有关的附加信息。尽管这些数据是特定于CPU的,它们至少提供了有关页访问控制的一些信息。下列位在linux内核支持的...
  • Linux内存之页表

    2021-05-10 16:09:33
    Linux的相关页表的框架在 ...针对现在的64位操作系统,Linux已经可以支持4级页表操作,即pgd,pud,pmdpte。但目前一般嵌入式的应用并不会使能该功能,所以在代码中涉及到pudpmd的指针,实际都是指向pgd表项的...
  • 一、用户态、内核内核空间是共享的,存在整个内核的代码所有的内核模块以及内核所维护的数据。进程在运行时一般会处于两种状态:用户态,内核态。用户态是指进程在用户代码中运行。内核态是指进程进入内核代码,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,820
精华内容 11,528
关键字:

windows内核页表和进程页表