Assembly 在x86 32位中禁用分页
我试图直接写入物理内存位置,因此我使用汇编函数首先禁用分页,写入值,然后重新启用分页,但由于某些原因,在尝试写入值时仍会触发页面错误 据我所知,在x86-32位中,分页是通过在cr0中翻转位32来设置的,因此下面是我的汇编函数:Assembly 在x86 32位中禁用分页,assembly,x86,paging,virtual-memory,page-fault,Assembly,X86,Paging,Virtual Memory,Page Fault,我试图直接写入物理内存位置,因此我使用汇编函数首先禁用分页,写入值,然后重新启用分页,但由于某些原因,在尝试写入值时仍会触发页面错误 据我所知,在x86-32位中,分页是通过在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 lin
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中的位翻转时仍会触发页面错误?当跳转指令(仅限远跳转)完成时,cr0寄存器中的更改将变为活动状态 但是,禁用分页不是一个好主意:您必须保证代码位于1:1映射内存中,并且中断被禁用 如果使用堆栈,还必须确保堆栈映射为1:1 通过将ecx中的物理地址映射到虚拟地址,然后写入虚拟地址的方式修改页表要容易得多。描述了如何禁用分页,作为从保护模式切换回实模式过程的一部分: 9.9.2切换回实地址模式 处理器从保护模式切换回实地址模式 如果软件清除CR0中的PE位 使用MOV CR0指令注册。重新进入的程序 实地址模式应执行以下步骤:
- 将程序控制转移到标识映射到物理地址(即线性地址)的线性地址 地址等于物理地址)
- 确保GDT和IDT位于标识映射页面中
- 清除CR0寄存器中的PG位
- 将0H移入CR3寄存器以刷新TLB
请注意,在再次设置PG位之前,必须重新加载CR3。另外,因为您所做的是非常不寻常的,您可能会遇到错误和兼容性问题与您的模拟器。在切换回实模式的过程中,它可能只能正确地处理禁用分页的问题,因为这可能是它被测试的唯一场景。甚至物理CPU在这方面也可能有问题。您是否试图在已启用分页的操作系统上禁用分页?它是您自己的操作系统还是众所周知的操作系统(linux、Windows、MacOS)?当现代操作系统已经启用分页功能时,绝对不应该禁用它。要写入物理地址,可以使用操作系统提供的工具(
/dev/mem
或设备\PhysicalMemory
)或kernel.BTW提供的函数(我不习惯AT&T语法)您在代码中反转了一个地址的值。实际上这是第31位,因为第0位是第一位。如果代码从具有不同物理地址和虚拟地址的页面运行,禁用分页不会导致错误吗?或者更确切地说,既然EIP
是一个物理地址,就让其他指令运行。你有没有在bochs
中单步执行此操作,或者在发生故障时查看到底发生了什么?此外,我认为明智的方法是将物理页映射到某个虚拟内存中,然后写入它。不过,这是一种无聊的方式。这种疯狂的方式看起来确实很有趣。如果代码、堆栈、GDT、IDT、所有中断处理程序以及它们可能使用的所有东西都是标识映射的,那么禁用和重新启用分页将是“安全的”;但是它也会很慢(使所有TLB条目无效),并且您必须想一想,如果所有内容都是标识映射的,那么您为什么要首先启用分页功能呢