Deleted Added
full compact
26c26
< * $FreeBSD: head/usr.sbin/bhyve/pci_emul.c 248477 2013-03-18 22:38:30Z neel $
---
> * $FreeBSD: head/usr.sbin/bhyve/pci_emul.c 249321 2013-04-10 02:12:39Z neel $
30c30
< __FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_emul.c 248477 2013-03-18 22:38:30Z neel $");
---
> __FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_emul.c 249321 2013-04-10 02:12:39Z neel $");
33a34
> #include <sys/errno.h>
40a42
> #include <stdbool.h>
355a358,480
> /*
> * Register (or unregister) the MMIO or I/O region associated with the BAR
> * register 'idx' of an emulated pci device.
> */
> static void
> modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
> {
> int error;
> struct inout_port iop;
> struct mem_range mr;
>
> switch (pi->pi_bar[idx].type) {
> case PCIBAR_IO:
> bzero(&iop, sizeof(struct inout_port));
> iop.name = pi->pi_name;
> iop.port = pi->pi_bar[idx].addr;
> iop.size = pi->pi_bar[idx].size;
> if (registration) {
> iop.flags = IOPORT_F_INOUT;
> iop.handler = pci_emul_io_handler;
> iop.arg = pi;
> error = register_inout(&iop);
> } else
> error = unregister_inout(&iop);
> break;
> case PCIBAR_MEM32:
> case PCIBAR_MEM64:
> bzero(&mr, sizeof(struct mem_range));
> mr.name = pi->pi_name;
> mr.base = pi->pi_bar[idx].addr;
> mr.size = pi->pi_bar[idx].size;
> if (registration) {
> mr.flags = MEM_F_RW;
> mr.handler = pci_emul_mem_handler;
> mr.arg1 = pi;
> mr.arg2 = idx;
> error = register_mem(&mr);
> } else
> error = unregister_mem(&mr);
> break;
> default:
> error = EINVAL;
> break;
> }
> assert(error == 0);
> }
>
> static void
> unregister_bar(struct pci_devinst *pi, int idx)
> {
>
> modify_bar_registration(pi, idx, 0);
> }
>
> static void
> register_bar(struct pci_devinst *pi, int idx)
> {
>
> modify_bar_registration(pi, idx, 1);
> }
>
> /* Are we decoding i/o port accesses for the emulated pci device? */
> static int
> porten(struct pci_devinst *pi)
> {
> uint16_t cmd;
>
> cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
>
> return (cmd & PCIM_CMD_PORTEN);
> }
>
> /* Are we decoding memory accesses for the emulated pci device? */
> static int
> memen(struct pci_devinst *pi)
> {
> uint16_t cmd;
>
> cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
>
> return (cmd & PCIM_CMD_MEMEN);
> }
>
> /*
> * Update the MMIO or I/O address that is decoded by the BAR register.
> *
> * If the pci device has enabled the address space decoding then intercept
> * the address range decoded by the BAR register.
> */
> static void
> update_bar_address(struct pci_devinst *pi, uint64_t addr, int idx, int type)
> {
> int decode;
>
> if (pi->pi_bar[idx].type == PCIBAR_IO)
> decode = porten(pi);
> else
> decode = memen(pi);
>
> if (decode)
> unregister_bar(pi, idx);
>
> switch (type) {
> case PCIBAR_IO:
> case PCIBAR_MEM32:
> pi->pi_bar[idx].addr = addr;
> break;
> case PCIBAR_MEM64:
> pi->pi_bar[idx].addr &= ~0xffffffffUL;
> pi->pi_bar[idx].addr |= addr;
> break;
> case PCIBAR_MEMHI64:
> pi->pi_bar[idx].addr &= 0xffffffff;
> pi->pi_bar[idx].addr |= addr;
> break;
> default:
> assert(0);
> }
>
> if (decode)
> register_bar(pi, idx);
> }
>
360c485
< int i, error;
---
> int error;
362,363d486
< struct inout_port iop;
< struct mem_range memp;
369a493,501
> /* Enforce minimum BAR sizes required by the PCI standard */
> if (type == PCIBAR_IO) {
> if (size < 4)
> size = 4;
> } else {
> if (size < 16)
> size = 16;
> }
>
446,451c578
< /* add a handler to intercept accesses to the I/O bar */
< if (type == PCIBAR_IO) {
< iop.name = pdi->pi_name;
< iop.flags = IOPORT_F_INOUT;
< iop.handler = pci_emul_io_handler;
< iop.arg = pdi;
---
> register_bar(pdi, idx);
453,470d579
< for (i = 0; i < size; i++) {
< iop.port = addr + i;
< register_inout(&iop);
< }
< } else if (type == PCIBAR_MEM32 || type == PCIBAR_MEM64) {
< /* add memory bar intercept handler */
< memp.name = pdi->pi_name;
< memp.flags = MEM_F_RW;
< memp.base = addr;
< memp.size = size;
< memp.handler = pci_emul_mem_handler;
< memp.arg1 = pdi;
< memp.arg2 = idx;
<
< error = register_mem(&memp);
< assert(error == 0);
< }
<
1103a1213,1268
> static uint32_t
> bits_changed(uint32_t old, uint32_t new, uint32_t mask)
> {
>
> return ((old ^ new) & mask);
> }
>
> static void
> pci_emul_cmdwrite(struct pci_devinst *pi, uint32_t new, int bytes)
> {
> int i;
> uint16_t old;
>
> /*
> * The command register is at an offset of 4 bytes and thus the
> * guest could write 1, 2 or 4 bytes starting at this offset.
> */
>
> old = pci_get_cfgdata16(pi, PCIR_COMMAND); /* stash old value */
> CFGWRITE(pi, PCIR_COMMAND, new, bytes); /* update config */
> new = pci_get_cfgdata16(pi, PCIR_COMMAND); /* get updated value */
>
> /*
> * If the MMIO or I/O address space decoding has changed then
> * register/unregister all BARs that decode that address space.
> */
> for (i = 0; i < PCI_BARMAX; i++) {
> switch (pi->pi_bar[i].type) {
> case PCIBAR_NONE:
> case PCIBAR_MEMHI64:
> break;
> case PCIBAR_IO:
> /* I/O address space decoding changed? */
> if (bits_changed(old, new, PCIM_CMD_PORTEN)) {
> if (porten(pi))
> register_bar(pi, i);
> else
> unregister_bar(pi, i);
> }
> break;
> case PCIBAR_MEM32:
> case PCIBAR_MEM64:
> /* MMIO address space decoding changed? */
> if (bits_changed(old, new, PCIM_CMD_MEMEN)) {
> if (memen(pi))
> register_bar(pi, i);
> else
> unregister_bar(pi, i);
> }
> break;
> default:
> assert(0);
> }
> }
> }
>
1111c1276
< uint64_t mask, bar;
---
> uint64_t addr, bar, mask;
1177a1343
> mask = ~(pi->pi_bar[idx].size - 1);
1180c1346
< bar = 0;
---
> pi->pi_bar[idx].addr = bar = 0;
1183,1185c1349,1358
< mask = ~(pi->pi_bar[idx].size - 1);
< mask &= PCIM_BAR_IO_BASE;
< bar = (*eax & mask) | PCIM_BAR_IO_SPACE;
---
> addr = *eax & mask;
> addr &= 0xffff;
> bar = addr | PCIM_BAR_IO_SPACE;
> /*
> * Register the new BAR value for interception
> */
> if (addr != pi->pi_bar[idx].addr) {
> update_bar_address(pi, addr, idx,
> PCIBAR_IO);
> }
1188,1190c1361
< mask = ~(pi->pi_bar[idx].size - 1);
< mask &= PCIM_BAR_MEM_BASE;
< bar = *eax & mask;
---
> addr = bar = *eax & mask;
1191a1363,1366
> if (addr != pi->pi_bar[idx].addr) {
> update_bar_address(pi, addr, idx,
> PCIBAR_MEM32);
> }
1194,1196c1369
< mask = ~(pi->pi_bar[idx].size - 1);
< mask &= PCIM_BAR_MEM_BASE;
< bar = *eax & mask;
---
> addr = bar = *eax & mask;
1198a1372,1375
> if (addr != (uint32_t)pi->pi_bar[idx].addr) {
> update_bar_address(pi, addr, idx,
> PCIBAR_MEM64);
> }
1202,1204c1379,1384
< mask &= PCIM_BAR_MEM_BASE;
< bar = ((uint64_t)*eax << 32) & mask;
< bar = bar >> 32;
---
> addr = ((uint64_t)*eax << 32) & mask;
> bar = addr >> 32;
> if (bar != pi->pi_bar[idx - 1].addr >> 32) {
> update_bar_address(pi, addr, idx - 1,
> PCIBAR_MEMHI64);
> }
1212a1393,1394
> } else if (coff == PCIR_COMMAND) {
> pci_emul_cmdwrite(pi, *eax, bytes);