mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
KVM: selftests: Verify VMX's GUEST_PENDING_DBG_EXCEPTIONS.BS Consistency Check
In x86's debug_regs test, add a test case to cover the scenario where a single-step #DB occurs in an STI-shadow, in which case KVM needs to stuff vmcs.GUEST_PENDING_DBG_EXCEPTIONS.BS in order to satisfy a flawed VM-Entry Consistency Check. Wire up an IRQ handler to gain a bit of bonus coverage, as the subsequent IRET from the #DB sets RFLAGS.IF, but *without* STI-blocking, and so the pending IRQ is expected on the instruction immediately following STI. Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com> [sean: expect the IRQ on the CLI, and explain why] Link: https://patch.msgid.link/20260515222638.1949982-11-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
063a22451f
commit
b8284279b7
|
|
@ -15,11 +15,51 @@
|
|||
|
||||
#define IRQ_VECTOR 0xAA
|
||||
|
||||
#define CAST_TO_RIP(v) ((unsigned long long)&(v))
|
||||
|
||||
/* For testing data access debug BP */
|
||||
u32 guest_value;
|
||||
|
||||
extern unsigned char sw_bp, hw_bp, write_data, ss_start, bd_start;
|
||||
extern unsigned char fep_bd_start;
|
||||
extern unsigned char fep_bd_start, fep_sti_start, fep_sti_end;
|
||||
|
||||
static int irqs_received;
|
||||
|
||||
static void guest_db_handler(struct ex_regs *regs)
|
||||
{
|
||||
static int count;
|
||||
unsigned long target_rips[2] = {
|
||||
CAST_TO_RIP(fep_sti_start),
|
||||
CAST_TO_RIP(fep_sti_end),
|
||||
};
|
||||
|
||||
__GUEST_ASSERT(regs->rip == target_rips[count],
|
||||
"STI[%u]: unexpected rip 0x%lx (should be 0x%lx)",
|
||||
count, regs->rip, target_rips[count]);
|
||||
regs->rflags &= ~X86_EFLAGS_TF;
|
||||
count++;
|
||||
}
|
||||
|
||||
static void guest_irq_handler(struct ex_regs *regs)
|
||||
{
|
||||
/*
|
||||
* The pending IRQ should finally be take when KVM_GUESTDBG_BLOCKIRQ is
|
||||
* cleared and IRQs are enabled. Note, the IRQ is expected to arrive
|
||||
* on the instruction immediately after STI, even though its in an STI
|
||||
* shadow. Because the next instruction has a coincident #DB, and #DBs
|
||||
* are not subject to STI-blocking, the #DB will push RFLAGS.IF=1 on
|
||||
* the stack, and the eventual IRET will unmask IRQs and obliterate the
|
||||
* STI shadow in the process.
|
||||
*/
|
||||
unsigned long target_rip = CAST_TO_RIP(fep_sti_start);
|
||||
|
||||
__GUEST_ASSERT(regs->rip == target_rip,
|
||||
"IRQ: unexpected rip 0x%lx (should be 0x%lx)",
|
||||
regs->rip, target_rip);
|
||||
|
||||
irqs_received++;
|
||||
x2apic_write_reg(APIC_EOI, 0);
|
||||
}
|
||||
|
||||
static void guest_code(void)
|
||||
{
|
||||
|
|
@ -66,14 +106,32 @@ static void guest_code(void)
|
|||
/* DR6.BD test */
|
||||
asm volatile("bd_start: mov %%dr0, %%rax" : : : "rax");
|
||||
|
||||
if (is_forced_emulation_enabled)
|
||||
/*
|
||||
* Note, the IRET from the #DB that occurs in the below STI-shadow will
|
||||
* unmask IRQs, i.e. the pending interrupt will be delivered after #DB
|
||||
* handling, on the CLI!
|
||||
*/
|
||||
if (is_forced_emulation_enabled) {
|
||||
asm volatile(KVM_FEP "fep_bd_start: mov %%dr0, %%rax" : : : "rax");
|
||||
|
||||
/* pending debug exceptions for emulation */
|
||||
asm volatile("pushf\n\t"
|
||||
"orq $" __stringify(X86_EFLAGS_TF) ", (%rsp)\n\t"
|
||||
"popf\n\t"
|
||||
"sti\n\t"
|
||||
"fep_sti_start:"
|
||||
"cli\n\t"
|
||||
"pushf\n\t"
|
||||
"orq $" __stringify(X86_EFLAGS_TF) ", (%rsp)\n\t"
|
||||
"popf\n\t"
|
||||
KVM_FEP "sti\n\t"
|
||||
"fep_sti_end:"
|
||||
"cli\n\t");
|
||||
GUEST_ASSERT(irqs_received == 1);
|
||||
}
|
||||
GUEST_DONE();
|
||||
}
|
||||
|
||||
#define CAST_TO_RIP(v) ((unsigned long long)&(v))
|
||||
|
||||
static void vcpu_skip_insn(struct kvm_vcpu *vcpu, int insn_len)
|
||||
{
|
||||
struct kvm_regs regs;
|
||||
|
|
@ -227,6 +285,9 @@ int main(void)
|
|||
memset(&debug, 0, sizeof(debug));
|
||||
vcpu_guest_debug_set(vcpu, &debug);
|
||||
|
||||
vm_install_exception_handler(vm, DB_VECTOR, guest_db_handler);
|
||||
vm_install_exception_handler(vm, IRQ_VECTOR, guest_irq_handler);
|
||||
|
||||
vcpu_run(vcpu);
|
||||
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
|
||||
cmd = get_ucall(vcpu, &uc);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user