#ifndef ICC_BUS_H_
#define ICC_BUS_H_
+
+struct v3_icc_ops {
+ int (*raise_intr)(struct guest_info * core, int intr_num, void * private_data);
+};
+
+
/**
*
*/
-int v3_icc_register_apic(struct v3_vm_info *info, struct vm_device *icc_bus, struct vm_device *apic, uint32_t apic_num);
+int v3_icc_register_apic(struct guest_info * vm, struct vm_device * icc_bus, uint8_t apic_phys_id, struct v3_icc_ops * ops, void * priv_data);
+
/**
* Send an inter-processor interrupt (IPI) from this local APIC to another local APIC.
*
- * @param icc_bus The ICC bus that facilitates the communication.
- * @param apic_num The remote APIC number.
- * @param intr_num The interrupt number.
+ * @param icc_bus - The ICC bus that routes IPIs.
+ * @param apic_num - The remote APIC number.
+ * @param intr_num - The interrupt number.
*/
-int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t apic_num, uint32_t intr_num);
+int v3_icc_send_irq(struct vm_device * icc_bus, uint8_t apic_num, uint32_t irq_num);
+
+
+
#endif /* ICC_BUS_H_ */
menu "Virtual Devices"
config APIC
- bool "APIC"
+ bool "APIC"
default y
+ depends on ICC_BUS
help
Includes the Virtual APIC device
Enable debugging for the APIC
+
+config IO_APIC
+ bool "IOAPIC"
+ depends on ICC_BUS
+ default y
+ help
+ Includes the Virtual IO APIC
+
+config DEBUG_IO_APIC
+ bool "IO APIC Debugging"
+ default n
+ depends on IO_APIC && DEBUG_ON
+ help
+ Enable debugging for the IO APIC
+
+
+config ICC_BUS
+ bool "ICC BUS"
+ default y
+ help
+ The ICC Bus for APIC/IOAPIC communication
+
+
config BOCHS_DEBUG
bool "Bochs Debug Console Device"
default y
Enable debugging for the IDE Layer
-config IO_APIC
- bool "IOAPIC"
- depends on ICC_BUS
- default y
- help
- Includes the Virtual IO APIC
-
-config DEBUG_IO_APIC
- bool "IO APIC Debugging"
- default n
- depends on IO_APIC && DEBUG_ON
- help
- Enable debugging for the IO APIC
-
obj-$(CONFIG_APIC) += apic.o
+obj-$(CONFIG_IO_APIC) += io_apic.o
+obj-$(CONFIG_ICC_BUS) += icc_bus.o
obj-$(CONFIG_PIT) += 8254.o
obj-$(CONFIG_PIC) += 8259a.o
obj-$(CONFIG_BOCHS_DEBUG) += bochs_debug.o
obj-$(CONFIG_GENERIC) += generic.o
obj-$(CONFIG_I440FX) += i440fx.o
obj-$(CONFIG_IDE) += ide.o
-obj-$(CONFIG_IO_APIC) += io_apic.o
+
obj-$(CONFIG_KEYBOARD) += keyboard.o
obj-$(CONFIG_LINUX_VIRTIO_BALLOON) += lnx_virtio_balloon.o
obj-$(CONFIG_LINUX_VIRTIO_BLOCK) += lnx_virtio_blk.o
#include <devices/apic.h>
#include <devices/apic_regs.h>
+#include <devices/icc_bus.h>
#include <palacios/vmm.h>
#include <palacios/vmm_msr.h>
#include <palacios/vmm_sprintf.h>
#include <palacios/vm_guest.h>
+
#ifndef CONFIG_DEBUG_APIC
#undef PrintDebug
#define PrintDebug(fmt, args...)
uint32_t eoi;
- uint32_t my_apic_id;
- struct vm_device *icc_bus;
+ struct vm_device * icc_bus;
v3_lock_t lock;
};
-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);
+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);
static void init_apic_state(struct apic_state * apic) {
apic->base_addr = DEFAULT_BASE_ADDR;
-static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) {
+static int read_apic_msr(struct guest_info * core, 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;
+ struct apic_state * apics = (struct apic_state *)(dev->private_data);
+ struct apic_state * apic = &(apics[core->cpu_id]);
+
v3_lock(apic->lock);
dst->value = apic->base_addr;
v3_unlock(apic->lock);
}
-static int write_apic_msr(uint_t msr, v3_msr_t src, void * priv_data) {
+static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
struct vm_device * dev = (struct vm_device *)priv_data;
- 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);
+ struct apic_state * apics = (struct apic_state *)(dev->private_data);
+ struct apic_state * apic = &(apics[core->cpu_id]);
+ struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, core->cpu_id, apic->base_addr);
if (old_reg == NULL) {
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) {
+ if (v3_hook_full_mem(dev->vm, core->cpu_id, 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;
}
-static int apic_read(addr_t guest_addr, void * dst, 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;
+static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
+ struct apic_state * apic = (struct apic_state *)priv_data;
addr_t reg_addr = guest_addr - apic->base_addr;
struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
uint32_t val = 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;
+static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
+ struct apic_state * apic = (struct apic_state *)priv_data;
addr_t reg_addr = guest_addr - apic->base_addr;
struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
uint32_t op_val = *(uint32_t *)src;
case INT_CMD_LO_OFFSET:
apic->int_cmd.lo = op_val;
- v3_icc_send_ipi(apic->icc_bus, apic->int_cmd.dst, apic->int_cmd.val);
+ // ICC???
+ v3_icc_send_irq(apic->icc_bus, apic->int_cmd.dst, apic->int_cmd.val);
break;
case INT_CMD_HI_OFFSET:
apic->int_cmd.hi = op_val;
// returns 1 if an interrupt is pending, 0 otherwise
static int apic_intr_pending(struct guest_info * info, void * private_data) {
- struct vm_device * dev = (struct vm_device *)private_data;
- struct apic_state * apic = (struct apic_state *)dev->private_data;
+ struct apic_state * apic = (struct apic_state *)private_data;
int req_irq = get_highest_irr(apic);
int svc_irq = get_highest_isr(apic);
}
static int apic_get_intr_number(struct guest_info * info, void * private_data) {
- struct vm_device * dev = (struct vm_device *)private_data;
- struct apic_state * apic = (struct apic_state *)dev->private_data;
+ struct apic_state * apic = (struct apic_state *)private_data;
int req_irq = get_highest_irr(apic);
int svc_irq = get_highest_isr(apic);
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
-
- if (irq == 238) {
- struct vm_device * dev = (struct vm_device *)private_data;
- struct apic_state * apic = (struct apic_state *)dev->private_data;
- return activate_apic_irq(apic, irq);
- }
-#endif
+static int apic_raise_intr(struct guest_info * info, int irq, void * private_data) {
+ struct apic_state * apic = (struct apic_state *)private_data;
- return 0;
+ return activate_apic_irq(apic, irq);
}
-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;
- struct apic_state * apic = (struct apic_state *)dev->private_data;
+ struct apic_state * apic = (struct apic_state *)private_data;
int major_offset = (irq & ~0x00000007) >> 3;
int minor_offset = irq & 0x00000007;
uchar_t * req_location = apic->int_req_reg + major_offset;
*svc_location |= flag;
*req_location &= ~flag;
-#ifdef CONFIG_CRAY_XT
- if ((irq == 238) || (irq == 239)) {
- PrintError("APIC: Begin IRQ %d (ISR=%x), (IRR=%x)\n", irq, *svc_location, *req_location);
- }
-#endif
-
- return 0;
-}
-
-
-
-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;
- }
- // 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;
}
+
/* Timer Functions */
static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
- struct vm_device * dev = (struct vm_device *)priv_data;
- struct apic_state * apic = (struct apic_state *)dev->private_data;
+ struct apic_state * apic = (struct apic_state *)priv_data;
// The 32 bit GCC runtime is a pile of shit
#ifdef __V3_64BIT__
uint64_t tmr_ticks = 0;
+static struct v3_icc_ops icc_ops = {
+ .raise_intr = apic_raise_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);
+ int i;
if (!icc) {
- PrintError("Cannot find device %s\n", icc_name);
+ PrintError("Cannot find ICC Bus (%s)\n", icc_name);
return -1;
}
- struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
+ // We allocate one apic per core
+ // APICs are accessed via index which correlates with the core's cpu_id
+ struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state) * vm->num_cores);
struct vm_device * dev = v3_allocate_device(name, &dev_ops, apic);
return -1;
}
- 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);
+
+ for (i = 0; i < vm->num_cores; i++) {
+ struct guest_info * core = &(vm->cores[i]);
+
+ v3_register_intr_controller(core, &intr_ops, &(apic[i]));
+ v3_add_timer(core, &timer_ops, &(apic[i]));
+ v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, &(apic[i]));
+
+ v3_icc_register_apic(core, icc, i, &icc_ops, &(apic[i]));
+
+ init_apic_state(&(apic[i]));
}
- 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);
-
return 0;
}
#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>
+#include <devices/icc_bus.h>
-#define MAX_APIC 256
+#define MAX_APICS 256
-struct icc_bus_internal {
- struct vm_device * apic[MAX_APIC];
+
+struct ipi_thunk_data {
+ struct vm_device * target;
+ uint64_t val;
+};
+
+struct int_cmd_reg {
+ union {
+ uint64_t val;
+
+ struct {
+ uint32_t lo;
+ uint32_t hi;
+ } __attribute__((packed));
+
+ struct {
+ uint_t vec : 8;
+ uint_t msg_type : 3;
+ uint_t dst_mode : 1;
+ uint_t del_status : 1;
+ uint_t rsvd1 : 1;
+ uint_t lvl : 1;
+ uint_t trig_mode : 1;
+ uint_t rem_rd_status : 2;
+ uint_t dst_shorthand : 2;
+ uint64_t rsvd2 : 36;
+ uint32_t dst : 8;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
+struct apic_data {
+ struct guest_info * core;
+ struct v3_icc_ops * ops;
+
+ void * priv_data;
+ int present;
+};
+
+
+struct icc_bus_state {
+ struct apic_data apics[MAX_APICS];
};
static struct v3_device_ops dev_ops = {
.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;
+int v3_icc_send_irq(struct vm_device * icc_bus, uint8_t apic_num, uint32_t irq_num) {
+ struct icc_bus_state * state = (struct icc_bus_state *)icc_bus->private_data;
+ struct apic_data * apic = &(state->apics[apic_num]);
+
struct int_cmd_reg icr;
- icr.lo = val;
+ icr.lo = irq_num;
- char *type = NULL, *dest = NULL;
+
+ char * type = NULL;
+ char * 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.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;
+
+ 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);
+ 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);
+ apic->ops->raise_intr(apic->core, irq_num & 0xff, apic->priv_data);
- V3_Call_On_CPU(apic_num, icc_force_exit, (void *)(uint64_t)(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;
+
+/* THIS IS A BIG ASSUMPTION: APIC PHYSID == LOGID == CORENUM */
+
+int v3_icc_register_apic(struct guest_info * core, struct vm_device * icc_bus,
+ uint8_t apic_num, struct v3_icc_ops * ops, void * priv_data) {
+ struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
+ struct apic_data * apic = &(icc->apics[apic_num]);
+
+ if (apic->present == 1) {
+ PrintError("Attempt to re-register apic %u\n", apic_num);
+ return -1;
+ }
+
+ apic->present = 1;
+ apic->priv_data = priv_data;
+ apic->core = core;
+ apic->ops = ops;
+
+ PrintDebug("Registered apic%u\n", apic_num);
+
+ 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 icc_bus_state * icc_bus = (struct icc_bus_state *)V3_Malloc(sizeof(struct icc_bus_state));
+ memset(icc_bus, 0, sizeof(struct icc_bus_state));
struct vm_device * dev = v3_allocate_device(name, &dev_ops, icc_bus);
return -1;
}
- init_icc_bus_internal_state(icc_bus);
-
return 0;
}
#include <palacios/vmm.h>
#include <palacios/vmm_dev_mgr.h>
-#include <devices/apic.h>
+#include <devices/icc_bus.h>
#include <palacios/vm_guest.h>
#ifndef CONFIG_DEBUG_IO_APIC
struct redir_tbl_entry redir_tbl[24];
- // This is a temporary method of communication between the IOAPIC and the LAPIC
- struct vm_device * apic;
+ struct vm_device * icc_bus;
};
}
-static int ioapic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
+static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
struct vm_device * dev = (struct vm_device *)priv_data;
struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
uint32_t reg_tgt = guest_addr - ioapic->base_addr;
}
-static int ioapic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
+static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
struct vm_device * dev = (struct vm_device *)priv_data;
struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
uint32_t reg_tgt = guest_addr - ioapic->base_addr;
return length;
}
-/* Interrupt controller functions */
-static int ioapic_intr_pending(struct guest_info * info, void * private_data) {
- return 0;
-}
-
-
-static int ioapic_get_intr_number(struct guest_info * info, void * private_data) {
- return 0;
-}
-
-static int ioapic_begin_irq(struct guest_info * info, void * private_data, int irq) {
- return 0;
-}
-static int ioapic_raise_irq(struct guest_info * info, void * private_data, int irq) {
+static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) {
struct vm_device * dev = (struct vm_device *)private_data;
struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
struct redir_tbl_entry * irq_entry = NULL;
if (irq_entry->mask == 0) {
PrintDebug("IOAPIC Signalling APIC to raise INTR %d\n", irq_entry->vec);
- //v3_apic_raise_intr(info, ioapic->apic, irq_entry->vec);
- v3_apic_raise_intr(ioapic->apic, irq_entry->vec);
+ v3_icc_send_irq(ioapic->icc_bus, irq_entry->dst_field, irq_entry->vec);
}
return 0;
}
/* I don't know if we can do anything here.... */
-static int ioapic_lower_irq(struct guest_info * info, void * private_data, int irq) {
+static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) {
return 0;
}
-static struct intr_ctrl_ops intr_ops = {
- .intr_pending = ioapic_intr_pending,
- .get_intr_number = ioapic_get_intr_number,
+static struct intr_router_ops router_ops = {
.raise_intr = ioapic_raise_irq,
- .begin_irq = ioapic_begin_irq,
.lower_intr = ioapic_lower_irq,
};
-static int ioapic_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
- struct vm_device * apic = v3_find_dev(vm, v3_cfg_val(cfg, "irq_bus"));
+static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+ struct vm_device * icc_bus = v3_find_dev(vm, v3_cfg_val(cfg, "irq_bus"));
char * name = v3_cfg_val(cfg, "name");
- if (!apic) {
- PrintError("Could not locate APIC device (%s)\n", v3_cfg_val(cfg, "irq_bus"));
+ if (!icc_bus) {
+ PrintError("Could not locate ICC BUS device (%s)\n", v3_cfg_val(cfg, "irq_bus"));
return -1;
}
struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
- ioapic->apic = apic;
+ ioapic->icc_bus = icc_bus;
struct vm_device * dev = v3_allocate_device(name, &dev_ops, ioapic);
}
- v3_register_intr_controller(vm, &intr_ops, dev);
+ v3_register_intr_router(vm, &router_ops, dev);
init_ioapic_state(ioapic);
- v3_hook_full_mem(vm, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB,
+ v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB,
ioapic_read, ioapic_write, dev);
return 0;