* Patches for Nvidia GPU passthrough
@ 2016-07-14 20:19 marcus
2016-07-14 21:34 ` Andrew Cooper
0 siblings, 1 reply; 2+ messages in thread
From: marcus @ 2016-07-14 20:19 UTC (permalink / raw)
To: xen-devel
[-- Attachment #1: Type: text/plain, Size: 5691 bytes --]
Hello all,
I've been working on enabling passthrough for newer Nvidia cards and
drivers (GTX 980 specifically) on Xen and I'd like to document my
findings up to now and ask for assistance. I apologize if this is not
the correct mailing list, but I thought xen-devel is more suitable since
we are talking about code changes in Xen anyway.
Problem with Nvidia GPUs has been (for two years now) that drivers
detect it being running inside a VM and refuse to work (Code 43 error)
if the card is not a Quadro or other high-end non-consumer grade GPU
(though few other things could cause Code 43 or BSOD also). Now, since
KVM has supported Nvidia GPU passthrough for quite a while (and I've
personally succeeded in passing through GTX 980 using KVM on both Win 7
and Win 8.1 VM's), I decided to port those few patches from KVM to Xen.
------------------
#### Patch #1: Spoof Xen and Hypervisor signatures:
KVM has for a while supported hiding both the "KVMKVMKVMKVM" signature
(with "-cpu kvm=off" flag) as well as the Viridian hypervisor signature
("-cpu hv_vendor_id="..." flag). Currently there's no such functionality
in Xen, so I patched it in quite similar way to what Alex Willimson did
for KVM.
Attached is a patch for Xen 4.6.1 that spoofs Xen signature
("XenVMMXenVMM" to "ZenZenZenZen") and Viridian signature ("Microsoft
Hv" to "Wetware Labs") when "spoof_xen=1" and "spoof_viridian=1" are
added to VM configuration file.
The signatures are currently hard-coded, and currently there's no way to
modify them (beyond re-compiling Xen), since HVMLoader also uses a
hard-coded string to detect Xen and there's no API (understandably) to
change that signature in real-time.
This works with qemu-xen-traditional without any additional changes, but
qemu-xen requires that SeaBIOS is patched as well:
https://github.com/WetwareLabs/seabios/commit/ec102d72fc1d7b2e6c8e9607266dc9bd4a42bce0
With spoofing on, it was possible to use official binary drivers from
NVidia (tested version 367.27) on Arch Linux VM (without spoofing the
driver would fail with a error message such as "The NVIDIA GPU at
PCI:0:5:0 is not supported by the 367.27 NVIDIA driver". However this
was not enough on Windows VM's, as the Code 43 would occur regardless of
spoofing.
#### Patch #2: Disable NoSnoop.
Background information and the related patch for KVM is here:
https://patchwork.kernel.org/patch/3019371/
The fix was quite simple for Xen: Just modify the initial PCIe DEVCTL
capabilities to disable NoSnoop, and make the capability read-only.
Double-checking with Linux VM, I can see that NoSnoop is disabled for
all devices (with lspci -vvv), but this would not prevent Code 43 on
Windows VM.
##### Patch #3: Set CPUID to Core2duo
There have been few reports where forcing CPUID to Core2duo on KVM (-cpu
core2duo) would help alleviate Code 43 problems (and also increase
compatibility with Windows 10 VMs), so I copied all CPUID registers from
proven-to-be-working KVM configuration using libcpuid
(https://github.com/anrieff/libcpuid) and applied them to Xen VM. LibXL
is also patched (attached file) to allow hexadecimal input of CPUID (to
make it easier to convert CPUID output from libcpuid).
cpuid = [
'0:eax=0000000a,ebx=756e6547,ecx=6c65746e,edx=49656e69',
'1:eax=000006fb,ebx=00000800,ecx=80202201,edx=0f8bfbff',
'2:eax=00000001,ebx=00000000,ecx=00000000,edx=002c307d',
'3:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
'4,0:eax=00000121,ebx=01c0003f,ecx=0000003f,edx=00000001',
'4,1:eax=00000122,ebx=01c0003f,ecx=0000003f,edx=00000001',
'4,2:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
'4,3:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
'5:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
'6:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
'7,0:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
'0x80000000:eax=80000008,ebx=756e6547,ecx=6c65746e,edx=49656e69',
'0x80000001:eax=000006fb,ebx=00000000,ecx=00000001,edx=20100800',
'0x80000002:eax=65746e49,ebx=2952286c,ecx=726f4320,edx=4d542865',
'0x80000003:eax=44203229,ebx=43206f75,ecx=20205550,edx=54202020',
'0x80000004:eax=30303737,ebx=20402020,ecx=30342e32,edx=007a4847',
'0x80000005:eax=01ff01ff,ebx=01ff01ff,ecx=40020140,edx=40020140',
'0x80000006:eax=00000000,ebx=42004200,ecx=02008140,edx=00000000',
'0x80000007:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
'0x80000008:eax=00003028,ebx=00000000,ecx=00000000,edx=00000000'
]
This makes the /proc/cpuinfo almost identical between KVM and Xen VMs
running Linux. Only exceptions are flags "rep_good" (which is missing
under Xen) and "eager_fpu" and "xsaveopt" (not seen under KVM), but as
these are not explicitly set by CPUID but are Linux-specific flags, they
shouldn't (?) matter on Windows VMs.
------------------
Anyway, even applying all of these patches would not alleviate Code 43.
To be more specific, all NVidia drivers up to 364.72 would BSOD on boot
(SYSTEM_SERVICE_EXCEPTION), and newer drivers (368.22+) would cause Code
43. This happens on both Windows 7 Pro and 8.1 VMs. Result on qemu-xen
and -traditional is identical. Dom0 is Qubes 3.1 (Linux 4.1.24), Xen
4.6.1. Hardware: Intel i7-5820K, Asrock X99 WS motherboard, 32GB Corsair
mem, EVGA GTX980.
I would love if some of you could try these patches with both newer and
older NVidia cards. Also any suggestions, ideas and further patches
would be greatly appreciated! :)
Thanks!
Best regards,
Marcus
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: read-hex-cpuid.patch --]
[-- Type: text/x-diff; name=read-hex-cpuid.patch, Size: 2058 bytes --]
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/libxl/libxl_cpuid.c xen-4.6.1-new/tools/libxl/libxl_cpuid.c
--- xen-4.6.1/tools/libxl/libxl_cpuid.c 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/tools/libxl/libxl_cpuid.c 2016-07-10 12:09:36.092000000 +0300
@@ -318,12 +318,31 @@
if (endptr == NULL) {
endptr = strchr(str, 0);
}
- if (endptr - str != 32) {
- return 5;
- }
+
entry->policy[value] = calloc(32 + 1, 1);
- strncpy(entry->policy[value], str, 32);
+ switch (endptr - str) {
+ case 32: {
+ strncpy(entry->policy[value], str, 32);
+ }
+ break;
+ case 8: {
+ uint32_t cpuid_hex = strtoul(str,&endptr,16);
+ if ( str +8 != endptr )
+ return 6;
+ for (int i=0;i<32;i++) {
+ if ( cpuid_hex & (1<<i) )
+ entry->policy[value][31-i]='1';
+ else
+ entry->policy[value][31-i]='0';
+ }
+ entry->policy[value][32]=0;
+ }
+ break;
+ default:
+ return 5;
+ }
entry->policy[value][32] = 0;
+
if (*endptr == 0) {
break;
}
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/libxl/xl_cmdimpl.c xen-4.6.1-new/tools/libxl/xl_cmdimpl.c
--- xen-4.6.1/tools/libxl/xl_cmdimpl.c 2016-07-11 23:45:45.046000000 +0300
+++ xen-4.6.1-new/tools/libxl/xl_cmdimpl.c 2016-07-10 12:07:55.564000000 +0300
@@ -2095,7 +2095,10 @@
errstr = "invalid register name (must be e[abcd]x)";
break;
case 5:
- errstr = "policy string must be exactly 32 characters long";
+ errstr = "policy string must be exactly 32 (binary) or 8 (hex) characters long";
+ break;
+ case 6:
+ errstr = "error decoding policy string";
break;
default:
errstr = "unknown error";
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: spoof-xen-viridian.patch --]
[-- Type: text/x-diff; name=spoof-xen-viridian.patch, Size: 9935 bytes --]
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/firmware/hvmloader/hvmloader.c xen-4.6.1-new/tools/firmware/hvmloader/hvmloader.c
--- xen-4.6.1/tools/firmware/hvmloader/hvmloader.c 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/tools/firmware/hvmloader/hvmloader.c 2016-07-04 23:31:32.815000000 +0300
@@ -127,9 +127,11 @@
if ( !strcmp("XenVMMXenVMM", signature) )
break;
+ if ( !strcmp("ZenZenZenZen", signature) )
+ break;
}
- BUG_ON(strcmp("XenVMMXenVMM", signature) || ((eax - base) < 2));
+ BUG_ON( (strcmp("XenVMMXenVMM", signature) && strcmp("ZenZenZenZen", signature) ) || ((eax - base) < 2));
/* Fill in hypercall transfer pages. */
cpuid(base + 2, &eax, &ebx, &ecx, &edx);
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/libxl/libxl_create.c xen-4.6.1-new/tools/libxl/libxl_create.c
--- xen-4.6.1/tools/libxl/libxl_create.c 2016-07-09 16:47:05.181000000 +0300
+++ xen-4.6.1-new/tools/libxl/libxl_create.c 2016-07-04 23:49:54.802000000 +0300
@@ -284,6 +284,8 @@
libxl_defbool_setdefault(&b_info->u.hvm.acpi_s4, true);
libxl_defbool_setdefault(&b_info->u.hvm.nx, true);
libxl_defbool_setdefault(&b_info->u.hvm.viridian, false);
+ libxl_defbool_setdefault(&b_info->u.hvm.spoof_viridian, false);
+ libxl_defbool_setdefault(&b_info->u.hvm.spoof_xen, false);
libxl_defbool_setdefault(&b_info->u.hvm.hpet, true);
libxl_defbool_setdefault(&b_info->u.hvm.vpt_align, true);
libxl_defbool_setdefault(&b_info->u.hvm.nested_hvm, false);
@@ -1263,6 +1265,11 @@
libxl__device_console_add(gc, domid, &console, state, &device);
libxl__device_console_dispose(&console);
+ LOG(DEBUG, "Checking spoofing for guest (domid %d): xen %d, vir %d", domid,
+ libxl_defbool_val(d_config->b_info.u.hvm.spoof_xen),
+ libxl_defbool_val(d_config->b_info.u.hvm.spoof_viridian)
+ );
+
dcs->dmss.dm.guest_domid = domid;
if (libxl_defbool_val(d_config->b_info.device_model_stubdomain))
libxl__spawn_stub_dm(egc, &dcs->dmss);
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/libxl/libxl_dom.c xen-4.6.1-new/tools/libxl/libxl_dom.c
--- xen-4.6.1/tools/libxl/libxl_dom.c 2016-07-09 16:47:05.212000000 +0300
+++ xen-4.6.1-new/tools/libxl/libxl_dom.c 2016-07-04 23:31:32.819000000 +0300
@@ -287,6 +287,10 @@
libxl_defbool_val(info->u.hvm.nested_hvm));
xc_hvm_param_set(handle, domid, HVM_PARAM_ALTP2M,
libxl_defbool_val(info->u.hvm.altp2m));
+ xc_hvm_param_set(handle, domid, HVM_PARAM_SPOOF_XEN,
+ libxl_defbool_val(info->u.hvm.spoof_xen));
+ xc_hvm_param_set(handle, domid, HVM_PARAM_SPOOF_VIRIDIAN,
+ libxl_defbool_val(info->u.hvm.spoof_viridian));
}
int libxl__build_pre(libxl__gc *gc, uint32_t domid,
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/libxl/libxl_types.idl xen-4.6.1-new/tools/libxl/libxl_types.idl
--- xen-4.6.1/tools/libxl/libxl_types.idl 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/tools/libxl/libxl_types.idl 2016-07-09 16:31:16.181000000 +0300
@@ -468,6 +468,8 @@
("viridian", libxl_defbool),
("viridian_enable", libxl_bitmap),
("viridian_disable", libxl_bitmap),
+ ("spoof_viridian", libxl_defbool),
+ ("spoof_xen", libxl_defbool),
("timeoffset", string),
("hpet", libxl_defbool),
("vpt_align", libxl_defbool),
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/libxl/xl_cmdimpl.c xen-4.6.1-new/tools/libxl/xl_cmdimpl.c
--- xen-4.6.1/tools/libxl/xl_cmdimpl.c 2016-07-09 16:47:05.027000000 +0300
+++ xen-4.6.1-new/tools/libxl/xl_cmdimpl.c 2016-07-04 23:32:38.046000000 +0300
@@ -1507,6 +1507,10 @@
xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0);
xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0);
+ xlu_cfg_get_defbool(config, "spoof_xen", &b_info->u.hvm.spoof_xen, 0);
+ xlu_cfg_get_defbool(config, "spoof_viridian", &b_info->u.hvm.spoof_viridian, 0);
+
+
switch (xlu_cfg_get_list(config, "viridian",
&viridian, &num_viridian, 1))
{
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/misc/xen-detect.c xen-4.6.1-new/tools/misc/xen-detect.c
--- xen-4.6.1/tools/misc/xen-detect.c 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/tools/misc/xen-detect.c 2016-07-04 23:31:32.809000000 +0300
@@ -69,6 +69,8 @@
if ( !strcmp("XenVMMXenVMM", signature) && (regs[0] >= (base + 2)) )
goto found;
+ if ( !strcmp("ZenZenZenZen", signature) && (regs[0] >= (base + 2)) )
+ goto found;
}
return 0;
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/xen/arch/x86/hvm/hvm.c xen-4.6.1-new/xen/arch/x86/hvm/hvm.c
--- xen-4.6.1/xen/arch/x86/hvm/hvm.c 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/xen/arch/x86/hvm/hvm.c 2016-07-09 16:33:35.429000000 +0300
@@ -6047,6 +6050,14 @@
case HVM_PARAM_IOREQ_SERVER_PFN:
d->arch.hvm_domain.ioreq_gmfn.base = a.value;
break;
+ case HVM_PARAM_SPOOF_XEN:
+ printk("spoof_xen %" PRId64 " - curr dom %d, dom %d\n", a.value, curr_d->domain_id, d->domain_id);
+ d->arch.hvm_domain.spoof_xen = a.value;
+ break;
+ case HVM_PARAM_SPOOF_VIRIDIAN:
+ printk("spoof_vir %" PRId64 " - curr dom %d, dom %d\n", a.value, curr_d->domain_id, d->domain_id);
+ d->arch.hvm_domain.spoof_viridian = a.value;
+ break;
case HVM_PARAM_NR_IOREQ_SERVER_PAGES:
{
unsigned int i;
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/xen/arch/x86/hvm/viridian.c xen-4.6.1-new/xen/arch/x86/hvm/viridian.c
--- xen-4.6.1/xen/arch/x86/hvm/viridian.c 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/xen/arch/x86/hvm/viridian.c 2016-07-09 16:39:34.327000000 +0300
@@ -72,9 +72,16 @@
{
case 0:
*eax = 0x40000006; /* Maximum leaf */
- *ebx = 0x7263694d; /* Magic numbers */
- *ecx = 0x666F736F;
- *edx = 0x76482074;
+ if (!d->arch.hvm_domain.spoof_viridian) { // "Microsoft Hv"
+ *ebx = 0x7263694d; // rciM
+ *ecx = 0x666F736F; // foso
+ *edx = 0x76482074; // vH t
+ } else {
+ printk("wetware cpuid_viridian_leaves spoof_vir\n"); // "Wetware Labs"
+ *ebx = 0x77746557; // wteW
+ *ecx = 0x20657261; // era
+ *edx = 0x7362614C; // sbaL
+ }
break;
case 1:
*eax = 0x31237648; /* Version number */
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/xen/arch/x86/traps.c xen-4.6.1-new/xen/arch/x86/traps.c
--- xen-4.6.1/xen/arch/x86/traps.c 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/xen/arch/x86/traps.c 2016-07-04 23:31:32.653000000 +0300
@@ -779,9 +781,18 @@
{
case 0:
*eax = base + limit; /* Largest leaf */
- *ebx = XEN_CPUID_SIGNATURE_EBX;
- *ecx = XEN_CPUID_SIGNATURE_ECX;
- *edx = XEN_CPUID_SIGNATURE_EDX;
+ if (!currd->arch.hvm_domain.spoof_xen ) {
+ printk("cpuid_hypervisor_leaves - real id. domid %d\n",currd->domain_id);
+ *ebx = XEN_CPUID_SIGNATURE_EBX;
+ *ecx = XEN_CPUID_SIGNATURE_ECX;
+ *edx = XEN_CPUID_SIGNATURE_EDX;
+ } else
+ {
+ printk("cpuid_hypervisor_leaves - spoofed id. domid %d\n",currd->domain_id);
+ *ebx = ZEN_CPUID_SIGNATURE_EBX;
+ *ecx = ZEN_CPUID_SIGNATURE_ECX;
+ *edx = ZEN_CPUID_SIGNATURE_EDX;
+ }
break;
case 1:
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/xen/include/asm-x86/hvm/domain.h xen-4.6.1-new/xen/include/asm-x86/hvm/domain.h
--- xen-4.6.1/xen/include/asm-x86/hvm/domain.h 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/xen/include/asm-x86/hvm/domain.h 2016-07-04 23:31:32.667000000 +0300
@@ -130,6 +130,9 @@
struct list_head msixtbl_list;
spinlock_t msixtbl_list_lock;
+ bool_t spoof_xen;
+ bool_t spoof_viridian;
+
struct viridian_domain viridian;
bool_t hap_enabled;
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/xen/include/public/arch-x86/cpuid.h xen-4.6.1-new/xen/include/public/arch-x86/cpuid.h
--- xen-4.6.1/xen/include/public/arch-x86/cpuid.h 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/xen/include/public/arch-x86/cpuid.h 2016-07-09 16:45:16.126000000 +0300
@@ -53,6 +53,10 @@
#define XEN_CPUID_SIGNATURE_ECX 0x65584d4d /* "MMXe" */
#define XEN_CPUID_SIGNATURE_EDX 0x4d4d566e /* "nVMM" */
+#define ZEN_CPUID_SIGNATURE_EBX 0x5A6e655A /* "ZenZ" */
+#define ZEN_CPUID_SIGNATURE_ECX 0x655A6e65 /* "enZe" */
+#define ZEN_CPUID_SIGNATURE_EDX 0x6e655A6e /* "nZen" */
+
/*
* Leaf 2 (0x40000x01)
* EAX[31:16]: Xen major version.
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/xen/include/public/hvm/params.h xen-4.6.1-new/xen/include/public/hvm/params.h
--- xen-4.6.1/xen/include/public/hvm/params.h 2016-02-09 16:44:19.000000000 +0200
+++ xen-4.6.1-new/xen/include/public/hvm/params.h 2016-07-04 23:31:32.672000000 +0300
@@ -192,6 +192,11 @@
/* Boolean: Enable altp2m */
#define HVM_PARAM_ALTP2M 35
-#define HVM_NR_PARAMS 36
+#define HVM_PARAM_SPOOF_XEN 36
+
+#define HVM_PARAM_SPOOF_VIRIDIAN 37
+
+#define HVM_NR_PARAMS 38
+
#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: disable-no-snoop.patch --]
[-- Type: text/x-diff; name=disable-no-snoop.patch, Size: 1368 bytes --]
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/qemu-xen/hw/xen/xen_pt_config_init.c xen-4.6.1-new/tools/qemu-xen/hw/xen/xen_pt_config_init.c
--- xen-4.6.1/tools/qemu-xen/hw/xen/xen_pt_config_init.c 2016-01-06 18:42:43.000000000 +0200
+++ xen-4.6.1-new/tools/qemu-xen/hw/xen/xen_pt_config_init.c 2016-07-12 21:22:40.331000000 +0300
@@ -896,8 +896,8 @@
{
.offset = PCI_EXP_DEVCTL,
.size = 2,
- .init_val = 0x2810,
- .ro_mask = 0x8400,
+ .init_val = 0x2010,
+ .ro_mask = 0x8C00,
.emu_mask = 0xFFFF,
.init = xen_pt_common_reg_init,
.u.w.read = xen_pt_word_reg_read,
diff -ur -x .cproject -x .project -x '*.swp' xen-4.6.1/tools/qemu-xen-traditional/hw/pass-through.c xen-4.6.1-new/tools/qemu-xen-traditional/hw/pass-through.c
--- xen-4.6.1/tools/qemu-xen-traditional/hw/pass-through.c 2016-01-04 17:35:42.000000000 +0200
+++ xen-4.6.1-new/tools/qemu-xen-traditional/hw/pass-through.c 2016-07-11 23:45:34.317000000 +0300
@@ -601,8 +601,8 @@
{
.offset = PCI_EXP_DEVCTL,
.size = 2,
- .init_val = 0x2810,
- .ro_mask = 0x8400,
+ .init_val = 0x2010,
+ .ro_mask = 0x8C00,
.emu_mask = 0xFFFF,
.init = pt_common_reg_init,
.u.w.read = pt_word_reg_read,
[-- Attachment #5: Type: text/plain, Size: 127 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: Patches for Nvidia GPU passthrough
2016-07-14 20:19 Patches for Nvidia GPU passthrough marcus
@ 2016-07-14 21:34 ` Andrew Cooper
0 siblings, 0 replies; 2+ messages in thread
From: Andrew Cooper @ 2016-07-14 21:34 UTC (permalink / raw)
To: marcus, xen-devel
On 14/07/2016 21:19, marcus@wetwa.re wrote:
> Hello all,
>
> I've been working on enabling passthrough for newer Nvidia cards and
> drivers (GTX 980 specifically) on Xen and I'd like to document my
> findings up to now and ask for assistance. I apologize if this is not
> the correct mailing list, but I thought xen-devel is more suitable
> since we are talking about code changes in Xen anyway.
This is definitely the right place, and I think a lot of users would be
very happy if this started working.
I think it is fine to accept patches which increase the flexibility of
configuration available to the VM administrator, although this is this
is inherently a cat-and-mouse game.
To answer your last question first, I suspect you will have a far easier
time getting things working by turning off all telltail signs of
virtualisation, getting things working, then slowly turning the options
back on to gain sensible performance back.
Off the top of my head, telltail signs include
* The hypervisor bit in cpuid
* The Xen cpuid leaves
* Other leaves, such as viridian
* Xen strings in the SMBIOS and ACPI tables
* The Xen platform PCI device
>
> Problem with Nvidia GPUs has been (for two years now) that drivers
> detect it being running inside a VM and refuse to work (Code 43 error)
> if the card is not a Quadro or other high-end non-consumer grade GPU
> (though few other things could cause Code 43 or BSOD also). Now, since
> KVM has supported Nvidia GPU passthrough for quite a while (and I've
> personally succeeded in passing through GTX 980 using KVM on both Win
> 7 and Win 8.1 VM's), I decided to port those few patches from KVM to Xen.
For the patches themselves, please read
http://wiki.xenproject.org/wiki/Submitting_Xen_Project_Patches
Particularly, you need a Signed-off-by tag and for the patches to be
based on the staging branch.
>
> ------------------
>
>
> #### Patch #1: Spoof Xen and Hypervisor signatures:
>
> KVM has for a while supported hiding both the "KVMKVMKVMKVM" signature
> (with "-cpu kvm=off" flag) as well as the Viridian hypervisor
> signature ("-cpu hv_vendor_id="..." flag). Currently there's no such
> functionality in Xen, so I patched it in quite similar way to what
> Alex Willimson did for KVM.
Viridian can be turned off completely. There is some libxc code which
seems to suggest that setting 0x40000000:eax=0 should be able to
restrict the Xen leaves, but I have never seen anyone actually try that.
>
> Attached is a patch for Xen 4.6.1 that spoofs Xen signature
> ("XenVMMXenVMM" to "ZenZenZenZen") and Viridian signature ("Microsoft
> Hv" to "Wetware Labs") when "spoof_xen=1" and "spoof_viridian=1" are
> added to VM configuration file.
Simply hacking these like this not ok upstream. In particular, I don't
think we can reasonably take changes like those to the public header
files. (Also, be careful with Zen - AMD's new range of processors is
called Zen/Zenith).
Wiring things up so a user can specify
0x40000000:ebx=0x5A6e655A,ecx=0x655A6e65,edx=0x6e655A6e would be ok though.
>
> The signatures are currently hard-coded, and currently there's no way
> to modify them (beyond re-compiling Xen), since HVMLoader also uses a
> hard-coded string to detect Xen and there's no API (understandably) to
> change that signature in real-time.
>
> This works with qemu-xen-traditional without any additional changes,
> but qemu-xen requires that SeaBIOS is patched as well:
> https://github.com/WetwareLabs/seabios/commit/ec102d72fc1d7b2e6c8e9607266dc9bd4a42bce0
>
> With spoofing on, it was possible to use official binary drivers from
> NVidia (tested version 367.27) on Arch Linux VM (without spoofing the
> driver would fail with a error message such as "The NVIDIA GPU at
> PCI:0:5:0 is not supported by the 367.27 NVIDIA driver". However this
> was not enough on Windows VM's, as the Code 43 would occur regardless
> of spoofing.
That is very interesting to know. I presume it will be the same for
other Linux distros?
>
>
> #### Patch #2: Disable NoSnoop.
>
> Background information and the related patch for KVM is here:
> https://patchwork.kernel.org/patch/3019371/
>
> The fix was quite simple for Xen: Just modify the initial PCIe DEVCTL
> capabilities to disable NoSnoop, and make the capability read-only.
> Double-checking with Linux VM, I can see that NoSnoop is disabled for
> all devices (with lspci -vvv), but this would not prevent Code 43 on
> Windows VM.
Is there any more information behind this? In principle, having the
ability to prevent NoSnoop accesses is good, but it is definitely not as
clear cut as that. Some IOMMUs have the ability to force a NoSnoop
access to be snooped, which is typically a better solution than playing
with guest-visible config space. (Of course, this doesn't work if the
IOMMU doesn't have the force snoop feature.)
It seems curious that forcibly preventing NoSnoop fixes Code 43. It
sounds like it is a fairly good hint that virtualisation is going on.
NoSnoop transactions are certainly more efficient than snooped ones, and
the most common use with graphics cards is to put the GPU pagetables in
Write Combining memory for efficient updates. I wonder whether the Code
43 is because the driver detects that NoSnoop accesses are not actually
working.
>
> ##### Patch #3: Set CPUID to Core2duo
>
> There have been few reports where forcing CPUID to Core2duo on KVM
> (-cpu core2duo) would help alleviate Code 43 problems (and also
> increase compatibility with Windows 10 VMs), so I copied all CPUID
> registers from proven-to-be-working KVM configuration using libcpuid
> (https://github.com/anrieff/libcpuid) and applied them to Xen VM.
> LibXL is also patched (attached file) to allow hexadecimal input of
> CPUID (to make it easier to convert CPUID output from libcpuid).
The hex patch looks like a straight improvement, and I would recommend
that you use it to follow the Xen patch submission process. Pay
particular attention to tools/libxl/CODING_STYLE, as your current patch
somewhat inconsistent.
>
> cpuid = [
> '0:eax=0000000a,ebx=756e6547,ecx=6c65746e,edx=49656e69',
> '1:eax=000006fb,ebx=00000800,ecx=80202201,edx=0f8bfbff',
> '2:eax=00000001,ebx=00000000,ecx=00000000,edx=002c307d',
> '3:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
> '4,0:eax=00000121,ebx=01c0003f,ecx=0000003f,edx=00000001',
> '4,1:eax=00000122,ebx=01c0003f,ecx=0000003f,edx=00000001',
> '4,2:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
> '4,3:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
> '5:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
> '6:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
> '7,0:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
> '0x80000000:eax=80000008,ebx=756e6547,ecx=6c65746e,edx=49656e69',
> '0x80000001:eax=000006fb,ebx=00000000,ecx=00000001,edx=20100800',
> '0x80000002:eax=65746e49,ebx=2952286c,ecx=726f4320,edx=4d542865',
> '0x80000003:eax=44203229,ebx=43206f75,ecx=20205550,edx=54202020',
> '0x80000004:eax=30303737,ebx=20402020,ecx=30342e32,edx=007a4847',
> '0x80000005:eax=01ff01ff,ebx=01ff01ff,ecx=40020140,edx=40020140',
> '0x80000006:eax=00000000,ebx=42004200,ecx=02008140,edx=00000000',
> '0x80000007:eax=00000000,ebx=00000000,ecx=00000000,edx=00000000',
> '0x80000008:eax=00003028,ebx=00000000,ecx=00000000,edx=00000000'
> ]
>
> This makes the /proc/cpuinfo almost identical between KVM and Xen VMs
> running Linux. Only exceptions are flags "rep_good" (which is missing
> under Xen) and "eager_fpu" and "xsaveopt" (not seen under KVM), but as
> these are not explicitly set by CPUID but are Linux-specific flags,
> they shouldn't (?) matter on Windows VMs.
rep_good and eager_fpu are Linux synthetic flags. rep_good comes from a
IA32_MISC_ENABLE setting, while eager_fpu is enabled by default in the
presence of xsaveopt.
If you upgrade to Xen 4.7 or later, you should find that xsaveopt starts
properly following your settings of the 0xd,1 leaf. (I did a lot of
CPUID work in 4.7, and have a lot yet to go.)
~Andrew
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2016-07-14 21:34 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-14 20:19 Patches for Nvidia GPU passthrough marcus
2016-07-14 21:34 ` Andrew Cooper
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).