驱动程序如何使用 MONITOR 指令(_mm_monitor 内在函数)?

2024-03-18

我正在探索使用MONITOR指令(或等效的内在指令,_mm_monitor)。尽管我找到了描述它们的文献,但我找不到任何关于如何使用它的具体示例/样本。

任何人都可以分享如何在驱动程序中使用该指令/内在的示例吗?本质上,我想用它来观察内存范围。


The monitor http://x86.renejeschke.de/html/file_module_x86_id_175.html instruction arms the address monitoring hardware using the address specified in RAX/EAX/AX.Quote from Intel
The state of the monitor is used by the instruction mwait.

使用的有效地址大小(16、32 或 64 位)取决于编码指令的有效地址大小(即可以用67h前缀,默认情况下它与代码大小相同)。

中给出的地址rax/eax/ax是逻辑地址的偏移部分,用于计算用于装备监视器的线性地址。
段部分是ds默认情况下,可以应用段覆盖前缀来更改段。
作为监视器使用的线性地址,分页不会影响监视。

The availability of the monitor (and mwait) instruction is indicated by the bit CPUID.01H:ECX.MONITOR[bit 3]1.
It is a privileged instruction but Intel claims:

这些指令在大于 0 的级别上有条件地可用。

检测这种情况的建议方法是try执行monitor并处理最终的#UD异常(以操作系统将其报告给用户层程序的自定义方式)。

监控的地址范围must可回写缓存。
由于涉及缓存和缓存一致性子系统size地址范围以最小和最大大小给出。
CPUID.01H:EAX[位 15:0]给出最小范围大小。这是硬件监视器监视的区域的长度。
然而,缓存一致性流量可能适用于较大尺寸的“块”(行),并且如果后者包含在前者中,则与受监控区域相邻的写入仍然会触发它。
这产生了最大范围大小,可以在CPUID.01H:EBX[位 15:0].
要正确使用monitor确保监视的数据结构适合最小范围大小,但也确保没有代理在其旁边的地址中写入最大范围大小。

例如,如果最小范围大小为 8 个字节,最大大小为 16 个字节,请确保监视的结构适合 8 个字节,但用另外 8 个字节填充它以达到总共 16 个字节,这样就不会从第 8 个字节开始写入到第 16 个字节发生。

在单集群系统中,以上两个值是相等的。我的都是64字节。
BIOS 负责报告高速缓存一致性线大小IA32_MONITOR_FILTER_LINE_SIZE在多集群系统中。

为了指令排序和访问权的目的,monitor是一个负载。

monitor允许程序员指定hints and 扩展.
扩展名指定于ecx当提示出现时edx.
不支持的扩展会引发 #GP 异常,不支持的提示将被忽略。
我不知道有任何扩展或提示monitor,英特尔手册报告

对于奔腾 4 处理器(系列 15,型号 3),未定义扩展或提示。

我相信这条线总体来说是正确的,只是其中有一个过时的处理器型号。
此外,伪代码为monitor报告#GPIf ECX ≠ 0.

装备显示器而不检查其状态(使用mwait)不会造成任何伤害。

其内在本质是void _mm_monitor(void const *p, unsigned extensions,unsigned hints).


一旦监视器布防,它可以由不同的条件触发:

  • 外部中断:NMI、SMM、INIT、BINIT、MCERR
  • 故障、中止,包括机器检查
  • 架构 TLB 失效,包括对 CR0、CR3、CR4 的写入和某些 MSR 写入
  • 由于快速系统调用和远程调用而导致的自愿转换
  • 屏蔽中断(如果启用)
  • 监视地址范围内的写入

监视器的状态对程序员不可见,但可以使用以下命令进行测试mwait.
mwait进入实现定义的低功耗状态,直到监视器处于触发状态。
如果监视器未进入布防状态或已被触发mwait is a nop否则它会使处理器停止执行指令,直到触发监视器为止。

mwait也可以给出扩展 and hints.
扩展名设置在ecx并提示eax.
在撰写本文时,唯一的扩展是:

Bit 0即使被屏蔽(例如,即使 EFLAGS.IF=0),也将中断视为中断事件。仅当以下情况时才可设置CPUID.05H:ECX[位 1] = 1.
位 31-1预订的

这些提示让程序员可以指定实现定义的低功耗模式。

Bits 3:0C 状态内的子 C 状态,由位 [7:4] 指示
Bits 7:4目标C状态
值为0表示C1; 1表示C2等
01111B 的值表示 C0
注意:MWAIT 扩展的目标 C 状态是处理器特定的 C 状态,而不是 ACPI C 状态

C 模式的子状态数(因此是可用性)由下式给出:CPUID.05h.EDX:

位 03 - 00:使用 MWAIT 支持的 C0* 子 C 状态数。
位 07 - 04:使用 MWAIT 支持的 C1* 子 C 状态数。
位 11 - 08:使用 MWAIT 支持的 C2* 子 C 状态数。
位 15 - 12:使用 MWAIT 支持的 C3* 子 C 状态数。
位 19 - 16:使用 MWAIT 支持的 C4* 子 C 状态数。
位 23 - 20:使用 MWAIT 支持的 C5* 子 C 状态数。
位 27 - 24:使用 MWAIT 支持的 C6* 子 C 状态数。
位 31 - 28:使用 MWAIT 支持的 C7* 子 C 状态数。

请注意,将 CPU 置于高于 C1 的状态也会禁用其他线程,因此触发监视器的写入必须来自其他代理。

其内在本质是void _mm_mwait(unsigned extensions, unsigned hints).


The monitor/mwait引入机制是为了帮助线程之间的同步,但它不太适合监视对内存范围的访问,因为触发条件包括频繁发生的事件。
之后mwait始终强制检查监视范围是否已写入。
有一个例子在这里 https://software.intel.com/en-us/articles/how-to-use-the-monitor-and-mwait-streaming-simd-extensions-3-instructions其中模式如下:

  1. 监视的结构使用特定值(例如 0)进行初始化。
  2. The monitor/mwait使用对。
  3. 在稍后的某个时刻,另一个再次将特定值(例如 1)写入所监视的结构中。
  4. 监视器被触发并且mwait“返回”,将监视的结构值与 1(发生写入)进行比较,如果不相等,则执行跳回 2。

一些样本,untested伪代码可能是:

struct MonitoredType
{
  int (*event)(struct MonitoredType const* m);              /*Return 0 to keep monitoring*/
  struct AnyType data;                                /*Less, in size, than MIN_MONITOR_RANGE*/
  char padding[MAX_MONITOR_RANGE - sizeof(AnyType)];
};

void wait_for_write(struct MonitoredType const* m)
{
   /* This may miss a write if it happens before MONITOR, beware of race conditions if necessary */
   do
   {
     _mm_monitor(&m->data, 0, 0);
     _mm_mwait(0, 0);
   } while ( ! m->event(m));
}

必须注意确保退出条件mwait是一次写入,而不是其他事件之一。
这就是函数指针的原因event.

为了监视对线性地址的写入/读取,可以使用以下替代方法:调试寄存器.
参见第 17 章英特尔手册3 https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-system-programming-manual-325384.html并检查操作系统文档以正确使用这些寄存器。


1 Meaning: Execute cpuid with eax set to 01h and test the bit 3 of ecx afterward. Note that IA32_MISC_ENABLE allows the OS or the firmware to disable monitor/mwait.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

驱动程序如何使用 MONITOR 指令(_mm_monitor 内在函数)? 的相关文章

随机推荐