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.


Update host device framework to support PCI and other interrupt types
Peter Dinda [Sun, 27 Jul 2014 20:33:40 +0000 (15:33 -0500)]
linux_module/iface-host-dev.c
linux_module/iface-host-dev.h
linux_usr/v3_user_host_dev.c
linux_usr/v3_user_host_dev.h
linux_usr/v3_user_host_dev_example.c
palacios/include/interfaces/vmm_host_dev.h
palacios/src/devices/generic.c
palacios/src/devices/pci_front.c
palacios/src/interfaces/vmm_host_dev.c

index 680d753..730a971 100644 (file)
@@ -149,6 +149,7 @@ struct palacios_host_device_user {
     char     url[MAX_URL]; // what is the url describing the device
 
     v3_guest_dev_t guestdev; // what is the palacios-side device
+    v3_guest_dev_intr_t guestintr; // what is the palacios-side device interrupt info
 
     wait_queue_head_t  user_wait_queue; // user space processes waiting on us (should be only one)
     wait_queue_head_t  host_wait_queue; // host threads (should only be one) waiting on user space
@@ -434,11 +435,18 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg
                }
                    break;
 
-               case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
+               case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_RAISE_GUEST: {
 
-                   DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n");
+                   DEEP_DEBUG_PRINT("palacios: hostdev: irq raise guest\n");
 
-                   return  v3_host_dev_raise_irq(dev, dev->guestdev, op.irq);
+                   return  v3_host_dev_raise_irq(dev, dev->guestdev, dev->guestintr, op.irq);
+               }
+                   break;
+               case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_LOWER_GUEST: {
+
+                   DEEP_DEBUG_PRINT("palacios: hostdev: irq lower guest\n");
+
+                   return  v3_host_dev_lower_irq(dev, dev->guestdev, dev->guestintr, op.irq);
                }
                    break;
 
@@ -728,6 +736,7 @@ static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
                                                     v3_bus_class_t bus,
                                                     v3_guest_dev_t gdev,
+                                                    v3_guest_dev_intr_t gintr,
                                                     void *host_priv_data)
 {
     struct v3_guest *guest= (struct v3_guest*)host_priv_data;
@@ -786,6 +795,8 @@ static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
     
     dev->guestdev = gdev;
     
+    dev->guestintr = gintr;
+    
     dev->guest = guest;
 
     palacios_spinlock_init(&(dev->lock));
index 7ef467b..4377ec9 100644 (file)
@@ -44,7 +44,8 @@
 struct palacios_host_dev_user_op {
 #define PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST  1
 #define PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST 2
-#define PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST   3
+#define PALACIOS_HOST_DEV_USER_REQUEST_IRQ_RAISE_GUEST   3
+#define PALACIOS_HOST_DEV_USER_REQUEST_IRQ_LOWER_GUEST   4
     uint32_t        type;   // type of operation (from the #defs above)
     void            *gpa;   // physical address in guest to read or write
     void USER      *data;   // user address of data that will be read or written
index 6996bfa..a0c1a99 100644 (file)
@@ -119,11 +119,24 @@ uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint6
     return do_user(devfd,&op);
 }
 
-int      v3_user_host_dev_inject_irq(int devfd, uint8_t irq)
+int      v3_user_host_dev_raise_irq(int devfd, uint8_t irq)
 {
     struct palacios_host_dev_user_op op;
 
-    op.type= PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST;
+    op.type= PALACIOS_HOST_DEV_USER_REQUEST_IRQ_RAISE_GUEST;
+    op.gpa=0;
+    op.data=0;
+    op.len=0;
+    op.irq=irq;
+    
+    return do_user(devfd,&op);
+}
+
+int      v3_user_host_dev_lower_irq(int devfd, uint8_t irq)
+{
+    struct palacios_host_dev_user_op op;
+
+    op.type= PALACIOS_HOST_DEV_USER_REQUEST_IRQ_LOWER_GUEST;
     op.gpa=0;
     op.data=0;
     op.len=0;
index 91bbc73..2981c55 100644 (file)
@@ -14,7 +14,11 @@ int v3_user_host_dev_push_response(int devfd, struct palacios_host_dev_host_requ
 
 uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len);
 uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len);
-int      v3_user_host_dev_inject_guest_irq(int devfd, uint8_t irq);
+
+// Note that "IRQ" here is context-dependent.  For a legacy device, it is the IRQ
+// For a PCI device, it is the PCI int #, etc.
+int      v3_user_host_dev_raise_guest_irq(int devfd, uint8_t irq);
+int      v3_user_host_dev_lower_guest_irq(int devfd, uint8_t irq);
 
 #endif
 
index 4f8144e..ea6cdc7 100644 (file)
@@ -25,7 +25,8 @@ int do_work(struct palacios_host_dev_host_request_response *req,
     //
     // uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len);
     // uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len);
-    // int      v3_user_host_dev_inject_guest_irq(int devfd, uint8_t irq);
+    // int      v3_user_host_dev_raise_irq(int devfd, uint8_t irq);
+    // int      v3_user_host_dev_lower_irq(int devfd, uint8_t irq);
     //
     // determine datasize - # bytes to include in response
     //
index 2b893b5..3474952 100644 (file)
   The purpose of this interface is to make it possible to implement
   virtual devices in the host OS.   It is intended to be used by 
   passthrough device implementations, such as the generic device 
-  and the PCI passthrough device.  
+  and the PCI front-end device.  
 
   One use of this interface, and the generic and PCI passthrough devices
-  might be to build an interface with simulated devices in SST 
+  might be to build an interface with simulated devices in QEMU, SST, etc
   under a Linux host.  That scenario would look like this:
 
 Guest config:
 
   generic device:
-    <device class="generic" id="mydev" impl="host_sst">
+    <device class="generic" id="mydev" forward="host_device" hostdev="url" >
        ports, memory regions, interrupts set with PASSTHROUGH option 
     </device>
 
-  PCI passthrough devive:
-    <device class="pci_passthrough" id="mydev", impl="host_sst">
+  PCI front devive:
+    <device class="pci_front" id="mydev", hostdev="url">
        vendor and device ids, etc
     </device>
 
-impl="physical" or lack of an impl key would indicate that direct hardware
-access is expected, which is how these devices currently operate. 
-
 
 Host (Linux) side:
 
@@ -70,7 +67,8 @@ Host (Linux) side:
 typedef void * v3_host_dev_t;
 /* A guest device is opaque to the host */
 typedef void * v3_guest_dev_t;
-
+/* Optional support for special interrupt handling ; raise=1 => raise otherwise lower */
+typedef void (*v3_guest_dev_intr_t)(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise);
 
 /* There is a notion of a bus class to which the device is attached */
 typedef enum { V3_BUS_CLASS_DIRECT, V3_BUS_CLASS_PCI } v3_bus_class_t;
@@ -82,6 +80,7 @@ struct v3_vm_info;
 v3_host_dev_t v3_host_dev_open(char *impl, 
                               v3_bus_class_t bus,
                               v3_guest_dev_t gdev,
+                              v3_guest_dev_intr_t intr,
                               struct v3_vm_info *vm); 
 
 int v3_host_dev_close(v3_host_dev_t hdev);
@@ -131,6 +130,7 @@ struct v3_host_dev_hooks {
     v3_host_dev_t (*open)(char *impl, 
                          v3_bus_class_t bus,
                          v3_guest_dev_t gdev,
+                         v3_guest_dev_intr_t intr,
                          void *host_priv_data);
 
     int (*close)(v3_host_dev_t hdev);
@@ -198,10 +198,14 @@ struct v3_host_dev_hooks {
 };
 
 /* This function is how the host will raise an irq to palacios
-   for the device.   The IRQ argument will be ignored for devices
-   whose irqs are managed by palacios */
+   for the device.   */
 int v3_host_dev_raise_irq(v3_host_dev_t hostdev,
                          v3_guest_dev_t guest_dev,
+                         v3_guest_dev_intr_t intr,
+                         uint8_t irq);
+int v3_host_dev_lower_irq(v3_host_dev_t hostdev,
+                         v3_guest_dev_t guest_dev,
+                         v3_guest_dev_intr_t intr,
                          uint8_t irq);
 
 /* These functions allow the host to read and write the guest
index 5e17d2f..ba2965f 100644 (file)
@@ -623,6 +623,19 @@ static int osdebug_hcall(struct guest_info *core, uint_t hcall_id, void * priv_d
 
 #endif
 
+#ifdef V3_CONFIG_HOST_DEVICE
+static void generic_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
+{
+    if (gdev) { 
+       struct vm_device *dev = (struct vm_device *) gdev;
+       if (raise) { 
+           v3_raise_irq(dev->vm,irq);
+       } else {
+           v3_lower_irq(dev->vm,irq);
+       }
+    }
+}
+#endif
 
 /*
    The device can be used to forward to the underlying physical device 
@@ -640,7 +653,7 @@ static int osdebug_hcall(struct guest_info *core, uint_t hcall_id, void * priv_d
 
 
    <device class="generic" id="my_id" 
-         empty | forward="physical_device" or forward="host_device" host_device="url">
+         empty | forward="physical_device" or forward="host_device" hostdev="url">
 
   (empty implies physical_dev)
 
@@ -717,7 +730,7 @@ static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
            v3_remove_device(dev);
            return -1;
        } else {
-           state->host_dev = v3_host_dev_open(host_dev,V3_BUS_CLASS_DIRECT,dev,vm);
+           state->host_dev = v3_host_dev_open(host_dev,V3_BUS_CLASS_DIRECT,dev,generic_intr_update_callback,vm);
            if (!(state->host_dev)) { 
                PrintError(vm, VCORE_NONE, "generic (%s): unable to open host device \"%s\"\n", state->name,host_dev);
                v3_remove_device(dev);
index d4d2de6..91c2e78 100644 (file)
@@ -269,6 +269,9 @@ static int pci_front_write_port(struct guest_info * core,
 // We assume that someone has called pull_config to get a local
 // copy of the config data from the host device by this point
 //
+// It might be smarter to do the pull config here since 
+// in init we may not yet have the host device running... 
+//
 static int pci_bar_init(int bar_num, uint32_t * dst, void * private_data) {
     struct vm_device * dev = (struct vm_device *)private_data;
     struct pci_front_internal * state = (struct pci_front_internal *)(dev->private_data);
@@ -733,6 +736,27 @@ static int pci_front_free(struct pci_front_internal *state)
     return 0;
 }
 
+#ifdef V3_CONFIG_HOST_DEVICE
+static void pci_front_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
+{
+    if (gdev) { 
+
+       struct vm_device *dev = (struct vm_device *) gdev;
+       struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
+
+       // We expect the host device will raise and lower irqs as needed, so we
+       // don't need an "acked" irq.  Also, we expect the host is using INTX, not
+       // MSI.  It's doubtful that MSI will work.  
+       // expect: state->pci_dev->irq_type==IRQ_INTX
+       if (raise) { 
+           v3_pci_raise_irq(state->pci_bus, state->pci_dev, irq);
+       } else {
+           v3_pci_lower_irq(state->pci_bus, state->pci_dev, irq);
+       }
+    }
+}
+#endif
+
 
 static struct v3_device_ops dev_ops = {
 //
@@ -792,7 +816,7 @@ static int pci_front_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg)
        return -1;
     }
     
-    if (!(state->host_dev=v3_host_dev_open(url,V3_BUS_CLASS_PCI,dev,vm))) { 
+    if (!(state->host_dev=v3_host_dev_open(url,V3_BUS_CLASS_PCI,dev,pci_front_intr_update_callback,vm))) { 
        PrintError(info->vm_info, info, "pci_front (%s): unable to attach to host device %s\n",state->name, url);
        v3_remove_device(dev);
        return -1;
index ebae331..5992f9e 100644 (file)
@@ -30,12 +30,13 @@ struct v3_host_dev_hooks * host_dev_hooks = 0;
 v3_host_dev_t v3_host_dev_open(char *impl,
                               v3_bus_class_t bus,
                               v3_guest_dev_t gdev,
+                              v3_guest_dev_intr_t intr,
                               struct v3_vm_info *vm)
 {                                             
     V3_ASSERT(VM_NONE, VCORE_NONE, host_dev_hooks != NULL);
     V3_ASSERT(VM_NONE, VCORE_NONE, host_dev_hooks->open != NULL);
 
-    return host_dev_hooks->open(impl,bus,gdev,vm->host_priv_data);
+    return host_dev_hooks->open(impl,bus,gdev,intr,vm->host_priv_data);
 }
 
 int v3_host_dev_close(v3_host_dev_t hdev) 
@@ -125,14 +126,37 @@ int v3_host_dev_ack_irq(v3_host_dev_t hdev, uint8_t irq)
 
 int v3_host_dev_raise_irq(v3_host_dev_t hostdev,
                          v3_guest_dev_t guest_dev,
+                         v3_guest_dev_intr_t intr,
                          uint8_t irq)
 {
-    // Make this smarter later...
+    if (intr) { 
+       intr(hostdev,guest_dev,irq,1);
+       return 0;
+    } else {
+       struct vm_device *dev = (struct vm_device *) guest_dev;
+       
+       if (dev && dev->vm) { 
+           return v3_raise_irq(dev->vm,irq);
+       } else {
+           return -1;
+       }
+    }
+}
 
+int v3_host_dev_lower_irq(v3_host_dev_t hostdev,
+                         v3_guest_dev_t guest_dev,
+                         v3_guest_dev_intr_t intr,
+                         uint8_t irq)
+{
     struct vm_device *dev = (struct vm_device *) guest_dev;
     
     if (dev && dev->vm) { 
-       return v3_raise_irq(dev->vm,irq);
+       if (intr) { 
+           intr(hostdev,guest_dev,irq,0);
+           return 0;
+       } else {
+           return v3_lower_irq(dev->vm,irq);
+       }
     } else {
        return -1;
     }