位移以在Linux中查找给定虚拟地址的页表条目

时间:2015-12-07 20:12:07

标签: linux kernel paging

我正在使用Linux 3.18.20的简化版本,我需要创建两个新的系统调用:一个读取给定虚拟地址的页表项,另一个写入对应的页表项给定的虚拟地址。我一直在使用英特尔架构参考手册,卷。 3,第4章,第5节,了解虚拟地址如何转换为物理地址,并且为了实现我的系统调用,我创建了一个辅助函数,它返回所请求的页表项的虚拟地址(或NULL,如果该页表条目不存在)。

我创建了一个测试程序,它创建了一个局部变量(可能存储在堆栈中,对吗?)并将其虚拟地址传递给我的系统调用,以确保我的翻译正确完成。然后,我手动完成所有的移位操作,以确保我的代码完成我认为的操作;它似乎是正确的,所以我在这一点上得出的唯一结论是,我不知道我不知道的是什么;我需要一条至关重要的信息,我甚至没有意识到我需要这些信息。

你能看一下我的代码,并告诉我是否有一些明显的我做错了吗?

unsigned long *find_pte(unsigned long vaddr) {
    unsigned long cr3, pml4_addr, pml4e, pml4e_addr;
    unsigned long pdpt_addr, pdpte_addr, pdpte;
    unsigned long pd_addr, pde_addr, pde;
    unsigned long pt_addr, pte_addr;
    unsigned long vaddr30thru38, vaddr39thru47, vaddr21thru29, vaddr12thru20;

    cr3 = (unsigned long) get_pagetable();
    /* get_pageable() is a helper function, provided by my professor,
    that supposedly returns the contents of the CR3 register, with the most
    significant and least significant 12 bits replaced with 0.*/
    printk("in syscall: vaddr=%lx, cr3=%lx\n", vaddr, cr3);//DEBUG
    pml4_addr = cr3;
    vaddr39thru47 = (vaddr >> 36) & 0xff8;
    printk("in syscall: vaddr39thru47=%lx\n", vaddr39thru47);//DEBUG
    pml4e_addr = pml4_addr | vaddr39thru47;
    printk("in syscall: physical pml4e_addr=%lx\n", pml4e_addr);//DEBUG
    pml4e_addr = (unsigned long) __va(pml4e_addr);
    printk("in syscall: virtual pml4e_addr=%lx\n", pml4e_addr);//DEBUG
    pml4e = *((unsigned long*) pml4e_addr);
    printk("in syscall: pml4e=%lx\n", pml4e);//DEBUG
    if ((pml4e & 1) == 0) {
            printk("in syscall: pml4e's valid bit is not set\n");//DEBUG
            return NULL;
    }
    printk("in syscall: pml4e's valid bit is set\n");//DEBUG

    vaddr30thru38 = (vaddr >> 27) & 0xff8;
    printk("in syscall: vaddr30thru38=%lx\n", vaddr30thru38);
    pdpte_addr = (pdpt_addr | vaddr30thru38);
    printk("in syscall: physical pdpte_addr=%lx\n", pdpte_addr);//DEBUG
    pdpte_addr = (unsigned long) __va(pdpte_addr);
    printk("in syscall: virtual pdpte_addr=%lx\n", pdpte_addr);//DEBUG
    pdpte = *((unsigned long*) pdpte_addr);
    printk("in syscall: pdpte=%lx\n", pdpte);//DEBUG
    if (((pdpte >> 7) & 1) == 1) {
            printk("in syscall: pdpte's ps flag is 1\n");//DEBUG
            return (unsigned long*) pdpte_addr;
    }
    printk("in syscall: pdpte's ps flag is 0\n");//DEBUG
    if ((pdpte & 1) == 0) {
            printk("in syscall: pdpte's valid bit is not set\n");//DEBUG
            return NULL;
    }
    printk("in syscall: pdpte's valid bit is set\n");//DEBUG
    pd_addr = pdpte & 0x000ffffffffff000;
    printk("in syscall: pd_addr=%lx\n", pd_addr);//DEBUG
    vaddr21thru29 = (vaddr >> 18) & 0xff8;
    printk("in syscall: vaddr21thru29=%lx\n", vaddr21thru29);//DEBUG
    pde_addr = pd_addr | vaddr21thru29;
    printk("in syscall: physical pde_addr=%lx\n", pde_addr);//DEBUG
    pde_addr = (unsigned long) __va(pde_addr);
    printk("in syscall: virtual pde_addr=%lx\n", pde_addr);//DEBUG
    pde = *((unsigned long*) pde_addr);
    printk("in syscall: pde=%lx\n", pde);//DEBUG
    if (((pde >> 7) & 1) == 1) {
            printk("in syscall: pde's ps flag is 1\n");//DEBUG
            return (unsigned long*) pde_addr;
    }
    printk("in syscall: pde's ps flag is 0\n");//DEBUG
    if ((pde & 1) == 0) {
            printk("in syscall: pde's valid bit is not set\n");//DEBUG
            return NULL;
    }
    printk("in syscall: pde's valid bit is set\n");//DEBUG
    pt_addr = pde & 0x000ffffffffff000;
    printk("in syscall: pt_addr=%lx\n", pt_addr);//DEBUG
    vaddr12thru20 = (vaddr >> 9) & 0xff8;
    printk("in syscall: vaddr12thru20=%lx\n", vaddr12thru20);//DEBUG
    pte_addr = pt_addr | vaddr12thru20;
    printk("in syscall: physical pte_addr=%lx\n", pte_addr);//DEBUG
    pte_addr = (unsigned long) __va(pte_addr);
    return (unsigned long*) pte_addr;

1 个答案:

答案 0 :(得分:1)

没关系。我的代码没有任何问题(除了省略一行,将代码从我的文件复制到Stack Overflow时出错)。我的测试错误地将其标记为已损坏。