KVM: selftests: Add helpers for locally (un)blocking IRQs on x86

Copy KVM-Unit-Tests' x86 helpers for emitting STI and CLI, comments and
all, and use them throughout x86 selftests.  The safe_halt() and sti_nop()
logic in particular benefits from centralized comments, as the behavior
isn't obvious unless the reader is already aware of the STI shadow.

Cc: Manali Shukla <Manali.Shukla@amd.com>
Link: https://lore.kernel.org/r/20241220012617.3513898-1-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
Sean Christopherson 2024-12-19 17:26:17 -08:00
parent 7803339fa9
commit 983820cb53
7 changed files with 51 additions and 14 deletions

View File

@ -1335,6 +1335,46 @@ static inline void kvm_hypercall_map_gpa_range(uint64_t gpa, uint64_t size,
GUEST_ASSERT(!ret);
}
/*
* Execute HLT in an STI interrupt shadow to ensure that a pending IRQ that's
* intended to be a wake event arrives *after* HLT is executed. Modern CPUs,
* except for a few oddballs that KVM is unlikely to run on, block IRQs for one
* instruction after STI, *if* RFLAGS.IF=0 before STI. Note, Intel CPUs may
* block other events beyond regular IRQs, e.g. may block NMIs and SMIs too.
*/
static inline void safe_halt(void)
{
asm volatile("sti; hlt");
}
/*
* Enable interrupts and ensure that interrupts are evaluated upon return from
* this function, i.e. execute a nop to consume the STi interrupt shadow.
*/
static inline void sti_nop(void)
{
asm volatile ("sti; nop");
}
/*
* Enable interrupts for one instruction (nop), to allow the CPU to process all
* interrupts that are already pending.
*/
static inline void sti_nop_cli(void)
{
asm volatile ("sti; nop; cli");
}
static inline void sti(void)
{
asm volatile("sti");
}
static inline void cli(void)
{
asm volatile ("cli");
}
void __vm_xsave_require_permission(uint64_t xfeature, const char *name);
#define vm_xsave_require_permission(xfeature) \

View File

@ -63,8 +63,10 @@ static void receiver_code(void *hcall_page, vm_vaddr_t pgs_gpa)
/* Signal sender vCPU we're ready */
ipis_rcvd[vcpu_id] = (u64)-1;
for (;;)
asm volatile("sti; hlt; cli");
for (;;) {
safe_halt();
cli();
}
}
static void guest_ipi_handler(struct ex_regs *regs)

View File

@ -42,10 +42,7 @@ static void l2_guest_code(struct svm_test_data *svm)
x2apic_write_reg(APIC_ICR,
APIC_DEST_SELF | APIC_INT_ASSERT | INTR_IRQ_NUMBER);
__asm__ __volatile__(
"sti\n"
"nop\n"
);
sti_nop();
GUEST_ASSERT(vintr_irq_called);
GUEST_ASSERT(intr_irq_called);

View File

@ -86,7 +86,7 @@ static void ucna_injection_guest_code(void)
wrmsr(MSR_IA32_MCx_CTL2(UCNA_BANK), ctl2 | MCI_CTL2_CMCI_EN);
/* Enables interrupt in guest. */
asm volatile("sti");
sti();
/* Let user space inject the first UCNA */
GUEST_SYNC(SYNC_FIRST_UCNA);

View File

@ -106,7 +106,8 @@ static void halter_guest_code(struct test_data_page *data)
data->halter_tpr = xapic_read_reg(APIC_TASKPRI);
data->halter_ppr = xapic_read_reg(APIC_PROCPRI);
data->hlt_count++;
asm volatile("sti; hlt; cli");
safe_halt();
cli();
data->wake_count++;
}
}

View File

@ -18,7 +18,7 @@ struct xapic_vcpu {
static void xapic_guest_code(void)
{
asm volatile("cli");
cli();
xapic_enable();
@ -38,7 +38,7 @@ static void xapic_guest_code(void)
static void x2apic_guest_code(void)
{
asm volatile("cli");
cli();
x2apic_enable();

View File

@ -191,10 +191,7 @@ static void guest_code(void)
struct vcpu_runstate_info *rs = (void *)RUNSTATE_VADDR;
int i;
__asm__ __volatile__(
"sti\n"
"nop\n"
);
sti_nop();
/* Trigger an interrupt injection */
GUEST_SYNC(TEST_INJECT_VECTOR);