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.


Fixed merge conflict in vmm_halt.c
Patrick G. Bridges [Wed, 25 Apr 2012 14:57:29 +0000 (08:57 -0600)]
37 files changed:
linux_module/iface-file.c
linux_module/palacios-stubs.c
linux_module/vm.c
linux_usr/v3_cons_sc.c
palacios/include/devices/apic.h
palacios/include/devices/pci.h
palacios/include/devices/pci_types.h
palacios/include/interfaces/vmm_file.h
palacios/include/palacios/vmm_intr.h
palacios/src/devices/8259a.c
palacios/src/devices/apic.c
palacios/src/devices/cirrus_gfx_card.c
palacios/src/devices/filedisk.c
palacios/src/devices/i440fx.c
palacios/src/devices/ide.c
palacios/src/devices/io_apic.c
palacios/src/devices/keyboard.c
palacios/src/devices/lnx_virtio_balloon.c
palacios/src/devices/lnx_virtio_blk.c
palacios/src/devices/lnx_virtio_console.c
palacios/src/devices/lnx_virtio_nic.c
palacios/src/devices/lnx_virtio_sym.c
palacios/src/devices/lnx_virtio_symmod.c
palacios/src/devices/lnx_virtio_vnet.c
palacios/src/devices/ne2k.c
palacios/src/devices/pci.c
palacios/src/devices/pci_front.c
palacios/src/devices/pci_passthrough.c
palacios/src/devices/piix3.c
palacios/src/devices/rtl8139.c
palacios/src/interfaces/vmm_file.c
palacios/src/palacios/svm.c
palacios/src/palacios/svm_handler.c
palacios/src/palacios/vmm_dev_mgr.c
palacios/src/palacios/vmm_halt.c
palacios/src/palacios/vmm_intr.c
palacios/src/palacios/vmm_shadow_paging.c

index be31f16..091c773 100644 (file)
@@ -243,7 +243,7 @@ static int palacios_file_close(void * file_ptr) {
     return 0;
 }
 
-static long long palacios_file_size(void * file_ptr) {
+static unsigned long long palacios_file_size(void * file_ptr) {
     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
     struct file * filp = pfile->filp;
     struct kstat s;
@@ -259,7 +259,7 @@ static long long palacios_file_size(void * file_ptr) {
     return s.size;
 }
 
-static long long palacios_file_read(void * file_ptr, void * buffer, long long length, long long offset){
+static unsigned long long palacios_file_read(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset){
     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
     struct file * filp = pfile->filp;
     ssize_t ret;
@@ -273,14 +273,14 @@ static long long palacios_file_read(void * file_ptr, void * buffer, long long le
     set_fs(old_fs);
        
     if (ret <= 0) {
-       printk("sys_read of %p for %lld bytes failed\n", filp, length);         
+       printk("sys_read of %p for %lld bytes at offset %llu failed (ret=%ld)\n", filp, length, offset, ret);
     }
        
     return ret;
 }
 
 
-static long long palacios_file_write(void * file_ptr, void * buffer, long long length, long long offset) {
+static unsigned long long palacios_file_write(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset) {
     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
     struct file * filp = pfile->filp;
     mm_segment_t old_fs;
@@ -295,7 +295,7 @@ static long long palacios_file_write(void * file_ptr, void * buffer, long long l
 
  
     if (ret <= 0) {
-       printk("sys_write failed\n");           
+       printk("sys_write for %llu bytes at offset %llu failed (ret=%ld)\n", length, offset, ret);              
     }
        
     return ret;
index c5b0ca0..12b4e45 100644 (file)
@@ -158,6 +158,7 @@ palacios_xcall(
 struct lnx_thread_arg {
     int (*fn)(void * arg);
     void * arg;
+    char * name;
 };
 
 static int lnx_thread_target(void * arg) {
@@ -176,6 +177,9 @@ static int lnx_thread_target(void * arg) {
     kfree(thread_info);
     // handle cleanup 
 
+    
+    printk("Palacios Thread (%s) EXITTING\n", thread_info->name);
+
     do_exit(ret);
     
     return 0; // should not get here.
@@ -194,6 +198,7 @@ palacios_start_kernel_thread(
 
     thread_info->fn = fn;
     thread_info->arg = arg;
+    thread_info->name = thread_name;
 
     return kthread_run( lnx_thread_target, thread_info, thread_name );
 }
@@ -212,6 +217,7 @@ palacios_start_thread_on_cpu(int cpu_id,
 
     thread_info->fn = fn;
     thread_info->arg = arg;
+    thread_info->name = thread_name;
 
 
     thread = kthread_create( lnx_thread_target, thread_info, thread_name );
index da9b460..e2b621a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/file.h>
 #include <linux/spinlock.h>
 #include <linux/rbtree.h>
+#include <linux/module.h>
 
 #include <palacios/vmm.h>
 
index 3b9e192..6404905 100644 (file)
@@ -600,6 +600,16 @@ int main(int argc, char* argv[]) {
                writeit(cons_fd,sc);
                sc |= 0x80;
                writeit(cons_fd,sc);
+            } else if (key == '~') {  // CTRL-C 
+                unsigned char sc;
+                sc = 0x1d;  // left ctrl down
+                writeit(cons_fd,sc);
+                sc = 0x2e; // c down
+               writeit(cons_fd,sc);
+               sc = 0x2e | 0x80;   // c up
+                writeit(cons_fd,sc);
+                sc = 0x1d | 0x80;   // left ctrl up
+                writeit(cons_fd,sc);
             }else {
                if (send_char_to_palacios_as_scancodes(cons_fd,key)) {
                    fprintf(stderr, "Error sendign key to console\n");
index 4ddfc7c..0be5283 100644 (file)
 
 #include <palacios/vmm_dev_mgr.h>
 
-
 typedef enum {IPI_FIXED = 0,
              IPI_LOWEST_PRIO = 1,
              IPI_SMI = 2,
+             IPI_RES1 = 3,
              IPI_NMI = 4,
              IPI_INIT = 5,
-             IPI_EXINT = 7 } ipi_mode_t; 
+             IPI_SIPI = 6,
+             IPI_EXTINT = 7 } ipi_mode_t; 
 
 
 struct v3_gen_ipi {
@@ -42,13 +43,14 @@ struct v3_gen_ipi {
     uint8_t dst_shorthand : 2;
 
     uint8_t dst;
+
+
+    int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
+    void * private_data;
 } __attribute__((packed));
 
 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data);
 
-int v3_apic_raise_intr(struct v3_vm_info * vm, 
-                      uint32_t irq, uint32_t dst,
-                      void * dev_data);
 
 
 
index ff2e27d..bbb61c5 100644 (file)
 
 #include <palacios/vmm_types.h>
 #include <palacios/vmm_rbtree.h>
+#include <palacios/vmm_intr.h>
 
 #include <devices/pci_types.h>
 
-
 struct vm_device;
 
 
+typedef enum { PCI_CMD_DMA_DISABLE  = 1,
+              PCI_CMD_DMA_ENABLE   = 2,
+              PCI_CMD_INTX_DISABLE = 3, 
+              PCI_CMD_INTX_ENABLE  = 4,
+              PCI_CMD_MSI_DISABLE  = 5,
+              PCI_CMD_MSI_ENABLE   = 6,
+              PCI_CMD_MSIX_DISABLE = 7,
+              PCI_CMD_MSIX_ENABLE  = 8 } pci_cmd_t;
+
 typedef enum { PCI_BAR_IO, 
               PCI_BAR_MEM24, 
               PCI_BAR_MEM32, 
@@ -104,6 +113,13 @@ struct v3_pci_bar {
 #define PCI_MEM64_BASE_LO(bar_val) (bar_val & PCI_MEM64_MASK_LO)
 #define PCI_EXP_ROM_BASE(rom_val) (rom_val & PCI_EXP_ROM_MASK)
 
+#define PCI_IO_BAR_VAL(addr) ((addr & PCI_IO_MASK) | 0x1)
+#define PCI_MEM24_BAR_VAL(addr, prefetch) (((addr & PCI_MEM24_MASK) | 0x2) | ((prefetch) != 0) << 3)
+#define PCI_MEM32_BAR_VAL(addr, prefetch) (((addr & PCI_MEM_MASK) | ((prefetch) != 0) << 3))
+#define PCI_MEM64_HI_BAR_VAL(addr, prefetch) (addr & PCI_MEM64_MASK_HI)
+#define PCI_MEM64_LO_BAR_VAL(addr, prefetch) ((((addr) & PCI_MEM64_MASK_LO) | 0x4) | ((prefetch) != 0) << 3)
+#define PCI_EXP_ROM_VAL(addr, enable) (((addr) & PCI_EXP_ROM_MASK) | ((enable) != 0))
+
 
 struct pci_device {
 
@@ -134,30 +150,45 @@ struct pci_device {
 
     char name[64];
 
-    int (*config_update)(uint_t reg_num, void * src, uint_t length, void * priv_data);
-
-    int (*cmd_update)(struct pci_device * pci_dev, uchar_t io_enabled, uchar_t mem_enabled);
+    int (*config_write)(struct pci_device * pci_dev, uint32_t reg_num, void * src, 
+                       uint_t length, void * priv_data);
+    int (*config_read)(struct pci_device * pci_dev, uint32_t reg_num, void * dst, 
+                      uint_t length, void * priv_data);
+    int (*cmd_update)(struct pci_device * pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data);
     int (*exp_rom_update)(struct pci_device * pci_dev, uint32_t * src, void * private_data);
 
-    int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data);
-    int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data);
+    struct v3_vm_info * vm;
 
+    struct list_head cfg_hooks;
+    struct list_head capabilities; 
 
-    int exp_rom_update_flag;
-    int bar_update_flag;
+    struct msi_msg_ctrl * msi_cap;
+    struct msix_cap * msix_cap;
+    struct vm_device * apic_dev;
+
+    enum {IRQ_NONE, IRQ_INTX, IRQ_MSI, IRQ_MSIX} irq_type;
 
     void * priv_data;
 };
 
 
 int v3_pci_set_irq_bridge(struct vm_device * pci_bus, int bus_num,
-                         int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data), 
-                         int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data), 
+                         int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec), 
+                         int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec), 
                          void * dev_data);
 
 
-int v3_pci_raise_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev);
-int v3_pci_lower_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev);
+/* Raising a PCI IRQ requires the specification of a vector index. 
+ *  If you are not sure, set vec_index to 0. 
+ * For IntX IRQs, the index is the interrupt line the device is using (INTA=0, INTB=1, ...) - only used in multi-function devices
+ * For MSI and MSIX, the index is the vector index if multi-vectors are enabled  
+ */
+
+int v3_pci_raise_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index);
+int v3_pci_lower_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index);
+
+int v3_pci_raise_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec);
+int v3_pci_lower_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec);
 
 struct pci_device * 
 v3_pci_register_device(struct vm_device * pci,
@@ -167,21 +198,34 @@ v3_pci_register_device(struct vm_device * pci,
                       int fn_num,
                       const char * name,
                       struct v3_pci_bar * bars,
-                      int (*config_update)(uint_t reg_num, void * src, uint_t length, void * private_data),
-                      int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled),
+                      int (*config_write)(struct pci_device * pci_dev, uint32_t reg_num, void * src, 
+                                          uint_t length, void * private_data),
+                      int (*config_read)(struct pci_device * pci_dev, uint32_t reg_num, void * dst, 
+                                         uint_t length, void * private_data),
+                      int (*cmd_update)(struct pci_device *pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data),
                       int (*exp_rom_update)(struct pci_device * pci_dev, uint32_t * src, void * private_data),
                       void * priv_data);
 
 
-struct pci_device * 
-v3_pci_register_passthrough_device(struct vm_device * pci,
-                                  int bus_num,
-                                  int dev_num,
-                                  int fn_num,
-                                  const char * name,
-                                  int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data),
-                                  int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data),
-                                  void * private_data);
+
+int v3_pci_hook_config_range(struct pci_device * pci, 
+                            uint32_t start, uint32_t length, 
+                            int (*write)(struct pci_device * pci_dev, uint32_t offset, 
+                                                void * src, uint_t length, void * private_data), 
+                            int (*read)(struct pci_device * pci_dev, uint32_t offset, 
+                                                void * src, uint_t length, void * private_data), 
+                            void * private_data);
+
+
+
+
+typedef enum { PCI_CAP_INVALID = 0, 
+              PCI_CAP_PM = 0x1,
+              PCI_CAP_MSI = 0x5,
+              PCI_CAP_MSIX = 0x11,
+               PCI_CAP_PCIE = 0x10 } pci_cap_type_t;
+
+int v3_pci_enable_capability(struct pci_device * pci, pci_cap_type_t cap_type);
 
 
 #endif
index c3cd4cb..f6a98ce 100644 (file)
@@ -63,6 +63,28 @@ struct pci_config_header {
 } __attribute__((packed));
 
 
+struct pci_cmd_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t io_enable         : 1;
+           uint16_t mem_enable        : 1;
+           uint16_t dma_enable        : 1;
+           uint16_t special_cycles    : 1;
+           uint16_t mem_wr_inv_enable : 1;
+           uint16_t vga_snoop         : 1;
+           uint16_t parity_err_resp   : 1;
+           uint16_t rsvd1             : 1;
+           uint16_t serr_enable       : 1;
+           uint16_t fast_b2b_enable   : 1;
+           uint16_t intx_disable      : 1;
+           uint16_t rsvd2             : 5;
+       } __attribute__((packed));
+    } __attribute__((packed));
+
+} __attribute__((packed));
+
+
 typedef enum { PCI_CLASS_PRE2 = 0x00, 
               PCI_CLASS_STORAGE = 0x01, 
               PCI_CLASS_NETWORK = 0x02,
@@ -165,5 +187,357 @@ typedef enum { PCI_BRIDGE_SUBCLASS_HOST_PCI = 0x00,
   };
 */
 
+
+
+struct msi_addr {
+    union {
+       uint32_t val;
+       struct {
+           uint32_t rsvd1        : 2;
+           uint32_t dst_mode     : 1;
+           uint32_t redir_hint   : 1;
+           uint32_t rsvd2        : 8;
+           uint32_t dst_id       : 8;
+           uint32_t fixaddr      : 12;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct msi_data {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t vector       : 8;
+           uint16_t del_mode     : 3;
+           uint16_t rsvd1        : 3;
+           uint16_t level        : 1;
+           uint16_t trig_mode    : 1;
+       } __attribute__((packed));;
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct msi_msg_ctrl {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t msi_enable       : 1;
+           uint16_t mult_msg_capable : 3;
+           uint16_t mult_msg_enable  : 3;
+           uint16_t cap_64bit        : 1;
+           uint16_t per_vect_mask    : 1;
+           uint16_t rsvd             : 7;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct msi32_msg_addr {
+    struct msi_msg_ctrl msg_ctrl;
+    struct msi_addr addr;
+    struct msi_data data;
+} __attribute__((packed));
+
+
+struct msi64_msg_addr {
+    struct msi_msg_ctrl msg_ctrl;
+    struct msi_addr addr;
+    uint32_t hi_addr;
+    struct msi_data data;
+} __attribute__((packed));
+
+
+struct msi64_pervec_msg_addr {
+    struct msi_msg_ctrl msg_ctrl;
+    struct msi_addr addr;
+    uint32_t hi_addr;
+    struct msi_data data;
+    uint16_t rsvd;
+    uint32_t mask;
+    uint32_t pending;
+} __attribute__((packed));
+
+
+struct msix_msg_ctrl {
+    uint16_t table_size   : 11;
+    uint16_t rsvd         : 4;
+    uint16_t msix_enable  : 1;
+} __attribute__((packed));
+
+struct msix_cap {
+    struct msix_msg_ctrl msg_ctrl;
+    uint32_t hi_addr;
+    uint32_t bir      : 3;
+    uint32_t table_offset : 29;
+} __attribute__((packed));
+
+
+struct msix_table {
+    struct {
+       struct msi_data data;
+       struct msi_addr addr;
+    } __attribute__((packed)) entries[0];
+} __attribute__((packed));
+
+
+
+// See PCI power management specification (1.2)
+struct pmc_cap {
+    struct {
+       uint16_t version        : 3;
+       uint16_t pme_clock      : 1;
+       uint16_t rsvd1          : 1;
+       uint16_t dsi            : 1;
+       uint16_t aux_current    : 3;
+       uint16_t d1_support     : 1;
+       uint16_t d2_support     : 1;
+       uint16_t pme_support    : 5;
+    } __attribute__((packed)) pmc;
+
+    struct {
+       uint16_t power_state    : 2;
+       uint16_t rsvd1          : 1;
+       uint16_t no_soft_reset  : 1;
+       uint16_t rsvd2          : 4;
+       uint16_t pme_en         : 1;
+       uint16_t data_select    : 4;
+       uint16_t data_scale     : 2;
+       uint16_t pme_status     : 1;
+    } __attribute__((packed)) pmcsr;
+
+    struct {
+       uint8_t rsvd1           : 6;
+       uint8_t b2_b3           : 1;
+       uint8_t bpcc_en         : 1;
+    } __attribute__((packed)) pmcsr_bse;
+
+    uint8_t data;
+} __attribute__((packed));
+
+
+struct pcie_cap_reg {
+    uint16_t version     : 4;
+    uint16_t type        : 4;
+    uint16_t slot_impl   : 1;
+    uint16_t irq_msg_num : 5;
+    uint16_t rsvd        : 2;
+} __attribute__((packed));
+
+struct pcie_cap_v1 {
+    struct pcie_cap_reg pcie_cap;
+
+    union {
+       uint32_t val;
+       struct {
+           uint32_t max_payload          : 3;
+           uint32_t phantom_fns          : 2;
+           uint32_t ext_tag_support      : 1;
+           uint32_t endpt_L0_latency     : 3;
+           uint32_t endpt_L1_latency     : 3;
+           uint32_t maybe_rsvd1          : 3;
+           uint32_t role_err_reporting   : 1;
+           uint32_t rsvd2                : 2;
+           uint32_t slot_pwr_lim_val     : 8;
+           uint32_t slot_pwr_lim_scale   : 2;
+           uint32_t rsvd3                : 4;
+       } __attribute__((packed));
+    } __attribute__((packed)) dev_cap;
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t correctable_err_enable  : 1;
+           uint16_t non_fatal_err_enable    : 1;
+           uint16_t fatal_err_enable        : 1;
+           uint16_t unsupp_req_enable       : 1;
+           uint16_t relaxed_order_enable    : 1;
+           uint16_t max_payload_size        : 3;
+           uint16_t ext_tag_field_enable    : 1;
+           uint16_t phantom_fn_enable       : 1;
+           uint16_t aux_pwr_enable          : 1;
+           uint16_t no_snoop_enable         : 1;
+           uint16_t max_read_req_size       : 3;
+           uint16_t bridge_cfg_retry_enable : 1;
+       } __attribute__((packed));
+    } __attribute__((packed)) dev_ctrl;
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t correctable_err         : 1;
+           uint16_t non_fatal_err           : 1;
+           uint16_t fatal_err               : 1;
+           uint16_t unsupp_req              : 1;
+           uint16_t aux_pwr                 : 1;
+           uint16_t transaction_pending     : 1;
+           uint16_t rsvd                    : 10;
+       } __attribute__((packed));
+    } __attribute__((packed)) dev_status;
+
+    union {
+       uint32_t val;
+       struct {
+           uint32_t max_link_speed            : 4;
+           uint32_t max_link_width            : 6;
+           uint32_t aspm_support              : 2; /* Active State Power Management Support */
+           uint32_t L0_exit_latency           : 3;
+           uint32_t L1_exit_latency           : 3;
+           uint32_t clk_pwr_mngmt             : 1;
+           uint32_t surprise_pwr_down_capable : 1;
+           uint32_t data_link_active_capable  : 1;
+           uint32_t rsvd1                     : 3;
+           uint32_t port_number               : 8;
+       } __attribute__((packed));
+    } __attribute__((packed)) link_cap;
+
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t aspm_ctrl                 : 2;
+           uint16_t rsvd1                     : 1;
+           uint16_t rd_cmpl_bndry             : 1;
+           uint16_t link_disable              : 1;
+           uint16_t retrain_link              : 1;
+           uint16_t common_clk_cfg            : 1;
+           uint16_t ext_synch                 : 1;
+           uint16_t clk_pwr_mngmt_enable      : 1;
+           uint16_t rsvd2                     : 7;
+       } __attribute__((packed));
+    } __attribute__((packed)) link_ctrl;
+
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t link_speed               : 4;
+           uint16_t negotiate_link_width     : 6;
+           uint16_t undef                    : 1;
+           uint16_t link_training            : 1;
+           uint16_t slot_clk_cfg             : 1;
+           uint16_t data_link_layer_active   : 1;
+           uint16_t rsvd                     : 2;
+       } __attribute__((packed));
+    } __attribute__((packed)) link_status;
+
+} __attribute__((packed));
+
+
+
+
+struct pcie_cap_v2 {
+   struct pcie_cap_reg pcie_cap;
+
+    union {
+       uint32_t val;
+       struct {
+           uint32_t max_payload          : 3;
+           uint32_t phantom_fns          : 2;
+           uint32_t ext_tag_support      : 1;
+           uint32_t endpt_L0_latency     : 3;
+           uint32_t endpt_L1_latency     : 3;
+           uint32_t maybe_rsvd1          : 3;
+           uint32_t role_err_reporting   : 1;
+           uint32_t rsvd2                : 2;
+           uint32_t slot_pwr_lim_val     : 8;
+           uint32_t slot_pwr_lim_scale   : 2;
+           uint32_t fn_level_reset       : 1;
+           uint32_t rsvd3                : 3;
+       } __attribute__((packed));
+    } __attribute__((packed)) dev_cap;
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t correctable_err_enable  : 1;
+           uint16_t non_fatal_err_enable    : 1;
+           uint16_t fatal_err_enable        : 1;
+           uint16_t unsupp_req_enable       : 1;
+           uint16_t relaxed_order_enable    : 1;
+           uint16_t max_payload_size        : 3;
+           uint16_t ext_tag_field_enable    : 1;
+           uint16_t phantom_fn_enable       : 1;
+           uint16_t aux_pwr_enable          : 1;
+           uint16_t no_snoop_enable         : 1;
+           uint16_t max_read_req_size       : 3;
+           uint16_t bridge_cfg_retry_enable : 1;
+       } __attribute__((packed));
+    } __attribute__((packed)) dev_ctrl;
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t correctable_err         : 1;
+           uint16_t non_fatal_err           : 1;
+           uint16_t fatal_err               : 1;
+           uint16_t unsupp_req              : 1;
+           uint16_t aux_pwr                 : 1;
+           uint16_t transaction_pending     : 1;
+           uint16_t rsvd                    : 10;
+       } __attribute__((packed));
+    } __attribute__((packed)) dev_status;
+
+    union {
+       uint32_t val;
+       struct {
+           uint32_t max_link_speed            : 4;
+           uint32_t max_link_width            : 6;
+           uint32_t aspm_support              : 2; /* Active State Power Management Support */
+           uint32_t L0_exit_latency           : 3;
+           uint32_t L1_exit_latency           : 3;
+           uint32_t clk_pwr_mngmt             : 1;
+           uint32_t surprise_pwr_down_capable : 1;
+           uint32_t data_link_active_capable  : 1;
+           uint32_t rsvd1                     : 3;
+           uint32_t port_number               : 8;
+       } __attribute__((packed));
+    } __attribute__((packed)) link_cap;
+
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t aspm_ctrl                 : 2;
+           uint16_t rsvd1                     : 1;
+           uint16_t rd_cmpl_bndry             : 1;
+           uint16_t link_disable              : 1;
+           uint16_t retrain_link              : 1;
+           uint16_t common_clk_cfg            : 1;
+           uint16_t ext_synch                 : 1;
+           uint16_t clk_pwr_mngmt_enable      : 1;
+           uint16_t rsvd2                     : 7;
+       } __attribute__((packed));
+    } __attribute__((packed)) link_ctrl;
+
+
+    union {
+       uint16_t val;
+       struct {
+           uint16_t link_speed               : 4;
+           uint16_t negotiate_link_width     : 6;
+           uint16_t undef                    : 1;
+           uint16_t link_training            : 1;
+           uint16_t slot_clk_cfg             : 1;
+           uint16_t data_link_layer_active   : 1;
+           uint16_t rsvd                     : 2;
+       } __attribute__((packed));
+    } __attribute__((packed)) link_status;
+
+
+    /* Some crap whose format we don't know because the PCI-SIG sucks */
+    
+    uint32_t slot_cap;
+    uint16_t slot_ctrl;
+    uint16_t slot_status;
+
+    uint16_t root_ctrl;
+    uint16_t root_cap;
+    uint32_t root_status;
+
+} __attribute__((packed));
+
+
+
 #endif
 
index 69b78d8..421c73e 100644 (file)
@@ -49,11 +49,11 @@ struct v3_file_hooks {
     void * (*open)(const char * path, int mode, void * host_data);
     int (*close)(void * fd);
 
-    long long (*size)(void * fd);
+    unsigned long long (*size)(void * fd);
 
     // blocking reads and writes
-    long long (*read)(void * fd, void * buffer, long long length, long long offset);
-    long long (*write)(void * fd, void * buffer, long long length, long long offset);
+    unsigned long long (*read)(void * fd, void * buffer, unsigned long long length, unsigned long long offset);
+    unsigned long long (*write)(void * fd, void * buffer, unsigned long long length, unsigned long long offset);
 
 };
 
index adf2aa4..de98185 100644 (file)
@@ -35,6 +35,14 @@ struct v3_vm_info;
 struct v3_interrupt;
 
 
+struct v3_irq {
+    uint32_t irq;
+
+    int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
+    void * private_data;
+};
+
+
 
 struct v3_irq_hook {
     int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data);
@@ -82,6 +90,12 @@ int v3_lower_virq(struct guest_info * info, int irq);
 int v3_raise_irq(struct v3_vm_info * vm, int irq);
 int v3_lower_irq(struct v3_vm_info * vm, int irq);
 
+/* The irq structure is passed by value to avoid confusion and 
+ * the possibility that people will dynamically allocate memory for it 
+ */
+int v3_raise_acked_irq(struct v3_vm_info * vm, struct v3_irq irq);
+int v3_lower_acked_irq(struct v3_vm_info * vm, struct v3_irq irq);
+
 
 int v3_raise_swintr(struct guest_info * core, uint8_t vector);
 
@@ -93,8 +107,8 @@ struct intr_ctrl_ops {
 };
 
 struct intr_router_ops {
-    int (*raise_intr)(struct v3_vm_info * vm, void * private_data, int irq);
-    int (*lower_intr)(struct v3_vm_info * vm, void * private_data, int irq);
+    int (*raise_intr)(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq);
+    int (*lower_intr)(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq);
 };
 
 void v3_clear_pending_intr(struct guest_info * core);
index b383151..7e4b7a4 100644 (file)
@@ -159,6 +159,11 @@ struct pic_internal {
 
     struct guest_info * core;
 
+    struct {
+       int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
+       void * private_data;
+    } irq_ack_cbs[15];
+
 
     void * router_handle;
     void * controller_handle;
@@ -197,46 +202,53 @@ static void DumpPICState(struct pic_internal *p)
 }
 
 
-static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, int irq) {
+static int pic_raise_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
     struct pic_internal * state = (struct pic_internal*)private_data;
+    uint8_t irq_num = irq->irq;
 
-    if (irq == 2) {
-       irq = 9;
-       state->master_irr |= 0x04;  // PAD
+    if (irq_num == 2) {
+       irq_num = 9;
+       state->master_irr |= 0x04;
     }
 
-    PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq);
+    PrintDebug("8259 PIC: Raising irq %d in the PIC\n", irq_num);
 
-    if (irq <= 7) {
-       state->master_irr |= 0x01 << irq;
-    } else if ((irq > 7) && (irq < 16)) {
-       state->slave_irr |= 0x01 << (irq - 8);  // PAD if -7 then irq 15=no irq
+    if (irq_num <= 7) {
+       state->master_irr |= 0x01 << irq_num;
+    } else if ((irq_num > 7) && (irq_num < 16)) {
+       state->slave_irr |= 0x01 << (irq_num - 8);
     } else {
-       PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq);
+       PrintDebug("8259 PIC: Invalid IRQ raised (%d)\n", irq_num);
        return -1;
     }
 
-#ifdef V3_CONFIG_MULTITHREAD_OS
-    v3_interrupt_cpu(vm, 0, 0);
-#endif
+    state->irq_ack_cbs[irq_num].ack = irq->ack;
+    state->irq_ack_cbs[irq_num].private_data = irq->private_data;
+
+    if (V3_Get_CPU() != vm->cores[0].pcpu_id) {
+       // guest is running on another core, interrupt it to deliver irq
+       v3_interrupt_cpu(vm, 0, 0);
+    }
 
     return 0;
 }
 
 
-static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, int irq) {
+static int pic_lower_intr(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
     struct pic_internal * state = (struct pic_internal*)private_data;
+    uint8_t irq_num = irq->irq;
 
-    PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq);
-    if (irq <= 7) {
 
-       state->master_irr &= ~(1 << irq);
+    PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq_num);
+    if (irq_num <= 7) {
+
+       state->master_irr &= ~(1 << irq_num);
        if ((state->master_irr & ~(state->master_imr)) == 0) {
            PrintDebug("\t\tFIXME: Master maybe should do sth\n");
        }
-    } else if ((irq > 7) && (irq < 16)) {
+    } else if ((irq_num > 7) && (irq_num < 16)) {
 
-       state->slave_irr &= ~(1 << (irq - 8));
+       state->slave_irr &= ~(1 << (irq_num - 8));
        if ((state->slave_irr & (~(state->slave_imr))) == 0) {
            PrintDebug("\t\tFIXME: Slave maybe should do sth\n");
        }
@@ -325,7 +337,7 @@ static int pic_begin_irq(struct guest_info * info, void * private_data, int irq)
                state->master_irr &= ~(0x1 << irq);
            }
        } else {
-          PrintDebug("8259 PIC: (master) Ignoring begin_irq for %d since I don't own it\n",irq);
+          PrintDebug("8259 PIC: (master) Ignoring begin_irq for %d since I don't own it\n", irq);
        }
 
     } else {
@@ -337,11 +349,12 @@ static int pic_begin_irq(struct guest_info * info, void * private_data, int irq)
               state->slave_irr &= ~(0x1 << (irq - 8));
           }
        } else {
-          PrintDebug("8259 PIC: (slave) Ignoring begin_irq for %d since I don't own it\n",irq);
+          PrintDebug("8259 PIC: (slave) Ignoring begin_irq for %d since I don't own it\n", irq);
        }
-
     }
 
+
+
     return 0;
 }
 
@@ -462,6 +475,15 @@ static int write_master_port1(struct guest_info * core, ushort_t port, void * sr
             if ((cw2->EOI) && (!cw2->R) && (cw2->SL)) {
                 // specific EOI;
                 state->master_isr &= ~(0x01 << cw2->level);
+
+
+               /*
+               // ack the irq if requested
+               if (state->irq_ack_cbs[irq].ack) {
+                   state->irq_ack_cbs[irq].ack(info, irq, state->irq_ack_cbs[irq].private_data);
+               }
+               */
+
             } else if ((cw2->EOI) & (!cw2->R) && (!cw2->SL)) {
                 int i;
                 // Non-specific EOI
index 80f3d30..44ca08d 100644 (file)
@@ -72,14 +72,6 @@ static char * deliverymode_str[] = {
 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
               APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
 
-#define APIC_FIXED_DELIVERY  0x0
-#define APIC_LOWEST_DELIVERY 0x1
-#define APIC_SMI_DELIVERY    0x2
-#define APIC_RES1_DELIVERY   0x3
-#define APIC_NMI_DELIVERY    0x4
-#define APIC_INIT_DELIVERY   0x5
-#define APIC_SIPI_DELIVERY   0x6
-#define APIC_EXTINT_DELIVERY 0x7
 
 #define APIC_SHORTHAND_NONE        0x0
 #define APIC_SHORTHAND_SELF        0x1
@@ -180,6 +172,18 @@ struct apic_msr {
 
 
 
+
+struct irq_queue_entry {
+    uint32_t vector;
+    int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
+    void * private_data;
+
+    struct list_head list_node;
+};
+
+
+
+
 typedef enum {INIT_ST, 
              SIPI, 
              STARTED} ipi_state_t; 
@@ -234,6 +238,11 @@ struct apic_state {
     uint8_t int_en_reg[32];
     uint8_t trig_mode_reg[32];
 
+    struct {
+       int (*ack)(struct guest_info * core, uint32_t irq, void * private_data);
+       void * private_data;
+    } irq_ack_cbs[256];
+
     struct guest_info * core;
 
     void * controller_handle;
@@ -241,7 +250,12 @@ struct apic_state {
     struct v3_timer * timer;
 
 
-    struct v3_queue irq_queue;
+    struct {
+       v3_lock_t lock;
+       
+       uint64_t num_entries;
+       struct list_head entries;
+    } irq_queue ;
 
     uint32_t eoi;
 
@@ -328,8 +342,9 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) {
     apic->spec_eoi.val = 0x00000000;
 
 
-    v3_init_queue(&(apic->irq_queue));
-
+    INIT_LIST_HEAD(&(apic->irq_queue.entries));
+    v3_lock_init(&(apic->irq_queue.lock));
+    apic->irq_queue.num_entries = 0;
 
 }
 
@@ -388,7 +403,9 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo
 
 
 // irq_num is the bit offset into a 256 bit buffer...
-static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
+static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num, 
+                            int (*ack)(struct guest_info * core, uint32_t irq, void * private_data), 
+                            void * private_data) {
     int major_offset = (irq_num & ~0x00000007) >> 3;
     int minor_offset = irq_num & 0x00000007;
     uint8_t * req_location = apic->int_req_reg + major_offset;
@@ -405,6 +422,9 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 
     if (*en_location & flag) {
        *req_location |= flag;
+       apic->irq_ack_cbs[irq_num].ack = ack;
+       apic->irq_ack_cbs[irq_num].private_data = private_data;
+
        return 1;
     } else {
        PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
@@ -415,7 +435,12 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
 }
 
 
-static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) {
+
+static int add_apic_irq_entry(struct apic_state * apic, uint32_t irq_num, 
+                             int (*ack)(struct guest_info * core, uint32_t irq, void * private_data),
+                             void * private_data) {
+    unsigned int flags = 0;
+    struct irq_queue_entry * entry = NULL;
 
     if (irq_num <= 15) {
        PrintError("core %d: Attempting to raise an invalid interrupt: %d\n", 
@@ -423,16 +448,53 @@ static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) {
        return -1;
     }
 
-    v3_enqueue(&(apic->irq_queue), (addr_t)irq_num);
+    entry = V3_Malloc(sizeof(struct irq_queue_entry));
+
+    if (entry == NULL) {
+       PrintError("Could not allocate irq queue entry\n");
+       return -1;
+    }
+
+    entry->vector = irq_num;
+    entry->ack = ack;
+    entry->private_data = private_data;
+
+    flags = v3_lock_irqsave(apic->irq_queue.lock);
+    
+    list_add_tail(&(entry->list_node), &(apic->irq_queue.entries));
+    apic->irq_queue.num_entries++;
+
+    v3_unlock_irqrestore(apic->irq_queue.lock, flags);
+  
 
     return 0;
 }
 
 static void drain_irq_entries(struct apic_state * apic) {
-    uint32_t irq = 0;
 
-    while ((irq = (uint32_t)v3_dequeue(&(apic->irq_queue))) != 0) {
-       activate_apic_irq(apic, irq);
+    while (1) {
+       unsigned int flags = 0;
+       struct irq_queue_entry * entry = NULL;
+    
+       flags = v3_lock_irqsave(apic->irq_queue.lock);
+       
+       if (!list_empty(&(apic->irq_queue.entries))) {
+           struct list_head * q_entry = apic->irq_queue.entries.next;
+           entry = list_entry(q_entry, struct irq_queue_entry, list_node);
+
+           apic->irq_queue.num_entries--;
+           list_del(q_entry);
+       }
+       
+       v3_unlock_irqrestore(apic->irq_queue.lock, flags);
+
+       if (entry == NULL) {
+           break;
+       }
+
+       activate_apic_irq(apic, entry->vector, entry->ack, entry->private_data);
+
+       V3_Free(entry);
     }
 
 }
@@ -485,7 +547,7 @@ static int get_highest_irr(struct apic_state * apic) {
 
 
 
-static int apic_do_eoi(struct apic_state * apic) {
+static int apic_do_eoi(struct guest_info * core, struct apic_state * apic) {
     int isr_irq = get_highest_isr(apic);
 
     if (isr_irq != -1) {
@@ -498,6 +560,10 @@ static int apic_do_eoi(struct apic_state * apic) {
        
        *svc_location &= ~flag;
 
+       if (apic->irq_ack_cbs[isr_irq].ack) {
+           apic->irq_ack_cbs[isr_irq].ack(core, isr_irq, apic->irq_ack_cbs[isr_irq].private_data);
+       }
+
 #ifdef V3_CONFIG_CRAY_XT
        
        if ((isr_irq == 238) || 
@@ -526,7 +592,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
     switch (int_type) {
        case APIC_TMR_INT:
            vec_num = apic->tmr_vec_tbl.vec;
-           del_mode = APIC_FIXED_DELIVERY;
+           del_mode = IPI_FIXED;
            masked = apic->tmr_vec_tbl.mask;
            break;
        case APIC_THERM_INT:
@@ -551,7 +617,7 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
            break;
        case APIC_ERR_INT:
            vec_num = apic->err_vec_tbl.vec;
-           del_mode = APIC_FIXED_DELIVERY;
+           del_mode = IPI_FIXED;
            masked = apic->err_vec_tbl.mask;
            break;
        default:
@@ -565,9 +631,9 @@ static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_t
        return 0;
     }
 
-    if (del_mode == APIC_FIXED_DELIVERY) {
+    if (del_mode == IPI_FIXED) {
        //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
-       return add_apic_irq_entry(apic, vec_num);
+       return add_apic_irq_entry(apic, vec_num, NULL, NULL);
     } else {
        PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
        return -1;
@@ -681,34 +747,31 @@ static int should_deliver_ipi(struct apic_dev_state * apic_dev,
 // Only the src_apic pointer is used
 static int deliver_ipi(struct apic_state * src_apic, 
                       struct apic_state * dst_apic, 
-                      uint32_t vector, uint8_t del_mode) {
+                      struct v3_gen_ipi * ipi) {
 
 
     struct guest_info * dst_core = dst_apic->core;
 
 
-    switch (del_mode) {
+    switch (ipi->mode) {
 
-       case APIC_FIXED_DELIVERY:  
-       case APIC_LOWEST_DELIVERY: {
+       case IPI_FIXED:  
+       case IPI_LOWEST_PRIO: {
            // lowest priority - 
            // caller needs to have decided which apic to deliver to!
 
-           PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->vcpu_id); 
+           PrintDebug("delivering IRQ %d to core %u\n", ipi->vector, dst_core->vcpu_id); 
 
-           add_apic_irq_entry(dst_apic, vector);
+           add_apic_irq_entry(dst_apic, ipi->vector, ipi->ack, ipi->private_data);
            
-#ifdef V3_CONFIG_MULTITHREAD_OS
            if (dst_apic != src_apic) { 
                PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); 
                v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0);
            }
-#endif
-
 
            break;
        }
-       case APIC_INIT_DELIVERY: { 
+       case IPI_INIT: { 
 
            PrintDebug(" INIT delivery to core %u\n", dst_core->vcpu_id);
 
@@ -735,7 +798,7 @@ static int deliver_ipi(struct apic_state * src_apic,
 
            break;                                                      
        }
-       case APIC_SIPI_DELIVERY: { 
+       case IPI_SIPI: { 
 
            // Sanity check
            if (dst_apic->ipi_state != SIPI) { 
@@ -744,10 +807,10 @@ static int deliver_ipi(struct apic_state * src_apic,
                break;
            }
 
-           v3_reset_vm_core(dst_core, vector);
+           v3_reset_vm_core(dst_core, ipi->vector);
 
            PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
-                      vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
+                      ipi->vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
            // Maybe need to adjust the APIC?
            
            // We transition the target core to SIPI state
@@ -761,7 +824,7 @@ static int deliver_ipi(struct apic_state * src_apic,
            break;                                                      
        }
 
-       case APIC_EXTINT_DELIVERY: // EXTINT
+       case IPI_EXTINT: // EXTINT
            /* Two possible things to do here: 
             * 1. Ignore the IPI and assume the 8259a (PIC) will handle it
             * 2. Add 32 to the vector and inject it...
@@ -769,11 +832,11 @@ static int deliver_ipi(struct apic_state * src_apic,
             */
            return 0;
 
-       case APIC_SMI_DELIVERY: 
-       case APIC_RES1_DELIVERY: // reserved                                            
-       case APIC_NMI_DELIVERY:
+       case IPI_SMI: 
+       case IPI_RES1: // reserved                                              
+       case IPI_NMI:
        default:
-           PrintError("IPI %d delivery is unsupported\n", del_mode); 
+           PrintError("IPI %d delivery is unsupported\n", ipi->mode); 
            return -1;
     }
     
@@ -810,34 +873,32 @@ static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev,
 
 static int route_ipi(struct apic_dev_state * apic_dev,
                     struct apic_state * src_apic, 
-                    struct int_cmd_reg * icr) {
+                    struct v3_gen_ipi * ipi) {
     struct apic_state * dest_apic = NULL;
 
 
-    PrintDebug("apic: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
-              deliverymode_str[icr->del_mode], 
-              icr->vec, 
+    PrintDebug("apic: IPI %s %u from apic %p to %s %s %u\n",
+              deliverymode_str[ipi->mode], 
+              ipi->vector, 
               src_apic,               
-              (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
-              shorthand_str[icr->dst_shorthand], 
-              icr->dst,
-              icr->val);
+              (ipi->logical == 0) ? "(physical)" : "(logical)", 
+              shorthand_str[ipi->dst_shorthand], 
+              ipi->dst);
 
 
-    switch (icr->dst_shorthand) {
+    switch (ipi->dst_shorthand) {
 
        case APIC_SHORTHAND_NONE:  // no shorthand
-           if (icr->dst_mode == APIC_DEST_PHYSICAL) { 
+           if (ipi->logical == APIC_DEST_PHYSICAL) { 
 
-               dest_apic = find_physical_apic(apic_dev, icr->dst);
+               dest_apic = find_physical_apic(apic_dev, ipi->dst);
                
                if (dest_apic == NULL) { 
-                   PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst);
+                   PrintError("apic: Attempted send to unregistered apic id=%u\n", ipi->dst);
                    return -1;
                }
 
-               if (deliver_ipi(src_apic, dest_apic, 
-                               icr->vec, icr->del_mode) == -1) {
+               if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
                    PrintError("apic: Could not deliver IPI\n");
                    return -1;
                }
@@ -845,11 +906,11 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 
                PrintDebug("apic: done\n");
 
-           } else if (icr->dst_mode == APIC_DEST_LOGICAL) {
+           } else if (ipi->logical == APIC_DEST_LOGICAL) {
                
-               if (icr->del_mode != APIC_LOWEST_DELIVERY) { 
+               if (ipi->mode != IPI_LOWEST_PRIO) { 
                    int i;
-                   uint8_t mda = icr->dst;
+                   uint8_t mda = ipi->dst;
 
                    // logical, but not lowest priority
                    // we immediately trigger
@@ -869,8 +930,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                            return -1;
                        } else if (del_flag == 1) {
 
-                           if (deliver_ipi(src_apic, dest_apic, 
-                                           icr->vec, icr->del_mode) == -1) {
+                           if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
                                PrintError("apic: Error: Could not deliver IPI\n");
                                return -1;
                            }
@@ -878,7 +938,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                    }
                } else {  // APIC_LOWEST_DELIVERY
                    struct apic_state * cur_best_apic = NULL;
-                   uint8_t mda = icr->dst;
+                   uint8_t mda = ipi->dst;
                    int i;
 
                    // logical, lowest priority
@@ -908,15 +968,14 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 
                            v3_unlock_irqrestore(apic_dev->state_lock, flags);
 
-                       }                       
+                       }
                    }
 
                    // now we will deliver to the best one if it exists
                    if (!cur_best_apic) { 
                        PrintDebug("apic: lowest priority deliver, but no destinations!\n");
                    } else {
-                       if (deliver_ipi(src_apic, cur_best_apic, 
-                                       icr->vec, icr->del_mode) == -1) {
+                       if (deliver_ipi(src_apic, cur_best_apic, ipi) == -1) {
                            PrintError("apic: Error: Could not deliver IPI\n");
                            return -1;
                        }
@@ -936,15 +995,15 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 
 
 
-           if (icr->dst_mode == APIC_DEST_PHYSICAL)  {  /* physical delivery */
-               if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
+           if (ipi->logical == APIC_DEST_PHYSICAL)  {  /* physical delivery */
+               if (deliver_ipi(src_apic, src_apic, ipi) == -1) {
                    PrintError("apic: Could not deliver IPI to self (physical)\n");
                    return -1;
                }
-           } else if (icr->dst_mode == APIC_DEST_LOGICAL) {  /* logical delivery */
+           } else if (ipi->logical == APIC_DEST_LOGICAL) {  /* logical delivery */
                PrintError("apic: use of logical delivery in self (untested)\n");
 
-               if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
+               if (deliver_ipi(src_apic, src_apic, ipi) == -1) {
                    PrintError("apic: Could not deliver IPI to self (logical)\n");
                    return -1;
                }
@@ -961,8 +1020,8 @@ static int route_ipi(struct apic_dev_state * apic_dev,
            for (i = 0; i < apic_dev->num_apics; i++) { 
                dest_apic = &(apic_dev->apics[i]);
                
-               if ((dest_apic != src_apic) || (icr->dst_shorthand == APIC_SHORTHAND_ALL)) { 
-                   if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
+               if ((dest_apic != src_apic) || (ipi->dst_shorthand == APIC_SHORTHAND_ALL)) { 
+                   if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
                        PrintError("apic: Error: Could not deliver IPI\n");
                        return -1;
                    }
@@ -972,7 +1031,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
            break;
        }
        default:
-           PrintError("apic: Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
+           PrintError("apic: Error routing IPI, invalid Mode (%d)\n", ipi->dst_shorthand);
            return -1;
     }
  
@@ -1410,23 +1469,32 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            // Action Registers
        case EOI_OFFSET:
            // do eoi 
-           apic_do_eoi(apic);
+           apic_do_eoi(core, apic);
            break;
 
        case INT_CMD_LO_OFFSET: {
            // execute command 
 
-           struct int_cmd_reg tmp_icr;
+           struct v3_gen_ipi tmp_ipi;
 
            apic->int_cmd.lo = op_val;
 
-           tmp_icr = apic->int_cmd;
+           tmp_ipi.vector = apic->int_cmd.vec;
+           tmp_ipi.mode = apic->int_cmd.del_mode;
+           tmp_ipi.logical = apic->int_cmd.dst_mode;
+           tmp_ipi.trigger_mode = apic->int_cmd.trig_mode;
+           tmp_ipi.dst_shorthand = apic->int_cmd.dst_shorthand;
+           tmp_ipi.dst = apic->int_cmd.dst;
+               
+           tmp_ipi.ack = NULL;
+           tmp_ipi.private_data = NULL;
+           
 
            //      V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
            //       apic->lapic_id.val, core->vcpu_id,
            //       apic->int_cmd.val, apic->int_cmd.dst);
 
-           if (route_ipi(apic_dev, apic, &tmp_icr) == -1) { 
+           if (route_ipi(apic_dev, apic, &tmp_ipi) == -1) { 
                PrintError("IPI Routing failure\n");
                return -1;
            }
@@ -1504,41 +1572,11 @@ static int apic_get_intr_number(struct guest_info * core, void * private_data) {
 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
        (((struct vm_device *)dev_data)->private_data);
-    struct int_cmd_reg tmp_icr;
-
-    // zero out all the fields
-    tmp_icr.val = 0;
 
-    tmp_icr.vec = ipi->vector;
-    tmp_icr.del_mode = ipi->mode;
-    tmp_icr.dst_mode = ipi->logical;
-    tmp_icr.trig_mode = ipi->trigger_mode;
-    tmp_icr.dst_shorthand = ipi->dst_shorthand;
-    tmp_icr.dst = ipi->dst;
-
-
-    return route_ipi(apic_dev, NULL, &tmp_icr);
+    return route_ipi(apic_dev, NULL, ipi);
 }
 
 
-int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
-    struct apic_dev_state * apic_dev = (struct apic_dev_state *)
-       (((struct vm_device*)dev_data)->private_data);
-    struct apic_state * apic = &(apic_dev->apics[dst]); 
-
-    PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
-
-    add_apic_irq_entry(apic, irq);
-
-#ifdef V3_CONFIG_MULTITHREAD_OS   
-    if ((V3_Get_CPU() != dst)) {
-       v3_interrupt_cpu(vm, dst, 0);
-    }
-#endif
-
-    return 0;
-}
-
 
 
 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
index e9d27be..ce25023 100644 (file)
@@ -539,8 +539,8 @@ static int cirrus_gfx_card_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg){
        //                                                     Not sure if STD
        pci_dev = v3_pci_register_device(video_state->pci_bus, PCI_STD_DEVICE, 0,
                                         //or0  1st null could be pci_config_update
-                                        -1, 0, "CIRRUS_GFX_CARD", bars, NULL, NULL,
-                                        NULL, dev);
+                                        -1, 0, "CIRRUS_GFX_CARD", bars, NULL, NULL, 
+                                        NULL, NULL, dev);
 
        if (pci_dev == NULL) {
            PrintError("Failed to register VIDEO %d with PCI\n", i);
index bf1aaf8..9625d3b 100644 (file)
@@ -36,10 +36,10 @@ struct disk_state {
 
 
 
-static int write_all(v3_file_t fd, char * buf, int offset, int length) {
-    int bytes_written = 0;
+static int write_all(v3_file_t fd, char * buf, uint64_t offset, uint64_t length) {
+    uint64_t bytes_written = 0;
     
-    PrintDebug("Writing %d bytes\n", length - bytes_written);
+    PrintDebug("Writing %llu bytes\n", length - bytes_written);
     while (bytes_written < length) {
        int tmp_bytes = v3_file_write(fd, buf + bytes_written, length - bytes_written, offset + bytes_written);
        PrintDebug("Wrote %d bytes\n", tmp_bytes);
@@ -56,10 +56,10 @@ static int write_all(v3_file_t fd, char * buf, int offset, int length) {
 }
 
 
-static int read_all(v3_file_t fd, char * buf, int offset, int length) {
-    int bytes_read = 0;
+static int read_all(v3_file_t fd, char * buf, uint64_t offset, uint64_t length) {
+    uint64_t bytes_read = 0;
     
-    PrintDebug("Reading %d bytes\n", length - bytes_read);
+    PrintDebug("Reading %llu bytes\n", length - bytes_read);
     while (bytes_read < length) {
        int tmp_bytes = v3_file_read(fd, buf + bytes_read, length - bytes_read, offset + bytes_read);
        PrintDebug("Read %d bytes\n", tmp_bytes);
@@ -78,7 +78,7 @@ static int read_all(v3_file_t fd, char * buf, int offset, int length) {
 static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
     struct disk_state * disk = (struct disk_state *)private_data;
 
-    PrintDebug("Reading %d bytes from %p to %p\n", (uint32_t)num_bytes, (uint8_t *)(disk->disk_image + lba), buf);
+    PrintDebug("Reading %llu bytes from %p to %p\n", num_bytes, (uint8_t *)(disk->disk_image + lba), buf);
 
     if (lba + num_bytes > disk->capacity) {
        PrintError("Out of bounds read: lba=%llu, num_bytes=%llu, capacity=%llu\n",
@@ -93,7 +93,7 @@ static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_
 static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) {
     struct disk_state * disk = (struct disk_state *)private_data;
 
-    PrintDebug("Writing %d bytes from %p to %p\n", (uint32_t)num_bytes,  buf, (uint8_t *)(disk->disk_image + lba));
+    PrintDebug("Writing %llu bytes from %p to %p\n", num_bytes,  buf, (uint8_t *)(disk->disk_image + lba));
 
     if (lba + num_bytes > disk->capacity) {
        PrintError("Out of bounds read: lba=%llu, num_bytes=%llu, capacity=%llu\n",
@@ -109,8 +109,7 @@ static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private
 static uint64_t get_capacity(void * private_data) {
     struct disk_state * disk = (struct disk_state *)private_data;
 
-    PrintDebug("Querying FILEDISK capacity %d\n", 
-              (uint32_t)(disk->capacity));
+    PrintDebug("Querying FILEDISK capacity %llu\n", disk->capacity);
 
     return disk->capacity;
 }
@@ -183,8 +182,8 @@ static int disk_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     disk->capacity = v3_file_size(disk->fd);
 
-    PrintDebug("Registering FILEDISK %s (path=%s, fd=%lu, size=%lu)\n",
-              dev_id, path, file->fd, file->capacity);
+    V3_Print("Registering FILEDISK %s (path=%s, fd=%lu, size=%llu)\n",
+            dev_id, path, (addr_t)disk->fd, disk->capacity);
 
 
     if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"), 
index 6c587d3..01e8088 100644 (file)
@@ -107,7 +107,7 @@ static int i440_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     pci_dev = v3_pci_register_device(state->pci, PCI_STD_DEVICE, 
                                     0, 0, 0, "i440FX", bars,
-                                    NULL, NULL, NULL, state);
+                                    NULL, NULL, NULL, NULL, state);
 
     if (!pci_dev) {
        v3_remove_device(dev);
index 285e534..206a8ef 100644 (file)
@@ -206,9 +206,17 @@ struct ide_channel {
     // Control Registers
     struct ide_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376
 
-    struct ide_dma_cmd_reg dma_cmd;
-    struct ide_dma_status_reg dma_status;
-    uint32_t dma_prd_addr;
+    union {
+       uint8_t dma_ports[8];
+       struct {
+           struct ide_dma_cmd_reg dma_cmd;
+           uint8_t rsvd1;
+           struct ide_dma_status_reg dma_status;
+           uint8_t rsvd2;
+           uint32_t dma_prd_addr;
+       } __attribute__((packed));
+    } __attribute__((packed));
+
     uint32_t dma_tbl_index;
 };
 
@@ -283,7 +291,9 @@ static inline int is_lba_enabled(struct ide_channel * channel) {
 /* Drive Commands */
 static void ide_raise_irq(struct ide_internal * ide, struct ide_channel * channel) {
     if (channel->ctrl_reg.irq_disable == 0) {
-       //        PrintError("Raising IDE Interrupt %d\n", channel->irq);
+
+       //PrintError("Raising IDE Interrupt %d\n", channel->irq);
+
         channel->dma_status.int_gen = 1;
         v3_raise_irq(ide->vm, channel->irq);
     }
@@ -356,12 +366,12 @@ static int dma_write(struct guest_info * core, struct ide_internal * ide, struct
 #include "ata.h"
 
 
-#ifdef V3_CONFIG_DEBUG_IDE
+
 static void print_prd_table(struct ide_internal * ide, struct ide_channel * channel) {
     struct ide_dma_prd prd_entry;
     int index = 0;
 
-    PrintDebug("Dumping PRD table\n");
+    V3_Print("Dumping PRD table\n");
 
     while (1) {
        uint32_t prd_entry_addr = channel->dma_prd_addr + (sizeof(struct ide_dma_prd) * index);
@@ -374,7 +384,7 @@ static void print_prd_table(struct ide_internal * ide, struct ide_channel * chan
            return;
        }
 
-       PrintDebug("\tPRD Addr: %x, PRD Len: %d, EOT: %d\n", 
+       V3_Print("\tPRD Addr: %x, PRD Len: %d, EOT: %d\n", 
                   prd_entry.base_addr, 
                   (prd_entry.size == 0) ? 0x10000 : prd_entry.size, 
                   prd_entry.end_of_table);
@@ -388,7 +398,7 @@ static void print_prd_table(struct ide_internal * ide, struct ide_channel * chan
 
     return;
 }
-#endif
+
 
 /* IO Operations */
 static int dma_read(struct guest_info * core, struct ide_internal * ide, struct ide_channel * channel) {
@@ -456,15 +466,18 @@ static int dma_read(struct guest_info * core, struct ide_internal * ide, struct
                    }
                } else {
                    /*
-                   PrintError("DMA of command packet\n");
                    PrintError("How does this work (ATAPI CMD=%x)???\n", drive->cd_state.atapi_cmd);
                    return -1;
                    */
                    int cmd_ret = 0;
 
+                   //V3_Print("DMA of command packet\n");
+
                    bytes_to_write = (prd_bytes_left > bytes_left) ? bytes_left : prd_bytes_left;
                    prd_bytes_left = bytes_to_write;
 
+
+                   // V3_Print("Writing ATAPI cmd OP DMA (cmd=%x) (len=%d)\n", drive->cd_state.atapi_cmd, prd_bytes_left);
                    cmd_ret = v3_write_gpa_memory(core, prd_entry.base_addr + prd_offset, 
                                                  bytes_to_write, drive->data_buf); 
 
@@ -591,7 +604,13 @@ static int dma_write(struct guest_info * core, struct ide_internal * ide, struct
        PrintDebug("PRD Addr: %x, PRD Len: %d, EOT: %d\n", 
                   prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table);
 
-       prd_bytes_left = prd_entry.size;
+
+       if (prd_entry.size == 0) {
+           // a size of 0 means 64k
+           prd_bytes_left = 0x10000;
+       } else {
+           prd_bytes_left = prd_entry.size;
+       }
 
        while (prd_bytes_left > 0) {
            uint_t bytes_to_write = 0;
@@ -632,6 +651,12 @@ static int dma_write(struct guest_info * core, struct ide_internal * ide, struct
 
        if ((prd_entry.end_of_table == 1) && (bytes_left > 0)) {
            PrintError("DMA table not large enough for data transfer...\n");
+           PrintError("\t(bytes_left=%u) (transfer_length=%u)...\n", 
+                      bytes_left, drive->transfer_length);
+           PrintError("PRD Addr: %x, PRD Len: %d, EOT: %d\n", 
+                      prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table);
+
+           print_prd_table(ide, channel);
            return -1;
        }
     }
@@ -745,7 +770,7 @@ static int write_dma_port(struct guest_info * core, ushort_t port, void * src, u
 }
 
 
-static int read_dma_port(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * private_data) {
+static int read_dma_port(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
     struct ide_internal * ide = (struct ide_internal *)private_data;
     uint16_t port_offset = port & (DMA_CHANNEL_FLAG - 1);
     uint_t channel_flag = (port & DMA_CHANNEL_FLAG) >> 3;
@@ -753,44 +778,13 @@ static int read_dma_port(struct guest_info * core, ushort_t port, void * dst, ui
 
     PrintDebug("Reading DMA port %d (%x) (channel=%d)\n", port, port, channel_flag);
 
-    switch (port_offset) {
-       case DMA_CMD_PORT:
-           *(uint8_t *)dst = channel->dma_cmd.val;
-           break;
-
-       case DMA_STATUS_PORT:
-           if (length != 1) {
-               PrintError("Invalid read length for DMA status port\n");
-               return -1;
-           }
-
-           *(uint8_t *)dst = channel->dma_status.val;
-           break;
-
-       case DMA_PRD_PORT0:
-       case DMA_PRD_PORT1:
-       case DMA_PRD_PORT2:
-       case DMA_PRD_PORT3: {
-           uint_t addr_index = port_offset & 0x3;
-           uint8_t * addr_buf = (uint8_t *)&(channel->dma_prd_addr);
-           int i = 0;
-
-           if (addr_index + length > 4) {
-               PrintError("DMA Port space overrun port=%x len=%d\n", port_offset, length);
-               return -1;
-           }
-
-           for (i = 0; i < length; i++) {
-               *((uint8_t *)dst + i) = addr_buf[addr_index + i];
-           }
-
-           break;
-       }
-       default:
-           PrintError("IDE: Invalid DMA Port (%d) (%s)\n", port, dma_port_to_str(port_offset));
-           break;
+    if (port_offset + length > 16) {
+       PrintError("DMA Port Read: Port overrun (port_offset=%d, length=%d)\n", port_offset, length);
+       return -1;
     }
 
+    memcpy(dst, channel->dma_ports + port_offset, length);
+    
     PrintDebug("\tval=%x (len=%d)\n", *(uint32_t *)dst, length);
 
     return length;
@@ -1453,7 +1447,6 @@ static void init_channel(struct ide_channel * channel) {
     channel->cmd_reg = 0x00;
     channel->ctrl_reg.val = 0x08;
 
-
     channel->dma_cmd.val = 0;
     channel->dma_status.val = 0;
     channel->dma_prd_addr = 0;
@@ -1466,7 +1459,7 @@ static void init_channel(struct ide_channel * channel) {
 }
 
 
-static int pci_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
+static int pci_config_update(struct pci_device * pci_dev, uint32_t reg_num, void * src, uint_t length, void * private_data) {
     PrintDebug("PCI Config Update\n");
     /*
     struct ide_internal * ide = (struct ide_internal *)(private_data);
@@ -1855,7 +1848,7 @@ static int ide_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
        pci_dev = v3_pci_register_device(ide->pci_bus, PCI_STD_DEVICE, 0, sb_pci->dev_num, 1, 
                                         "PIIX3_IDE", bars,
-                                        pci_config_update, NULL, NULL, ide);
+                                        pci_config_update, NULL, NULL, NULL, ide);
 
        if (pci_dev == NULL) {
            PrintError("Failed to register IDE BUS %d with PCI\n", i); 
index 0d7c3dc..9d477de 100644 (file)
@@ -263,11 +263,12 @@ static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src,
 }
 
 
-static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) {
+static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
     struct io_apic_state * ioapic = (struct io_apic_state *)(private_data);  
     struct redir_tbl_entry * irq_entry = NULL;
+    uint8_t irq_num = irq->irq;
 
-    if (irq==0) { 
+    if (irq_num == 0) { 
       // IRQ 0 being raised, in the Palacios context, means the PIT
       // However, the convention is that it is the PIC that is connected
       // to PIN 0 of the IOAPIC and the PIT is connected to pin 2
@@ -275,15 +276,15 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq
       // the PIC may signal to the IOAPIC in a different path.
       // Yes, this is kind of hideous, but it is needed to have the
       // PIT correctly show up via the IOAPIC
-      irq=2;
+      irq_num = 2;
     }
 
-    if (irq > 24) {
+    if (irq_num > 24) {
        PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.id);
        return -1;
     }
 
-    irq_entry = &(ioapic->redir_tbl[irq]);
+    irq_entry = &(ioapic->redir_tbl[irq_num]);
 
     if (irq_entry->mask == 0) {
        struct v3_gen_ipi ipi;
@@ -299,6 +300,8 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq
        ipi.dst = irq_entry->dst_field;
        ipi.dst_shorthand = 0;
 
+       ipi.ack = irq->ack;
+       ipi.private_data = irq->private_data;
 
        PrintDebug("ioapic %u: IPI: vector 0x%x, mode 0x%x, logical 0x%x, trigger 0x%x, dst 0x%x, shorthand 0x%x\n",
                   ioapic->ioapic_id.id, ipi.vector, ipi.mode, ipi.logical, ipi.trigger_mode, ipi.dst, ipi.dst_shorthand);
@@ -313,7 +316,7 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq
 }
 
 /* I don't know if we can do anything here.... */
-static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) {
+static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
     return 0;
 }
 
index 794e8b3..ea57b32 100644 (file)
@@ -188,6 +188,9 @@ struct keyboard_internal {
         // after having a f0 sent to 60
        // we wait for a new output byte on 60
        GETSET_SCANCODES,
+       // first send ACK (0xfa)
+       // then wait for reception, and reset kb state
+       SET_DEFAULTS,
     } state;
 
 
@@ -223,6 +226,9 @@ struct keyboard_internal {
 };
 
 
+static int keyboard_reset_device(struct keyboard_internal * kbd);
+
+
 static int update_kb_irq(struct keyboard_internal * state) {
     int irq_num = 0;
 
@@ -898,6 +904,11 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void *
            kbd->state = NORMAL;
            break;
 
+       case SET_DEFAULTS:
+           keyboard_reset_device(kbd);
+           kbd->state = NORMAL;
+           break;
+
        default:
        case NORMAL: {
            // command is being sent to keyboard controller
@@ -942,6 +953,15 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void *
                    kbd->state = GETSET_SCANCODES;
                    break;
 
+
+               case 0xf6: // set defaults
+                   // ACK command
+                   // clear output buffer
+                   // reset to init state
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+                   kbd->state = SET_DEFAULTS;
+                   break;
+
                case 0xfe: // resend
                case 0xfd: // set key type make
                case 0xfc: // set key typ make/break
@@ -950,7 +970,7 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void *
                case 0xf9: // set all make
                case 0xf8: // set all make/break
                case 0xf7: // set all typemaktic
-               case 0xf6: // set defaults
+
                    PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
                    ret = -1;
                    break;
index e936f9e..af3a903 100644 (file)
@@ -172,7 +172,7 @@ static int handle_kick(struct guest_info * core, struct virtio_balloon_state * v
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
+       v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0);
        virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE;
     }
 
@@ -336,7 +336,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u
        case VIRTIO_ISR_PORT:
            *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
            virtio->virtio_cfg.pci_isr = 0;
-           v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
+           v3_pci_lower_irq(virtio->pci_bus, virtio->pci_dev, 0);
            break;
 
        default:
@@ -379,7 +379,7 @@ static int set_size(struct virtio_balloon_state * virtio, addr_t size) {
 
     PrintDebug("Requesting %d pages\n", virtio->balloon_cfg.requested_pages);
 
-    v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
+    v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0);
     virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE | VIRTIO_ISR_CFG_CHANGED;
     
     return 0;
@@ -476,7 +476,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
                                         0, PCI_AUTO_DEV_NUM, 0,
                                         "LNX_VIRTIO_BALLOON", bars,
-                                        NULL, NULL, NULL, virtio_state);
+                                        NULL, NULL, NULL, NULL, virtio_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
index fd9ec61..6cdfa06 100644 (file)
@@ -285,7 +285,7 @@ static int handle_kick(struct guest_info * core, struct virtio_blk_state * blk_s
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  blk_state->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(blk_state->virtio_dev->pci_bus, 0, blk_state->pci_dev);
+       v3_pci_raise_irq(blk_state->virtio_dev->pci_bus, blk_state->pci_dev, 0);
        blk_state->virtio_cfg.pci_isr = 1;
     }
 
@@ -454,7 +454,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u
        case VIRTIO_ISR_PORT:
            *(uint8_t *)dst = blk_state->virtio_cfg.pci_isr;
            blk_state->virtio_cfg.pci_isr = 0;
-           v3_pci_lower_irq(blk_state->virtio_dev->pci_bus, 0, blk_state->pci_dev);
+           v3_pci_lower_irq(blk_state->virtio_dev->pci_bus, blk_state->pci_dev, 0);
            break;
 
        default:
@@ -548,7 +548,7 @@ static int register_dev(struct virtio_dev_state * virtio, struct virtio_blk_stat
     pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 
                                     0, PCI_AUTO_DEV_NUM, 0,
                                     "LNX_VIRTIO_BLK", bars,
-                                    NULL, NULL, NULL, blk_state);
+                                    NULL, NULL, NULL, NULL, blk_state);
     
     if (!pci_dev) {
        PrintError("Could not register PCI Device\n");
index f7f2a11..0afefb8 100644 (file)
@@ -147,7 +147,7 @@ static int handle_kick(struct guest_info * core, struct virtio_console_state * v
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
+       v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0);
        virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE;
     }
 
@@ -194,7 +194,7 @@ static uint64_t virtio_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len
 
     // say hello
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-           v3_pci_raise_irq(cons_state->pci_bus, 0, cons_state->pci_dev);
+       v3_pci_raise_irq(cons_state->pci_bus, cons_state->pci_dev, 0);
            cons_state->virtio_cfg.pci_isr = 0x1;
     }
 
@@ -359,7 +359,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u
        case VIRTIO_ISR_PORT:
            *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
            virtio->virtio_cfg.pci_isr = 0;
-           v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
+           v3_pci_lower_irq(virtio->pci_bus, virtio->pci_dev, 0);
            break;
 
        default:
@@ -489,7 +489,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
                                         0, PCI_AUTO_DEV_NUM, 0,
                                         "LNX_VIRTIO_CONSOLE", bars,
-                                        NULL, NULL, NULL, virtio_state);
+                                        NULL, NULL, NULL, NULL, virtio_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
index 400cb0c..7f217ae 100644 (file)
@@ -266,81 +266,78 @@ static int handle_pkt_tx(struct guest_info * core,
                         struct virtio_net_state * virtio_state,
                         int quote)
 {
-    struct virtio_queue *q = &(virtio_state->tx_vq);
+    struct virtio_queue * q;
     int txed = 0, left = 0;
     unsigned long flags;
 
+    q = &(virtio_state->tx_vq);
     if (!q->ring_avail_addr) {
        return -1;
     }
 
-    flags = v3_lock_irqsave(virtio_state->tx_lock);
-    while (q->cur_avail_idx != q->avail->index) {
-       struct virtio_net_hdr_mrg_rxbuf * hdr = NULL;
+    while (1) {
        struct vring_desc * hdr_desc = NULL;
        addr_t hdr_addr = 0;
-       uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
-       int desc_cnt = get_desc_count(q, desc_idx);
+       uint16_t desc_idx, tmp_idx;
+       int desc_cnt;
+       
+       flags = v3_lock_irqsave(virtio_state->tx_lock);
+
+       if(q->cur_avail_idx == q->avail->index ||
+           (quote > 0 && txed >= quote)) {
+           left = (q->cur_avail_idx != q->avail->index);
+           break;
+       }
+       
+       desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
+       tmp_idx = q->cur_avail_idx ++;
+       
+       v3_unlock_irqrestore(virtio_state->tx_lock, flags);
 
+       desc_cnt = get_desc_count(q, desc_idx);
        if(desc_cnt != 2){
            PrintError("VNIC: merged rx buffer not supported, desc_cnt %d\n", desc_cnt);
-           goto exit_error;
        }
 
        hdr_desc = &(q->desc[desc_idx]);
-       if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
-           PrintError("Could not translate block header address\n");
-           goto exit_error;
-       }
+       if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) != -1) {
+           struct virtio_net_hdr_mrg_rxbuf * hdr;
+           struct vring_desc * buf_desc;
 
-       hdr = (struct virtio_net_hdr_mrg_rxbuf *)hdr_addr;
-       desc_idx = hdr_desc->next;
+           hdr = (struct virtio_net_hdr_mrg_rxbuf *)hdr_addr;
+           desc_idx = hdr_desc->next;
 
-       V3_Net_Print(2, "Virtio NIC: TX hdr count : %d\n", hdr->num_buffers);
-
-       /* here we assumed that one ethernet pkt is not splitted into multiple buffer */        
-       struct vring_desc * buf_desc = &(q->desc[desc_idx]);
-       if (tx_one_pkt(core, virtio_state, buf_desc) == -1) {
-           PrintError("Virtio NIC: Fails to send packet\n");
-       }
-       if(buf_desc->next & VIRTIO_NEXT_FLAG){
-           PrintError("Virtio NIC: TX more buffer need to read\n");
+           /* here we assumed that one ethernet pkt is not splitted into multiple buffer */    
+           buf_desc = &(q->desc[desc_idx]);
+           if (tx_one_pkt(core, virtio_state, buf_desc) == -1) {
+               PrintError("Virtio NIC: Fails to send packet\n");
+           }
+       } else {
+           PrintError("Could not translate block header address\n");
        }
+
+       flags = v3_lock_irqsave(virtio_state->tx_lock);
        
        q->used->ring[q->used->index % q->queue_size].id = 
-           q->avail->ring[q->cur_avail_idx % q->queue_size];
+           q->avail->ring[tmp_idx % q->queue_size];
        
-       q->used->ring[q->used->index % q->queue_size].length = 
-           buf_desc->length; /* What do we set this to???? */
+       //q->used->ring[q->used->index % q->queue_size].length = buf_desc->length; /* What do we set this to???? */
        
        q->used->index ++;
-       q->cur_avail_idx ++;
        
-       if(++txed >= quote && quote > 0){
-           left = (q->cur_avail_idx != q->avail->index);
-           break;
-       }
+       v3_unlock_irqrestore(virtio_state->tx_lock, flags);
+
+       txed ++;
     }
-    
-    v3_unlock_irqrestore(virtio_state->tx_lock, flags);
-    
+        
     if (txed && !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 
-                        0, virtio_state->pci_dev);
+                        virtio_state->pci_dev, 0);
        virtio_state->virtio_cfg.pci_isr = 0x1;
        virtio_state->stats.rx_interrupts ++;
     }
 
-    if(txed > 0) {
-       V3_Net_Print(2, "Virtio Handle TX: txed pkts: %d, left %d\n", txed, left);
-    }
-
     return left;
-    
- exit_error:
-    
-    v3_unlock_irqrestore(virtio_state->tx_lock, flags);
-    return -1;
 }
 
 
@@ -557,7 +554,7 @@ static int virtio_io_read(struct guest_info *core,
            *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
            virtio->virtio_cfg.pci_isr = 0;
            v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 
-                            0, virtio->pci_dev);
+                            virtio->pci_dev, 0);
            break;
 
        case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN:
@@ -712,7 +709,7 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
                     virtio->pci_dev->config_header.intr_line);
 
        virtio->virtio_cfg.pci_isr = 0x1;       
-       v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
+       v3_pci_raise_irq(virtio->virtio_dev->pci_bus, virtio->pci_dev, 0);
        virtio->stats.rx_interrupts ++;
     }
 
@@ -807,7 +804,7 @@ static int register_dev(struct virtio_dev_state * virtio,
     pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 
                                     0, PCI_AUTO_DEV_NUM, 0,
                                     "LNX_VIRTIO_NIC", bars,
-                                    NULL, NULL, NULL, net_state);
+                                    NULL, NULL, NULL, NULL, net_state);
     
     if (!pci_dev) {
        PrintError("Virtio NIC: Could not register PCI Device\n");
@@ -842,6 +839,7 @@ static int register_dev(struct virtio_dev_state * virtio,
     return 0;
 }
 
+#if 0
 #define RATE_UPPER_THRESHOLD 10  /* 10000 pkts per second, around 100Mbits */
 #define RATE_LOWER_THRESHOLD 1
 #define PROFILE_PERIOD 10000 /*us*/
@@ -909,7 +907,7 @@ static void virtio_nic_timer(struct guest_info * core,
 static struct v3_timer_ops timer_ops = {
     .update_timer = virtio_nic_timer,
 };
-
+#endif
 
 static int connect_fn(struct v3_vm_info * info, 
                      void * frontend_data, 
@@ -930,8 +928,7 @@ static int connect_fn(struct v3_vm_info * info,
     net_state->tx_notify = 1;
     net_state->rx_notify = 1;
        
-    net_state->timer = v3_add_timer(&(info->cores[0]),
-                                &timer_ops,net_state);
+    //net_state->timer = v3_add_timer(&(info->cores[0]), &timer_ops,net_state);
 
     ops->recv = virtio_rx;
     ops->poll = virtio_poll;
index f5b6501..010415f 100644 (file)
@@ -147,7 +147,7 @@ static int handle_kick(struct guest_info * core, struct virtio_sym_state * sym_s
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  sym_state->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev);
+       v3_pci_raise_irq(sym_state->pci_bus, sym_state->pci_dev, 0);
        sym_state->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE;
     }
 
@@ -314,7 +314,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u
        case VIRTIO_ISR_PORT:
            *(uint8_t *)dst = sym_state->virtio_cfg.pci_isr;
            sym_state->virtio_cfg.pci_isr = 0;
-           v3_pci_lower_irq(sym_state->pci_bus, 0, sym_state->pci_dev);
+           v3_pci_lower_irq(sym_state->pci_bus, sym_state->pci_dev, 0);
            break;
 
        default:
@@ -420,7 +420,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
                                         0, PCI_AUTO_DEV_NUM, 0,
                                         "LNX_VIRTIO_SYM", bars,
-                                        NULL, NULL, NULL, virtio_state);
+                                        NULL, NULL, NULL, NULL, virtio_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
index 993dcb6..d8172df 100644 (file)
@@ -238,7 +238,7 @@ static int handle_xfer_kick(struct guest_info * core, struct virtio_sym_state *
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  sym_state->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev);
+       v3_pci_raise_irq(sym_state->pci_bus, sym_state->pci_dev, 0);
        sym_state->virtio_cfg.pci_isr = 1;
     }
 
@@ -307,7 +307,7 @@ static int handle_notification_kick(struct guest_info * core, struct virtio_sym_
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  sym_state->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(sym_state->pci_bus, 0, sym_state->pci_dev);
+       v3_pci_raise_irq(sym_state->pci_bus, sym_state->pci_dev, 0);
        sym_state->virtio_cfg.pci_isr = 1;
     }
 
@@ -491,7 +491,7 @@ static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, u
        case VIRTIO_ISR_PORT:
            *(uint8_t *)dst = sym_state->virtio_cfg.pci_isr;
            sym_state->virtio_cfg.pci_isr = 0;
-           v3_pci_lower_irq(sym_state->pci_bus, 0, sym_state->pci_dev);
+           v3_pci_lower_irq(sym_state->pci_bus, sym_state->pci_dev, 0);
            break;
 
        default:
@@ -579,7 +579,7 @@ static int virtio_load_capsule(struct v3_vm_info * vm, struct v3_sym_capsule * m
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("SYMMOD: Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
+       v3_pci_raise_irq(virtio->pci_bus, virtio->pci_dev, 0);
        virtio->virtio_cfg.pci_isr = 0x1;
     }
 
@@ -677,7 +677,7 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
                                         0, PCI_AUTO_DEV_NUM, 0,
                                         "LNX_VIRTIO_SYMMOD", bars,
-                                        NULL, NULL, NULL, virtio_state);
+                                        NULL, NULL, NULL, NULL, virtio_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
index 7b6d75c..5bf8ae0 100644 (file)
@@ -204,7 +204,7 @@ static int handle_cmd_kick(struct guest_info * core,
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  vnet_state->pci_dev->config_header.intr_line);
-       v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
+       v3_pci_raise_irq(vnet_state->pci_bus, vnet_state->pci_dev, 0);
        vnet_state->virtio_cfg.pci_isr = 1;
     }
 
@@ -258,7 +258,7 @@ static int vnet_pkt_input_cb(struct v3_vm_info * vm,
     }
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-       v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
+       v3_pci_raise_irq(vnet_state->pci_bus, vnet_state->pci_dev, 0);
        vnet_state->virtio_cfg.pci_isr = 0x1;
        PrintDebug("Raising IRQ %d\n",  vnet_state->pci_dev->config_header.intr_line);
     }
@@ -320,8 +320,8 @@ static int do_tx_pkts(struct guest_info * core,
     }
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-           v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
-           vnet_state->virtio_cfg.pci_isr = 0x1;
+       v3_pci_raise_irq(vnet_state->pci_bus,  vnet_state->pci_dev, 0);
+       vnet_state->virtio_cfg.pci_isr = 0x1;
     }
        
     return 0;
@@ -525,7 +525,7 @@ static int vnet_virtio_io_read(struct guest_info * core,
        case VIRTIO_ISR_PORT:
            *(uint8_t *)dst = vnet_state->virtio_cfg.pci_isr;
            vnet_state->virtio_cfg.pci_isr = 0;
-           v3_pci_lower_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
+           v3_pci_lower_irq(vnet_state->pci_bus, vnet_state->pci_dev, 0);
            break;
 
        default:
@@ -623,7 +623,7 @@ static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
                                         0, 5 /*PCI_AUTO_DEV_NUM*/, 0,
                                         "LNX_VIRTIO_VNET", bars,
-                                        NULL, NULL, NULL, vnet_state);
+                                        NULL, NULL, NULL, NULL, vnet_state);
 
        if (!pci_dev) {
            PrintError("Could not register PCI Device\n");
index b4796f7..3c8fa06 100644 (file)
@@ -334,7 +334,7 @@ static int ne2k_update_irq(struct ne2k_state * nic_state) {
        if (pci_dev == NULL){
            v3_raise_virq(&(nic_state->vm->cores[0]), NE2K_DEFAULT_IRQ);
        } else {            
-           v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev);
+          v3_pci_raise_irq(nic_state->pci_bus, nic_state->pci_dev, 0);
        }
 
        nic_state->statistics.rx_interrupts ++;
@@ -1124,7 +1124,7 @@ static int register_dev(struct ne2k_state * nic_state)
 
        pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, 
                                         "NE2000", bars,
-                                        pci_config_update, NULL, NULL, nic_state);
+                                        pci_config_update, NULL, NULL, NULL, nic_state);
 
 
        if (pci_dev == NULL) {
index 05272a8..f9a2f9b 100644 (file)
 #include <devices/pci_types.h>
 
 #include <palacios/vm_guest.h>
+#include <palacios/vm_guest_mem.h>
 
 
+#include <devices/apic.h>
+
 
 #ifndef V3_CONFIG_DEBUG_PCI
 #undef PrintDebug
 // This must always be a multiple of 8
 #define MAX_BUS_DEVICES 32
 
+#define PCI_CAP_ID_MSI 0x05
+#define PCI_CAP_ID_MSIX 0x11
+
+
 struct pci_addr_reg {
     union {
        uint32_t val;
@@ -62,7 +69,8 @@ struct pci_addr_reg {
            uint_t fn_num     : 3;
            uint_t dev_num    : 5;
            uint_t bus_num    : 8;
-           uint_t rsvd2      : 7;
+           uint_t hi_reg_num : 4;
+           uint_t rsvd2      : 3;
            uint_t enable     : 1;
        } __attribute__((packed));
     } __attribute__((packed));
@@ -82,8 +90,8 @@ struct pci_bus {
     uint8_t dev_map[MAX_BUS_DEVICES / 8];
 
 
-    int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data);
-    int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data);
+    int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec);
+    int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec);
     void * irq_dev_data;
 };
 
@@ -102,6 +110,58 @@ struct pci_internal {
 
 
 
+struct cfg_range_hook {
+    uint32_t start;
+    uint32_t length;
+
+    int (*write)(struct pci_device * pci_dev, uint32_t offset, 
+                void * src, uint_t length, void * private_data);
+
+    int (*read)(struct pci_device * pci_dev, uint32_t offset, 
+               void * dst, uint_t length, void * private_data);
+
+    void * private_data;
+
+    struct list_head list_node;
+};
+
+
+
+struct pci_cap {
+    uint8_t id;
+    uint32_t offset;
+    uint8_t enabled;
+
+    struct list_head cap_node;
+};
+
+
+// These mark read only fields in the pci config header. 
+// If a bit is 1, then the field is writable in the header
+/* Notes: 
+ * BIST is disabled by default (All writes to it will be dropped 
+ * Cardbus CIS is disabled (All writes are dropped)
+ * Writes to capability pointer are disabled
+ */
+static uint8_t pci_hdr_write_mask_00[64] = { 0x00, 0x00, 0x00, 0x00, /* Device ID, Vendor ID */
+                                            0xbf, 0xff, 0x00, 0xf9, /* Command, status */
+                                            0x00, 0x00, 0x00, 0x00, /* Revision ID, Class code */
+                                            0x00, 0xff, 0x00, 0x00, /* CacheLine Size, Latency Timer, Header Type, BIST */
+                                            0xff, 0xff, 0xff, 0xff, /* BAR 0 */
+                                            0xff, 0xff, 0xff, 0xff, /* BAR 1 */
+                                            0xff, 0xff, 0xff, 0xff, /* BAR 2 */
+                                            0xff, 0xff, 0xff, 0xff, /* BAR 3 */
+                                            0xff, 0xff, 0xff, 0xff, /* BAR 4 */
+                                            0xff, 0xff, 0xff, 0xff, /* BAR 5 */
+                                            0x00, 0x00, 0x00, 0x00, /* CardBus CIS Ptr */
+                                            0xff, 0xff, 0xff, 0xff, /* SubSystem Vendor ID, SubSystem ID */
+                                            0xff, 0xff, 0xff, 0xff, /* ExpRom BAR */
+                                            0x00, 0x00, 0x00, 0x00, /* CAP ptr (0xfc to enable), RSVD */
+                                            0x00, 0x00, 0x00, 0x00, /* Reserved */
+                                            0xff, 0x00, 0x00, 0x00 /* INTR Line, INTR Pin, MIN_GNT, MAX_LAT */
+}; 
+
+
 
 
 #ifdef V3_CONFIG_DEBUG_PCI
@@ -225,181 +285,565 @@ static struct pci_device * get_device(struct pci_bus * bus, uint8_t dev_num, uin
 
 
 
+// There won't be many hooks at all, so unordered lists are acceptible for now 
+static struct cfg_range_hook * find_cfg_range_hook(struct pci_device * pci, uint32_t start, uint32_t length) {
+    uint32_t end = start + length - 1; // end is inclusive
+    struct cfg_range_hook * hook = NULL;
 
+    list_for_each_entry(hook, &(pci->cfg_hooks), list_node) {
+       uint32_t hook_end = hook->start + hook->length - 1;
+       if (!((hook->start > end) || (hook_end < start))) {
+           return hook;
+       }
+    }
+    
+    return NULL;
+}
 
 
-static int addr_port_read(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
-    struct pci_internal * pci_state = priv_data;
-    int reg_offset = port & 0x3;
-    uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
+int v3_pci_hook_config_range(struct pci_device * pci, 
+                            uint32_t start, uint32_t length, 
+                            int (*write)(struct pci_device * pci_dev, uint32_t offset, 
+                                                void * src, uint_t length, void * private_data), 
+                            int (*read)(struct pci_device * pci_dev, uint32_t offset, 
+                                               void * dst, uint_t length, void * private_data), 
+                            void * private_data) {
+    struct cfg_range_hook * hook = NULL;    
+    
 
-    PrintDebug("Reading PCI Address Port (%x): %x len=%d\n", port, pci_state->addr_reg.val, length);
+    if (find_cfg_range_hook(pci, start, length)) {
+       PrintError("Tried to hook an already hooked config region\n");
+       return -1;
+    }
+    
+    hook = V3_Malloc(sizeof(struct cfg_range_hook));
 
-    if (length == 4) {
-       if (reg_offset != 0) {
-           PrintError("Invalid Address Port Read\n");
-           return -1;
+    if (!hook) {
+       PrintError("Could not allocate range hook\n");
+       return -1;
+    }
+
+    memset(hook, 0, sizeof(struct cfg_range_hook));
+
+    hook->start = start;
+    hook->length = length;
+    hook->private_data = private_data;
+    hook->write = write;
+    hook->read = read;
+
+    list_add(&(hook->list_node), &(pci->cfg_hooks));
+
+    return 0;
+
+}
+
+
+
+
+// Note byte ordering: LSB -> MSB
+static uint8_t msi_32_rw_bitmask[10] = { 0x00, 0x00,                     /* ID, next ptr */
+                                        0x71, 0x00,                     /* MSG CTRL */
+                                        0xfc, 0xff, 0xff, 0xff,         /* MSG ADDR */
+                                        0xff, 0xff};                    /* MSG DATA */
+
+static uint8_t msi_64_rw_bitmask[14] = { 0x00, 0x00,                     /* ID, next ptr */
+                                        0x71, 0x00,                     /* MSG CTRL */
+                                        0xfc, 0xff, 0xff, 0xff,         /* MSG LO ADDR */
+                                        0xff, 0xff, 0xff, 0xff,         /* MSG HI ADDR */
+                                        0xff, 0xff};                    /* MSG DATA */
+
+static uint8_t msi_64pervect_rw_bitmask[24] = { 0x00, 0x00,              /* ID, next ptr */
+                                               0x71, 0x00,              /* MSG CTRL */
+                                               0xfc, 0xff, 0xff, 0xff,  /* MSG LO CTRL */
+                                               0xff, 0xff, 0xff, 0xff,  /* MSG HI ADDR */
+                                               0xff, 0xff,              /* MSG DATA */
+                                               0x00, 0x00,              /* RSVD */
+                                               0xff, 0xff, 0xff, 0xff,  
+                                               0x00, 0x00, 0x00, 0x00}; 
+
+static uint8_t msix_rw_bitmask[12] = { 0x00, 0x00,                       /* ID, next ptr */
+                                      0x00, 0x80, 
+                                      0xff, 0xff, 0xff, 0xff,
+                                      0x08, 0xff, 0xff, 0xff};
+
+
+/* I am completely guessing what the format is here. 
+   I only have version 1 of the PCIe spec and cannot download version 2 or 3 
+   without paying the PCI-SIG $3000 a year for membership. 
+   So this is just cobbled together from the version 1 spec and KVM. 
+*/ 
+
+
+static uint8_t pciev1_rw_bitmask[20] = { 0x00, 0x00, /* ID, next ptr */
+                                        0x00, 0x00, /* PCIE CAP register */
+                                        0x00, 0x00, 0x00, 0x00, /* DEV CAP */
+                                        0xff, 0xff, /* DEV CTRL */
+                                        0x0f, 0x00, /* DEV STATUS */
+                                        0x00, 0x00, 0x00, 0x00, /* LINK CAP */
+                                        0xfb, 0x01, /* LINK CTRL */
+                                        0x00, 0x00  /* LINK STATUS */ 
+};
+
+
+static uint8_t pciev2_rw_bitmask[60] = { 0x00, 0x00, /* ID, next ptr */
+                                        0x00, 0x00, /* PCIE CAP register */
+                                        0x00, 0x00, 0x00, 0x00, /* DEV CAP */
+                                        0xff, 0xff, /* DEV CTRL */
+                                        0x0f, 0x00, /* DEV STATUS */
+                                        0x00, 0x00, 0x00, 0x00, /* LINK CAP */
+                                        0xfb, 0x01, /* LINK CTRL */
+                                        0x00, 0x00, /* LINK STATUS */ 
+                                        0x00, 0x00, 0x00, 0x00, /* SLOT CAP ?? */
+                                        0x00, 0x00, /* SLOT CTRL ?? */
+                                        0x00, 0x00, /* SLOT STATUS */
+                                        0x00, 0x00, /* ROOT CTRL */
+                                        0x00, 0x00, /* ROOT CAP */
+                                        0x00, 0x00, 0x00, 0x00, /* ROOT STATUS */
+                                        0x00, 0x00, 0x00, 0x00, /* WHO THE FUCK KNOWS */
+                                        0x00, 0x00, 0x00, 0x00, 
+                                        0x00, 0x00, 0x00, 0x00, 
+                                        0x00, 0x00, 0x00, 0x00, 
+                                        0x00, 0x00, 0x00, 0x00 
+};
+
+static uint8_t pm_rw_bitmask[] = { 0x00, 0x00, /* ID, next ptr */
+                                  0x00, 0x00, /* PWR MGMT CAPS */
+                                  0x03, 0x9f, /* PWR MGMT CTRL */
+                                  0x00, 0x00  /* PMCSR_BSE, Data */
+};
+
+
+
+int cap_write(struct pci_device * pci, uint32_t offset, void * src, uint_t length, void * private_data) {
+    struct pci_cap * cap = private_data;
+    uint32_t cap_offset = cap->offset;
+    pci_cap_type_t cap_type = cap->id;
+
+    uint32_t write_offset = offset - cap_offset;
+    void * cap_ptr = &(pci->config_space[cap_offset + 2]);    
+    int i = 0;
+
+    int msi_was_enabled = 0;
+    int msix_was_enabled = 0;
+
+
+    V3_Print("CAP write trapped (val=%x, cfg_offset=%d, write_offset=%d)\n", *(uint32_t *)src, offset, write_offset);
+
+    if (cap_type == PCI_CAP_MSI) {
+       struct msi_msg_ctrl * msg_ctrl = cap_ptr;
+
+       if (msg_ctrl->msi_enable == 1) {
+           msi_was_enabled = 1;
        }
-       *(uint32_t *)dst = *(uint32_t *)reg_addr;
-    } else if (length == 2) {
-       if (reg_offset > 2) {
-           PrintError("Invalid Address Port Read\n");
+    } else if (cap_type == PCI_CAP_MSIX) {
+       struct msix_cap * msix_cap = cap_ptr;
+
+       if (msix_cap->msg_ctrl.msix_enable == 1) {
+           msix_was_enabled = 1;
+       }
+    }
+
+    for (i = 0; i < length; i++) {
+       uint8_t mask = 0;
+
+       if (cap_type == PCI_CAP_MSI) {
+           struct msi_msg_ctrl * msg_ctrl = cap_ptr;
+
+           V3_Print("MSI Cap Ctrl=%x\n", *(uint16_t *)pci->msi_cap);
+           V3_Print("MSI ADDR=%x\n", *(uint32_t *)(cap_ptr + 2));
+           V3_Print("MSI HI ADDR=%x\n", *(uint32_t *)(cap_ptr + 6));
+           V3_Print("MSI Data=%x\n", *(uint16_t *)(cap_ptr + 10));
+
+           if (msg_ctrl->cap_64bit) {
+               if (msg_ctrl->per_vect_mask) {
+                   mask = msi_64pervect_rw_bitmask[write_offset];
+               } else {
+                   mask = msi_64_rw_bitmask[write_offset];
+               }
+           } else {
+               mask = msi_32_rw_bitmask[write_offset];
+           }
+       } else if (cap_type == PCI_CAP_MSIX) {
+           mask = msix_rw_bitmask[write_offset];
+       } else if (cap_type == PCI_CAP_PCIE) {
+           struct pcie_cap_reg * pcie_cap = cap_ptr;
+
+           if (pcie_cap->version == 1) {
+               mask = pciev1_rw_bitmask[write_offset];
+           } else if (pcie_cap->version == 2) {
+               mask = pciev2_rw_bitmask[write_offset];
+           } else {
+               return 0;
+           }
+       } else if (cap_type == PCI_CAP_PM) {
+           mask = pm_rw_bitmask[write_offset];
+       }
+
+       pci->config_space[offset + i] &= ~mask;
+       pci->config_space[offset + i] |= ((*(uint8_t *)(src + i)) & mask);
+
+       write_offset++;
+    }
+
+
+    if (pci->cmd_update) {
+
+       /* Detect changes to interrupt types for cmd updates */
+       if (cap_type == PCI_CAP_MSI) {
+           struct msi_msg_ctrl * msg_ctrl = cap_ptr;
+           
+           V3_Print("msi_was_enabled=%d, msi_is_enabled=%d\n", msi_was_enabled,  msg_ctrl->msi_enable);
+
+           if ((msg_ctrl->msi_enable == 1) && (msi_was_enabled == 0)) {
+               pci->irq_type = IRQ_MSI;
+               pci->cmd_update(pci, PCI_CMD_MSI_ENABLE, msg_ctrl->mult_msg_enable, pci->priv_data);
+           } else if ((msg_ctrl->msi_enable == 0) && (msi_was_enabled == 1)) {
+               pci->irq_type = IRQ_NONE;
+               pci->cmd_update(pci, PCI_CMD_MSI_DISABLE, 0, pci->priv_data);
+           }
+       } else if (cap_type == PCI_CAP_MSIX) {
+           struct msix_cap * msix_cap = cap_ptr;
+
+           if ((msix_cap->msg_ctrl.msix_enable == 1) && (msix_was_enabled == 0)) {
+               pci->irq_type = IRQ_MSIX;
+               pci->cmd_update(pci, PCI_CMD_MSIX_ENABLE, msix_cap->msg_ctrl.table_size, pci->priv_data);
+           } else if ((msix_cap->msg_ctrl.msix_enable == 0) && (msix_was_enabled == 1)) {
+               pci->irq_type = IRQ_NONE;
+               pci->cmd_update(pci, PCI_CMD_MSIX_DISABLE, msix_cap->msg_ctrl.table_size, pci->priv_data);
+           }
+       }
+    }
+
+    return 0;
+}
+
+
+static int init_pci_cap(struct pci_device * pci, pci_cap_type_t cap_type, uint_t cap_offset) {
+    void * cap_ptr = &(pci->config_space[cap_offset + 2]);
+
+    if (cap_type == PCI_CAP_MSI) {
+       struct msi32_msg_addr * msi = cap_ptr;
+
+       // We only expose a basic 32 bit MSI interface
+       msi->msg_ctrl.msi_enable = 0;
+       msi->msg_ctrl.mult_msg_enable = 0;
+       msi->msg_ctrl.cap_64bit = 0;
+       msi->msg_ctrl.per_vect_mask = 0;
+       
+       msi->addr.val = 0; 
+       msi->data.val = 0;
+
+    } else if (cap_type == PCI_CAP_MSIX) {
+       
+       
+
+    } else if (cap_type == PCI_CAP_PCIE) {
+       struct pcie_cap_v2 * pcie = cap_ptr;
+       
+       // The v1 and v2 formats are identical for the first X bytes
+       // So we use the v2 struct, and only modify extended fields if v2 is detected
+       
+       pcie->dev_cap.fn_level_reset = 0;
+       
+       pcie->dev_ctrl.val &= 0x70e0; // only preserve max_payload_size and max_read_req_size untouched
+       pcie->dev_ctrl.relaxed_order_enable = 1;
+       pcie->dev_ctrl.no_snoop_enable = 1;
+
+       pcie->dev_status.val = 0;
+
+       pcie->link_cap.val &= 0x0003ffff;
+
+       pcie->link_status.val &= 0x03ff;
+       
+       if (pcie->pcie_cap.version >= 2) {
+           pcie->slot_cap = 0;
+           pcie->slot_ctrl = 0;
+           pcie->slot_status = 0;
+
+           pcie->root_ctrl = 0;
+           pcie->root_cap = 0;
+           pcie->root_status = 0;
+       }
+    } else if (cap_type == PCI_CAP_PM) {
+
+    }
+
+
+    return 0;
+}
+
+
+// enumerate all capabilities and disable them.
+static int scan_pci_caps(struct pci_device * pci) {
+    uint_t cap_offset = pci->config_header.cap_ptr;
+        
+    V3_Print("Scanning for Capabilities (cap_offset=%d)\n", cap_offset);
+
+    while (cap_offset != 0) {
+       uint8_t id = pci->config_space[cap_offset];
+       uint8_t next = pci->config_space[cap_offset + 1];
+
+       V3_Print("Found Capability 0x%x at offset %d (0x%x)\n", 
+                id, cap_offset, cap_offset);
+
+       struct pci_cap * cap = V3_Malloc(sizeof(struct pci_cap));
+
+       if (!cap) {
+           PrintError("Error allocating PCI CAP info\n");
            return -1;
        }
-       *(uint16_t *)dst = *(uint16_t *)reg_addr;
-    } else if (length == 1) {
-       *(uint8_t *)dst = *(uint8_t *)reg_addr;
-    } else {
-       PrintError("Invalid read length (%d) for PCI address register\n", length);
+       memset(cap, 0, sizeof(struct pci_cap));
+       
+       cap->id = id;
+       cap->offset = cap_offset;
+
+       list_add(&(cap->cap_node), &(pci->capabilities));
+
+       // set correct init values 
+       init_pci_cap(pci, id, cap_offset);
+
+
+       // set to the next pointer
+       cap_offset = next;
+    }
+
+    // Disable Capabilities
+    pci->config_header.cap_ptr = 0;
+
+    // Hook Cap pointer to return cached config space value
+    if (v3_pci_hook_config_range(pci, 0x34, 1, 
+                                NULL, NULL, NULL) == -1) {
+       PrintError("Could not hook cap pointer\n");
        return -1;
     }
     
 
-    return length;
+
+/*
+    // Disable all PCIE extended capabilities for now
+    pci->config_space[0x100] = 0;
+    pci->config_space[0x101] = 0;
+    pci->config_space[0x102] = 0;
+    pci->config_space[0x103] = 0;
+*/  
+
+
+    return 0;
+
 }
 
+int v3_pci_enable_capability(struct pci_device * pci, pci_cap_type_t cap_type) {
+    uint32_t size = 0;
+    struct pci_cap * tmp_cap = NULL;
+    struct pci_cap * cap = NULL;
+    void * cap_ptr = NULL;
 
-static int addr_port_write(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
-    struct pci_internal * pci_state = priv_data;
-    int reg_offset = port & 0x3; 
-    uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
+
+    list_for_each_entry(tmp_cap, &(pci->capabilities), cap_node) {
+       if (tmp_cap->id == cap_type) {
+           cap = tmp_cap;
+           break;
+       }
+    }
+
+    if ((cap == NULL) || (cap->enabled)) {
+       return -1;
+    }
 
 
-    if (length == 4) {
-       if (reg_offset != 0) {
-           PrintError("Invalid Address Port Write\n");
-           return -1;
+    V3_Print("Found Capability %x at %x (%d)\n", cap_type, cap->offset, cap->offset);
+
+    // found the capability
+
+    // mark it as enabled
+    cap->enabled = 1;
+
+    cap_ptr = &(pci->config_space[cap->offset + 2]);
+
+    if (cap_type == PCI_CAP_MSI) {
+       pci->msi_cap = cap_ptr;
+       
+       if (pci->msi_cap->cap_64bit) {
+           if (pci->msi_cap->per_vect_mask) {
+               // 64 bit MSI w/ per vector masking
+               size = 22;
+           } else {
+               // 64 bit MSI
+               size = 12;
+           }
+       } else {
+           // 32 bit MSI
+           size = 8;
        }
+    } else if (cap_type == PCI_CAP_MSIX) {
+       pci->msix_cap = cap_ptr;
+       
+       // disable passthrough for MSIX BAR
+
+       pci->bar[pci->msix_cap->bir].type = PCI_BAR_MEM32;
 
-       PrintDebug("Writing PCI 4 bytes Val=%x\n",  *(uint32_t *)src);
+       size = 10;
+    } else if (cap_type == PCI_CAP_PCIE) {
+       struct pcie_cap_reg * pcie_cap = (struct pcie_cap_reg *)&(pci->config_space[cap->offset + 2]);
 
-       *(uint32_t *)reg_addr = *(uint32_t *)src;
-    } else if (length == 2) {
-       if (reg_offset > 2) {
-           PrintError("Invalid Address Port Write\n");
+       if (pcie_cap->version == 1) {
+           size = 20;
+       } else if (pcie_cap->version == 2) {
+           size = 60;
+       } else {
            return -1;
        }
+    } else if (cap_type == PCI_CAP_PM) {
+       size = 8;
+    }
 
-       PrintDebug("Writing PCI 2 byte Val=%x\n",  *(uint16_t *)src);
 
-       *(uint16_t *)reg_addr = *(uint16_t *)src;
-    } else if (length == 1) {
-       PrintDebug("Writing PCI 1 byte Val=%x\n",  *(uint8_t *)src);
-       *(uint8_t *)reg_addr = *(uint8_t *)src;
-    } else {
-       PrintError("Invalid write length (%d) for PCI address register\n", length);
+    V3_Print("Hooking capability range (offset=%d, size=%d)\n", cap->offset, size);
+
+    if (v3_pci_hook_config_range(pci, cap->offset, size + 2, 
+                                cap_write, NULL, cap) == -1) {
+       PrintError("Could not hook config range (start=%d, size=%d)\n", 
+                  cap->offset + 2, size);
        return -1;
     }
 
-    PrintDebug("Writing PCI Address Port(%x): %x\n", port, pci_state->addr_reg.val);
+
+
+    // link it to the active capabilities list
+    pci->config_space[cap->offset + 1] = pci->config_header.cap_ptr;
+    pci->config_header.cap_ptr = cap->offset; // add to the head of the list
+
+    return 0;
+}
+
+
+
+
+static int addr_port_read(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
+    struct pci_internal * pci_state = priv_data;
+    int reg_offset = port & 0x3;
+    uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
+
+    PrintDebug("Reading PCI Address Port (%x): %x len=%d\n", port, pci_state->addr_reg.val, length);
+
+    if (reg_offset + length > 4) {
+       PrintError("Invalid Address port write\n");
+       return -1;
+    }
+
+    memcpy(dst, reg_addr, length);    
 
     return length;
 }
 
 
-static int data_port_read(struct guest_info * core, ushort_t port, void * dst, uint_t length, void * priv_data) {
+static int addr_port_write(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
+    struct pci_internal * pci_state = priv_data;
+    int reg_offset = port & 0x3; 
+    uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
+
+    if (reg_offset + length > 4) {
+       PrintError("Invalid Address port write\n");
+       return -1;
+    }
+
+    // Set address register
+    memcpy(reg_addr, src, length);
+
+    PrintDebug("Writing PCI Address Port(%x): AddrReg=%x (op_val = %x, len=%d) \n", port, pci_state->addr_reg.val, *(uint32_t *)src, length);
+
+    return length;
+}
+
+
+static int data_port_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data) {
     struct pci_internal * pci_state =  priv_data;
     struct pci_device * pci_dev = NULL;
-    uint_t reg_num = (pci_state->addr_reg.reg_num << 2) + (port & 0x3);
-    int i;
+    uint_t reg_num =  (pci_state->addr_reg.hi_reg_num << 16) +(pci_state->addr_reg.reg_num << 2) + (port & 0x3);
+    int i = 0;
+    int bytes_left = length;
 
     if (pci_state->addr_reg.bus_num != 0) {
-       int i = 0;
-       for (i = 0; i < length; i++) {
-           *((uint8_t *)dst + i) = 0xff;
-       }
-
+       memset(dst, 0xff, length);
        return length;
     }
 
-    PrintDebug("Reading PCI Data register. bus = %d, dev = %d, reg = %d (%x), cfg_reg = %x\n", 
+
+    pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num, pci_state->addr_reg.fn_num);
+    
+    if (pci_dev == NULL) {
+       memset(dst, 0xff, length);
+       return length;
+    } 
+
+    PrintDebug("Reading PCI Data register. bus = %d, dev = %d, fn = %d, reg = %d (%x), cfg_reg = %x\n", 
               pci_state->addr_reg.bus_num, 
               pci_state->addr_reg.dev_num, 
+              pci_state->addr_reg.fn_num,
               reg_num, reg_num, 
               pci_state->addr_reg.val);
 
-    pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num, pci_state->addr_reg.fn_num);
-    
-    if (pci_dev == NULL) {
-       for (i = 0; i < length; i++) {
-           *(uint8_t *)((uint8_t *)dst + i) = 0xff;
-       }
 
-       return length;
-    }
+    while (bytes_left > 0) {
+       struct cfg_range_hook * cfg_hook  = find_cfg_range_hook(pci_dev, reg_num + i, 1);
+       void * cfg_dst =  &(pci_dev->config_space[reg_num + i]);
 
-    if (pci_dev->type == PCI_PASSTHROUGH) {
-       if (pci_dev->config_read(reg_num, dst, length, pci_dev->priv_data) == -1) {
-           PrintError("Failed to handle configuration update for passthrough pci_device\n");
-           return -1;
-       }
-       
-       return 0;
-    }
+       if (cfg_hook) {
+           uint_t range_len = cfg_hook->length - ((reg_num + i) - cfg_hook->start);
+           range_len = (range_len > bytes_left) ? bytes_left : range_len;
 
-    for (i = 0; i < length; i++) {
-       *(uint8_t *)((uint8_t *)dst + i) = pci_dev->config_space[reg_num + i];
-    }
+           if (cfg_hook->read) {
+               cfg_hook->read(pci_dev, reg_num + i, cfg_dst, range_len, cfg_hook->private_data);
+           }
+           
+           bytes_left -= range_len;
+           i += range_len;
+       } else {
+           if (pci_dev->config_read) {
+               if (pci_dev->config_read(pci_dev, reg_num + i, cfg_dst, 1, pci_dev->priv_data) != 0) {
+                   PrintError("Error in config_read from PCI device (%s)\n", pci_dev->name);
+               }
+           }
 
+           bytes_left--;
+           i++;
+       } 
+    }      
+
+    memcpy(dst, &(pci_dev->config_space[reg_num]), length);
+           
     PrintDebug("\tVal=%x, len=%d\n", *(uint32_t *)dst, length);
 
     return length;
 }
 
 
-static inline int is_cfg_reg_writable(uchar_t header_type, int reg_num) {
-    if (header_type == 0x00) {
-       switch (reg_num) {
-           case 0x00:
-           case 0x01:
-           case 0x02:
-           case 0x03:
-           case 0x08:
-           case 0x09:
-           case 0x0a:
-           case 0x0b:
-           case 0x0e:
-           case 0x3d:
-               return 0;
-                           
-           default:
-               return 1;
-       }
-    } else if (header_type == 0x80) {
-       switch (reg_num) {
-           case 0x00:
-           case 0x01:
-           case 0x02:
-           case 0x03:
-           case 0x08:
-           case 0x09:
-           case 0x0a:
-           case 0x0b:
-           case 0x0e:
-           case 0x3d:
-               return 0;
-                           
-           default:
-               return 1;
-       }
-    } else {
-       // PCI to PCI Bridge = 0x01
-       // CardBus Bridge = 0x02
 
-       // huh?
-       PrintError("Invalid PCI Header type (0x%.2x)\n", header_type);
+static int bar_update(struct pci_device * pci_dev, uint32_t offset, 
+                     void * src, uint_t length, void * private_data) {
+    struct v3_pci_bar * bar = (struct v3_pci_bar *)private_data;
+    int bar_offset = offset & ~0x03;
+    int bar_num = (bar_offset - 0x10) / 4;
+    uint32_t new_val = *(uint32_t *)src;
+    
+    PrintDebug("Updating BAR Register  (Dev=%s) (bar=%d) (old_val=0x%x) (new_val=0x%x)\n", 
+              pci_dev->name, bar_num, bar->val, new_val);
 
-       return -1;
-    }
-}
+    // Cache the changes locally
+    memcpy(&(pci_dev->config_space[offset]), src, length);
 
-static int bar_update(struct guest_info * info, struct pci_device * pci, int bar_num, uint32_t new_val) {
-    struct v3_pci_bar * bar = &(pci->bar[bar_num]);
+    if (bar->type == PCI_BAR_PASSTHROUGH) {
+        if (bar->bar_write(bar_num, (void *)(pci_dev->config_space + bar_offset), bar->private_data) == -1) {
+           PrintError("Error in Passthrough bar write operation\n");
+           return -1;
+       }
+       
+       return 0;
+    }
+   
+    // Else we are a virtualized BAR
 
-    PrintDebug("Updating BAR Register  (Dev=%s) (bar=%d) (old_val=0x%x) (new_val=0x%x)\n", 
-              pci->name, bar_num, bar->val, new_val);
+    *(uint32_t *)(pci_dev->config_space + offset) &= bar->mask;
 
     switch (bar->type) {
        case PCI_BAR_IO: {
@@ -410,7 +854,7 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar
                       bar->num_ports);
                
            // only do this if pci device is enabled....
-           if (!(pci->config_header.status & 0x1)) {
+           if (!(pci_dev->config_header.status & 0x1)) {
                PrintError("PCI Device IO space not enabled\n");
            }
 
@@ -419,15 +863,15 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar
                PrintDebug("Rehooking PCI IO port (old port=%u) (new port=%u)\n",  
                           PCI_IO_BASE(bar->val) + i, PCI_IO_BASE(new_val) + i);
 
-               v3_unhook_io_port(info->vm_info, PCI_IO_BASE(bar->val) + i);
+               v3_unhook_io_port(pci_dev->vm, PCI_IO_BASE(bar->val) + i);
 
-               if (v3_hook_io_port(info->vm_info, PCI_IO_BASE(new_val) + i, 
+               if (v3_hook_io_port(pci_dev->vm, PCI_IO_BASE(new_val) + i, 
                                    bar->io_read, bar->io_write, 
                                    bar->private_data) == -1) {
 
                    PrintError("Could not hook PCI IO port (old port=%u) (new port=%u)\n",  
                               PCI_IO_BASE(bar->val) + i, PCI_IO_BASE(new_val) + i);
-                   v3_print_io_map(info->vm_info);
+                   v3_print_io_map(pci_dev->vm);
                    return -1;
                }
            }
@@ -437,12 +881,12 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar
            break;
        }
        case PCI_BAR_MEM32: {
-           v3_unhook_mem(info->vm_info, V3_MEM_CORE_ANY, (addr_t)(bar->val));
+           v3_unhook_mem(pci_dev->vm, V3_MEM_CORE_ANY, (addr_t)(bar->val));
            
            if (bar->mem_read) {
-               v3_hook_full_mem(info->vm_info, V3_MEM_CORE_ANY, PCI_MEM32_BASE(new_val), 
+               v3_hook_full_mem(pci_dev->vm, V3_MEM_CORE_ANY, PCI_MEM32_BASE(new_val), 
                                 PCI_MEM32_BASE(new_val) + (bar->num_pages * PAGE_SIZE_4KB),
-                                bar->mem_read, bar->mem_write, pci->priv_data);
+                                bar->mem_read, bar->mem_write, pci_dev->priv_data);
            } else {
                PrintError("Write hooks not supported for PCI\n");
                return -1;
@@ -454,7 +898,7 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar
        }
        case PCI_BAR_NONE: {
            PrintDebug("Reprogramming an unsupported BAR register (Dev=%s) (bar=%d) (val=%x)\n", 
-                      pci->name, bar_num, new_val);
+                      pci_dev->name, bar_num, new_val);
            break;
        }
        default:
@@ -466,12 +910,12 @@ static int bar_update(struct guest_info * info, struct pci_device * pci, int bar
 }
 
 
-static int data_port_write(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
+static int data_port_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data) {
     struct pci_internal * pci_state = priv_data;
     struct pci_device * pci_dev = NULL;
-    uint_t reg_num = (pci_state->addr_reg.reg_num << 2) + (port & 0x3);
-    int i;
-
+    uint_t reg_num = (pci_state->addr_reg.hi_reg_num << 16) +(pci_state->addr_reg.reg_num << 2) + (port & 0x3);
+    int i = 0;
+    int ret = length;
 
     if (pci_state->addr_reg.bus_num != 0) {
        return length;
@@ -493,110 +937,107 @@ static int data_port_write(struct guest_info * core, ushort_t port, void * src,
                   pci_state->addr_reg.dev_num); 
        return -1;
     }
-    
-    if (pci_dev->type == PCI_PASSTHROUGH) {
-       if (pci_dev->config_write(reg_num, src, length, pci_dev->priv_data) == -1) {
-           PrintError("Failed to handle configuration update for passthrough pci_device\n");
-           return -1;
-       }
-       
-       return 0;
-    }
 
+    /* update the config space
+       If a hook has been registered for a given region, call the hook with the max write length
+    */ 
+    while (length > 0) {
+       struct cfg_range_hook * cfg_hook  = find_cfg_range_hook(pci_dev, reg_num + i, 1);
 
-    for (i = 0; i < length; i++) {
-       uint_t cur_reg = reg_num + i;
-       int writable = is_cfg_reg_writable(pci_dev->config_header.header_type, cur_reg);
-       
-       if (writable == -1) {
-           PrintError("Invalid PCI configuration space\n");
-           return -1;
-       }
-
-       if (writable) {
-           pci_dev->config_space[cur_reg] = *(uint8_t *)((uint8_t *)src + i);
+       if (cfg_hook) {
+           uint_t range_len = cfg_hook->length - ((reg_num + i) - cfg_hook->start);
+           range_len = (range_len > length) ? length : range_len;
+           
+           if (cfg_hook->write) {
+               cfg_hook->write(pci_dev, reg_num + i, (void *)(src + i), range_len, cfg_hook->private_data);
+           }
 
-           if ((cur_reg >= 0x10) && (cur_reg < 0x28)) {
-               // BAR Register Update
-               int bar_reg = ((cur_reg & ~0x3) - 0x10) / 4;
-               
-               pci_dev->bar_update_flag = 1;
-               pci_dev->bar[bar_reg].updated = 1;
-               
-               // PrintDebug("Updating BAR register %d\n", bar_reg);
+           length -= range_len;
+           i += range_len;
+       } else {
+           // send the writes to the cached config space, and to the generic callback if present
+           uint8_t mask = 0xff;
 
-           } else if ((cur_reg >= 0x30) && (cur_reg < 0x34)) {
-               // Extension ROM update
+           if (reg_num < 64) {
+               mask = pci_hdr_write_mask_00[reg_num + i];
+           }
+           
+           if (mask != 0) {
+               uint8_t new_val = *(uint8_t *)(src + i);
+               uint8_t old_val = pci_dev->config_space[reg_num + i];
 
-               pci_dev->exp_rom_update_flag = 1;
-           } else if (cur_reg == 0x04) {
-               // COMMAND update            
-               uint8_t command = *((uint8_t *)src + i);
+               pci_dev->config_space[reg_num + i] = ((new_val & mask) | (old_val & ~mask));
                
-               PrintError("command update for %s old=%x new=%x\n",
-                          pci_dev->name, 
-                          pci_dev->config_space[cur_reg],command);
-
-               pci_dev->config_space[cur_reg] = command;             
-
-               if (pci_dev->cmd_update) {
-                   pci_dev->cmd_update(pci_dev, (command & 0x01), (command & 0x02));
+               if (pci_dev->config_write) {
+                   pci_dev->config_write(pci_dev, reg_num + i, &(pci_dev->config_space[reg_num + i]), 1, pci_dev->priv_data);
                }
-               
-           } else if (cur_reg == 0x0f) {
-               // BIST update
-               pci_dev->config_header.BIST = 0x00;
-           }
-       } else {
-           PrintError("PCI Write to read only register %d\n", cur_reg);
+           }       
+
+           length--;
+           i++;
        }
     }
 
-    if (pci_dev->config_update) {
-       pci_dev->config_update(reg_num, src, length, pci_dev->priv_data);
+    return ret;
+}
+
+
+
+static int exp_rom_write(struct pci_device * pci_dev, uint32_t offset, 
+                        void * src, uint_t length, void * private_data) {
+    int bar_offset = offset & ~0x03;
+
+    if (pci_dev->exp_rom_update) {
+       pci_dev->exp_rom_update(pci_dev, (void *)(pci_dev->config_space + bar_offset), pci_dev->priv_data);
+       
+       return 0;
     }
 
-    // Scan for BAR updated
-    if (pci_dev->bar_update_flag) {
-       for (i = 0; i < 6; i++) {
-           if (pci_dev->bar[i].updated) {
-               int bar_offset = 0x10 + 4 * i;
+    PrintError("Expansion ROM update not handled. Will appear to not Exist\n");
 
+    return 0;
+}
 
-               if (pci_dev->bar[i].type == PCI_BAR_PASSTHROUGH) {
-                   if (pci_dev->bar[i].bar_write(i, (uint32_t *)(pci_dev->config_space + bar_offset), pci_dev->bar[i].private_data) == -1) {
-                       PrintError("Error in passthrough bar write operation\n");
-                       return -1;
-                   }
-               } else {
 
-                   *(uint32_t *)(pci_dev->config_space + bar_offset) &= pci_dev->bar[i].mask;
-                   // check special flags....
+static int cmd_write(struct pci_device * pci_dev, uint32_t offset, 
+                    void * src, uint_t length, void * private_data) {
 
-                   // bar_update
-                   if (bar_update(core, pci_dev, i, *(uint32_t *)(pci_dev->config_space + bar_offset)) == -1) {
-                       PrintError("PCI Device %s: Bar update Error Bar=%d\n", pci_dev->name, i);
-                       return -1;
-                   }
-               }
+    int i = 0;
 
-               pci_dev->bar[i].updated = 0;
-           }
-       }
-       pci_dev->bar_update_flag = 0;
-    }
+    struct pci_cmd_reg old_cmd;
+    struct pci_cmd_reg new_cmd;
+    old_cmd.val = pci_dev->config_header.command;
+
+    for (i = 0; i < length; i++) {
+        uint8_t mask = pci_hdr_write_mask_00[offset + i];
+       uint8_t new_val = *(uint8_t *)(src + i);
+       uint8_t old_val = pci_dev->config_space[offset + i];
 
-    if ((pci_dev->exp_rom_update_flag) && (pci_dev->exp_rom_update)) {
-       pci_dev->exp_rom_update(pci_dev, &(pci_dev->config_header.expansion_rom_address), pci_dev->priv_data);
-       pci_dev->exp_rom_update_flag = 0;
+       pci_dev->config_space[offset + i] = ((new_val & mask) | (old_val & ~mask));
     }
 
+    new_cmd.val = pci_dev->config_header.command;
 
-    return length;
-}
+
+    if (pci_dev->cmd_update) {
+       if ((new_cmd.intx_disable == 1) && (old_cmd.intx_disable == 0)) {
+           pci_dev->irq_type = IRQ_NONE;
+           pci_dev->cmd_update(pci_dev, PCI_CMD_INTX_DISABLE, 0, pci_dev->priv_data);
+       } else if ((new_cmd.intx_disable == 0) && (old_cmd.intx_disable == 1)) {
+           pci_dev->irq_type = IRQ_INTX;
+           pci_dev->cmd_update(pci_dev, PCI_CMD_INTX_ENABLE, 0, pci_dev->priv_data);
+       }
 
 
+       if ((new_cmd.dma_enable == 1) && (old_cmd.dma_enable == 0)) {
+           pci_dev->cmd_update(pci_dev, PCI_CMD_DMA_ENABLE, 0, pci_dev->priv_data);
+       } else if ((new_cmd.dma_enable == 0) && (old_cmd.dma_enable == 1)) {
+           pci_dev->cmd_update(pci_dev, PCI_CMD_DMA_DISABLE, 0, pci_dev->priv_data);
+       }
+    }
 
+    return 0;
+}
 
 
 static void init_pci_busses(struct pci_internal * pci_state) {
@@ -625,6 +1066,27 @@ static int pci_free(struct pci_internal * pci_state) {
            node = v3_rb_next(node);
            
            v3_rb_erase(&(dev->dev_tree_node), &(bus->devices));
+           
+           // Free config range hooks
+           { 
+               struct cfg_range_hook * hook = NULL;
+               struct cfg_range_hook * tmp = NULL;
+               list_for_each_entry_safe(hook, tmp, &(dev->cfg_hooks), list_node) {
+                   list_del(&(hook->list_node));
+                   V3_Free(hook);
+               }
+           }
+
+           // Free caps
+           {
+               struct pci_cap * cap = NULL;
+               struct pci_cap * tmp = NULL;
+               list_for_each_entry_safe(cap, tmp, &(dev->cfg_hooks), cap_node) {
+                   list_del(&(cap->cap_node));
+                   V3_Free(cap);
+               }
+           }
+
            V3_Free(dev);
        }
 
@@ -785,82 +1247,85 @@ static inline int init_bars(struct v3_vm_info * vm, struct pci_device * pci_dev)
 
     for (i = 0; i < 6; i++) {
        int bar_offset = 0x10 + (4 * i);
+       struct v3_pci_bar * bar = &(pci_dev->bar[i]);
 
-       if (pci_dev->bar[i].type == PCI_BAR_IO) {
+       if (bar->type == PCI_BAR_IO) {
            int j = 0;
-           pci_dev->bar[i].mask = (~((pci_dev->bar[i].num_ports) - 1)) | 0x01;
+           bar->mask = (~((bar->num_ports) - 1)) | 0x01;
 
-           if (pci_dev->bar[i].default_base_port != 0xffff) {
-               pci_dev->bar[i].val = pci_dev->bar[i].default_base_port & pci_dev->bar[i].mask;
+           if (bar->default_base_port != 0xffff) {
+               bar->val = bar->default_base_port & bar->mask;
            } else {
-               pci_dev->bar[i].val = 0;
+               bar->val = 0;
            }
 
-           pci_dev->bar[i].val |= 0x00000001;
+           bar->val |= 0x00000001;
 
-           for (j = 0; j < pci_dev->bar[i].num_ports; j++) {
+           for (j = 0; j < bar->num_ports; j++) {
                // hook IO
-               if (pci_dev->bar[i].default_base_port != 0xffff) {
-                   if (v3_hook_io_port(vm, pci_dev->bar[i].default_base_port + j,
-                                       pci_dev->bar[i].io_read, pci_dev->bar[i].io_write, 
-                                       pci_dev->bar[i].private_data) == -1) {
-                       PrintError("Could not hook default io port %x\n", pci_dev->bar[i].default_base_port + j);
+               if (bar->default_base_port != 0xffff) {
+                   if (v3_hook_io_port(vm, bar->default_base_port + j,
+                                       bar->io_read, bar->io_write, 
+                                       bar->private_data) == -1) {
+                       PrintError("Could not hook default io port %x\n", bar->default_base_port + j);
                        return -1;
                    }
                }
            }
 
-           *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val;
+           *(uint32_t *)(pci_dev->config_space + bar_offset) = bar->val;
 
-       } else if (pci_dev->bar[i].type == PCI_BAR_MEM32) {
-           pci_dev->bar[i].mask = ~((pci_dev->bar[i].num_pages << 12) - 1);
-           pci_dev->bar[i].mask |= 0xf; // preserve the configuration flags
+       } else if (bar->type == PCI_BAR_MEM32) {
+           bar->mask = ~((bar->num_pages << 12) - 1);
+           bar->mask |= 0xf; // preserve the configuration flags
 
-           if (pci_dev->bar[i].default_base_addr != 0xffffffff) {
-               pci_dev->bar[i].val = pci_dev->bar[i].default_base_addr & pci_dev->bar[i].mask;
+           if (bar->default_base_addr != 0xffffffff) {
+               bar->val = bar->default_base_addr & bar->mask;
            } else {
-               pci_dev->bar[i].val = 0;
+               bar->val = 0;
            }
 
            // hook memory
-           if (pci_dev->bar[i].mem_read) {
+           if (bar->mem_read) {
                // full hook
-               v3_hook_full_mem(vm, V3_MEM_CORE_ANY, pci_dev->bar[i].default_base_addr,
-                                pci_dev->bar[i].default_base_addr + (pci_dev->bar[i].num_pages * PAGE_SIZE_4KB),
-                                pci_dev->bar[i].mem_read, pci_dev->bar[i].mem_write, pci_dev->priv_data);
-           } else if (pci_dev->bar[i].mem_write) {
+               v3_hook_full_mem(vm, V3_MEM_CORE_ANY, bar->default_base_addr,
+                                bar->default_base_addr + (bar->num_pages * PAGE_SIZE_4KB),
+                                bar->mem_read, bar->mem_write, pci_dev->priv_data);
+           } else if (bar->mem_write) {
                // write hook
                PrintError("Write hooks not supported for PCI devices\n");
                return -1;
                /*
-                 v3_hook_write_mem(pci_dev->vm_dev->vm, pci_dev->bar[i].default_base_addr, 
-                 pci_dev->bar[i].default_base_addr + (pci_dev->bar[i].num_pages * PAGE_SIZE_4KB),
-                 pci_dev->bar[i].mem_write, pci_dev->vm_dev);
+                 v3_hook_write_mem(pci_dev->vm_dev->vm, bar->default_base_addr, 
+                 bar->default_base_addr + (bar->num_pages * PAGE_SIZE_4KB),
+                 bar->mem_write, pci_dev->vm_dev);
                */
            } else {
                // set the prefetchable flag...
-               pci_dev->bar[i].val |= 0x00000008;
+               bar->val |= 0x00000008;
            }
 
 
-           *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val;
+           *(uint32_t *)(pci_dev->config_space + bar_offset) = bar->val;
 
-       } else if (pci_dev->bar[i].type == PCI_BAR_MEM24) {
+       } else if (bar->type == PCI_BAR_MEM24) {
            PrintError("16 Bit memory ranges not supported (reg: %d)\n", i);
            return -1;
-       } else if (pci_dev->bar[i].type == PCI_BAR_NONE) {
-           pci_dev->bar[i].val = 0x00000000;
-           pci_dev->bar[i].mask = 0x00000000; // This ensures that all updates will be dropped
-           *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val;
-       } else if (pci_dev->bar[i].type == PCI_BAR_PASSTHROUGH) {
+       } else if (bar->type == PCI_BAR_NONE) {
+           bar->val = 0x00000000;
+           bar->mask = 0x00000000; // This ensures that all updates will be dropped
+           *(uint32_t *)(pci_dev->config_space + bar_offset) = bar->val;
+       } else if (bar->type == PCI_BAR_PASSTHROUGH) {
 
            // Call the bar init function to get the local cached value
-           pci_dev->bar[i].bar_init(i, &(pci_dev->bar[i].val), pci_dev->bar[i].private_data);
+           bar->bar_init(i, &(bar->val), bar->private_data);
 
        } else {
            PrintError("Invalid BAR type for bar #%d\n", i);
            return -1;
        }
+
+       v3_pci_hook_config_range(pci_dev, bar_offset, 4, bar_update, NULL, bar);
     }
 
     return 0;
@@ -868,8 +1333,8 @@ static inline int init_bars(struct v3_vm_info * vm, struct pci_device * pci_dev)
 
 
 int v3_pci_set_irq_bridge(struct  vm_device * pci_bus, int bus_num, 
-                         int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data),
-                         int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data),
+                         int (*raise_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec),
+                         int (*lower_pci_irq)(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec),
                          void * priv_data) {
     struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
 
@@ -881,20 +1346,129 @@ int v3_pci_set_irq_bridge(struct  vm_device * pci_bus, int bus_num,
     return 0;
 }
 
-int v3_pci_raise_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev) {
-   struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
-   struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
+int v3_pci_raise_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index) {
+   struct v3_irq vec;
 
-   return bus->raise_pci_irq(dev, bus->irq_dev_data);
+   vec.ack = NULL;
+   vec.private_data = NULL;
+   vec.irq = vec_index;
+
+   return v3_pci_raise_acked_irq(pci_bus, dev, vec);
 }
 
-int v3_pci_lower_irq(struct vm_device * pci_bus, int bus_num, struct pci_device * dev) {
+int v3_pci_lower_irq(struct vm_device * pci_bus, struct pci_device * dev, uint32_t vec_index) {
+    struct v3_irq vec;
+
+    vec.irq = vec_index;
+    vec.ack = NULL;
+    vec.private_data = NULL;
+    
+    return v3_pci_lower_acked_irq(pci_bus, dev, vec);
+}
+
+int v3_pci_raise_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec) {
    struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
-   struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
+   struct pci_bus * bus = &(pci_state->bus_list[dev->bus_num]);
+
+
+   if (dev->irq_type == IRQ_INTX) {
+       return bus->raise_pci_irq(dev, bus->irq_dev_data, &vec);
+   } else if (dev->irq_type == IRQ_MSI) {
+       struct v3_gen_ipi ipi;
+       struct msi_addr * addr = NULL;
+       struct msi_data * data = NULL;       
+       
+       if (dev->msi_cap->cap_64bit) {
+          if (dev->msi_cap->per_vect_mask) {
+              struct msi64_pervec_msg_addr * msi = (void *)dev->msi_cap;
+              addr = &(msi->addr);
+              data = &(msi->data);
+          } else {
+              struct msi64_msg_addr * msi = (void *)dev->msi_cap;
+              addr = &(msi->addr);
+              data = &(msi->data);
+          }
+       } else {
+          struct msi32_msg_addr * msi = (void *)dev->msi_cap;
+          addr = &(msi->addr);
+          data = &(msi->data);
+       }
+
+       memset(&ipi, 0, sizeof(struct v3_gen_ipi));
+
+       // decode MSI fields into IPI
+
+       ipi.vector = data->vector + vec.irq;
+       ipi.mode = data->del_mode;
+       ipi.logical = addr->dst_mode;
+       ipi.trigger_mode = data->trig_mode;
+       ipi.dst_shorthand = 0;
+       ipi.dst = addr->dst_id;
+       
+
+       v3_apic_send_ipi(dev->vm, &ipi, dev->apic_dev);
+
+       return 0;       
+   } else if (dev->irq_type == IRQ_MSIX) {
+       addr_t msix_table_gpa = 0;
+       struct msix_table * msix_table = NULL;
+       uint_t bar_idx = dev->msix_cap->bir;
+       struct v3_gen_ipi ipi;
+       struct msi_addr * addr = NULL;
+       struct msi_data * data = NULL;   
+       
+       if (dev->bar[bar_idx].type != PCI_BAR_MEM32) {
+          PrintError("Non 32bit MSIX BAR registers are not supported\n");
+          return -1;
+       }
+
+       msix_table_gpa = dev->bar[bar_idx].val;
+       msix_table_gpa += dev->msix_cap->table_offset;
+
+       if (v3_gpa_to_hva(&(dev->vm->cores[0]), msix_table_gpa, (void *)&(msix_table)) != 0) {
+          PrintError("Could not translate MSIX Table GPA (%p)\n", (void *)msix_table_gpa);
+          return -1;
+       }
+       
+       memset(&ipi, 0, sizeof(struct v3_gen_ipi));
+
+       data = &(msix_table->entries[vec.irq].data);
+       addr = &(msix_table->entries[vec.irq].addr);;
+       
+       // decode MSIX fields into IPI
+       ipi.vector = data->vector + vec.irq;
+       ipi.mode = data->del_mode;
+       ipi.logical = addr->dst_mode;
+       ipi.trigger_mode = data->trig_mode;
+       ipi.dst_shorthand = 0;
+       ipi.dst = addr->dst_id;
+       
+
+
+       V3_Print("Decode MSIX\n");
+
+       v3_apic_send_ipi(dev->vm, &ipi, dev->apic_dev);
+
+       return 0;
+   } 
+   
+   // Should never get here
+   return -1;
 
-   return bus->lower_pci_irq(dev, bus->irq_dev_data);
 }
 
+int v3_pci_lower_acked_irq(struct vm_device * pci_bus, struct pci_device * dev, struct v3_irq vec) {
+    if (dev->irq_type == IRQ_INTX) {
+       struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
+       struct pci_bus * bus = &(pci_state->bus_list[dev->bus_num]);
+       
+       return bus->lower_pci_irq(dev, bus->irq_dev_data, &vec);
+    } else {
+       return -1;
+    }
+}
+
+
 // if dev_num == -1, auto assign 
 struct pci_device * v3_pci_register_device(struct vm_device * pci,
                                           pci_device_type_t dev_type, 
@@ -903,8 +1477,11 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci,
                                           int fn_num,
                                           const char * name,
                                           struct v3_pci_bar * bars,
-                                          int (*config_update)(uint_t reg_num, void * src, uint_t length, void * priv_data),
-                                          int (*cmd_update)(struct pci_device * pci_dev, uchar_t io_enabled, uchar_t mem_enabled),
+                                          int (*config_write)(struct pci_device * pci_dev, uint32_t reg_num, void * src, 
+                                                              uint_t length, void * priv_data),
+                                          int (*config_read)(struct pci_device * pci_dev, uint32_t reg_num, void * dst, 
+                                                             uint_t length, void * priv_data),
+                                          int (*cmd_update)(struct pci_device * pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data),
                                           int (*exp_rom_update)(struct pci_device * pci_dev, uint32_t * src, void * priv_data),
                                           void * priv_data) {
 
@@ -966,14 +1543,53 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci,
     pci_dev->fn_num = fn_num;
 
     strncpy(pci_dev->name, name, sizeof(pci_dev->name));
+    pci_dev->vm = pci->vm;
     pci_dev->priv_data = priv_data;
 
+    INIT_LIST_HEAD(&(pci_dev->cfg_hooks));
+    INIT_LIST_HEAD(&(pci_dev->capabilities));
+
+    
+    {
+       // locate APIC for MSI/MSI-X
+       pci_dev->apic_dev = v3_find_dev(pci->vm, "apic");
+    }
+
     // register update callbacks
-    pci_dev->config_update = config_update;
+    pci_dev->config_write = config_write;
+    pci_dev->config_read = config_read;
     pci_dev->cmd_update = cmd_update;
     pci_dev->exp_rom_update = exp_rom_update;
 
 
+
+    if (config_read) {
+       int i = 0;
+
+       // Only 256 bytes for now, should expand it in the future
+       for (i = 0; i < 256; i++) {
+           config_read(pci_dev, i, &(pci_dev->config_space[i]), 1, pci_dev->priv_data);
+       }
+    }
+
+    V3_Print("Scanning for Capabilities\n");
+
+    // scan for caps
+    scan_pci_caps(pci_dev);
+
+    pci_dev->irq_type = IRQ_INTX;
+
+    V3_Print("Caps scanned\n");
+
+    // hook important regions
+    v3_pci_hook_config_range(pci_dev, 0x30, 4, exp_rom_write, NULL, NULL);  // ExpRom
+    v3_pci_hook_config_range(pci_dev, 0x04, 2, cmd_write, NULL, NULL);      // CMD Reg
+    // * Status resets
+    // * Drop BIST
+    // 
+
+    
+
     //copy bars
     for (i = 0; i < 6; i ++) {
        pci_dev->bar[i].type = bars[i].type;
@@ -1024,70 +1640,3 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci,
     return pci_dev;
 }
 
-
-
-// if dev_num == -1, auto assign 
-struct pci_device * v3_pci_register_passthrough_device(struct vm_device * pci,
-                                                      int bus_num,
-                                                      int dev_num,
-                                                      int fn_num,
-                                                      const char * name,
-                                                      int (*config_write)(uint_t reg_num, void * src, uint_t length, void * private_data),
-                                                      int (*config_read)(uint_t reg_num, void * dst, uint_t length, void * private_data),
-                                                      void * private_data) {
-
-    struct pci_internal * pci_state = (struct pci_internal *)pci->private_data;
-    struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
-    struct pci_device * pci_dev = NULL;
-
-    if (dev_num > MAX_BUS_DEVICES) {
-       PrintError("Requested Invalid device number (%d)\n", dev_num);
-       return NULL;
-    }
-
-    if (dev_num == PCI_AUTO_DEV_NUM) {
-       PrintDebug("Searching for free device number\n");
-       if ((dev_num = get_free_dev_num(bus)) == -1) {
-           PrintError("No more available PCI slots on bus %d\n", bus->bus_num);
-           return NULL;
-       }
-    }
-    
-    PrintDebug("Checking for PCI Device\n");
-
-    if (get_device(bus, dev_num, fn_num) != NULL) {
-       PrintError("PCI Device already registered at slot %d on bus %d\n", 
-                  dev_num, bus->bus_num);
-       return NULL;
-    }
-
-    
-    pci_dev = (struct pci_device *)V3_Malloc(sizeof(struct pci_device));
-
-    if (pci_dev == NULL) {
-       PrintError("Could not allocate pci device\n");
-       return NULL;
-    }
-
-    memset(pci_dev, 0, sizeof(struct pci_device));
-    
-    pci_dev->bus_num = bus_num;
-    pci_dev->dev_num = dev_num;
-    pci_dev->fn_num = fn_num;
-
-    strncpy(pci_dev->name, name, sizeof(pci_dev->name));
-    pci_dev->priv_data = private_data;
-
-    // register update callbacks
-    pci_dev->config_write = config_write;
-    pci_dev->config_read = config_read;
-
-    // add the device
-    add_device_to_bus(bus, pci_dev);
-
-#ifdef V3_CONFIG_DEBUG_PCI
-    pci_dump_state(pci_state);
-#endif
-
-    return pci_dev;
-}
index 70dc980..68428b5 100644 (file)
@@ -607,7 +607,7 @@ static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
 }
 
 
-static int pci_front_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) 
+static int pci_front_config_update(struct pci_device *pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) 
 {
     int i;
     struct vm_device * dev = (struct vm_device *)private_data;
@@ -690,6 +690,7 @@ static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * de
                                     bus_num, -1, 0, 
                                     state->name, bars,
                                     pci_front_config_update,
+                                    NULL,      // no suport for config reads
                                     NULL,      // no support for command updates
                                     NULL,      // no support for expansion roms              
                                     dev);
index b8f921b..e8d72db 100644 (file)
@@ -588,7 +588,7 @@ static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
 }
 
 
-static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
+static int pt_config_update(struct pci_device * pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) {
     struct vm_device * dev = (struct vm_device *)private_data;
     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
@@ -732,6 +732,7 @@ static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * de
                                     bus_num, -1, 0, 
                                     state->name, bars,
                                     pt_config_update,
+                                    NULL, 
                                     NULL,
                                     pt_exp_rom_write,               
                                     dev);
@@ -762,7 +763,7 @@ static int irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void
     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
 
 
-    v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
+    v3_pci_raise_irq(state->pci_bus, state->pci_dev, 0);
 
     V3_ACK_IRQ(intr->irq);
 
index b482b48..35925b5 100644 (file)
@@ -371,12 +371,16 @@ struct pirq_rc_reg {
 */
 
 
-static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) {
+static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec) {
     struct v3_southbridge * piix3 = dev_data;
     struct pci_device * piix3_pci = piix3->southbridge_pci;
     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data);
     int intr_pin = pci_dev->config_header.intr_pin - 1;
     int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3;
+    struct v3_irq irq; // Make a copy of the irq state because we will switch the irq number
+
+    irq.ack = vec->ack;
+    irq.private_data = vec->private_data;
 
     /*
     PrintError("Raising PCI dev %d intr %d via IOAPIC as IRQ %d and via PIRQ as IRQ %d on VM %p\n", 
@@ -388,7 +392,10 @@ static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) {
     // deliver first by PIRQ, if it exists
     //
     if (piix3_cfg->pirq_rc[irq_index] < 16) {
-       v3_raise_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index] & 0xf);
+       irq.irq = piix3_cfg->pirq_rc[irq_index] & 0xf;
+
+       //      V3_Print("Raising PIIX IRQ %d\n", irq.irq);
+       v3_raise_acked_irq(piix3->vm, irq);
     } else {
       // not an error
     }
@@ -396,7 +403,9 @@ static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) {
     // deliver next via the PCI0 to ioapic mapping defined in the 
     // mptable (ioapic, pins 16->19 are used for PCI0)
     // ideally this would check to verify that an ioapic is actually available
-    v3_raise_irq(piix3->vm, 16+irq_index);
+    irq.irq = (irq_index + 1) + 16;
+    //    V3_Print("Raising PIIX IRQ (#2) %d\n", irq.irq);
+    v3_raise_acked_irq(piix3->vm, irq);
     
 
     return 0;
@@ -404,21 +413,26 @@ static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) {
 
 
 
-static int lower_pci_irq(struct pci_device * pci_dev, void * dev_data) {
+static int lower_pci_irq(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec) {
     struct v3_southbridge * piix3 = dev_data;
     struct pci_device * piix3_pci = piix3->southbridge_pci;
     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data);
     int intr_pin = pci_dev->config_header.intr_pin - 1;
     int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3;
-    
+    struct v3_irq irq; // Make a copy of the irq state because we will switch the irq number
+
+    irq.ack = vec->ack;
+    irq.private_data = vec->private_data;
     //    PrintError("Lowering PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]);
 
     // First, lower the pin on the ioapic
-    v3_lower_irq(piix3->vm, irq_index+16);
+    irq.irq = (irq_index + 1) + 16;
+    v3_lower_acked_irq(piix3->vm, irq);
     
     // Next, lower whatever we asserted by the PIRQs
     if (piix3_cfg->pirq_rc[irq_index] < 16) {
-       v3_lower_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index] & 0xf);
+       irq.irq = piix3_cfg->pirq_rc[irq_index] & 0xf;
+       v3_lower_acked_irq(piix3->vm, irq);
     } else {
       // not an error
     }
@@ -457,7 +471,7 @@ static int setup_pci(struct v3_southbridge * piix3) {
     pci_dev = v3_pci_register_device(piix3->pci_bus, PCI_MULTIFUNCTION, 
                                     bus_num, -1, 0, 
                                     "PIIX3", bars, 
-                                    NULL, NULL, NULL, piix3);
+                                    NULL, NULL, NULL, NULL, piix3);
     if (pci_dev == NULL) {
        PrintError("Could not register PCI Device for PIIX3\n");
        return -1;
index 33a5cfa..fde3ef9 100644 (file)
@@ -582,7 +582,7 @@ static inline void rtl8139_update_irq(struct rtl8139_state * nic_state) {
     int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0xffff);
 
     if(isr & 0xffff){
-       v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev);
+       v3_pci_raise_irq(nic_state->pci_bus, nic_state->pci_dev, 0);
        nic_state->statistic.tx_interrupts ++;
     }
 }
@@ -1732,7 +1732,7 @@ static int register_dev(struct rtl8139_state * nic_state)  {
 
     pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, 
                                         "RTL8139", bars,
-                                        NULL, NULL, NULL, nic_state);
+                                    NULL, NULL, NULL, NULL, nic_state);
 
 
     if (pci_dev == NULL) {
index c4d3f28..4827a95 100644 (file)
@@ -28,8 +28,7 @@ static struct v3_file_hooks * file_hooks = NULL;
 
 void V3_Init_File(struct v3_file_hooks * hooks) {
     file_hooks = hooks;
-    PrintDebug("V3 file access inited\n");
-
+    V3_Print("V3 file interface intialized\n");
     return;
 }
 
index 28fe355..115a369 100644 (file)
@@ -155,7 +155,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
     ctrl_area->instrs.NMI = 1;
     ctrl_area->instrs.SMI = 0; // allow SMIs to run in guest
     ctrl_area->instrs.INIT = 1;
-    ctrl_area->instrs.PAUSE = 1;
+    //    ctrl_area->instrs.PAUSE = 1;
     ctrl_area->instrs.shutdown_evts = 1;
 
 
index 1fc0b7c..96fcaa1 100644 (file)
@@ -56,7 +56,8 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i
 #endif
 
 
-    //PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); 
+
+    //    PrintDebug("SVM Returned: Exit Code: %p\n", (void *)exit_code); 
 
     switch (exit_code) {
        case VMEXIT_IOIO: {
@@ -309,10 +310,10 @@ int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_i
            PrintError("SVM Returned: Exit Code: %p\n", (void *)(addr_t)exit_code); 
            
            PrintError("io_info1 low = 0x%.8x\n", *(uint_t*)&(exit_info1));
-           PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(exit_info1)) + 4));
+           PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uint8_t *)&(exit_info1)) + 4));
            
            PrintError("io_info2 low = 0x%.8x\n", *(uint_t*)&(exit_info2));
-           PrintError("io_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(exit_info2)) + 4));
+           PrintError("io_info2 high = 0x%.8x\n", *(uint_t *)(((uint8_t *)&(exit_info2)) + 4));
            
            
            if (info->shdw_pg_mode == SHADOW_PAGING) {
index d08b227..a9e2af9 100644 (file)
@@ -68,7 +68,7 @@ int V3_init_devices() {
 
 
     while (tmp_dev != __stop__v3_devices) {
-       PrintDebug("Device: %s\n", tmp_dev->name);
+       V3_Print("Registering Device: %s\n", tmp_dev->name);
 
        if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
            PrintError("Multiple instance of device (%s)\n", tmp_dev->name);
index 621b68c..eca50cf 100644 (file)
@@ -40,7 +40,7 @@ int v3_handle_halt(struct guest_info * info) {
     } else {
        PrintDebug("CPU Yield\n");
 
-       while (!v3_intr_pending(info)) {
+       while (!v3_intr_pending(info) && (info->vm_info->run_state == VM_RUNNING)) {
             uint64_t t, cycles;
            /* Yield, allowing time to pass while yielded */
            t = v3_get_host_time(&info->time_state);
index 9010a4c..02b8fbd 100644 (file)
@@ -274,37 +274,59 @@ int v3_lower_virq(struct guest_info * info, int irq) {
 
 
 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
+    struct v3_irq irq_state;
+
+    irq_state.irq = irq;
+    irq_state.ack = NULL;
+    irq_state.private_data = NULL;
+
+    return v3_lower_acked_irq(vm, irq_state);
+}
+
+int v3_raise_irq(struct v3_vm_info * vm, int irq) {
+    struct v3_irq irq_state;
+
+    irq_state.irq = irq;
+    irq_state.ack = NULL;
+    irq_state.private_data = NULL;
+
+    return v3_raise_acked_irq(vm, irq_state);
+}
+
+
+int v3_raise_acked_irq(struct v3_vm_info * vm, struct v3_irq irq) {
     struct intr_router * router = NULL;
     struct v3_intr_routers * routers = &(vm->intr_routers);
 
-    //    PrintDebug("[v3_lower_irq]\n");
+    //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
 
     list_for_each_entry(router, &(routers->router_list), router_node) {
-       router->router_ops->lower_intr(vm, router->priv_data, irq);
+       router->router_ops->raise_intr(vm, router->priv_data, &irq);
     }
+
     v3_unlock_irqrestore(routers->irq_lock, irq_state);
 
     return 0;
 }
 
-int v3_raise_irq(struct v3_vm_info * vm, int irq) {
+
+int v3_lower_acked_irq(struct v3_vm_info * vm, struct v3_irq irq) {
     struct intr_router * router = NULL;
     struct v3_intr_routers * routers = &(vm->intr_routers);
 
-    //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
+    //    PrintDebug("[v3_lower_irq]\n");
     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
 
     list_for_each_entry(router, &(routers->router_list), router_node) {
-       router->router_ops->raise_intr(vm, router->priv_data, irq);
+       router->router_ops->lower_intr(vm, router->priv_data, &irq);
     }
-
     v3_unlock_irqrestore(routers->irq_lock, irq_state);
 
     return 0;
-}
 
+}
 
 
 
@@ -325,7 +347,15 @@ v3_intr_type_t v3_intr_pending(struct guest_info * info) {
     //  PrintDebug("[intr_pending]\n");
     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
 
-    // VIRQs have priority
+    // External IRQs have lowest priority
+    list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
+       if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
+           ret = V3_EXTERNAL_IRQ;
+           break;
+       }
+    }   
+
+    // VIRQs have 2nd priority
     for (i = 0; i < MAX_IRQ / 8; i++) {
        if (intr_state->virq_map[i] != 0) {   
            ret = V3_VIRTUAL_IRQ;
@@ -333,16 +363,7 @@ v3_intr_type_t v3_intr_pending(struct guest_info * info) {
        }
     }
 
-    if (ret == V3_INVALID_INTR) {
-       list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
-           if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
-               ret = V3_EXTERNAL_IRQ;
-               break;
-           }
-       }
-    }
-    
-    /* for swintr injection */
+    /* SWINTRs have highest */
     if (intr_state->swintr_posted == 1) {
         ret = V3_SOFTWARE_INTR;
     }
index f57ddda..d3e4c93 100644 (file)
@@ -197,6 +197,11 @@ int v3_init_shdw_impl(struct v3_vm_info * vm) {
 int v3_deinit_shdw_impl(struct v3_vm_info * vm) {
     struct v3_shdw_pg_impl * impl = vm->shdw_impl.current_impl;
 
+    if (impl == NULL) {
+       // Shadow paging not implemented
+       return 0;
+    }
+
     if (impl->deinit(vm) == -1) {
        PrintError("Error deinitializing shadow paging implementation\n");
        return -1;