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.


Merge branch 'devel' of ssh://newskysaw.cs.northwestern.edu/home/palacios/palacios...
Patrick G. Bridges [Thu, 10 Nov 2011 16:50:30 +0000 (09:50 -0700)]
linux_module/iface-packet.c
palacios/src/devices/curses_cons.c
palacios/src/devices/io_apic.c
palacios/src/devices/mptable.c
palacios/src/devices/ne2k.c
palacios/src/devices/piix3.c
palacios/src/devices/rtl8139.c

index c03d628..f3562b0 100644 (file)
@@ -95,7 +95,7 @@ static int
 init_socket(struct raw_interface * iface, const char * eth_dev){
     int err;
     struct sockaddr_ll sock_addr;
-    struct ifreq if_req;
+    struct net_device * net_dev;
 
     err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &(iface->raw_sock)); 
     if (err < 0) {
@@ -103,14 +103,9 @@ init_socket(struct raw_interface * iface, const char * eth_dev){
        return -1;
     }
 
-    memset(&if_req, 0, sizeof(if_req));
-    strncpy(if_req.ifr_name, eth_dev, sizeof(if_req.ifr_name));
-
-    err = iface->raw_sock->ops->ioctl(iface->raw_sock, SIOCGIFINDEX, (long)&if_req);
-    if (err < 0){
-       printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s, error %d\n", 
-              if_req.ifr_name, err);
-
+    net_dev = dev_get_by_name(&init_net, eth_dev);
+    if(net_dev == NULL) {
+       printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s\n", eth_dev);
        sock_release(iface->raw_sock);
        return -1;
     }
@@ -118,7 +113,7 @@ init_socket(struct raw_interface * iface, const char * eth_dev){
     memset(&sock_addr, 0, sizeof(sock_addr));
     sock_addr.sll_family = PF_PACKET;
     sock_addr.sll_protocol = htons(ETH_P_ALL);
-    sock_addr.sll_ifindex = if_req.ifr_ifindex;
+    sock_addr.sll_ifindex = net_dev->ifindex;
 
     err = iface->raw_sock->ops->bind(iface->raw_sock, 
                                     (struct sockaddr *)&sock_addr, 
@@ -132,7 +127,7 @@ init_socket(struct raw_interface * iface, const char * eth_dev){
     }
 
     printk(KERN_INFO "Bind a palacios raw packet interface to device %s, device index %d\n",
-          if_req.ifr_name, if_req.ifr_ifindex);
+          eth_dev, net_dev->ifindex);
 
     return 0;
 }
index e71cb51..1447bd5 100644 (file)
@@ -42,6 +42,7 @@ struct cons_state {
     v3_console_t cons;
     int rows;
     int cols;
+    uint8_t * framebuf;
     struct vm_device * frontend_dev;
 };
 
@@ -90,23 +91,27 @@ static int screen_update(uint_t x, uint_t y, uint_t length, void * private_data)
     struct vm_device * dev = (struct vm_device *)private_data;
     struct cons_state * state = (struct cons_state *)dev->private_data;
     uint_t offset = (x + y * state->cols) * BYTES_PER_COL;
-    uint8_t fb_buf[length];
     int i;
     uint_t cur_x = x;
     uint_t cur_y = y;
     
+    if (length > (state->rows * state->cols * BYTES_PER_COL)) {
+       PrintError("Screen update larger than curses framebuffer\n");
+       return 0;
+    }
+
     PrintDebug("screen_update(%d, %d, %d, %p)\n", x, y, length, private_data);
 
     /* grab frame buffer */
-    v3_cons_get_fb(state->frontend_dev, fb_buf, offset, length);
+    v3_cons_get_fb(state->frontend_dev, state->framebuf, offset, length);
     
     /* update the screen */
     for (i = 0; i < length; i += 2) {
        uint_t col_index = i;
        uint8_t col[2];
        
-       col[0] = fb_buf[col_index];     // Character
-       col[1] = fb_buf[col_index + 1]; // Attribute
+       col[0] = state->framebuf[col_index];     // Character
+       col[1] = state->framebuf[col_index + 1]; // Attribute
        
        /* update current character */
        if (v3_console_set_char(state->cons, cur_x, cur_y, col[0], col[1]) < 0) {
@@ -228,6 +233,8 @@ static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg)
     state->frontend_dev = frontend;
     state->cols = 80;
     state->rows = 25;
+    state->framebuf = V3_Malloc(state->cols * state->rows * BYTES_PER_COL);
+
 
     /* open tty for screen display */
     state->cons = v3_console_open(vm, state->cols, state->rows);
index 0817e9b..0d7c3dc 100644 (file)
@@ -267,6 +267,17 @@ static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq
     struct io_apic_state * ioapic = (struct io_apic_state *)(private_data);  
     struct redir_tbl_entry * irq_entry = NULL;
 
+    if (irq==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
+      // Hence we convert this to the relvant pin.  In the future,
+      // 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;
+    }
+
     if (irq > 24) {
        PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.id);
        return -1;
index 3b6a463..2dbb8ac 100644 (file)
 
   Currently, we set up n identical processors (based on
   number of cores in guest info), with apics 0..n-1, and
-  ioapic as n.
+  ioapic as n.  The ISA interrupt lines map to pins 0..15
+  of the first ioapic.  PCI bus lines map to pins 16..19
+  of the first ioapic.  The system supports virtual wire
+  compability mode and symmetric mode.   PIC mode is not supported. 
 
   The expectation is that the target will have 
   8 bytes (for ___HVMMP signature) followed by 896 bytes of space
@@ -72,6 +75,7 @@
 
 
 #define BUS_ISA "ISA   "
+#define BUS_PCI "PCI   "
 
 #define INT_TYPE_INT 0
 #define INT_TYPE_NMI 1
@@ -214,6 +218,7 @@ struct mp_table_local_interrupt_assignment {
 
 
 
+#define NUM_PCI_SLOTS 8
 
 
 static inline int check_for_cookie(void * target) {
@@ -275,6 +280,11 @@ static int write_pointer(void * target, uint32_t mptable_gpa) {
     p->pointer = mptable_gpa;
     p->length = 1;             // length in 16 byte chunks
     p->spec_rev = SPEC_REV;
+
+    // The remaining zeros indicate that an MP config table is present
+    // and that virtual wire mode is implemented (not PIC mode)
+    // Either virtual wire or PIC must be implemented in addition to
+    // symmetric I/O mode
     
     // checksum calculation
     p->checksum = 0;
@@ -292,7 +302,7 @@ static int write_pointer(void * target, uint32_t mptable_gpa) {
 
     
 
-static int write_mptable(void * target, uint32_t numcores) {
+static int write_mptable(void * target, uint32_t numcores, int have_ioapic, int have_pci) {
     uint32_t i = 0;
     uint8_t sum = 0;
     uint8_t core = 0;
@@ -315,12 +325,16 @@ static int write_mptable(void * target, uint32_t numcores) {
     memcpy(header->oem_id, OEM_ID, 8);
     memcpy(header->prod_id, PROD_ID, 12);
 
-    // n processors, 1 ioapic, 1 isa bus, 16 IRQs = 18+n
-    header->entry_count = numcores + 18;
+    // numcores entries for apics, one entry for ioapic (if it exists)
+    // one entry for isa bus (if ioapic exists), one entry for pci bus (if exists),
+    // 16 entries for isa irqs (if ioapic exists) + num_slots*num_intr pci irqs
+    // (if ioapic and pci exist)
+    header->entry_count = numcores + !!have_ioapic + !!have_ioapic + !!have_pci +
+      16*(!!have_ioapic) + NUM_PCI_SLOTS * 4 * (!!have_pci) * (!!have_ioapic);
+
     header->lapic_addr = LAPIC_ADDR;
     
     // now we arrange the processors;
-    
     for (core = 0; core < numcores; core++) { 
        proc = (struct mp_table_processor *)cur;
        memset((void *)proc, 0, sizeof(struct mp_table_processor));
@@ -343,59 +357,126 @@ static int write_mptable(void * target, uint32_t numcores) {
        cur += sizeof(struct mp_table_processor);
     }
 
-    // next comes the ISA bas
+    // PCI bus is always zero
+    if (have_pci) { 
+      bus = (struct mp_table_bus *)cur;
+      cur += sizeof(struct mp_table_bus);
+      
+      memset((void *)bus, 0, sizeof(struct mp_table_bus));
+      bus->entry_type = ENTRY_BUS;
+      bus->bus_id = 0;
+      memcpy(bus->bus_type, BUS_PCI, 6);
+    }
+
+    // next comes the ISA bus  (bus one)
     bus = (struct mp_table_bus *)cur;
     cur += sizeof(struct mp_table_bus);
 
     memset((void *)bus, 0, sizeof(struct mp_table_bus));
     bus->entry_type = ENTRY_BUS;
-    bus->bus_id = 0;
+    bus->bus_id = 1;
     memcpy(bus->bus_type, BUS_ISA, 6);
 
+
     // next comes the IOAPIC
-    ioapic = (struct mp_table_ioapic *)cur;
-    cur += sizeof(struct mp_table_ioapic);
-    
-    memset((void *)ioapic, 0, sizeof(struct mp_table_ioapic));
-    ioapic->entry_type = ENTRY_IOAPIC;
-    ioapic->ioapic_id = numcores;
-    ioapic->ioapic_version = IOAPIC_VERSION;
-    ioapic->ioapic_flags.en = 1;
-    ioapic->ioapic_address = IOAPIC_ADDR;
+    if (have_ioapic) { 
+      ioapic = (struct mp_table_ioapic *)cur;
+      cur += sizeof(struct mp_table_ioapic);
+      
+      memset((void *)ioapic, 0, sizeof(struct mp_table_ioapic));
+      ioapic->entry_type = ENTRY_IOAPIC;
+      ioapic->ioapic_id = numcores;
+      ioapic->ioapic_version = IOAPIC_VERSION;
+      ioapic->ioapic_flags.en = 1;
+      ioapic->ioapic_address = IOAPIC_ADDR;
+    }
 
 
+    // LEGACY ISA IRQ mappings
     // The MPTABLE IRQ mappings are kind of odd. 
     // We don't include a bus IRQ 2, and instead remap Bus IRQ 0 to dest irq 2
-
-
-    for (irq = 0; irq < 16; irq++) { 
+    // The idea here is that the timer hooks to 2, while the PIC hooks
+    // to zero in ExtInt mode.  This makes it possible to do virtual wire
+    // mode via the ioapic.
+    //
+    // Note that the timer connects to pin 2 of the IOAPIC.  Sadly,
+    // the timer is unaware of this and just raises irq 0.  The ioapic
+    // transforms this to a pin 2 interrupt.   If we want the PIC
+    // to be able to channel interrupts via pin 0, we need a separate
+    // path. 
+    if (have_ioapic) {
+      for (irq = 0; irq < 16; irq++) { 
        uint8_t dst_irq = irq;
-
+       
        if (irq == 0) {
-           dst_irq = 2;
+         dst_irq = 2;
        } else if (irq == 2) {
-           continue;
+         continue;
        }
-
+       
        interrupt = (struct mp_table_io_interrupt_assignment *)cur;
        memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment));
-
+       
        interrupt->entry_type = ENTRY_IOINT;
        interrupt->interrupt_type = INT_TYPE_INT;
        interrupt->flags.po = INT_POLARITY_DEFAULT;
        interrupt->flags.el = INT_TRIGGER_DEFAULT;
-       interrupt->source_bus_id = 0;
+       interrupt->source_bus_id = 1;
        interrupt->source_bus_irq = irq;
        interrupt->dest_ioapic_id = numcores;
        interrupt->dest_ioapic_intn = dst_irq;
-
+       
        cur += sizeof(struct mp_table_io_interrupt_assignment);
+      }
     }
-
+      
+    if (have_pci && have_ioapic)     {
+      // Interrupt redirection entries for PCI bus
+      // 
+      // We need an entry for each slot+pci interrupt
+      // There can be 32 slots, each of which can use 4 interrupts
+      // Thus there are 128 entries
+      //
+      // In this simple setup, we map
+      // slot i, intr j (both zero based)  to  pci_irq[(i+j)%4]
+      
+      int slot, intr;
+      static uint8_t pci_irq[4] = {16,17,18,19};
+      
+      for (slot=0;slot<NUM_PCI_SLOTS;slot++) { 
+       for (intr=0;intr<4;intr++) { 
+         
+         uint8_t dst_irq = pci_irq[(slot+intr)%4];
+         
+         interrupt = (struct mp_table_io_interrupt_assignment *)cur;
+         memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment));
+
+         interrupt->entry_type = ENTRY_IOINT;
+         interrupt->interrupt_type = INT_TYPE_INT;
+         interrupt->flags.po = INT_POLARITY_DEFAULT;
+         interrupt->flags.el = INT_TRIGGER_DEFAULT;
+         interrupt->source_bus_id = 0;
+          // Yes, this is how you encode the slot and pin of a PCI device
+          // As we all know, bits are expensive
+          // We can have as many as 32 slots, but to get that large,
+          // we would need to tweak the bios's landing zone for the mptable
+         interrupt->source_bus_irq = (slot<<2) | intr ;
+         interrupt->dest_ioapic_id = numcores;
+         interrupt->dest_ioapic_intn = dst_irq;
+         
+         cur += sizeof(struct mp_table_io_interrupt_assignment);
+         
+         //V3_Print("PCI0, slot %d, irq %d maps to irq %d\n",slot,intr,dst_irq);
+       }
+      }
+    }
+    
     // now we can set the length;
 
     header->base_table_length = (cur - (uint8_t *)header);
 
+    V3_Print("MPtable size: %u\n",header->base_table_length);
+
     // checksum calculation
     header->checksum = 0;
     sum = 0;
@@ -403,15 +484,54 @@ static int write_mptable(void * target, uint32_t numcores) {
        sum += ((uint8_t *)target)[i];
     }
     header->checksum = (255 - sum) + 1;
-
-
        
     return 0;
 }
 
+
+static v3_cfg_tree_t *find_first_peer_device_of_class(v3_cfg_tree_t *themptablenode, char *theclass)
+{
+  v3_cfg_tree_t *p=themptablenode->parent;
+  v3_cfg_tree_t *c;
+
+
+  if (p==NULL) { 
+    return NULL;
+  }
+
+  for (c=v3_xml_child(p,"device"); 
+       c && strcasecmp(v3_cfg_val(c,"class"),theclass); 
+       c=v3_xml_next(c)) {
+  }
+
+  return c;
+}
+
+  
+
+
 static int mptable_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     void * target = NULL;
 
+    int have_pci = find_first_peer_device_of_class(cfg,"pci")!=NULL;
+    int have_piix3 = find_first_peer_device_of_class(cfg,"piix3")!=NULL;
+    int have_apic = find_first_peer_device_of_class(cfg,"lapic")!=NULL;
+    int have_ioapic = find_first_peer_device_of_class(cfg,"ioapic")!=NULL;
+
+    if (!have_apic) { 
+      PrintError("Attempt to instantiate MPTABLE but machine has no apics!\n");
+      return -1;
+    }
+
+    if (!have_ioapic) { 
+      PrintError("Attempt to instantiate MPTABLE without ioapic - will try, but this won't end well\n");
+    }
+
+    if (have_pci && (!have_piix3 || !have_ioapic)) { 
+      PrintError("Attempt to instantiate MPTABLE with a PCI Bus, but without either a piix3 or an ioapic\n");
+      return -1;
+    }
+      
     if (v3_gpa_to_hva(&(vm->cores[0]), BIOS_MP_TABLE_DEFAULT_LOCATION, (addr_t *)&target) == -1) { 
        PrintError("Cannot inject mptable due to unmapped bios!\n");
        return -1;
@@ -439,7 +559,7 @@ static int mptable_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
        return -1;
     }
 
-    if (write_mptable(target + sizeof(struct mp_floating_pointer), vm->num_cores) == -1) {
+    if (write_mptable(target + sizeof(struct mp_floating_pointer), vm->num_cores, have_ioapic, have_pci)) {
        PrintError("Cannot inject mptable configuration header and entries\n");
        return -1;
     }
index bc51c78..d4e8852 100644 (file)
@@ -1175,8 +1175,9 @@ static int connect_fn(struct v3_vm_info * info,
     nic_state->backend_data = private_data;    
 
     ops->recv = ne2k_rx;
-    ops->poll = NULL;
-    memcpy(ops->config.fnt_mac, nic_state->mac, ETH_ALEN);
+    ops->poll = NULL;   
+    ops->config.frontend_data = nic_state;
+    ops->config.fnt_mac = nic_state->mac;
 
     return 0;
 }
index 8752943..b482b48 100644 (file)
@@ -74,7 +74,7 @@ struct top_of_mem_reg {
        uint8_t value;
        struct {
            uint8_t rsvd1                    : 1;
-           uint8_t isadma_reg_fwd_en        : 1;
+    uint8_t isadma_reg_fwd_en        : 1;
            uint8_t piix_rsvd                : 1;
            uint8_t isadma_lo_bios_fwd_en    : 1;
            uint8_t top_of_mem               : 4;
@@ -377,19 +377,28 @@ static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) {
     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;
-    
-    //PrintError("Raising PCI IRQ %d, %p\n", piix3_cfg->pirq_rc[irq_index], piix3->vm);
-    
+
+    /*
+    PrintError("Raising PCI dev %d intr %d via IOAPIC as IRQ %d and via PIRQ as IRQ %d on VM %p\n", 
+              pci_dev->dev_num, pci_dev->config_header.intr_pin, 
+              16+irq_index,
+              piix3_cfg->pirq_rc[irq_index], piix3->vm);
+    */
+
+    // 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);
     } else {
-       PrintError("Tried to raise interrupt on disabled PIRQ entry (%d)\n", irq_index);
-       PrintError("\tpirq_rc values: 0=0x%x, 1=0x%x, 2=0x%x, 3=0x%x\n", 
-                  piix3_cfg->pirq_rc[0], piix3_cfg->pirq_rc[1],
-                  piix3_cfg->pirq_rc[2], piix3_cfg->pirq_rc[3]);
-       return -1;
+      // not an error
     }
 
+    // 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);
+    
+
     return 0;
 }
 
@@ -403,15 +412,15 @@ static int lower_pci_irq(struct pci_device * pci_dev, void * dev_data) {
     int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3;
     
     //    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);
     
+    // 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);
     } else {
-       PrintError("Tried to lower interrupt on disabled PIRQ entry (%d)\n", irq_index);
-       PrintError("\tpirq_rc values: 0=0x%x, 1=0x%x, 2=0x%x, 3=0x%x\n", 
-                  piix3_cfg->pirq_rc[0], piix3_cfg->pirq_rc[1],
-                  piix3_cfg->pirq_rc[2], piix3_cfg->pirq_rc[3]);
-       return -1;
+      // not an error
     }
 
     return 0;
index 0a1a335..176d053 100644 (file)
@@ -1774,7 +1774,8 @@ static int connect_fn(struct v3_vm_info * info,
 
     ops->recv = rtl8139_rx;
     ops->poll = NULL;
-    memcpy(ops->config.fnt_mac, nic_state->mac, ETH_ALEN);
+    ops->config.frontend_data = nic_state;
+    ops->config.fnt_mac = nic_state->mac;
 
     return 0;
 }