【发布时间】:2015-12-07 20:12:07
【问题描述】:
我正在使用 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;
【问题讨论】: