uint32_t eoi;
+ uint32_t my_apic_id;
+ struct vm_device *icc_bus;
- struct guest_info * core;
+ v3_lock_t lock;
};
-static void apic_incoming_ipi(void *val);
static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data);
static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data);
apic->ext_apic_feature.val = 0x00040007;
apic->ext_apic_ctrl.val = 0x00000000;
apic->spec_eoi.val = 0x00000000;
+
+ v3_lock_init(&(apic->lock));
}
static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) {
struct vm_device * dev = (struct vm_device *)priv_data;
struct apic_state * apic = (struct apic_state *)dev->private_data;
+ v3_lock(apic->lock);
dst->value = apic->base_addr;
+ v3_unlock(apic->lock);
return 0;
}
struct apic_state * apic = (struct apic_state *)dev->private_data;
struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, apic->base_addr);
+
if (old_reg == NULL) {
// uh oh...
PrintError("APIC Base address region does not exit...\n");
return -1;
}
+ v3_lock(apic->lock);
+
v3_delete_shadow_region(dev->vm, old_reg);
apic->base_addr = src.value;
if (v3_hook_full_mem(dev->vm, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev) == -1) {
PrintError("Could not hook new APIC Base address\n");
+ v3_unlock(apic->lock);
return -1;
}
+ v3_unlock(apic->lock);
return 0;
}
}
+/**
+ *
+ */
static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
struct vm_device * dev = (struct vm_device *)priv_data;
struct apic_state * apic = (struct apic_state *)dev->private_data;
case INT_CMD_LO_OFFSET:
apic->int_cmd.lo = op_val;
- V3_Call_On_CPU(apic->int_cmd.dst, apic_incoming_ipi, (void *)apic->int_cmd.val);
-
+ v3_icc_send_ipi(apic->icc_bus, apic->int_cmd.dst, apic->int_cmd.val);
break;
case INT_CMD_HI_OFFSET:
apic->int_cmd.hi = op_val;
return -1;
}
+#if 0
static int apic_raise_intr(struct guest_info * info, void * private_data, int irq) {
#ifdef CONFIG_CRAY_XT
// The Seastar is connected directly to the LAPIC via LINT0 on the ICC bus
static int apic_lower_intr(struct guest_info * info, void * private_data, int irq) {
return 0;
}
+#endif
static int apic_begin_irq(struct guest_info * info, void * private_data, int irq) {
struct vm_device * dev = (struct vm_device *)private_data;
int v3_apic_raise_intr(struct guest_info * info, struct vm_device * apic_dev, int intr_num) {
struct apic_state * apic = (struct apic_state *)apic_dev->private_data;
+ // Special cases go here
+ // startup, etc
+
if (activate_apic_irq(apic, intr_num) == -1) {
PrintError("Error: Could not activate apic_irq\n");
return -1;
}
- v3_interrupt_cpu(info, 0);
+ // Don't need this since we'll have the IPI force an exit if
+ // This is called on a different core
+ /* v3_interrupt_cpu(info, 0); */
return 0;
}
apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
if (apic_intr_pending(info, priv_data)) {
- PrintDebug("Overriding pending IRQ %d\n", apic_get_intr_number(dev->vm, priv_data));
+ PrintDebug("Overriding pending IRQ %d\n", apic_get_intr_number(info, priv_data));
}
if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
}
-static void apic_incoming_ipi(void *val)
-{
-PrintError("In apic_incoming_ipi, val=%p\n", val);
- struct int_cmd_reg int_cmd;
- char *type = NULL, *dest;
- char foo[8];
- int_cmd.val = (uint64_t)val;
- switch (int_cmd.dst_shorthand)
- {
- case 0x0:
- sprintf(foo, "%d", int_cmd.dst);
- dest = foo;
- break;
- case 0x1:
- dest = "(self)";
- break;
- case 0x2:
- dest = "(broadcast inclusive)";
- break;
- case 0x3:
- dest = "(broadcast)";
- break;
- }
- switch (int_cmd.msg_type)
- {
- case 0x0:
- type = "";
- break;
- case 0x4:
- type = "(NMI)";
- break;
- case 0x5:
- type = "(INIT)";
- break;
- case 0x6:
- type = "(Startup)";
- break;
- }
- PrintError("Receieved IPI on CPU %d type=%s dest=%s\n",
- V3_Get_CPU(), type, dest);
-//%p %s to CPU %d on CPU %d.\n", val, foo, type, dest, (int)V3_Get_CPU());
- return;
-}
-
static struct intr_ctrl_ops intr_ops = {
.intr_pending = apic_intr_pending,
.get_intr_number = apic_get_intr_number,
- .raise_intr = apic_raise_intr,
.begin_irq = apic_begin_irq,
- .lower_intr = apic_lower_intr,
};
static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
PrintDebug("Creating APIC\n");
char * name = v3_cfg_val(cfg, "name");
+ char * icc_name = v3_cfg_val(cfg,"irq_bus");
+ int i;
+ struct vm_device * icc = v3_find_dev(vm, icc_name);
+
+ if (!icc) {
+ PrintError("Cannot find device %s\n", icc_name);
+ return -1;
+ }
struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
return -1;
}
- v3_register_intr_controller(vm, &intr_ops, dev);
- v3_add_timer(vm, &timer_ops, dev);
+ for (i = 0; i < vm->num_cores; i++)
+ {
+ v3_register_intr_controller(&vm->cores[i], &intr_ops, dev);
+ v3_add_timer(&vm->cores[i], &timer_ops, dev);
+ }
init_apic_state(apic);
+ v3_icc_register_apic(vm, icc, dev,apic->my_apic_id);
+
v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
v3_hook_full_mem(vm, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_dev_mgr.h>
+#include <palacios/vmm_sprintf.h>
+#include <palacios/vm_guest.h>
+#include <devices/apic_regs.h>
+#include <devices/apic.h>
+
+#define MAX_APIC 256
+
+struct icc_bus_internal {
+ struct vm_device * apic[MAX_APIC];
+};
+
+static struct v3_device_ops dev_ops = {
+ .free = NULL,
+ .reset = NULL,
+ .start = NULL,
+ .stop = NULL,
+};
+
+int v3_icc_register_apic(struct v3_vm_info *info, struct vm_device *icc_bus, struct vm_device *apic, uint32_t apic_num)
+{
+ struct icc_bus_internal * icc = (struct icc_bus_internal *)icc_bus->private_data;
+
+ if (apic_num < MAX_APIC) {
+ if (icc->apic[apic_num]) {
+ PrintError("Attempt to re-register apic %u\n", apic_num);
+ return -1;
+ } else {
+ icc->apic[apic_num] = apic;
+ PrintDebug("Registered apic or ioapic %u\n", apic_num);
+ return 0;
+ }
+ } else {
+ PrintError("Too many apics for icc bus!");
+ return -1;
+ }
+}
+
+struct ipi_thunk_data {
+ struct vm_device *target;
+ uint64_t val;
+} ;
+
+static void icc_force_exit(void *val)
+{
+ return;
+}
+
+int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t apic_num, uint32_t val) {
+ struct icc_bus_internal * internal = (struct icc_bus_internal *)icc_bus->private_data;
+
+ struct int_cmd_reg icr;
+ icr.lo = val;
+
+ char *type = NULL, *dest = NULL;
+ char foo[8];
+
+ switch (icr.dst_shorthand)
+ {
+ case 0x0:
+ sprintf(foo, "%d", icr.dst);
+ dest = foo;
+ break;
+ case 0x1:
+ dest = "(self)";
+ break;
+ case 0x2:
+ dest = "(broadcast inclusive)";
+ break;
+ case 0x3:
+ dest = "(broadcast)";
+ break;
+ }
+ switch (icr.msg_type)
+ {
+ case 0x0:
+ type = "";
+ break;
+ case 0x4:
+ type = "(NMI)";
+ break;
+ case 0x5:
+ type = "(INIT)";
+ break;
+ case 0x6:
+ type = "(Startup)";
+ break;
+ }
+
+
+ PrintDebug("Sending IPI of type %s and destination type %s from LAPIC %u to LAPIC %u.\n", type, dest, V3_Get_CPU(), apic_num);
+
+ v3_apic_raise_intr(internal->apic[apic_num], val & 0xff);
+
+ V3_Call_On_CPU(apic_num, icc_force_exit, (void *)(uint64_t)(val & 0xff));
+
+ return 0;
+}
+
+
+static int init_icc_bus_internal_state(struct icc_bus_internal* icc) {
+ int i;
+ for (i=0;i<MAX_APIC;i++) { icc->apic[i]=0; }
+ return 0;
+}
+
+static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+ PrintDebug("Creating ICC_BUS\n");
+ char * name = v3_cfg_val(cfg, "name");
+
+ struct icc_bus_internal * icc_bus = (struct icc_bus_internal *)V3_Malloc(sizeof(struct icc_bus_internal));
+
+ struct vm_device * dev = v3_allocate_device(name, &dev_ops, icc_bus);
+
+ if (v3_attach_device(vm, dev) == -1) {
+ PrintError("Could not attach device %s\n", name);
+ return -1;
+ }
+
+ init_icc_bus_internal_state(icc_bus);
+
+ return 0;
+}
+
+
+
+device_register("ICC_BUS", icc_bus_init)