i386: hvf: refactor event injection code for hvf

This patch refactors the event-injection code for hvf by using the
appropriate fields already provided by CPUX86State. At vmexit, it fills
these fields so that hvf_inject_interrupts can just retrieve them without
calling into hvf.

Signed-off-by: Sergio Andres Gomez Del Real <Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-14-Sergio.G.DelReal@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Sergio Andres Gomez Del Real 2017-09-13 04:05:21 -05:00 committed by Paolo Bonzini
parent babfa20ca4
commit b7394c8394
6 changed files with 102 additions and 42 deletions

View file

@ -3285,6 +3285,9 @@ static void x86_cpu_reset(CPUState *s)
memset(env->mtrr_var, 0, sizeof(env->mtrr_var));
memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed));
env->interrupt_injected = -1;
env->exception_injected = -1;
env->nmi_injected = false;
#if !defined(CONFIG_USER_ONLY)
/* We hard-wire the BSP to the first CPU. */
apic_designate_bsp(cpu->apic_state, s->cpu_index == 0);

View file

@ -587,6 +587,55 @@ void hvf_disable(int shouldDisable)
hvf_disabled = shouldDisable;
}
static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_info)
{
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
env->exception_injected = -1;
env->interrupt_injected = -1;
env->nmi_injected = false;
if (idtvec_info & VMCS_IDT_VEC_VALID) {
switch (idtvec_info & VMCS_IDT_VEC_TYPE) {
case VMCS_IDT_VEC_HWINTR:
case VMCS_IDT_VEC_SWINTR:
env->interrupt_injected = idtvec_info & VMCS_IDT_VEC_VECNUM;
break;
case VMCS_IDT_VEC_NMI:
env->nmi_injected = true;
break;
case VMCS_IDT_VEC_HWEXCEPTION:
case VMCS_IDT_VEC_SWEXCEPTION:
env->exception_injected = idtvec_info & VMCS_IDT_VEC_VECNUM;
break;
case VMCS_IDT_VEC_PRIV_SWEXCEPTION:
default:
abort();
}
if ((idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWEXCEPTION ||
(idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWINTR) {
env->ins_len = ins_len;
}
if (idtvec_info & VMCS_INTR_DEL_ERRCODE) {
env->has_error_code = true;
env->error_code = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_ERROR);
}
}
if ((rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
VMCS_INTERRUPTIBILITY_NMI_BLOCKING)) {
env->hflags2 |= HF2_NMI_MASK;
} else {
env->hflags2 &= ~HF2_NMI_MASK;
}
if (rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
(VMCS_INTERRUPTIBILITY_STI_BLOCKING |
VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) {
env->hflags |= HF_INHIBIT_IRQ_MASK;
} else {
env->hflags &= ~HF_INHIBIT_IRQ_MASK;
}
}
int hvf_vcpu_exec(CPUState *cpu)
{
X86CPU *x86_cpu = X86_CPU(cpu);
@ -606,12 +655,9 @@ int hvf_vcpu_exec(CPUState *cpu)
cpu->vcpu_dirty = false;
}
env->hvf_emul->interruptable =
!(rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
(VMCS_INTERRUPTIBILITY_STI_BLOCKING |
VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING));
hvf_inject_interrupts(cpu);
if (hvf_inject_interrupts(cpu)) {
return EXCP_INTERRUPT;
}
vmx_update_tpr(cpu);
qemu_mutex_unlock_iothread();
@ -628,7 +674,10 @@ int hvf_vcpu_exec(CPUState *cpu)
uint64_t exit_qual = rvmcs(cpu->hvf_fd, VMCS_EXIT_QUALIFICATION);
uint32_t ins_len = (uint32_t)rvmcs(cpu->hvf_fd,
VMCS_EXIT_INSTRUCTION_LENGTH);
uint64_t idtvec_info = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_INFO);
hvf_store_events(cpu, ins_len, idtvec_info);
rip = rreg(cpu->hvf_fd, HV_X86_RIP);
RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS);
env->eflags = RFLAGS(env);

View file

@ -299,6 +299,7 @@
/*
* VMCS IDT-Vectoring information fields
*/
#define VMCS_IDT_VEC_VECNUM 0xFF
#define VMCS_IDT_VEC_VALID (1U << 31)
#define VMCS_IDT_VEC_TYPE 0x700
#define VMCS_IDT_VEC_ERRCODE_VALID (1U << 11)
@ -306,6 +307,8 @@
#define VMCS_IDT_VEC_NMI (2 << 8)
#define VMCS_IDT_VEC_HWEXCEPTION (3 << 8)
#define VMCS_IDT_VEC_SWINTR (4 << 8)
#define VMCS_IDT_VEC_PRIV_SWEXCEPTION (5 << 8)
#define VMCS_IDT_VEC_SWEXCEPTION (6 << 8)
/*
* VMCS Guest interruptibility field

View file

@ -181,6 +181,10 @@ static inline void macvm_set_rip(CPUState *cpu, uint64_t rip)
static inline void vmx_clear_nmi_blocking(CPUState *cpu)
{
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
env->hflags2 &= ~HF2_NMI_MASK;
uint32_t gi = (uint32_t) rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY);
gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
@ -188,6 +192,10 @@ static inline void vmx_clear_nmi_blocking(CPUState *cpu)
static inline void vmx_set_nmi_blocking(CPUState *cpu)
{
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
env->hflags2 |= HF2_NMI_MASK;
uint32_t gi = (uint32_t)rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY);
gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi);

View file

@ -356,50 +356,47 @@ void vmx_clear_int_window_exiting(CPUState *cpu)
bool hvf_inject_interrupts(CPUState *cpu_state)
{
int allow_nmi = !(rvmcs(cpu_state->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) &
VMCS_INTERRUPTIBILITY_NMI_BLOCKING);
X86CPU *x86cpu = X86_CPU(cpu_state);
CPUX86State *env = &x86cpu->env;
uint64_t idt_info = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_INFO);
uint8_t vector;
uint64_t intr_type;
bool have_event = true;
if (env->interrupt_injected != -1) {
vector = env->interrupt_injected;
intr_type = VMCS_INTR_T_SWINTR;
} else if (env->exception_injected != -1) {
vector = env->exception_injected;
if (vector == EXCP03_INT3 || vector == EXCP04_INTO) {
intr_type = VMCS_INTR_T_SWEXCEPTION;
} else {
intr_type = VMCS_INTR_T_HWEXCEPTION;
}
} else if (env->nmi_injected) {
vector = NMI_VEC;
intr_type = VMCS_INTR_T_NMI;
} else {
have_event = false;
}
uint64_t info = 0;
if (idt_info & VMCS_IDT_VEC_VALID) {
uint8_t vector = idt_info & 0xff;
uint64_t intr_type = idt_info & VMCS_INTR_T_MASK;
info = idt_info;
if (have_event) {
info = vector | intr_type | VMCS_INTR_VALID;
uint64_t reason = rvmcs(cpu_state->hvf_fd, VMCS_EXIT_REASON);
if (intr_type == VMCS_INTR_T_NMI && reason != EXIT_REASON_TASK_SWITCH) {
allow_nmi = 1;
if (env->nmi_injected && reason != EXIT_REASON_TASK_SWITCH) {
vmx_clear_nmi_blocking(cpu_state);
}
if ((allow_nmi || intr_type != VMCS_INTR_T_NMI)) {
if (!(env->hflags2 & HF2_NMI_MASK) || intr_type != VMCS_INTR_T_NMI) {
info &= ~(1 << 12); /* clear undefined bit */
if (intr_type == VMCS_INTR_T_SWINTR ||
intr_type == VMCS_INTR_T_PRIV_SWEXCEPTION ||
intr_type == VMCS_INTR_T_SWEXCEPTION) {
uint64_t ins_len = rvmcs(cpu_state->hvf_fd,
VMCS_EXIT_INSTRUCTION_LENGTH);
wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len);
}
if (vector == EXCEPTION_BP || vector == EXCEPTION_OF) {
/*
* VT-x requires #BP and #OF to be injected as software
* exceptions.
*/
info &= ~VMCS_INTR_T_MASK;
info |= VMCS_INTR_T_SWEXCEPTION;
uint64_t ins_len = rvmcs(cpu_state->hvf_fd,
VMCS_EXIT_INSTRUCTION_LENGTH);
wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len);
wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, env->ins_len);
}
uint64_t err = 0;
if (idt_info & VMCS_INTR_DEL_ERRCODE) {
err = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_ERROR);
wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR, err);
if (env->has_error_code) {
wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR,
env->error_code);
}
/*printf("reinject %lx err %d\n", info, err);*/
wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info);
@ -407,7 +404,7 @@ bool hvf_inject_interrupts(CPUState *cpu_state)
}
if (cpu_state->interrupt_request & CPU_INTERRUPT_NMI) {
if (allow_nmi && !(info & VMCS_INTR_VALID)) {
if (!(env->hflags2 & HF2_NMI_MASK) && !(info & VMCS_INTR_VALID)) {
cpu_state->interrupt_request &= ~CPU_INTERRUPT_NMI;
info = VMCS_INTR_VALID | VMCS_INTR_T_NMI | NMI_VEC;
wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info);
@ -416,7 +413,7 @@ bool hvf_inject_interrupts(CPUState *cpu_state)
}
}
if (env->hvf_emul->interruptable &&
if (!(env->hflags & HF_INHIBIT_IRQ_MASK) &&
(cpu_state->interrupt_request & CPU_INTERRUPT_HARD) &&
(EFLAGS(env) & IF_MASK) && !(info & VMCS_INTR_VALID)) {
int line = cpu_get_pic_interrupt(&x86cpu->env);
@ -429,6 +426,8 @@ bool hvf_inject_interrupts(CPUState *cpu_state)
if (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) {
vmx_set_int_window_exiting(cpu_state);
}
return (cpu_state->interrupt_request
& (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR));
}
int hvf_process_events(CPUState *cpu_state)

View file

@ -1038,8 +1038,6 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
env->exception_injected = -1;
env->interrupt_injected = -1;
env->xcr0 = 1;
if (kvm_irqchip_in_kernel()) {
env->mp_state = cpu_is_bsp(cpu) ? KVM_MP_STATE_RUNNABLE :