在x86 CPU中,控制寄存器编号为0。 该寄存器的第16位表示“写保护”设置。 如果该位清零,CPU可以覆盖只读数据。 (在页表条目中配置)在内存中。 如果该位置1,则CPU无法覆盖内存中的RO数据。
我很好奇的是 “这个位的最初目的是什么?” “为什么x86 CPU需要这个?”答案 0 :(得分:14)
引自Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A pg. 2-15(强调我的):
WP写保护(CR0的第16位) - 设置后,禁止超级用户程序写入只读页面;当清除时,允许管理程序级程序写入只读页面(无论U / S位设置如何;请参见第4.1.3节和第4.6节)。 此标志有助于实现创建UNIX等操作系统使用的新进程(分叉)的写时复制方法。
更新: 看wikipedia on fork():
每当进程(父进程或子进程)修改页面时,就会为执行修改的进程(父进程或子进程)单独创建该特定页面的单独副本。
这是写时复制的核心,但是当内核完成修改时会出现问题(例如当系统调用发生写操作时 - 想想read()
)。
来自4.1.3:
CR0.WP允许保护页面免受管理员模式写入的影响。如果CR0.WP = 0,则为超级用户模式写入 允许访问具有只读访问权限的线性地址;如果CR0.WP = 1,则不是。 (用户模式 永远不允许对具有只读访问权限的线性地址进行写访问,无论其值如何 CR0.WP。)
通过设置CR0.WP = 1
,内核将在修改只读用户页面时收到通知(带有页面错误),并且可以在继续页面修改之前执行写入时复制操作。
答案 1 :(得分:1)
WP = 1是默认值。当内核写入只读(写保护)用户(U)页面时,它启用陷阱,因此内核可以检查它是否为COW页面(因此,它知道需要创建该页面的另一个副本而不是COW)。 ,否则它将不得不检查正在访问的每个内存地址,否则将使更改对映射内存的其他进程可见,从而破坏了COW。
可以将WP设置为0(但要确保在此处理期间禁用了中断/屏蔽了中断,以便执行不知道这种情况的代码无法控制)。这样就可以取消写保护的cr3页面的写保护(因为当您将其递归PML4条目中的写位设置为自身时,在WP = 0之前,无法对其进行任何操作,否则它将继续导致陷阱)