Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_emul.c
Show All 27 Lines | ||||||||||||||
* $FreeBSD$ | * $FreeBSD$ | |||||||||||||
*/ | */ | |||||||||||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | |||||||||||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | |||||||||||||
#include <sys/param.h> | #include <sys/param.h> | |||||||||||||
#include <sys/linker_set.h> | #include <sys/linker_set.h> | |||||||||||||
#include <sys/mman.h> | ||||||||||||||
#include <ctype.h> | #include <ctype.h> | |||||||||||||
#include <err.h> | #include <err.h> | |||||||||||||
#include <errno.h> | #include <errno.h> | |||||||||||||
#include <err.h> | ||||||||||||||
#include <pthread.h> | #include <pthread.h> | |||||||||||||
#include <stdio.h> | #include <stdio.h> | |||||||||||||
#include <stdlib.h> | #include <stdlib.h> | |||||||||||||
#include <string.h> | #include <string.h> | |||||||||||||
#include <strings.h> | #include <strings.h> | |||||||||||||
#include <assert.h> | #include <assert.h> | |||||||||||||
#include <stdbool.h> | #include <stdbool.h> | |||||||||||||
#include <sysexits.h> | #include <sysexits.h> | |||||||||||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | struct businfo { | |||||||||||||
struct slotinfo slotinfo[MAXSLOTS]; | struct slotinfo slotinfo[MAXSLOTS]; | |||||||||||||
}; | }; | |||||||||||||
static struct businfo *pci_businfo[MAXBUSES]; | static struct businfo *pci_businfo[MAXBUSES]; | |||||||||||||
SET_DECLARE(pci_devemu_set, struct pci_devemu); | SET_DECLARE(pci_devemu_set, struct pci_devemu); | |||||||||||||
static uint64_t pci_emul_iobase; | static uint64_t pci_emul_iobase; | |||||||||||||
static uint8_t *pci_emul_rombase; | ||||||||||||||
static uint64_t pci_emul_romoffset; | ||||||||||||||
static uint8_t *pci_emul_romlim; | ||||||||||||||
static uint64_t pci_emul_membase32; | static uint64_t pci_emul_membase32; | |||||||||||||
static uint64_t pci_emul_membase64; | static uint64_t pci_emul_membase64; | |||||||||||||
static uint64_t pci_emul_memlim64; | static uint64_t pci_emul_memlim64; | |||||||||||||
struct pci_bar_allocation { | struct pci_bar_allocation { | |||||||||||||
TAILQ_ENTRY(pci_bar_allocation) chain; | TAILQ_ENTRY(pci_bar_allocation) chain; | |||||||||||||
struct pci_devinst *pdi; | struct pci_devinst *pdi; | |||||||||||||
int idx; | int idx; | |||||||||||||
enum pcibar_type type; | enum pcibar_type type; | |||||||||||||
uint64_t size; | uint64_t size; | |||||||||||||
}; | }; | |||||||||||||
TAILQ_HEAD(pci_bar_list, pci_bar_allocation) pci_bars = TAILQ_HEAD_INITIALIZER( | TAILQ_HEAD(pci_bar_list, pci_bar_allocation) pci_bars = TAILQ_HEAD_INITIALIZER( | |||||||||||||
pci_bars); | pci_bars); | |||||||||||||
#define PCI_EMUL_IOBASE 0x2000 | #define PCI_EMUL_IOBASE 0x2000 | |||||||||||||
#define PCI_EMUL_IOLIMIT 0x10000 | #define PCI_EMUL_IOLIMIT 0x10000 | |||||||||||||
#define PCI_EMUL_ROMSIZE 0x10000000 | ||||||||||||||
#define PCI_EMUL_ECFG_BASE 0xE0000000 /* 3.5GB */ | #define PCI_EMUL_ECFG_BASE 0xE0000000 /* 3.5GB */ | |||||||||||||
#define PCI_EMUL_ECFG_SIZE (MAXBUSES * 1024 * 1024) /* 1MB per bus */ | #define PCI_EMUL_ECFG_SIZE (MAXBUSES * 1024 * 1024) /* 1MB per bus */ | |||||||||||||
SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE); | SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE); | |||||||||||||
/* | /* | |||||||||||||
* OVMF always uses 0xC0000000 as base address for 32 bit PCI MMIO. Don't | * OVMF always uses 0xC0000000 as base address for 32 bit PCI MMIO. Don't | |||||||||||||
* change this address without changing it in OVMF. | * change this address without changing it in OVMF. | |||||||||||||
*/ | */ | |||||||||||||
▲ Show 20 Lines • Show All 428 Lines • ▼ Show 20 Lines | if (registration) { | |||||||||||||
mr.arg2 = idx; | mr.arg2 = idx; | |||||||||||||
error = register_mem(&mr); | error = register_mem(&mr); | |||||||||||||
} else | } else | |||||||||||||
error = unregister_mem(&mr); | error = unregister_mem(&mr); | |||||||||||||
if (pe->pe_baraddr != NULL) | if (pe->pe_baraddr != NULL) | |||||||||||||
(*pe->pe_baraddr)(pi->pi_vmctx, pi, idx, registration, | (*pe->pe_baraddr)(pi->pi_vmctx, pi, idx, registration, | |||||||||||||
pi->pi_bar[idx].addr); | pi->pi_bar[idx].addr); | |||||||||||||
break; | break; | |||||||||||||
case PCIBAR_ROM: | ||||||||||||||
error = 0; | ||||||||||||||
if (pe->pe_baraddr != NULL) | ||||||||||||||
(*pe->pe_baraddr)(pi->pi_vmctx, pi, idx, registration, | ||||||||||||||
pi->pi_bar[idx].addr); | ||||||||||||||
break; | ||||||||||||||
default: | default: | |||||||||||||
error = EINVAL; | error = EINVAL; | |||||||||||||
break; | break; | |||||||||||||
} | } | |||||||||||||
assert(error == 0); | assert(error == 0); | |||||||||||||
} | } | |||||||||||||
static void | static void | |||||||||||||
unregister_bar(struct pci_devinst *pi, int idx) | unregister_bar(struct pci_devinst *pi, int idx) | |||||||||||||
{ | { | |||||||||||||
modify_bar_registration(pi, idx, 0); | modify_bar_registration(pi, idx, 0); | |||||||||||||
} | } | |||||||||||||
static void | static void | |||||||||||||
register_bar(struct pci_devinst *pi, int idx) | register_bar(struct pci_devinst *pi, int idx) | |||||||||||||
{ | { | |||||||||||||
modify_bar_registration(pi, idx, 1); | modify_bar_registration(pi, idx, 1); | |||||||||||||
} | } | |||||||||||||
/* Is the ROM enabled for the emulated pci device? */ | ||||||||||||||
static int | ||||||||||||||
romen(struct pci_devinst *pi) | ||||||||||||||
{ | ||||||||||||||
return (pi->pi_bar[PCI_ROM_IDX].lobits & PCIM_BIOS_ENABLE) == | ||||||||||||||
PCIM_BIOS_ENABLE; | ||||||||||||||
} | ||||||||||||||
/* Are we decoding i/o port accesses for the emulated pci device? */ | /* Are we decoding i/o port accesses for the emulated pci device? */ | |||||||||||||
static int | static int | |||||||||||||
porten(struct pci_devinst *pi) | porten(struct pci_devinst *pi) | |||||||||||||
{ | { | |||||||||||||
uint16_t cmd; | uint16_t cmd; | |||||||||||||
cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); | cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); | |||||||||||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | update_bar_address(struct pci_devinst *pi, uint64_t addr, int idx, int type) | |||||||||||||
if (decode) | if (decode) | |||||||||||||
register_bar(pi, idx); | register_bar(pi, idx); | |||||||||||||
} | } | |||||||||||||
int | int | |||||||||||||
pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type, | pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type, | |||||||||||||
uint64_t size) | uint64_t size) | |||||||||||||
{ | { | |||||||||||||
assert(idx >= 0 && idx <= PCI_BARMAX); | if ((type != PCIBAR_ROM) && (idx < 0 || idx > PCI_BARMAX)) { | |||||||||||||
errx(4, "Illegal BAR idx"); | ||||||||||||||
} else if ((type == PCIBAR_ROM) && (idx != PCI_ROM_IDX)) { | ||||||||||||||
errx(4, "Illegal ROM idx"); | ||||||||||||||
} | ||||||||||||||
if ((size & (size - 1)) != 0) | if ((size & (size - 1)) != 0) | |||||||||||||
size = 1UL << flsl(size); /* round up to a power of 2 */ | size = 1UL << flsl(size); /* round up to a power of 2 */ | |||||||||||||
/* Enforce minimum BAR sizes required by the PCI standard */ | /* Enforce minimum BAR sizes required by the PCI standard */ | |||||||||||||
if (type == PCIBAR_IO) { | if (type == PCIBAR_IO) { | |||||||||||||
if (size < 4) | if (size < 4) | |||||||||||||
size = 4; | size = 4; | |||||||||||||
} else if (type == PCIBAR_ROM) { | ||||||||||||||
if (size < ~PCIM_BIOS_ADDR_MASK + 1) | ||||||||||||||
size = ~PCIM_BIOS_ADDR_MASK + 1; | ||||||||||||||
} else { | } else { | |||||||||||||
if (size < 16) | if (size < 16) | |||||||||||||
size = 16; | size = 16; | |||||||||||||
} | } | |||||||||||||
/* | /* | |||||||||||||
* To reduce fragmentation of the MMIO space, we allocate the BARs by | * To reduce fragmentation of the MMIO space, we allocate the BARs by | |||||||||||||
* size. Therefore, don't allocate the BAR yet. We create a list of all | * size. Therefore, don't allocate the BAR yet. We create a list of all | |||||||||||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type, | |||||||||||||
*/ | */ | |||||||||||||
uint16_t enbit = 0; | uint16_t enbit = 0; | |||||||||||||
switch (type) { | switch (type) { | |||||||||||||
case PCIBAR_IO: | case PCIBAR_IO: | |||||||||||||
enbit = PCIM_CMD_PORTEN; | enbit = PCIM_CMD_PORTEN; | |||||||||||||
break; | break; | |||||||||||||
case PCIBAR_MEM64: | case PCIBAR_MEM64: | |||||||||||||
case PCIBAR_MEM32: | case PCIBAR_MEM32: | |||||||||||||
case PCIBAR_ROM: | ||||||||||||||
enbit = PCIM_CMD_MEMEN; | enbit = PCIM_CMD_MEMEN; | |||||||||||||
break; | break; | |||||||||||||
default: | default: | |||||||||||||
enbit = 0; | enbit = 0; | |||||||||||||
break; | break; | |||||||||||||
} | } | |||||||||||||
const uint16_t cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND); | const uint16_t cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND); | |||||||||||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | case PCIBAR_MEM64: | |||||||||||||
} | } | |||||||||||||
break; | break; | |||||||||||||
case PCIBAR_MEM32: | case PCIBAR_MEM32: | |||||||||||||
baseptr = &pci_emul_membase32; | baseptr = &pci_emul_membase32; | |||||||||||||
limit = PCI_EMUL_MEMLIMIT32; | limit = PCI_EMUL_MEMLIMIT32; | |||||||||||||
mask = PCIM_BAR_MEM_BASE; | mask = PCIM_BAR_MEM_BASE; | |||||||||||||
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32; | lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32; | |||||||||||||
break; | break; | |||||||||||||
case PCIBAR_ROM: | ||||||||||||||
/* do not claim memory for ROM. OVMF will do it for us. */ | ||||||||||||||
baseptr = NULL; | ||||||||||||||
limit = 0; | ||||||||||||||
mask = PCIM_BIOS_ADDR_MASK; | ||||||||||||||
lobits = 0; | ||||||||||||||
break; | ||||||||||||||
default: | default: | |||||||||||||
printf("pci_emul_alloc_base: invalid bar type %d\n", type); | printf("pci_emul_alloc_base: invalid bar type %d\n", type); | |||||||||||||
assert(0); | assert(0); | |||||||||||||
} | } | |||||||||||||
if (baseptr != NULL) { | if (baseptr != NULL) { | |||||||||||||
error = pci_emul_alloc_resource(baseptr, limit, size, &addr); | error = pci_emul_alloc_resource(baseptr, limit, size, &addr); | |||||||||||||
if (error != 0) | if (error != 0) | |||||||||||||
Show All 15 Lines | pci_emul_assign_bar(struct pci_devinst *const pdi, const int idx, | |||||||||||||
/* Initialize the BAR register in config space */ | /* Initialize the BAR register in config space */ | |||||||||||||
bar = (addr & mask) | lobits; | bar = (addr & mask) | lobits; | |||||||||||||
pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar); | pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar); | |||||||||||||
if (type == PCIBAR_MEM64) { | if (type == PCIBAR_MEM64) { | |||||||||||||
assert(idx + 1 <= PCI_BARMAX); | assert(idx + 1 <= PCI_BARMAX); | |||||||||||||
pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64; | pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64; | |||||||||||||
pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32); | pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32); | |||||||||||||
khngUnsubmitted Done Inline Actions
khng: | ||||||||||||||
} | } | |||||||||||||
if (type != PCIBAR_ROM) { | ||||||||||||||
register_bar(pdi, idx); | register_bar(pdi, idx); | |||||||||||||
} | ||||||||||||||
return (0); | return (0); | |||||||||||||
} | } | |||||||||||||
int | ||||||||||||||
pci_emul_alloc_rom(struct pci_devinst *const pdi, const uint64_t size, | ||||||||||||||
void **const addr) | ||||||||||||||
{ | ||||||||||||||
/* allocate ROM space once on first call */ | ||||||||||||||
if (pci_emul_rombase == 0) { | ||||||||||||||
pci_emul_rombase = vm_create_devmem(pdi->pi_vmctx, VM_PCIROM, | ||||||||||||||
"pcirom", PCI_EMUL_ROMSIZE); | ||||||||||||||
if (pci_emul_rombase == MAP_FAILED) { | ||||||||||||||
warnx("%s: failed to create rom segment", __func__); | ||||||||||||||
return (-1); | ||||||||||||||
} | ||||||||||||||
pci_emul_romlim = pci_emul_rombase + PCI_EMUL_ROMSIZE; | ||||||||||||||
pci_emul_romoffset = 0; | ||||||||||||||
} | ||||||||||||||
/* ROM size should be a power of 2 and greater than 2 KB */ | ||||||||||||||
const uint64_t rom_size = MAX(1UL << flsl(size), | ||||||||||||||
~PCIM_BIOS_ADDR_MASK + 1); | ||||||||||||||
/* check if ROM fits into ROM space */ | ||||||||||||||
if (pci_emul_romoffset + rom_size > PCI_EMUL_ROMSIZE) { | ||||||||||||||
warnx("%s: no space left in rom segment:", __func__); | ||||||||||||||
warnx("%16lu bytes left", | ||||||||||||||
PCI_EMUL_ROMSIZE - pci_emul_romoffset); | ||||||||||||||
warnx("%16lu bytes required by %d/%d/%d", rom_size, pdi->pi_bus, | ||||||||||||||
pdi->pi_slot, pdi->pi_func); | ||||||||||||||
return (-1); | ||||||||||||||
} | ||||||||||||||
/* allocate ROM BAR */ | ||||||||||||||
const int error = pci_emul_alloc_bar(pdi, PCI_ROM_IDX, PCIBAR_ROM, | ||||||||||||||
rom_size); | ||||||||||||||
if (error) | ||||||||||||||
return error; | ||||||||||||||
/* return address */ | ||||||||||||||
*addr = pci_emul_rombase + pci_emul_romoffset; | ||||||||||||||
/* save offset into ROM Space */ | ||||||||||||||
pdi->pi_romoffset = pci_emul_romoffset; | ||||||||||||||
/* increase offset for next ROM */ | ||||||||||||||
pci_emul_romoffset += rom_size; | ||||||||||||||
return (0); | ||||||||||||||
} | ||||||||||||||
#define CAP_START_OFFSET 0x40 | #define CAP_START_OFFSET 0x40 | |||||||||||||
static int | static int | |||||||||||||
pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen) | pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen) | |||||||||||||
{ | { | |||||||||||||
int i, capoff, reallen; | int i, capoff, reallen; | |||||||||||||
uint16_t sts; | uint16_t sts; | |||||||||||||
assert(caplen > 0); | assert(caplen > 0); | |||||||||||||
▲ Show 20 Lines • Show All 1,057 Lines • ▼ Show 20 Lines | pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old) | |||||||||||||
new = pci_get_cfgdata16(pi, PCIR_COMMAND); | new = pci_get_cfgdata16(pi, PCIR_COMMAND); | |||||||||||||
changed = old ^ new; | changed = old ^ new; | |||||||||||||
/* | /* | |||||||||||||
* If the MMIO or I/O address space decoding has changed then | * If the MMIO or I/O address space decoding has changed then | |||||||||||||
* register/unregister all BARs that decode that address space. | * register/unregister all BARs that decode that address space. | |||||||||||||
*/ | */ | |||||||||||||
for (i = 0; i <= PCI_BARMAX; i++) { | for (i = 0; i <= PCI_BARMAX_WITH_ROM; i++) { | |||||||||||||
switch (pi->pi_bar[i].type) { | switch (pi->pi_bar[i].type) { | |||||||||||||
case PCIBAR_NONE: | case PCIBAR_NONE: | |||||||||||||
case PCIBAR_MEMHI64: | case PCIBAR_MEMHI64: | |||||||||||||
break; | break; | |||||||||||||
case PCIBAR_IO: | case PCIBAR_IO: | |||||||||||||
/* I/O address space decoding changed? */ | /* I/O address space decoding changed? */ | |||||||||||||
if (changed & PCIM_CMD_PORTEN) { | if (changed & PCIM_CMD_PORTEN) { | |||||||||||||
if (new & PCIM_CMD_PORTEN) | if (new & PCIM_CMD_PORTEN) | |||||||||||||
register_bar(pi, i); | register_bar(pi, i); | |||||||||||||
else | else | |||||||||||||
unregister_bar(pi, i); | unregister_bar(pi, i); | |||||||||||||
} | } | |||||||||||||
break; | break; | |||||||||||||
case PCIBAR_ROM: | ||||||||||||||
/* skip (un-)register of ROM if it disabled */ | ||||||||||||||
if (!romen(pi)) | ||||||||||||||
break; | ||||||||||||||
/* fallthrough */ | ||||||||||||||
case PCIBAR_MEM32: | case PCIBAR_MEM32: | |||||||||||||
case PCIBAR_MEM64: | case PCIBAR_MEM64: | |||||||||||||
/* MMIO address space decoding changed? */ | /* MMIO address space decoding changed? */ | |||||||||||||
if (changed & PCIM_CMD_MEMEN) { | if (changed & PCIM_CMD_MEMEN) { | |||||||||||||
if (new & PCIM_CMD_MEMEN) | if (new & PCIM_CMD_MEMEN) | |||||||||||||
register_bar(pi, i); | register_bar(pi, i); | |||||||||||||
else | else | |||||||||||||
unregister_bar(pi, i); | unregister_bar(pi, i); | |||||||||||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | if (in) { | |||||||||||||
pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax); | pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax); | |||||||||||||
} else { | } else { | |||||||||||||
/* Let the device emulation override the default handler */ | /* Let the device emulation override the default handler */ | |||||||||||||
if (pe->pe_cfgwrite != NULL && | if (pe->pe_cfgwrite != NULL && | |||||||||||||
(*pe->pe_cfgwrite)(ctx, vcpu, pi, coff, bytes, *eax) == 0) | (*pe->pe_cfgwrite)(ctx, vcpu, pi, coff, bytes, *eax) == 0) | |||||||||||||
return; | return; | |||||||||||||
/* | /* | |||||||||||||
* Special handling for write to BAR registers | * Special handling for write to BAR and ROM registers | |||||||||||||
*/ | */ | |||||||||||||
if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) { | if ((coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) || | |||||||||||||
(coff >= PCIR_BIOS && coff < PCIR_BIOS + 4)) { | ||||||||||||||
/* | /* | |||||||||||||
* Ignore writes to BAR registers that are not | * Ignore writes to BAR registers that are not | |||||||||||||
* 4-byte aligned. | * 4-byte aligned. | |||||||||||||
*/ | */ | |||||||||||||
if (bytes != 4 || (coff & 0x3) != 0) | if (bytes != 4 || (coff & 0x3) != 0) | |||||||||||||
return; | return; | |||||||||||||
if (coff != PCIR_BIOS) { | ||||||||||||||
idx = (coff - PCIR_BAR(0)) / 4; | idx = (coff - PCIR_BAR(0)) / 4; | |||||||||||||
} else { | ||||||||||||||
idx = PCI_ROM_IDX; | ||||||||||||||
} | ||||||||||||||
mask = ~(pi->pi_bar[idx].size - 1); | mask = ~(pi->pi_bar[idx].size - 1); | |||||||||||||
switch (pi->pi_bar[idx].type) { | switch (pi->pi_bar[idx].type) { | |||||||||||||
case PCIBAR_NONE: | case PCIBAR_NONE: | |||||||||||||
pi->pi_bar[idx].addr = bar = 0; | pi->pi_bar[idx].addr = bar = 0; | |||||||||||||
break; | break; | |||||||||||||
case PCIBAR_IO: | case PCIBAR_IO: | |||||||||||||
addr = *eax & mask; | addr = *eax & mask; | |||||||||||||
addr &= 0xffff; | addr &= 0xffff; | |||||||||||||
Show All 25 Lines | if ((coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) || | |||||||||||||
case PCIBAR_MEMHI64: | case PCIBAR_MEMHI64: | |||||||||||||
mask = ~(pi->pi_bar[idx - 1].size - 1); | mask = ~(pi->pi_bar[idx - 1].size - 1); | |||||||||||||
addr = ((uint64_t)*eax << 32) & mask; | addr = ((uint64_t)*eax << 32) & mask; | |||||||||||||
bar = addr >> 32; | bar = addr >> 32; | |||||||||||||
if (bar != pi->pi_bar[idx - 1].addr >> 32) { | if (bar != pi->pi_bar[idx - 1].addr >> 32) { | |||||||||||||
update_bar_address(pi, addr, idx - 1, | update_bar_address(pi, addr, idx - 1, | |||||||||||||
PCIBAR_MEMHI64); | PCIBAR_MEMHI64); | |||||||||||||
} | } | |||||||||||||
break; | ||||||||||||||
case PCIBAR_ROM: | ||||||||||||||
addr = bar = *eax & mask; | ||||||||||||||
if (memen(pi) && romen(pi)) { | ||||||||||||||
unregister_bar(pi, idx); | ||||||||||||||
} | ||||||||||||||
pi->pi_bar[idx].addr = addr; | ||||||||||||||
pi->pi_bar[idx].lobits = *eax & | ||||||||||||||
PCIM_BIOS_ENABLE; | ||||||||||||||
/* romen could have changed it value */ | ||||||||||||||
if (memen(pi) && romen(pi)) { | ||||||||||||||
register_bar(pi, idx); | ||||||||||||||
} | ||||||||||||||
bar |= pi->pi_bar[idx].lobits; | ||||||||||||||
break; | break; | |||||||||||||
default: | default: | |||||||||||||
assert(0); | assert(0); | |||||||||||||
} | } | |||||||||||||
pci_set_cfgdata32(pi, coff, bar); | pci_set_cfgdata32(pi, coff, bar); | |||||||||||||
} else if (pci_emul_iscap(pi, coff)) { | } else if (pci_emul_iscap(pi, coff)) { | |||||||||||||
pci_emul_capwrite(pi, coff, bytes, *eax, 0, 0); | pci_emul_capwrite(pi, coff, bytes, *eax, 0, 0); | |||||||||||||
▲ Show 20 Lines • Show All 437 Lines • Show Last 20 Lines |