superwujc 发表于 2016-06-06 13:50

linux x86内存分页时,pgd与cr3的疑问

请教各位高手

每个进程都有独立的PGD,保存在当前进程的内存描述符mm_struct的pgd字段中,而该字段的值是从cr3中加载

但我通过运行以下内核模块,打印cr3与pgd的值时,发现二者并不一致#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <asm/pgtable.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>

static int __init show_pgd(void)
{
        unsigned long cr3, pgd_entry_index;
        struct mm_struct *mm;
        pgd_t *pgdir, *pgd_entry;
        unsigned long vaddr = 0;
        vaddr = (unsigned long)vmalloc(1000 * sizeof(char));
        if (vaddr == 0) {
                printk("vmalloc failed..\n");
                return -1;
        }
        printk("vmalloc_vaddr=0x%lx\n", vaddr);

        cr3 = read_cr3();
        mm = current->mm;
        pgdir = mm->pgd;
        pgd_entry = pgd_offset(current->mm, vaddr);
        pgd_entry_index = pgd_index(vaddr);

        printk("cr3 = 0x%lx\n", cr3);
        printk("pgdir = 0x%lx\n", pgd_val(*pgdir));
        printk("pgd_entry = 0x%lx\n", pgd_val(*pgd_entry));
        printk("pgd_entry_index = %ld\n", pgd_entry_index);

        vfree((void*)vaddr);

        return 0;
}

static void __exit finish(void)
{
        printk("The module is exit\n");
}

module_init(show_pgd);
module_exit(finish);
MODULE_LICENSE("GPL");
make并insmod,dmesg查看结果vmalloc_vaddr=0xffffc90009852000
cr3 = 0x36b9a000
pgdir = 0x3a2e1067
pgd_entry = 0x3fad8067
pgd_entry_index = 402PGD的值为0x3a2e1067,而cr3中的值为0x36b9a000

此处不解,请各位指点一下,谢谢。

qianguozheng 发表于 2016-06-06 19:15

cr3是什么玩意。。。

qianguozheng 发表于 2016-06-06 19:21

http://bbs.chinaunix.net/thread-2091410-1-1.html

superwujc 发表于 2016-06-07 05:26

回复 3# qianguozheng

感谢,但不知道楼上想说什么?
   

nswcfd 发表于 2016-06-07 14:09

回答不了楼主cr3和pgd不一致问题,但是用vmalloc做测试貌似是有问题的,
vmalloc修改的是init_mm的页表,而不是current->mm。——当然产生一次缺页中断之后就一致了。

superwujc 发表于 2016-06-07 15:23

回复 5# nswcfd

感谢楼上,cr3与current->mm->pgd确实是一致的,进程context 切换后,current->mm->pgd相当于二级指针,自身是一个地址,另指向页全局目录PGD的地址#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <asm/pgtable.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>

static int __init show_pgd(void)
{
        unsigned long cr3, vaddr, pgd_entry_index;
        pgd_t *pgdir, *pgd_entry;
        vaddr = (unsigned long)vmalloc(1000 * sizeof(char));
        if (vaddr == 0) {
                printk("vmalloc failed..\n");
                return -1;
        }
        printk("vmalloc_vaddr=0x%lx\n", vaddr);

        cr3 = read_cr3();
        pgdir = current->mm->pgd;
        pgd_entry = pgd_offset(current->mm, vaddr);
        pgd_entry_index = pgd_index(vaddr);

        printk("cr3 = 0x%lx\n", cr3);
        printk("virtual pgd = %p\n", pgdir);
        printk("physical pgd = 0x%lx\n", __pa(pgdir));
        printk("pgd_entry = 0x%lx\n", pgd_val(*pgd_entry));
        printk("pgd_entry_index = %ld\n", pgd_entry_index);

        vfree((void*)vaddr);

        return 0;
}

static void __exit finish(void)
{
        printk("The module is exit\n");
}

module_init(show_pgd);
module_exit(finish);
MODULE_LICENSE("GPL");
运行结果为vmalloc_vaddr=0xffffc90009c2d000
cr3 = 0x38be9000
virtual pgd = ffff880038be9000
physical pgd = 0x38be9000
pgd_entry = 0x3fad8067
pgd_entry_index = 402另请教一下

怎样在kernel module中自行处理page fault,也就是pte不存在时手动分配页帧?

nswcfd 发表于 2016-06-12 16:43

不是很清楚,或许现有的page fault流程有hook或者notifier可以使用,但不知道是否能够完全替代kernel自身的流程。
页: [1]
查看完整版本: linux x86内存分页时,pgd与cr3的疑问