#define PCI_MEM32_BASE(bar_val) (bar_val & 0xfffffff0)
struct pci_device {
+
union {
uint8_t config_space[256];
} __attribute__((packed));
} __attribute__((packed));
-
-
struct v3_pci_bar bar[6];
- uint_t bus_num;
struct rb_node dev_tree_node;
- int dev_num;
+ uint_t bus_num;
+
+ union {
+ uint8_t devfn;
+ struct {
+ uint8_t fn_num : 3;
+ uint8_t dev_num : 5;
+ } __attribute__((packed));
+ } __attribute__((packed));
+
char name[64];
struct vm_device * vm_dev; //the corresponding virtual device
int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled);
int (*ext_rom_update)(struct pci_device *pci_dev);
-
int ext_rom_update_flag;
int bar_update_flag;
struct pci_device *
v3_pci_register_device(struct vm_device * pci,
pci_device_type_t dev_type,
- uint_t bus_num,
- const char * name,
+ int bus_num,
int dev_num,
+ int fn_num,
+ const char * name,
struct v3_pci_bar * bars,
int (*config_update)(struct pci_device * pci_dev, uint_t reg_num, int length),
int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled),
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2009, Lei Xia <lxia@northwestern.edu>
+ * Copyright (c) 2009, Chang Seok Bae <jhuell@gmail.com>
+ * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Lei Xia <lxia@northwestern.edu>
+ * Chang Seok Bae <jhuell@gmail.com>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __DEVICES_SOUTHBRIDGE_H__
+#define __DEVICES_SOUTHBRIDGE_H__
+
+
+#ifdef __V3VEE__
+
+
+typedef enum {V3_SB_INVALID, V3_SB_PIIX3, V3_SB_PIIX4, V3_SB_CMD646} v3_southbridge_type_t;
+
+struct v3_southbridge {
+ struct vm_device * pci_bus;
+ struct pci_device * southbridge_pci;
+
+ v3_southbridge_type_t type;
+};
+
+
+#endif // ! __V3VEE__
+
+#endif
#include <palacios/vmm.h>
#include <devices/i440fx.h>
+#include <devices/pci.h>
struct i440_state {
- int foo;
+ struct vm_device * pci;
};
}
-static int i440_init(struct vm_device * dev) {
- // struct i440_state * state = (struct i440_state *)(dev->private_data);
-
-
- v3_dev_hook_io(dev, 0x00b2,
- &io_read, &io_write);
- v3_dev_hook_io(dev, 0x00b3,
- &io_read, &io_write);
+static int i440_init(struct vm_device * dev) {
+ struct i440_state * state = (struct i440_state *)(dev->private_data);
+ struct pci_device * pci_dev = NULL;
+ struct v3_pci_bar bars[6];
+ int i;
- v3_dev_hook_io(dev, 0x0cf8,
- &io_read, &io_write);
+ for (i = 0; i < 4; i++) {
+ v3_dev_hook_io(dev, 0x0cf8 + i,
+ &io_read, &io_write);
+ v3_dev_hook_io(dev, 0x0cfc + i,
+ &io_read, &io_write);
+ }
+ for (i = 0; i < 6; i++) {
+ bars[i].type = PCI_BAR_NONE;
+ }
+ pci_dev = v3_pci_register_device(state->pci, PCI_STD_DEVICE, 0, 0, 0, "i440FX", bars,
+ NULL, NULL, NULL, dev);
- v3_dev_hook_io(dev, 0x0cf9,
- &io_read, &io_write);
+ if (!pci_dev) {
+ return -1;
+ }
+ pci_dev->config_header.vendor_id = 0x8086;
+ pci_dev->config_header.device_id = 0x1237;
+ pci_dev->config_header.revision = 0x0002;
+ pci_dev->config_header.subclass = 0x00; // SubClass: host2pci
+ pci_dev->config_header.class = 0x06; // Class: PCI bridge
+ pci_dev->config_space[0x72] = 0x02; // SMRAM (?)
return 0;
}
struct vm_device * v3_create_i440fx(struct vm_device * pci) {
-
struct i440_state * state = NULL;
-
state = (struct i440_state *)V3_Malloc(sizeof(struct i440_state));
+
+ state->pci = pci;
struct vm_device * i440_dev = v3_create_device("i440FX", &dev_ops, state);
return i440_dev;
-
}
#include <palacios/vm_guest_mem.h>
#include <devices/ide.h>
#include <devices/pci.h>
+#include <devices/southbridge.h>
#include "ide-types.h"
#include "atapi-types.h"
int irq; // this is temporary until we add PCI support
- struct pci_device * pci_dev;
-
// Control Registers
struct ide_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376
struct ide_internal {
struct ide_channel channels[2];
- struct vm_device * pci;
- struct vm_device * southbridge;
- struct pci_device * busmaster_pci;
+
+ struct v3_southbridge * southbridge;
+ struct vm_device * pci_bus;
+
+ struct pci_device * ide_pci;
};
}
-/*
- * This is an ugly ugly ugly way to differentiate between the first and second DMA channels
- */
-
-static int write_dma_port(ushort_t port_offset, void * src, uint_t length, struct vm_device * dev, struct ide_channel * channel);
-static int read_dma_port(ushort_t port_offset, void * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel);
-
-
-static int write_pri_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
- struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
- PrintDebug("IDE: Writing PRI DMA Port %x (%s) (val=%x)\n", port, dma_port_to_str(port & 0x7), *(uint32_t *)src);
- return write_dma_port(port & 0x7, src, length, dev, &(ide->channels[0]));
-}
-
-static int write_sec_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
- struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
- PrintDebug("IDE: Writing SEC DMA Port %x (%s) (val=%x)\n", port, dma_port_to_str(port & 0x7), *(uint32_t *)src);
- return write_dma_port(port & 0x7, src, length, dev, &(ide->channels[1]));
-}
-
-
-static int read_pri_dma_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
- struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
- PrintDebug("IDE: Reading PRI DMA Port %x (%s)\n", port, dma_port_to_str(port & 0x7));
- return read_dma_port(port & 0x7, dst, length, dev, &(ide->channels[0]));
-}
-
-static int read_sec_dma_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
- struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
- PrintDebug("IDE: Reading SEC DMA Port %x (%s)\n", port, dma_port_to_str(port & 0x7));
- return read_dma_port(port & 0x7, dst, length, dev, &(ide->channels[1]));
-}
-
#define DMA_CMD_PORT 0x00
#define DMA_STATUS_PORT 0x02
#define DMA_PRD_PORT2 0x06
#define DMA_PRD_PORT3 0x07
+#define DMA_CHANNEL_FLAG 0x08
-static int write_dma_port(ushort_t port_offset, void * src, uint_t length,
- struct vm_device * dev, struct ide_channel * channel) {
+static int write_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ uint16_t port_offset = port & (DMA_CHANNEL_FLAG - 1);
+ uint_t channel_flag = (port & DMA_CHANNEL_FLAG) >> 3;
+ struct ide_channel * channel = &(ide->channels[channel_flag]);
switch (port_offset) {
case DMA_CMD_PORT:
}
-static int read_dma_port(ushort_t port_offset, void * dst, uint_t length,
- struct vm_device * dev, struct ide_channel * channel) {
+static int read_dma_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ uint16_t port_offset = port & (DMA_CHANNEL_FLAG - 1);
+ uint_t channel_flag = (port & DMA_CHANNEL_FLAG) >> 3;
+ struct ide_channel * channel = &(ide->channels[channel_flag]);
switch (port_offset) {
case DMA_CMD_PORT:
static int init_ide_state(struct vm_device * dev) {
struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
- int i, j;
-
+ int i;
/*
- Check if the PIIX 3 actually represents both IDE channels in a single PCI entry */
+ * Check if the PIIX 3 actually represents both IDE channels in a single PCI entry
+ */
for (i = 0; i < 1; i++) {
init_channel(&(ide->channels[i]));
// JRL: this is a terrible hack...
ide->channels[i].irq = PRI_DEFAULT_IRQ + i;
-
-
- if (ide->pci) {
- struct v3_pci_bar bars[6];
- struct pci_device * pci_dev = NULL;
-
- for (j = 0; j < 6; j++) {
- bars[j].type = PCI_BAR_NONE;
- }
-
-
- bars[4].type = PCI_BAR_IO;
- bars[4].default_base_port = PRI_DEFAULT_DMA_PORT + (i * 0x8);
- bars[4].num_ports = 8;
-
- if (i == 0) {
- bars[4].io_read = read_pri_dma_port;
- bars[4].io_write = write_pri_dma_port;
- } else {
- bars[4].io_read = read_sec_dma_port;
- bars[4].io_write = write_sec_dma_port;
- }
-
- pci_dev = v3_pci_register_device(ide->pci, PCI_STD_DEVICE, 0, "V3_IDE", -1, bars,
- pci_config_update, NULL, NULL, dev);
-
- if (pci_dev == NULL) {
- PrintError("Failed to register IDE BUS %d with PCI\n", i);
- return -1;
- }
-
- ide->channels[i].pci_dev = pci_dev;
-
- /* This is for CMD646 devices
- pci_dev->config_header.vendor_id = 0x1095;
- pci_dev->config_header.device_id = 0x0646;
- pci_dev->config_header.revision = 0x8f07;
- */
- pci_dev->config_header.vendor_id = 0x8086;
- pci_dev->config_header.device_id = 0x7010;
- pci_dev->config_header.revision = 0x8000;
-
- pci_dev->config_header.subclass = 0x01;
- pci_dev->config_header.class = 0x01;
-
-
- pci_dev->config_header.command = 0;
- pci_dev->config_header.status = 0x0280;
-
- // pci_dev->config_header.intr_line = PRI_DEFAULT_IRQ + i;
- // pci_dev->config_header.intr_pin = 1;
- }
-
-
}
+
return 0;
}
static int init_ide(struct vm_device * dev) {
- //struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
PrintDebug("IDE: Initializing IDE\n");
v3_dev_hook_io(dev, PRI_ADDR_REG_PORT,
&read_port_std, &write_port_std);
+
+
+
+ if (ide->pci_bus) {
+ struct v3_pci_bar bars[6];
+ struct v3_southbridge * southbridge = (struct v3_southbridge *)(ide->southbridge);
+ struct pci_device * sb_pci = (struct pci_device *)(southbridge->southbridge_pci);
+ struct pci_device * pci_dev = NULL;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ bars[i].type = PCI_BAR_NONE;
+ }
+
+ bars[4].type = PCI_BAR_IO;
+ bars[4].default_base_port = PRI_DEFAULT_DMA_PORT;
+ bars[4].num_ports = 16;
+
+ bars[4].io_read = read_dma_port;
+ bars[4].io_write = write_dma_port;
+
+ 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, dev);
+
+ if (pci_dev == NULL) {
+ PrintError("Failed to register IDE BUS %d with PCI\n", i);
+ return -1;
+ }
+
+ /* This is for CMD646 devices
+ pci_dev->config_header.vendor_id = 0x1095;
+ pci_dev->config_header.device_id = 0x0646;
+ pci_dev->config_header.revision = 0x8f07;
+ */
+
+ pci_dev->config_header.vendor_id = 0x8086;
+ pci_dev->config_header.device_id = 0x7010;
+ pci_dev->config_header.revision = 0x8000;
+
+ pci_dev->config_header.subclass = 0x01;
+ pci_dev->config_header.class = 0x01;
+
+ pci_dev->config_header.command = 0;
+ pci_dev->config_header.status = 0x0280;
+ }
+
return 0;
}
};
-struct vm_device * v3_create_ide(struct vm_device * pci, struct vm_device * southbridge) {
+struct vm_device * v3_create_ide(struct vm_device * pci_bus, struct vm_device * southbridge_dev) {
struct ide_internal * ide = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal));
struct vm_device * device = v3_create_device("IDE", &dev_ops, ide);
- ide->pci = pci;
- ide->southbridge = southbridge;
+ ide->pci_bus = pci_bus;
+ ide->southbridge = (struct v3_southbridge *)(southbridge_dev->private_data);
PrintDebug("IDE: Creating IDE bus x 2\n");
parent = *p;
tmp_dev = rb_entry(parent, struct pci_device, dev_tree_node);
- if (dev->dev_num < tmp_dev->dev_num) {
+ if (dev->devfn < tmp_dev->devfn) {
p = &(*p)->rb_left;
- } else if (dev->dev_num > tmp_dev->dev_num) {
+ } else if (dev->devfn > tmp_dev->devfn) {
p = &(*p)->rb_right;
} else {
return tmp_dev;
}
-static struct pci_device * get_device(struct pci_bus * bus, int dev_num) {
+static struct pci_device * get_device(struct pci_bus * bus, uint8_t dev_num, uint8_t fn_num) {
struct rb_node * n = bus->devices.rb_node;
struct pci_device * dev = NULL;
+ uint8_t devfn = ((dev_num & 0x1f) << 3) | (fn_num & 0x7);
while (n) {
dev = rb_entry(n, struct pci_device, dev_tree_node);
- if (dev_num < dev->dev_num) {
+ if (devfn < dev->devfn) {
n = n->rb_left;
- } else if (dev_num > dev->dev_num) {
+ } else if (devfn > dev->devfn) {
n = n->rb_right;
} else {
return dev;
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_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++) {
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
*(uint32_t *)src, length);
- pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
+ 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) {
PrintError("Writing configuration space for non-present device (dev_num=%d)\n",
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 (is_cfg_reg_writable(pci_dev->config_header.header_type, cur_reg)) {
+ if (writable) {
pci_dev->config_space[cur_reg] = *(uint8_t *)((uint8_t *)src + i);
if ((cur_reg >= 0x10) && (cur_reg < 0x28)) {
-
-static int init_i440fx(struct vm_device * dev) {
- struct pci_device * pci_dev = NULL;
- struct v3_pci_bar bars[6];
- int i;
-
- for (i = 0; i < 6; i++) {
- bars[i].type = PCI_BAR_NONE;
- }
-
- pci_dev = v3_pci_register_device(dev, PCI_STD_DEVICE, 0, "i440FX", 0, bars,
- NULL, NULL, NULL, NULL);
-
- if (!pci_dev) {
- return -1;
- }
-
- pci_dev->config_header.vendor_id = 0x8086;
- pci_dev->config_header.device_id = 0x1237;
- pci_dev->config_header.revision = 0x0002;
- pci_dev->config_header.subclass = 0x00; // SubClass: host2pci
- pci_dev->config_header.class = 0x06; // Class: PCI bridge
-
- pci_dev->bus_num = 0;
- return 0;
-}
-
-
-
-
static void init_pci_busses(struct pci_internal * pci_state) {
int i;
pci_state->addr_reg.val = 0;
init_pci_busses(pci_state);
-
- if (init_i440fx(dev) == -1) {
- PrintError("Could not intialize i440fx\n");
- return -1;
- }
PrintDebug("Sizeof config header=%d\n", (int)sizeof(struct pci_config_header));
// if dev_num == -1, auto assign
struct pci_device * v3_pci_register_device(struct vm_device * pci,
pci_device_type_t dev_type,
- uint_t bus_num,
- const char * name,
+ int bus_num,
int dev_num,
+ int fn_num,
+ const char * name,
struct v3_pci_bar * bars,
int (*config_update)(struct pci_device * pci_dev, uint_t reg_num, int length),
int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled),
}
}
- if (get_device(bus, dev_num) != NULL) {
+ 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));
-
+
switch (dev_type) {
case PCI_STD_DEVICE:
pci_dev->config_header.header_type = 0x00;
break;
+ case PCI_MULTIFUNCTION:
+ pci_dev->config_header.header_type = 0x80;
+ break;
default:
PrintError("Unhandled PCI Device Type: %d\n", dev_type);
return NULL;
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->vm_dev = dev;
pci_dev->ext_rom_update = ext_rom_update;
-
//copy bars
- for (i = 0; i < 6; i ++){
+ for (i = 0; i < 6; i ++) {
pci_dev->bar[i].type = bars[i].type;
if (pci_dev->bar[i].type == PCI_BAR_IO) {
#include <devices/piix3.h>
#include <palacios/vmm.h>
#include <devices/pci.h>
+#include <devices/southbridge.h>
+
+
+
+static int reset_piix3(struct vm_device * dev) {
+ struct v3_southbridge * piix3 = (struct v3_southbridge *)(dev->private_data);
+ struct pci_device * pci_dev = piix3->southbridge_pci;
+
+ pci_dev->config_header.command = 0x0007; // master, memory and I/O
+ pci_dev->config_header.status = 0x0200;
+
+ pci_dev->config_space[0x4c] = 0x4d;
+ pci_dev->config_space[0x4e] = 0x03;
+ pci_dev->config_space[0x4f] = 0x00;
+ pci_dev->config_space[0x60] = 0x80;
+ pci_dev->config_space[0x69] = 0x02;
+ pci_dev->config_space[0x70] = 0x80;
+ pci_dev->config_space[0x76] = 0x0c;
+ pci_dev->config_space[0x77] = 0x0c;
+ pci_dev->config_space[0x78] = 0x02;
+ pci_dev->config_space[0x79] = 0x00;
+ pci_dev->config_space[0x80] = 0x00;
+ pci_dev->config_space[0x82] = 0x00;
+ pci_dev->config_space[0xa0] = 0x08;
+ pci_dev->config_space[0xa2] = 0x00;
+ pci_dev->config_space[0xa3] = 0x00;
+ pci_dev->config_space[0xa4] = 0x00;
+ pci_dev->config_space[0xa5] = 0x00;
+ pci_dev->config_space[0xa6] = 0x00;
+ pci_dev->config_space[0xa7] = 0x00;
+ pci_dev->config_space[0xa8] = 0x0f;
+ pci_dev->config_space[0xaa] = 0x00;
+ pci_dev->config_space[0xab] = 0x00;
+ pci_dev->config_space[0xac] = 0x00;
+ pci_dev->config_space[0xae] = 0x00;
+ return 0;
+}
-struct piix3_state {
- uint8_t pci_dev_num;
- struct vm_device * pci;
+static int init_piix3(struct vm_device * dev) {
+ struct v3_southbridge * piix3 = (struct v3_southbridge *)(dev->private_data);
+ struct pci_device * pci_dev = NULL;
+ struct v3_pci_bar bars[6];
+ int i;
-};
+ for (i = 0; i < 6; i++) {
+ bars[i].type = PCI_BAR_NONE;
+ }
+ pci_dev = v3_pci_register_device(piix3->pci_bus, PCI_MULTIFUNCTION,
+ 0, -1, 0,
+ "PIIX3", bars,
+ NULL, NULL, NULL, dev);
+ if (!pci_dev) {
+ PrintError("Could not register PCI Device for PIIX3\n");
+ return -1;
+ }
-static int init_piix3(struct vm_device * dev) {
+ pci_dev->config_header.vendor_id = 0x8086;
+ pci_dev->config_header.device_id = 0x7000; // PIIX4 is 0x7001
+ pci_dev->config_header.subclass = 0x01; // SubClass: host2pci
+ pci_dev->config_header.class = 0x06; // Class: PCI bridge
+
+ piix3->southbridge_pci = pci_dev;
+
+ reset_piix3(dev);
return 0;
}
static struct vm_device_ops dev_ops = {
.init = init_piix3,
.deinit = deinit_piix3,
- .reset = NULL,
+ .reset = reset_piix3,
.start = NULL,
.stop = NULL,
};
struct vm_device * v3_create_piix3(struct vm_device * pci) {
- struct piix3_state * piix3 = (struct piix3_state *)V3_Malloc(sizeof(struct piix3_state));
+ struct v3_southbridge * piix3 = (struct v3_southbridge *)V3_Malloc(sizeof(struct v3_southbridge));
struct vm_device * dev = NULL;
- piix3->pci = pci;
+ piix3->pci_bus = pci;
+ piix3->type = V3_SB_PIIX3;
dev = v3_create_device("PIIX3", &dev_ops, piix3);
v3_attach_device(info, para_net);
if (config_ptr->enable_pci == 1) {
+ PrintDebug("Attaching PCI\n");
v3_attach_device(info, pci);
+ PrintDebug("Attaching Northbridge\n");
v3_attach_device(info, northbridge);
+ PrintDebug("Attaching Southbridge\n");
v3_attach_device(info, southbridge);
}
+ PrintDebug("Attaching IDE\n");
v3_attach_device(info, ide);