提交 7b9c09f7 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/sstabellini/tags/xen-2015-09-10-tag' into staging

xen-2015-09-10

# gpg: Signature made Thu 10 Sep 2015 17:52:08 BST using RSA key ID 70E1AE90
# gpg: Good signature from "Stefano Stabellini <stefano.stabellini@eu.citrix.com>"

* remotes/sstabellini/tags/xen-2015-09-10-tag: (29 commits)
  xen/pt: Don't slurp wholesale the PCI configuration registers
  xen/pt: Check for return values for xen_host_pci_[get|set] in init
  xen/pt: Move bulk of xen_pt_unregister_device in its own routine.
  xen/pt: Make xen_pt_unregister_device idempotent
  xen/pt: Log xen_host_pci_get/set errors in MSI code.
  xen/pt: Log xen_host_pci_get in two init functions
  xen/pt: Remove XenPTReg->data field.
  xen/pt: Check if reg->init function sets the 'data' past the reg->size
  xen/pt: Sync up the dev.config and data values.
  xen/pt: Use xen_host_pci_get_[byte|word] instead of dev.config
  xen/pt: Use XEN_PT_LOG properly to guard against compiler warnings.
  xen/pt/msi: Add the register value when printing logging and error messages
  xen: use errno instead of rc for xc_domain_add_to_physmap
  xen/pt: xen_host_pci_config_read returns -errno, not -1 on failure
  xen/pt: Make xen_pt_msi_set_enable static
  xen/pt: Update comments with proper function name.
  xen/HVM: atomically access pointers in bufioreq handling
  xen-hvm: When using xc_domain_add_to_physmap also include errno when reporting
  xen, gfx passthrough: add opregion mapping
  xen, gfx passthrough: register host bridge specific to passthrough
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -1881,6 +1881,34 @@ EOF
#if !defined(HVM_MAX_VCPUS)
# error HVM_MAX_VCPUS not defined
#endif
int main(void) {
xc_interface *xc;
xs_daemon_open();
xc = xc_interface_open(0, 0, 0);
xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
xc_gnttab_open(NULL, 0);
xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL);
xc_reserved_device_memory_map(xc, 0, 0, 0, 0, NULL, 0);
return 0;
}
EOF
compile_prog "" "$xen_libs"
then
xen_ctrl_version=460
xen=yes
# Xen 4.5
elif
cat > $TMPC <<EOF &&
#include <xenctrl.h>
#include <xenstore.h>
#include <stdint.h>
#include <xen/hvm/hvm_info_table.h>
#if !defined(HVM_MAX_VCPUS)
# error HVM_MAX_VCPUS not defined
#endif
int main(void) {
xc_interface *xc;
xs_daemon_open();
......
......@@ -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);
......
......@@ -7,6 +7,7 @@ obj-$(CONFIG_XEN) += ../xenpv/ xen/
obj-y += kvmvapic.o
obj-y += acpi-build.o
obj-y += pci-assign-load-rom.o
gen-hex-y += hw/i386/acpi-dsdt.hex
gen-hex-y += hw/i386/q35-acpi-dsdt.hex
......
......@@ -37,6 +37,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
#include "kvm_i386.h"
#include "hw/pci/pci-assign.h"
#define MSIX_PAGE_SIZE 0x1000
......@@ -48,17 +49,6 @@
#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
#define IORESOURCE_MEM_64 0x00100000
//#define DEVICE_ASSIGNMENT_DEBUG
#ifdef DEVICE_ASSIGNMENT_DEBUG
#define DEBUG(fmt, ...) \
do { \
fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__); \
} while (0)
#else
#define DEBUG(fmt, ...)
#endif
typedef struct PCIRegion {
int type; /* Memory or port I/O */
int valid;
......@@ -1896,73 +1886,15 @@ static void assign_register_types(void)
type_init(assign_register_types)
/*
* Scan the assigned devices for the devices that have an option ROM, and then
* load the corresponding ROM data to RAM. If an error occurs while loading an
* option ROM, we just ignore that option ROM and continue with the next one.
*/
static void assigned_dev_load_option_rom(AssignedDevice *dev)
{
char name[32], rom_file[64];
FILE *fp;
uint8_t val;
struct stat st;
void *ptr;
/* If loading ROM from file, pci handles it */
if (dev->dev.romfile || !dev->dev.rom_bar) {
return;
}
int size = 0;
snprintf(rom_file, sizeof(rom_file),
"/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
dev->host.domain, dev->host.bus, dev->host.slot,
dev->host.function);
pci_assign_dev_load_option_rom(&dev->dev, OBJECT(dev), &size,
dev->host.domain, dev->host.bus,
dev->host.slot, dev->host.function);
if (stat(rom_file, &st)) {
return;
}
if (access(rom_file, F_OK)) {
error_report("pci-assign: Insufficient privileges for %s", rom_file);
return;
}
/* Write "1" to the ROM file to enable it */
fp = fopen(rom_file, "r+");
if (fp == NULL) {
return;
if (!size) {
error_report("pci-assign: Invalid ROM.");
}
val = 1;
if (fwrite(&val, 1, 1, fp) != 1) {
goto close_rom;
}
fseek(fp, 0, SEEK_SET);
snprintf(name, sizeof(name), "%s.rom",
object_get_typename(OBJECT(dev)));
memory_region_init_ram(&dev->dev.rom, OBJECT(dev), name, st.st_size,
&error_abort);
vmstate_register_ram(&dev->dev.rom, &dev->dev.qdev);
ptr = memory_region_get_ram_ptr(&dev->dev.rom);
memset(ptr, 0xff, st.st_size);
if (!fread(ptr, 1, st.st_size, fp)) {
error_report("pci-assign: Cannot read from host %s", rom_file);
error_printf("Device option ROM contents are probably invalid "
"(check dmesg).\nSkip option ROM probe with rombar=0, "
"or load from file with romfile=\n");
goto close_rom;
}
pci_register_bar(&dev->dev, PCI_ROM_SLOT, 0, &dev->dev.rom);
dev->dev.has_rom = true;
close_rom:
/* Write "0" to disable ROM */
fseek(fp, 0, SEEK_SET);
val = 0;
if (!fwrite(&val, 1, 1, fp)) {
DEBUG("%s\n", "Failed to disable pci-sysfs rom file");
}
fclose(fp);
}
......@@ -50,7 +50,8 @@
#include "cpu.h"
#include "qemu/error-report.h"
#ifdef CONFIG_XEN
# include <xen/hvm/hvm_info_table.h>
#include <xen/hvm/hvm_info_table.h>
#include "hw/xen/xen_pt.h"
#endif
#include "migration/migration.h"
......@@ -76,7 +77,8 @@ static bool has_reserved_memory = true;
static bool kvmclock_enabled = true;
/* PC hardware initialisation */
static void pc_init1(MachineState *machine)
static void pc_init1(MachineState *machine,
const char *host_type, const char *pci_type)
{
PCMachineState *pcms = PC_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
......@@ -194,7 +196,9 @@ static void pc_init1(MachineState *machine)
}
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
pci_bus = i440fx_init(host_type,
pci_type,
&i440fx_state, &piix3_devfn, &isa_bus, gsi,
system_memory, system_io, machine->ram_size,
pcms->below_4g_mem_size,
pcms->above_4g_mem_size,
......@@ -412,15 +416,25 @@ static void pc_init_isa(MachineState *machine)
}
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
enable_compat_apic_id_mode();
pc_init1(machine);
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
}
#ifdef CONFIG_XEN
static void pc_xen_hvm_init_pci(MachineState *machine)
{
const char *pci_type = has_igd_gfx_passthru ?
TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE : TYPE_I440FX_PCI_DEVICE;
pc_init1(machine,
TYPE_I440FX_PCI_HOST_BRIDGE,
pci_type);
}
static void pc_xen_hvm_init(MachineState *machine)
{
PCIBus *bus;
pc_init1(machine);
pc_xen_hvm_init_pci(machine);
bus = pci_find_primary_bus();
if (bus != NULL) {
......@@ -436,7 +450,8 @@ static void pc_xen_hvm_init(MachineState *machine)
if (compat) { \
compat(machine); \
} \
pc_init1(machine); \
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
TYPE_I440FX_PCI_DEVICE); \
} \
DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
......@@ -878,6 +893,118 @@ static void pc_i440fx_0_10_machine_options(MachineClass *m)
DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
pc_i440fx_0_10_machine_options);
typedef struct {
uint16_t gpu_device_id;
uint16_t pch_device_id;
uint8_t pch_revision_id;
} IGDDeviceIDInfo;
/* In real world different GPU should have different PCH. But actually
* the different PCH DIDs likely map to different PCH SKUs. We do the
* same thing for the GPU. For PCH, the different SKUs are going to be
* all the same silicon design and implementation, just different
* features turn on and off with fuses. The SW interfaces should be
* consistent across all SKUs in a given family (eg LPT). But just same
* features may not be supported.
*
* Most of these different PCH features probably don't matter to the
* Gfx driver, but obviously any difference in display port connections
* will so it should be fine with any PCH in case of passthrough.
*
* So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
* scenarios, 0x9cc3 for BDW(Broadwell).
*/
static const IGDDeviceIDInfo igd_combo_id_infos[] = {
/* HSW Classic */
{0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
{0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
{0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
{0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
{0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
/* HSW ULT */
{0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
{0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
{0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
{0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
{0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
{0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
/* HSW CRW */
{0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
{0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
/* HSW Server */
{0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
/* HSW SRVR */
{0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
/* BSW */
{0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
{0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
{0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
{0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
{0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
{0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
{0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
{0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
{0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
{0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
{0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
};
static void isa_bridge_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
dc->desc = "ISA bridge faked to support IGD PT";
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->class_id = PCI_CLASS_BRIDGE_ISA;
};
static TypeInfo isa_bridge_info = {
.name = "igd-passthrough-isa-bridge",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = isa_bridge_class_init,
};
static void pt_graphics_register_types(void)
{
type_register_static(&isa_bridge_info);
}
type_init(pt_graphics_register_types)
void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
{
struct PCIDevice *bridge_dev;
int i, num;
uint16_t pch_dev_id = 0xffff;
uint8_t pch_rev_id;
num = ARRAY_SIZE(igd_combo_id_infos);
for (i = 0; i < num; i++) {
if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
pch_dev_id = igd_combo_id_infos[i].pch_device_id;
pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
}
}
if (pch_dev_id == 0xffff) {
return;
}
/* Currently IGD drivers always need to access PCH by 1f.0. */
bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
"igd-passthrough-isa-bridge");
/*
* Note that vendor id is always PCI_VENDOR_ID_INTEL.
*/
if (!bridge_dev) {
fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
return;
}
pci_config_set_device_id(bridge_dev->config, pch_dev_id);
pci_config_set_revision(bridge_dev->config, pch_rev_id);
}
static void isapc_machine_options(MachineClass *m)
{
......
/*
* This is splited from hw/i386/kvm/pci-assign.c
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "qemu/error-report.h"
#include "ui/console.h"
#include "hw/loader.h"
#include "monitor/monitor.h"
#include "qemu/range.h"
#include "sysemu/sysemu.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci-assign.h"
/*
* Scan the assigned devices for the devices that have an option ROM, and then
* load the corresponding ROM data to RAM. If an error occurs while loading an
* option ROM, we just ignore that option ROM and continue with the next one.
*/
void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner,
int *size, unsigned int domain,
unsigned int bus, unsigned int slot,
unsigned int function)
{
char name[32], rom_file[64];
FILE *fp;
uint8_t val;
struct stat st;
void *ptr = NULL;
/* If loading ROM from file, pci handles it */
if (dev->romfile || !dev->rom_bar) {
return NULL;
}
snprintf(rom_file, sizeof(rom_file),
"/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
domain, bus, slot, function);
if (stat(rom_file, &st)) {
return NULL;
}
if (access(rom_file, F_OK)) {
error_report("pci-assign: Insufficient privileges for %s", rom_file);
return NULL;
}
/* Write "1" to the ROM file to enable it */
fp = fopen(rom_file, "r+");
if (fp == NULL) {
return NULL;
}
val = 1;
if (fwrite(&val, 1, 1, fp) != 1) {
goto close_rom;
}
fseek(fp, 0, SEEK_SET);
snprintf(name, sizeof(name), "%s.rom", object_get_typename(owner));
memory_region_init_ram(&dev->rom, owner, name, st.st_size, &error_abort);
vmstate_register_ram(&dev->rom, &dev->qdev);
ptr = memory_region_get_ram_ptr(&dev->rom);
memset(ptr, 0xff, st.st_size);
if (!fread(ptr, 1, st.st_size, fp)) {
error_report("pci-assign: Cannot read from host %s", rom_file);
error_printf("Device option ROM contents are probably invalid "
"(check dmesg).\nSkip option ROM probe with rombar=0, "
"or load from file with romfile=\n");
goto close_rom;
}
pci_register_bar(dev, PCI_ROM_SLOT, 0, &dev->rom);
dev->has_rom = true;
*size = st.st_size;
close_rom:
/* Write "0" to disable ROM */
fseek(fp, 0, SEEK_SET);
val = 0;
if (!fwrite(&val, 1, 1, fp)) {
DEBUG("%s\n", "Failed to disable pci-sysfs rom file");
}
fclose(fp);
return ptr;
}
......@@ -40,7 +40,6 @@
* http://download.intel.com/design/chipsets/datashts/29054901.pdf
*/
#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
#define I440FX_PCI_HOST_BRIDGE(obj) \
OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX_PCI_HOST_BRIDGE)
......@@ -95,7 +94,6 @@ typedef struct PIIX3State {
#define PIIX3_PCI_DEVICE(obj) \
OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE)
#define TYPE_I440FX_PCI_DEVICE "i440FX"
#define I440FX_PCI_DEVICE(obj) \
OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
......@@ -305,7 +303,8 @@ static void i440fx_realize(PCIDevice *dev, Error **errp)
dev->config[I440FX_SMRAM] = 0x02;
}
PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
PCIBus *i440fx_init(const char *host_type, const char *pci_type,
PCII440FXState **pi440fx_state,
int *piix3_devfn,
ISABus **isa_bus, qemu_irq *pic,
MemoryRegion *address_space_mem,
......@@ -325,7 +324,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
unsigned i;
I440FXState *i440fx;
dev = qdev_create(NULL, TYPE_I440FX_PCI_HOST_BRIDGE);
dev = qdev_create(NULL, host_type);
s = PCI_HOST_BRIDGE(dev);
b = pci_bus_new(dev, NULL, pci_address_space,
address_space_io, 0, TYPE_PCI_BUS);
......@@ -333,7 +332,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
qdev_init_nofail(dev);
d = pci_create_simple(b, 0, TYPE_I440FX_PCI_DEVICE);
d = pci_create_simple(b, 0, pci_type);
*pi440fx_state = I440FX_PCI_DEVICE(d);
f = *pi440fx_state;
f->system_memory = address_space_mem;
......@@ -740,6 +739,90 @@ static const TypeInfo i440fx_info = {
.class_init = i440fx_class_init,
};
/* IGD Passthrough Host Bridge. */
typedef struct {
uint8_t offset;
uint8_t len;
} IGDHostInfo;
/* Here we just expose minimal host bridge offset subset. */
static const IGDHostInfo igd_host_bridge_infos[] = {
{0x08, 2}, /* revision id */
{0x2c, 2}, /* sybsystem vendor id */
{0x2e, 2}, /* sybsystem id */
{0x50, 2}, /* SNB: processor graphics control register */
{0x52, 2}, /* processor graphics control register */
{0xa4, 4}, /* SNB: graphics base of stolen memory */
{0xa8, 4}, /* SNB: base of GTT stolen memory */
};
static int host_pci_config_read(int pos, int len, uint32_t val)
{
char path[PATH_MAX];
int config_fd;
ssize_t size = sizeof(path);
/* Access real host bridge. */
int rc = snprintf(path, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
0, 0, 0, 0, "config");
if (rc >= size || rc < 0) {
return -ENODEV;
}
config_fd = open(path, O_RDWR);
if (config_fd < 0) {
return -ENODEV;
}
if (lseek(config_fd, pos, SEEK_SET) != pos) {
return -errno;
}
do {
rc = read(config_fd, (uint8_t *)&val, len);
} while (rc < 0 && (errno == EINTR || errno == EAGAIN));
if (rc != len) {
return -errno;
}
return 0;
}
static int igd_pt_i440fx_initfn(struct PCIDevice *pci_dev)
{
uint32_t val = 0;
int rc, i, num;
int pos, len;
num = ARRAY_SIZE(igd_host_bridge_infos);
for (i = 0; i < num; i++) {
pos = igd_host_bridge_infos[i].offset;
len = igd_host_bridge_infos[i].len;
rc = host_pci_config_read(pos, len, val);
if (rc) {
return -ENODEV;
}
pci_default_write_config(pci_dev, pos, val, len);
}
return 0;
}
static void igd_passthrough_i440fx_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = igd_pt_i440fx_initfn;
dc->desc = "IGD Passthrough Host bridge";
}
static const TypeInfo igd_passthrough_i440fx_info = {
.name = TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE,
.parent = TYPE_I440FX_PCI_DEVICE,
.instance_size = sizeof(PCII440FXState),
.class_init = igd_passthrough_i440fx_class_init,
};
static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
......@@ -781,6 +864,7 @@ static const TypeInfo i440fx_pcihost_info = {
static void i440fx_register_types(void)
{
type_register_static(&i440fx_info);
type_register_static(&igd_passthrough_i440fx_info);
type_register_static(&piix3_pci_type_info);
type_register_static(&piix3_info);
type_register_static(&piix3_xen_info);
......
......@@ -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;
......@@ -387,6 +392,11 @@ error:
return rc;
}
bool xen_host_pci_device_closed(XenHostPCIDevice *d)
{
return d->config_fd == -1;
}
void xen_host_pci_device_put(XenHostPCIDevice *d)
{
if (d->config_fd >= 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];
......@@ -38,6 +39,7 @@ typedef struct XenHostPCIDevice {
int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
uint8_t bus, uint8_t dev, uint8_t func);
void xen_host_pci_device_put(XenHostPCIDevice *pci_dev);
bool xen_host_pci_device_closed(XenHostPCIDevice *d);
int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p);
int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p);
......
......@@ -56,6 +56,7 @@
#include "hw/pci/pci.h"
#include "hw/xen/xen.h"
#include "hw/i386/pc.h"
#include "hw/xen/xen_backend.h"
#include "xen_pt.h"
#include "qemu/range.h"
......@@ -378,7 +379,7 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
}
}
/* need to shift back before passing them to xen_host_pci_device */
/* need to shift back before passing them to xen_host_pci_set_block. */
val >>= (addr & 3) << 3;
memory_region_transaction_commit();
......@@ -406,7 +407,7 @@ out:
(uint8_t *)&val + index, len);
if (rc < 0) {
XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
XEN_PT_ERR(d, "xen_host_pci_set_block failed. return value: %d.\n", rc);
}
}
}
......@@ -502,6 +503,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;
}
......@@ -683,13 +685,86 @@ static const MemoryListener xen_pt_io_listener = {
.priority = 10,
};
static void
xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
XenHostPCIDevice *dev)
{
uint16_t gpu_dev_id;
PCIDevice *d = &s->dev;
gpu_dev_id = dev->device_id;
igd_passthrough_isa_bridge_create(d->bus, gpu_dev_id);
}
/* destroy. */
static void xen_pt_destroy(PCIDevice *d) {
XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
XenHostPCIDevice *host_dev = &s->real_device;
uint8_t machine_irq = s->machine_irq;
uint8_t intx;
int rc;
if (machine_irq && !xen_host_pci_device_closed(&s->real_device)) {
intx = xen_pt_pci_intx(s);
rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
PT_IRQ_TYPE_PCI,
pci_bus_num(d->bus),
PCI_SLOT(s->dev.devfn),
intx,
0 /* isa_irq */);
if (rc < 0) {
XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
" (machine irq: %i, err: %d)"
" But bravely continuing on..\n",
'a' + intx, machine_irq, errno);
}
}
/* N.B. xen_pt_config_delete takes care of freeing them. */
if (s->msi) {
xen_pt_msi_disable(s);
}
if (s->msix) {
xen_pt_msix_disable(s);
}
if (machine_irq) {
xen_pt_mapped_machine_irq[machine_irq]--;
if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
if (rc < 0) {
XEN_PT_ERR(d, "unmapping of interrupt %i failed. (err: %d)"
" But bravely continuing on..\n",
machine_irq, errno);
}
}
s->machine_irq = 0;
}
/* delete all emulated config registers */
xen_pt_config_delete(s);
xen_pt_unregister_vga_regions(host_dev);
if (s->listener_set) {
memory_listener_unregister(&s->memory_listener);
memory_listener_unregister(&s->io_listener);
s->listener_set = false;
}
if (!xen_host_pci_device_closed(&s->real_device)) {
xen_host_pci_device_put(&s->real_device);
}
}
/* init */
static int xen_pt_initfn(PCIDevice *d)
{
XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
int rc = 0;
uint8_t machine_irq = 0;
uint8_t machine_irq = 0, scratch;
uint16_t cmd = 0;
int pirq = XEN_PT_UNASSIGNED_PIRQ;
......@@ -715,27 +790,48 @@ static int xen_pt_initfn(PCIDevice *d)
}
/* Initialize virtualized PCI configuration (Extended 256 Bytes) */
if (xen_host_pci_get_block(&s->real_device, 0, d->config,
PCI_CONFIG_SPACE_SIZE) == -1) {
xen_host_pci_device_put(&s->real_device);
return -1;
}
memset(d->config, 0, PCI_CONFIG_SPACE_SIZE);
s->memory_listener = xen_pt_memory_listener;
s->io_listener = xen_pt_io_listener;
/* Setup VGA bios for passthrough GFX */
if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
(s->real_device.dev == 2) && (s->real_device.func == 0)) {
if (!is_igd_vga_passthrough(&s->real_device)) {
XEN_PT_ERR(d, "Need to enable igd-passthru if you're trying"
" to passthrough IGD GFX.\n");
xen_host_pci_device_put(&s->real_device);
return -1;
}
if (xen_pt_setup_vga(s, &s->real_device) < 0) {
XEN_PT_ERR(d, "Setup VGA BIOS of passthrough GFX failed!\n");
xen_host_pci_device_put(&s->real_device);
return -1;
}
/* Register ISA bridge for passthrough GFX. */
xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
}
/* Handle real device's MMIO/PIO BARs */
xen_pt_register_regions(s, &cmd);
/* reinitialize each config register to be emulated */
if (xen_pt_config_init(s)) {
rc = xen_pt_config_init(s);
if (rc) {
XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");
xen_host_pci_device_put(&s->real_device);
return -1;
goto err_out;
}
/* Bind interrupt */
if (!s->dev.config[PCI_INTERRUPT_PIN]) {
rc = xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &scratch);
if (rc) {
XEN_PT_ERR(d, "Failed to read PCI_INTERRUPT_PIN! (rc:%d)\n", rc);
goto err_out;
}
if (!scratch) {
XEN_PT_LOG(d, "no pin interrupt\n");
goto out;
}
......@@ -785,69 +881,41 @@ static int xen_pt_initfn(PCIDevice *d)
out:
if (cmd) {
xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
pci_get_word(d->config + PCI_COMMAND) | cmd);
uint16_t val;
rc = xen_host_pci_get_word(&s->real_device, PCI_COMMAND, &val);
if (rc) {
XEN_PT_ERR(d, "Failed to read PCI_COMMAND! (rc: %d)\n", rc);
goto err_out;
} else {
val |= cmd;
rc = xen_host_pci_set_word(&s->real_device, PCI_COMMAND, val);
if (rc) {
XEN_PT_ERR(d, "Failed to write PCI_COMMAND val=0x%x!(rc: %d)\n",
val, rc);
goto err_out;
}
}
}
memory_listener_register(&s->memory_listener, &s->dev.bus_master_as);
memory_listener_register(&s->io_listener, &address_space_io);
s->listener_set = true;
XEN_PT_LOG(d,
"Real physical device %02x:%02x.%d registered successfully!\n",
s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function);
return 0;
err_out:
xen_pt_destroy(d);
assert(rc);
return rc;
}
static void xen_pt_unregister_device(PCIDevice *d)
{
XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
uint8_t machine_irq = s->machine_irq;
uint8_t intx = xen_pt_pci_intx(s);
int rc;
if (machine_irq) {
rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
PT_IRQ_TYPE_PCI,
pci_bus_num(d->bus),
PCI_SLOT(s->dev.devfn),
intx,
0 /* isa_irq */);
if (rc < 0) {
XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
" (machine irq: %i, err: %d)"
" But bravely continuing on..\n",
'a' + intx, machine_irq, errno);
}
}
if (s->msi) {
xen_pt_msi_disable(s);
}
if (s->msix) {
xen_pt_msix_disable(s);
}
if (machine_irq) {
xen_pt_mapped_machine_irq[machine_irq]--;
if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
if (rc < 0) {
XEN_PT_ERR(d, "unmapping of interrupt %i failed. (err: %d)"
" But bravely continuing on..\n",
machine_irq, errno);
}
}
}
/* delete all emulated config registers */
xen_pt_config_delete(s);
memory_listener_unregister(&s->memory_listener);
memory_listener_unregister(&s->io_listener);
xen_host_pci_device_put(&s->real_device);
xen_pt_destroy(d);
}
static Property xen_pci_passthrough_properties[] = {
......
......@@ -40,6 +40,9 @@ typedef struct XenPCIPassthroughState XenPCIPassthroughState;
#define XEN_PT_DEVICE(obj) \
OBJECT_CHECK(XenPCIPassthroughState, (obj), TYPE_XEN_PT_DEVICE)
uint32_t igd_read_opregion(XenPCIPassthroughState *s);
void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
/* function type for config reg */
typedef int (*xen_pt_conf_reg_init)
(XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
......@@ -66,8 +69,9 @@ typedef int (*xen_pt_conf_byte_read)
#define XEN_PT_BAR_ALLF 0xFFFFFFFF
#define XEN_PT_BAR_UNMAPPED (-1)
#define PCI_CAP_MAX 48
#define XEN_PCI_CAP_MAX 48
#define XEN_PCI_INTEL_OPREGION 0xfc
typedef enum {
XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */
......@@ -134,7 +138,11 @@ struct XenPTRegInfo {
struct XenPTReg {
QLIST_ENTRY(XenPTReg) entries;
XenPTRegInfo *reg;
uint32_t data; /* emulated value */
union {
uint8_t *byte;
uint16_t *half_word;
uint32_t *word;
} ptr; /* pointer to dev.config. */
};
typedef const struct XenPTRegGroupInfo XenPTRegGroupInfo;
......@@ -217,6 +225,7 @@ struct XenPCIPassthroughState {
MemoryListener memory_listener;
MemoryListener io_listener;
bool listener_set;
};
int xen_pt_config_init(XenPCIPassthroughState *s);
......@@ -282,6 +291,7 @@ static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
" value=%i, acceptable range is 1 - 4\n", r_val);
r_val = 0;
} else {
/* Note that if s.real_device.config_fd is closed we make 0xff. */
r_val -= 1;
}
......@@ -289,7 +299,6 @@ static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
}
/* MSI/MSI-X */
int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
int xen_pt_msi_setup(XenPCIPassthroughState *s);
int xen_pt_msi_update(XenPCIPassthroughState *d);
void xen_pt_msi_disable(XenPCIPassthroughState *s);
......@@ -305,5 +314,18 @@ static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
return s->msix && s->msix->bar_index == bar;
}
extern void *pci_assign_dev_load_option_rom(PCIDevice *dev,
struct Object *owner, int *size,
unsigned int domain,
unsigned int bus, unsigned int slot,
unsigned int function);
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 */
此差异已折叠。
/*
* graphics passthrough
*/
#include "xen_pt.h"
#include "xen-host-pci-device.h"
#include "hw/xen/xen_backend.h"
static unsigned long igd_guest_opregion;
static unsigned long igd_host_opregion;
#define XEN_PCI_INTEL_OPREGION_MASK 0xfff
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;
int ret = 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;
}
}
if (igd_guest_opregion) {
ret = xc_domain_memory_mapping(xen_xc, xen_domid,
(unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
3,
DPCI_REMOVE_MAPPING);
if (ret) {
return ret;
}
}
return 0;
}
static void *get_vgabios(XenPCIPassthroughState *s, int *size,
XenHostPCIDevice *dev)
{
return pci_assign_dev_load_option_rom(&s->dev, OBJECT(&s->dev), size,
dev->domain, dev->bus,
dev->dev, dev->func);
}
/* Refer to Seabios. */
struct rom_header {
uint16_t signature;
uint8_t size;
uint8_t initVector[4];
uint8_t reserved[17];
uint16_t pcioffset;
uint16_t pnpoffset;
} __attribute__((packed));
struct pci_data {
uint32_t signature;
uint16_t vendor;
uint16_t device;
uint16_t vitaldata;
uint16_t dlen;
uint8_t drevision;
uint8_t class_lo;
uint16_t class_hi;
uint16_t ilen;
uint16_t irevision;
uint8_t type;
uint8_t indicator;
uint16_t reserved;
} __attribute__((packed));
int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev)
{
unsigned char *bios = NULL;
struct rom_header *rom;
int bios_size;
char *c = NULL;
char checksum = 0;
uint32_t len = 0;
struct pci_data *pd = NULL;
if (!is_igd_vga_passthrough(dev)) {
return -1;
}
bios = get_vgabios(s, &bios_size, dev);
if (!bios) {
XEN_PT_ERR(&s->dev, "VGA: Can't getting VBIOS!\n");
return -1;
}
/* Currently we fixed this address as a primary. */
rom = (struct rom_header *)bios;
pd = (void *)(bios + (unsigned char)rom->pcioffset);
/* We may need to fixup Device Identification. */
if (pd->device != s->real_device.device_id) {
pd->device = s->real_device.device_id;
len = rom->size * 512;
/* Then adjust the bios checksum */
for (c = (char *)bios; c < ((char *)bios + len); c++) {
checksum += *c;
}
if (checksum) {
bios[len - 1] -= checksum;
XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
checksum);
}
}
/* Currently we fixed this address as a primary for legacy BIOS. */
cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
return 0;
}
uint32_t igd_read_opregion(XenPCIPassthroughState *s)
{
uint32_t val = 0;
if (!igd_guest_opregion) {
return val;
}
val = igd_guest_opregion;
XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
return val;
}
#define XEN_PCI_INTEL_OPREGION_PAGES 0x3
#define XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED 0x1
void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
{
int ret;
if (igd_guest_opregion) {
XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
val);
return;
}
/* We just work with LE. */
xen_host_pci_get_block(&s->real_device, XEN_PCI_INTEL_OPREGION,
(uint8_t *)&igd_host_opregion, 4);
igd_guest_opregion = (unsigned long)(val & ~XEN_PCI_INTEL_OPREGION_MASK)
| (igd_host_opregion & XEN_PCI_INTEL_OPREGION_MASK);
ret = xc_domain_iomem_permission(xen_xc, xen_domid,
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
XEN_PCI_INTEL_OPREGION_PAGES,
XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED);
if (ret) {
XEN_PT_ERR(&s->dev, "[%d]:Can't enable to access IGD host opregion:"
" 0x%lx.\n", ret,
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT)),
igd_guest_opregion = 0;
return;
}
ret = xc_domain_memory_mapping(xen_xc, xen_domid,
(unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
XEN_PCI_INTEL_OPREGION_PAGES,
DPCI_ADD_MAPPING);
if (ret) {
XEN_PT_ERR(&s->dev, "[%d]:Can't map IGD host opregion:0x%lx to"
" guest opregion:0x%lx.\n", ret,
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
(unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
igd_guest_opregion = 0;
return;
}
XEN_PT_LOG(&s->dev, "Map OpRegion: 0x%lx -> 0x%lx\n",
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
(unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
}
......@@ -75,19 +75,29 @@ static int msi_msix_enable(XenPCIPassthroughState *s,
bool enable)
{
uint16_t val = 0;
int rc;
if (!address) {
return -1;
}
xen_host_pci_get_word(&s->real_device, address, &val);
rc = xen_host_pci_get_word(&s->real_device, address, &val);
if (rc) {
XEN_PT_ERR(&s->dev, "Failed to read MSI/MSI-X register (0x%x), rc:%d\n",
address, rc);
return rc;
}
if (enable) {
val |= flag;
} else {
val &= ~flag;
}
xen_host_pci_set_word(&s->real_device, address, val);
return 0;
rc = xen_host_pci_set_word(&s->real_device, address, val);
if (rc) {
XEN_PT_ERR(&s->dev, "Failed to write MSI/MSI-X register (0x%x), rc:%d\n",
address, rc);
}
return rc;
}
static int msi_msix_setup(XenPCIPassthroughState *s,
......@@ -220,7 +230,7 @@ static int msi_msix_disable(XenPCIPassthroughState *s,
* MSI virtualization functions
*/
int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
static int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
{
XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
......@@ -276,7 +286,7 @@ void xen_pt_msi_disable(XenPCIPassthroughState *s)
return;
}
xen_pt_msi_set_enable(s, false);
(void)xen_pt_msi_set_enable(s, false);
msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
msi->initialized);
......
......@@ -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;
......
......@@ -220,7 +220,13 @@ extern int no_hpet;
struct PCII440FXState;
typedef struct PCII440FXState PCII440FXState;
PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
#define TYPE_I440FX_PCI_DEVICE "i440FX"
#define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX"
PCIBus *i440fx_init(const char *host_type, const char *pci_type,
PCII440FXState **pi440fx_state, int *piix_devfn,
ISABus **isa_bus, qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
......@@ -721,4 +727,5 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
(m)->compat_props = props; \
} while (0)
extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id);
#endif
/*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Just split from hw/i386/kvm/pci-assign.c.
*/
#ifndef PCI_ASSIGN_H
#define PCI_ASSIGN_H
#include "hw/pci/pci.h"
//#define DEVICE_ASSIGNMENT_DEBUG
#ifdef DEVICE_ASSIGNMENT_DEBUG
#define DEBUG(fmt, ...) \
do { \
fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__); \
} while (0)
#else
#define DEBUG(fmt, ...)
#endif
void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner,
int *size, unsigned int domain,
unsigned int bus, unsigned int slot,
unsigned int function);
#endif /* PCI_ASSIGN_H */
......@@ -186,6 +186,15 @@ static inline int xen_get_vmport_regs_pfn(XenXC xc, domid_t dom,
}
#endif
/* Xen before 4.6 */
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 460
#ifndef HVM_IOREQSRV_BUFIOREQ_ATOMIC
#define HVM_IOREQSRV_BUFIOREQ_ATOMIC 2
#endif
#endif
/* Xen before 4.5 */
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 450
......@@ -370,7 +379,8 @@ static inline void xen_unmap_pcidev(XenXC xc, domid_t dom,
static inline int xen_create_ioreq_server(XenXC xc, domid_t dom,
ioservid_t *ioservid)
{
int rc = xc_hvm_create_ioreq_server(xc, dom, 1, ioservid);
int rc = xc_hvm_create_ioreq_server(xc, dom, HVM_IOREQSRV_BUFIOREQ_ATOMIC,
ioservid);
if (rc == 0) {
trace_xen_ioreq_server_create(*ioservid);
......@@ -407,4 +417,26 @@ static inline int xen_set_ioreq_server_state(XenXC xc, domid_t dom,
#endif
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 460
static inline int xen_xc_domain_add_to_physmap(XenXC xch, uint32_t domid,
unsigned int space,
unsigned long idx,
xen_pfn_t gpfn)
{
return xc_domain_add_to_physmap(xch, domid, space, idx, gpfn);
}
#else
static inline int xen_xc_domain_add_to_physmap(XenXC xch, uint32_t domid,
unsigned int space,
unsigned long idx,
xen_pfn_t gpfn)
{
/* In Xen 4.6 rc is -1 and errno contains the error value. */
int rc = xc_domain_add_to_physmap(xch, domid, space, idx, gpfn);
if (rc == -1)
return errno;
return rc;
}
#endif
#endif /* QEMU_HW_XEN_COMMON_H */
......@@ -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
......
......@@ -936,6 +936,13 @@ xen_map_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %
xen_unmap_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64
xen_map_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
handle_ioreq(void *req, uint32_t type, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p type=%d dir=%d df=%d ptr=%d port=%#"PRIx64" data=%#"PRIx64" count=%d size=%d"
handle_ioreq_read(void *req, uint32_t type, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p read type=%d df=%d ptr=%d port=%#"PRIx64" data=%#"PRIx64" count=%d size=%d"
handle_ioreq_write(void *req, uint32_t type, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p write type=%d df=%d ptr=%d port=%#"PRIx64" data=%#"PRIx64" count=%d size=%d"
cpu_ioreq_pio(void *req, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p pio dir=%d df=%d ptr=%d port=%#"PRIx64" data=%#"PRIx64" count=%d size=%d"
cpu_ioreq_pio_read_reg(void *req, uint64_t data, uint64_t addr, uint32_t size) "I/O=%p pio read reg data=%#"PRIx64" port=%#"PRIx64" size=%d"
cpu_ioreq_pio_write_reg(void *req, uint64_t data, uint64_t addr, uint32_t size) "I/O=%p pio write reg data=%#"PRIx64" port=%#"PRIx64" size=%d"
cpu_ioreq_move(void *req, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p copy dir=%d df=%d ptr=%d port=%#"PRIx64" data=%#"PRIx64" count=%d size=%d"
# xen-mapcache.c
xen_map_cache(uint64_t phys_addr) "want %#"PRIx64
......
......@@ -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)) {
......
......@@ -344,10 +344,10 @@ go_physmap:
unsigned long idx = pfn + i;
xen_pfn_t gpfn = start_gpfn + i;
rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
rc = xen_xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
if (rc) {
DPRINTF("add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
PRI_xen_pfn" failed: %d (errno: %d)\n", idx, gpfn, rc, errno);
return -rc;
}
}
......@@ -421,10 +421,10 @@ static int xen_remove_from_physmap(XenIOState *state,
xen_pfn_t idx = start_addr + i;
xen_pfn_t gpfn = phys_offset + i;
rc = xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
rc = xen_xc_domain_add_to_physmap(xen_xc, xen_domid, XENMAPSPACE_gmfn, idx, gpfn);
if (rc) {
fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"
PRI_xen_pfn" failed: %d\n", idx, gpfn, rc);
PRI_xen_pfn" failed: %d (errno: %d)\n", idx, gpfn, rc, errno);
return -rc;
}
}
......@@ -813,9 +813,14 @@ static void cpu_ioreq_pio(ioreq_t *req)
{
uint32_t i;
trace_cpu_ioreq_pio(req, req->dir, req->df, req->data_is_ptr, req->addr,
req->data, req->count, req->size);
if (req->dir == IOREQ_READ) {
if (!req->data_is_ptr) {
req->data = do_inp(req->addr, req->size);
trace_cpu_ioreq_pio_read_reg(req, req->data, req->addr,
req->size);
} else {
uint32_t tmp;
......@@ -826,6 +831,8 @@ static void cpu_ioreq_pio(ioreq_t *req)
}
} else if (req->dir == IOREQ_WRITE) {
if (!req->data_is_ptr) {
trace_cpu_ioreq_pio_write_reg(req, req->data, req->addr,
req->size);
do_outp(req->addr, req->size, req->data);
} else {
for (i = 0; i < req->count; i++) {
......@@ -842,6 +849,9 @@ static void cpu_ioreq_move(ioreq_t *req)
{
uint32_t i;
trace_cpu_ioreq_move(req, req->dir, req->df, req->data_is_ptr, req->addr,
req->data, req->count, req->size);
if (!req->data_is_ptr) {
if (req->dir == IOREQ_READ) {
for (i = 0; i < req->count; i++) {
......@@ -914,11 +924,18 @@ static void handle_vmport_ioreq(XenIOState *state, ioreq_t *req)
static void handle_ioreq(XenIOState *state, ioreq_t *req)
{
trace_handle_ioreq(req, req->type, req->dir, req->df, req->data_is_ptr,
req->addr, req->data, req->count, req->size);
if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
(req->size < sizeof (target_ulong))) {
req->data &= ((target_ulong) 1 << (8 * req->size)) - 1;
}
if (req->dir == IOREQ_WRITE)
trace_handle_ioreq_write(req, req->type, req->df, req->data_is_ptr,
req->addr, req->data, req->count, req->size);
switch (req->type) {
case IOREQ_TYPE_PIO:
cpu_ioreq_pio(req);
......@@ -958,23 +975,38 @@ static void handle_ioreq(XenIOState *state, ioreq_t *req)
default:
hw_error("Invalid ioreq type 0x%x\n", req->type);
}
if (req->dir == IOREQ_READ) {
trace_handle_ioreq_read(req, req->type, req->df, req->data_is_ptr,
req->addr, req->data, req->count, req->size);
}
}
static int handle_buffered_iopage(XenIOState *state)
{
buffered_iopage_t *buf_page = state->buffered_io_page;
buf_ioreq_t *buf_req = NULL;
ioreq_t req;
int qw;
if (!state->buffered_io_page) {
if (!buf_page) {
return 0;
}
memset(&req, 0x00, sizeof(req));
while (state->buffered_io_page->read_pointer != state->buffered_io_page->write_pointer) {
buf_req = &state->buffered_io_page->buf_ioreq[
state->buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
for (;;) {
uint32_t rdptr = buf_page->read_pointer, wrptr;
xen_rmb();
wrptr = buf_page->write_pointer;
xen_rmb();
if (rdptr != buf_page->read_pointer) {
continue;
}
if (rdptr == wrptr) {
break;
}
buf_req = &buf_page->buf_ioreq[rdptr % IOREQ_BUFFER_SLOT_NUM];
req.size = 1UL << buf_req->size;
req.count = 1;
req.addr = buf_req->addr;
......@@ -986,15 +1018,14 @@ static int handle_buffered_iopage(XenIOState *state)
req.data_is_ptr = 0;
qw = (req.size == 8);
if (qw) {
buf_req = &state->buffered_io_page->buf_ioreq[
(state->buffered_io_page->read_pointer + 1) % IOREQ_BUFFER_SLOT_NUM];
buf_req = &buf_page->buf_ioreq[(rdptr + 1) %
IOREQ_BUFFER_SLOT_NUM];
req.data |= ((uint64_t)buf_req->data) << 32;
}
handle_ioreq(state, &req);
xen_mb();
state->buffered_io_page->read_pointer += qw ? 2 : 1;
atomic_add(&buf_page->read_pointer, qw + 1);
}
return req.count;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册