【发布时间】:2015-06-05 04:24:35
【问题描述】:
我正在努力编写一个将虚拟内存地址转换为物理地址的函数。我希望该函数返回一个虚拟 16 位地址的物理内存地址。
我只是使用忽略权限位(读、写等)的 16 位长虚拟地址。页表有 256 页,所以基表寄存器 BTR 只指向该表。
我希望函数返回:
Success: the physical address (a void*)
Page Fault: the virtual page number (an integer)
Protection Fault: a copy of the PTE
这是页表项:
31 30..28 27..............................................4 3 2 1 0
+-----+------+-------------------------------------------------+-+-+-+-+
|Valid|unused| 24-bit Physical Page Number |P|R|W|X|
+-----+------+-------------------------------------------------+-+-+-+-+
我正在尝试了解虚拟内存的工作原理。我对如何获取 16 位虚拟地址并将其映射到 32 位页表条目以及如何从那里获取物理地址感到困惑。我已经定义了result_t 和下面的页表条目的联合,但我不确定如何使用它们。我从网上看得到了很多帮助,但一切都变得混乱了,我只想了解一切是如何直接运作的。
以下是一些必要的定义:
extern void* BTR;
typedef struct result_st {
enum {SUCCESS, PAGEFAULT,
PROTFAULT, NOTIMPLEMENTED} status;
union {
void* pa;
unsigned vpn;
unsigned pte;
} value;
} result_t;
static result_t success(void* pa) {
result_t res;
res.status=SUCCESS;
res.value.pa = pa;
return res;
}
typedef union {
unsigned All;
struct {
unsigned Valid :1;
unsigned Unused :3;
unsigned PhysicalPageNumber :24;
unsigned SupervisoryMode :1;
unsigned Read :1;
unsigned Execute :1;
unsigned Write :1;
};
} PageTableEntry;
static int is_valid (unsigned pte) {
return 1 & (pte >> 31);
}
这是我正在编写的函数:
result_t legacy(unsigned short va)
{
result_t result;
unsigned pte = va << 8;
result.value.pte = pte;
// This is my attempt so far.
// I want to use is_Valid() somewhere
void* pa = pte >> 8 | (va & 255);
return success(pa);
}
感谢您提供的任何建议!
【问题讨论】:
-
页表可能有不同类型,二级、三级等。
-
不是这个,只有一个。
-
不是很依赖平台吗?我希望是的,所以你应该把平台标签和位数。它不能只是通用的 C 问题
-
我提供了地址的页表项、位数和位长。这不是特定于平台的,我正在定义平台。
-
@slippeel:那么它可能设计得很糟糕。如果我假设 32 位虚拟地址和 32 位物理地址,那么您的
page number需要向左移动,因为它位于错误的位置(例如phys = ((entry & mask) << 8) + offset而不是phys = (entry & mask) + offset)并且page number应该是第 12 位改为页表条目的 31。除此之外,每个进程/虚拟地址空间都需要一个完整的页表,这将花费 4 MiB(即使它们只使用其虚拟地址空间的一小部分);所以 ~100 个进程 = ~400 MiB 的 RAM,大部分被浪费了。
标签: c virtual-memory