gpt4 book ai didi

assembly - x86 指令是否需要它们自己的编码以及它们的所有参数同时存在于内存中?

转载 作者:行者123 更新时间:2023-12-01 23:23:48 25 4
gpt4 key购买 nike

我试图弄清楚是否有可能运行一个 Linux VM,其 RAM 仅由单个物理页面支持。

为了模拟这一点,我修改了 KVM 中的嵌套页面错误处理程序以删除
来自所有嵌套页表 (NPT) 条目的当前位,
除了对应于当前处理的页面错误的那个。

在尝试启动 Linux 客户机时,我观察到使用内存操作数的汇编指令,例如

add [rbp+0x820DDA], ebp

导致页面错误循环,直到我恢复包含页面的当前位
指令以及操作数中引用的页面(在本例中为 [rbp+0x820DDA] )。

我想知道为什么会这样。 CPU不应该顺序访问内存页面,即先读取指令然后访问内存操作数吗?
还是 x86 要求指令页和所有操作数页可以同时访问?

我正在 AMD Zen 1 上进行测试。

最佳答案

是的,它们确实需要机器代码和所有内存操作数。

Shouldn't the CPU access the memory pages sequentially, i.e. first read the instruction and then access the memory operand?



是的,逻辑上会发生这种情况,但是页面错误异常会中断该两步过程并丢弃任何进度。 CPU 无法记住发生页面错误时它在中间的指令是什么。

当页面错误处理程序在处理了有效页面错误后返回时,RIP= 错误指令的地址,因此 CPU 重新尝试从头开始执行它。

操作系统修改错误指令的机器码并期望它在 iret 之后执行不同的指令是合法的。来自页面错误处理程序(或任何其他异常或中断处理程序)。因此,AFAIK 在您所讨论的情况下,在架构上要求 CPU 从 CS:RIP 重新执行代码提取。 (假设它甚至确实返回到有故障的 CS:RIP,而不是在等待磁盘出现硬页面错误时调度另一个进程,或者在无效页面错误时将 SIGSEGV 传递给信号处理程序。)

管理程序进入/退出在架构上也可能是必需的。即使纸面上没有明确禁止,这也不是 CPU 的工作方式。

@torek 评论说,某些 (CISC) 微处理器会在页面错误时部分解码指令并转储微寄存器状态,但 x86 并非如此。

一些指令是可中断的并且可以取得部分进展,例如 rep movs (memcpy in a can) 和其他字符串指令,或收集负载/分散存储。但唯一的机制是更新架构寄存器,如用于字符串操作的 RCX/RSI/RDI,或用于收集的目标和掩码寄存器(例如 AVX2 vpgatherdd 的手册)。不将操作码/解码结果保留在一些隐藏的内部寄存器中,并在从页面错误处理程序 iret 之后重新启动它。这些是执行多个单独数据访问的指令。

还要记住,x86(像大多数 ISA 一样)保证指令是原子的。中断/异常:在中断之前,它们要么完全发生,要么根本不发生。 Interrupting an assembly instruction while it is operating .例如 add [mem], reg如果存储部分出现故障,即使没有 lock,也需要丢弃负载。前缀。

在最坏的情况下,存在的 guest 用户空间页面数量可能是 6 个(加上每个单独的 guest 内核页表子树):
  • movsqmovsw跨越页面边界的 2 字节指令,因此需要两个页面才能对其进行解码。
  • qword 源操作数 [rsi]也是分页
  • qword 目标操作数 [rdi]也是分页

  • 如果这 6 页中的任何一页出现错误,我们将回到第一页。
    rep movsd也是一个 2 字节的指令,在它的一个步骤上取得进展会有相同的要求。类似案例如 push [mem]pop [mem]可以用未对齐的堆栈构造。

    使收集加载/分散存储“可中断”(用其进度更新掩码向量)的原因(或附带好处)之一是避免增加此最小占用空间以执行单个指令。还可以提高在一次聚集或分散期间处理多个故障的效率。

    @Brandon 在评论中指出 guest 将需要其内存中的页表 ,并且用户空间页面拆分也可以是 1GiB 拆分,因此两侧位于顶级 PML4 的不同子树中。 HW page walk 需要接触所有这些访客页面表页面才能取得进展。这种病态的情况不太可能偶然发生。

    允许 TLB(和 page-walker 内部)缓存一些页表数据,并且不需要从头开始重新启动 page-walk,除非操作系统这样做 invlpg或者设置一个新的 CR3 顶级页面目录。将页面从不存在更改为存在时,这些都不是必需的;纸上的 x86 保证不需要它(因此不允许对不存在的 PTE 进行“负缓存”,至少对软件不可见)。因此,即使某些 guest 物理页表页面实际上不存在,CPU 也可能不会 VMexit。

    PMU 性能计数器 可以启用和配置,以便指令也需要 写入 PEBS 缓冲区的性能事件 对于那个指令。将计数器的掩码配置为仅计算用户空间指令,而不是内核,很可能每次返回用户空间时它都会尝试使计数器溢出并将样本存储在缓冲区中,从而产生页面错误。

    关于assembly - x86 指令是否需要它们自己的编码以及它们的所有参数同时存在于内存中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60968748/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com