diff --git a/hw/pass-through.c b/hw/pass-through.c index 919937f..1378022 100644 --- a/hw/pass-through.c +++ b/hw/pass-through.c @@ -237,6 +237,14 @@ static int pt_bar_reg_restore(struct pt_dev *ptdev, static int pt_exp_rom_bar_reg_restore(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t real_offset, uint32_t dev_value, uint32_t *value); +static int pt_intel_opregion_read(struct pt_dev *ptdev, + struct pt_reg_tbl *cfg_entry, + uint32_t *value, uint32_t valid_mask); +static int pt_intel_opregion_write(struct pt_dev *ptdev, + struct pt_reg_tbl *cfg_entry, + uint32_t *value, uint32_t dev_value, uint32_t valid_mask); +static uint8_t pt_reg_grp_header0_size_init(struct pt_dev *ptdev, + struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset); /* pt_reg_info_tbl declaration * - only for emulated register (either a part or whole bit). @@ -443,6 +451,18 @@ static struct pt_reg_info_tbl pt_emu_reg_header0_tbl[] = { .u.dw.write = pt_exp_rom_bar_reg_write, .u.dw.restore = pt_exp_rom_bar_reg_restore, }, + /* Vendor ID reg */ + { + .offset = PCI_INTEL_OPREGION, + .size = 4, + .init_val = 0x0000, + .ro_mask = 0xFFFFFFFF, + .emu_mask = 0xFFFFFFFF, + .init = pt_common_reg_init, + .u.dw.read = pt_intel_opregion_read, + .u.dw.write = pt_intel_opregion_write, + .u.dw.restore = NULL, + }, { .size = 0, }, @@ -736,7 +756,7 @@ static const struct pt_reg_grp_info_tbl pt_emu_reg_grp_tbl[] = { .grp_id = 0xFF, .grp_type = GRP_TYPE_EMU, .grp_size = 0x40, - .size_init = pt_reg_grp_size_init, + .size_init = pt_reg_grp_header0_size_init, .emu_reg_tbl= pt_emu_reg_header0_tbl, }, /* PCI PowerManagement Capability reg group */ @@ -1400,7 +1420,7 @@ static struct pt_reg_grp_tbl* pt_find_reg_grp(struct pt_dev *ptdev, { /* check address */ if ((reg_grp_entry->base_offset <= address) && - ((reg_grp_entry->base_offset + reg_grp_entry->size) > address)) + ((reg_grp_entry->base_offset + reg_grp_entry->size) >= address)) goto out; } /* group entry not found */ @@ -1455,8 +1475,7 @@ out: return index; } -static void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, - int len) +void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { struct pt_dev *assigned_device = (struct pt_dev *)d; struct pci_dev *pci_dev = assigned_device->pci_dev; @@ -1637,7 +1656,7 @@ exit: return; } -static uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len) +uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len) { struct pt_dev *assigned_device = (struct pt_dev *)d; struct pci_dev *pci_dev = assigned_device->pci_dev; @@ -2965,6 +2984,14 @@ static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev, return reg->init_val; } +static uint8_t pt_reg_grp_header0_size_init(struct pt_dev *ptdev, + struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset) +{ + if (igd_passthru) + return 0xFF; + return grp_reg->grp_size; +} + /* get register group size */ static uint8_t pt_reg_grp_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset) @@ -4113,6 +4140,21 @@ static int pt_pmcsr_reg_restore(struct pt_dev *ptdev, return 0; } +static int pt_intel_opregion_read(struct pt_dev *ptdev, + struct pt_reg_tbl *cfg_entry, + uint32_t *value, uint32_t valid_mask) +{ + *value = igd_read_opregion(ptdev); + return 0; +} + +static int pt_intel_opregion_write(struct pt_dev *ptdev, + struct pt_reg_tbl *cfg_entry, + uint32_t *value, uint32_t dev_value, uint32_t valid_mask) +{ + igd_write_opregion(ptdev, *value); + return 0; +} static struct pt_dev * register_real_device(PCIBus *e_bus, const char *e_dev_name, int e_devfn, uint8_t r_bus, uint8_t r_dev, uint8_t r_func, uint32_t machine_irq, struct pci_access *pci_access, diff --git a/hw/pass-through.h b/hw/pass-through.h index 884139c..9ab9638 100644 --- a/hw/pass-through.h +++ b/hw/pass-through.h @@ -422,6 +422,10 @@ PCIBus *intel_pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, const char *name, uint16_t revision); void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, uint32_t val, int len); uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len); +uint32_t igd_read_opregion(struct pt_dev *pci_dev); +void igd_write_opregion(struct pt_dev *real_dev, uint32_t val); +uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len); +void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len); #endif /* __PASSTHROUGH_H__ */ diff --git a/hw/pt-graphics.c b/hw/pt-graphics.c index fec7390..2e1dc44 100644 --- a/hw/pt-graphics.c +++ b/hw/pt-graphics.c @@ -13,6 +13,8 @@ extern int gfx_passthru; extern int igd_passthru; +static uint32_t igd_guest_opregion = 0; + static int pch_map_irq(PCIDevice *pci_dev, int irq_num) { PT_LOG("pch_map_irq called\n"); @@ -37,6 +39,54 @@ void intel_pch_init(PCIBus *bus) pch_map_irq, "intel_bridge_1f"); } +uint32_t igd_read_opregion(struct pt_dev *pci_dev) +{ + uint32_t val = -1; + + if ( igd_guest_opregion ) + val = pt_pci_read_config((PCIDevice*)pci_dev, PCI_INTEL_OPREGION, 4); + +#ifdef PT_DEBUG_PCI_CONFIG_ACCESS + PT_LOG_DEV((PCIDevice*)pci_dev, "addr=%x len=%x val=%x\n", + PCI_INTEL_OPREGION, 4, val); +#endif + return val; +} + +void igd_write_opregion(struct pt_dev *real_dev, uint32_t val) +{ + uint32_t host_opregion = 0; + int ret; + + if ( igd_guest_opregion ) + { + PT_LOG("opregion register already been set, ignoring %x\n", val); + return; + } + + host_opregion = pt_pci_host_read(real_dev->pci_dev, + PCI_INTEL_OPREGION, 4); + igd_guest_opregion = (val & ~0xfff) | (host_opregion & 0xfff); + PT_LOG("Map OpRegion: %x -> %x\n", host_opregion, igd_guest_opregion); + + ret = xc_domain_memory_mapping(xc_handle, domid, + igd_guest_opregion >> XC_PAGE_SHIFT, + host_opregion >> XC_PAGE_SHIFT, + 2, + DPCI_ADD_MAPPING); + + if ( ret != 0 ) + { + PT_LOG("Error: Can't map opregion\n"); + igd_guest_opregion = 0; + } +#ifdef PT_DEBUG_PCI_CONFIG_ACCESS + PT_LOG_DEV((PCIDevice*)real_dev, "addr=%x len=%lx val=%x\n", + PCI_INTEL_OPREGION, len, val); +#endif + +} + void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, uint32_t val, int len) { struct pci_dev *pci_dev_host_bridge = pt_pci_get_dev(0, 0, 0); @@ -99,7 +149,6 @@ uint32_t igd_pci_read(PCIDevice *pci_dev, uint32_t config_addr, int len) int register_vga_regions(struct pt_dev *real_device) { u16 vendor_id; - int igd_opregion; int ret = 0; if ( !gfx_passthru || real_device->pci_dev->device_class != 0x0300 ) @@ -117,19 +166,6 @@ int register_vga_regions(struct pt_dev *real_device) 0x20, DPCI_ADD_MAPPING); - /* 1:1 map ASL Storage register value */ - vendor_id = pt_pci_host_read(real_device->pci_dev, 0, 2); - igd_opregion = pt_pci_host_read(real_device->pci_dev, PCI_INTEL_OPREGION, 4); - if ( (vendor_id == PCI_VENDOR_ID_INTEL ) && igd_opregion ) - { - ret |= xc_domain_memory_mapping(xc_handle, domid, - igd_opregion >> XC_PAGE_SHIFT, - igd_opregion >> XC_PAGE_SHIFT, - 2, - DPCI_ADD_MAPPING); - PT_LOG("register_vga: igd_opregion = %x\n", igd_opregion); - } - if ( ret != 0 ) PT_LOG("VGA region mapping failed\n"); @@ -141,7 +177,7 @@ int register_vga_regions(struct pt_dev *real_device) */ int unregister_vga_regions(struct pt_dev *real_device) { - u32 vendor_id, igd_opregion; + u32 vendor_id; int ret = 0; if ( !gfx_passthru || real_device->pci_dev->device_class != 0x0300 ) @@ -160,12 +196,11 @@ int unregister_vga_regions(struct pt_dev *real_device) DPCI_REMOVE_MAPPING); vendor_id = pt_pci_host_read(real_device->pci_dev, PCI_VENDOR_ID, 2); - igd_opregion = pt_pci_host_read(real_device->pci_dev, PCI_INTEL_OPREGION, 4); - if ( (vendor_id == PCI_VENDOR_ID_INTEL) && igd_opregion ) + if ( (vendor_id == PCI_VENDOR_ID_INTEL) && igd_guest_opregion ) { ret |= xc_domain_memory_mapping(xc_handle, domid, - igd_opregion >> XC_PAGE_SHIFT, - igd_opregion >> XC_PAGE_SHIFT, + igd_guest_opregion >> XC_PAGE_SHIFT, + igd_guest_opregion >> XC_PAGE_SHIFT, 2, DPCI_REMOVE_MAPPING); }