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.


added symbiotic virtio device
[palacios.git] / palacios / src / devices / pci.c
index cce7aa8..7cd1147 100644 (file)
@@ -41,6 +41,7 @@
 #define CONFIG_ADDR_PORT    0x0cf8
 #define CONFIG_DATA_PORT    0x0cfc
 
+#define PCI_DEV_IO_PORT_BASE 0xc000
 
 #define PCI_BUS_COUNT 1
 
@@ -74,6 +75,11 @@ struct pci_bus {
 
     // Bitmap of the allocated device numbers
     uint8_t dev_map[MAX_BUS_DEVICES / 8];
+
+
+    int (*raise_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev);
+    int (*lower_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev);
+    struct vm_device * irq_bridge_dev;
 };
 
 
@@ -82,6 +88,9 @@ struct pci_internal {
     // Configuration address register
     struct pci_addr_reg addr_reg;
 
+    // Base IO Port which PCI devices will register with...
+    uint16_t dev_io_base; 
+
     // Attached Busses
     struct pci_bus bus_list[PCI_BUS_COUNT];
 };
@@ -376,23 +385,36 @@ static inline int is_cfg_reg_writable(uchar_t header_type, int reg_num) {
 static int bar_update(struct pci_device * pci, int bar_num, uint32_t new_val) {
     struct v3_pci_bar * bar = &(pci->bar[bar_num]);
 
-    PrintDebug("Updating BAR Register  (Dev=%s) (bar=%d) (old_val=%x) (new_val=%x)\n", 
+    PrintError("Updating BAR Register  (Dev=%s) (bar=%d) (old_val=0x%x) (new_val=0x%x)\n", 
               pci->name, bar_num, bar->val, new_val);
 
     switch (bar->type) {
        case PCI_BAR_IO: {
            int i = 0;
 
-               PrintDebug("\tRehooking %d IO ports from base %x to %x\n",
-                          bar->num_ports, PCI_IO_BASE(bar->val), PCI_IO_BASE(new_val));
+           PrintError("\tRehooking %d IO ports from base 0x%x to 0x%x for %d ports\n",
+                      bar->num_ports, PCI_IO_BASE(bar->val), PCI_IO_BASE(new_val),
+                      bar->num_ports);
                
            // only do this if pci device is enabled....
+           if (!(pci->config_header.status & 0x1)) {
+               PrintError("PCI Device IO space not enabled\n");
+           }
+
            for (i = 0; i < bar->num_ports; i++) {
 
+               PrintError("Rehooking PCI IO port (old port=%u) (new port=%u)\n",  
+                          PCI_IO_BASE(bar->val) + i, PCI_IO_BASE(new_val) + i);
+
                v3_dev_unhook_io(pci->vm_dev, PCI_IO_BASE(bar->val) + i);
 
-               v3_dev_hook_io(pci->vm_dev, PCI_IO_BASE(new_val) + i, 
-                              bar->io_read, bar->io_write);
+               if (v3_dev_hook_io(pci->vm_dev, PCI_IO_BASE(new_val) + i, 
+                                  bar->io_read, bar->io_write) == -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);
+                   return -1;
+               }
            }
 
            bar->val = new_val;
@@ -440,9 +462,10 @@ static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_d
        return length;
     }
 
-    PrintDebug("Writing PCI Data register. bus = %d, dev = %d, reg = %d (%x) addr_reg = %x (val=%x, len=%d)\n", 
+    PrintDebug("Writing PCI Data register. bus = %d, dev = %d, fn = %d, reg = %d (%x) addr_reg = %x (val=%x, len=%d)\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,
               *(uint32_t *)src, length);
@@ -500,6 +523,8 @@ static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_d
                // BIST update
                pci_dev->config_header.BIST = 0x00;
            }
+       } else {
+           PrintError("PCI Write to read only register %d\n", cur_reg);
        }
     }
 
@@ -609,6 +634,7 @@ static int pci_init(struct guest_info * vm, void * cfg_data) {
 
     
     pci_state->addr_reg.val = 0; 
+    pci_state->dev_io_base = PCI_DEV_IO_PORT_BASE;
 
     init_pci_busses(pci_state);
     
@@ -636,7 +662,12 @@ static inline int init_bars(struct pci_device * pci_dev) {
            int j = 0;
            pci_dev->bar[i].mask = (~((pci_dev->bar[i].num_ports) - 1)) | 0x01;
 
-           pci_dev->bar[i].val = pci_dev->bar[i].default_base_port & pci_dev->bar[i].mask;
+           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;
+           } else {
+               pci_dev->bar[i].val = 0;
+           }
+
            pci_dev->bar[i].val |= 0x00000001;
 
            for (j = 0; j < pci_dev->bar[i].num_ports; j++) {
@@ -656,7 +687,11 @@ static inline int init_bars(struct pci_device * pci_dev) {
            pci_dev->bar[i].mask = ~((pci_dev->bar[i].num_pages << 12) - 1);
            pci_dev->bar[i].mask |= 0xf; // preserve the configuration flags
 
-           pci_dev->bar[i].val = pci_dev->bar[i].default_base_addr & pci_dev->bar[i].mask;
+           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;
+           } else {
+               pci_dev->bar[i].val = 0;
+           }
 
            // hook memory
            if (pci_dev->bar[i].mem_read) {
@@ -698,6 +733,34 @@ static inline int init_bars(struct pci_device * pci_dev) {
 }
 
 
+int v3_pci_set_irq_bridge(struct  vm_device * pci_bus, int bus_num, 
+                         int (*raise_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev),
+                         int (*lower_pci_irq)(struct vm_device * dev, struct pci_device * pci_dev),
+                         struct vm_device * bridge_dev) {
+    struct pci_internal * pci_state = (struct pci_internal *)pci_bus->private_data;
+
+
+    pci_state->bus_list[bus_num].raise_pci_irq = raise_pci_irq;
+    pci_state->bus_list[bus_num].lower_pci_irq = lower_pci_irq;
+    pci_state->bus_list[bus_num].irq_bridge_dev = bridge_dev;
+
+    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]);
+
+   return bus->raise_pci_irq(bus->irq_bridge_dev, dev);
+}
+
+int v3_pci_lower_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]);
+
+   return bus->lower_pci_irq(bus->irq_bridge_dev, dev);
+}
+
 // if dev_num == -1, auto assign 
 struct pci_device * v3_pci_register_device(struct vm_device * pci,
                                           pci_device_type_t dev_type, 
@@ -779,7 +842,16 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci,
 
        if (pci_dev->bar[i].type == PCI_BAR_IO) {
            pci_dev->bar[i].num_ports = bars[i].num_ports;
-           pci_dev->bar[i].default_base_port = bars[i].default_base_port;
+
+           // This is a horrible HACK becaues the BIOS is supposed to set the PCI base ports 
+           // And if the BIOS doesn't, Linux just happily overlaps device port assignments
+           if (bars[i].default_base_port != (uint16_t)-1) {
+               pci_dev->bar[i].default_base_port = bars[i].default_base_port;
+           } else {
+               pci_dev->bar[i].default_base_port = pci_state->dev_io_base;
+               pci_state->dev_io_base += ( 0x100 * ((bars[i].num_ports / 0x100) + 1) );
+           }
+
            pci_dev->bar[i].io_read = bars[i].io_read;
            pci_dev->bar[i].io_write = bars[i].io_write;
        } else if (pci_dev->bar[i].type == PCI_BAR_MEM32) {
@@ -809,6 +881,3 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci,
 
     return pci_dev;
 }
-
-
-