#endif
#ifdef CONFIG_DEBUG_APIC
-static char *shorthand_str[] = {
+static char * shorthand_str[] = {
"(no shorthand)",
"(self)",
"(all)",
"(all-but-me)",
};
-static char *deliverymode_str[] = {
+static char * deliverymode_str[] = {
"(fixed)",
"(lowest priority)",
"(SMI)",
#define EXT_INT_LOC_VEC_TBL_OFFSET2 0x520 // 0x500 - 0x530
#define EXT_INT_LOC_VEC_TBL_OFFSET3 0x530 // 0x500 - 0x530
-
-
-
-
struct apic_msr {
union {
uint64_t value;
uint8_t bootstrap_cpu : 1;
uint8_t rsvd2 : 2;
uint8_t apic_enable : 1;
- uint64_t base_addr : 40;
- uint32_t rsvd3 : 12;
+ uint64_t base_addr : 40;
+ uint32_t rsvd3 : 12;
} __attribute__((packed));
} __attribute__((packed));
} __attribute__((packed));
-typedef enum {INIT, SIPI, STARTED} ipi_state_t;
+typedef enum {INIT_ST,
+ SIPI,
+ STARTED} ipi_state_t;
struct apic_dev_state;
struct guest_info * core;
+ void * controller_handle;
+
+ struct v3_timer * timer;
+
uint32_t eoi;
v3_lock_t lock;
+
+
static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
apic->lapic_id.val = id;
- apic->ipi_state = INIT;
+ apic->ipi_state = INIT_ST;
// The P6 has 6 LVT entries, so we set the value to (6-1)...
apic->apic_ver.val = 0x80050010;
apic->base_addr = src.value;
- if (v3_hook_full_mem(core->vm_info, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev) == -1) {
+ if (v3_hook_full_mem(core->vm_info, core->cpu_id, apic->base_addr,
+ apic->base_addr + PAGE_SIZE_4KB,
+ apic_read, apic_write, apic_dev) == -1) {
PrintError("apic %u: core %u: Could not hook new APIC Base address\n",
apic->lapic_id.val, core->cpu_id);
v3_unlock(apic->lock);
if (irq_num <= 15) {
- PrintError("apic %u: core ?: Attempting to raise an invalid interrupt: %d\n", apic->lapic_id.val,irq_num);
+ PrintError("apic %u: core %d: Attempting to raise an invalid interrupt: %d\n",
+ apic->lapic_id.val, apic->core->cpu_id, irq_num);
return -1;
}
- PrintDebug("apic %u: core ?: Raising APIC IRQ %d\n", apic->lapic_id.val, irq_num);
+ PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->cpu_id, irq_num);
if (*req_location & flag) {
- //V3_Print("Interrupts coallescing\n");
+ PrintDebug("Interrupt %d coallescing\n", irq_num);
}
if (*en_location & flag) {
*req_location |= flag;
} else {
- PrintDebug("apic %u: core ?: Interrupt not enabled... %.2x\n",
- apic->lapic_id.val, *en_location);
+ PrintDebug("apic %u: core %d: Interrupt not enabled... %.2x\n",
+ apic->lapic_id.val, apic->core->cpu_id,*en_location);
return 0;
}
static int should_deliver_ipi(struct guest_info * dst_core,
struct apic_state * dst_apic, uint8_t mda) {
- if (mda == 0xff) {
- // always deliver broadcast
- return 1;
- }
if (dst_apic->dst_fmt.model == 0xf) {
- return should_deliver_cluster_ipi(dst_core, dst_apic, mda);
- } else if (dst_apic->dst_fmt.model == 0x0) {
+
+ if (mda == 0xff) {
+ // always deliver broadcast
+ return 1;
+ }
+
return should_deliver_flat_ipi(dst_core, dst_apic, mda);
+ } else if (dst_apic->dst_fmt.model == 0x0) {
+
+ if (mda == 0xff) {
+ // always deliver broadcast
+ return 1;
+ }
+
+ return should_deliver_cluster_ipi(dst_core, dst_apic, mda);
} else {
PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n",
dst_apic->lapic_id.val, dst_core->cpu_id, dst_apic->dst_fmt.model);
}
-static int deliver_ipi(struct guest_info * core,
- struct apic_state * src_apic,
+static int deliver_ipi(struct apic_state * src_apic,
struct apic_state * dst_apic,
uint32_t vector, uint8_t del_mode) {
case 0: //fixed
case 1: // lowest priority
- PrintDebug(" delivering IRQ to core %u\n", dst_core->cpu_id);
+ PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->cpu_id);
activate_apic_irq(dst_apic, vector);
// host maitains logical proc->phsysical proc
PrintDebug(" non-local core, forcing it to exit\n");
- v3_interrupt_cpu(core->vm_info, dst_core->cpu_id, 0);
+#ifdef CONFIG_MULTITHREAD_OS
+ v3_interrupt_cpu(dst_core->vm_info, dst_core->cpu_id, 0);
+#else
+ V3_ASSERT(0);
+#endif
}
break;
// TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
// Sanity check
- if (dst_apic->ipi_state != INIT) {
+ if (dst_apic->ipi_state != INIT_ST) {
PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored\n",
- dst_core->cpu_id, dst_core->cpu_mode);
+ dst_core->cpu_id, dst_apic->ipi_state);
// Only a warning, since INIT INIT SIPI is common
break;
}
// Sanity check
if (dst_apic->ipi_state != SIPI) {
PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
- dst_core->cpu_id, dst_core->cpu_mode);
+ dst_core->cpu_id, dst_apic->ipi_state);
break;
}
}
-static int route_ipi(struct guest_info * core, struct apic_dev_state * apic_dev,
- struct apic_state * src_apic, uint32_t icr_val) {
- struct int_cmd_reg * icr = (struct int_cmd_reg *)&icr_val;
+static int route_ipi(struct apic_dev_state * apic_dev,
+ struct apic_state * src_apic,
+ struct int_cmd_reg * icr) {
struct apic_state * dest_apic = NULL;
- PrintDebug("route_ipi: src_apic=%p, icr_data=%x",
- src_apic, icr_val);
-
-
- // initial sanity checks
- if (src_apic == NULL) {
- PrintError("route_ipi: Apparently sending from unregistered apic id=%d\n",
- src_apic->core->cpu_id);
- return -1;
- }
+ PrintDebug("route_ipi: src_apic=%p, icr_data=%p\n",
+ src_apic, (void *)(addr_t)icr->val);
if ((icr->dst_mode == 0) && (icr->dst >= apic_dev->num_apics)) {
dest_apic = &(apic_dev->apics[icr->dst]);
- PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
+ PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx) (destapic=%p\n",
deliverymode_str[icr->del_mode],
icr->vec,
src_apic,
(icr->dst_mode == 0) ? "(physical)" : "(logical)",
shorthand_str[icr->dst_shorthand],
icr->dst,
- icr->val);
-
+ icr->val,
+ dest_apic);
switch (icr->dst_shorthand) {
if (icr->dst_mode == 0) {
// physical delivery
- if (deliver_ipi(core, src_apic, dest_apic,
+ if (deliver_ipi(src_apic, dest_apic,
icr->vec, icr->del_mode) == -1) {
PrintError("Error: Could not deliver IPI\n");
return -1;
// logical delivery
int i;
uint8_t mda = icr->dst;
-
for (i = 0; i < apic_dev->num_apics; i++) {
dest_apic = &(apic_dev->apics[i]);
int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
PrintError("Error checking delivery mode\n");
return -1;
} else if (del_flag == 1) {
- if (deliver_ipi(core, src_apic, dest_apic,
+ if (deliver_ipi(src_apic, dest_apic,
icr->vec, icr->del_mode) == -1) {
PrintError("Error: Could not deliver IPI\n");
return -1;
case 1: // self
+ if (src_apic == NULL) {
+ PrintError("Sending IPI to self from generic IPI sender\n");
+ break;
+ }
+
if (icr->dst_mode == 0) {
- if (deliver_ipi(core, src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
+ if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
PrintError("Could not deliver IPI\n");
return -1;
}
} else {
// logical delivery
- PrintError("icc_bus: use of logical delivery in self is not yet supported.\n");
+ PrintError("use of logical delivery in self is not yet supported.\n");
return -1;
}
break;
dest_apic = &(apic_dev->apics[i]);
if ((dest_apic != src_apic) || (icr->dst_shorthand == 2)) {
- if (deliver_ipi(core, src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
+ if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
PrintError("Error: Could not deliver IPI\n");
return -1;
}
PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
apic->lapic_id.val, core->cpu_id, apic, priv_data);
- PrintDebug("Write to address space (%p) (val=%x)\n",
- (void *)guest_addr, *(uint32_t *)src);
+ PrintDebug("apic %u: core %u: write to address space (%p) (val=%x)\n",
+ apic->lapic_id.val, core->cpu_id, (void *)guest_addr, *(uint32_t *)src);
if (msr->apic_enable == 0) {
PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
apic->lapic_id.val, core->cpu_id,
apic->int_cmd.val, apic->int_cmd.dst);
- if (route_ipi(core, apic_dev, apic, apic->int_cmd.val) == -1) {
+ if (route_ipi(apic_dev, apic, &(apic->int_cmd)) == -1) {
PrintError("IPI Routing failure\n");
return -1;
}
}
-int v3_apic_raise_intr(struct v3_vm_info * vm, struct vm_device * dev,
- uint32_t irq, uint32_t dst) {
- struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
+int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
+ struct apic_dev_state * apic_dev = (struct apic_dev_state *)
+ (((struct vm_device *)dev_data)->private_data);
+ struct int_cmd_reg tmp_icr;
+
+ // zero out all the fields
+ tmp_icr.val = 0;
+
+ tmp_icr.vec = ipi->vector;
+ tmp_icr.del_mode = ipi->mode;
+ tmp_icr.dst_mode = ipi->logical;
+ tmp_icr.trig_mode = ipi->trigger_mode;
+ tmp_icr.dst_shorthand = ipi->dst_shorthand;
+ tmp_icr.dst = ipi->dst;
+
+
+ return route_ipi(apic_dev, NULL, &tmp_icr);
+}
+
+
+int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
+ struct apic_dev_state * apic_dev = (struct apic_dev_state *)
+ (((struct vm_device*)dev_data)->private_data);
struct apic_state * apic = &(apic_dev->apics[dst]);
PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst);
activate_apic_irq(apic, irq);
if (V3_Get_CPU() != dst) {
+#ifdef CONFIG_MULTITHREAD_OS
v3_interrupt_cpu(vm, dst, 0);
+#else
+ V3_ASSERT(0);
+#endif
}
return 0;
};
-static struct vm_timer_ops timer_ops = {
+static struct v3_timer_ops timer_ops = {
.update_timer = apic_update_time,
};
-static int apic_free(struct vm_device * dev) {
+static int apic_free(struct apic_dev_state * apic_dev) {
+ int i = 0;
+ struct v3_vm_info * vm = NULL;
+
+ for (i = 0; i < apic_dev->num_apics; i++) {
+ struct apic_state * apic = &(apic_dev->apics[i]);
+ struct guest_info * core = apic->core;
+
+ vm = core->vm_info;
+
+ v3_remove_intr_controller(core, apic->controller_handle);
+
+ if (apic->timer) {
+ v3_remove_timer(core, apic->timer);
+ }
- /* TODO: This should crosscall to force an unhook on each CPU */
+ // unhook memory
- // struct apic_state * apic = (struct apic_state *)dev->private_data;
+ }
- v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
+ v3_unhook_msr(vm, BASE_ADDR_MSR);
+ V3_Free(apic_dev);
return 0;
}
static struct v3_device_ops dev_ops = {
- .free = apic_free,
- .reset = NULL,
- .start = NULL,
- .stop = NULL,
+ .free = (int (*)(void *))apic_free,
};
apic_dev->num_apics = vm->num_cores;
- struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic_dev);
+ struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
- if (v3_attach_device(vm, dev) == -1) {
+ if (dev == NULL) {
PrintError("apic: Could not attach device %s\n", dev_id);
+ V3_Free(apic_dev);
return -1;
}
init_apic_state(apic, i);
- v3_register_intr_controller(core, &intr_ops, apic_dev);
+ apic->controller_handle = v3_register_intr_controller(core, &intr_ops, apic_dev);
- v3_add_timer(core, &timer_ops, apic_dev);
+ apic->timer = v3_add_timer(core, &timer_ops, apic_dev);
+
+ if (apic->timer == NULL) {
+ PrintError("APIC: Failed to attach timer to core %d\n", i);
+ v3_remove_device(dev);
+ return -1;
+ }
v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
#ifdef CONFIG_DEBUG_APIC
for (i = 0; i < vm->num_cores; i++) {
struct apic_state * apic = &(apic_dev->apics[i]);
- PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
- i, apic, apic->lapic_id.val, apic->base_addr_msr.value);
+ PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx and core at %p\n",
+ i, apic, apic->lapic_id.val, apic->base_addr_msr.value,apic->core);
}
#endif