X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Ficc_bus.c;h=cfe3c056e0eca463fbd2000f9bc4102694dbc3bb;hb=5bb5bb2b3113a92410bc3b2d30bc48d0f4e0bb55;hp=6c5e9e75554498904e30da17704084168c9070a4;hpb=65e038cb9940879f002209382eeafae6f58934b6;p=palacios.git diff --git a/palacios/src/devices/icc_bus.c b/palacios/src/devices/icc_bus.c index 6c5e9e7..cfe3c05 100644 --- a/palacios/src/devices/icc_bus.c +++ b/palacios/src/devices/icc_bus.c @@ -23,7 +23,6 @@ #include #include - #define MAX_APICS 256 #ifndef CONFIG_DEBUG_ICC_BUS @@ -135,14 +134,14 @@ static int deliver(uint32_t src_apic, struct apic_data *dest_apic, struct int_cm // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...) // Sanity check - if (core->cpu_mode!=INIT) { + if (core->cpu_mode != INIT) { PrintError("icc_bus: Warning: core %u is not in INIT state, ignored\n",core->cpu_id); // Only a warning, since INIT INIT SIPI is common break; } // We transition the target core to SIPI state - core->cpu_mode=SIPI; // note: locking should not be needed here + core->cpu_mode = SIPI; // note: locking should not be needed here // That should be it since the target core should be // waiting in host on this transition @@ -202,65 +201,181 @@ static int deliver(uint32_t src_apic, struct apic_data *dest_apic, struct int_cm // 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) { + +int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data, + uint32_t dfr_data, uint32_t extirq) { PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx, extirq=%u\n",icc_bus,src_apic,icr_data,extirq); struct int_cmd_reg *icr = (struct int_cmd_reg *)&icr_data; + struct dst_fmt_reg *dfr = (struct dst_fmt_reg*)&dfr_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 && src_apic!=state->ioapic_id)) { + 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) { - PrintError("icc_bus: Attempted send to unregistered apic id=%u\n",icr->dst); + + + 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; } - - struct apic_data * dest_apic = &(state->apics[icr->dst]); - PrintDebug("icc_bus: IPI %s %u from %s %u to %s %u (icr=0x%llx) (extirq=%u)\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, + dest_apic = &(state->apics[icr->dst]); + + + PrintDebug("icc_bus: IPI %s %u from %s %u to %s %s %u (icr=0x%llx, dfr=0x%x) (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, dfr->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 (deliver(src_apic,dest_apic,icr,state,extirq)) { - return -1; + + 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 + uint8_t mda = icr->dst; // message destination address, not physical address + + if (dfr->model==0xf) { + // flat model + // this means we deliver the IPI each destination APIC where + // mda of sender & ldr of receiver is nonzero + // mda=0xff means broadcast to all + // + int i; + for (i=0;iapics[i]); + if (dest_apic->present && + dest_apic->ops->should_deliver_flat(dest_apic->core, + mda, + dest_apic->priv_data)) { + if (deliver(src_apic,dest_apic,icr,state,extirq)) { + return -1; + } + } + } + } else if (dfr->model==0x0) { + // cluster model + // + // there are two variants of this + // + // 1. (ancient P5/P6) All apics are on one bus + // mda[31:28] is the target cluster, + // mda[27:24] has one bit for each apic in the cluster + // mda[31:28] of sending apic == ldr[31:28] of dest apic means + // the dest apic is part of the cluster + // then mda[27:24] & ldr[27:24] nonzero means to deliver + // also, mda=0xff still means broadcast + // So, basically, you have 15 clusters of 4 apics each + broadcast + // + // 2. (current) hierarchical cluster model + // This is some hwat unclearly documented in volume 3, 9-32 + // basically, you have a hierarchy of clusters that where + // each cluster has 4 agents (APICs?) and a cluster manager. + // The cluster manager is not an apic, though, and outside of + // scope of documents. Again, you have 15 clusters of 4 apics + // each + broadcast. My impression is that this is identical + // to variant 1 for our purposes. + // + // + // if we are in lowest priorty mode, we should just pick one + // according to the arbitrarion prioty register + int i; + for (i=0;iapics[i]); + if (dest_apic->present && + dest_apic->ops->should_deliver_cluster(dest_apic->core, + mda, + dest_apic->priv_data)) { + if (deliver(src_apic,dest_apic,icr,state,extirq)) { + return -1; + } + } + } + } else { + PrintError("icc_bus: unknown logical delivery model 0x%x\n", dfr->model); + 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,extirq)) { + + 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 - 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; + if (icr->dst_mode==0) { + // physical + 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; + } + } } + } else { + // logical delivery + PrintError("icc_bus: use of logical delivery in %s is not yet supported\n", + icr->dst_shorthand==2 ? "all" : "all-but-me" ); + return -1; } - } break; + } + default: + return -1; } + return 0; } @@ -308,7 +423,6 @@ int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, ui } - static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { PrintDebug("icc_bus: Creating ICC_BUS\n");