From: Jack Lange Date: Wed, 27 Oct 2010 04:32:40 +0000 (-0500) Subject: removed icc bus X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=9e04092774141204bec0341885f5e726410ceb8e removed icc bus --- diff --git a/palacios/include/devices/apic.h b/palacios/include/devices/apic.h index e4452e7..6ad758e 100644 --- a/palacios/include/devices/apic.h +++ b/palacios/include/devices/apic.h @@ -26,7 +26,7 @@ -int v3_apic_raise_intr(struct guest_info * info, struct vm_device * apic_dev, int intr_num); +int v3_apic_raise_intr(struct v3_vm_info * vm, struct vm_device * apic_dev, uint32_t irq, uint32_t dst); #endif // ! __V3VEE__ diff --git a/palacios/include/devices/icc_bus.h b/palacios/include/devices/icc_bus.h deleted file mode 100644 index e9aebbd..0000000 --- a/palacios/include/devices/icc_bus.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 - * Copyright (c) 2008, The V3VEE Project - * All rights reserved. - * - * Author: Jack Lange - * - * This is free software. You are permitted to use, - * redistribute, and modify it as specified in the file "V3VEE_LICENSE". - */ - -#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 (*should_deliver)(struct guest_info * core, uint8_t mda, void * private_data); -}; - - -/** - * - */ -int v3_icc_register_apic(struct guest_info *core, struct vm_device * icc_bus, uint8_t apic_phys_id, struct v3_icc_ops * ops, void * priv_data); -int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, uint8_t apic_phys_id); - -/** - * Send an inter-processor interrupt (IPI) from one local APIC to another local APIC. - * - * @param icc_bus - The ICC bus that routes IPIs. - * @param apic_src - The source APIC id. - * @param apic_num - The remote APIC number. - * @param icr - A copy of the APIC's ICR. (LAPIC-style ICR, clone from redir table for ioapics) - * @param dfr - A copy of the APIC's DFR (LAPIC-style DFR) - & @param extirq - irq for external interrupts (e.g., from 8259) - */ -int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t apic_src, uint64_t icr, uint32_t ext_irq); - - -#if 0 -/** - * Send an IRQinter-processor interrupt (IPI) from one local APIC to another local APIC. - * - * @param icc_bus - The ICC bus that routes IPIs. - * @param apic_src - The source APIC id. - * @param apic_num - The remote APIC number. - * @param icrlo - The low 32 bites of the APIC's ICR. - */ -int v3_icc_send_irq(struct vm_device * icc_bus, uint32_t ioapic_src, uint8_t apic_num, uint8_t irq); - -#endif - - -#endif /* ICC_BUS_H_ */ diff --git a/palacios/src/devices/Kconfig b/palacios/src/devices/Kconfig index 7bcc256..7185263 100644 --- a/palacios/src/devices/Kconfig +++ b/palacios/src/devices/Kconfig @@ -3,7 +3,7 @@ menu "Virtual Devices" config APIC bool "APIC" default y - depends on ICC_BUS && EXPERIMENTAL + depends on EXPERIMENTAL help Includes the Virtual APIC device @@ -19,7 +19,7 @@ config DEBUG_APIC config IO_APIC bool "IOAPIC" - depends on ICC_BUS && EXPERIMENTAL + depends on EXPERIMENTAL default y help Includes the Virtual IO APIC @@ -32,20 +32,6 @@ config DEBUG_IO_APIC Enable debugging for the IO APIC -config ICC_BUS - bool "ICC BUS" - default y - depends on EXPERIMENTAL - help - The ICC Bus for APIC/IOAPIC communication - -config DEBUG_ICC_BUS - bool "ICC BUS Debugging" - default n - depends on ICC_BUS && DEBUG_ON - help - Enable debugging for the ICC BUS - config BOCHS_DEBUG bool "Bochs Debug Console Device" diff --git a/palacios/src/devices/Makefile b/palacios/src/devices/Makefile index 817645d..7ed99be 100644 --- a/palacios/src/devices/Makefile +++ b/palacios/src/devices/Makefile @@ -1,6 +1,5 @@ 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 diff --git a/palacios/src/devices/apic.c b/palacios/src/devices/apic.c index 0254d67..d439e25 100644 --- a/palacios/src/devices/apic.c +++ b/palacios/src/devices/apic.c @@ -20,11 +20,11 @@ #include #include -#include #include #include #include #include +#include #ifndef CONFIG_DEBUG_APIC @@ -138,6 +138,8 @@ struct apic_msr { typedef enum {INIT, SIPI, STARTED} ipi_state_t; +struct apic_dev_state; + struct apic_state { addr_t base_addr; @@ -185,10 +187,10 @@ struct apic_state { uint8_t int_svc_reg[32]; uint8_t int_en_reg[32]; uint8_t trig_mode_reg[32]; - - uint32_t eoi; - struct vm_device * icc_bus; + struct guest_info * core; + + uint32_t eoi; v3_lock_t lock; }; @@ -196,11 +198,18 @@ struct apic_state { +struct apic_dev_state { + int num_apics; + + struct apic_state apics[0]; +} __attribute__((packed)); + + 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, uint32_t id, struct vm_device * icc) { +static void init_apic_state(struct apic_state * apic, uint32_t id) { apic->base_addr = DEFAULT_BASE_ADDR; if (id == 0) { @@ -231,8 +240,6 @@ static void init_apic_state(struct apic_state * apic, uint32_t id, struct vm_dev apic->lapic_id.val = id; - apic->icc_bus = icc; - apic->ipi_state = INIT; // The P6 has 6 LVT entries, so we set the value to (6-1)... @@ -265,9 +272,8 @@ static void init_apic_state(struct apic_state * apic, uint32_t id, struct vm_dev 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 * apics = (struct apic_state *)(dev->private_data); - struct apic_state * apic = &(apics[core->cpu_id]); + struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data; + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); PrintDebug("apic %u: core %u: MSR read\n", apic->lapic_id.val, core->cpu_id); v3_lock(apic->lock); @@ -278,13 +284,12 @@ static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, v 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 * apics = (struct apic_state *)(dev->private_data); - struct apic_state * apic = &(apics[core->cpu_id]); - struct v3_mem_region * old_reg = v3_get_mem_region(dev->vm, core->cpu_id, apic->base_addr); + struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data; + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); + struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->cpu_id, apic->base_addr); - PrintDebug("apic %u: core %u: MSR write\n",apic->lapic_id.val,core->cpu_id); + PrintDebug("apic %u: core %u: MSR write\n", apic->lapic_id.val, core->cpu_id); if (old_reg == NULL) { // uh oh... @@ -295,11 +300,11 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo v3_lock(apic->lock); - v3_delete_mem_region(dev->vm, old_reg); + v3_delete_mem_region(core->vm_info, old_reg); apic->base_addr = src.value; - 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) { + 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); @@ -481,8 +486,291 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t } + +static inline int should_deliver_cluster_ipi(struct guest_info * dst_core, + struct apic_state * dst_apic, uint8_t mda) { + + if ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) && // (I am in the cluster and + ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) { // I am in the set) + + PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n", + dst_apic->lapic_id.val, dst_core->cpu_id, mda, + dst_apic->log_dst.dst_log_id); + + return 1; + } else { + PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n", + dst_apic->lapic_id.val, dst_core->cpu_id, mda, dst_ + dst_apic->log_dst.dst_log_id); + return 0; + } +} + +static inline int should_deliver_flat_ipi(struct guest_info * dst_core, + struct apic_state * dst_apic, uint8_t mda) { + + if (dst_apic->log_dst.dst_log_id & mda) { // I am in the set + + PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n", + dst_apic->lapic_id.val, dst_core->cpu_id, mda, + dst_apic->log_dst.dst_log_id); + return 1; + } else { + PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n", + dst_apic->lapic_id.val, dst_core->cpu_id, mda, + dst_apic->log_dst.dst_log_id); + 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) { + return should_deliver_flat_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); + return -1; + } +} + + +static int deliver_ipi(struct guest_info * core, + struct apic_state * src_apic, + struct apic_state * dst_apic, + uint32_t vector, uint8_t del_mode) { + + struct guest_info * dst_core = dst_apic->core; + + switch (del_mode) { + + case 0: //fixed + case 1: // lowest priority + PrintDebug("icc_bus: delivering IRQ to core %u\n", dst_core->cpu_id); + + activate_apic_irq(dst_apic, vector); + + if (dst_apic != src_apic) { + // Assume core # is same as logical processor for now + // TODO FIX THIS FIX THIS + // THERE SHOULD BE: guestapicid->virtualapicid map, + // cpu_id->logical processor map + // host maitains logical proc->phsysical proc + PrintDebug("icc_bus: non-local core, forcing it to exit\n"); + + v3_interrupt_cpu(core->vm_info, dst_core->cpu_id, 0); + } + + break; + case 5: { //INIT + + PrintDebug("icc_bus: INIT delivery to core %u\n", dst_core->cpu_id); + + // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...) + + // Sanity check + if (dst_apic->ipi_state != INIT) { + PrintError("icc_bus: Warning: core %u is not in INIT state (mode = %d), ignored\n", + dst_core->cpu_id, dst_core->cpu_mode); + // Only a warning, since INIT INIT SIPI is common + break; + } + + // We transition the target core to SIPI state + dst_apic->ipi_state = SIPI; // note: locking should not be needed here + + // That should be it since the target core should be + // waiting in host on this transition + // either it's on another core or on a different preemptive thread + // in both cases, it will quickly notice this transition + // in particular, we should not need to force an exit here + + PrintDebug("icc_bus: INIT delivery done\n"); + + break; + } + case 6: { //SIPI + + // Sanity check + if (dst_apic->ipi_state != SIPI) { + PrintError("icc_bus: core %u is not in SIPI state (mode = %d), ignored!\n", + dst_core->cpu_id, dst_core->cpu_mode); + break; + } + + // Write the RIP, CS, and descriptor + // assume the rest is already good to go + // + // vector VV -> rip at 0 + // CS = VV00 + // This means we start executing at linear address VV000 + // + // So the selector needs to be VV00 + // and the base needs to be VV000 + // + dst_core->rip = 0; + dst_core->segments.cs.selector = vector << 8; + dst_core->segments.cs.limit = 0xffff; + dst_core->segments.cs.base = vector << 12; + + PrintDebug("icc_bus: SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n", + vec, dst_core->segments.cs.selector, dst_core->cpu_id); + // Maybe need to adjust the APIC? + + // We transition the target core to SIPI state + dst_core->core_run_state = CORE_RUNNING; // note: locking should not be needed here + + // As with INIT, we should not need to do anything else + + PrintDebug("icc_bus: SIPI delivery done\n"); + + break; + } + case 2: // SMI + case 3: // reserved + case 4: // NMI + case 7: // ExtInt + default: + PrintError("IPI %d delivery is unsupported\n", del_mode); + return -1; + } + + return 0; + +} + + +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; + struct apic_state * dest_apic = NULL; + + PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx, extirq=%u\n", + icc_bus, src_apic, icr_data, extirq); + + + // initial sanity checks + if (src_apic == NULL) { + PrintError("icc_bus: Apparently sending from unregistered apic id=%d\n", + src_apic->core->cpu_id); + return -1; + } + + + if ((icr->dst_mode == 0) && (icr->dst >= apic_dev->num_apics)) { + PrintError("icc_bus: Attempted send to unregistered apic id=%u\n", + icr->dst); + return -1; + } + + dest_apic = &(apic_dev->apics[icr->dst]); + + + PrintDebug("icc_bus: IPI %s %u from %s %u to %s %s %u (icr=0x%llx, extirq=%u)\n", + deliverymode_str[icr->del_mode], + icr->vec, + (src_apic == state->ioapic_id) ? "ioapic" : "apic", + src_apic, + (icr->dst_mode == 0) ? "(physical)" : "(logical)", + shorthand_str[icr->dst_shorthand], + icr->dst, + icr->val, + extirq); + + + switch (icr->dst_shorthand) { + + case 0: // no shorthand + if (icr->dst_mode == 0) { + // physical delivery + + if (deliver_ipi(core, src_apic, dest_apic, + icr->vec, icr->del_mode) == -1) { + PrintError("Error: Could not deliver IPI\n"); + return -1; + } + + } else { + // 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); + + if (del_flag == -1) { + PrintError("Error checking delivery mode\n"); + return -1; + } else if (del_flag == 1) { + if (deliver_ipi(core, src_apic, dest_apic, + icr->vec, icr->del_mode) == -1) { + PrintError("Error: Could not deliver IPI\n"); + return -1; + } + } + } + } + + break; + + case 1: // self + + if (icr->dst_mode == 0) { + if (deliver_ipi(core, 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"); + return -1; + } + break; + + case 2: + case 3: { // all and all-but-me + // assuming that logical verus physical doesn't matter + // although it is odd that both are used + int i; + + for (i = 0; i < apic_dev->num_apics; i++) { + 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) { + PrintError("Error: Could not deliver IPI\n"); + return -1; + } + } + } + + break; + } + default: + PrintError("Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand); + return -1; + } + + + return 0; +} + + + 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); + struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data); + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 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; @@ -745,7 +1033,8 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui * */ 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); + struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data); + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 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; @@ -909,13 +1198,15 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u case INT_CMD_LO_OFFSET: apic->int_cmd.lo = op_val; - // ICC??? PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n", apic->lapic_id.val, core->cpu_id, apic->int_cmd.val, apic->int_cmd.dst); - if (v3_icc_send_ipi(apic->icc_bus, apic->lapic_id.val, apic->int_cmd.val, 0)==-1) { + + if (route_ipi(core, apic_dev, apic, apic->int_cmd.val) == -1) { + PrintError("IPI Routing failure\n"); return -1; } + break; case INT_CMD_HI_OFFSET: @@ -943,8 +1234,9 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u /* Interrupt Controller Functions */ // returns 1 if an interrupt is pending, 0 otherwise -static int apic_intr_pending(struct guest_info * info, void * private_data) { - struct apic_state * apic = (struct apic_state *)private_data; +static int apic_intr_pending(struct guest_info * core, void * private_data) { + struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data); + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); int req_irq = get_highest_irr(apic); int svc_irq = get_highest_isr(apic); @@ -958,8 +1250,9 @@ static int apic_intr_pending(struct guest_info * info, void * private_data) { return 0; } -static int apic_get_intr_number(struct guest_info * info, void * private_data) { - struct apic_state * apic = (struct apic_state *)private_data; +static int apic_get_intr_number(struct guest_info * core, void * private_data) { + struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data); + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); int req_irq = get_highest_irr(apic); int svc_irq = get_highest_isr(apic); @@ -973,16 +1266,25 @@ static int apic_get_intr_number(struct guest_info * info, void * private_data) { } -static int apic_raise_intr(struct guest_info * info, int irq, void * private_data) { - struct apic_state * apic = (struct apic_state *)private_data; +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); + struct apic_state * apic = &(apic_dev->apics[dst]); + + activate_apic_irq(apic, irq); - return activate_apic_irq(apic, irq); + if (V3_Get_CPU() != dst) { + v3_interrupt_cpu(vm, dst, 0); + } + + return 0; } -static int apic_begin_irq(struct guest_info * info, void * private_data, int irq) { - struct apic_state * apic = (struct apic_state *)private_data; +static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) { + struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data); + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); int major_offset = (irq & ~0x00000007) >> 3; int minor_offset = irq & 0x00000007; uint8_t * req_location = apic->int_req_reg + major_offset; @@ -1007,10 +1309,12 @@ static int apic_begin_irq(struct guest_info * info, void * private_data, int irq /* Timer Functions */ -static void apic_update_time(struct guest_info * info, +static void apic_update_time(struct guest_info * core, uint64_t cpu_cycles, uint64_t cpu_freq, void * priv_data) { - struct apic_state * apic = (struct apic_state *)(priv_data); + struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data); + struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); + // The 32 bit GCC runtime is a pile of shit #ifdef __V3_64BIT__ uint64_t tmr_ticks = 0; @@ -1060,7 +1364,7 @@ static void apic_update_time(struct guest_info * info, break; default: PrintError("apic %u: core %u: Invalid Timer Divider configuration\n", - apic->lapic_id.val, info->cpu_id); + apic->lapic_id.val, core->cpu_id); return; } @@ -1078,7 +1382,7 @@ static void apic_update_time(struct guest_info * info, apic->lapic_id.val, info->cpu_id, apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num); - if (apic_intr_pending(info, priv_data)) { + if (apic_intr_pending(core, priv_data)) { PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", apic->lapic_id.val, info->cpu_id, apic_get_intr_number(info, priv_data)); @@ -1086,7 +1390,7 @@ static void apic_update_time(struct guest_info * info, if (activate_internal_irq(apic, APIC_TMR_INT) == -1) { PrintError("apic %u: core %u: Could not raise Timer interrupt\n", - apic->lapic_id.val, info->cpu_id); + apic->lapic_id.val, core->cpu_id); } if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) { @@ -1132,76 +1436,23 @@ static struct v3_device_ops dev_ops = { .stop = NULL, }; -static int apic_should_deliver_flat(struct guest_info * core, uint8_t mda, void * private_data) -{ - struct apic_state * apic = (struct apic_state *)private_data; - if (mda==0xff || // broadcast or - (apic->log_dst.dst_log_id & mda)) { // I am in the set - PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n", - apic->lapic_id.val, core->cpu_id, mda, apic->log_dst.dst_log_id); - return 1; - } else { - PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n", - apic->lapic_id.val, core->cpu_id, mda, apic->log_dst.dst_log_id); - return 0; - } -} -static int apic_should_deliver_cluster(struct guest_info * core, uint8_t mda, void * private_data) -{ - struct apic_state * apic = (struct apic_state *)private_data; - if (mda==0xff || // broadcast or - ( ((mda & 0xf0) == (apic->log_dst.dst_log_id & 0xf0)) && // (I am in the cluster and - ((mda & 0x0f) & (apic->log_dst.dst_log_id & 0x0f)) ) ) { // I am in the set) - PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n", - apic->lapic_id.val, core->cpu_id, mda, apic->log_dst.dst_log_id); - - return 1; - } else { - PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n", - apic->lapic_id.val, core->cpu_id, mda, apic->log_dst.dst_log_id); - return 0; - } -} - -static int apic_should_deliver(struct guest_info * core, uint8_t mda, void *private_data) -{ - struct apic_state * apic = (struct apic_state *)private_data; - if (apic->dst_fmt.model == 0xf) { - return apic_should_deliver_cluster(core, mda, private_data); - } else if (apic->dst_fmt.model == 0x0) { - return apic_should_deliver_flat(core, mda, private_data); - } else { - PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", apic->lapic_id.val, core->cpu_id, apic->dst_fmt.model); - return 0; - } -} - -static struct v3_icc_ops icc_ops = { - .raise_intr = apic_raise_intr, - .should_deliver = apic_should_deliver, -}; static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { - PrintDebug("apic: creating an APIC for each core\n"); char * dev_id = v3_cfg_val(cfg, "ID"); - char * icc_bus_id = v3_cfg_val(cfg, "bus"); - struct vm_device * icc = v3_find_dev(vm, icc_bus_id); - int i; + struct apic_dev_state * apic_dev = NULL; + int i = 0; - if (!icc) { - PrintError("apic: Cannot find ICC Bus (%s)\n", icc_bus_id); - return -1; - } + PrintDebug("apic: creating an APIC for each core\n"); - // We allocate one apic per core - // APICs are accessed via index which correlates with the core's cpu_id - // 0..num_cores-1 at num_cores is the ioapic (one only) - struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state) * vm->num_cores); + apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + + sizeof(struct apic_state) * vm->num_cores); - struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic); + apic_dev->num_apics = vm->num_cores; + + struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic_dev); if (v3_attach_device(vm, dev) == -1) { PrintError("apic: Could not attach device %s\n", dev_id); @@ -1210,30 +1461,34 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { for (i = 0; i < vm->num_cores; i++) { + struct apic_state * apic = &(apic_dev->apics[i]); struct guest_info * core = &(vm->cores[i]); - init_apic_state(&(apic[i]),i,icc); - - v3_register_intr_controller(core, &intr_ops, &(apic[i])); + apic->core = core; - v3_add_timer(core, &timer_ops, &(apic[i])); + init_apic_state(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_register_intr_controller(core, &intr_ops, apic_dev); - v3_icc_register_apic(core, icc, i, &icc_ops, &(apic[i])); + v3_add_timer(core, &timer_ops, apic_dev); - PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic[i].lapic_id.val); + v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev); + PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val); } +#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[i]), apic[i].lapic_id.val, apic[i].base_addr_msr.value); + i, apic, apic->lapic_id.val, apic->base_addr_msr.value); } +#endif + - PrintDebug("apic: priv_data is at %p\n", apic); + PrintDebug("apic: priv_data is at %p\n", apic_dev); - v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev); + v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev); return 0; } diff --git a/palacios/src/devices/icc_bus.c b/palacios/src/devices/icc_bus.c deleted file mode 100644 index f1cb982..0000000 --- a/palacios/src/devices/icc_bus.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * 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 - * Copyright (c) 2008, The V3VEE Project - * All rights reserved. - * - * Author: Jack Lange - * - * This is free software. You are permitted to use, - * redistribute, and modify it as specified in the file "V3VEE_LICENSE". - */ - -#include -#include -#include -#include -#include - -#define MAX_APICS 256 - -#ifndef CONFIG_DEBUG_ICC_BUS -#undef PrintDebug -#define PrintDebug(fmt, args...) -#endif - - -void v3_force_exit(void *p) { -#ifdef CONFIG_DEBUG_ICC_BUS - struct guest_info *core=(struct guest_info *)p; -#endif - PrintDebug("core %u: Forced to exit!\n",core->cpu_id); -} - -struct ipi_thunk_data { - struct vm_device * target; - uint64_t val; -}; - - - -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]; - - uint32_t ioapic_id; -}; - -static struct v3_device_ops dev_ops = { - .free = NULL, - .reset = NULL, - .start = NULL, - .stop = NULL, -}; - -#ifdef CONFIG_DEBUG_ICC_BUS -static char *shorthand_str[] = { - "(no shorthand)", - "(self)", - "(all)", - "(all-but-me)", - }; - -static char *deliverymode_str[] = { - "(fixed)", - "(lowest priority)", - "(SMI)", - "(reserved)", - "(NMI)", - "(INIT)", - "(Start Up)", - "(ExtInt)", -}; -#endif - - -static int deliver(uint32_t src_apic, struct apic_data *dest_apic, struct int_cmd_reg *icr, struct icc_bus_state * state, uint32_t extirq) { - - switch (icr->del_mode) { - - case 0: //fixed - case 1: // lowest priority - case 7: // ExtInt - PrintDebug("icc_bus: delivering IRQ to core %u\n",dest_apic->core->cpu_id); - - dest_apic->ops->raise_intr(dest_apic->core, - (icr->del_mode != 7) ? icr->vec : extirq, - dest_apic->priv_data); - - if ((src_apic != state->ioapic_id) && (dest_apic->core->cpu_id != src_apic)) { - // Assume core # is same as logical processor for now - // TODO FIX THIS FIX THIS - // THERE SHOULD BE: guestapicid->virtualapicid map, - // cpu_id->logical processor map - // host maitains logical proc->phsysical proc - PrintDebug("icc_bus: non-local core, forcing it to exit\n"); - - V3_Call_On_CPU(dest_apic->core->cpu_id, v3_force_exit, (void *)(dest_apic->core)); - // TODO: do what the print says - } - break; - - case 2: //SMI - PrintError("icc_bus: SMI delivery is unsupported\n"); - return -1; - break; - - case 3: //reserved - PrintError("icc_bus: Reserved delivery mode 3 is unsupported\n"); - return -1; - break; - - case 4: //NMI - PrintError("icc_bus: NMI delivery is unsupported\n"); - return -1; - break; - - case 5: { //INIT - struct guest_info *core = dest_apic->core; - - PrintDebug("icc_bus: INIT delivery to core %u\n", core->cpu_id); - - // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...) - - // Sanity check - if (dest_apic->ipi_state != INIT) { - PrintError("icc_bus: Warning: core %u is not in INIT state (mode = %d), ignored\n", - core->cpu_id, core->cpu_mode); - // Only a warning, since INIT INIT SIPI is common - break; - } - - // We transition the target core to SIPI state - dest_apic->ipi_state = SIPI; // note: locking should not be needed here - - // That should be it since the target core should be - // waiting in host on this transition - // either it's on another core or on a different preemptive thread - // in both cases, it will quickly notice this transition - // in particular, we should not need to force an exit here - - PrintDebug("icc_bus: INIT delivery done\n"); - - } - break; - - case 6: { //SIPI - struct guest_info *core = dest_apic->core; - - // Sanity check - if (dest_apic->ipi_state != SIPI) { - PrintError("icc_bus: core %u is not in SIPI state (mode = %d), ignored!\n",core->cpu_id, core->cpu_mode); - break; - } - - // Write the RIP, CS, and descriptor - // assume the rest is already good to go - // - // vector VV -> rip at 0 - // CS = VV00 - // This means we start executing at linear address VV000 - // - // So the selector needs to be VV00 - // and the base needs to be VV000 - // - core->rip = 0; - core->segments.cs.selector = icr->vec << 8; - core->segments.cs.limit = 0xffff; - core->segments.cs.base = icr->vec << 12; - - PrintDebug("icc_bus: SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n", - icr->vec, core->segments.cs.selector, core->cpu_id); - // Maybe need to adjust the APIC? - - // We transition the target core to SIPI state - core->core_run_state = CORE_RUNNING; // note: locking should not be needed here - - // As with INIT, we should not need to do anything else - - PrintDebug("icc_bus: SIPI delivery done\n"); - - } - break; - } - - return 0; -} - - -// -// icr_data contains interrupt vector *except* for ext_int -// in which case it is given via irq -// - -int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data, uint32_t extirq) { - - struct int_cmd_reg *icr = (struct int_cmd_reg *)&icr_data; - - struct icc_bus_state * state = (struct icc_bus_state *)icc_bus->private_data; - struct apic_data * dest_apic = NULL; - PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx, extirq=%u\n", - icc_bus, src_apic, icr_data, extirq); - - // initial sanity checks - if ((src_apic >= MAX_APICS) || - ((state->apics[src_apic].present == 0) && - (src_apic != state->ioapic_id))) { - PrintError("icc_bus: Apparently sending from unregistered apic id=%u\n",src_apic); - return -1; - } - - - if ((icr->dst_mode == 0) && (state->apics[icr->dst].present == 0)) { - PrintError("icc_bus: Attempted send to unregistered apic id=%u\n", icr->dst); - return -1; - } - - dest_apic = &(state->apics[icr->dst]); - - - PrintDebug("icc_bus: IPI %s %u from %s %u to %s %s %u (icr=0x%llx, extirq=%u)\n", - deliverymode_str[icr->del_mode], icr->vec, - src_apic==state->ioapic_id ? "ioapic" : "apic", - src_apic, - icr->dst_mode==0 ? "(physical)" : "(logical)", - shorthand_str[icr->dst_shorthand], icr->dst,icr->val, - extirq); - - /* - - if (icr->dst==state->ioapic_id) { - PrintError("icc_bus: Attempted send to ioapic ignored\n"); - return -1; - } - */ - - - - switch (icr->dst_shorthand) { - - case 0: // no shorthand - - if (icr->dst_mode==0) { - // physical delivery - struct apic_data * dest_apic = &(state->apics[icr->dst]); - if (deliver(src_apic,dest_apic,icr,state,extirq)) { - return -1; - } - } else { - // logical delivery - int i; - uint8_t mda = icr->dst; - for (i=0;iapics[i]); - if (dest_apic->present && - dest_apic->ops->should_deliver(dest_apic->core, - mda, - dest_apic->priv_data)) { - if (deliver(src_apic,dest_apic,icr,state,extirq)) { - return -1; - } - } - } - } - - break; - - case 1: // self - - if (icr->dst_mode==0) { - // physical delivery - if (icr->dst==state->ioapic_id) { - PrintError("icc_bus: ioapic attempting to send to itself\n"); - return -1; - } - struct apic_data *dest_apic=&(state->apics[src_apic]); - if (deliver(src_apic,dest_apic,icr,state,extirq)) { - return -1; - } - } else { - // logical delivery - PrintError("icc_bus: use of logical delivery in self is not yet supported.\n"); - - return -1; - } - break; - - case 2: - - case 3: { // all and all-but-me - // assuming that logical verus physical doesn't matter - // although it is odd that both are used - int i; - for (i=0;iapics[i]); - if (dest_apic->present && (i!=src_apic || icr->dst_shorthand==2)) { - if (deliver(src_apic,dest_apic,icr,state,extirq)) { - return -1; - } - } - } - } - break; - - default: - return -1; - } - - - 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("icc_bus: 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("icc_bus: Registered apic %u\n", apic_num); - - return 0; -} - - -int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, uint8_t apic_num) -{ - struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data; - - if (icc->ioapic_id) { - PrintError("icc_bus: Attempt to register a second ioapic!\n"); - return -1; - } - - icc->ioapic_id=apic_num; - - PrintDebug("icc_bus: Registered ioapic %u\n", apic_num); - - - return 0; -} - - -static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { - PrintDebug("icc_bus: Creating ICC_BUS\n"); - - char * dev_id = v3_cfg_val(cfg, "ID"); - - 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(dev_id, &dev_ops, icc_bus); - - if (v3_attach_device(vm, dev) == -1) { - PrintError("icc_bus: Could not attach device %s\n", dev_id); - return -1; - } - - return 0; -} - - - -device_register("ICC_BUS", icc_bus_init) diff --git a/palacios/src/devices/io_apic.c b/palacios/src/devices/io_apic.c index fc6fdb9..8fa49ee 100644 --- a/palacios/src/devices/io_apic.c +++ b/palacios/src/devices/io_apic.c @@ -20,8 +20,7 @@ #include #include -#include -#include +#include #include #ifndef CONFIG_DEBUG_IO_APIC @@ -136,7 +135,7 @@ struct io_apic_state { struct redir_tbl_entry redir_tbl[24]; - struct vm_device * icc_bus; + struct vm_device * apic_dev; }; @@ -276,26 +275,19 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq if (irq_entry->mask == 0) { - PrintDebug("ioapic %u: IOAPIC Signalling APIC to raise INTR %d\n", ioapic->ioapic_id.id, irq_entry->vec); + PrintDebug("ioapic %u: IOAPIC Signalling APIC to raise INTR %d\n", + ioapic->ioapic_id.id, irq_entry->vec); - - // the format of the redirection table entry is just slightly - // different than that of the lapic's cmd register, which is the other - // way an IPI is initiated. So we will translate - // - struct int_cmd_reg icr; - icr.val = irq_entry->val; - icr.rsvd1=0; - icr.lvl=1; - icr.trig_mode=irq_entry->trig_mode; - icr.rem_rd_status=0; - icr.dst_shorthand=0; // no shorthand - icr.rsvd2=0; - - PrintDebug("io apic %u: raising irq %u on ICC bus.\n", - ioapic->ioapic_id.id, irq); - v3_icc_send_ipi(ioapic->icc_bus, ioapic->ioapic_id.id,icr.val, irq); + // May need these for future reference + // icr.val = irq_entry->val; + // icr.trig_mode = irq_entry->trig_mode; + + PrintDebug("io apic: raising irq %u\n", irq); + + + v3_apic_raise_intr(vm, ioapic->apic_dev, irq, irq_entry->val); + } return 0; @@ -331,19 +323,15 @@ static struct v3_device_ops dev_ops = { 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, "bus")); + struct vm_device * apic_dev = v3_find_dev(vm, v3_cfg_val(cfg, "apic")); char * dev_id = v3_cfg_val(cfg, "ID"); - if (!icc_bus) { - PrintError("ioapic: Could not locate ICC BUS device (%s)\n", v3_cfg_val(cfg, "bus")); - return -1; - } PrintDebug("ioapic: Creating IO APIC\n"); struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state)); - ioapic->icc_bus = icc_bus; + ioapic->apic_dev = apic_dev; struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, ioapic); @@ -358,8 +346,6 @@ static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { init_ioapic_state(ioapic,vm->num_cores); - v3_icc_register_ioapic(vm,icc_bus,ioapic->ioapic_id.id); - v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, ioapic_read, ioapic_write, dev);