diff --git a/articles/20221103-riscv-page-fault-part2.md b/articles/20221103-riscv-page-fault-part2.md index 1d84021bdf0c7df94bf9b0bff896651bc049b355..1baf11635503775bc41fceac935556f837390389 100644 --- a/articles/20221103-riscv-page-fault-part2.md +++ b/articles/20221103-riscv-page-fault-part2.md @@ -93,9 +93,7 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf) return do_wp_page(vmf); /* - * 写内存的异常,页表项又有 W 权限,说明已经第二次进入异常了,上次因为 tlb 中没有改过来导致了这一次异常,这种情况是极其不可能出现的。 - * 需要将 Dirty 位置位,因为虽然上次异常时已经置过位了(在 do_wp_page() 会置位),但是目前为止还没有写成功内存(不然也不会又来到缺页异常) - * 在上次和这次之间这段时间,Dirty 位可能已经被回收机制复位了。 + * 写内存的异常,页表项又有 W 权限,说明是软件管理 W 位的处理器架构,这种 CPU 会抛出异常,让软件处理 */ entry = pte_mkdirty(entry); } @@ -145,10 +143,8 @@ unlock: - 继续判断是否是写内存异常,若页表项无写权限,调用 `do_wp_page()` 处理。此函数不仅包含匿名页的写时复制,也包括共享文件映射回写相关的写保护机制处理。本函数将在本系统后续部分详细叙述。 -- 写内存的异常,但页表项有写权限,说明是本 CPU 线程第二次进入异常了,上次是检测到别的 CPU 线程把页表项改了,直接退出了。本 CPU 线程的 TLB 没有刷新导致了这一次异常,这种情况是极其不可能出现的,因为应用程序员在不同线程写同一内存应该加锁。如果真出现此情况,比如某种特殊需求或者应用程序忘了加锁,则需要将 Dirty 位置位。这是因为虽然上次别的线程异常时已经置过位了(在 `do_wp_page()` 会置位),但是目前为止本线程还没有成功写过该内存页(不然也不会又来到缺页异常),在上次和这次之间这段时间,Dirty 位也可能已经被回收机制(二次机会法)复位了,所以本次写还应该置位。此外也将 ACCESS 位置位,原因和 DIRTY 位一样。接着调用 `ptep_set_access_flags()` 将上面修改好的项写入页表项,并刷新 MMU 相关缓存,这样同样的位置就不会再出现缺页异常了。这一步处理的逻辑理解起来非常费力,设计的时候是估计是很难想到的,应该是在实践中出 bug 补充的,这也说明了操作系统开发很难一步到位,稳定的系统需要很长时间的积累。 - -## do_anonymous_page() 函数分析 - +- 写内存的异常,但页表项有写权限,这部分逻辑主要是处理处理器硬件不负责管理 A 位和 W 位的情况。某些架构的处理器硬件不管理 A 位和 W 位,第一次读或写的时候会进入缺页异常,交给软件处理,软件将 A 位和 W 位置位。RISC-V 架构的文档中表示管理或者不管理都可以。也就是说,如果是管理 A 位和 W 位的 CPU ,则不会出现写内存的异常但页表项有写权限的情形。 + 上文说到 `do_anonymous_page()` 用来具体处理私有匿名映射的缺页,下面具体分析: ```c