【发布时间】:2015-11-21 09:42:48
【问题描述】:
我正在尝试直接写入物理内存位置,所以我使用汇编函数首先禁用分页,写入值,然后重新启用分页,但由于某种原因,尝试时仍然会触发页面错误写入值。
据我了解,在 x86-32bit 中,通过翻转 cr0 中的第 32 位来打开和关闭分页,所以这是我的汇编函数:
mov 4(%esp), %ecx //address
mov 8(%esp), %edx //value
mov %cr0, %eax
and $0x7fffffff, %eax
mov %eax, %cr0
mov %edx, (%ecx) //this line still triggers a page fault somehow
or $0x80000000, %eax
mov %eax, %cr0
ret
这是实现我想做的正确方法吗?如果是这样,为什么在cr0中的位翻转时仍然会触发页面错误?
【问题讨论】:
-
您是否尝试在已启用分页的操作系统上禁用分页?它是您自己的操作系统还是众所周知的操作系统(linux、Windows、MacOS)?当现代操作系统已经启用分页时,您绝对应该不禁用分页。要写入物理地址,请使用操作系统提供的工具(
/dev/mem或Device\PhysicalMemory)或 kernel.BTW 提供的函数,看来(我不习惯 AT&T 语法)你反转了值代码中的地址。 -
其实是第 31 位,因为第 0 位是第一位。
-
如果代码从具有不同物理地址和虚拟地址的页面运行,禁用分页会不会导致错误?或者更确切地说,使一些其他指令运行,因为
EIP是一个物理地址。您是否在bochs中单步执行了此操作,或者在遇到错误时确切了解发生了什么? -
另外,我认为 sane 的方法是将物理页面映射到某处的虚拟内存中,然后写入它。不过,那是无聊的方式。这种疯狂的方式看起来确实很有趣。
-
如果代码、堆栈、GDT、IDT、所有中断处理程序以及它们可能使用的所有东西都是标识映射的,那么禁用和重新启用分页是“安全的”;但它也会很慢(使所有 TLB 条目无效),如果一切都是身份映射的,你必须想知道为什么你首先要启用分页.. ;-)
标签: assembly x86 paging virtual-memory page-fault