简体   繁体   English

如何实现分页,并在知道虚拟地址的情况下找到物理内存地址

[英]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/Paginghttps://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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM