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