From: Peter Dinda Date: Thu, 8 Jul 2010 23:11:53 +0000 (-0500) Subject: Partially functional icc_bus (works for UP) X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=300810f123725663d5f7ae638ff6cb93d0a89ae5 Partially functional icc_bus (works for UP) Works up to init for SMP --- diff --git a/palacios/include/devices/apic_regs.h b/palacios/include/devices/apic_regs.h index 4d4f540..67f5b24 100644 --- a/palacios/include/devices/apic_regs.h +++ b/palacios/include/devices/apic_regs.h @@ -220,7 +220,7 @@ struct int_cmd_reg { struct { uint_t vec : 8; - uint_t msg_type : 3; + uint_t del_mode : 3; uint_t dst_mode : 1; uint_t del_status : 1; uint_t rsvd1 : 1; diff --git a/palacios/include/devices/icc_bus.h b/palacios/include/devices/icc_bus.h index c51f6f8..6b1fabb 100644 --- a/palacios/include/devices/icc_bus.h +++ b/palacios/include/devices/icc_bus.h @@ -29,19 +29,32 @@ struct v3_icc_ops { /** * */ -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); - +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 this local APIC to another local APIC. + * Send an inter-processor interrupt (IPI) from one local APIC to another local APIC. * - * @param icc_bus - The ICC bus that routes IPIs. + * @param icc_bus - The ICC bus that routes IPIs. + * @param apic_src - The source APIC id. * @param apic_num - The remote APIC number. - * @param intr_num - The interrupt number. + * @param icr - A copy of the APIC's ICR. (LAPIC-style ICR, clone from redir table for ioapics) */ -int v3_icc_send_irq(struct vm_device * icc_bus, uint8_t apic_num, uint32_t irq_num); +int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t apic_src, uint64_t icr); + +#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 b04376f..9a07e71 100644 --- a/palacios/src/devices/Kconfig +++ b/palacios/src/devices/Kconfig @@ -38,6 +38,13 @@ config ICC_BUS 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/apic.c b/palacios/src/devices/apic.c index 7289717..b35258d 100644 --- a/palacios/src/devices/apic.c +++ b/palacios/src/devices/apic.c @@ -191,12 +191,12 @@ struct apic_state { 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) { +static void init_apic_state(struct apic_state * apic, uint32_t id, struct vm_device * icc) { apic->base_addr = DEFAULT_BASE_ADDR; apic->base_addr_msr.value = 0x0000000000000900LL; apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); - PrintDebug("Sizeof Interrupt Request Register %d, should be 32\n", + PrintDebug("apic %u: Sizeof Interrupt Request Register %d, should be 32\n", apic->lapic_id.val, (uint_t)sizeof(apic->int_req_reg)); memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg)); @@ -210,6 +210,8 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) { apic->tmr_cur_cnt = 0x00000000; apic->lapic_id.val = id; + + apic->icc_bus = icc; // The P6 has 6 LVT entries, so we set the value to (6-1)... apic->apic_ver.val = 0x80050010; @@ -261,7 +263,7 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo if (old_reg == NULL) { // uh oh... - PrintError("APIC Base address region does not exit...\n"); + PrintError("apic %u: APIC Base address region does not exit...\n",apic->lapic_id.val); return -1; } @@ -272,7 +274,7 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo 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) { - PrintError("Could not hook new APIC Base address\n"); + PrintError("apic %u: Could not hook new APIC Base address\n",apic->lapic_id.val); v3_unlock(apic->lock); return -1; } @@ -290,12 +292,18 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) { uchar_t * en_location = apic->int_en_reg + major_offset; uchar_t flag = 0x1 << minor_offset; + +#if 1 + if (irq_num <= 15) { - PrintError("Attempting to raise an invalid interrupt: %d\n", irq_num); + PrintError("apic %u: Attempting to raise an invalid interrupt: %d\n", apic->lapic_id.val,irq_num); return -1; } - PrintDebug("Raising APIC IRQ %d\n", irq_num); +#endif + + + PrintDebug("apic %u: Raising APIC IRQ %d\n", apic->lapic_id.val,irq_num); if (*req_location & flag) { //V3_Print("Interrupts coallescing\n"); @@ -304,7 +312,7 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) { if (*en_location & flag) { *req_location |= flag; } else { - PrintDebug("Interrupt not enabled... %.2x\n", *en_location); + PrintDebug("apic %u: Interrupt not enabled... %.2x\n", apic->lapic_id.val, *en_location); return 0; } @@ -428,13 +436,13 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t masked = apic->err_vec_tbl.mask; break; default: - PrintError("Invalid APIC interrupt type\n"); + PrintError("apic %u: Invalid APIC interrupt type\n",apic->lapic_id.val); return -1; } // interrupt is masked, don't send if (masked == 1) { - PrintDebug("Inerrupt is masked\n"); + PrintDebug("apic %u: Inerrupt is masked\n",apic->lapic_id.val); return 0; } @@ -442,24 +450,25 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t //PrintDebug("Activating internal APIC IRQ %d\n", vec_num); return activate_apic_irq(apic, vec_num); } else { - PrintError("Unhandled Delivery Mode\n"); + PrintError("apic %u: Unhandled Delivery Mode\n",apic->lapic_id.val); return -1; } } 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_state * apics = (struct apic_state *)(priv_data); + struct apic_state * apic = &(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; - PrintDebug("Read apic address space (%p)\n", + PrintDebug("apic %u: Read apic address space (%p)\n",apic->lapic_id.val, (void *)guest_addr); if (msr->apic_enable == 0) { - PrintError("Write to APIC address space with disabled APIC\n"); + PrintError("apic %u: Write to APIC address space with disabled APIC\n",apic->lapic_id.val); return -1; } @@ -671,8 +680,9 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui case SEOI_OFFSET: default: - PrintError("Read from Unhandled APIC Register: %x\n", (uint32_t)reg_addr); - return -1; + PrintError("apic %u: Read from Unhandled APIC Register: %x (getting zero)\n", apic->lapic_id.val, (uint32_t)reg_addr); + // return -1; + val=0; } @@ -693,11 +703,11 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui *val_ptr = val; } else { - PrintError("Invalid apic read length (%d)\n", length); + PrintError("apic %u: Invalid apic read length (%d)\n", apic->lapic_id.val, length); return -1; } - PrintDebug("Read finished (val=%x)\n", *(uint32_t *)dst); + PrintDebug("apic %u: Read finished (val=%x)\n", apic->lapic_id.val, *(uint32_t *)dst); return length; } @@ -707,22 +717,24 @@ 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_state * apics = (struct apic_state *)(priv_data); + struct apic_state * apic = &(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; - PrintDebug("Write to apic address space (%p) (val=%x)\n", + PrintDebug("apic %u: Write to address space (%p) (val=%x)\n", + apic->lapic_id.val, (void *)guest_addr, *(uint32_t *)src); if (msr->apic_enable == 0) { - PrintError("Write to APIC address space with disabled APIC\n"); + PrintError("apic %u: Write to APIC address space with disabled APIC\n",apic->lapic_id.val); return -1; } if (length != 4) { - PrintError("Invalid apic write length (%d)\n", length); + PrintError("apic %u: Invalid apic write length (%d)\n", apic->lapic_id.val, length); return -1; } @@ -757,9 +769,9 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u case PPR_OFFSET: case EXT_APIC_FEATURE_OFFSET: #if 1 - PrintError("Attempting to write to read only register %p (ignored)\n", (void *)reg_addr); + PrintError("apic %u: Attempting to write to read only register %p (ignored)\n", apic->lapic_id.val, (void *)reg_addr); #else - PrintError("Attempting to write to read only register %p (error)\n", (void *)reg_addr); + PrintError("apic %u: Attempting to write to read only register %p (error)\n", apic->lapic_id.val, (void *)reg_addr); return -1; #endif break; @@ -862,7 +874,9 @@ 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??? - v3_icc_send_irq(apic->icc_bus, apic->int_cmd.dst, apic->int_cmd.val); + PrintDebug("apic %u: sending cmd 0x%llx to apic %u\n",apic->lapic_id.val, + apic->int_cmd.val, apic->int_cmd.dst); + v3_icc_send_ipi(apic->icc_bus, apic->lapic_id.val, apic->int_cmd.val); break; case INT_CMD_HI_OFFSET: apic->int_cmd.hi = op_val; @@ -872,11 +886,11 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u case EXT_APIC_CMD_OFFSET: case SEOI_OFFSET: default: - PrintError("Write to Unhandled APIC Register: %x\n", (uint32_t)reg_addr); - return -1; + PrintError("apic %u: Write to Unhandled APIC Register: %x (ignored)\n", apic->lapic_id.val, (uint32_t)reg_addr); + // return -1; } - PrintDebug("Write finished\n"); + PrintDebug("apic %u: Write finished\n",apic->lapic_id.val); return length; } @@ -943,7 +957,8 @@ 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, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) { - struct apic_state * apic = (struct apic_state *)priv_data; + struct apic_state * apics = (struct apic_state *)(priv_data); + struct apic_state * apic = &(apics[info->cpu_id]); // The 32 bit GCC runtime is a pile of shit #ifdef __V3_64BIT__ uint64_t tmr_ticks = 0; @@ -961,7 +976,7 @@ static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullo if ((apic->tmr_init_cnt == 0) || ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) && (apic->tmr_cur_cnt == 0))) { - //PrintDebug("APIC timer not yet initialized\n"); + //PrintDebug("apic %u: APIC timer not yet initialized\n",apic->lapic_id.val); return; } @@ -992,7 +1007,7 @@ static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullo shift_num = 7; break; default: - PrintError("Invalid Timer Divider configuration\n"); + PrintError("apic %u: Invalid Timer Divider configuration\n",apic->lapic_id.val); return; } @@ -1006,15 +1021,15 @@ static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullo apic->tmr_cur_cnt = 0; // raise irq - PrintDebug("Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", + PrintDebug("apic %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", apic->lapic_id.val, 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(info, priv_data)); + PrintDebug("apic %u: Overriding pending IRQ %d\n", apic->lapic_id.val, apic_get_intr_number(info, priv_data)); } if (activate_internal_irq(apic, APIC_TMR_INT) == -1) { - PrintError("Could not raise Timer interrupt\n"); + PrintError("apic %u: Could not raise Timer interrupt\n",apic->lapic_id.val); } if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) { @@ -1042,6 +1057,9 @@ static struct vm_timer_ops timer_ops = { static int apic_free(struct vm_device * dev) { + + /* TODO: This should crosscall to force an unhook on each CPU */ + // struct apic_state * apic = (struct apic_state *)dev->private_data; v3_unhook_msr(dev->vm, BASE_ADDR_MSR); @@ -1066,14 +1084,14 @@ static struct v3_icc_ops icc_ops = { static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { - PrintDebug("Creating an APIC for each core\n"); + PrintDebug("apic: creating an APIC for each core\n"); char * name = v3_cfg_val(cfg, "name"); char * icc_name = v3_cfg_val(cfg,"bus"); struct vm_device * icc = v3_find_dev(vm, icc_name); int i; if (!icc) { - PrintError("Cannot find ICC Bus (%s)\n", icc_name); + PrintError("apic: Cannot find ICC Bus (%s)\n", icc_name); return -1; } @@ -1085,7 +1103,7 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { struct vm_device * dev = v3_allocate_device(name, &dev_ops, apic); if (v3_attach_device(vm, dev) == -1) { - PrintError("Could not attach device %s\n", name); + PrintError("apic: Could not attach device %s\n", name); return -1; } @@ -1093,7 +1111,7 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { for (i = 0; i < vm->num_cores; i++) { struct guest_info * core = &(vm->cores[i]); - init_apic_state(&(apic[i]),i); + init_apic_state(&(apic[i]),i,icc); v3_register_intr_controller(core, &intr_ops, &(apic[i])); diff --git a/palacios/src/devices/icc_bus.c b/palacios/src/devices/icc_bus.c index f5de549..e75734d 100644 --- a/palacios/src/devices/icc_bus.c +++ b/palacios/src/devices/icc_bus.c @@ -21,41 +21,25 @@ #include #include #include +#include + #define MAX_APICS 256 +#ifndef CONFIG_DEBUG_ICC_BUS +#undef PrintDebug +#define PrintDebug(fmt, args...) +#endif + + +void v3_force_exit() { +} 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 { @@ -69,6 +53,8 @@ struct apic_data { struct icc_bus_state { struct apic_data apics[MAX_APICS]; + + uint32_t ioapic_id; }; static struct v3_device_ops dev_ops = { @@ -79,59 +65,131 @@ static struct v3_device_ops dev_ops = { }; +static char *shorthand_str[] = { + "(no shorthand)", + "(self)", + "(all)", + "(all-but-me)", + }; + +static char *deliverymode_str[] = { + "(fixed)", + "(lowest priority)", + "(SMI)", + "(reserved)", + "(NMI)", + "(INIT)", + "(Start Up)", + "(reserved)", +}; -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]); +static int deliver(uint32_t src_apic, struct apic_data *dest_apic, struct int_cmd_reg *icr, struct icc_bus_state * state) { + + switch (icr->del_mode) { + + case 0: //fixed + case 1: // lowest priority + PrintDebug("icc_bus: delivering to core %u\n",dest_apic->core->cpu_id); + dest_apic->ops->raise_intr(dest_apic->core, icr->vec, dest_apic->priv_data); + if (src_apic!=state->ioapic_id && dest_apic->core->cpu_id != src_apic) { + PrintDebug("icc_bus: non-local core, forcing it to exit\n"); + // TODO: do what the print says + } + break; + + case 2: //SMI + PrintError("icc_bus: SMI delivery is unsupported\n"); + return -1; + break; + + case 3: //reserved + case 7: + 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 + PrintError("icc_bus: INIT delivery is unsupported\n"); + return -1; + break; + + case 6: //Start Up + PrintError("icc_bus: Startup Delivery is unsupported\n"); + return -1; + break; + } - struct int_cmd_reg icr; - icr.lo = irq_num; + return 0; +} - 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; - } +int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data) { - switch (icr.msg_type) { - case 0x0: - type = ""; - break; - case 0x4: - type = "(NMI)"; - break; - case 0x5: - type = "(INIT)"; - break; - case 0x6: - type = "(Startup)"; - break; + PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx\n",icc_bus,src_apic,icr_data); + + struct int_cmd_reg *icr = (struct int_cmd_reg *)&icr_data; + struct icc_bus_state * state = (struct icc_bus_state *)icc_bus->private_data; + + // initial sanity checks + if (src_apic>=MAX_APICS || (!state->apics[src_apic].present && 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) { + PrintError("icc_bus: Attempted send to unregistered apic id=%u\n",icr->dst); + return -1; } + + struct apic_data * dest_apic = &(state->apics[icr->dst]); + + + PrintDebug("icc_bus: IPI %s %u from %s %u to %s %u (icr=0x%llx)\n", + deliverymode_str[icr->del_mode], icr->vec, src_apic==state->ioapic_id ? "ioapic" : "apic", + src_apic, shorthand_str[icr->dst_shorthand], icr->dst,icr->val); - PrintDebug("Sending IPI of type %s and destination type %s from LAPIC %u to LAPIC %u.\n", - type, dest, V3_Get_CPU(), apic_num); - 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)); + switch (icr->dst_shorthand) { + + case 0: // no shorthand + if (deliver(src_apic,dest_apic,icr,state)) { + return -1; + } + break; + + case 1: // self + if (icr->dst==state->ioapic_id) { + PrintError("icc_bus: ioapic attempting to send to itself\n"); + return -1; + } + if (deliver(src_apic,dest_apic,icr,state)) { + return -1; + } + break; + + case 2: + case 3: { // all and all-but-me + 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)) { + return -1; + } + } + } + } + break; + } return 0; } @@ -146,7 +204,7 @@ int v3_icc_register_apic(struct guest_info * core, struct vm_device * icc_bus, struct apic_data * apic = &(icc->apics[apic_num]); if (apic->present == 1) { - PrintError("Attempt to re-register apic %u\n", apic_num); + PrintError("icc_bus: Attempt to re-register apic %u\n", apic_num); return -1; } @@ -155,16 +213,33 @@ int v3_icc_register_apic(struct guest_info * core, struct vm_device * icc_bus, apic->core = core; apic->ops = ops; - PrintDebug("Registered apic%u\n", apic_num); + 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("Creating ICC_BUS\n"); + PrintDebug("icc_bus: Creating ICC_BUS\n"); char * name = v3_cfg_val(cfg, "name"); @@ -174,7 +249,7 @@ static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { 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); + PrintError("icc_bus: Could not attach device %s\n", name); return -1; } diff --git a/palacios/src/devices/io_apic.c b/palacios/src/devices/io_apic.c index 9a0db56..263f940 100644 --- a/palacios/src/devices/io_apic.c +++ b/palacios/src/devices/io_apic.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #ifndef CONFIG_DEBUG_IO_APIC @@ -140,12 +141,12 @@ struct io_apic_state { }; -static void init_ioapic_state(struct io_apic_state * ioapic) { +static void init_ioapic_state(struct io_apic_state * ioapic, uint32_t id) { int i = 0; ioapic->base_addr = IO_APIC_BASE_ADDR; ioapic->index_reg = 0; - ioapic->ioapic_id.val = 0x00000000; + ioapic->ioapic_id.val = id; ioapic->ioapic_ver.val = 0x00170011; ioapic->ioapic_arb_id.val = 0x00000000; @@ -163,7 +164,7 @@ static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint32_t reg_tgt = guest_addr - ioapic->base_addr; uint32_t * op_val = (uint32_t *)dst; - PrintDebug("IOAPIC Read at %p\n", (void *)guest_addr); + PrintDebug("ioapic %u: IOAPIC Read at %p\n", ioapic->ioapic_id.val, (void *)guest_addr); if (reg_tgt == 0x00) { *op_val = ioapic->index_reg; @@ -185,7 +186,7 @@ static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) % 1; if (redir_index > 0x3f) { - PrintError("Invalid redirection table entry %x\n", (uint32_t)redir_index); + PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.val, (uint32_t)redir_index); return -1; } if (hi_val) { @@ -207,7 +208,7 @@ static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, uint32_t reg_tgt = guest_addr - ioapic->base_addr; uint32_t op_val = *(uint32_t *)src; - PrintDebug("IOAPIC Write at %p (val = %d)\n", (void *)guest_addr, *(uint32_t *)src); + PrintDebug("ioapic %u: IOAPIC Write at %p (val = %d)\n", ioapic->ioapic_id.val, (void *)guest_addr, *(uint32_t *)src); if (reg_tgt == 0x00) { ioapic->index_reg = op_val; @@ -219,7 +220,7 @@ static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, break; case IOAPIC_VER_REG: // GPF/PageFault/Ignore? - PrintError("Writing to read only IOAPIC register\n"); + PrintError("ioapic %u: Writing to read only IOAPIC register\n", ioapic->ioapic_id.val); return -1; case IOAPIC_ARB_REG: ioapic->ioapic_arb_id.val = op_val; @@ -233,14 +234,14 @@ static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, if (redir_index > 0x3f) { - PrintError("Invalid redirection table entry %x\n", (uint32_t)redir_index); + PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.val, (uint32_t)redir_index); return -1; } if (hi_val) { - PrintDebug("Writing to hi of pin %d\n", redir_index); + PrintDebug("ioapic %u: Writing to hi of pin %d\n", ioapic->ioapic_id.val, redir_index); ioapic->redir_tbl[redir_index].hi = op_val; } else { - PrintDebug("Writing to lo of pin %d\n", redir_index); + PrintDebug("ioapic %u: Writing to lo of pin %d\n", ioapic->ioapic_id.val, redir_index); op_val &= REDIR_LO_MASK; ioapic->redir_tbl[redir_index].lo &= ~REDIR_LO_MASK; ioapic->redir_tbl[redir_index].lo |= op_val; @@ -259,15 +260,30 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq struct redir_tbl_entry * irq_entry = NULL; if (irq > 24) { - PrintDebug("IRQ out of range of IO APIC\n"); + PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.val); return -1; } irq_entry = &(ioapic->redir_tbl[irq]); if (irq_entry->mask == 0) { - PrintDebug("IOAPIC Signalling APIC to raise INTR %d\n", irq_entry->vec); - v3_icc_send_irq(ioapic->icc_bus, irq_entry->dst_field, irq_entry->vec); + PrintDebug("ioapic %u: IOAPIC Signalling APIC to raise INTR %d\n", ioapic->ioapic_id.val, 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; + + v3_icc_send_ipi(ioapic->icc_bus, ioapic->ioapic_id.val,icr.val); } return 0; @@ -307,11 +323,11 @@ static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { char * name = v3_cfg_val(cfg, "name"); if (!icc_bus) { - PrintError("Could not locate ICC BUS device (%s)\n", v3_cfg_val(cfg, "bus")); + PrintError("ioapic: Could not locate ICC BUS device (%s)\n", v3_cfg_val(cfg, "bus")); return -1; } - PrintDebug("Creating IO APIC\n"); + PrintDebug("ioapic: Creating IO APIC\n"); struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state)); @@ -321,13 +337,16 @@ static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { if (v3_attach_device(vm, dev) == -1) { - PrintError("Could not attach device %s\n", name); + PrintError("ioapic: Could not attach device %s\n", name); return -1; } v3_register_intr_router(vm, &router_ops, dev); - init_ioapic_state(ioapic); + + init_ioapic_state(ioapic,vm->num_cores); + + v3_icc_register_ioapic(vm,icc_bus,ioapic->ioapic_id.val); v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, ioapic_read, ioapic_write, dev); diff --git a/palacios/src/palacios/vmm_telemetry.c b/palacios/src/palacios/vmm_telemetry.c index 16088a2..fae3c76 100644 --- a/palacios/src/palacios/vmm_telemetry.c +++ b/palacios/src/palacios/vmm_telemetry.c @@ -211,6 +211,11 @@ void v3_print_telemetry(struct v3_vm_info * vm) { V3_Print("Exit information for Core %d\n", core->cpu_id); + if (!node) { + V3_Print("No information yet for this core\n"); + continue; + } + do { evt = rb_entry(node, struct exit_event, tree_node); const char * code_str = vmexit_code_to_str(evt->exit_code);