Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_emul.c
Show First 20 Lines • Show All 453 Lines • ▼ Show 20 Lines | ||||||||||||||
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) | |||||||||||||
{ | { | |||||||||||||
return (pci_emul_alloc_pbar(pdi, idx, 0, type, size)); | return (pci_emul_alloc_pbar(pdi, idx, 0, type, size)); | |||||||||||||
} | } | |||||||||||||
static bool | ||||||||||||||
is_passthru(struct pci_devinst *pi) | ||||||||||||||
{ | ||||||||||||||
if (strcmp(pi->pi_d->pe_emu, "passthru") == 0) | ||||||||||||||
return true; | ||||||||||||||
else | ||||||||||||||
return false; | ||||||||||||||
} | ||||||||||||||
/* | /* | |||||||||||||
* Register (or unregister) the MMIO or I/O region associated with the BAR | * Register (or unregister) the MMIO or I/O region associated with the BAR | |||||||||||||
* register 'idx' of an emulated pci device. | * register 'idx' of an emulated pci device. | |||||||||||||
*/ | */ | |||||||||||||
static void | static void | |||||||||||||
modify_bar_registration(struct pci_devinst *pi, int idx, int registration) | modify_bar_registration(struct pci_devinst *pi, int idx, int registration) | |||||||||||||
{ | { | |||||||||||||
int error; | int error; | |||||||||||||
Show All 34 Lines | default: | |||||||||||||
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) | |||||||||||||
{ | { | |||||||||||||
if (!is_passthru(pi)) | ||||||||||||||
modify_bar_registration(pi, idx, 0); | modify_bar_registration(pi, idx, 0); | |||||||||||||
else | ||||||||||||||
unregister_bar_passthru(pi, idx); | ||||||||||||||
} | } | |||||||||||||
static void | static void | |||||||||||||
register_bar(struct pci_devinst *pi, int idx) | register_bar(struct pci_devinst *pi, int idx) | |||||||||||||
{ | { | |||||||||||||
if (!is_passthru(pi)) | ||||||||||||||
modify_bar_registration(pi, idx, 1); | modify_bar_registration(pi, idx, 1); | |||||||||||||
else | ||||||||||||||
register_bar_passthru(pi, idx); | ||||||||||||||
} | } | |||||||||||||
/* 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; | |||||||||||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase, | |||||||||||||
/* 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: | ||||||||||||||
} | } | |||||||||||||
cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND); | cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND); | |||||||||||||
if (is_passthru(pdi)) { | ||||||||||||||
if ((cmd & enbit) == enbit && idx != pci_msix_table_bar(pdi)) | ||||||||||||||
register_bar(pdi, idx); | ||||||||||||||
} | ||||||||||||||
else { | ||||||||||||||
if ((cmd & enbit) != enbit) | if ((cmd & enbit) != enbit) | |||||||||||||
pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit); | pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit); | |||||||||||||
register_bar(pdi, idx); | register_bar(pdi, idx); | |||||||||||||
} | ||||||||||||||
return (0); | return (0); | |||||||||||||
} | } | |||||||||||||
// mask should be a power of 2 minus 1 (e.g. 0x000FFFFF) | ||||||||||||||
uint64_t | ||||||||||||||
pci_emul_alloc_mmio(enum pcibar_type type, uint64_t size, uint64_t mask) | ||||||||||||||
{ | ||||||||||||||
int error; | ||||||||||||||
error = 1; | ||||||||||||||
uint64_t *baseptr, limit, base; | ||||||||||||||
switch (type) { | ||||||||||||||
case PCIBAR_IO: | ||||||||||||||
baseptr = &pci_emul_iobase; | ||||||||||||||
limit = PCI_EMUL_IOLIMIT; | ||||||||||||||
break; | ||||||||||||||
case PCIBAR_MEM32: | ||||||||||||||
baseptr = &pci_emul_membase32; | ||||||||||||||
limit = PCI_EMUL_MEMLIMIT32; | ||||||||||||||
break; | ||||||||||||||
case PCIBAR_MEM64: | ||||||||||||||
baseptr = &pci_emul_membase64; | ||||||||||||||
limit = PCI_EMUL_MEMLIMIT64; | ||||||||||||||
break; | ||||||||||||||
default: | ||||||||||||||
return 0; | ||||||||||||||
} | ||||||||||||||
// align base | ||||||||||||||
base = (*baseptr + mask) & ~mask; | ||||||||||||||
if (base + size > limit) | ||||||||||||||
return 0; | ||||||||||||||
*baseptr = base + size; | ||||||||||||||
return base; | ||||||||||||||
} | ||||||||||||||
#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,099 Lines • ▼ Show 20 Lines | if (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) || | |||||||||||||
(coff & (bytes - 1)) != 0) { | (coff & (bytes - 1)) != 0) { | |||||||||||||
if (in) | if (in) | |||||||||||||
*eax = 0xffffffff; | *eax = 0xffffffff; | |||||||||||||
return; | return; | |||||||||||||
} | } | |||||||||||||
/* | /* | |||||||||||||
* Ignore all writes beyond the standard config space and return all | * Ignore all writes beyond the standard config space and return all | |||||||||||||
* ones on reads. | * ones on reads for non passthru devices. | |||||||||||||
*/ | */ | |||||||||||||
if (coff >= PCI_REGMAX + 1) { | if (coff >= PCI_REGMAX + 1 && !is_passthru(pi)) { | |||||||||||||
if (in) { | if (in) { | |||||||||||||
*eax = 0xffffffff; | *eax = 0xffffffff; | |||||||||||||
/* | /* | |||||||||||||
* Extended capabilities begin at offset 256 in config | * Extended capabilities begin at offset 256 in config | |||||||||||||
* space. Absence of extended capabilities is signaled | * space. Absence of extended capabilities is signaled | |||||||||||||
* with all 0s in the extended capability header at | * with all 0s in the extended capability header at | |||||||||||||
* offset 256. | * offset 256. | |||||||||||||
*/ | */ | |||||||||||||
Show All 12 Lines | if (in) { | |||||||||||||
/* Let the device emulation override the default handler */ | /* Let the device emulation override the default handler */ | |||||||||||||
if (pe->pe_cfgread != NULL) { | if (pe->pe_cfgread != NULL) { | |||||||||||||
needcfg = pe->pe_cfgread(ctx, vcpu, pi, coff, bytes, | needcfg = pe->pe_cfgread(ctx, vcpu, pi, coff, bytes, | |||||||||||||
eax); | eax); | |||||||||||||
} else { | } else { | |||||||||||||
needcfg = 1; | needcfg = 1; | |||||||||||||
} | } | |||||||||||||
if (needcfg) | if (needcfg) { | |||||||||||||
if (coff <= PCI_REGMAX) | ||||||||||||||
*eax = CFGREAD(pi, coff, bytes); | *eax = CFGREAD(pi, coff, bytes); | |||||||||||||
else if (coff <= PCI_REGMAX + 4) | ||||||||||||||
*eax = 0x00000000; | ||||||||||||||
else | ||||||||||||||
*eax = 0xFFFFFFFF; | ||||||||||||||
} | ||||||||||||||
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; | |||||||||||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) { | |||||||||||||
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); | |||||||||||||
} else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) { | } else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) { | |||||||||||||
pci_emul_cmdsts_write(pi, coff, *eax, bytes); | pci_emul_cmdsts_write(pi, coff, *eax, bytes); | |||||||||||||
} else { | } else if (coff <= PCI_REGMAX) { | |||||||||||||
CFGWRITE(pi, coff, *eax, bytes); | CFGWRITE(pi, coff, *eax, bytes); | |||||||||||||
} | } | |||||||||||||
} | } | |||||||||||||
} | } | |||||||||||||
static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff; | static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff; | |||||||||||||
static int | static int | |||||||||||||
▲ Show 20 Lines • Show All 429 Lines • Show Last 20 Lines |