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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
@ -388,6 +402,12 @@ static void machine_initfn(Object *obj)
|
||||
object_property_set_description(obj, "usb",
|
||||
"Set on/off to enable/disable usb",
|
||||
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",
|
||||
machine_get_firmware,
|
||||
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_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;
|
||||
}
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
@ -25,6 +25,7 @@ typedef struct XenHostPCIDevice {
|
||||
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
uint32_t class_code;
|
||||
int irq;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
xen_pt_register_vga_regions(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -801,6 +802,7 @@ out:
|
||||
static void xen_pt_unregister_device(PCIDevice *d)
|
||||
{
|
||||
XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
|
||||
XenHostPCIDevice *host_dev = &s->real_device;
|
||||
uint8_t machine_irq = s->machine_irq;
|
||||
uint8_t intx = xen_pt_pci_intx(s);
|
||||
int rc;
|
||||
@ -844,6 +846,8 @@ static void xen_pt_unregister_device(PCIDevice *d)
|
||||
/* delete all emulated config registers */
|
||||
xen_pt_config_delete(s);
|
||||
|
||||
xen_pt_unregister_vga_regions(host_dev);
|
||||
|
||||
memory_listener_unregister(&s->memory_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;
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
|
111
hw/xen/xen_pt_graphics.c
Normal file
111
hw/xen/xen_pt_graphics.c
Normal 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;
|
||||
}
|
@ -137,6 +137,7 @@ struct MachineState {
|
||||
bool mem_merge;
|
||||
bool usb;
|
||||
bool usb_disabled;
|
||||
bool igd_gfx_passthru;
|
||||
char *firmware;
|
||||
bool iommu;
|
||||
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"
|
||||
" mem-merge=on|off controls memory merge support (default: on)\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"
|
||||
" 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",
|
||||
@ -55,6 +56,8 @@ than one accelerator specified, the next one is used if the previous one fails
|
||||
to initialize.
|
||||
@item kernel_irqchip=on|off
|
||||
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
|
||||
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
|
||||
|
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 */
|
||||
|
||||
@ -4528,6 +4535,9 @@ int main(int argc, char **argv, char **envp)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Check if IGD GFX passthrough. */
|
||||
igd_gfx_passthru();
|
||||
|
||||
/* init generic devices */
|
||||
if (qemu_opts_foreach(qemu_find_opts("device"),
|
||||
device_init_func, NULL, NULL)) {
|
||||
|
Loading…
Reference in New Issue
Block a user