diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index 382f30b5d4..e6e0f70a81 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -633,6 +633,79 @@ assigned slave device. =back +=item B + +(HVM/x86 only) Specifies information about Reserved Device Memory (RDM), +which is necessary to enable robust device passthrough. One example of RDM +is reported through ACPI Reserved Memory Region Reporting (RMRR) structure +on x86 platform. + +B has the form C<[KEY=VALUE,KEY=VALUE,...> where: + +=over 4 + +=item B + +Possible Bs are: + +=over 4 + +=item B + +Currently there is only one valid type: + +"host" means all reserved device memory on this platform should be checked to +reserve regions in this VM's guest address space. This global rdm parameter +allows user to specify reserved regions explicitly, and using "host" includes +all reserved regions reported on this platform, which is useful when doing +hotplug. + +By default this isn't set so we don't check all rdms. Instead, we just check +rdm specific to a given device if you're assigning this kind of device. Note +this option is not recommended unless you can make sure any conflict does exist. + +For example, you're trying to set "memory = 2800" to allocate memory to one +given VM but the platform owns two RDM regions like, + +Device A [sbdf_A]: RMRR region_A: base_addr ac6d3000 end_address ac6e6fff +Device B [sbdf_B]: RMRR region_B: base_addr ad800000 end_address afffffff + +In this conflict case, + +#1. If B is set to "host", for example, + +rdm = "strategy=host,policy=strict" or rdm = "strategy=host,policy=relaxed" + +It means all conflicts will be handled according to the policy +introduced by B as described below. + +#2. If B is not set at all, but + +pci = [ 'sbdf_A, rdm_policy=xxxxx' ] + +It means only one conflict of region_A will be handled according to the policy +introduced by B as described inside pci options. + +=item B + +Specifies how to deal with conflicts when reserving reserved device +memory in guest address space. + +When that conflict is unsolved, + +"strict" means VM can't be created, or the associated device can't be +attached in the case of hotplug. + +"relaxed" allows VM to be created but may cause VM to crash if +pass-through device accesses RDM. For exampl,e Windows IGD GFX driver +always accessed RDM regions so it leads to VM crash. + +Note this may be overridden by rdm_policy option in PCI device configuration. + +=back + +=back + =item B Specifies the host PCI devices to passthrough to this guest. Each B @@ -695,6 +768,14 @@ dom0 without confirmation. Please use with care. D0-D3hot power management states for the PCI device. False (0) by default. +=item B + +(HVM/x86 only) This is same as policy option inside the rdm option but +just specific to a given device. Therefore the default is "relaxed" as +same as policy option as well. + +Note this would override global B option. + =back =back diff --git a/docs/misc/vtd.txt b/docs/misc/vtd.txt index 9af0e992f4..88b2102e3e 100644 --- a/docs/misc/vtd.txt +++ b/docs/misc/vtd.txt @@ -111,6 +111,30 @@ in the config file: To override for a specific device: pci = [ '01:00.0,msitranslate=0', '03:00.0' ] +RDM, 'reserved device memory', for PCI Device Passthrough +--------------------------------------------------------- + +There are some devices the BIOS controls, for e.g. USB devices to perform +PS2 emulation. The regions of memory used for these devices are marked +reserved in the e820 map. When we turn on DMA translation, DMA to those +regions will fail. Hence BIOS uses RMRR to specify these regions along with +devices that need to access these regions. OS is expected to setup +identity mappings for these regions for these devices to access these regions. + +While creating a VM we should reserve them in advance, and avoid any conflicts. +So we introduce user configurable parameters to specify RDM resource and +according policies, + +To enable this globally, add "rdm" in the config file: + + rdm = "strategy=host, policy=relaxed" (default policy is "relaxed") + +Or just for a specific device: + + pci = [ '01:00.0,rdm_policy=relaxed', '03:00.0,rdm_policy=strict' ] + +For all the options available to RDM, see xl.cfg(5). + Caveat on Conventional PCI Device Passthrough --------------------------------------------- diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index a32e3df8b0..7c884c4365 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -50,6 +50,12 @@ int libxl__domain_create_info_setdefault(libxl__gc *gc, return 0; } +void libxl__rdm_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info) +{ + if (b_info->u.hvm.rdm.policy == LIBXL_RDM_RESERVE_POLICY_INVALID) + b_info->u.hvm.rdm.policy = LIBXL_RDM_RESERVE_POLICY_RELAXED; +} + int libxl__domain_build_info_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info) { @@ -332,6 +338,7 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc, libxl_defbool_setdefault(&b_info->u.hvm.gfx_passthru, false); + libxl__rdm_setdefault(gc, b_info); break; case LIBXL_DOMAIN_TYPE_PV: libxl_defbool_setdefault(&b_info->u.pv.e820_host, false); diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 3c09668f8f..4bb0f38148 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -1176,6 +1176,8 @@ _hidden int libxl__device_vtpm_setdefault(libxl__gc *gc, libxl_device_vtpm *vtpm _hidden int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb); _hidden int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb); _hidden int libxl__device_pci_setdefault(libxl__gc *gc, libxl_device_pci *pci); +_hidden void libxl__rdm_setdefault(libxl__gc *gc, + libxl_domain_build_info *b_info); _hidden const char *libxl__device_nic_devname(libxl__gc *gc, uint32_t domid, diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c index 632c15e12b..1ebdce73be 100644 --- a/tools/libxl/libxl_pci.c +++ b/tools/libxl/libxl_pci.c @@ -988,6 +988,12 @@ static int do_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcidev, i out: if (!libxl_is_stubdom(ctx, domid, NULL)) { + if (pcidev->rdm_policy == LIBXL_RDM_RESERVE_POLICY_STRICT) { + flag &= ~XEN_DOMCTL_DEV_RDM_RELAXED; + } else if (pcidev->rdm_policy != LIBXL_RDM_RESERVE_POLICY_RELAXED) { + LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unknown rdm check flag."); + return ERROR_FAIL; + } rc = xc_assign_device(ctx->xch, domid, pcidev_encode_bdf(pcidev), flag); if (rc < 0 && (hvm || errno != ENOSYS)) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_assign_device failed"); @@ -1040,6 +1046,9 @@ static int libxl__device_pci_reset(libxl__gc *gc, unsigned int domain, unsigned int libxl__device_pci_setdefault(libxl__gc *gc, libxl_device_pci *pci) { + /* We'd like to force reserve rdm specific to a device by default.*/ + if (pci->rdm_policy == LIBXL_RDM_RESERVE_POLICY_INVALID) + pci->rdm_policy = LIBXL_RDM_RESERVE_POLICY_STRICT; return 0; } diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index bc0c4ef330..db9f75a1e3 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -77,6 +77,17 @@ libxl_domain_type = Enumeration("domain_type", [ (2, "PV"), ], init_val = "LIBXL_DOMAIN_TYPE_INVALID") +libxl_rdm_reserve_strategy = Enumeration("rdm_reserve_strategy", [ + (0, "ignore"), + (1, "host"), + ]) + +libxl_rdm_reserve_policy = Enumeration("rdm_reserve_policy", [ + (-1, "invalid"), + (0, "strict"), + (1, "relaxed"), + ], init_val = "LIBXL_RDM_RESERVE_POLICY_INVALID") + libxl_channel_connection = Enumeration("channel_connection", [ (0, "UNKNOWN"), (1, "PTY"), @@ -387,6 +398,11 @@ libxl_gic_version = Enumeration("gic_version", [ (0x30, "v3") ], init_val = "LIBXL_GIC_VERSION_DEFAULT") +libxl_rdm_reserve = Struct("rdm_reserve", [ + ("strategy", libxl_rdm_reserve_strategy), + ("policy", libxl_rdm_reserve_policy), + ]) + libxl_domain_build_info = Struct("domain_build_info",[ ("max_vcpus", integer), ("avail_vcpus", libxl_bitmap), @@ -486,6 +502,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ # See libxl_ms_vm_genid_generate() ("ms_vm_genid", libxl_ms_vm_genid), ("serial_list", libxl_string_list), + ("rdm", libxl_rdm_reserve), ])), ("pv", Struct(None, [("kernel", string), ("slack_memkb", MemKB), @@ -566,6 +583,7 @@ libxl_device_pci = Struct("device_pci", [ ("power_mgmt", bool), ("permissive", bool), ("seize", bool), + ("rdm_policy", libxl_rdm_reserve_policy), ]) libxl_device_dtdev = Struct("device_dtdev", [