【问题标题】:How do I enable SSE for my freestanding bootable code?如何为我的独立可启动代码启用 SSE?
【发布时间】:2021-07-11 18:02:57
【问题描述】:

(这个问题原本是关于CVTSI2SD指令,我以为它在奔腾M CPU上不起作用,但实际上是因为我使用的是自定义操作系统,我需要手动启用SSE .)

我有一个 Pentium M CPU 和一个自定义操作系统,到目前为止还没有使用 SSE 指令,但我现在需要使用它们。

尝试执行任何 SSE 指令会导致中断 6、非法操作码(在 Linux 中会导致 SIGILL,但这不是 Linux),在 Intel architectures software developer's manual 中也有提及(我从现在开始提及on as IASDM) as #UD - Invalid Opcode (UnDefined Opcode)

编辑:Peter Cordes 实际上找到了正确的原因,并指出了解决方案,我在下面继续:

如果您运行的旧操作系统不支持在上下文切换时保存 XMM reg,则不会设置其中一个机器控制寄存器中的 SSE 启用位。

确实,IASDM 提到了这一点:

如果操作系统没有为 SSE 提供足够的系统级支持,执行 SSE 或 SSE2 指令也可以生成#UD。

Peter Cordes 向我指出了 SSE OSDev wiki,它描述了如何通过写入 CR0CR4 控制寄存器来启用 SSE:

clear the CR0.EM bit (bit 2) [ CR0 &= ~(1 << 2) ]
set the CR0.MP bit (bit 1) [ CR0 |= (1 << 1) ]
set the CR4.OSFXSR bit (bit 9) [ CR4 |= (1 << 9) ]
set the CR4.OSXMMEXCPT bit (bit 10) [ CR4 |= (1 << 10) ]

请注意,为了能够写入这些寄存器,如果您处于保护模式,那么您需要处于特权级别 0。The answer to this question 解释了如何测试它:如果处于保护模式,即,当CR0 中的bit 0 (PE) 设置为1 时,您可以测试CS 选择器中的bit 0 和bit 1,它们应该都是0。

最后,自定义操作系统必须在上下文切换期间正确处理 XMM 寄存器,必要时保存和恢复它们。

【问题讨论】:

  • “但是,Pentium M 无法识别 CVTSI2SD”源?
  • 什么是崩溃的原因 - SIGILL(“非法指令”)或别的什么?
  • 能否请您在 GDB 下运行该应用程序,并在崩溃现场给我们(gdb) disas /r 的错误和输出?
  • 你确定你实际上没有Pentium III-M吗?
  • 执行mov eax, 1 / cpuid后能不能贴出eax的值?

标签: x86 sse instruction-set


【解决方案1】:

如果您运行的旧操作系统或自定义操作系统不支持在上下文切换中保存 XMM reg,则它不会在机器控制寄存器中设置 SSE 启用位。在这种情况下,所有触及 xmm regs 的指令都会出错。

我花了一秒钟才找到,但 http://wiki.osdev.org/SSE 解释了如何更改 CR0 和 CR4 以允许 SSE 指令在没有 #UD 的裸机上运行。


我对您的旧版本问题的第一个想法是 您可能已经使用-mavx-march=sandybridge 或等效项编译了您的程序,导致编译器发出所有内容的 VEX 编码版本。

CVTSI2SD   xmm1, xmm2/m32         ; SSE2
VCVTSI2SD  xmm1, xmm2, xmm3/m32   ; AVX

有关链接,请参阅https://stackoverflow.com/tags/x86/info,包括英特尔的 insn set ref 手册。


相关:Which versions of Windows support/require which CPU multimedia extensions? 有一些关于如何检查对 AVX 和 AVX512 支持的详细信息(这也引入了新的架构状态,因此操作系统必须设置一个位,否则硬件会出错)。它是从另一个角度来看的,但链接应指示如何激活/禁用 AVX 支持。

【讨论】:

  • 我使用的是旧的 GCC,它似乎没有那种架构。我查看了程序集,还尝试通过asm()直接插入指令,所以这种情况几乎没有。
  • 这是-mavx,哎呀。拆机看看。如果它是vcvt...,并且您的程序因 SIGILL 而死,那么这是一个 AVX 问题。否则,您可能得到的是 SIGSEGV,而不是 SIGILL。如果是 SIGILL,那么有一些奇怪的事情发生了,你应该在 gdb 下运行它,所以它会在出错的确切指令处停止。
  • 我尝试编译一些特别包含CVTSI2SD的汇编代码,以确保它是罪魁祸首,我得到了中断6。但它也发生在CVTSI2SS,所以它实际上是与SSE相关的问题。包含对%xmmN 寄存器的引用的指令不起作用。
  • stackoverflow.com/questions/6121792/… 上有一个关于检测操作系统支持的答案。但是 IIRC,英特尔建议的检测操作系统支持的方法是尝试运行 SSE 指令,看看它是否与#UD 发生故障。是的,非常可怕,尤其是。对于库或其他东西,因为这会强制调用程序处理 SIGILL! IIRC,操作系统必须设置的机器控制寄存器甚至不能被非特权代码读取。
  • @anol:我按照我的建议进行了编辑。希望这会吸引一些来自操作系统类型的专家帮助。当您尝试使用 mov cr 指令时,您可能想提及您的 CPU 处于什么状态。 (实模式?32位保护模式?)
【解决方案2】:

如果您有此类问题,建议您咨询Intel's manual

手册中明确指出CVTSI2SD是SSE2指令。

【讨论】:

  • CPUID 报告支持指令的内容是什么? less /proc/cpuinfo | grep flags 如果您使用的是 Linux。
  • @anol 在手册中,您需要阅读的部分是第 3 卷,第 13.1 节,为 SSE 扩展提供操作系统支持。本节对 SSE 支持必须做的事情进行了非常清晰的描述和列表。迈克尔,您绝对应该在回答中添加对本节的引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-20
  • 1970-01-01
  • 2021-10-04
  • 2011-03-13
  • 1970-01-01
相关资源
最近更新 更多