aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu-all.h2
-rw-r--r--cpu-exec.c9
-rw-r--r--hw/apic.c37
-rw-r--r--target-i386/cpu.h4
-rw-r--r--target-i386/exec.h2
-rw-r--r--target-i386/helper.c22
6 files changed, 64 insertions, 12 deletions
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