diff --git a/cpu-all.h b/cpu-all.h index 48a9a2c113..97a224db89 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -768,6 +768,8 @@ extern int use_icount; #define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ #define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ #define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ +#define CPU_INTERRUPT_INIT 0x400 /* INIT pending. */ +#define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */ void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); diff --git a/cpu-exec.c b/cpu-exec.c index 8734337d67..db5cb5730e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -380,7 +380,14 @@ int cpu_exec(CPUState *env1) } #endif #if defined(TARGET_I386) - if (env->hflags2 & HF2_GIF_MASK) { + if (interrupt_request & CPU_INTERRUPT_INIT) { + svm_check_intercept(SVM_EXIT_INIT); + do_cpu_init(env); + env->exception_index = EXCP_HALTED; + cpu_loop_exit(); + } else if (interrupt_request & CPU_INTERRUPT_SIPI) { + do_cpu_sipi(env); + } else if (env->hflags2 & HF2_GIF_MASK) { if ((interrupt_request & CPU_INTERRUPT_SMI) && !(env->hflags & HF_SMM_MASK)) { svm_check_intercept(SVM_EXIT_SMI); diff --git a/hw/apic.c b/hw/apic.c index 3e04132413..b059185bb5 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -85,6 +85,8 @@ typedef struct APICState { int64_t initial_count_load_time, next_time; uint32_t idx; QEMUTimer *timer; + int sipi_vector; + int wait_for_sipi; } APICState; static int apic_io_memory; @@ -93,7 +95,6 @@ static int last_apic_idx = 0; static int apic_irq_delivered; -static void apic_init_ipi(APICState *s); static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); static void apic_update_irq(APICState *s); static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, @@ -249,7 +250,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, case APIC_DM_INIT: /* normal INIT IPI sent to processors */ foreach_apic(apic_iter, deliver_bitmask, - apic_init_ipi(apic_iter) ); + cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_INIT) ); return; case APIC_DM_EXTINT: @@ -454,10 +455,14 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, } -static void apic_init_ipi(APICState *s) +void apic_init_reset(CPUState *env) { + APICState *s = env->apic_state; int i; + if (!s) + return; + s->tpr = 0; s->spurious_vec = 0xff; s->log_dest = 0; @@ -474,22 +479,31 @@ static void apic_init_ipi(APICState *s) s->initial_count = 0; s->initial_count_load_time = 0; s->next_time = 0; + s->wait_for_sipi = 1; - cpu_reset(s->cpu_env); - - s->cpu_env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP); + env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP); } -/* send a SIPI message to the CPU to start it */ static void apic_startup(APICState *s, int vector_num) { - CPUState *env = s->cpu_env; - if (!env->halted) + s->sipi_vector = vector_num; + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI); +} + +void apic_sipi(CPUState *env) +{ + APICState *s = env->apic_state; + + cpu_reset_interrupt(env, CPU_INTERRUPT_SIPI); + + if (!s->wait_for_sipi) return; + env->eip = 0; - cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, + cpu_x86_load_seg_cache(env, R_CS, s->sipi_vector << 8, s->sipi_vector << 12, 0xffff, 0); env->halted = 0; + s->wait_for_sipi = 0; } static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, @@ -894,7 +908,8 @@ static void apic_reset(void *opaque) s->apicbase = 0xfee00000 | (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE; - apic_init_ipi(s); + cpu_reset(s->cpu_env); + apic_init_reset(s->cpu_env); if (bsp) { /* diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 3cd391a01f..a50f0594b0 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -888,4 +888,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK)); } +void apic_init_reset(CPUState *env); +void apic_sipi(CPUState *env); +void do_cpu_init(CPUState *env); +void do_cpu_sipi(CPUState *env); #endif /* CPU_I386_H */ diff --git a/target-i386/exec.h b/target-i386/exec.h index fbaf5bc984..42b471a269 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -345,6 +345,8 @@ static inline int cpu_has_work(CPUState *env) work = (env->interrupt_request & CPU_INTERRUPT_HARD) && (env->eflags & IF_MASK); work |= env->interrupt_request & CPU_INTERRUPT_NMI; + work |= env->interrupt_request & CPU_INTERRUPT_INIT; + work |= env->interrupt_request & CPU_INTERRUPT_SIPI; return work; } diff --git a/target-i386/helper.c b/target-i386/helper.c index 75e7ccd454..8a76abdac5 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1738,3 +1738,25 @@ CPUX86State *cpu_x86_init(const char *cpu_model) return env; } + +#if !defined(CONFIG_USER_ONLY) +void do_cpu_init(CPUState *env) +{ + int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI; + cpu_reset(env); + env->interrupt_request = sipi; + apic_init_reset(env); +} + +void do_cpu_sipi(CPUState *env) +{ + apic_sipi(env); +} +#else +void do_cpu_init(CPUState *env) +{ +} +void do_cpu_sipi(CPUState *env) +{ +} +#endif