xen, gfx passthrough: basic graphics passthrough support

basic gfx passthrough support:
- add a vga type for gfx passthrough
- register/unregister legacy VGA I/O ports and MMIOs for passthrough GFX

Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
This commit is contained in:
Tiejun Chen 2015-07-15 13:37:45 +08:00 committed by Stefano Stabellini
parent bcd7461e7e
commit 798141799c
10 changed files with 165 additions and 1 deletions

View File

@ -226,6 +226,20 @@ static void machine_set_usb(Object *obj, bool value, Error **errp)
ms->usb_disabled = !value; ms->usb_disabled = !value;
} }
static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
return ms->igd_gfx_passthru;
}
static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp)
{
MachineState *ms = MACHINE(obj);
ms->igd_gfx_passthru = value;
}
static char *machine_get_firmware(Object *obj, Error **errp) static char *machine_get_firmware(Object *obj, Error **errp)
{ {
MachineState *ms = MACHINE(obj); MachineState *ms = MACHINE(obj);
@ -388,6 +402,12 @@ static void machine_initfn(Object *obj)
object_property_set_description(obj, "usb", object_property_set_description(obj, "usb",
"Set on/off to enable/disable usb", "Set on/off to enable/disable usb",
NULL); NULL);
object_property_add_bool(obj, "igd-passthru",
machine_get_igd_gfx_passthru,
machine_set_igd_gfx_passthru, NULL);
object_property_set_description(obj, "igd-passthru",
"Set on/off to enable/disable igd passthrou",
NULL);
object_property_add_str(obj, "firmware", object_property_add_str(obj, "firmware",
machine_get_firmware, machine_get_firmware,
machine_set_firmware, NULL); machine_set_firmware, NULL);

View File

@ -3,3 +3,4 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o xen_pt_graphics.o

View File

@ -376,6 +376,11 @@ int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
goto error; goto error;
} }
d->irq = v; d->irq = v;
rc = xen_host_pci_get_hex_value(d, "class", &v);
if (rc) {
goto error;
}
d->class_code = v;
d->is_virtfn = xen_host_pci_dev_is_virtfn(d); d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
return 0; return 0;

View File

@ -25,6 +25,7 @@ typedef struct XenHostPCIDevice {
uint16_t vendor_id; uint16_t vendor_id;
uint16_t device_id; uint16_t device_id;
uint32_t class_code;
int irq; int irq;
XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1]; XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];

View File

@ -502,6 +502,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
d->rom.size, d->rom.base_addr); d->rom.size, d->rom.base_addr);
} }
xen_pt_register_vga_regions(d);
return 0; return 0;
} }
@ -801,6 +802,7 @@ out:
static void xen_pt_unregister_device(PCIDevice *d) static void xen_pt_unregister_device(PCIDevice *d)
{ {
XenPCIPassthroughState *s = XEN_PT_DEVICE(d); XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
XenHostPCIDevice *host_dev = &s->real_device;
uint8_t machine_irq = s->machine_irq; uint8_t machine_irq = s->machine_irq;
uint8_t intx = xen_pt_pci_intx(s); uint8_t intx = xen_pt_pci_intx(s);
int rc; int rc;
@ -844,6 +846,8 @@ static void xen_pt_unregister_device(PCIDevice *d)
/* delete all emulated config registers */ /* delete all emulated config registers */
xen_pt_config_delete(s); xen_pt_config_delete(s);
xen_pt_unregister_vga_regions(host_dev);
memory_listener_unregister(&s->memory_listener); memory_listener_unregister(&s->memory_listener);
memory_listener_unregister(&s->io_listener); memory_listener_unregister(&s->io_listener);

View File

@ -305,5 +305,13 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
return s->msix && s->msix->bar_index == bar; return s->msix && s->msix->bar_index == bar;
} }
extern bool has_igd_gfx_passthru;
static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
{
return (has_igd_gfx_passthru
&& ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
}
int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev);
#endif /* !XEN_PT_H */ #endif /* !XEN_PT_H */

111
hw/xen/xen_pt_graphics.c Normal file
View File

@ -0,0 +1,111 @@
/*
* graphics passthrough
*/
#include "xen_pt.h"
#include "xen-host-pci-device.h"
#include "hw/xen/xen_backend.h"
typedef struct VGARegion {
int type; /* Memory or port I/O */
uint64_t guest_base_addr;
uint64_t machine_base_addr;
uint64_t size; /* size of the region */
int rc;
} VGARegion;
#define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200
static struct VGARegion vga_args[] = {
{
.type = IORESOURCE_IO,
.guest_base_addr = 0x3B0,
.machine_base_addr = 0x3B0,
.size = 0xC,
.rc = -1,
},
{
.type = IORESOURCE_IO,
.guest_base_addr = 0x3C0,
.machine_base_addr = 0x3C0,
.size = 0x20,
.rc = -1,
},
{
.type = IORESOURCE_MEM,
.guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
.machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
.size = 0x20,
.rc = -1,
},
};
/*
* register VGA resources for the domain with assigned gfx
*/
int xen_pt_register_vga_regions(XenHostPCIDevice *dev)
{
int i = 0;
if (!is_igd_vga_passthrough(dev)) {
return 0;
}
for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
if (vga_args[i].type == IORESOURCE_IO) {
vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
vga_args[i].guest_base_addr,
vga_args[i].machine_base_addr,
vga_args[i].size, DPCI_ADD_MAPPING);
} else {
vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
vga_args[i].guest_base_addr,
vga_args[i].machine_base_addr,
vga_args[i].size, DPCI_ADD_MAPPING);
}
if (vga_args[i].rc) {
XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n",
vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
vga_args[i].rc);
return vga_args[i].rc;
}
}
return 0;
}
/*
* unregister VGA resources for the domain with assigned gfx
*/
int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
{
int i = 0;
if (!is_igd_vga_passthrough(dev)) {
return 0;
}
for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
if (vga_args[i].type == IORESOURCE_IO) {
vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
vga_args[i].guest_base_addr,
vga_args[i].machine_base_addr,
vga_args[i].size, DPCI_REMOVE_MAPPING);
} else {
vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
vga_args[i].guest_base_addr,
vga_args[i].machine_base_addr,
vga_args[i].size, DPCI_REMOVE_MAPPING);
}
if (vga_args[i].rc) {
XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n",
vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
vga_args[i].rc);
return vga_args[i].rc;
}
}
return 0;
}

View File

@ -137,6 +137,7 @@ struct MachineState {
bool mem_merge; bool mem_merge;
bool usb; bool usb;
bool usb_disabled; bool usb_disabled;
bool igd_gfx_passthru;
char *firmware; char *firmware;
bool iommu; bool iommu;
bool suppress_vmdesc; bool suppress_vmdesc;

View File

@ -38,6 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
" dump-guest-core=on|off include guest memory in a core dump (default=on)\n" " dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
" mem-merge=on|off controls memory merge support (default: on)\n" " mem-merge=on|off controls memory merge support (default: on)\n"
" iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n" " iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n"
" igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n"
" aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n" " aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n"
" dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n" " dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n"
" suppress-vmdesc=on|off disables self-describing migration (default=off)\n", " suppress-vmdesc=on|off disables self-describing migration (default=off)\n",
@ -55,6 +56,8 @@ than one accelerator specified, the next one is used if the previous one fails
to initialize. to initialize.
@item kernel_irqchip=on|off @item kernel_irqchip=on|off
Enables in-kernel irqchip support for the chosen accelerator when available. Enables in-kernel irqchip support for the chosen accelerator when available.
@item gfx_passthru=on|off
Enables IGD GFX passthrough support for the chosen machine when available.
@item vmport=on|off|auto @item vmport=on|off|auto
Enables emulation of VMWare IO port, for vmmouse etc. auto says to select the Enables emulation of VMWare IO port, for vmmouse etc. auto says to select the
value based on accel. For accel=xen the default is off otherwise the default value based on accel. For accel=xen the default is off otherwise the default

10
vl.c
View File

@ -1338,6 +1338,13 @@ static inline void semihosting_arg_fallback(const char *file, const char *cmd)
} }
} }
/* Now we still need this for compatibility with XEN. */
bool has_igd_gfx_passthru;
static void igd_gfx_passthru(void)
{
has_igd_gfx_passthru = current_machine->igd_gfx_passthru;
}
/***********************************************************/ /***********************************************************/
/* USB devices */ /* USB devices */
@ -4528,6 +4535,9 @@ int main(int argc, char **argv, char **envp)
exit(1); exit(1);
} }
/* Check if IGD GFX passthrough. */
igd_gfx_passthru();
/* init generic devices */ /* init generic devices */
if (qemu_opts_foreach(qemu_find_opts("device"), if (qemu_opts_foreach(qemu_find_opts("device"),
device_init_func, NULL, NULL)) { device_init_func, NULL, NULL)) {