From cefeffc7e5831b8e17a0e01cd62e0ae920f2a941 Mon Sep 17 00:00:00 2001 From: Jean Guyader Date: Thu, 24 Nov 2011 15:43:59 +0000 Subject: [PATCH] hvmloader: Intel GPU passthrough, reverse OpRegion The Intel GPU uses a two pages NVS region called OpRegion. In order to get full support for the driver in the guest we need to map this region. This patch reserves 2 pages on the top of the memory in the reserved area and mark this region as NVS in the e820. Then we write the address to the config space (offset 0xfc) so the device model can map the OpRegion at this address in the guest. Signed-off-by: Jean Guyader Committed-by: Keir Fraser --- tools/firmware/hvmloader/config.h | 1 + tools/firmware/hvmloader/e820.c | 34 +++++++++++++++++++++++++---- tools/firmware/hvmloader/pci.c | 12 ++++++++++ tools/firmware/hvmloader/pci_regs.h | 2 ++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/tools/firmware/hvmloader/config.h b/tools/firmware/hvmloader/config.h index d911352e82..9cac9c1000 100644 --- a/tools/firmware/hvmloader/config.h +++ b/tools/firmware/hvmloader/config.h @@ -5,6 +5,7 @@ enum virtual_vga { VGA_none, VGA_std, VGA_cirrus, VGA_pt }; extern enum virtual_vga virtual_vga; +extern unsigned long igd_opregion_pgbase; struct bios_config { const char *name; diff --git a/tools/firmware/hvmloader/e820.c b/tools/firmware/hvmloader/e820.c index 3b50dd015d..0fc0b1c306 100644 --- a/tools/firmware/hvmloader/e820.c +++ b/tools/firmware/hvmloader/e820.c @@ -128,11 +128,37 @@ int build_e820_table(struct e820entry *e820, * Explicitly reserve space for special pages. * This space starts at RESERVED_MEMBASE an extends to cover various * fixed hardware mappings (e.g., LAPIC, IOAPIC, default SVGA framebuffer). + * + * If igd_opregion_pgbase we need to split the RESERVED region in two. */ - e820[nr].addr = RESERVED_MEMBASE; - e820[nr].size = (uint32_t)-e820[nr].addr; - e820[nr].type = E820_RESERVED; - nr++; + + if ( igd_opregion_pgbase ) + { + uint32_t igd_opregion_base = igd_opregion_pgbase << PAGE_SHIFT; + + e820[nr].addr = RESERVED_MEMBASE; + e820[nr].size = (uint32_t) igd_opregion_base - RESERVED_MEMBASE; + e820[nr].type = E820_RESERVED; + nr++; + + e820[nr].addr = igd_opregion_base; + e820[nr].size = 2 * PAGE_SIZE; + e820[nr].type = E820_NVS; + nr++; + + e820[nr].addr = igd_opregion_base + 2 * PAGE_SIZE; + e820[nr].size = (uint32_t)-e820[nr].addr; + e820[nr].type = E820_RESERVED; + nr++; + } + else + { + e820[nr].addr = RESERVED_MEMBASE; + e820[nr].size = (uint32_t)-e820[nr].addr; + e820[nr].type = E820_RESERVED; + nr++; + } + if ( hvm_info->high_mem_pgend ) { diff --git a/tools/firmware/hvmloader/pci.c b/tools/firmware/hvmloader/pci.c index 00490f184e..fd56e50874 100644 --- a/tools/firmware/hvmloader/pci.c +++ b/tools/firmware/hvmloader/pci.c @@ -32,6 +32,7 @@ unsigned long pci_mem_start = PCI_MEM_START; unsigned long pci_mem_end = PCI_MEM_END; enum virtual_vga virtual_vga = VGA_none; +unsigned long igd_opregion_pgbase = 0; void pci_setup(void) { @@ -95,6 +96,17 @@ void pci_setup(void) { vga_devfn = devfn; virtual_vga = VGA_pt; + if ( vendor_id == 0x8086 ) + { + igd_opregion_pgbase = mem_hole_alloc(2); + /* + * Write the the OpRegion offset to give the opregion + * address to the device model. The device model will trap + * and map the OpRegion at the give address. + */ + pci_writel(vga_devfn, PCI_INTEL_OPREGION, + igd_opregion_pgbase << PAGE_SHIFT); + } } break; case 0x0680: diff --git a/tools/firmware/hvmloader/pci_regs.h b/tools/firmware/hvmloader/pci_regs.h index f37affedd0..0803f77a55 100644 --- a/tools/firmware/hvmloader/pci_regs.h +++ b/tools/firmware/hvmloader/pci_regs.h @@ -105,6 +105,8 @@ #define PCI_MIN_GNT 0x3e /* 8 bits */ #define PCI_MAX_LAT 0x3f /* 8 bits */ +#define PCI_INTEL_OPREGION 0xfc /* 4 bits */ + #endif /* __HVMLOADER_PCI_REGS_H__ */ /* -- 2.39.5