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:
parent
bcd7461e7e
commit
798141799c
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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
10
vl.c
|
@ -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)) {
|
||||||
|
|
Loading…
Reference in New Issue