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 | ||||||||||||||