- 页表机制做了哪些事?
页表确定了什么是内存地址,以及可访问哪些部分的物理内存。
- 页表机制实现了哪些目标?
- 操作系统给每个进程提供了私有的地址空间和内存;
- xv6隔离不同进程的地址空间,多路复用不同进程到同一个物理内存上;
- 提供了一种间接性,允许xv6执行若干个技巧:映射若干个地址空间到相同的内存,使用未映射的页来保护内核栈和用户栈。
本章的剩余部分解释了RISC-V硬件提供的页表机制,以及xv6是如何使用页表机制的。
第3.6节 进程的地址空间
每个进程都有一个单独的页表。
当xv6在进程间切换时,xv6也会修改页表。
一个进程的用户内存从0开始,可增长到MAXVA
,理论上允许一个进程在256GB大的内存中寻址。
当一个进程向xv6请求更多的内存时,xv6会做3件事:
- 使用
kalloc
函数来分配物理内存; - 向进程的页表中添加页表项PTEs,使得页表指向新的物理页;
- 设置这些页表项中的
PTE_R
、PTE_X
、PTE_W
、PTE_U
、PTE_V
等标记;
注意,
- 大部分进程不使用整个用户地址空间。
- 对那些未使用的页表项,xv6不设置其
PTE_V
标记。
3个很好的页表使用举例
例1 不同进程的页表将用户地址转换到物理内存的不同页,使得每个进程有自己私有的用户内存。
例2 每个进程认为自己的内存是从0开始的连续的虚拟地址,而进程的物理内存可以是不连续的。
例3 内核将带有trampoline代码的物理页映射到用户地址空间的顶部,使得这样的一个单独的物理内存的页出现在所有的地址空间里。
在xv6中,一个正在执行的进程的用户内存的布局是怎样的?
栈是一个单独的页,图中展示的是exec创建该栈时的初始内容。
栈顶的内容是包含有命令行参数、指向命令行参数的指针数组等。
在栈顶下是一些值,允许一个程序从main处开始,好像函数main(argc,argv)刚被调用一样。
如何检测用户栈溢出?
xv6在栈的下面放置了一个无效的保护页。
如果用户栈溢出了,进程会尝试使用在栈之下的地址,则硬件会生成一个页面故障,因为这个映射是无效的。
注意,当用户栈溢出时,真实世界里的操作系统可能会自动为其分配更多的内存。
网友评论