aboutsummaryrefslogtreecommitdiff
path: root/hw/apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/apic.c')
-rw-r--r--hw/apic.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/hw/apic.c b/hw/apic.c
index 8c8b2de14b..000339b97a 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -83,12 +83,13 @@ typedef struct APICState {
int count_shift;
uint32_t initial_count;
int64_t initial_count_load_time, next_time;
+ uint32_t idx;
QEMUTimer *timer;
} APICState;
static int apic_io_memory;
static APICState *local_apics[MAX_APICS + 1];
-static int last_apic_id = 0;
+static int last_apic_idx = 0;
static int apic_irq_delivered;
@@ -400,6 +401,23 @@ static void apic_eoi(APICState *s)
apic_update_irq(s);
}
+static int apic_find_dest(uint8_t dest)
+{
+ APICState *apic = local_apics[dest];
+ int i;
+
+ if (apic && apic->id == dest)
+ return dest; /* shortcut in case apic->id == apic->idx */
+
+ for (i = 0; i < MAX_APICS; i++) {
+ apic = local_apics[i];
+ if (apic && apic->id == dest)
+ return i;
+ }
+
+ return -1;
+}
+
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode)
{
@@ -410,8 +428,10 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
if (dest == 0xff) {
memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
} else {
+ int idx = apic_find_dest(dest);
memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
- set_bit(deliver_bitmask, dest);
+ if (idx >= 0)
+ set_bit(deliver_bitmask, idx);
}
} else {
/* XXX: cluster mode */
@@ -457,8 +477,7 @@ static void apic_init_ipi(APICState *s)
cpu_reset(s->cpu_env);
- if (!(s->apicbase & MSR_IA32_APICBASE_BSP))
- s->cpu_env->halted = 1;
+ s->cpu_env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP);
}
/* send a SIPI message to the CPU to start it */
@@ -487,14 +506,14 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
break;
case 1:
memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
- set_bit(deliver_bitmask, s->id);
+ set_bit(deliver_bitmask, s->idx);
break;
case 2:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
break;
case 3:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
- reset_bit(deliver_bitmask, s->id);
+ reset_bit(deliver_bitmask, s->idx);
break;
}
@@ -870,13 +889,14 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id)
static void apic_reset(void *opaque)
{
APICState *s = opaque;
+ int bsp = cpu_is_bsp(s->cpu_env);
s->apicbase = 0xfee00000 |
- (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
+ (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
apic_init_ipi(s);
- if (s->id == 0) {
+ if (bsp) {
/*
* LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
* time typically by BIOS, so PIC interrupt can be delivered to the
@@ -902,12 +922,12 @@ int apic_init(CPUState *env)
{
APICState *s;
- if (last_apic_id >= MAX_APICS)
+ if (last_apic_idx >= MAX_APICS)
return -1;
s = qemu_mallocz(sizeof(APICState));
env->apic_state = s;
- s->id = last_apic_id++;
- env->cpuid_apic_id = s->id;
+ s->idx = last_apic_idx++;
+ s->id = env->cpuid_apic_id;
s->cpu_env = env;
apic_reset(s);
@@ -923,10 +943,10 @@ int apic_init(CPUState *env)
}
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
- register_savevm("apic", s->id, 2, apic_save, apic_load, s);
+ register_savevm("apic", s->idx, 2, apic_save, apic_load, s);
qemu_register_reset(apic_reset, 0, s);
- local_apics[s->id] = s;
+ local_apics[s->idx] = s;
return 0;
}