Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Partially functional icc_bus (works for UP)
[palacios.git] / palacios / src / devices / icc_bus.c
index fe76cff..e75734d 100644 (file)
 #include <palacios/vmm_dev_mgr.h>
 #include <palacios/vmm_sprintf.h>
 #include <palacios/vm_guest.h>
+#include <devices/icc_bus.h>
 #include <devices/apic_regs.h>
-#include <devices/apic.h>
 
-#define MAX_APIC 256
 
-struct icc_bus_internal {
-    struct vm_device * apic[MAX_APIC];
+#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 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 = {
@@ -36,108 +64,195 @@ 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;
+
+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)",
+};
+
+
+
+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 ipi_thunk_data {
-    struct vm_device *target;
-    uint64_t          val;
-} ;
+    return 0;
+} 
 
-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;
+
+int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data) {
+
+    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;
     }
-    switch (icr.msg_type)
-    {
-    case 0x0:
-        type = "";
-        break;
-    case 0x4:
-        type = "(NMI)";
-        break;
-    case 0x5:
-        type = "(INIT)";
-        break;
-    case 0x6:
-        type = "(Startup)";
-        break;
+    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);
+
+
+
+
+    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;i<MAX_APICS;i++) { 
+               dest_apic=&(state->apics[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;
+}
 
 
-    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);
+/* THIS IS A BIG ASSUMPTION: APIC PHYSID == LOGID == CORENUM */
 
-    V3_Call_On_CPU(apic_num,  icc_force_exit, (void *)(uint64_t)(val & 0xff));
+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;
 }
 
 
-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;
+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");
 
-    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);
 
     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;
     }
 
-    init_icc_bus_internal_state(icc_bus);
-
     return 0;
 }