我如何实现分页,并通过虚拟地址找到物理内存地址

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我如何实现分页,并通过虚拟地址找到物理内存地址相关的知识,希望对你有一定的参考价值。

我想实现分页的初始化。关于osdev Wiki的一些链接:https://wiki.osdev.org/Paginghttps://wiki.osdev.org/Setting_Up_Paging,我自己的版本非常不同。因为,当我们查看page directory时,他们说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_();
 

此功能帮助我知道物理地址,也知道虚拟地址:

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));

我的方向错误?

还是还是一样?

答案

假设您正在尝试标识物理地址空间的前4个MiB:

a]对于unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000)));,它是一个局部变量(例如,可能放在堆栈上);并且该函数返回后将无法生存(例如,其使用的堆栈空间稍后将被其他函数覆盖),从而导致页表损坏。这样的结局不太可能。

b]对于__FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;,您要移动i两次,一次是使用* 0x1000(与<< 12相同),另一次是<< 12。这太多了,它需要更像__FIRST_PAGE_TABLE__[i] = (i << 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__) | PAGE_PRESENT(1) | PAGE_READ_WRITE;

除此之外;我非常希望更好地使用类型。特别;您可能应该养成使用uint32_t(或uint64_t或您自己的typedef)作为物理地址的习惯,以确保您不会将虚拟地址与物理地址相混淆(并确保当您犯错时,编译器会抱怨错误的类型);因为(即使现在由于身份映射它现在还不是很重要),它很快就会变得很重要。我还建议对页表条目和页目录条目使用uint32_t,因为它们必须为32位,而不是“编译器感觉为int应该是什么大小”(请注意,这与您的想法有所不同有关代码的信息,这比编译器实际执行的操作或int是否恰好是32位更重要)。

以上是关于我如何实现分页,并通过虚拟地址找到物理内存地址的主要内容,如果未能解决你的问题,请参考以下文章

操作系统实现之内存分页机制.虚拟空间

操作系统实现之内存分页机制.虚拟空间

操作系统实现之内存分页机制.虚拟空间

内存管理

linux进程内存相关

虚拟记忆效应以及分页和分段之间的关系