在 qemu - kvm 上获取多个性能监控中断
Geting multiple performance monitoring interrupt on qemu - kvm
我按照 给出的步骤和指示进行操作,现在可以得到一次计数器溢出中断。但是我不能多次得到它。无论我如何处理,Iterrupt 确实会再次触发。尽管我负责清除中断掩码。
没有任何代码很难判断,但如果您已经收到第一个 PMI,那么计数器寄存器设置正确,问题可能出在上层1。
我会检查:
已将 EOI 发送到 LAPIC。
我假设您使用固定向量配置了本地 APIC 的 PMI 寄存器。
在这种情况下,您必须将 EOI 发送到 EOI 寄存器。
引用英特尔(第 3 卷第 10.8.5 章)
For all interrupts except those delivered with the NMI, SMI, INIT, ExtINT, the start-up, or INIT-Deassert delivery
mode, the interrupt handler must include a write to the end-of-interrupt (EOI) register.
示例代码:
mov DWORD [APIC_BASE+0xb0], eax
对于未重定位的 LAPIC,有效地址是 0xfee000b0
.
写入的值无关紧要,我拿起一个寄存器来保持指令的编码简短。
当然,您必须根据您的上下文正确访问 LAPIC。
要设置 IF
标志
IF
标志清除是一个不太可能的假设,但也很容易排除。
由于中断门(但不是陷阱门)清除 IF
,因此请确保您选择退出 ISR 的方式正确恢复 IF
。
1 如果我没记错的话,PMI 不需要重新装备。
这个问题在 forum 中讨论,他们发现这是内核中的错误。但是,您可以这样做来规避它:
在需要重新编程 msr MSR_PERF_FIXED_CTR0 (0x38d) 的任何地方,放置这些行:
Msr::write(Msr::MSR_PERF_FIXED_CTR0, 0xfffffffffff0ull);
Msr::write(Msr::MSR_PERF_FIXED_CTRL, 0x0);
Msr::write(Msr::MSR_PERF_FIXED_CTR0, 0xfffffffffff0ull);
Msr::write(Msr::MSR_PERF_FIXED_CTRL, 0xa);
值 0x0 和 0xa 之间的切换导致内核重新编程计数器。
我按照
没有任何代码很难判断,但如果您已经收到第一个 PMI,那么计数器寄存器设置正确,问题可能出在上层1。
我会检查:
已将 EOI 发送到 LAPIC。
我假设您使用固定向量配置了本地 APIC 的 PMI 寄存器。
在这种情况下,您必须将 EOI 发送到 EOI 寄存器。
引用英特尔(第 3 卷第 10.8.5 章)For all interrupts except those delivered with the NMI, SMI, INIT, ExtINT, the start-up, or INIT-Deassert delivery mode, the interrupt handler must include a write to the end-of-interrupt (EOI) register.
示例代码:
mov DWORD [APIC_BASE+0xb0], eax
对于未重定位的 LAPIC,有效地址是0xfee000b0
.
写入的值无关紧要,我拿起一个寄存器来保持指令的编码简短。
当然,您必须根据您的上下文正确访问 LAPIC。
要设置
IF
标志
IF
标志清除是一个不太可能的假设,但也很容易排除。
由于中断门(但不是陷阱门)清除IF
,因此请确保您选择退出 ISR 的方式正确恢复IF
。
1 如果我没记错的话,PMI 不需要重新装备。
这个问题在 forum 中讨论,他们发现这是内核中的错误。但是,您可以这样做来规避它: 在需要重新编程 msr MSR_PERF_FIXED_CTR0 (0x38d) 的任何地方,放置这些行:
Msr::write(Msr::MSR_PERF_FIXED_CTR0, 0xfffffffffff0ull);
Msr::write(Msr::MSR_PERF_FIXED_CTRL, 0x0);
Msr::write(Msr::MSR_PERF_FIXED_CTR0, 0xfffffffffff0ull);
Msr::write(Msr::MSR_PERF_FIXED_CTRL, 0xa);
值 0x0 和 0xa 之间的切换导致内核重新编程计数器。