[英]how can I implement paging , and find physical memory address knowing virtual address
I want to implement the initialisation of paging .我想实现 paging 的初始化。 Referring to some links of osdev wiki : https://wiki.osdev.org/Paging , https://wiki.osdev.org/Setting_Up_Paging , my own version is very different.
参考 osdev wiki 的一些链接: https://wiki.osdev.org/Paging , https://wiki.osdev.org/Setting_Up_Paging ,我自己的版本非常不同。 Because , when we look at the page directory , they said that 12 bits is for the flag and the rest is for the address of the page table , so I tried something like this:
因为,当我们查看页目录时,他们说12位是标志,其余的是页表地址,所以我尝试了这样的事情:
void init_paging() {
unsigned int i = 0;
unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000)));
for (i = 0; i < 0x400; i++) __PAGE_DIRECTORY__[i] = PAGE_PRESENT(0) | PAGE_READ_WRITE;
for (i = 0; i < 0x400; i++) __FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
__PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__ << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
_EnablingPaging_();
}
this function help me to know the physical address knowing the virtual address :这个函数帮助我知道物理地址知道虚拟地址:
void *get_phyaddr(void *virtualaddr) {
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
unsigned long *pd = (unsigned long *)__PAGE_DIRECTORY__[pdindex];
unsigned long *pt = (unsigned long *)pd[ptindex];
return (void *)(pt + ((unsigned int)virtualaddr & 0xFFF));
} }
I'm in the wrong direction?我走错方向了?
Or still the same?还是还是一样?
Assuming you're trying to identity map the first 4 MiB of the physical address space:假设您正在尝试对物理地址空间的前 4 MiB 进行身份映射:
a) for unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000)));
a) 对于
unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000)));
it's a local variable (eg likely put on the stack);它是一个局部变量(例如可能放在堆栈中); and it will not survive after the function returns (eg the stack space it was using will be overwritten by other functions later), causing the page table to become corrupted.
并且在函数返回后它将无法生存(例如,它使用的堆栈空间稍后将被其他函数覆盖),从而导致页表损坏。 That isn't likely to end well.
这不太可能有好结局。
b) For __FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
b) 对于
__FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
__FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
, you're shifting i
twice, once with * 0x1000
(which is the same as << 12
) and again with the << 12
. ,您将
i
移动两次,一次使用* 0x1000
(与<< 12
相同),再次使用<< 12
。 This is too much, and it needs to be more like __FIRST_PAGE_TABLE__[i] = (i << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
这太多了,需要更像
__FIRST_PAGE_TABLE__[i] = (i << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
__FIRST_PAGE_TABLE__[i] = (i << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
. .
c) For __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__ << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
c) 对于
__PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__ << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
__PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__ << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
, the address is already an address (and not a "page number" that needs to be shifted), so it needs to be more like __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
,地址已经是地址(而不是需要移位的“页码”),所以需要更像
__PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
__PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
. .
Beyond that;除此之外; I'd very much prefer better use of types.
我非常喜欢更好地使用类型。 Specifically;
具体来说; you should probably get in the habit of using
uint32_t
(or uint64_t
, or a typedef
of your own) for physical addresses to make sure you don't accidentally confuse a virtual address with a physical address (and make sure the compiler complains abut the wrong type when you make a mistake);您可能应该养成使用
uint32_t
(或uint64_t
,或您自己的typedef
)作为物理地址的习惯,以确保您不会意外地将虚拟地址与物理地址混淆(并确保编译器抱怨错误出错时输入); because (even though it's not very important now because you're identity mapping) it will become important "soon".因为(即使它现在不是很重要,因为您正在进行身份映射)它将“很快”变得重要。 I'd also recommend using
uint32_t
for page table entries and page directory entries, because they must be 32 bits and not "whatever size the compiler felt like int
should be" (note that this is a difference in how you think about the code, which is more important than what the compiler actually does or whether int
happens to be 32 bits anyway).我还建议将
uint32_t
用于页表条目和页目录条目,因为它们必须是 32 位,而不是“编译器认为int
应该是什么大小”(请注意,这与您对代码的看法有所不同,这比编译器实际执行的操作或int
是否恰好是 32 位更重要)。
When we ask page , but the page was not present , we have pageFault Interrupt
.当我们询问页面,但页面不存在时,我们有
pageFault Interrupt
。 SO to avoid that , we can check if the page is there , else , i choice to return 0x0
:为了避免这种情况,我们可以检查页面是否存在,否则,我选择返回
0x0
:
physaddr_t *get_phyaddr(void *virtualaddr) {
uint32_t pdindex = (uint32_t)virtualaddr >> 22;
uint32_t ptindex = (uint32_t)virtualaddr >> 12 & 0x03FF;
uint32_t *pd, *pt, ptable;
if ((page_directory[pdindex] & 0x3) == 0x3) {
pd = (uint32_t *)(page_directory[pdindex] & 0xFFFFF000);
if ((pd[ptindex] & 0x3) == 0x3) {
ptable = pd[ptindex] & 0xFFFFF000;
pt = (uint32_t *)ptable;
return (physaddr_t *)(pt + ((uint32_t)(virtualaddr)&0xFFF));
} else
return 0x0;
} else
return 0x0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.