Intel 80386中的CR0寄存器WP位与OS内核写操作的关系:以MIT6.828中的仿真实验环境为例

在80386中,CR系列寄存器被称为控制寄存器,用于改变或控制CPU或其他数字设备的一般行为。控制寄存器执行的常见任务包括中断控制、切换寻址模式、分页控制和协处理器控制。

CR寄存器有32位二进制数,CR0主要控制保护模式的开启以及分页模式的开启等等,其中,第十六位bit被称为"WP"位,即 Write Protection 写保护位,这一位的功能比较模糊,许多材料上也没有进行具体解释。如 MIT 6.828 课程给出的参考资料80386 Programmer’s Reference Manual – Section 6.5 (mit.edu),其中对于权限为 Supervisor 时,读写保护的检查情况为:

when the combined U/S attribute is S, the R/W attributeis not checked.

即 Supervisor 模式下,将无视页的读写保护,但这种说法并不完全正确。

在Intel手册中有详尽的解释:

When the processor is in supervisor mode and the WP flag in register
CR0 is clear (its state following reset initialization), all pages
are both readable and writable (write- protection is ignored). When
the processor is in user mode, it can write only to user- mode pages
that are read/write accessible. User-mode pages which are read/write
or read-only are readable; supervisor-mode pages are neither
readable nor writable from user mode. A page-fault exception is
generated on any attempt to violate the protection rules. Starting
with the P6 family, Intel processors allow user-mode pages to be
write- protected against supervisor-mode access. Setting CR0.WP = 1
enables supervisor- mode sensitivity to user-mode, write protected
pages. Supervisor pages which are read-only are not writable from
any privilege level (if CR0.WP = 1)

总结

WP = 1时,Supervisor不能写R/W没有置位的页。

WP = 0时,Supervisor可以写任何页。

实例

错误理解

在实现OS的分页管理时,需要实现物理页面分配的功能,其中可能需要对分配的页面进行零初始化,即:

memset((void*)page2pa(page_free_list), 0, PGSIZE);

其中page_free_list是将要分配的物理页元信息的虚拟地址,page2pa将元信息所代表的物理页的物理地址提取出来。执行这个操作后,QEMU仿真器报了处理器级别的错误,停机了。根据gdb信息,我发现是memset在执行第一个参数的处理时出现了问题。

直觉地,我以为是传参出了问题,猜测进程运行过程中都进行虚拟地址级别的处理,如果传入一个物理地址,那么memset将会报错。于是我进行了修改,将第一个参数转化为虚拟地址。

memset(page2kva(page_free_list), 0, PGSIZE);

此时,程序可以正常运行。

正确理解

在继续进行实验的过程中,我意识到对于函数传进的地址,处理器都会进行页表寻址的操作,而不会检查你传入的地址类型。也就是说,就算我传入了一个物理地址,处理器并不会直接抛出错误,而是会根据传入的物理地址当做虚拟地址进行寻址。

根据实验预先的页表设置,如下:

     虚拟地址范围      物理地址范围    权限
00000000-00400000 00000000-00400000 -r-
f0000000-f0400000 00000000-00400000 -rw

即将高地址和低地址的两端长度为4MB的虚拟地址区域,直接映射到了物理地址的低4MB区域,这是方便内核进行物理地址访问而设计的。根据映射关系,我发现传入一个高位置的虚拟内存,在寻址后得到的物理内存即为pa = va - 0xf0000000,这和直接将这个物理地址当成虚拟地址寻址后的结果相等,因为还是自己。那么,之前那种理解是错误的,不管memset第一个参数接受到的是一个地址的虚拟地址还是物理地址,寻址后都会得到相同的结果。

那么,区别可能在于权限访问上。查阅参考资料,发现内核模式在读写时会无视权限保护,这与实践结果不一致,于是我进一步查阅更详细的资料。通过查阅Intel手册,我发现是因为WP的置位导致了内核运行也会对读写权限敏感,而参考资料上的说法是在WP=0时才正确。

于是,我在实验设置上更改了WP的置位进行测试:

orl	$(CR0_PE|CR0_PG|CR0_WP), %eax
改为
orl	$(CR0_PE|CR0_PG), %eax

之后,即便是使用最开始的函数调用:

memset((void*)page2pa(page_free_list), 0, PGSIZE);

处理器也没有再报错。这证明了这次错误是因为内核使用memset,在WP置位的情况下对一个写保护的页进行写操作导致的。理解上是因为对WP置位的理解不够深入,不能简单地用“”传入一个非虚拟地址“”这样浅层的理由去解释。如果我们置位了,那么内核写一个不可写的页面就会报错,而非内核无视读写保护。内核需要对写保护敏感主要是为了之后的写时复制机制所设置的,会更加方便。

  • 37
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值