我的项目是在我要用C和汇编语言编写的一小部分内核上执行我自己的JVM。 因此,我仍在学习内核如何完成其主要工作。
现在,按照一些指南,我设置页面调度
.map
mov eax , p3_t
or eax , 0b11
mov dword [p4_t] , eax
mov eax , p2_t
or eax , 0b11
mov dword [p3_t] , eax
mov ecx , 0
.map_pd:
mov eax, 0x200000
mul ecx
or eax , 0b10000011
mov [p2_t+ecx*8] , eax
inc ecx
cmp ecx, 512
jne .map_pd
mov eax, p4_t
mov cr3, eax
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
mov eax, cr0
or eax, 1 << 31
or eax , 1 << 16
mov cr0, eax
这应该设置并启用分页。 不幸的是,这些指南给我的信息很少。
现在,如何在C内核中管理分页和虚拟地址? 你们可以给我一些其他有关分页的指南吗?
答案 0 :(得分:2)
听起来好像您仅启用分页,因为x86-64要求使用分页,并且您实际上并不想将其用于为不同的进程提供自己的虚拟地址空间之类的东西:
一个简单的选择是对所有RAM进行身份映射:物理=虚拟地址。 https://wiki.osdev.org/Setting_Up_Long_Mode#Setting_up_the_Paging
另请参阅https://wiki.osdev.org/Paging和https://wiki.osdev.org/Setting_Up_Paging_With_PAE(x86-64 page-table entry format与32位PAE相同,但使用更多级别。)
1GB的大页面可提供更好的性能(更少的TLB遗漏,以及当您执行TLB遗漏时缩短的页面遍历),并意味着更少的页面表级别和更少的总PTE。在较旧的硬件上2MB的大页面可能是一个不错的选择,但是现代的CPU也对1G页面具有良好的TLB支持。
答案 1 :(得分:2)
我在您的资料中看到的一个问题是,您隐式地假设虚拟和物理地址相同。例如,您链接内核以使其以0x1000000运行,然后以0x1000000复制到内存中。使它可重新定位有一定的优雅之处,也许有对齐限制。
这些说明显示了您的V = P假设:
mov eax , p3_t
or eax , 0b11
mov dword [p4_t] , eax
如果要写入V!= P,则必须通过链接和运行时地址之间的差来调整标签p3_t,p4_t。人们通常喜欢为此使用%ebx;假设您使用的是基于0的细分:
call l1 ; get actual ip.
l1:
pop ebx
sub ebx, offset l1 ; adjust symbols by P - V.
...
mov eax, pl_t[ebx]