diff options
author | Henrik Riomar <henrik.riomar@gmail.com> | 2018-09-26 22:57:24 +0200 |
---|---|---|
committer | Leonardo Arena <rnalrd@alpinelinux.org> | 2018-10-01 12:22:30 +0000 |
commit | 35dc7cff76a711450db5044179e53d074ad7257a (patch) | |
tree | 268baa27d9ae1a6b3cff9a173bedef0fcfbdac9a | |
parent | 96e1e57fed146a3449b7070143861b7e22ba57f4 (diff) | |
download | aports-35dc7cff76a711450db5044179e53d074ad7257a.tar.bz2 aports-35dc7cff76a711450db5044179e53d074ad7257a.tar.xz |
main/xen: upgrade to 4.10.2
Remove XSA-270 and XSA-274 from secfix list as they are not in XEN but in
the Linux kernel.
Remove XSA-271 for the list due to that tha bug is in XAPI and not in XEN.
-rw-r--r-- | main/xen/APKBUILD | 11 | ||||
-rw-r--r-- | main/xen/git.patch | 8547 |
2 files changed, 3 insertions, 8555 deletions
diff --git a/main/xen/APKBUILD b/main/xen/APKBUILD index 3385370b08..e413a045ed 100644 --- a/main/xen/APKBUILD +++ b/main/xen/APKBUILD @@ -2,8 +2,8 @@ # Contributor: Roger Pau Monne <roger.pau@entel.upc.edu> # Maintainer: William Pitcock <nenolod@dereferenced.org> pkgname=xen -pkgver=4.10.1 -pkgrel=3 +pkgver=4.10.2 +pkgrel=0 pkgdesc="Xen hypervisor" url="http://www.xen.org/" arch="x86_64 armhf aarch64" @@ -120,11 +120,8 @@ options="!strip" # - CVE-2018-10982 XSA-261 # - CVE-2018-10981 XSA-262 # 4.10.1-r3: -# - CVE-2018-14678 XSA-274 # - CVE-2018-3646 XSA-273 # - CVE-2018-15470 XSA-272 -# - CVE-2018-14007 XSA-271 -# - CVE-2018-15471 XSA-270 # - CVE-2018-15468 XSA-269 # - CVE-2018-15469 XSA-268 # - CVE-2018-3665 XSA-267 @@ -178,7 +175,6 @@ source="https://downloads.xenproject.org/release/$pkgname/$pkgver/$pkgname-$pkgv http://xenbits.xen.org/xen-extfiles/tpm_emulator-$_TPMEMU_VERSION.tar.gz http://xenbits.xen.org/xen-extfiles/zlib-$_ZLIB_VERSION.tar.gz http://xenbits.xen.org/xen-extfiles/ipxe-git-$_IPXE_GIT_TAG.tar.gz - git.patch qemu-xen_paths.patch @@ -430,7 +426,7 @@ EOF } -sha512sums="236c02bee69e33644703ed26d323d4c491a91fc05bd0ee0990a7368579f7c82f5bb4510845bf80348fd923024d7d60d521f593dfd0365d971dc592f8ef10fbea xen-4.10.1.tar.gz +sha512sums="2e301b4d6eb106fcb52203bc1208c8fd1fc7bb5d795166c0f86e4085227050301f7daa6f21db440c47bc2ca2c7f87d9b96753cfdf3fa724e0416b5679b84c163 xen-4.10.2.tar.gz 2e0b0fd23e6f10742a5517981e5171c6e88b0a93c83da701b296f5c0861d72c19782daab589a7eac3f9032152a0fc7eff7f5362db8fccc4859564a9aa82329cf gmp-4.3.2.tar.bz2 c2bc9ffc8583aeae71cee9ddcc4418969768d4e3764d47307da54f93981c0109fb07d84b061b3a3628bd00ba4d14a54742bc04848110eb3ae8ca25dbfbaabadb grub-0.97.tar.gz 1465b58279af1647f909450e394fe002ca165f0ff4a0254bfa9fe0e64316f50facdde2729d79a4e632565b4500cf4d6c74192ac0dd3bc9fe09129bbd67ba089d lwip-1.3.0.tar.gz @@ -440,7 +436,6 @@ c2bc9ffc8583aeae71cee9ddcc4418969768d4e3764d47307da54f93981c0109fb07d84b061b3a36 4928b5b82f57645be9408362706ff2c4d9baa635b21b0d41b1c82930e8c60a759b1ea4fa74d7e6c7cae1b7692d006aa5cb72df0c3b88bf049779aa2b566f9d35 tpm_emulator-0.7.4.tar.gz 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e zlib-1.2.3.tar.gz bbcce5e55040e7e29adebd4a5253a046016a6e2e7ff34cf801a42d147e1ec1af57e0297318249bfa9c5bbeac969fe4b37c18cbf845a80b2136d65387a4fc31da ipxe-git-356f6c1b64d7a97746d1816cef8ca22bdd8d0b5d.tar.gz -0fd2622469f3ff136b33a66576319920e050aac3fefa41c06306661eb6f6792fc21a4c15c8928febd10b1a14b4c712a2918532cdb23ccbddba9f1ba55d7d4478 git.patch 1936ab39a1867957fa640eb81c4070214ca4856a2743ba7e49c0cd017917071a9680d015f002c57fa7b9600dbadd29dcea5887f50e6c133305df2669a7a933f3 qemu-xen_paths.patch f095ea373f36381491ad36f0662fb4f53665031973721256b23166e596318581da7cbb0146d0beb2446729adfdb321e01468e377793f6563a67d68b8b0f7ffe3 hotplug-vif-vtrill.patch 77b08e9655e091b0352e4630d520b54c6ca6d659d1d38fbb4b3bfc9ff3e66db433a2e194ead32bb10ff962c382d800a670e82b7a62835b238e294b22808290ea musl-hvmloader-fix-stdint.patch diff --git a/main/xen/git.patch b/main/xen/git.patch deleted file mode 100644 index b4224d8d67..0000000000 --- a/main/xen/git.patch +++ /dev/null @@ -1,8547 +0,0 @@ -diff --git a/docs/man/xl.conf.pod.5 b/docs/man/xl.conf.pod.5 -index da91b8626c..37262a7ef8 100644 ---- a/docs/man/xl.conf.pod.5 -+++ b/docs/man/xl.conf.pod.5 -@@ -185,6 +185,28 @@ massively huge guests). - - =back - -+=item B<vm.cpumask>="CPULIST" -+ -+=item B<vm.hvm.cpumask>="CPULIST" -+ -+=item B<vm.pv.cpumask>="CPULIST" -+ -+Global masks that are applied when creating guests and pinning vcpus -+to indicate which cpus they are allowed to run on. Specifically, -+C<vm.cpumask> applies to all guest types, C<vm.hvm.cpumask> applies to -+both HVM and PVH guests and C<vm.pv.cpumask> applies to PV guests. -+ -+The hard affinity of guest's vcpus are logical-AND'ed with respective -+masks. If the resulting affinity mask is empty, operation will fail. -+ -+Use --ignore-global-affinity-masks to skip applying global masks. -+ -+The default value for these masks are all 1's, i.e. all cpus are allowed. -+ -+Due to bug(s), these options may not interact well with other options -+concerning CPU affinity. One example is CPU pools. Users should always double -+check that the required affinity has taken effect. -+ - =back - - =head1 SEE ALSO -diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown -index 6c673eedc8..470da80174 100644 ---- a/docs/misc/xen-command-line.markdown -+++ b/docs/misc/xen-command-line.markdown -@@ -248,6 +248,9 @@ the NMI watchdog is also enabled. - ### bti (x86) - > `= List of [ thunk=retpoline|lfence|jmp, ibrs=<bool>, ibpb=<bool>, rsb_{vmexit,native}=<bool> ]` - -+**WARNING: This command line option is deprecated, and superseded by -+_spec-ctrl=_ - using both options in combination is undefined.** -+ - Branch Target Injection controls. By default, Xen will pick the most - appropriate BTI mitigations based on compiled in support, loaded microcode, - and hardware details. -@@ -493,9 +496,10 @@ accounting for hardware capabilities as enumerated via CPUID. - - Currently accepted: - --The Speculation Control hardware features `ibrsb`, `stibp`, `ibpb` are used by --default if avaiable. They can be ignored, e.g. `no-ibrsb`, at which point Xen --won't use them itself, and won't offer them to guests. -+The Speculation Control hardware features `ibrsb`, `stibp`, `ibpb`, -+`l1d-flush` and `ssbd` are used by default if available and applicable. They can -+be ignored, e.g. `no-ibrsb`, at which point Xen won't use them itself, and -+won't offer them to guests. - - ### cpuid\_mask\_cpu (AMD only) - > `= fam_0f_rev_c | fam_0f_rev_d | fam_0f_rev_e | fam_0f_rev_f | fam_0f_rev_g | fam_10_rev_b | fam_10_rev_c | fam_11_rev_b` -@@ -916,6 +920,21 @@ Controls EPT related features. - - Specify which console gdbstub should use. See **console**. - -+### gnttab -+> `= List of [ max-ver:<integer>, transitive=<bool> ]` -+ -+> Default: `gnttab=max-ver:2,transitive` -+ -+Control various aspects of the grant table behaviour available to guests. -+ -+* `max-ver` Select the maximum grant table version to offer to guests. Valid -+version are 1 and 2. -+* `transitive` Permit or disallow the use of transitive grants. Note that the -+use of grant table v2 without transitive grants is an ABI breakage from the -+guests point of view. -+ -+The usage of gnttab v2 is not security supported on ARM platforms. -+ - ### gnttab\_max\_frames - > `= <integer>` - -@@ -1348,6 +1367,15 @@ Because responsibility for APIC setup is shared between Xen and the - domain 0 kernel this option is automatically propagated to the domain - 0 command line. - -+### invpcid (x86) -+> `= <boolean>` -+ -+> Default: `true` -+ -+By default, Xen will use the INVPCID instruction for TLB management if -+it is available. This option can be used to cause Xen to fall back to -+older mechanisms, which are generally slower. -+ - ### noirqbalance - > `= <boolean>` - -@@ -1426,6 +1454,20 @@ Flag to enable Memory Protection Keys. - The protection-key feature provides an additional mechanism by which IA-32e - paging controls access to usermode addresses. - -+### pcid (x86) -+> `= <boolean> | xpti=<bool>` -+ -+> Default: `xpti` -+ -+> Can be modified at runtime (change takes effect only for domains created -+ afterwards) -+ -+If available, control usage of the PCID feature of the processor for -+64-bit pv-domains. PCID can be used either for no domain at all (`false`), -+for all of them (`true`), only for those subject to XPTI (`xpti`) or for -+those not subject to XPTI (`no-xpti`). The feature is used only in case -+INVPCID is supported and not disabled via `invpcid=false`. -+ - ### psr (Intel) - > `= List of ( cmt:<boolean> | rmid_max:<integer> | cat:<boolean> | cos_max:<integer> | cdp:<boolean> )` - -@@ -1486,6 +1528,30 @@ do; there may be other custom operating systems which do. If you're - certain you don't plan on having PV guests which use this feature, - turning it off can reduce the attack surface. - -+### pv-l1tf (x86) -+> `= List of [ <bool>, dom0=<bool>, domu=<bool> ]` -+ -+> Default: `false` on believed-unaffected hardware, or in pv-shim mode. -+> `domu` on believed-affected hardware. -+ -+Mitigations for L1TF / XSA-273 / CVE-2018-3620 for PV guests. -+ -+For backwards compatibility, we may not alter an architecturally-legitimate -+pagetable entry a PV guest chooses to write. We can however force such a -+guest into shadow mode so that Xen controls the PTEs which are reachable by -+the CPU pagewalk. -+ -+Shadowing is performed at the point where a PV guest first tries to write an -+L1TF-vulnerable PTE. Therefore, a PV guest kernel which has been updated with -+its own L1TF mitigations will not trigger shadow mode if it is well behaved. -+ -+If CONFIG\_SHADOW\_PAGING is not compiled in, this mitigation instead crashes -+the guest when an L1TF-vulnerable PTE is written, which still allows updated, -+well-behaved PV guests to run, despite Shadow being compiled out. -+ -+In the pv-shim case, Shadow is expected to be compiled out, and a malicious -+guest kernel can only leak data from the shim Xen, rather than the host Xen. -+ - ### pv-shim (x86) - > `= <boolean>` - -@@ -1690,6 +1756,13 @@ Use `smap=hvm` to allow SMAP use by HVM guests only. - Flag to enable Supervisor Mode Execution Protection - Use `smep=hvm` to allow SMEP use by HVM guests only. - -+### smt (x86) -+> `= <boolean>` -+ -+Default: `true` -+ -+Control bring up of multiple hyper-threads per CPU core. -+ - ### snb\_igd\_quirk - > `= <boolean> | cap | <integer>` - -@@ -1698,6 +1771,75 @@ enforces the maximum theoretically necessary timeout of 670ms. Any number - is being interpreted as a custom timeout in milliseconds. Zero or boolean - false disable the quirk workaround, which is also the default. - -+### spec-ctrl (x86) -+> `= List of [ <bool>, xen=<bool>, {pv,hvm,msr-sc,rsb}=<bool>, -+> bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,eager-fpu, -+> l1d-flush}=<bool> ]` -+ -+Controls for speculative execution sidechannel mitigations. By default, Xen -+will pick the most appropriate mitigations based on compiled in support, -+loaded microcode, and hardware details, and will virtualise appropriate -+mitigations for guests to use. -+ -+**WARNING: Any use of this option may interfere with heuristics. Use with -+extreme care.** -+ -+An overall boolean value, `spec-ctrl=no`, can be specified to turn off all -+mitigations, including pieces of infrastructure used to virtualise certain -+mitigation features for guests. This also includes settings which `xpti`, -+`smt`, `pv-l1tf` control, unless the respective option(s) have been -+specified earlier on the command line. -+ -+Alternatively, a slightly more restricted `spec-ctrl=no-xen` can be used to -+turn off all of Xen's mitigations, while leaving the virtualisation support -+in place for guests to use. -+ -+Use of a positive boolean value for either of these options is invalid. -+ -+The booleans `pv=`, `hvm=`, `msr-sc=` and `rsb=` offer fine grained control -+over the alternative blocks used by Xen. These impact Xen's ability to -+protect itself, and Xen's ability to virtualise support for guests to use. -+ -+* `pv=` and `hvm=` offer control over all suboptions for PV and HVM guests -+ respectively. -+* `msr-sc=` offers control over Xen's support for manipulating MSR\_SPEC\_CTRL -+ on entry and exit. These blocks are necessary to virtualise support for -+ guests and if disabled, guests will be unable to use IBRS/STIBP/SSBD/etc. -+* `rsb=` offers control over whether to overwrite the Return Stack Buffer / -+ Return Address Stack on entry to Xen. -+ -+If Xen was compiled with INDIRECT\_THUNK support, `bti-thunk=` can be used to -+select which of the thunks gets patched into the `__x86_indirect_thunk_%reg` -+locations. The default thunk is `retpoline` (generally preferred for Intel -+hardware), with the alternatives being `jmp` (a `jmp *%reg` gadget, minimal -+overhead), and `lfence` (an `lfence; jmp *%reg` gadget, preferred for AMD). -+ -+On hardware supporting IBRS (Indirect Branch Restricted Speculation), the -+`ibrs=` option can be used to force or prevent Xen using the feature itself. -+If Xen is not using IBRS itself, functionality is still set up so IBRS can be -+virtualised for guests. -+ -+On hardware supporting IBPB (Indirect Branch Prediction Barrier), the `ibpb=` -+option can be used to force (the default) or prevent Xen from issuing branch -+prediction barriers on vcpu context switches. -+ -+On hardware supporting SSBD (Speculative Store Bypass Disable), the `ssbd=` -+option can be used to force or prevent Xen using the feature itself. On AMD -+hardware, this is a global option applied at boot, and not virtualised for -+guest use. On Intel hardware, the feature is virtualised for guests, -+independently of Xen's choice of setting. -+ -+On all hardware, the `eager-fpu=` option can be used to force or prevent Xen -+from using fully eager FPU context switches. This is currently implemented as -+a global control. By default, Xen will choose to use fully eager context -+switches on hardware believed to speculate past #NM exceptions. -+ -+On hardware supporting L1D_FLUSH, the `l1d-flush=` option can be used to force -+or prevent Xen from issuing an L1 data cache flush on each VMEntry. -+Irrespective of Xen's setting, the feature is virtualised for HVM guests to -+use. By default, Xen will enable this mitigation on hardware believed to be -+vulnerable to L1TF. -+ - ### sync\_console - > `= <boolean>` - -@@ -1923,14 +2065,24 @@ clustered mode. The default, given no hint from the **FADT**, is cluster - mode. - - ### xpti --> `= <boolean>` -+> `= List of [ default | <boolean> | dom0=<bool> | domu=<bool> ]` - --> Default: `false` on AMD hardware -+> Default: `false` on hardware not to be vulnerable to Meltdown (e.g. AMD) - > Default: `true` everywhere else - - Override default selection of whether to isolate 64-bit PV guest page - tables. - -+`true` activates page table isolation even on hardware not vulnerable by -+Meltdown for all domains. -+ -+`false` deactivates page table isolation on all systems for all domains. -+ -+`default` sets the default behaviour. -+ -+With `dom0` and `domu` it is possible to control page table isolation -+for dom0 or guest domains only. -+ - ### xsave - > `= <boolean>` - -diff --git a/tools/Makefile b/tools/Makefile -index ab7a01ee1b..67977ad850 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -232,7 +232,7 @@ subdir-all-qemu-xen-dir: qemu-xen-dir-find - else \ - enable_trace_backend='' ; \ - fi ; \ -- PKG_CONFIG_PATH=$(XEN_ROOT)/tools/pkg-config \ -+ PKG_CONFIG_PATH=$(XEN_ROOT)/tools/pkg-config$${PKG_CONFIG_PATH:+:$${PKG_CONFIG_PATH}} \ - $$source/configure --enable-xen --target-list=i386-softmmu \ - $(QEMU_XEN_ENABLE_DEBUG) \ - $$enable_trace_backend \ -diff --git a/tools/examples/xl.conf b/tools/examples/xl.conf -index 374b6bbc2e..0446deb304 100644 ---- a/tools/examples/xl.conf -+++ b/tools/examples/xl.conf -@@ -37,3 +37,8 @@ - # (which can take a long time to find out if launching huge guests). - # see xl.conf(5) for details. - #claim_mode=1 -+ -+# Specify global vcpu hard affinity masks. See xl.conf(5) for details. -+#vm.cpumask="0-7" -+#vm.pv.cpumask="0-3" -+#vm.hvm.cpumask="3-7" -diff --git a/tools/libacpi/Makefile b/tools/libacpi/Makefile -index a47a658a25..c17f3924cc 100644 ---- a/tools/libacpi/Makefile -+++ b/tools/libacpi/Makefile -@@ -43,7 +43,7 @@ all: $(C_SRC) $(H_SRC) - - $(H_SRC): $(ACPI_BUILD_DIR)/%.h: %.asl iasl - iasl -vs -p $(ACPI_BUILD_DIR)/$*.$(TMP_SUFFIX) -tc $< -- sed -e 's/AmlCode/$*/g' $(ACPI_BUILD_DIR)/$*.hex >$@ -+ sed -e 's/AmlCode/$*/g' -e 's/_aml_code//g' $(ACPI_BUILD_DIR)/$*.hex >$@ - rm -f $(addprefix $(ACPI_BUILD_DIR)/, $*.aml $*.hex) - - $(MK_DSDT): mk_dsdt.c -@@ -76,7 +76,7 @@ $(ACPI_BUILD_DIR)/dsdt_anycpu_arm.asl: $(MK_DSDT) - - $(C_SRC): $(ACPI_BUILD_DIR)/%.c: iasl $(ACPI_BUILD_DIR)/%.asl - iasl -vs -p $(ACPI_BUILD_DIR)/$*.$(TMP_SUFFIX) -tc $(ACPI_BUILD_DIR)/$*.asl -- sed -e 's/AmlCode/$*/g' $(ACPI_BUILD_DIR)/$*.hex > $@.$(TMP_SUFFIX) -+ sed -e 's/AmlCode/$*/g' -e 's/_aml_code//g' $(ACPI_BUILD_DIR)/$*.hex > $@.$(TMP_SUFFIX) - echo "int $*_len=sizeof($*);" >> $@.$(TMP_SUFFIX) - mv -f $@.$(TMP_SUFFIX) $@ - rm -f $(addprefix $(ACPI_BUILD_DIR)/, $*.aml $*.hex) -diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c -index 9fa2f7c360..21537f06f1 100644 ---- a/tools/libxc/xc_cpuid_x86.c -+++ b/tools/libxc/xc_cpuid_x86.c -@@ -575,6 +575,12 @@ static void xc_cpuid_pv_policy(xc_interface *xch, - break; - } - -+ case 0x80000008: -+ regs[0] &= 0x0000ffffu; -+ regs[1] = info->featureset[featureword_of(X86_FEATURE_CLZERO)]; -+ regs[2] = regs[3] = 0; -+ break; -+ - case 0x00000005: /* MONITOR/MWAIT */ - case 0x0000000b: /* Extended Topology Enumeration */ - case 0x8000000a: /* SVM revision and features */ -diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c -index 3a21f4e7da..52e16c20ed 100644 ---- a/tools/libxl/libxl_cpuid.c -+++ b/tools/libxl/libxl_cpuid.c -@@ -204,7 +204,9 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str) - {"avx512-4fmaps",0x00000007, 0, CPUID_REG_EDX, 3, 1}, - {"ibrsb", 0x00000007, 0, CPUID_REG_EDX, 26, 1}, - {"stibp", 0x00000007, 0, CPUID_REG_EDX, 27, 1}, -+ {"l1d-flush", 0x00000007, 0, CPUID_REG_EDX, 28, 1}, - {"arch-caps", 0x00000007, 0, CPUID_REG_EDX, 29, 1}, -+ {"ssbd", 0x00000007, 0, CPUID_REG_EDX, 31, 1}, - - {"lahfsahf", 0x80000001, NA, CPUID_REG_ECX, 0, 1}, - {"cmplegacy", 0x80000001, NA, CPUID_REG_ECX, 1, 1}, -diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c -index b51178b9fd..07399bb8e0 100644 ---- a/tools/libxl/libxl_dm.c -+++ b/tools/libxl/libxl_dm.c -@@ -798,6 +798,8 @@ static char *qemu_disk_scsi_drive_string(libxl__gc *gc, const char *target_path, - int colo_mode) - { - char *drive = NULL; -+ char *common = GCSPRINTF("cache=writeback,readonly=%s", -+ disk->readwrite ? "off" : "on"); - const char *exportname = disk->colo_export; - const char *active_disk = disk->active_disk; - const char *hidden_disk = disk->hidden_disk; -@@ -805,8 +807,8 @@ static char *qemu_disk_scsi_drive_string(libxl__gc *gc, const char *target_path, - switch (colo_mode) { - case LIBXL__COLO_NONE: - drive = libxl__sprintf -- (gc, "file=%s,if=scsi,bus=0,unit=%d,format=%s,cache=writeback", -- target_path, unit, format); -+ (gc, "%s,file=%s,if=scsi,bus=0,unit=%d,format=%s", -+ common, target_path, unit, format); - break; - case LIBXL__COLO_PRIMARY: - /* -@@ -819,13 +821,13 @@ static char *qemu_disk_scsi_drive_string(libxl__gc *gc, const char *target_path, - * vote-threshold=1 - */ - drive = GCSPRINTF( -- "if=scsi,bus=0,unit=%d,cache=writeback,driver=quorum," -+ "%s,if=scsi,bus=0,unit=%d,,driver=quorum," - "id=%s," - "children.0.file.filename=%s," - "children.0.driver=%s," - "read-pattern=fifo," - "vote-threshold=1", -- unit, exportname, target_path, format); -+ common, unit, exportname, target_path, format); - break; - case LIBXL__COLO_SECONDARY: - /* -@@ -839,7 +841,7 @@ static char *qemu_disk_scsi_drive_string(libxl__gc *gc, const char *target_path, - * file.backing.backing=exportname, - */ - drive = GCSPRINTF( -- "if=scsi,id=top-colo,bus=0,unit=%d,cache=writeback," -+ "%s,if=scsi,id=top-colo,bus=0,unit=%d," - "driver=replication," - "mode=secondary," - "top-id=top-colo," -@@ -848,7 +850,7 @@ static char *qemu_disk_scsi_drive_string(libxl__gc *gc, const char *target_path, - "file.backing.driver=qcow2," - "file.backing.file.filename=%s," - "file.backing.backing=%s", -- unit, active_disk, hidden_disk, exportname); -+ common, unit, active_disk, hidden_disk, exportname); - break; - default: - abort(); -@@ -866,6 +868,8 @@ static char *qemu_disk_ide_drive_string(libxl__gc *gc, const char *target_path, - const char *exportname = disk->colo_export; - const char *active_disk = disk->active_disk; - const char *hidden_disk = disk->hidden_disk; -+ -+ assert(disk->readwrite); /* should have been checked earlier */ - - switch (colo_mode) { - case LIBXL__COLO_NONE: -@@ -1575,8 +1579,9 @@ static int libxl__build_device_model_args_new(libxl__gc *gc, - if (strncmp(disks[i].vdev, "sd", 2) == 0) { - if (colo_mode == LIBXL__COLO_SECONDARY) { - drive = libxl__sprintf -- (gc, "if=none,driver=%s,file=%s,id=%s", -- format, target_path, disks[i].colo_export); -+ (gc, "if=none,driver=%s,file=%s,id=%s,readonly=%s", -+ format, target_path, disks[i].colo_export, -+ disks[i].readwrite ? "off" : "on"); - - flexarray_append(dm_args, "-drive"); - flexarray_append(dm_args, drive); -@@ -2586,7 +2591,7 @@ int libxl__need_xenpv_qemu(libxl__gc *gc, libxl_domain_config *d_config) - goto out; - } - -- if (d_config->num_vfbs > 0) { -+ if (d_config->num_vfbs > 0 || d_config->num_p9s > 0) { - ret = 1; - goto out; - } -diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c -index b1a46c667d..85298d277d 100644 ---- a/tools/misc/xen-cpuid.c -+++ b/tools/misc/xen-cpuid.c -@@ -165,9 +165,8 @@ static const char *str_7d0[32] = - [4 ... 25] = "REZ", - - [26] = "ibrsb", [27] = "stibp", -- [28] = "REZ", [29] = "arch_caps", -- -- [30 ... 31] = "REZ", -+ [28] = "l1d_flush", [29] = "arch_caps", -+ [30] = "REZ", [31] = "ssbd", - }; - - static struct { -diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml -index 13cf3b5bf4..5a8c377603 100644 ---- a/tools/ocaml/xenstored/store.ml -+++ b/tools/ocaml/xenstored/store.ml -@@ -262,7 +262,8 @@ let path_write store perm path value = - Node.check_perm store.root perm Perms.WRITE; - Node.set_value store.root value, false - ) else -- Path.apply_modify store.root path do_write, !node_created -+ let root = Path.apply_modify store.root path do_write in -+ root, !node_created - - let path_rm store perm path = - let do_rm node name = -diff --git a/tools/xl/xl.c b/tools/xl/xl.c -index 179908b4f6..7d2142f16f 100644 ---- a/tools/xl/xl.c -+++ b/tools/xl/xl.c -@@ -28,6 +28,9 @@ - #include <libxl_utils.h> - #include <libxlutil.h> - #include "xl.h" -+#include "xl_parse.h" -+ -+#include "xl_utils.h" - - xentoollog_logger_stdiostream *logger; - int dryrun_only; -@@ -42,6 +45,9 @@ char *default_gatewaydev = NULL; - char *default_vifbackend = NULL; - char *default_remus_netbufscript = NULL; - char *default_colo_proxy_script = NULL; -+libxl_bitmap global_vm_affinity_mask; -+libxl_bitmap global_hvm_affinity_mask; -+libxl_bitmap global_pv_affinity_mask; - enum output_format default_output_format = OUTPUT_FORMAT_JSON; - int claim_mode = 1; - bool progress_use_cr = 0; -@@ -203,6 +209,26 @@ static void parse_global_config(const char *configfile, - if (!xlu_cfg_get_long (config, "max_maptrack_frames", &l, 0)) - max_maptrack_frames = l; - -+ libxl_bitmap_init(&global_vm_affinity_mask); -+ libxl_cpu_bitmap_alloc(ctx, &global_vm_affinity_mask, 0); -+ libxl_bitmap_init(&global_hvm_affinity_mask); -+ libxl_cpu_bitmap_alloc(ctx, &global_hvm_affinity_mask, 0); -+ libxl_bitmap_init(&global_pv_affinity_mask); -+ libxl_cpu_bitmap_alloc(ctx, &global_pv_affinity_mask, 0); -+ -+ if (!xlu_cfg_get_string (config, "vm.cpumask", &buf, 0)) -+ parse_cpurange(buf, &global_vm_affinity_mask); -+ else -+ libxl_bitmap_set_any(&global_vm_affinity_mask); -+ if (!xlu_cfg_get_string (config, "vm.hvm.cpumask", &buf, 0)) -+ parse_cpurange(buf, &global_hvm_affinity_mask); -+ else -+ libxl_bitmap_set_any(&global_hvm_affinity_mask); -+ if (!xlu_cfg_get_string (config, "vm.pv.cpumask", &buf, 0)) -+ parse_cpurange(buf, &global_pv_affinity_mask); -+ else -+ libxl_bitmap_set_any(&global_pv_affinity_mask); -+ - xlu_cfg_destroy(config); - } - -diff --git a/tools/xl/xl.h b/tools/xl/xl.h -index 6b60d1db50..7b9f58fc6c 100644 ---- a/tools/xl/xl.h -+++ b/tools/xl/xl.h -@@ -41,6 +41,7 @@ struct domain_create { - int vncautopass; - int console_autoconnect; - int checkpointed_stream; -+ int ignore_global_affinity_masks; - const char *config_file; - char *extra_config; /* extra config string */ - const char *restore_file; -@@ -277,6 +278,9 @@ extern char *default_colo_proxy_script; - extern char *blkdev_start; - extern int max_grant_frames; - extern int max_maptrack_frames; -+extern libxl_bitmap global_vm_affinity_mask; -+extern libxl_bitmap global_hvm_affinity_mask; -+extern libxl_bitmap global_pv_affinity_mask; - - enum output_format { - OUTPUT_FORMAT_JSON, -@@ -292,6 +296,9 @@ typedef enum { - } domain_restart_type; - - extern void printf_info_sexp(int domid, libxl_domain_config *d_config, FILE *fh); -+extern void apply_global_affinity_masks(libxl_domain_type type, -+ libxl_bitmap *vcpu_affinity_array, -+ unsigned int size); - - #define XL_GLOBAL_CONFIG XEN_CONFIG_DIR "/xl.conf" - #define XL_LOCK_FILE XEN_LOCK_DIR "/xl" -diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c -index 5546cf66e7..1a6c28dfdc 100644 ---- a/tools/xl/xl_cmdtable.c -+++ b/tools/xl/xl_cmdtable.c -@@ -34,7 +34,8 @@ struct cmd_spec cmd_table[] = { - "-e Do not wait in the background for the death of the domain.\n" - "-V, --vncviewer Connect to the VNC display after the domain is created.\n" - "-A, --vncviewer-autopass\n" -- " Pass VNC password to viewer via stdin." -+ " Pass VNC password to viewer via stdin.\n" -+ "--ignore-global-affinity-masks Ignore global masks in xl.conf." - }, - { "config-update", - &main_config_update, 1, 1, -@@ -224,7 +225,8 @@ struct cmd_spec cmd_table[] = { - &main_vcpupin, 1, 1, - "Set which CPUs a VCPU can use", - "[option] <Domain> <VCPU|all> <Hard affinity|-|all> <Soft affinity|-|all>", -- "-f, --force undo an override pinning done by the kernel", -+ "-f, --force undo an override pinning done by the kernel\n" -+ "--ignore-global-affinity-masks Ignore global masks in xl.conf", - }, - { "vcpu-set", - &main_vcpuset, 0, 1, -diff --git a/tools/xl/xl_vcpu.c b/tools/xl/xl_vcpu.c -index 8e735b38c1..3384eeed06 100644 ---- a/tools/xl/xl_vcpu.c -+++ b/tools/xl/xl_vcpu.c -@@ -68,6 +68,61 @@ static void print_domain_vcpuinfo(uint32_t domid, uint32_t nr_cpus) - libxl_vcpuinfo_list_free(vcpuinfo, nb_vcpu); - } - -+void apply_global_affinity_masks(libxl_domain_type type, -+ libxl_bitmap *vcpu_affinity_array, -+ unsigned int size) -+{ -+ libxl_bitmap *mask = &global_vm_affinity_mask; -+ libxl_bitmap *type_mask; -+ unsigned int i; -+ -+ switch (type) { -+ case LIBXL_DOMAIN_TYPE_HVM: -+ case LIBXL_DOMAIN_TYPE_PVH: -+ type_mask = &global_hvm_affinity_mask; -+ break; -+ case LIBXL_DOMAIN_TYPE_PV: -+ type_mask = &global_pv_affinity_mask; -+ break; -+ default: -+ fprintf(stderr, "Unknown guest type\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ for (i = 0; i < size; i++) { -+ int rc; -+ libxl_bitmap *t = &vcpu_affinity_array[i]; -+ libxl_bitmap b1, b2; -+ -+ libxl_bitmap_init(&b1); -+ libxl_bitmap_init(&b2); -+ -+ rc = libxl_bitmap_and(ctx, &b1, t, mask); -+ if (rc) { -+ fprintf(stderr, "libxl_bitmap_and errored\n"); -+ exit(EXIT_FAILURE); -+ } -+ rc = libxl_bitmap_and(ctx, &b2, &b1, type_mask); -+ if (rc) { -+ fprintf(stderr, "libxl_bitmap_and errored\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (libxl_bitmap_is_empty(&b2)) { -+ fprintf(stderr, "vcpu hard affinity map is empty\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ /* Replace target bitmap with the result */ -+ libxl_bitmap_dispose(t); -+ libxl_bitmap_init(t); -+ libxl_bitmap_copy_alloc(ctx, t, &b2); -+ -+ libxl_bitmap_dispose(&b1); -+ libxl_bitmap_dispose(&b2); -+ } -+} -+ - static void vcpulist(int argc, char **argv) - { - libxl_dominfo *dominfo; -@@ -118,6 +173,7 @@ int main_vcpupin(int argc, char **argv) - { - static struct option opts[] = { - {"force", 0, 0, 'f'}, -+ {"ignore-global-affinity-masks", 0, 0, 'i'}, - COMMON_LONG_OPTS - }; - libxl_vcpuinfo *vcpuinfo; -@@ -132,15 +188,18 @@ int main_vcpupin(int argc, char **argv) - const char *vcpu, *hard_str, *soft_str; - char *endptr; - int opt, nb_cpu, nb_vcpu, rc = EXIT_FAILURE; -- bool force = false; -+ bool force = false, ignore_masks = false; - - libxl_bitmap_init(&cpumap_hard); - libxl_bitmap_init(&cpumap_soft); - -- SWITCH_FOREACH_OPT(opt, "f", opts, "vcpu-pin", 3) { -+ SWITCH_FOREACH_OPT(opt, "fi", opts, "vcpu-pin", 3) { - case 'f': - force = true; - break; -+ case 'i': -+ ignore_masks = true; -+ break; - default: - break; - } -@@ -222,6 +281,23 @@ int main_vcpupin(int argc, char **argv) - goto out; - } - -+ /* Only hard affinity matters here */ -+ if (!ignore_masks) { -+ libxl_domain_config d_config; -+ -+ libxl_domain_config_init(&d_config); -+ rc = libxl_retrieve_domain_configuration(ctx, domid, &d_config); -+ if (rc) { -+ fprintf(stderr, "Could not retrieve domain configuration\n"); -+ libxl_domain_config_dispose(&d_config); -+ goto out; -+ } -+ -+ apply_global_affinity_masks(d_config.b_info.type, hard, 1); -+ -+ libxl_domain_config_dispose(&d_config); -+ } -+ - if (force) { - if (libxl_set_vcpuaffinity_force(ctx, domid, vcpuid, hard, soft)) { - fprintf(stderr, "Could not set affinity for vcpu `%ld'.\n", -diff --git a/tools/xl/xl_vmcontrol.c b/tools/xl/xl_vmcontrol.c -index 89c2b25ded..a1d633795c 100644 ---- a/tools/xl/xl_vmcontrol.c -+++ b/tools/xl/xl_vmcontrol.c -@@ -804,6 +804,36 @@ int create_domain(struct domain_create *dom_info) - parse_config_data(config_source, config_data, config_len, &d_config); - } - -+ if (!dom_info->ignore_global_affinity_masks) { -+ libxl_domain_build_info *b_info = &d_config.b_info; -+ -+ /* It is possible that no hard affinity is specified in config file. -+ * Generate hard affinity maps now if we care about those. -+ */ -+ if (b_info->num_vcpu_hard_affinity == 0 && -+ (!libxl_bitmap_is_full(&global_vm_affinity_mask) || -+ (b_info->type == LIBXL_DOMAIN_TYPE_PV && -+ !libxl_bitmap_is_full(&global_pv_affinity_mask)) || -+ (b_info->type != LIBXL_DOMAIN_TYPE_PV && -+ !libxl_bitmap_is_full(&global_hvm_affinity_mask)) -+ )) { -+ b_info->num_vcpu_hard_affinity = b_info->max_vcpus; -+ b_info->vcpu_hard_affinity = -+ xmalloc(b_info->max_vcpus * sizeof(libxl_bitmap)); -+ -+ for (i = 0; i < b_info->num_vcpu_hard_affinity; i++) { -+ libxl_bitmap *m = &b_info->vcpu_hard_affinity[i]; -+ libxl_bitmap_init(m); -+ libxl_cpu_bitmap_alloc(ctx, m, 0); -+ libxl_bitmap_set_any(m); -+ } -+ } -+ -+ apply_global_affinity_masks(b_info->type, -+ b_info->vcpu_hard_affinity, -+ b_info->num_vcpu_hard_affinity); -+ } -+ - if (migrate_fd >= 0) { - if (d_config.c_info.name) { - /* when we receive a domain we get its name from the config -@@ -1124,7 +1154,7 @@ int main_create(int argc, char **argv) - const char *filename = NULL; - struct domain_create dom_info; - int paused = 0, debug = 0, daemonize = 1, console_autoconnect = 0, -- quiet = 0, monitor = 1, vnc = 0, vncautopass = 0; -+ quiet = 0, monitor = 1, vnc = 0, vncautopass = 0, ignore_masks = 0; - int opt, rc; - static struct option opts[] = { - {"dryrun", 0, 0, 'n'}, -@@ -1132,6 +1162,7 @@ int main_create(int argc, char **argv) - {"defconfig", 1, 0, 'f'}, - {"vncviewer", 0, 0, 'V'}, - {"vncviewer-autopass", 0, 0, 'A'}, -+ {"ignore-global-affinity-masks", 0, 0, 'i'}, - COMMON_LONG_OPTS - }; - -@@ -1142,7 +1173,7 @@ int main_create(int argc, char **argv) - argc--; argv++; - } - -- SWITCH_FOREACH_OPT(opt, "Fnqf:pcdeVA", opts, "create", 0) { -+ SWITCH_FOREACH_OPT(opt, "Fnqf:pcdeVAi", opts, "create", 0) { - case 'f': - filename = optarg; - break; -@@ -1174,6 +1205,9 @@ int main_create(int argc, char **argv) - case 'A': - vnc = vncautopass = 1; - break; -+ case 'i': -+ ignore_masks = 1; -+ break; - } - - memset(&dom_info, 0, sizeof(dom_info)); -@@ -1203,6 +1237,7 @@ int main_create(int argc, char **argv) - dom_info.vnc = vnc; - dom_info.vncautopass = vncautopass; - dom_info.console_autoconnect = console_autoconnect; -+ dom_info.ignore_global_affinity_masks = ignore_masks; - - rc = create_domain(&dom_info); - if (rc < 0) { -diff --git a/xen/Makefile b/xen/Makefile -index ecec297b9b..580af86931 100644 ---- a/xen/Makefile -+++ b/xen/Makefile -@@ -2,7 +2,7 @@ - # All other places this is stored (eg. compile.h) should be autogenerated. - export XEN_VERSION = 4 - export XEN_SUBVERSION = 10 --export XEN_EXTRAVERSION ?= .1$(XEN_VENDORVERSION) -+export XEN_EXTRAVERSION ?= .2-pre$(XEN_VENDORVERSION) - export XEN_FULLVERSION = $(XEN_VERSION).$(XEN_SUBVERSION)$(XEN_EXTRAVERSION) - -include xen-version - -diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig -index f621e799ed..33535ca9aa 100644 ---- a/xen/arch/x86/Kconfig -+++ b/xen/arch/x86/Kconfig -@@ -71,6 +71,7 @@ config SHADOW_PAGING - * Running HVM guests on hardware lacking hardware paging support - (First-generation Intel VT-x or AMD SVM). - * Live migration of PV guests. -+ * L1TF sidechannel mitigation for PV guests. - - Under a small number of specific workloads, shadow paging may be - deliberately used as a performance optimisation. -diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk -index 70e9d8f5cf..03b1b581f3 100644 ---- a/xen/arch/x86/Rules.mk -+++ b/xen/arch/x86/Rules.mk -@@ -23,6 +23,7 @@ $(call as-insn-check,CFLAGS,CC,"rdseed %eax",-DHAVE_GAS_RDSEED) - $(call as-insn-check,CFLAGS,CC,".equ \"x\"$$(comma)1", \ - -U__OBJECT_LABEL__ -DHAVE_GAS_QUOTED_SYM \ - '-D__OBJECT_LABEL__=$(subst $(BASEDIR)/,,$(CURDIR))/$$@') -+$(call as-insn-check,CFLAGS,CC,"invpcid (%rax)$$(comma)%rax",-DHAVE_AS_INVPCID) - - CFLAGS += -mno-red-zone -mno-sse -fpic - CFLAGS += -fno-asynchronous-unwind-tables -diff --git a/xen/arch/x86/acpi/power.c b/xen/arch/x86/acpi/power.c -index 1e4e5680a7..f3480aa800 100644 ---- a/xen/arch/x86/acpi/power.c -+++ b/xen/arch/x86/acpi/power.c -@@ -28,6 +28,7 @@ - #include <asm/tboot.h> - #include <asm/apic.h> - #include <asm/io_apic.h> -+#include <asm/spec_ctrl.h> - #include <acpi/cpufreq/cpufreq.h> - - uint32_t system_reset_counter = 1; -@@ -163,6 +164,7 @@ static int enter_state(u32 state) - { - unsigned long flags; - int error; -+ struct cpu_info *ci; - unsigned long cr4; - - if ( (state <= ACPI_STATE_S0) || (state > ACPI_S_STATES_MAX) ) -@@ -203,12 +205,18 @@ static int enter_state(u32 state) - printk(XENLOG_ERR "Some devices failed to power down."); - system_state = SYS_STATE_resume; - device_power_up(error); -+ console_end_sync(); - error = -EIO; - goto done; - } - else - error = 0; - -+ ci = get_cpu_info(); -+ spec_ctrl_enter_idle(ci); -+ /* Avoid NMI/#MC using MSR_SPEC_CTRL until we've reloaded microcode. */ -+ ci->spec_ctrl_flags &= ~SCF_ist_wrmsr; -+ - ACPI_FLUSH_CPU_CACHE(); - - switch ( state ) -@@ -243,17 +251,23 @@ static int enter_state(u32 state) - if ( (state == ACPI_STATE_S3) && error ) - tboot_s3_error(error); - -+ console_end_sync(); -+ -+ microcode_resume_cpu(0); -+ -+ /* Re-enabled default NMI/#MC use of MSR_SPEC_CTRL. */ -+ ci->spec_ctrl_flags |= (default_spec_ctrl_flags & SCF_ist_wrmsr); -+ spec_ctrl_exit_idle(ci); -+ - done: - spin_debug_enable(); - local_irq_restore(flags); -- console_end_sync(); - acpi_sleep_post(state); - if ( hvm_cpu_up() ) - BUG(); -+ cpufreq_add_cpu(0); - - enable_cpu: -- cpufreq_add_cpu(0); -- microcode_resume_cpu(0); - rcu_barrier(); - mtrr_aps_sync_begin(); - enable_nonboot_cpus(); -diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c -index fc9677f020..76078b55b2 100644 ---- a/xen/arch/x86/cpu/amd.c -+++ b/xen/arch/x86/cpu/amd.c -@@ -9,6 +9,7 @@ - #include <asm/amd.h> - #include <asm/hvm/support.h> - #include <asm/setup.h> /* amd_init_cpu */ -+#include <asm/spec_ctrl.h> - #include <asm/acpi.h> - #include <asm/apic.h> - -@@ -504,17 +505,23 @@ static void amd_get_topology(struct cpuinfo_x86 *c) - u32 eax, ebx, ecx, edx; - - cpuid(0x8000001e, &eax, &ebx, &ecx, &edx); -- c->compute_unit_id = ebx & 0xFF; - c->x86_num_siblings = ((ebx >> 8) & 0x3) + 1; -+ -+ if (c->x86 < 0x17) -+ c->compute_unit_id = ebx & 0xFF; -+ else { -+ c->cpu_core_id = ebx & 0xFF; -+ c->x86_max_cores /= c->x86_num_siblings; -+ } - } - - if (opt_cpu_info) - printk("CPU %d(%d) -> Processor %d, %s %d\n", - cpu, c->x86_max_cores, c->phys_proc_id, -- cpu_has(c, X86_FEATURE_TOPOEXT) ? "Compute Unit" : -- "Core", -- cpu_has(c, X86_FEATURE_TOPOEXT) ? c->compute_unit_id : -- c->cpu_core_id); -+ c->compute_unit_id != INVALID_CUID ? "Compute Unit" -+ : "Core", -+ c->compute_unit_id != INVALID_CUID ? c->compute_unit_id -+ : c->cpu_core_id); - } - - static void early_init_amd(struct cpuinfo_x86 *c) -@@ -594,6 +601,25 @@ static void init_amd(struct cpuinfo_x86 *c) - c->x86_capability); - } - -+ /* -+ * If the user has explicitly chosen to disable Memory Disambiguation -+ * to mitigiate Speculative Store Bypass, poke the appropriate MSR. -+ */ -+ if (opt_ssbd) { -+ int bit = -1; -+ -+ switch (c->x86) { -+ case 0x15: bit = 54; break; -+ case 0x16: bit = 33; break; -+ case 0x17: bit = 10; break; -+ } -+ -+ if (bit >= 0 && !rdmsr_safe(MSR_AMD64_LS_CFG, value)) { -+ value |= 1ull << bit; -+ wrmsr_safe(MSR_AMD64_LS_CFG, value); -+ } -+ } -+ - /* MFENCE stops RDTSC speculation */ - if (!cpu_has_lfence_dispatch) - __set_bit(X86_FEATURE_MFENCE_RDTSC, c->x86_capability); -diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c -index fdb2bf1779..eb266c5ba6 100644 ---- a/xen/arch/x86/cpu/common.c -+++ b/xen/arch/x86/cpu/common.c -@@ -14,6 +14,7 @@ - #include <public/sysctl.h> /* for XEN_INVALID_{SOCKET,CORE}_ID */ - - #include "cpu.h" -+#include "mcheck/x86_mca.h" - - bool_t opt_arat = 1; - boolean_param("arat", opt_arat); -@@ -345,6 +346,9 @@ static void __init early_cpu_detect(void) - hap_paddr_bits = PADDR_BITS; - } - -+ if (c->x86_vendor != X86_VENDOR_AMD) -+ park_offline_cpus = opt_mce; -+ - initialize_cpu_data(0); - } - -@@ -747,6 +751,7 @@ void load_system_tables(void) - [IST_MCE - 1] = stack_top + IST_MCE * PAGE_SIZE, - [IST_DF - 1] = stack_top + IST_DF * PAGE_SIZE, - [IST_NMI - 1] = stack_top + IST_NMI * PAGE_SIZE, -+ [IST_DB - 1] = stack_top + IST_DB * PAGE_SIZE, - - [IST_MAX ... ARRAY_SIZE(tss->ist) - 1] = - 0x8600111111111111ul, -@@ -774,6 +779,7 @@ void load_system_tables(void) - set_ist(&idt_tables[cpu][TRAP_double_fault], IST_DF); - set_ist(&idt_tables[cpu][TRAP_nmi], IST_NMI); - set_ist(&idt_tables[cpu][TRAP_machine_check], IST_MCE); -+ set_ist(&idt_tables[cpu][TRAP_debug], IST_DB); - - /* - * Bottom-of-stack must be 16-byte aligned! -diff --git a/xen/arch/x86/cpu/mcheck/mce.c b/xen/arch/x86/cpu/mcheck/mce.c -index df0106ec3c..1ee1870de9 100644 ---- a/xen/arch/x86/cpu/mcheck/mce.c -+++ b/xen/arch/x86/cpu/mcheck/mce.c -@@ -695,12 +695,15 @@ static void cpu_bank_free(unsigned int cpu) - - mcabanks_free(poll); - mcabanks_free(clr); -+ -+ per_cpu(poll_bankmask, cpu) = NULL; -+ per_cpu(mce_clear_banks, cpu) = NULL; - } - - static int cpu_bank_alloc(unsigned int cpu) - { -- struct mca_banks *poll = mcabanks_alloc(); -- struct mca_banks *clr = mcabanks_alloc(); -+ struct mca_banks *poll = per_cpu(poll_bankmask, cpu) ?: mcabanks_alloc(); -+ struct mca_banks *clr = per_cpu(mce_clear_banks, cpu) ?: mcabanks_alloc(); - - if ( !poll || !clr ) - { -@@ -728,7 +731,13 @@ static int cpu_callback( - - case CPU_UP_CANCELED: - case CPU_DEAD: -- cpu_bank_free(cpu); -+ if ( !park_offline_cpus ) -+ cpu_bank_free(cpu); -+ break; -+ -+ case CPU_REMOVE: -+ if ( park_offline_cpus ) -+ cpu_bank_free(cpu); - break; - } - -diff --git a/xen/arch/x86/cpu/mcheck/mce_intel.c b/xen/arch/x86/cpu/mcheck/mce_intel.c -index e5dd956a24..4474a34e34 100644 ---- a/xen/arch/x86/cpu/mcheck/mce_intel.c -+++ b/xen/arch/x86/cpu/mcheck/mce_intel.c -@@ -636,8 +636,6 @@ static void clear_cmci(void) - - static void cpu_mcheck_disable(void) - { -- clear_in_cr4(X86_CR4_MCE); -- - if ( cmci_support && opt_mce ) - clear_cmci(); - } -diff --git a/xen/arch/x86/cpu/mtrr/generic.c b/xen/arch/x86/cpu/mtrr/generic.c -index e9c0e5e059..7ba0c3f0fe 100644 ---- a/xen/arch/x86/cpu/mtrr/generic.c -+++ b/xen/arch/x86/cpu/mtrr/generic.c -@@ -5,6 +5,7 @@ - #include <xen/mm.h> - #include <xen/stdbool.h> - #include <asm/flushtlb.h> -+#include <asm/invpcid.h> - #include <asm/io.h> - #include <asm/mtrr.h> - #include <asm/msr.h> -@@ -400,8 +401,10 @@ static DEFINE_SPINLOCK(set_atomicity_lock); - * has been called. - */ - --static void prepare_set(void) -+static bool prepare_set(void) - { -+ unsigned long cr4; -+ - /* Note that this is not ideal, since the cache is only flushed/disabled - for this CPU while the MTRRs are changed, but changing this requires - more invasive changes to the way the kernel boots */ -@@ -412,18 +415,24 @@ static void prepare_set(void) - write_cr0(read_cr0() | X86_CR0_CD); - wbinvd(); - -- /* TLB flushing here relies on Xen always using CR4.PGE. */ -- BUILD_BUG_ON(!(XEN_MINIMAL_CR4 & X86_CR4_PGE)); -- write_cr4(read_cr4() & ~X86_CR4_PGE); -+ cr4 = read_cr4(); -+ if (cr4 & X86_CR4_PGE) -+ write_cr4(cr4 & ~X86_CR4_PGE); -+ else if (use_invpcid) -+ invpcid_flush_all(); -+ else -+ write_cr3(read_cr3()); - - /* Save MTRR state */ - rdmsrl(MSR_MTRRdefType, deftype); - - /* Disable MTRRs, and set the default type to uncached */ - mtrr_wrmsr(MSR_MTRRdefType, deftype & ~0xcff); -+ -+ return cr4 & X86_CR4_PGE; - } - --static void post_set(void) -+static void post_set(bool pge) - { - /* Intel (P6) standard MTRRs */ - mtrr_wrmsr(MSR_MTRRdefType, deftype); -@@ -432,7 +441,12 @@ static void post_set(void) - write_cr0(read_cr0() & ~X86_CR0_CD); - - /* Reenable CR4.PGE (also flushes the TLB) */ -- write_cr4(read_cr4() | X86_CR4_PGE); -+ if (pge) -+ write_cr4(read_cr4() | X86_CR4_PGE); -+ else if (use_invpcid) -+ invpcid_flush_all(); -+ else -+ write_cr3(read_cr3()); - - spin_unlock(&set_atomicity_lock); - } -@@ -441,14 +455,15 @@ static void generic_set_all(void) - { - unsigned long mask, count; - unsigned long flags; -+ bool pge; - - local_irq_save(flags); -- prepare_set(); -+ pge = prepare_set(); - - /* Actually set the state */ - mask = set_mtrr_state(); - -- post_set(); -+ post_set(pge); - local_irq_restore(flags); - - /* Use the atomic bitops to update the global mask */ -@@ -457,7 +472,6 @@ static void generic_set_all(void) - set_bit(count, &smp_changes_mask); - mask >>= 1; - } -- - } - - static void generic_set_mtrr(unsigned int reg, unsigned long base, -@@ -474,11 +488,12 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, - { - unsigned long flags; - struct mtrr_var_range *vr; -+ bool pge; - - vr = &mtrr_state.var_ranges[reg]; - - local_irq_save(flags); -- prepare_set(); -+ pge = prepare_set(); - - if (size == 0) { - /* The invalid bit is kept in the mask, so we simply clear the -@@ -499,7 +514,7 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, - mtrr_wrmsr(MSR_IA32_MTRR_PHYSMASK(reg), vr->mask); - } - -- post_set(); -+ post_set(pge); - local_irq_restore(flags); - } - -diff --git a/xen/arch/x86/cpu/vpmu_intel.c b/xen/arch/x86/cpu/vpmu_intel.c -index 207e2e712c..6e27f6ec8e 100644 ---- a/xen/arch/x86/cpu/vpmu_intel.c -+++ b/xen/arch/x86/cpu/vpmu_intel.c -@@ -454,13 +454,11 @@ static int core2_vpmu_alloc_resource(struct vcpu *v) - - if ( is_hvm_vcpu(v) ) - { -- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); -- if ( vmx_add_host_load_msr(MSR_CORE_PERF_GLOBAL_CTRL) ) -+ if ( vmx_add_host_load_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, 0) ) - goto out_err; - -- if ( vmx_add_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL) ) -+ if ( vmx_add_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, 0) ) - goto out_err; -- vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0); - } - - core2_vpmu_cxt = xzalloc_bytes(sizeof(*core2_vpmu_cxt) + -@@ -535,27 +533,7 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, - uint64_t *enabled_cntrs; - - if ( !core2_vpmu_msr_common_check(msr, &type, &index) ) -- { -- /* Special handling for BTS */ -- if ( msr == MSR_IA32_DEBUGCTLMSR ) -- { -- supported |= IA32_DEBUGCTLMSR_TR | IA32_DEBUGCTLMSR_BTS | -- IA32_DEBUGCTLMSR_BTINT; -- -- if ( cpu_has(¤t_cpu_data, X86_FEATURE_DSCPL) ) -- supported |= IA32_DEBUGCTLMSR_BTS_OFF_OS | -- IA32_DEBUGCTLMSR_BTS_OFF_USR; -- if ( !(msr_content & ~supported) && -- vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) ) -- return 0; -- if ( (msr_content & supported) && -- !vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) ) -- printk(XENLOG_G_WARNING -- "%pv: Debug Store unsupported on this CPU\n", -- current); -- } - return -EINVAL; -- } - - ASSERT(!supported); - -@@ -613,7 +591,7 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, - return -EINVAL; - - if ( is_hvm_vcpu(v) ) -- vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, -+ vmx_read_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, - &core2_vpmu_cxt->global_ctrl); - else - rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, core2_vpmu_cxt->global_ctrl); -@@ -682,7 +660,7 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, - return -EINVAL; - - if ( is_hvm_vcpu(v) ) -- vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, -+ vmx_read_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, - &core2_vpmu_cxt->global_ctrl); - else - rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, core2_vpmu_cxt->global_ctrl); -@@ -701,7 +679,7 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, - else - { - if ( is_hvm_vcpu(v) ) -- vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content); -+ vmx_write_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, msr_content); - else - wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, msr_content); - } -@@ -735,7 +713,7 @@ static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content) - break; - case MSR_CORE_PERF_GLOBAL_CTRL: - if ( is_hvm_vcpu(v) ) -- vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content); -+ vmx_read_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, msr_content); - else - rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, *msr_content); - break; -diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c -index b3c9ac6c48..24b9495faa 100644 ---- a/xen/arch/x86/cpuid.c -+++ b/xen/arch/x86/cpuid.c -@@ -43,6 +43,16 @@ static int __init parse_xen_cpuid(const char *s) - if ( !val ) - setup_clear_cpu_cap(X86_FEATURE_STIBP); - } -+ else if ( (val = parse_boolean("l1d-flush", s, ss)) >= 0 ) -+ { -+ if ( !val ) -+ setup_clear_cpu_cap(X86_FEATURE_L1D_FLUSH); -+ } -+ else if ( (val = parse_boolean("ssbd", s, ss)) >= 0 ) -+ { -+ if ( !val ) -+ setup_clear_cpu_cap(X86_FEATURE_SSBD); -+ } - else - rc = -EINVAL; - -@@ -368,6 +378,28 @@ static void __init calculate_host_policy(void) - } - } - -+static void __init guest_common_feature_adjustments(uint32_t *fs) -+{ -+ /* Unconditionally claim to be able to set the hypervisor bit. */ -+ __set_bit(X86_FEATURE_HYPERVISOR, fs); -+ -+ /* -+ * If IBRS is offered to the guest, unconditionally offer STIBP. It is a -+ * nop on non-HT hardware, and has this behaviour to make heterogeneous -+ * setups easier to manage. -+ */ -+ if ( test_bit(X86_FEATURE_IBRSB, fs) ) -+ __set_bit(X86_FEATURE_STIBP, fs); -+ -+ /* -+ * On hardware which supports IBRS/IBPB, we can offer IBPB independently -+ * of IBRS by using the AMD feature bit. An administrator may wish for -+ * performance reasons to offer IBPB without IBRS. -+ */ -+ if ( host_cpuid_policy.feat.ibrsb ) -+ __set_bit(X86_FEATURE_IBPB, fs); -+} -+ - static void __init calculate_pv_max_policy(void) - { - struct cpuid_policy *p = &pv_max_cpuid_policy; -@@ -380,18 +412,14 @@ static void __init calculate_pv_max_policy(void) - for ( i = 0; i < ARRAY_SIZE(pv_featureset); ++i ) - pv_featureset[i] &= pv_featuremask[i]; - -- /* Unconditionally claim to be able to set the hypervisor bit. */ -- __set_bit(X86_FEATURE_HYPERVISOR, pv_featureset); -- -- /* On hardware with IBRS/IBPB support, there are further adjustments. */ -- if ( test_bit(X86_FEATURE_IBRSB, pv_featureset) ) -- { -- /* Offer STIBP unconditionally. It is a nop on non-HT hardware. */ -- __set_bit(X86_FEATURE_STIBP, pv_featureset); -+ /* -+ * If Xen isn't virtualising MSR_SPEC_CTRL for PV guests because of -+ * administrator choice, hide the feature. -+ */ -+ if ( !boot_cpu_has(X86_FEATURE_SC_MSR_PV) ) -+ __clear_bit(X86_FEATURE_IBRSB, pv_featureset); - -- /* AMD's IBPB is a subset of IBRS/IBPB. */ -- __set_bit(X86_FEATURE_IBPB, pv_featureset); -- } -+ guest_common_feature_adjustments(pv_featureset); - - sanitise_featureset(pv_featureset); - cpuid_featureset_to_policy(pv_featureset, p); -@@ -419,9 +447,6 @@ static void __init calculate_hvm_max_policy(void) - for ( i = 0; i < ARRAY_SIZE(hvm_featureset); ++i ) - hvm_featureset[i] &= hvm_featuremask[i]; - -- /* Unconditionally claim to be able to set the hypervisor bit. */ -- __set_bit(X86_FEATURE_HYPERVISOR, hvm_featureset); -- - /* - * Xen can provide an APIC emulation to HVM guests even if the host's APIC - * isn't enabled. -@@ -437,6 +462,13 @@ static void __init calculate_hvm_max_policy(void) - raw_cpuid_policy.basic.sep ) - __set_bit(X86_FEATURE_SEP, hvm_featureset); - -+ /* -+ * If Xen isn't virtualising MSR_SPEC_CTRL for HVM guests because of -+ * administrator choice, hide the feature. -+ */ -+ if ( !boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ) -+ __clear_bit(X86_FEATURE_IBRSB, hvm_featureset); -+ - /* - * With VT-x, some features are only supported by Xen if dedicated - * hardware support is also available. -@@ -450,15 +482,7 @@ static void __init calculate_hvm_max_policy(void) - __clear_bit(X86_FEATURE_XSAVES, hvm_featureset); - } - -- /* On hardware with IBRS/IBPB support, there are further adjustments. */ -- if ( test_bit(X86_FEATURE_IBRSB, hvm_featureset) ) -- { -- /* Offer STIBP unconditionally. It is a nop on non-HT hardware. */ -- __set_bit(X86_FEATURE_STIBP, hvm_featureset); -- -- /* AMD's IBPB is a subset of IBRS/IBPB. */ -- __set_bit(X86_FEATURE_IBPB, hvm_featureset); -- } -+ guest_common_feature_adjustments(hvm_featureset); - - sanitise_featureset(hvm_featureset); - cpuid_featureset_to_policy(hvm_featureset, p); -@@ -601,14 +625,6 @@ void recalculate_cpuid_policy(struct domain *d) - recalculate_xstate(p); - recalculate_misc(p); - -- /* -- * Override STIBP to match IBRS. Guests can safely use STIBP -- * functionality on non-HT hardware, but can't necesserily protect -- * themselves from SP2/Spectre/Branch Target Injection if STIBP is hidden -- * on HT-capable hardware. -- */ -- p->feat.stibp = p->feat.ibrsb; -- - for ( i = 0; i < ARRAY_SIZE(p->cache.raw); ++i ) - { - if ( p->cache.subleaf[i].type >= 1 && -diff --git a/xen/arch/x86/debug.c b/xen/arch/x86/debug.c -index 9159f32db4..a500df01ac 100644 ---- a/xen/arch/x86/debug.c -+++ b/xen/arch/x86/debug.c -@@ -98,7 +98,7 @@ dbg_pv_va2mfn(dbgva_t vaddr, struct domain *dp, uint64_t pgd3val) - l2_pgentry_t l2e, *l2t; - l1_pgentry_t l1e, *l1t; - unsigned long cr3 = (pgd3val ? pgd3val : dp->vcpu[0]->arch.cr3); -- mfn_t mfn = maddr_to_mfn(cr3); -+ mfn_t mfn = maddr_to_mfn(cr3_pa(cr3)); - - DBGP2("vaddr:%lx domid:%d cr3:%lx pgd3:%lx\n", vaddr, dp->domain_id, - cr3, pgd3val); -diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c -index 5a4d5c3bfc..2020e0b682 100644 ---- a/xen/arch/x86/domain.c -+++ b/xen/arch/x86/domain.c -@@ -107,10 +107,11 @@ static void play_dead(void) - local_irq_disable(); - - /* -- * NOTE: After cpu_exit_clear, per-cpu variables are no longer accessible, -- * as they may be freed at any time. In this case, heap corruption or -- * #PF can occur (when heap debugging is enabled). For example, even -- * printk() can involve tasklet scheduling, which touches per-cpu vars. -+ * NOTE: After cpu_exit_clear, per-cpu variables may no longer accessible, -+ * as they may be freed at any time if offline CPUs don't get parked. In -+ * this case, heap corruption or #PF can occur (when heap debugging is -+ * enabled). For example, even printk() can involve tasklet scheduling, -+ * which touches per-cpu vars. - * - * Consider very carefully when adding code to *dead_idle. Most hypervisor - * subsystems are unsafe to call. -@@ -1517,17 +1518,12 @@ void paravirt_ctxt_switch_from(struct vcpu *v) - void paravirt_ctxt_switch_to(struct vcpu *v) - { - root_pgentry_t *root_pgt = this_cpu(root_pgt); -- unsigned long cr4; - - if ( root_pgt ) - root_pgt[root_table_offset(PERDOMAIN_VIRT_START)] = - l4e_from_page(v->domain->arch.perdomain_l3_pg, - __PAGE_HYPERVISOR_RW); - -- cr4 = pv_guest_cr4_to_real_cr4(v); -- if ( unlikely(cr4 != read_cr4()) ) -- write_cr4(cr4); -- - if ( unlikely(v->arch.debugreg[7] & DR7_ACTIVE_MASK) ) - activate_debugregs(v); - -@@ -1640,7 +1636,7 @@ static void __context_switch(void) - if ( cpu_has_xsaves && is_hvm_vcpu(n) ) - set_msr_xss(n->arch.hvm_vcpu.msr_xss); - } -- vcpu_restore_fpu_eager(n); -+ vcpu_restore_fpu_nonlazy(n, false); - nd->arch.ctxt_switch->to(n); - } - -@@ -1693,6 +1689,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next) - - ASSERT(local_irq_is_enabled()); - -+ get_cpu_info()->use_pv_cr3 = false; - get_cpu_info()->xen_cr3 = 0; - - cpumask_copy(&dirty_mask, next->vcpu_dirty_cpumask); -diff --git a/xen/arch/x86/domain_page.c b/xen/arch/x86/domain_page.c -index 3432a854dd..9a52276866 100644 ---- a/xen/arch/x86/domain_page.c -+++ b/xen/arch/x86/domain_page.c -@@ -51,7 +51,7 @@ static inline struct vcpu *mapcache_current_vcpu(void) - if ( (v = idle_vcpu[smp_processor_id()]) == current ) - sync_local_execstate(); - /* We must now be running on the idle page table. */ -- ASSERT(read_cr3() == __pa(idle_pg_table)); -+ ASSERT(cr3_pa(read_cr3()) == __pa(idle_pg_table)); - } - - return v; -diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c -index 74e9749d89..eefd94eb92 100644 ---- a/xen/arch/x86/domctl.c -+++ b/xen/arch/x86/domctl.c -@@ -226,7 +226,8 @@ static int update_domain_cpuid_info(struct domain *d, - */ - call_policy_changed = (is_hvm_domain(d) && - ((old_7d0 ^ p->feat.raw[0].d) & -- cpufeat_mask(X86_FEATURE_IBRSB))); -+ (cpufeat_mask(X86_FEATURE_IBRSB) | -+ cpufeat_mask(X86_FEATURE_L1D_FLUSH)))); - break; - - case 0xa: -@@ -1227,7 +1228,7 @@ long arch_do_domctl( - if ( _xcr0_accum ) - { - if ( evc->size >= PV_XSAVE_HDR_SIZE + XSTATE_AREA_MIN_SIZE ) -- ret = validate_xstate(_xcr0, _xcr0_accum, -+ ret = validate_xstate(d, _xcr0, _xcr0_accum, - &_xsave_area->xsave_hdr); - } - else if ( !_xcr0 ) -@@ -1251,8 +1252,7 @@ long arch_do_domctl( - vcpu_pause(v); - v->arch.xcr0 = _xcr0; - v->arch.xcr0_accum = _xcr0_accum; -- if ( _xcr0_accum & XSTATE_NONLAZY ) -- v->arch.nonlazy_xstate_used = 1; -+ v->arch.nonlazy_xstate_used = _xcr0_accum & XSTATE_NONLAZY; - compress_xsave_states(v, _xsave_area, - evc->size - PV_XSAVE_HDR_SIZE); - vcpu_unpause(v); -diff --git a/xen/arch/x86/flushtlb.c b/xen/arch/x86/flushtlb.c -index f6d7ad1650..797c5d52cc 100644 ---- a/xen/arch/x86/flushtlb.c -+++ b/xen/arch/x86/flushtlb.c -@@ -8,9 +8,12 @@ - */ - - #include <xen/sched.h> -+#include <xen/smp.h> - #include <xen/softirq.h> - #include <asm/flushtlb.h> -+#include <asm/invpcid.h> - #include <asm/page.h> -+#include <asm/pv/domain.h> - - /* Debug builds: Wrap frequently to stress-test the wrap logic. */ - #ifdef NDEBUG -@@ -49,6 +52,8 @@ static u32 pre_flush(void) - raise_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ); - - skip_clocktick: -+ hvm_flush_guest_tlbs(); -+ - return t2; - } - -@@ -69,21 +74,65 @@ static void post_flush(u32 t) - this_cpu(tlbflush_time) = t; - } - --void write_cr3(unsigned long cr3) -+static void do_tlb_flush(void) -+{ -+ u32 t = pre_flush(); -+ -+ if ( use_invpcid ) -+ invpcid_flush_all(); -+ else -+ { -+ unsigned long cr4 = read_cr4(); -+ -+ write_cr4(cr4 ^ X86_CR4_PGE); -+ write_cr4(cr4); -+ } -+ -+ post_flush(t); -+} -+ -+void switch_cr3_cr4(unsigned long cr3, unsigned long cr4) - { -- unsigned long flags, cr4 = read_cr4(); -+ unsigned long flags, old_cr4; - u32 t; -+ unsigned long old_pcid = cr3_pcid(read_cr3()); - - /* This non-reentrant function is sometimes called in interrupt context. */ - local_irq_save(flags); - - t = pre_flush(); - -- hvm_flush_guest_tlbs(); -- -- write_cr4(cr4 & ~X86_CR4_PGE); -- asm volatile ( "mov %0, %%cr3" : : "r" (cr3) : "memory" ); -- write_cr4(cr4); -+ old_cr4 = read_cr4(); -+ if ( old_cr4 & X86_CR4_PGE ) -+ { -+ /* -+ * X86_CR4_PGE set means PCID is inactive. -+ * We have to purge the TLB via flipping cr4.pge. -+ */ -+ old_cr4 = cr4 & ~X86_CR4_PGE; -+ write_cr4(old_cr4); -+ } -+ else if ( use_invpcid ) -+ /* -+ * Flushing the TLB via INVPCID is necessary only in case PCIDs are -+ * in use, which is true only with INVPCID being available. -+ * Without PCID usage the following write_cr3() will purge the TLB -+ * (we are in the cr4.pge off path) of all entries. -+ * Using invpcid_flush_all_nonglobals() seems to be faster than -+ * invpcid_flush_all(), so use that. -+ */ -+ invpcid_flush_all_nonglobals(); -+ -+ write_cr3(cr3); -+ -+ if ( old_cr4 != cr4 ) -+ write_cr4(cr4); -+ else if ( old_pcid != cr3_pcid(cr3) ) -+ /* -+ * Make sure no TLB entries related to the old PCID created between -+ * flushing the TLB and writing the new %cr3 value remain in the TLB. -+ */ -+ invpcid_flush_single_context(old_pcid); - - post_flush(t); - -@@ -113,22 +162,32 @@ unsigned int flush_area_local(const void *va, unsigned int flags) - * are various errata surrounding INVLPG usage on superpages, and - * a full flush is in any case not *that* expensive. - */ -- asm volatile ( "invlpg %0" -- : : "m" (*(const char *)(va)) : "memory" ); -+ if ( read_cr4() & X86_CR4_PCIDE ) -+ { -+ unsigned long addr = (unsigned long)va; -+ -+ /* -+ * Flush the addresses for all potential address spaces. -+ * We can't check the current domain for being subject to -+ * XPTI as current might be the idle vcpu while we still have -+ * some XPTI domain TLB entries. -+ * Using invpcid is okay here, as with PCID enabled we always -+ * have global pages disabled. -+ */ -+ invpcid_flush_one(PCID_PV_PRIV, addr); -+ invpcid_flush_one(PCID_PV_USER, addr); -+ if ( !cpu_has_no_xpti ) -+ { -+ invpcid_flush_one(PCID_PV_PRIV | PCID_PV_XPTI, addr); -+ invpcid_flush_one(PCID_PV_USER | PCID_PV_XPTI, addr); -+ } -+ } -+ else -+ asm volatile ( "invlpg %0" -+ : : "m" (*(const char *)(va)) : "memory" ); - } - else -- { -- u32 t = pre_flush(); -- unsigned long cr4 = read_cr4(); -- -- hvm_flush_guest_tlbs(); -- -- write_cr4(cr4 & ~X86_CR4_PGE); -- barrier(); -- write_cr4(cr4); -- -- post_flush(t); -- } -+ do_tlb_flush(); - } - - if ( flags & FLUSH_CACHE ) -@@ -161,5 +220,8 @@ unsigned int flush_area_local(const void *va, unsigned int flags) - - local_irq_restore(irqfl); - -+ if ( flags & FLUSH_ROOT_PGTBL ) -+ get_cpu_info()->root_pgt_changed = true; -+ - return flags; - } -diff --git a/xen/arch/x86/genapic/x2apic.c b/xen/arch/x86/genapic/x2apic.c -index 5fffb317d9..4fb9a2225d 100644 ---- a/xen/arch/x86/genapic/x2apic.c -+++ b/xen/arch/x86/genapic/x2apic.c -@@ -201,18 +201,21 @@ static int update_clusterinfo( - if ( !cluster_cpus_spare ) - cluster_cpus_spare = xzalloc(cpumask_t); - if ( !cluster_cpus_spare || -- !alloc_cpumask_var(&per_cpu(scratch_mask, cpu)) ) -+ !cond_alloc_cpumask_var(&per_cpu(scratch_mask, cpu)) ) - err = -ENOMEM; - break; - case CPU_UP_CANCELED: - case CPU_DEAD: -+ case CPU_REMOVE: -+ if ( park_offline_cpus == (action != CPU_REMOVE) ) -+ break; - if ( per_cpu(cluster_cpus, cpu) ) - { - cpumask_clear_cpu(cpu, per_cpu(cluster_cpus, cpu)); - if ( cpumask_empty(per_cpu(cluster_cpus, cpu)) ) -- xfree(per_cpu(cluster_cpus, cpu)); -+ XFREE(per_cpu(cluster_cpus, cpu)); - } -- free_cpumask_var(per_cpu(scratch_mask, cpu)); -+ FREE_CPUMASK_VAR(per_cpu(scratch_mask, cpu)); - break; - } - -diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c -index 8229c635e4..f18cbbd55a 100644 ---- a/xen/arch/x86/hpet.c -+++ b/xen/arch/x86/hpet.c -@@ -509,6 +509,8 @@ static void hpet_attach_channel(unsigned int cpu, - static void hpet_detach_channel(unsigned int cpu, - struct hpet_event_channel *ch) - { -+ unsigned int next; -+ - spin_lock_irq(&ch->lock); - - ASSERT(ch == per_cpu(cpu_bc_channel, cpu)); -@@ -517,7 +519,7 @@ static void hpet_detach_channel(unsigned int cpu, - - if ( cpu != ch->cpu ) - spin_unlock_irq(&ch->lock); -- else if ( cpumask_empty(ch->cpumask) ) -+ else if ( (next = cpumask_first(ch->cpumask)) >= nr_cpu_ids ) - { - ch->cpu = -1; - clear_bit(HPET_EVT_USED_BIT, &ch->flags); -@@ -525,7 +527,7 @@ static void hpet_detach_channel(unsigned int cpu, - } - else - { -- ch->cpu = cpumask_first(ch->cpumask); -+ ch->cpu = next; - set_channel_irq_affinity(ch); - local_irq_enable(); - } -diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c -index b282089e03..03db6b3d31 100644 ---- a/xen/arch/x86/hvm/emulate.c -+++ b/xen/arch/x86/hvm/emulate.c -@@ -1900,6 +1900,7 @@ static int hvmemul_get_fpu( - * masking of all exceptions by FNSTENV.) - */ - save_fpu_enable(); -+ curr->fpu_initialised = true; - curr->fpu_dirtied = true; - if ( (fpu_ctxt->fcw & 0x3f) != 0x3f ) - { -@@ -1991,13 +1992,20 @@ static void hvmemul_put_fpu( - if ( backout == X86EMUL_FPU_fpu ) - { - /* -- * To back out changes to the register file simply adjust state such -- * that upon next FPU insn use by the guest we'll reload the state -- * saved (or freshly loaded) by hvmemul_get_fpu(). -+ * To back out changes to the register file -+ * - in fully eager mode, restore original state immediately, -+ * - in lazy mode, simply adjust state such that upon next FPU insn -+ * use by the guest we'll reload the state saved (or freshly loaded) -+ * by hvmemul_get_fpu(). - */ -- curr->fpu_dirtied = false; -- stts(); -- hvm_funcs.fpu_leave(curr); -+ if ( curr->arch.fully_eager_fpu ) -+ vcpu_restore_fpu_nonlazy(curr, false); -+ else -+ { -+ curr->fpu_dirtied = false; -+ stts(); -+ hvm_funcs.fpu_leave(curr); -+ } - } - } - -@@ -2113,22 +2121,20 @@ static int _hvm_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt, - - vio->mmio_retry = 0; - -- switch ( rc = x86_emulate(&hvmemul_ctxt->ctxt, ops) ) -+ rc = x86_emulate(&hvmemul_ctxt->ctxt, ops); -+ if ( rc == X86EMUL_OKAY && vio->mmio_retry ) -+ rc = X86EMUL_RETRY; -+ -+ if ( !hvm_vcpu_io_need_completion(vio) ) - { -- case X86EMUL_OKAY: -- if ( vio->mmio_retry ) -- rc = X86EMUL_RETRY; -- /* fall through */ -- default: - vio->mmio_cache_count = 0; - vio->mmio_insn_bytes = 0; -- break; -- -- case X86EMUL_RETRY: -+ } -+ else -+ { - BUILD_BUG_ON(sizeof(vio->mmio_insn) < sizeof(hvmemul_ctxt->insn_buf)); - vio->mmio_insn_bytes = hvmemul_ctxt->insn_buf_bytes; - memcpy(vio->mmio_insn, hvmemul_ctxt->insn_buf, vio->mmio_insn_bytes); -- break; - } - - if ( hvmemul_ctxt->ctxt.retire.singlestep ) -diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c -index f7aed7f69e..28377091ca 100644 ---- a/xen/arch/x86/hvm/hpet.c -+++ b/xen/arch/x86/hvm/hpet.c -@@ -264,13 +264,20 @@ static void hpet_set_timer(HPETState *h, unsigned int tn, - diff = (timer_is_32bit(h, tn) && (-diff > HPET_TINY_TIME_SPAN)) - ? (uint32_t)diff : 0; - -+ destroy_periodic_time(&h->pt[tn]); - if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) ) -+ { - /* if LegacyReplacementRoute bit is set, HPET specification requires - timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC, - timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */ - irq = (tn == 0) ? 0 : 8; -+ h->pt[tn].source = PTSRC_isa; -+ } - else -+ { - irq = timer_int_route(h, tn); -+ h->pt[tn].source = PTSRC_ioapic; -+ } - - /* - * diff is the time from now when the timer should fire, for a periodic -diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c -index 18adec5ad8..8e237eb1ac 100644 ---- a/xen/arch/x86/hvm/hvm.c -+++ b/xen/arch/x86/hvm/hvm.c -@@ -895,6 +895,9 @@ const char *hvm_efer_valid(const struct vcpu *v, uint64_t value, - else - p = &host_cpuid_policy; - -+ if ( value & ~EFER_KNOWN_MASK ) -+ return "Unknown bits set"; -+ - if ( (value & EFER_SCE) && !p->extd.syscall ) - return "SCE without feature"; - -@@ -1258,7 +1261,7 @@ static int hvm_load_cpu_xsave_states(struct domain *d, hvm_domain_context_t *h) - ctxt = (struct hvm_hw_cpu_xsave *)&h->data[h->cur]; - h->cur += desc->length; - -- err = validate_xstate(ctxt->xcr0, ctxt->xcr0_accum, -+ err = validate_xstate(d, ctxt->xcr0, ctxt->xcr0_accum, - (const void *)&ctxt->save_area.xsave_hdr); - if ( err ) - { -@@ -1313,8 +1316,7 @@ static int hvm_load_cpu_xsave_states(struct domain *d, hvm_domain_context_t *h) - - v->arch.xcr0 = ctxt->xcr0; - v->arch.xcr0_accum = ctxt->xcr0_accum; -- if ( ctxt->xcr0_accum & XSTATE_NONLAZY ) -- v->arch.nonlazy_xstate_used = 1; -+ v->arch.nonlazy_xstate_used = ctxt->xcr0_accum & XSTATE_NONLAZY; - compress_xsave_states(v, &ctxt->save_area, - size - offsetof(struct hvm_hw_cpu_xsave, save_area)); - -diff --git a/xen/arch/x86/hvm/ioreq.c b/xen/arch/x86/hvm/ioreq.c -index d5afe20cc8..25b2445429 100644 ---- a/xen/arch/x86/hvm/ioreq.c -+++ b/xen/arch/x86/hvm/ioreq.c -@@ -87,14 +87,17 @@ static void hvm_io_assist(struct hvm_ioreq_vcpu *sv, uint64_t data) - - static bool hvm_wait_for_io(struct hvm_ioreq_vcpu *sv, ioreq_t *p) - { -+ unsigned int prev_state = STATE_IOREQ_NONE; -+ - while ( sv->pending ) - { - unsigned int state = p->state; - -- rmb(); -- switch ( state ) -+ smp_rmb(); -+ -+ recheck: -+ if ( unlikely(state == STATE_IOREQ_NONE) ) - { -- case STATE_IOREQ_NONE: - /* - * The only reason we should see this case is when an - * emulator is dying and it races with an I/O being -@@ -102,14 +105,30 @@ static bool hvm_wait_for_io(struct hvm_ioreq_vcpu *sv, ioreq_t *p) - */ - hvm_io_assist(sv, ~0ul); - break; -+ } -+ -+ if ( unlikely(state < prev_state) ) -+ { -+ gdprintk(XENLOG_ERR, "Weird HVM ioreq state transition %u -> %u\n", -+ prev_state, state); -+ sv->pending = false; -+ domain_crash(sv->vcpu->domain); -+ return false; /* bail */ -+ } -+ -+ switch ( prev_state = state ) -+ { - case STATE_IORESP_READY: /* IORESP_READY -> NONE */ - p->state = STATE_IOREQ_NONE; - hvm_io_assist(sv, p->data); - break; - case STATE_IOREQ_READY: /* IOREQ_{READY,INPROCESS} -> IORESP_READY */ - case STATE_IOREQ_INPROCESS: -- wait_on_xen_event_channel(sv->ioreq_evtchn, p->state != state); -- break; -+ wait_on_xen_event_channel(sv->ioreq_evtchn, -+ ({ state = p->state; -+ smp_rmb(); -+ state != prev_state; })); -+ goto recheck; - default: - gdprintk(XENLOG_ERR, "Weird HVM iorequest state %u\n", state); - sv->pending = false; -diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c -index f528e2d081..c85d004402 100644 ---- a/xen/arch/x86/hvm/irq.c -+++ b/xen/arch/x86/hvm/irq.c -@@ -41,6 +41,26 @@ static void assert_gsi(struct domain *d, unsigned ioapic_gsi) - vioapic_irq_positive_edge(d, ioapic_gsi); - } - -+int hvm_ioapic_assert(struct domain *d, unsigned int gsi, bool level) -+{ -+ struct hvm_irq *hvm_irq = hvm_domain_irq(d); -+ int vector; -+ -+ if ( gsi >= hvm_irq->nr_gsis ) -+ { -+ ASSERT_UNREACHABLE(); -+ return -1; -+ } -+ -+ spin_lock(&d->arch.hvm_domain.irq_lock); -+ if ( !level || hvm_irq->gsi_assert_count[gsi]++ == 0 ) -+ assert_gsi(d, gsi); -+ vector = vioapic_get_vector(d, gsi); -+ spin_unlock(&d->arch.hvm_domain.irq_lock); -+ -+ return vector; -+} -+ - static void assert_irq(struct domain *d, unsigned ioapic_gsi, unsigned pic_irq) - { - assert_gsi(d, ioapic_gsi); -diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S -index bf092fe071..5e7c080c7c 100644 ---- a/xen/arch/x86/hvm/svm/entry.S -+++ b/xen/arch/x86/hvm/svm/entry.S -@@ -83,7 +83,7 @@ UNLIKELY_END(svm_trace) - mov VCPUMSR_spec_ctrl_raw(%rax), %eax - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_GUEST /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ -+ SPEC_CTRL_EXIT_TO_HVM /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ - - pop %r15 - pop %r14 -@@ -108,7 +108,7 @@ UNLIKELY_END(svm_trace) - - GET_CURRENT(bx) - -- SPEC_CTRL_ENTRY_FROM_VMEXIT /* Req: b=curr %rsp=regs/cpuinfo, Clob: acd */ -+ SPEC_CTRL_ENTRY_FROM_HVM /* Req: b=curr %rsp=regs/cpuinfo, Clob: acd */ - /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ - - mov VCPU_svm_vmcb(%rbx),%rcx -diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c -index dedec5752d..aad3655855 100644 ---- a/xen/arch/x86/hvm/svm/svm.c -+++ b/xen/arch/x86/hvm/svm/svm.c -@@ -546,7 +546,10 @@ void svm_update_guest_cr(struct vcpu *v, unsigned int cr) - if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) ) - { - if ( v != current ) -- hw_cr0_mask |= X86_CR0_TS; -+ { -+ if ( !v->arch.fully_eager_fpu ) -+ hw_cr0_mask |= X86_CR0_TS; -+ } - else if ( vmcb_get_cr0(vmcb) & X86_CR0_TS ) - svm_fpu_enter(v); - } -@@ -1033,7 +1036,8 @@ static void svm_ctxt_switch_from(struct vcpu *v) - if ( unlikely((read_efer() & EFER_SVME) == 0) ) - return; - -- svm_fpu_leave(v); -+ if ( !v->arch.fully_eager_fpu ) -+ svm_fpu_leave(v); - - svm_save_dr(v); - svm_lwp_save(v); -@@ -1046,6 +1050,7 @@ static void svm_ctxt_switch_from(struct vcpu *v) - set_ist(&idt_tables[cpu][TRAP_double_fault], IST_DF); - set_ist(&idt_tables[cpu][TRAP_nmi], IST_NMI); - set_ist(&idt_tables[cpu][TRAP_machine_check], IST_MCE); -+ set_ist(&idt_tables[cpu][TRAP_debug], IST_DB); - } - - static void svm_ctxt_switch_to(struct vcpu *v) -@@ -1067,6 +1072,7 @@ static void svm_ctxt_switch_to(struct vcpu *v) - set_ist(&idt_tables[cpu][TRAP_double_fault], IST_NONE); - set_ist(&idt_tables[cpu][TRAP_nmi], IST_NONE); - set_ist(&idt_tables[cpu][TRAP_machine_check], IST_NONE); -+ set_ist(&idt_tables[cpu][TRAP_debug], IST_NONE); - - svm_restore_dr(v); - -@@ -1361,24 +1367,18 @@ static void svm_inject_event(const struct x86_event *event) - * Xen must emulate enough of the event injection to be sure that a - * further fault shouldn't occur during delivery. This covers the fact - * that hardware doesn't perform DPL checking on injection. -- * -- * Also, it accounts for proper positioning of %rip for an event with trap -- * semantics (where %rip should point after the instruction) which suffers -- * a fault during injection (at which point %rip should point at the -- * instruction). - */ - if ( event->type == X86_EVENTTYPE_PRI_SW_EXCEPTION || -- (!cpu_has_svm_nrips && (event->type == X86_EVENTTYPE_SW_INTERRUPT || -- event->type == X86_EVENTTYPE_SW_EXCEPTION)) ) -+ (!cpu_has_svm_nrips && (event->type >= X86_EVENTTYPE_SW_INTERRUPT)) ) - svm_emul_swint_injection(&_event); - -- switch ( _event.vector ) -+ switch ( _event.vector | -(_event.type == X86_EVENTTYPE_SW_INTERRUPT) ) - { - case TRAP_debug: - if ( regs->eflags & X86_EFLAGS_TF ) - { - __restore_debug_registers(vmcb, curr); -- vmcb_set_dr6(vmcb, vmcb_get_dr6(vmcb) | 0x4000); -+ vmcb_set_dr6(vmcb, vmcb_get_dr6(vmcb) | DR_STEP); - } - /* fall through */ - case TRAP_int3: -@@ -1388,6 +1388,13 @@ static void svm_inject_event(const struct x86_event *event) - domain_pause_for_debugger(); - return; - } -+ break; -+ -+ case TRAP_page_fault: -+ ASSERT(_event.type == X86_EVENTTYPE_HW_EXCEPTION); -+ curr->arch.hvm_vcpu.guest_cr[2] = _event.cr2; -+ vmcb_set_cr2(vmcb, _event.cr2); -+ break; - } - - if ( unlikely(eventinj.fields.v) && -@@ -1410,13 +1417,9 @@ static void svm_inject_event(const struct x86_event *event) - * icebp, software events with trap semantics need emulating, so %rip in - * the trap frame points after the instruction. - * -- * The x86 emulator (if requested by the x86_swint_emulate_* choice) will -- * have performed checks such as presence/dpl/etc and believes that the -- * event injection will succeed without faulting. -- * -- * The x86 emulator will always provide fault semantics for software -- * events, with _trap.insn_len set appropriately. If the injection -- * requires emulation, move %rip forwards at this point. -+ * svm_emul_swint_injection() has already confirmed that events with trap -+ * semantics won't fault on injection. Position %rip/NextRIP suitably, -+ * and restrict the event type to what hardware will tolerate. - */ - switch ( _event.type ) - { -@@ -1473,16 +1476,12 @@ static void svm_inject_event(const struct x86_event *event) - eventinj.fields.errorcode == (uint16_t)eventinj.fields.errorcode); - vmcb->eventinj = eventinj; - -- if ( _event.vector == TRAP_page_fault ) -- { -- curr->arch.hvm_vcpu.guest_cr[2] = _event.cr2; -- vmcb_set_cr2(vmcb, _event.cr2); -- HVMTRACE_LONG_2D(PF_INJECT, _event.error_code, TRC_PAR_LONG(_event.cr2)); -- } -+ if ( _event.vector == TRAP_page_fault && -+ _event.type == X86_EVENTTYPE_HW_EXCEPTION ) -+ HVMTRACE_LONG_2D(PF_INJECT, _event.error_code, -+ TRC_PAR_LONG(_event.cr2)); - else -- { - HVMTRACE_2D(INJ_EXC, _event.vector, _event.error_code); -- } - } - - static int svm_event_pending(struct vcpu *v) -@@ -1836,6 +1835,25 @@ static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content) - struct vcpu *v = current; - struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - -+ switch ( msr ) -+ { -+ /* -+ * Sync not needed while the cross-vendor logic is in unilateral effect. -+ case MSR_IA32_SYSENTER_CS: -+ case MSR_IA32_SYSENTER_ESP: -+ case MSR_IA32_SYSENTER_EIP: -+ */ -+ case MSR_STAR: -+ case MSR_LSTAR: -+ case MSR_CSTAR: -+ case MSR_SYSCALL_MASK: -+ case MSR_FS_BASE: -+ case MSR_GS_BASE: -+ case MSR_SHADOW_GS_BASE: -+ svm_sync_vmcb(v); -+ break; -+ } -+ - switch ( msr ) - { - case MSR_IA32_SYSENTER_CS: -@@ -1848,6 +1866,34 @@ static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content) - *msr_content = v->arch.hvm_svm.guest_sysenter_eip; - break; - -+ case MSR_STAR: -+ *msr_content = vmcb->star; -+ break; -+ -+ case MSR_LSTAR: -+ *msr_content = vmcb->lstar; -+ break; -+ -+ case MSR_CSTAR: -+ *msr_content = vmcb->cstar; -+ break; -+ -+ case MSR_SYSCALL_MASK: -+ *msr_content = vmcb->sfmask; -+ break; -+ -+ case MSR_FS_BASE: -+ *msr_content = vmcb->fs.base; -+ break; -+ -+ case MSR_GS_BASE: -+ *msr_content = vmcb->gs.base; -+ break; -+ -+ case MSR_SHADOW_GS_BASE: -+ *msr_content = vmcb->kerngsbase; -+ break; -+ - case MSR_IA32_MCx_MISC(4): /* Threshold register */ - case MSR_F10_MC4_MISC1 ... MSR_F10_MC4_MISC3: - /* -@@ -1976,32 +2022,81 @@ static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content) - int ret, result = X86EMUL_OKAY; - struct vcpu *v = current; - struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; -- int sync = 0; -+ bool sync = false; - - switch ( msr ) - { - case MSR_IA32_SYSENTER_CS: - case MSR_IA32_SYSENTER_ESP: - case MSR_IA32_SYSENTER_EIP: -- sync = 1; -- break; -- default: -+ case MSR_STAR: -+ case MSR_LSTAR: -+ case MSR_CSTAR: -+ case MSR_SYSCALL_MASK: -+ case MSR_FS_BASE: -+ case MSR_GS_BASE: -+ case MSR_SHADOW_GS_BASE: -+ sync = true; - break; - } - - if ( sync ) -- svm_sync_vmcb(v); -+ svm_sync_vmcb(v); - - switch ( msr ) - { -+ case MSR_IA32_SYSENTER_ESP: -+ case MSR_IA32_SYSENTER_EIP: -+ case MSR_LSTAR: -+ case MSR_CSTAR: -+ case MSR_FS_BASE: -+ case MSR_GS_BASE: -+ case MSR_SHADOW_GS_BASE: -+ if ( !is_canonical_address(msr_content) ) -+ goto gpf; -+ -+ switch ( msr ) -+ { -+ case MSR_IA32_SYSENTER_ESP: -+ vmcb->sysenter_esp = v->arch.hvm_svm.guest_sysenter_esp = msr_content; -+ break; -+ -+ case MSR_IA32_SYSENTER_EIP: -+ vmcb->sysenter_eip = v->arch.hvm_svm.guest_sysenter_eip = msr_content; -+ break; -+ -+ case MSR_LSTAR: -+ vmcb->lstar = msr_content; -+ break; -+ -+ case MSR_CSTAR: -+ vmcb->cstar = msr_content; -+ break; -+ -+ case MSR_FS_BASE: -+ vmcb->fs.base = msr_content; -+ break; -+ -+ case MSR_GS_BASE: -+ vmcb->gs.base = msr_content; -+ break; -+ -+ case MSR_SHADOW_GS_BASE: -+ vmcb->kerngsbase = msr_content; -+ break; -+ } -+ break; -+ - case MSR_IA32_SYSENTER_CS: - vmcb->sysenter_cs = v->arch.hvm_svm.guest_sysenter_cs = msr_content; - break; -- case MSR_IA32_SYSENTER_ESP: -- vmcb->sysenter_esp = v->arch.hvm_svm.guest_sysenter_esp = msr_content; -+ -+ case MSR_STAR: -+ vmcb->star = msr_content; - break; -- case MSR_IA32_SYSENTER_EIP: -- vmcb->sysenter_eip = v->arch.hvm_svm.guest_sysenter_eip = msr_content; -+ -+ case MSR_SYSCALL_MASK: -+ vmcb->sfmask = msr_content; - break; - - case MSR_IA32_DEBUGCTLMSR: -diff --git a/xen/arch/x86/hvm/svm/svmdebug.c b/xen/arch/x86/hvm/svm/svmdebug.c -index 89ef2db932..b5b946aa94 100644 ---- a/xen/arch/x86/hvm/svm/svmdebug.c -+++ b/xen/arch/x86/hvm/svm/svmdebug.c -@@ -131,9 +131,8 @@ bool svm_vmcb_isvalid(const char *from, const struct vmcb_struct *vmcb, - PRINTF("DR7: bits [63:32] are not zero (%#"PRIx64")\n", - vmcb_get_dr7(vmcb)); - -- if ( efer & ~(EFER_SCE | EFER_LME | EFER_LMA | EFER_NX | EFER_SVME | -- EFER_LMSLE | EFER_FFXSE) ) -- PRINTF("EFER: undefined bits are not zero (%#"PRIx64")\n", efer); -+ if ( efer & ~EFER_KNOWN_MASK ) -+ PRINTF("EFER: unknown bits are not zero (%#"PRIx64")\n", efer); - - if ( hvm_efer_valid(v, efer, -1) ) - PRINTF("EFER: %s (%"PRIx64")\n", hvm_efer_valid(v, efer, -1), efer); -diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c -index 997e7597e0..612ced2f0d 100644 ---- a/xen/arch/x86/hvm/svm/vmcb.c -+++ b/xen/arch/x86/hvm/svm/vmcb.c -@@ -178,8 +178,8 @@ static int construct_vmcb(struct vcpu *v) - paging_update_paging_modes(v); - - vmcb->_exception_intercepts = -- HVM_TRAP_MASK -- | (1U << TRAP_no_device); -+ HVM_TRAP_MASK | -+ (v->arch.fully_eager_fpu ? 0 : (1U << TRAP_no_device)); - - if ( paging_mode_hap(v->domain) ) - { -diff --git a/xen/arch/x86/hvm/viridian.c b/xen/arch/x86/hvm/viridian.c -index f0fa59d7d5..b02a70d086 100644 ---- a/xen/arch/x86/hvm/viridian.c -+++ b/xen/arch/x86/hvm/viridian.c -@@ -245,7 +245,7 @@ void cpuid_viridian_leaves(const struct vcpu *v, uint32_t leaf, - }; - union { - HV_PARTITION_PRIVILEGE_MASK mask; -- uint32_t lo, hi; -+ struct { uint32_t lo, hi; }; - } u; - - if ( !(viridian_feature_mask(d) & HVMPV_no_freq) ) -@@ -966,12 +966,10 @@ int viridian_hypercall(struct cpu_user_regs *regs) - gprintk(XENLOG_WARNING, "unimplemented hypercall %04x\n", - input.call_code); - /* Fallthrough. */ -- case HvGetPartitionId: - case HvExtCallQueryCapabilities: - /* -- * These hypercalls seem to be erroneously issued by Windows -- * despite neither AccessPartitionId nor EnableExtendedHypercalls -- * being set in CPUID leaf 2. -+ * This hypercall seems to be erroneously issued by Windows -+ * despite EnableExtendedHypercalls not being set in CPUID leaf 2. - * Given that return a status of 'invalid code' has not so far - * caused any problems it's not worth logging. - */ -diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S -index e750544b4b..c6504e3207 100644 ---- a/xen/arch/x86/hvm/vmx/entry.S -+++ b/xen/arch/x86/hvm/vmx/entry.S -@@ -38,9 +38,18 @@ ENTRY(vmx_asm_vmexit_handler) - movb $1,VCPU_vmx_launched(%rbx) - mov %rax,VCPU_hvm_guest_cr2(%rbx) - -- SPEC_CTRL_ENTRY_FROM_VMEXIT /* Req: b=curr %rsp=regs/cpuinfo, Clob: acd */ -+ SPEC_CTRL_ENTRY_FROM_HVM /* Req: b=curr %rsp=regs/cpuinfo, Clob: acd */ - /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ - -+ /* Hardware clears MSR_DEBUGCTL on VMExit. Reinstate it if debugging Xen. */ -+ .macro restore_lbr -+ mov $IA32_DEBUGCTLMSR_LBR, %eax -+ mov $MSR_IA32_DEBUGCTLMSR, %ecx -+ xor %edx, %edx -+ wrmsr -+ .endm -+ ALTERNATIVE __stringify(ASM_NOP14), restore_lbr, X86_FEATURE_XEN_LBR -+ - mov %rsp,%rdi - call vmx_vmexit_handler - -@@ -76,7 +85,7 @@ UNLIKELY_END(realmode) - mov VCPUMSR_spec_ctrl_raw(%rax), %eax - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_GUEST /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ -+ SPEC_CTRL_EXIT_TO_HVM /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ - - mov VCPU_hvm_guest_cr2(%rbx),%rax - -diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c -index a642118eab..2b223a16fe 100644 ---- a/xen/arch/x86/hvm/vmx/vmcs.c -+++ b/xen/arch/x86/hvm/vmx/vmcs.c -@@ -38,6 +38,7 @@ - #include <asm/flushtlb.h> - #include <asm/monitor.h> - #include <asm/shadow.h> -+#include <asm/spec_ctrl.h> - #include <asm/tboot.h> - #include <asm/apic.h> - -@@ -999,6 +1000,7 @@ static int construct_vmcs(struct vcpu *v) - unsigned long sysenter_eip; - u32 vmexit_ctl = vmx_vmexit_control; - u32 vmentry_ctl = vmx_vmentry_control; -+ int rc = 0; - - vmx_vmcs_enter(v); - -@@ -1086,8 +1088,8 @@ static int construct_vmcs(struct vcpu *v) - - if ( msr_bitmap == NULL ) - { -- vmx_vmcs_exit(v); -- return -ENOMEM; -+ rc = -ENOMEM; -+ goto out; - } - - memset(msr_bitmap, ~0, PAGE_SIZE); -@@ -1146,7 +1148,9 @@ static int construct_vmcs(struct vcpu *v) - __vmwrite(HOST_GS_BASE, 0); - - /* Host control registers. */ -- v->arch.hvm_vmx.host_cr0 = read_cr0() | X86_CR0_TS; -+ v->arch.hvm_vmx.host_cr0 = read_cr0() & ~X86_CR0_TS; -+ if ( !v->arch.fully_eager_fpu ) -+ v->arch.hvm_vmx.host_cr0 |= X86_CR0_TS; - __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0); - __vmwrite(HOST_CR4, mmu_cr4_features); - -@@ -1226,7 +1230,7 @@ static int construct_vmcs(struct vcpu *v) - - v->arch.hvm_vmx.exception_bitmap = HVM_TRAP_MASK - | (paging_mode_hap(d) ? 0 : (1U << TRAP_page_fault)) -- | (1U << TRAP_no_device); -+ | (v->arch.fully_eager_fpu ? 0 : (1U << TRAP_no_device)); - vmx_update_exception_bitmap(v); - - v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PE | X86_CR0_ET; -@@ -1269,141 +1273,197 @@ static int construct_vmcs(struct vcpu *v) - if ( cpu_has_vmx_tsc_scaling ) - __vmwrite(TSC_MULTIPLIER, d->arch.hvm_domain.tsc_scaling_ratio); - -- vmx_vmcs_exit(v); -- - /* will update HOST & GUEST_CR3 as reqd */ - paging_update_paging_modes(v); - - vmx_vlapic_msr_changed(v); - -- return 0; -+ if ( opt_l1d_flush && paging_mode_hap(d) ) -+ rc = vmx_add_msr(v, MSR_FLUSH_CMD, FLUSH_CMD_L1D, -+ VMX_MSR_GUEST_LOADONLY); -+ -+ out: -+ vmx_vmcs_exit(v); -+ -+ return rc; - } - --static int vmx_msr_entry_key_cmp(const void *key, const void *elt) -+/* -+ * Search an MSR list looking for an MSR entry, or the slot in which it should -+ * live (to keep the data sorted) if an entry is not found. -+ * -+ * The return pointer is guaranteed to be bounded by start and end. However, -+ * it may point at end, and may be invalid for the caller to dereference. -+ */ -+static struct vmx_msr_entry *locate_msr_entry( -+ struct vmx_msr_entry *start, struct vmx_msr_entry *end, uint32_t msr) - { -- const u32 *msr = key; -- const struct vmx_msr_entry *entry = elt; -+ while ( start < end ) -+ { -+ struct vmx_msr_entry *mid = start + (end - start) / 2; - -- if ( *msr > entry->index ) -- return 1; -- if ( *msr < entry->index ) -- return -1; -+ if ( msr < mid->index ) -+ end = mid; -+ else if ( msr > mid->index ) -+ start = mid + 1; -+ else -+ return mid; -+ } - -- return 0; -+ return start; - } - --struct vmx_msr_entry *vmx_find_msr(u32 msr, int type) -+struct vmx_msr_entry *vmx_find_msr(const struct vcpu *v, uint32_t msr, -+ enum vmx_msr_list_type type) - { -- struct vcpu *curr = current; -- unsigned int msr_count; -- struct vmx_msr_entry *msr_area; -+ const struct arch_vmx_struct *vmx = &v->arch.hvm_vmx; -+ struct vmx_msr_entry *start = NULL, *ent, *end; -+ unsigned int substart = 0, subend = vmx->msr_save_count; -+ unsigned int total = vmx->msr_load_count; - -- if ( type == VMX_GUEST_MSR ) -- { -- msr_count = curr->arch.hvm_vmx.msr_count; -- msr_area = curr->arch.hvm_vmx.msr_area; -- } -- else -+ ASSERT(v == current || !vcpu_runnable(v)); -+ -+ switch ( type ) - { -- ASSERT(type == VMX_HOST_MSR); -- msr_count = curr->arch.hvm_vmx.host_msr_count; -- msr_area = curr->arch.hvm_vmx.host_msr_area; -+ case VMX_MSR_HOST: -+ start = vmx->host_msr_area; -+ subend = vmx->host_msr_count; -+ total = subend; -+ break; -+ -+ case VMX_MSR_GUEST: -+ start = vmx->msr_area; -+ break; -+ -+ case VMX_MSR_GUEST_LOADONLY: -+ start = vmx->msr_area; -+ substart = subend; -+ subend = total; -+ break; -+ -+ default: -+ ASSERT_UNREACHABLE(); - } - -- if ( msr_area == NULL ) -+ if ( !start ) - return NULL; - -- return bsearch(&msr, msr_area, msr_count, sizeof(struct vmx_msr_entry), -- vmx_msr_entry_key_cmp); -+ end = start + total; -+ ent = locate_msr_entry(start + substart, start + subend, msr); -+ -+ return ((ent < end) && (ent->index == msr)) ? ent : NULL; - } - --int vmx_read_guest_msr(u32 msr, u64 *val) -+int vmx_add_msr(struct vcpu *v, uint32_t msr, uint64_t val, -+ enum vmx_msr_list_type type) - { -- struct vmx_msr_entry *ent; -+ struct arch_vmx_struct *vmx = &v->arch.hvm_vmx; -+ struct vmx_msr_entry **ptr, *start = NULL, *ent, *end; -+ unsigned int substart, subend, total; -+ int rc; -+ -+ ASSERT(v == current || !vcpu_runnable(v)); - -- if ( (ent = vmx_find_msr(msr, VMX_GUEST_MSR)) != NULL ) -+ switch ( type ) - { -- *val = ent->data; -- return 0; -- } -+ case VMX_MSR_HOST: -+ ptr = &vmx->host_msr_area; -+ substart = 0; -+ subend = vmx->host_msr_count; -+ total = subend; -+ break; - -- return -ESRCH; --} -+ case VMX_MSR_GUEST: -+ ptr = &vmx->msr_area; -+ substart = 0; -+ subend = vmx->msr_save_count; -+ total = vmx->msr_load_count; -+ break; - --int vmx_write_guest_msr(u32 msr, u64 val) --{ -- struct vmx_msr_entry *ent; -+ case VMX_MSR_GUEST_LOADONLY: -+ ptr = &vmx->msr_area; -+ substart = vmx->msr_save_count; -+ subend = vmx->msr_load_count; -+ total = subend; -+ break; - -- if ( (ent = vmx_find_msr(msr, VMX_GUEST_MSR)) != NULL ) -- { -- ent->data = val; -- return 0; -+ default: -+ ASSERT_UNREACHABLE(); -+ return -EINVAL; - } - -- return -ESRCH; --} -- --int vmx_add_msr(u32 msr, int type) --{ -- struct vcpu *curr = current; -- unsigned int idx, *msr_count; -- struct vmx_msr_entry **msr_area, *msr_area_elem; -+ vmx_vmcs_enter(v); - -- if ( type == VMX_GUEST_MSR ) -+ /* Allocate memory on first use. */ -+ if ( unlikely(!*ptr) ) - { -- msr_count = &curr->arch.hvm_vmx.msr_count; -- msr_area = &curr->arch.hvm_vmx.msr_area; -- } -- else -- { -- ASSERT(type == VMX_HOST_MSR); -- msr_count = &curr->arch.hvm_vmx.host_msr_count; -- msr_area = &curr->arch.hvm_vmx.host_msr_area; -- } -+ paddr_t addr; - -- if ( *msr_area == NULL ) -- { -- if ( (*msr_area = alloc_xenheap_page()) == NULL ) -- return -ENOMEM; -+ if ( (*ptr = alloc_xenheap_page()) == NULL ) -+ { -+ rc = -ENOMEM; -+ goto out; -+ } -+ -+ addr = virt_to_maddr(*ptr); - -- if ( type == VMX_GUEST_MSR ) -+ switch ( type ) - { -- __vmwrite(VM_EXIT_MSR_STORE_ADDR, virt_to_maddr(*msr_area)); -- __vmwrite(VM_ENTRY_MSR_LOAD_ADDR, virt_to_maddr(*msr_area)); -+ case VMX_MSR_HOST: -+ __vmwrite(VM_EXIT_MSR_LOAD_ADDR, addr); -+ break; -+ -+ case VMX_MSR_GUEST: -+ case VMX_MSR_GUEST_LOADONLY: -+ __vmwrite(VM_EXIT_MSR_STORE_ADDR, addr); -+ __vmwrite(VM_ENTRY_MSR_LOAD_ADDR, addr); -+ break; - } -- else -- __vmwrite(VM_EXIT_MSR_LOAD_ADDR, virt_to_maddr(*msr_area)); - } - -- for ( idx = 0; idx < *msr_count && (*msr_area)[idx].index <= msr; idx++ ) -- if ( (*msr_area)[idx].index == msr ) -- return 0; -+ start = *ptr; -+ end = start + total; -+ ent = locate_msr_entry(start + substart, start + subend, msr); - -- if ( *msr_count == (PAGE_SIZE / sizeof(struct vmx_msr_entry)) ) -- return -ENOSPC; -+ if ( (ent < end) && (ent->index == msr) ) -+ goto found; - -- memmove(*msr_area + idx + 1, *msr_area + idx, -- sizeof(*msr_area_elem) * (*msr_count - idx)); -+ /* If there isn't an existing entry for msr, insert room for one. */ -+ if ( total == (PAGE_SIZE / sizeof(*ent)) ) -+ { -+ rc = -ENOSPC; -+ goto out; -+ } - -- msr_area_elem = *msr_area + idx; -- msr_area_elem->index = msr; -- msr_area_elem->mbz = 0; -+ memmove(ent + 1, ent, sizeof(*ent) * (end - ent)); - -- ++*msr_count; -+ ent->index = msr; -+ ent->mbz = 0; - -- if ( type == VMX_GUEST_MSR ) -+ switch ( type ) - { -- msr_area_elem->data = 0; -- __vmwrite(VM_EXIT_MSR_STORE_COUNT, *msr_count); -- __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, *msr_count); -- } -- else -- { -- rdmsrl(msr, msr_area_elem->data); -- __vmwrite(VM_EXIT_MSR_LOAD_COUNT, *msr_count); -+ case VMX_MSR_HOST: -+ __vmwrite(VM_EXIT_MSR_LOAD_COUNT, ++vmx->host_msr_count); -+ break; -+ -+ case VMX_MSR_GUEST: -+ __vmwrite(VM_EXIT_MSR_STORE_COUNT, ++vmx->msr_save_count); -+ -+ /* Fallthrough */ -+ case VMX_MSR_GUEST_LOADONLY: -+ __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, ++vmx->msr_load_count); -+ break; - } - -- return 0; -+ /* Set the msr's value. */ -+ found: -+ ent->data = val; -+ rc = 0; -+ -+ out: -+ vmx_vmcs_exit(v); -+ -+ return rc; - } - - void vmx_set_eoi_exit_bitmap(struct vcpu *v, u8 vector) -@@ -1784,10 +1844,7 @@ void vmcs_dump_vcpu(struct vcpu *v) - vmentry_ctl = vmr32(VM_ENTRY_CONTROLS), - vmexit_ctl = vmr32(VM_EXIT_CONTROLS); - cr4 = vmr(GUEST_CR4); -- -- /* EFER.LMA is read as zero, and is loaded from vmentry_ctl on entry. */ -- BUILD_BUG_ON(VM_ENTRY_IA32E_MODE << 1 != EFER_LMA); -- efer = vmr(GUEST_EFER) | ((vmentry_ctl & VM_ENTRY_IA32E_MODE) << 1); -+ efer = vmr(GUEST_EFER); - - printk("*** Guest State ***\n"); - printk("CR0: actual=0x%016lx, shadow=0x%016lx, gh_mask=%016lx\n", -@@ -1797,7 +1854,7 @@ void vmcs_dump_vcpu(struct vcpu *v) - printk("CR3 = 0x%016lx\n", vmr(GUEST_CR3)); - if ( (v->arch.hvm_vmx.secondary_exec_control & - SECONDARY_EXEC_ENABLE_EPT) && -- (cr4 & X86_CR4_PAE) && !(efer & EFER_LMA) ) -+ (cr4 & X86_CR4_PAE) && !(vmentry_ctl & VM_ENTRY_IA32E_MODE) ) - { - printk("PDPTE0 = 0x%016lx PDPTE1 = 0x%016lx\n", - vmr(GUEST_PDPTE(0)), vmr(GUEST_PDPTE(1))); -diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c -index fc505c8cf7..508882e8d2 100644 ---- a/xen/arch/x86/hvm/vmx/vmx.c -+++ b/xen/arch/x86/hvm/vmx/vmx.c -@@ -682,6 +682,12 @@ static void vmx_cpuid_policy_changed(struct vcpu *v) - vmx_clear_msr_intercept(v, MSR_PRED_CMD, VMX_MSR_RW); - else - vmx_set_msr_intercept(v, MSR_PRED_CMD, VMX_MSR_RW); -+ -+ /* MSR_FLUSH_CMD is safe to pass through if the guest knows about it. */ -+ if ( cp->feat.l1d_flush ) -+ vmx_clear_msr_intercept(v, MSR_FLUSH_CMD, VMX_MSR_RW); -+ else -+ vmx_set_msr_intercept(v, MSR_FLUSH_CMD, VMX_MSR_RW); - } - - int vmx_guest_x86_mode(struct vcpu *v) -@@ -1035,7 +1041,8 @@ static void vmx_ctxt_switch_from(struct vcpu *v) - vmx_vmcs_reload(v); - } - -- vmx_fpu_leave(v); -+ if ( !v->arch.fully_eager_fpu ) -+ vmx_fpu_leave(v); - vmx_save_guest_msrs(v); - vmx_restore_host_msrs(); - vmx_save_dr(v); -@@ -1597,7 +1604,10 @@ static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr) - if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) ) - { - if ( v != current ) -- hw_cr0_mask |= X86_CR0_TS; -+ { -+ if ( !v->arch.fully_eager_fpu ) -+ hw_cr0_mask |= X86_CR0_TS; -+ } - else if ( v->arch.hvm_vcpu.hw_cr[0] & X86_CR0_TS ) - vmx_fpu_enter(v); - } -@@ -2835,8 +2845,10 @@ enum - - #define LBR_FROM_SIGNEXT_2MSB ((1ULL << 59) | (1ULL << 60)) - --#define FIXUP_LBR_TSX (1u << 0) --#define FIXUP_BDW_ERRATUM_BDF14 (1u << 1) -+#define LBR_MSRS_INSERTED (1u << 0) -+#define LBR_FIXUP_TSX (1u << 1) -+#define LBR_FIXUP_BDF14 (1u << 2) -+#define LBR_FIXUP_MASK (LBR_FIXUP_TSX | LBR_FIXUP_BDF14) - - static bool __read_mostly lbr_tsx_fixup_needed; - static bool __read_mostly bdw_erratum_bdf14_fixup_needed; -@@ -2899,7 +2911,7 @@ static int is_last_branch_msr(u32 ecx) - - static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content) - { -- const struct vcpu *curr = current; -+ struct vcpu *curr = current; - - HVM_DBG_LOG(DBG_LEVEL_MSR, "ecx=%#x", msr); - -@@ -2958,7 +2970,7 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content) - goto done; - } - -- if ( vmx_read_guest_msr(msr, msr_content) == 0 ) -+ if ( vmx_read_guest_msr(curr, msr, msr_content) == 0 ) - break; - - if ( is_last_branch_msr(msr) ) -@@ -3093,11 +3105,14 @@ void vmx_vlapic_msr_changed(struct vcpu *v) - static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content) - { - struct vcpu *v = current; -+ const struct cpuid_policy *cp = v->domain->arch.cpuid; - - HVM_DBG_LOG(DBG_LEVEL_MSR, "ecx=%#x, msr_value=%#"PRIx64, msr, msr_content); - - switch ( msr ) - { -+ uint64_t rsvd; -+ - case MSR_IA32_SYSENTER_CS: - __vmwrite(GUEST_SYSENTER_CS, msr_content); - break; -@@ -3111,45 +3126,85 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content) - goto gp_fault; - __vmwrite(GUEST_SYSENTER_EIP, msr_content); - break; -- case MSR_IA32_DEBUGCTLMSR: { -- int i, rc = 0; -- uint64_t supported = IA32_DEBUGCTLMSR_LBR | IA32_DEBUGCTLMSR_BTF; -+ case MSR_IA32_DEBUGCTLMSR: -+ rsvd = ~(IA32_DEBUGCTLMSR_LBR | IA32_DEBUGCTLMSR_BTF); - -- if ( boot_cpu_has(X86_FEATURE_RTM) ) -- supported |= IA32_DEBUGCTLMSR_RTM; -- if ( msr_content & ~supported ) -+ /* TODO: Wire vPMU settings properly through the CPUID policy */ -+ if ( vpmu_is_set(vcpu_vpmu(v), VPMU_CPU_HAS_BTS) ) - { -- /* Perhaps some other bits are supported in vpmu. */ -- if ( vpmu_do_wrmsr(msr, msr_content, supported) ) -- break; -+ rsvd &= ~(IA32_DEBUGCTLMSR_TR | IA32_DEBUGCTLMSR_BTS | -+ IA32_DEBUGCTLMSR_BTINT); -+ -+ if ( cpu_has(¤t_cpu_data, X86_FEATURE_DSCPL) ) -+ rsvd &= ~(IA32_DEBUGCTLMSR_BTS_OFF_OS | -+ IA32_DEBUGCTLMSR_BTS_OFF_USR); - } -- if ( msr_content & IA32_DEBUGCTLMSR_LBR ) -+ -+ if ( cp->feat.rtm ) -+ rsvd &= ~IA32_DEBUGCTLMSR_RTM; -+ -+ if ( msr_content & rsvd ) -+ goto gp_fault; -+ -+ /* -+ * When a guest first enables LBR, arrange to save and restore the LBR -+ * MSRs and allow the guest direct access. -+ * -+ * MSR_DEBUGCTL and LBR has existed almost as long as MSRs have -+ * existed, and there is no architectural way to hide the feature, or -+ * fail the attempt to enable LBR. -+ * -+ * Unknown host LBR MSRs or hitting -ENOSPC with the guest load/save -+ * list are definitely hypervisor bugs, whereas -ENOMEM for allocating -+ * the load/save list is simply unlucky (and shouldn't occur with -+ * sensible management by the toolstack). -+ * -+ * Either way, there is nothing we can do right now to recover, and -+ * the guest won't execute correctly either. Simply crash the domain -+ * to make the failure obvious. -+ */ -+ if ( !(v->arch.hvm_vmx.lbr_flags & LBR_MSRS_INSERTED) && -+ (msr_content & IA32_DEBUGCTLMSR_LBR) ) - { - const struct lbr_info *lbr = last_branch_msr_get(); -- if ( lbr == NULL ) -- break; - -- for ( ; (rc == 0) && lbr->count; lbr++ ) -- for ( i = 0; (rc == 0) && (i < lbr->count); i++ ) -- if ( (rc = vmx_add_guest_msr(lbr->base + i)) == 0 ) -+ if ( unlikely(!lbr) ) -+ { -+ gprintk(XENLOG_ERR, "Unknown Host LBR MSRs\n"); -+ domain_crash(v->domain); -+ return X86EMUL_OKAY; -+ } -+ -+ for ( ; lbr->count; lbr++ ) -+ { -+ unsigned int i; -+ -+ for ( i = 0; i < lbr->count; i++ ) -+ { -+ int rc = vmx_add_guest_msr(v, lbr->base + i, 0); -+ -+ if ( unlikely(rc) ) - { -- vmx_clear_msr_intercept(v, lbr->base + i, VMX_MSR_RW); -- if ( lbr_tsx_fixup_needed ) -- v->arch.hvm_vmx.lbr_fixup_enabled |= FIXUP_LBR_TSX; -- if ( bdw_erratum_bdf14_fixup_needed ) -- v->arch.hvm_vmx.lbr_fixup_enabled |= -- FIXUP_BDW_ERRATUM_BDF14; -+ gprintk(XENLOG_ERR, -+ "Guest load/save list error %d\n", rc); -+ domain_crash(v->domain); -+ return X86EMUL_OKAY; - } -- } - -- if ( (rc < 0) || -- (msr_content && (vmx_add_host_load_msr(msr) < 0)) ) -- hvm_inject_hw_exception(TRAP_machine_check, X86_EVENT_NO_EC); -- else -- __vmwrite(GUEST_IA32_DEBUGCTL, msr_content); -+ vmx_clear_msr_intercept(v, lbr->base + i, VMX_MSR_RW); -+ } -+ } -+ -+ v->arch.hvm_vmx.lbr_flags |= LBR_MSRS_INSERTED; -+ if ( lbr_tsx_fixup_needed ) -+ v->arch.hvm_vmx.lbr_flags |= LBR_FIXUP_TSX; -+ if ( bdw_erratum_bdf14_fixup_needed ) -+ v->arch.hvm_vmx.lbr_flags |= LBR_FIXUP_BDF14; -+ } - -+ __vmwrite(GUEST_IA32_DEBUGCTL, msr_content); - break; -- } -+ - case MSR_IA32_FEATURE_CONTROL: - case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: - /* None of these MSRs are writeable. */ -@@ -3175,7 +3230,7 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content) - switch ( long_mode_do_msr_write(msr, msr_content) ) - { - case HNDL_unhandled: -- if ( (vmx_write_guest_msr(msr, msr_content) != 0) && -+ if ( (vmx_write_guest_msr(v, msr, msr_content) != 0) && - !is_last_branch_msr(msr) ) - switch ( wrmsr_hypervisor_regs(msr, msr_content) ) - { -@@ -3717,6 +3772,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) - */ - __vmread(EXIT_QUALIFICATION, &exit_qualification); - HVMTRACE_1D(TRAP_DEBUG, exit_qualification); -+ __restore_debug_registers(v); - write_debugreg(6, exit_qualification | DR_STATUS_RESERVED_ONE); - if ( !v->domain->debugger_attached ) - { -@@ -4186,11 +4242,11 @@ out: - static void lbr_tsx_fixup(void) - { - struct vcpu *curr = current; -- unsigned int msr_count = curr->arch.hvm_vmx.msr_count; -+ unsigned int msr_count = curr->arch.hvm_vmx.msr_save_count; - struct vmx_msr_entry *msr_area = curr->arch.hvm_vmx.msr_area; - struct vmx_msr_entry *msr; - -- if ( (msr = vmx_find_msr(lbr_from_start, VMX_GUEST_MSR)) != NULL ) -+ if ( (msr = vmx_find_msr(curr, lbr_from_start, VMX_MSR_GUEST)) != NULL ) - { - /* - * Sign extend into bits 61:62 while preserving bit 63 -@@ -4200,15 +4256,15 @@ static void lbr_tsx_fixup(void) - msr->data |= ((LBR_FROM_SIGNEXT_2MSB & msr->data) << 2); - } - -- if ( (msr = vmx_find_msr(lbr_lastint_from, VMX_GUEST_MSR)) != NULL ) -+ if ( (msr = vmx_find_msr(curr, lbr_lastint_from, VMX_MSR_GUEST)) != NULL ) - msr->data |= ((LBR_FROM_SIGNEXT_2MSB & msr->data) << 2); - } - --static void sign_extend_msr(u32 msr, int type) -+static void sign_extend_msr(struct vcpu *v, u32 msr, int type) - { - struct vmx_msr_entry *entry; - -- if ( (entry = vmx_find_msr(msr, type)) != NULL ) -+ if ( (entry = vmx_find_msr(v, msr, type)) != NULL ) - { - if ( entry->data & VADDR_TOP_BIT ) - entry->data |= CANONICAL_MASK; -@@ -4219,6 +4275,8 @@ static void sign_extend_msr(u32 msr, int type) - - static void bdw_erratum_bdf14_fixup(void) - { -+ struct vcpu *curr = current; -+ - /* - * Occasionally, on certain Broadwell CPUs MSR_IA32_LASTINTTOIP has - * been observed to have the top three bits corrupted as though the -@@ -4228,17 +4286,17 @@ static void bdw_erratum_bdf14_fixup(void) - * erratum BDF14. Fix up MSR_IA32_LASTINT{FROM,TO}IP by - * sign-extending into bits 48:63. - */ -- sign_extend_msr(MSR_IA32_LASTINTFROMIP, VMX_GUEST_MSR); -- sign_extend_msr(MSR_IA32_LASTINTTOIP, VMX_GUEST_MSR); -+ sign_extend_msr(curr, MSR_IA32_LASTINTFROMIP, VMX_MSR_GUEST); -+ sign_extend_msr(curr, MSR_IA32_LASTINTTOIP, VMX_MSR_GUEST); - } - - static void lbr_fixup(void) - { - struct vcpu *curr = current; - -- if ( curr->arch.hvm_vmx.lbr_fixup_enabled & FIXUP_LBR_TSX ) -+ if ( curr->arch.hvm_vmx.lbr_flags & LBR_FIXUP_TSX ) - lbr_tsx_fixup(); -- if ( curr->arch.hvm_vmx.lbr_fixup_enabled & FIXUP_BDW_ERRATUM_BDF14 ) -+ if ( curr->arch.hvm_vmx.lbr_flags & LBR_FIXUP_BDF14 ) - bdw_erratum_bdf14_fixup(); - } - -@@ -4306,7 +4364,7 @@ bool vmx_vmenter_helper(const struct cpu_user_regs *regs) - } - - out: -- if ( unlikely(curr->arch.hvm_vmx.lbr_fixup_enabled) ) -+ if ( unlikely(curr->arch.hvm_vmx.lbr_flags & LBR_FIXUP_MASK) ) - lbr_fixup(); - - HVMTRACE_ND(VMENTRY, 0, 1/*cycles*/, 0, 0, 0, 0, 0, 0, 0); -diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c -index 181f4cb631..04e3c2e15b 100644 ---- a/xen/arch/x86/hvm/vpt.c -+++ b/xen/arch/x86/hvm/vpt.c -@@ -107,31 +107,49 @@ static int pt_irq_vector(struct periodic_time *pt, enum hvm_intsrc src) - static int pt_irq_masked(struct periodic_time *pt) - { - struct vcpu *v = pt->vcpu; -- unsigned int gsi, isa_irq; -- int mask; -- uint8_t pic_imr; -+ unsigned int gsi = pt->irq; - -- if ( pt->source == PTSRC_lapic ) -+ switch ( pt->source ) -+ { -+ case PTSRC_lapic: - { - struct vlapic *vlapic = vcpu_vlapic(v); -+ - return (!vlapic_enabled(vlapic) || - (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_MASKED)); - } - -- isa_irq = pt->irq; -- gsi = hvm_isa_irq_to_gsi(isa_irq); -- pic_imr = v->domain->arch.hvm_domain.vpic[isa_irq >> 3].imr; -- mask = vioapic_get_mask(v->domain, gsi); -- if ( mask < 0 ) -+ case PTSRC_isa: - { -- dprintk(XENLOG_WARNING, "d%u: invalid GSI (%u) for platform timer\n", -- v->domain->domain_id, gsi); -- domain_crash(v->domain); -- return -1; -+ uint8_t pic_imr = v->domain->arch.hvm_domain.vpic[pt->irq >> 3].imr; -+ -+ /* Check if the interrupt is unmasked in the PIC. */ -+ if ( !(pic_imr & (1 << (pt->irq & 7))) && vlapic_accept_pic_intr(v) ) -+ return 0; -+ -+ gsi = hvm_isa_irq_to_gsi(pt->irq); -+ } -+ -+ /* Fallthrough to check if the interrupt is masked on the IO APIC. */ -+ case PTSRC_ioapic: -+ { -+ int mask = vioapic_get_mask(v->domain, gsi); -+ -+ if ( mask < 0 ) -+ { -+ dprintk(XENLOG_WARNING, -+ "d%d: invalid GSI (%u) for platform timer\n", -+ v->domain->domain_id, gsi); -+ domain_crash(v->domain); -+ return -1; -+ } -+ -+ return mask; -+ } - } - -- return (((pic_imr & (1 << (isa_irq & 7))) || !vlapic_accept_pic_intr(v)) && -- mask); -+ ASSERT_UNREACHABLE(); -+ return 1; - } - - static void pt_lock(struct periodic_time *pt) -@@ -252,7 +270,7 @@ int pt_update_irq(struct vcpu *v) - struct list_head *head = &v->arch.hvm_vcpu.tm_list; - struct periodic_time *pt, *temp, *earliest_pt; - uint64_t max_lag; -- int irq, is_lapic, pt_vector; -+ int irq, pt_vector = -1; - - spin_lock(&v->arch.hvm_vcpu.tm_lock); - -@@ -288,29 +306,26 @@ int pt_update_irq(struct vcpu *v) - - earliest_pt->irq_issued = 1; - irq = earliest_pt->irq; -- is_lapic = (earliest_pt->source == PTSRC_lapic); - - spin_unlock(&v->arch.hvm_vcpu.tm_lock); - -- /* -- * If periodic timer interrut is handled by lapic, its vector in -- * IRR is returned and used to set eoi_exit_bitmap for virtual -- * interrupt delivery case. Otherwise return -1 to do nothing. -- */ -- if ( is_lapic ) -+ switch ( earliest_pt->source ) - { -+ case PTSRC_lapic: -+ /* -+ * If periodic timer interrupt is handled by lapic, its vector in -+ * IRR is returned and used to set eoi_exit_bitmap for virtual -+ * interrupt delivery case. Otherwise return -1 to do nothing. -+ */ - vlapic_set_irq(vcpu_vlapic(v), irq, 0); - pt_vector = irq; -- } -- else -- { -+ break; -+ -+ case PTSRC_isa: - hvm_isa_irq_deassert(v->domain, irq); - if ( platform_legacy_irq(irq) && vlapic_accept_pic_intr(v) && - v->domain->arch.hvm_domain.vpic[irq >> 3].int_output ) -- { - hvm_isa_irq_assert(v->domain, irq, NULL); -- pt_vector = -1; -- } - else - { - pt_vector = hvm_isa_irq_assert(v->domain, irq, vioapic_get_vector); -@@ -321,6 +336,17 @@ int pt_update_irq(struct vcpu *v) - if ( pt_vector < 0 || !vlapic_test_irq(vcpu_vlapic(v), pt_vector) ) - pt_vector = -1; - } -+ break; -+ -+ case PTSRC_ioapic: -+ /* -+ * NB: At the moment IO-APIC routed interrupts generated by vpt devices -+ * (HPET) are edge-triggered. -+ */ -+ pt_vector = hvm_ioapic_assert(v->domain, irq, false); -+ if ( pt_vector < 0 || !vlapic_test_irq(vcpu_vlapic(v), pt_vector) ) -+ pt_vector = -1; -+ break; - } - - return pt_vector; -@@ -418,7 +444,14 @@ void create_periodic_time( - struct vcpu *v, struct periodic_time *pt, uint64_t delta, - uint64_t period, uint8_t irq, time_cb *cb, void *data) - { -- ASSERT(pt->source != 0); -+ if ( !pt->source || -+ (pt->irq >= NR_ISAIRQS && pt->source == PTSRC_isa) || -+ (pt->irq >= hvm_domain_irq(v->domain)->nr_gsis && -+ pt->source == PTSRC_ioapic) ) -+ { -+ ASSERT_UNREACHABLE(); -+ return; -+ } - - destroy_periodic_time(pt); - -@@ -498,7 +531,7 @@ static void pt_adjust_vcpu(struct periodic_time *pt, struct vcpu *v) - { - int on_list; - -- ASSERT(pt->source == PTSRC_isa); -+ ASSERT(pt->source == PTSRC_isa || pt->source == PTSRC_ioapic); - - if ( pt->vcpu == NULL ) - return; -diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c -index 88452522ad..a1d128dd94 100644 ---- a/xen/arch/x86/i387.c -+++ b/xen/arch/x86/i387.c -@@ -15,6 +15,7 @@ - #include <asm/i387.h> - #include <asm/xstate.h> - #include <asm/asm_defns.h> -+#include <asm/spec_ctrl.h> - - /*******************************/ - /* FPU Restore Functions */ -@@ -205,13 +206,13 @@ static inline void fpu_fxsave(struct vcpu *v) - /* VCPU FPU Functions */ - /*******************************/ - /* Restore FPU state whenever VCPU is schduled in. */ --void vcpu_restore_fpu_eager(struct vcpu *v) -+void vcpu_restore_fpu_nonlazy(struct vcpu *v, bool need_stts) - { -- ASSERT(!is_idle_vcpu(v)); -- - /* Restore nonlazy extended state (i.e. parts not tracked by CR0.TS). */ -- if ( !v->arch.nonlazy_xstate_used ) -- return; -+ if ( !v->arch.fully_eager_fpu && !v->arch.nonlazy_xstate_used ) -+ goto maybe_stts; -+ -+ ASSERT(!is_idle_vcpu(v)); - - /* Avoid recursion */ - clts(); -@@ -221,17 +222,28 @@ void vcpu_restore_fpu_eager(struct vcpu *v) - * above) we also need to restore full state, to prevent subsequently - * saving state belonging to another vCPU. - */ -- if ( xstate_all(v) ) -+ if ( v->arch.fully_eager_fpu || (v->arch.xsave_area && xstate_all(v)) ) - { -- fpu_xrstor(v, XSTATE_ALL); -+ if ( cpu_has_xsave ) -+ fpu_xrstor(v, XSTATE_ALL); -+ else -+ fpu_fxrstor(v); -+ - v->fpu_initialised = 1; - v->fpu_dirtied = 1; -+ -+ /* Xen doesn't need TS set, but the guest might. */ -+ need_stts = is_pv_vcpu(v) && (v->arch.pv_vcpu.ctrlreg[0] & X86_CR0_TS); - } - else - { - fpu_xrstor(v, XSTATE_NONLAZY); -- stts(); -+ need_stts = true; - } -+ -+ maybe_stts: -+ if ( need_stts ) -+ stts(); - } - - /* -@@ -247,6 +259,8 @@ void vcpu_restore_fpu_lazy(struct vcpu *v) - if ( v->fpu_dirtied ) - return; - -+ ASSERT(!v->arch.fully_eager_fpu); -+ - if ( cpu_has_xsave ) - fpu_xrstor(v, XSTATE_LAZY); - else -@@ -297,6 +311,8 @@ int vcpu_init_fpu(struct vcpu *v) - { - int rc; - -+ v->arch.fully_eager_fpu = opt_eager_fpu; -+ - if ( (rc = xstate_alloc_save_area(v)) != 0 ) - return rc; - -diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c -index bb924e9225..f3dfe35785 100644 ---- a/xen/arch/x86/mm.c -+++ b/xen/arch/x86/mm.c -@@ -125,6 +125,7 @@ - #include <asm/guest.h> - - #include <asm/hvm/grant_table.h> -+#include <asm/pv/domain.h> - #include <asm/pv/grant_table.h> - - #include "pv/mm.h" -@@ -503,12 +504,60 @@ void free_shared_domheap_page(struct page_info *page) - - void make_cr3(struct vcpu *v, mfn_t mfn) - { -+ struct domain *d = v->domain; -+ - v->arch.cr3 = mfn_x(mfn) << PAGE_SHIFT; -+ if ( is_pv_domain(d) && d->arch.pv_domain.pcid ) -+ v->arch.cr3 |= get_pcid_bits(v, false); -+} -+ -+unsigned long pv_guest_cr4_to_real_cr4(const struct vcpu *v) -+{ -+ const struct domain *d = v->domain; -+ unsigned long cr4; -+ -+ cr4 = v->arch.pv_vcpu.ctrlreg[4] & ~X86_CR4_DE; -+ cr4 |= mmu_cr4_features & (X86_CR4_PSE | X86_CR4_SMEP | X86_CR4_SMAP | -+ X86_CR4_OSXSAVE | X86_CR4_FSGSBASE); -+ -+ if ( d->arch.pv_domain.pcid ) -+ cr4 |= X86_CR4_PCIDE; -+ else if ( !d->arch.pv_domain.xpti ) -+ cr4 |= X86_CR4_PGE; -+ -+ cr4 |= d->arch.vtsc ? X86_CR4_TSD : 0; -+ -+ return cr4; - } - - void write_ptbase(struct vcpu *v) - { -- write_cr3(v->arch.cr3); -+ struct cpu_info *cpu_info = get_cpu_info(); -+ unsigned long new_cr4; -+ -+ new_cr4 = (is_pv_vcpu(v) && !is_idle_vcpu(v)) -+ ? pv_guest_cr4_to_real_cr4(v) -+ : ((read_cr4() & ~(X86_CR4_PCIDE | X86_CR4_TSD)) | X86_CR4_PGE); -+ -+ if ( is_pv_vcpu(v) && v->domain->arch.pv_domain.xpti ) -+ { -+ cpu_info->root_pgt_changed = true; -+ cpu_info->pv_cr3 = __pa(this_cpu(root_pgt)); -+ if ( new_cr4 & X86_CR4_PCIDE ) -+ cpu_info->pv_cr3 |= get_pcid_bits(v, true); -+ switch_cr3_cr4(v->arch.cr3, new_cr4); -+ } -+ else -+ { -+ /* Make sure to clear use_pv_cr3 and xen_cr3 before pv_cr3. */ -+ cpu_info->use_pv_cr3 = false; -+ cpu_info->xen_cr3 = 0; -+ /* switch_cr3_cr4() serializes. */ -+ switch_cr3_cr4(v->arch.cr3, new_cr4); -+ cpu_info->pv_cr3 = 0; -+ } -+ -+ ASSERT(is_pv_vcpu(v) || read_cr4() == mmu_cr4_features); - } - - /* -@@ -605,6 +654,9 @@ static int alloc_segdesc_page(struct page_info *page) - return i == 512 ? 0 : -EINVAL; - } - -+static int __get_page_type(struct page_info *page, unsigned long type, -+ int preemptible); -+ - static int get_page_and_type_from_mfn( - mfn_t mfn, unsigned long type, struct domain *d, - int partial, int preemptible) -@@ -616,9 +668,7 @@ static int get_page_and_type_from_mfn( - unlikely(!get_page_from_mfn(mfn, d)) ) - return -EINVAL; - -- rc = (preemptible ? -- get_page_type_preemptible(page, type) : -- (get_page_type(page, type) ? 0 : -EINVAL)); -+ rc = __get_page_type(page, type, preemptible); - - if ( unlikely(rc) && partial >= 0 && - (!preemptible || page != current->arch.old_guest_table) ) -@@ -1108,7 +1158,7 @@ get_page_from_l2e( - int rc; - - if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) -- return 1; -+ return pv_l1tf_check_l2e(d, l2e) ? -ERESTART : 1; - - if ( unlikely((l2e_get_flags(l2e) & L2_DISALLOW_MASK)) ) - { -@@ -1143,7 +1193,7 @@ get_page_from_l3e( - int rc; - - if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ) -- return 1; -+ return pv_l1tf_check_l3e(d, l3e) ? -ERESTART : 1; - - if ( unlikely((l3e_get_flags(l3e) & l3_disallow_mask(d))) ) - { -@@ -1176,7 +1226,7 @@ get_page_from_l4e( - int rc; - - if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) -- return 1; -+ return pv_l1tf_check_l4e(d, l4e) ? -ERESTART : 1; - - if ( unlikely((l4e_get_flags(l4e) & L4_DISALLOW_MASK)) ) - { -@@ -1371,6 +1421,13 @@ static int alloc_l1_table(struct page_info *page) - - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - { -+ if ( !(l1e_get_flags(pl1e[i]) & _PAGE_PRESENT) ) -+ { -+ ret = pv_l1tf_check_l1e(d, pl1e[i]) ? -ERESTART : 0; -+ if ( ret ) -+ goto out; -+ } -+ - switch ( ret = get_page_from_l1e(pl1e[i], d, d) ) - { - default: -@@ -1391,6 +1448,7 @@ static int alloc_l1_table(struct page_info *page) - - fail: - gdprintk(XENLOG_WARNING, "Failure in alloc_l1_table: slot %#x\n", i); -+ out: - while ( i-- > 0 ) - put_page_from_l1e(pl1e[i], d); - -@@ -1438,8 +1496,7 @@ static int create_pae_xen_mappings(struct domain *d, l3_pgentry_t *pl3e) - return 1; - } - --static int alloc_l2_table(struct page_info *page, unsigned long type, -- int preemptible) -+static int alloc_l2_table(struct page_info *page, unsigned long type) - { - struct domain *d = page_get_owner(page); - unsigned long pfn = mfn_x(page_to_mfn(page)); -@@ -1451,8 +1508,7 @@ static int alloc_l2_table(struct page_info *page, unsigned long type, - - for ( i = page->nr_validated_ptes; i < L2_PAGETABLE_ENTRIES; i++ ) - { -- if ( preemptible && i > page->nr_validated_ptes -- && hypercall_preempt_check() ) -+ if ( i > page->nr_validated_ptes && hypercall_preempt_check() ) - { - page->nr_validated_ptes = i; - rc = -ERESTART; -@@ -1463,6 +1519,12 @@ static int alloc_l2_table(struct page_info *page, unsigned long type, - (rc = get_page_from_l2e(pl2e[i], pfn, d)) > 0 ) - continue; - -+ if ( unlikely(rc == -ERESTART) ) -+ { -+ page->nr_validated_ptes = i; -+ break; -+ } -+ - if ( rc < 0 ) - { - gdprintk(XENLOG_WARNING, "Failure in alloc_l2_table: slot %#x\n", i); -@@ -1745,7 +1807,7 @@ static void free_l1_table(struct page_info *page) - } - - --static int free_l2_table(struct page_info *page, int preemptible) -+static int free_l2_table(struct page_info *page) - { - struct domain *d = page_get_owner(page); - unsigned long pfn = mfn_x(page_to_mfn(page)); -@@ -1759,7 +1821,7 @@ static int free_l2_table(struct page_info *page, int preemptible) - do { - if ( is_guest_l2_slot(d, page->u.inuse.type_info, i) && - put_page_from_l2e(pl2e[i], pfn) == 0 && -- preemptible && i && hypercall_preempt_check() ) -+ i && hypercall_preempt_check() ) - { - page->nr_validated_ptes = i; - err = -ERESTART; -@@ -1983,6 +2045,8 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e, - rc = -EBUSY; - } - } -+ else if ( pv_l1tf_check_l1e(pt_dom, nl1e) ) -+ return -ERESTART; - else if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, - preserve_ad)) ) - { -@@ -2046,6 +2110,8 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, - rc = -EBUSY; - } - } -+ else if ( pv_l1tf_check_l2e(d, nl2e) ) -+ return -ERESTART; - else if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, vcpu, - preserve_ad)) ) - { -@@ -2107,6 +2173,8 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, - rc = -EFAULT; - } - } -+ else if ( pv_l1tf_check_l3e(d, nl3e) ) -+ return -ERESTART; - else if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, vcpu, - preserve_ad)) ) - { -@@ -2172,6 +2240,8 @@ static int mod_l4_entry(l4_pgentry_t *pl4e, - rc = -EFAULT; - } - } -+ else if ( pv_l1tf_check_l4e(d, nl4e) ) -+ return -ERESTART; - else if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, vcpu, - preserve_ad)) ) - { -@@ -2301,7 +2371,8 @@ static int alloc_page_type(struct page_info *page, unsigned long type, - rc = alloc_l1_table(page); - break; - case PGT_l2_page_table: -- rc = alloc_l2_table(page, type, preemptible); -+ ASSERT(preemptible); -+ rc = alloc_l2_table(page, type); - break; - case PGT_l3_page_table: - ASSERT(preemptible); -@@ -2393,7 +2464,8 @@ int free_page_type(struct page_info *page, unsigned long type, - rc = 0; - break; - case PGT_l2_page_table: -- rc = free_l2_table(page, preemptible); -+ ASSERT(preemptible); -+ rc = free_l2_table(page); - break; - case PGT_l3_page_table: - ASSERT(preemptible); -@@ -2477,7 +2549,7 @@ static int _put_page_type(struct page_info *page, bool preemptible, - nx = x & ~(PGT_validated|PGT_partial); - if ( unlikely((y = cmpxchg(&page->u.inuse.type_info, - x, nx)) != x) ) -- continue; -+ goto maybe_preempt; - /* We cleared the 'valid bit' so we do the clean up. */ - rc = _put_final_page_type(page, x, preemptible, ptpg); - ptpg = NULL; -@@ -2509,12 +2581,13 @@ static int _put_page_type(struct page_info *page, bool preemptible, - */ - cpu_relax(); - y = page->u.inuse.type_info; -- continue; -+ goto maybe_preempt; - } - - if ( likely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) == x) ) - break; - -+ maybe_preempt: - if ( preemptible && hypercall_preempt_check() ) - return -EINTR; - } -@@ -2627,12 +2700,11 @@ static int __get_page_type(struct page_info *page, unsigned long type, - if ( !(x & PGT_partial) ) - { - /* Someone else is updating validation of this page. Wait... */ -- while ( (y = page->u.inuse.type_info) == x ) -- { -+ do { - if ( preemptible && hypercall_preempt_check() ) - return -EINTR; - cpu_relax(); -- } -+ } while ( (y = page->u.inuse.type_info) == x ); - continue; - } - /* Type ref count was left at 1 when PGT_partial got set. */ -@@ -3469,12 +3541,9 @@ long do_mmuext_op( - } - - if ( rc == -ERESTART ) -- { -- ASSERT(i < count); - rc = hypercall_create_continuation( - __HYPERVISOR_mmuext_op, "hihi", - uops, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); -- } - else if ( curr->arch.old_guest_table ) - { - XEN_GUEST_HANDLE_PARAM(void) null; -@@ -3674,18 +3743,27 @@ long do_mmu_update( - case PGT_l4_page_table: - rc = mod_l4_entry(va, l4e_from_intpte(req.val), mfn, - cmd == MMU_PT_UPDATE_PRESERVE_AD, v); -- /* -- * No need to sync if all uses of the page can be accounted -- * to the page lock we hold, its pinned status, and uses on -- * this (v)CPU. -- */ -- if ( !rc && !cpu_has_no_xpti && -- ((page->u.inuse.type_info & PGT_count_mask) > -- (1 + !!(page->u.inuse.type_info & PGT_pinned) + -- (pagetable_get_pfn(curr->arch.guest_table) == mfn) + -- (pagetable_get_pfn(curr->arch.guest_table_user) == -- mfn))) ) -- sync_guest = true; -+ if ( !rc && !cpu_has_no_xpti ) -+ { -+ bool local_in_use = false; -+ -+ if ( pagetable_get_pfn(curr->arch.guest_table) == mfn ) -+ { -+ local_in_use = true; -+ get_cpu_info()->root_pgt_changed = true; -+ } -+ -+ /* -+ * No need to sync if all uses of the page can be -+ * accounted to the page lock we hold, its pinned -+ * status, and uses on this (v)CPU. -+ */ -+ if ( (page->u.inuse.type_info & PGT_count_mask) > -+ (1 + !!(page->u.inuse.type_info & PGT_pinned) + -+ (pagetable_get_pfn(curr->arch.guest_table_user) == -+ mfn) + local_in_use) ) -+ sync_guest = true; -+ } - break; - case PGT_writable_page: - perfc_incr(writable_mmu_updates); -@@ -3761,12 +3839,9 @@ long do_mmu_update( - } - - if ( rc == -ERESTART ) -- { -- ASSERT(i < count); - rc = hypercall_create_continuation( - __HYPERVISOR_mmu_update, "hihi", - ureqs, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); -- } - else if ( curr->arch.old_guest_table ) - { - XEN_GUEST_HANDLE_PARAM(void) null; -@@ -3799,7 +3874,7 @@ long do_mmu_update( - - cpumask_andnot(mask, pt_owner->domain_dirty_cpumask, cpumask_of(cpu)); - if ( !cpumask_empty(mask) ) -- flush_mask(mask, FLUSH_TLB_GLOBAL); -+ flush_mask(mask, FLUSH_TLB_GLOBAL | FLUSH_ROOT_PGTBL); - } - - perfc_add(num_page_updates, i); -@@ -4020,7 +4095,13 @@ static int __do_update_va_mapping( - long do_update_va_mapping(unsigned long va, u64 val64, - unsigned long flags) - { -- return __do_update_va_mapping(va, val64, flags, current->domain); -+ int rc = __do_update_va_mapping(va, val64, flags, current->domain); -+ -+ if ( rc == -ERESTART ) -+ rc = hypercall_create_continuation( -+ __HYPERVISOR_update_va_mapping, "lll", va, val64, flags); -+ -+ return rc; - } - - long do_update_va_mapping_otherdomain(unsigned long va, u64 val64, -@@ -4037,6 +4118,46 @@ long do_update_va_mapping_otherdomain(unsigned long va, u64 val64, - - put_pg_owner(pg_owner); - -+ if ( rc == -ERESTART ) -+ rc = hypercall_create_continuation( -+ __HYPERVISOR_update_va_mapping_otherdomain, -+ "llli", va, val64, flags, domid); -+ -+ return rc; -+} -+ -+int compat_update_va_mapping(unsigned int va, uint32_t lo, uint32_t hi, -+ unsigned int flags) -+{ -+ int rc = __do_update_va_mapping(va, ((uint64_t)hi << 32) | lo, -+ flags, current->domain); -+ -+ if ( rc == -ERESTART ) -+ rc = hypercall_create_continuation( -+ __HYPERVISOR_update_va_mapping, "iiii", va, lo, hi, flags); -+ -+ return rc; -+} -+ -+int compat_update_va_mapping_otherdomain(unsigned int va, -+ uint32_t lo, uint32_t hi, -+ unsigned int flags, domid_t domid) -+{ -+ struct domain *pg_owner; -+ int rc; -+ -+ if ( (pg_owner = get_pg_owner(domid)) == NULL ) -+ return -ESRCH; -+ -+ rc = __do_update_va_mapping(va, ((uint64_t)hi << 32) | lo, flags, pg_owner); -+ -+ put_pg_owner(pg_owner); -+ -+ if ( rc == -ERESTART ) -+ rc = hypercall_create_continuation( -+ __HYPERVISOR_update_va_mapping_otherdomain, -+ "iiiii", va, lo, hi, flags, domid); -+ - return rc; - } - -diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c -index 755a8f83ca..3954e74d43 100644 ---- a/xen/arch/x86/mm/paging.c -+++ b/xen/arch/x86/mm/paging.c -@@ -879,6 +879,8 @@ void paging_dump_domain_info(struct domain *d) - printk(" paging assistance: "); - if ( paging_mode_shadow(d) ) - printk("shadow "); -+ if ( paging_mode_sh_forced(d) ) -+ printk("forced "); - if ( paging_mode_hap(d) ) - printk("hap "); - if ( paging_mode_refcounts(d) ) -diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c -index 3a33e0b148..199dbbc929 100644 ---- a/xen/arch/x86/mm/shadow/common.c -+++ b/xen/arch/x86/mm/shadow/common.c -@@ -3057,6 +3057,15 @@ static void sh_new_mode(struct domain *d, u32 new_mode) - ASSERT(paging_locked_by_me(d)); - ASSERT(d != current->domain); - -+ /* -+ * If PG_SH_forced has previously been activated because of writing an -+ * L1TF-vulnerable PTE, it must remain active for the remaining lifetime -+ * of the domain, even if the logdirty mode needs to be controlled for -+ * migration purposes. -+ */ -+ if ( paging_mode_sh_forced(d) ) -+ new_mode |= PG_SH_forced | PG_SH_enable; -+ - d->arch.paging.mode = new_mode; - for_each_vcpu(d, v) - sh_update_paging_modes(v); -@@ -3935,6 +3944,33 @@ void shadow_audit_tables(struct vcpu *v) - - #endif /* Shadow audit */ - -+#ifdef CONFIG_PV -+ -+void pv_l1tf_tasklet(unsigned long data) -+{ -+ struct domain *d = (void *)data; -+ -+ domain_pause(d); -+ paging_lock(d); -+ -+ if ( !paging_mode_sh_forced(d) && !d->is_dying ) -+ { -+ int ret = shadow_one_bit_enable(d, PG_SH_forced); -+ -+ if ( ret ) -+ { -+ printk(XENLOG_G_ERR "d%d Failed to enable PG_SH_forced: %d\n", -+ d->domain_id, ret); -+ domain_crash(d); -+ } -+ } -+ -+ paging_unlock(d); -+ domain_unpause(d); -+} -+ -+#endif /* CONFIG_PV */ -+ - /* - * Local variables: - * mode: C -diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c -index e93e3b36b1..8c03ba0158 100644 ---- a/xen/arch/x86/mm/shadow/multi.c -+++ b/xen/arch/x86/mm/shadow/multi.c -@@ -952,6 +952,8 @@ static int shadow_set_l4e(struct domain *d, - - /* Write the new entry */ - shadow_write_entries(sl4e, &new_sl4e, 1, sl4mfn); -+ flush_root_pgtbl_domain(d); -+ - flags |= SHADOW_SET_CHANGED; - - if ( shadow_l4e_get_flags(old_sl4e) & _PAGE_PRESENT ) -@@ -966,6 +968,7 @@ static int shadow_set_l4e(struct domain *d, - } - sh_put_ref(d, osl3mfn, paddr); - } -+ - return flags; - } - -diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c -index 49140e46f0..f3f6d48668 100644 ---- a/xen/arch/x86/mpparse.c -+++ b/xen/arch/x86/mpparse.c -@@ -68,19 +68,26 @@ physid_mask_t phys_cpu_present_map; - - void __init set_nr_cpu_ids(unsigned int max_cpus) - { -+ unsigned int tot_cpus = num_processors + disabled_cpus; -+ - if (!max_cpus) -- max_cpus = num_processors + disabled_cpus; -+ max_cpus = tot_cpus; - if (max_cpus > NR_CPUS) - max_cpus = NR_CPUS; - else if (!max_cpus) - max_cpus = 1; - printk(XENLOG_INFO "SMP: Allowing %u CPUs (%d hotplug CPUs)\n", - max_cpus, max_t(int, max_cpus - num_processors, 0)); -- nr_cpu_ids = max_cpus; -+ -+ if (!park_offline_cpus) -+ tot_cpus = max_cpus; -+ nr_cpu_ids = min(tot_cpus, NR_CPUS + 0u); -+ if (park_offline_cpus && nr_cpu_ids < num_processors) -+ printk(XENLOG_WARNING "SMP: Cannot bring up %u further CPUs\n", -+ num_processors - nr_cpu_ids); - - #ifndef nr_cpumask_bits -- nr_cpumask_bits = (max_cpus + (BITS_PER_LONG - 1)) & -- ~(BITS_PER_LONG - 1); -+ nr_cpumask_bits = ROUNDUP(nr_cpu_ids, BITS_PER_LONG); - printk(XENLOG_DEBUG "NR_CPUS:%u nr_cpumask_bits:%u\n", - NR_CPUS, nr_cpumask_bits); - #endif -diff --git a/xen/arch/x86/msr.c b/xen/arch/x86/msr.c -index 48d061d7da..8e39d5f271 100644 ---- a/xen/arch/x86/msr.c -+++ b/xen/arch/x86/msr.c -@@ -131,6 +131,7 @@ int guest_rdmsr(const struct vcpu *v, uint32_t msr, uint64_t *val) - case MSR_AMD_PATCHLOADER: - case MSR_IA32_UCODE_WRITE: - case MSR_PRED_CMD: -+ case MSR_FLUSH_CMD: - /* Write-only */ - goto gp_fault; - -@@ -178,6 +179,8 @@ int guest_wrmsr(struct vcpu *v, uint32_t msr, uint64_t val) - - switch ( msr ) - { -+ uint64_t rsvd; -+ - case MSR_INTEL_PLATFORM_INFO: - case MSR_ARCH_CAPABILITIES: - /* Read-only */ -@@ -213,8 +216,10 @@ int guest_wrmsr(struct vcpu *v, uint32_t msr, uint64_t val) - * Note: SPEC_CTRL_STIBP is specified as safe to use (i.e. ignored) - * when STIBP isn't enumerated in hardware. - */ -+ rsvd = ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | -+ (cp->feat.ssbd ? SPEC_CTRL_SSBD : 0)); - -- if ( val & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP) ) -+ if ( val & rsvd ) - goto gp_fault; /* Rsvd bit set? */ - - vp->spec_ctrl.raw = val; -@@ -231,14 +236,25 @@ int guest_wrmsr(struct vcpu *v, uint32_t msr, uint64_t val) - wrmsrl(MSR_PRED_CMD, val); - break; - -+ case MSR_FLUSH_CMD: -+ if ( !cp->feat.l1d_flush ) -+ goto gp_fault; /* MSR available? */ -+ -+ if ( val & ~FLUSH_CMD_L1D ) -+ goto gp_fault; /* Rsvd bit set? */ -+ -+ if ( v == curr ) -+ wrmsrl(MSR_FLUSH_CMD, val); -+ break; -+ - case MSR_INTEL_MISC_FEATURES_ENABLES: - { -- uint64_t rsvd = ~0ull; - bool old_cpuid_faulting = vp->misc_features_enables.cpuid_faulting; - - if ( !vp->misc_features_enables.available ) - goto gp_fault; - -+ rsvd = ~0ull; - if ( dp->plaform_info.cpuid_faulting ) - rsvd &= ~MSR_MISC_FEATURES_CPUID_FAULTING; - -diff --git a/xen/arch/x86/oprofile/nmi_int.c b/xen/arch/x86/oprofile/nmi_int.c -index d8f5230906..3dfb8fef93 100644 ---- a/xen/arch/x86/oprofile/nmi_int.c -+++ b/xen/arch/x86/oprofile/nmi_int.c -@@ -182,7 +182,7 @@ int nmi_reserve_counters(void) - if (!allocate_msrs()) - return -ENOMEM; - -- /* We walk a thin line between law and rape here. -+ /* - * We need to be careful to install our NMI handler - * without actually triggering any NMIs as this will - * break the core code horrifically. -diff --git a/xen/arch/x86/percpu.c b/xen/arch/x86/percpu.c -index c9997b7937..8be4ebddf4 100644 ---- a/xen/arch/x86/percpu.c -+++ b/xen/arch/x86/percpu.c -@@ -28,7 +28,7 @@ static int init_percpu_area(unsigned int cpu) - char *p; - - if ( __per_cpu_offset[cpu] != INVALID_PERCPU_AREA ) -- return -EBUSY; -+ return 0; - - if ( (p = alloc_xenheap_pages(PERCPU_ORDER, 0)) == NULL ) - return -ENOMEM; -@@ -76,9 +76,12 @@ static int cpu_percpu_callback( - break; - case CPU_UP_CANCELED: - case CPU_DEAD: -- free_percpu_area(cpu); -+ if ( !park_offline_cpus ) -+ free_percpu_area(cpu); - break; -- default: -+ case CPU_REMOVE: -+ if ( park_offline_cpus ) -+ free_percpu_area(cpu); - break; - } - -diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c -index 5d8909fa13..1a8142f89b 100644 ---- a/xen/arch/x86/pv/dom0_build.c -+++ b/xen/arch/x86/pv/dom0_build.c -@@ -388,6 +388,8 @@ int __init dom0_construct_pv(struct domain *d, - if ( compat32 ) - { - d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 1; -+ d->arch.pv_domain.xpti = false; -+ d->arch.pv_domain.pcid = false; - v->vcpu_info = (void *)&d->shared_info->compat.vcpu_info[0]; - if ( setup_compat_arg_xlat(v) != 0 ) - BUG(); -@@ -721,7 +723,7 @@ int __init dom0_construct_pv(struct domain *d, - update_cr3(v); - - /* We run on dom0's page tables for the final part of the build process. */ -- write_ptbase(v); -+ switch_cr3_cr4(cr3_pa(v->arch.cr3), read_cr4()); - mapcache_override_current(v); - - /* Copy the OS image and free temporary buffer. */ -@@ -742,7 +744,7 @@ int __init dom0_construct_pv(struct domain *d, - (parms.virt_hypercall >= v_end) ) - { - mapcache_override_current(NULL); -- write_ptbase(current); -+ switch_cr3_cr4(current->arch.cr3, read_cr4()); - printk("Invalid HYPERCALL_PAGE field in ELF notes.\n"); - rc = -1; - goto out; -@@ -875,7 +877,7 @@ int __init dom0_construct_pv(struct domain *d, - - /* Return to idle domain's page tables. */ - mapcache_override_current(NULL); -- write_ptbase(current); -+ switch_cr3_cr4(current->arch.cr3, read_cr4()); - - update_domain_wallclock_time(d); - -diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c -index 74e9e667d2..bdcbd38f15 100644 ---- a/xen/arch/x86/pv/domain.c -+++ b/xen/arch/x86/pv/domain.c -@@ -9,7 +9,54 @@ - #include <xen/lib.h> - #include <xen/sched.h> - -+#include <asm/cpufeature.h> -+#include <asm/invpcid.h> -+#include <asm/spec_ctrl.h> - #include <asm/pv/domain.h> -+#include <asm/shadow.h> -+ -+static __read_mostly enum { -+ PCID_OFF, -+ PCID_ALL, -+ PCID_XPTI, -+ PCID_NOXPTI -+} opt_pcid = PCID_XPTI; -+ -+static __init int parse_pcid(const char *s) -+{ -+ int rc = 0; -+ -+ switch ( parse_bool(s, NULL) ) -+ { -+ case 0: -+ opt_pcid = PCID_OFF; -+ break; -+ -+ case 1: -+ opt_pcid = PCID_ALL; -+ break; -+ -+ default: -+ switch ( parse_boolean("xpti", s, NULL) ) -+ { -+ case 0: -+ opt_pcid = PCID_NOXPTI; -+ break; -+ -+ case 1: -+ opt_pcid = PCID_XPTI; -+ break; -+ -+ default: -+ rc = -EINVAL; -+ break; -+ } -+ break; -+ } -+ -+ return rc; -+} -+custom_runtime_param("pcid", parse_pcid); - - /* Override macros from asm/page.h to make them work with mfn_t */ - #undef mfn_to_page -@@ -81,6 +128,9 @@ int switch_compat(struct domain *d) - - d->arch.x87_fip_width = 4; - -+ d->arch.pv_domain.xpti = false; -+ d->arch.pv_domain.pcid = false; -+ - return 0; - - undo_and_fail: -@@ -166,6 +216,8 @@ int pv_vcpu_initialise(struct vcpu *v) - - void pv_domain_destroy(struct domain *d) - { -+ pv_l1tf_domain_destroy(d); -+ - destroy_perdomain_mapping(d, GDT_LDT_VIRT_START, - GDT_LDT_MBYTES << (20 - PAGE_SHIFT)); - -@@ -187,6 +239,8 @@ int pv_domain_initialise(struct domain *d, unsigned int domcr_flags, - }; - int rc = -ENOMEM; - -+ pv_l1tf_domain_init(d); -+ - d->arch.pv_domain.gdt_ldt_l1tab = - alloc_xenheap_pages(0, MEMF_node(domain_to_node(d))); - if ( !d->arch.pv_domain.gdt_ldt_l1tab ) -@@ -212,6 +266,32 @@ int pv_domain_initialise(struct domain *d, unsigned int domcr_flags, - /* 64-bit PV guest by default. */ - d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 0; - -+ d->arch.pv_domain.xpti = opt_xpti & (is_hardware_domain(d) -+ ? OPT_XPTI_DOM0 : OPT_XPTI_DOMU); -+ -+ if ( !is_pv_32bit_domain(d) && use_invpcid && cpu_has_pcid ) -+ switch ( opt_pcid ) -+ { -+ case PCID_OFF: -+ break; -+ -+ case PCID_ALL: -+ d->arch.pv_domain.pcid = true; -+ break; -+ -+ case PCID_XPTI: -+ d->arch.pv_domain.pcid = d->arch.pv_domain.xpti; -+ break; -+ -+ case PCID_NOXPTI: -+ d->arch.pv_domain.pcid = !d->arch.pv_domain.xpti; -+ break; -+ -+ default: -+ ASSERT_UNREACHABLE(); -+ break; -+ } -+ - return 0; - - fail: -@@ -239,13 +319,25 @@ void toggle_guest_mode(struct vcpu *v) - - void toggle_guest_pt(struct vcpu *v) - { -+ const struct domain *d = v->domain; -+ - if ( is_pv_32bit_vcpu(v) ) - return; - - v->arch.flags ^= TF_kernel_mode; - update_cr3(v); -+ if ( d->arch.pv_domain.xpti ) -+ { -+ struct cpu_info *cpu_info = get_cpu_info(); -+ -+ cpu_info->root_pgt_changed = true; -+ cpu_info->pv_cr3 = __pa(this_cpu(root_pgt)) | -+ (d->arch.pv_domain.pcid -+ ? get_pcid_bits(v, true) : 0); -+ } -+ - /* Don't flush user global mappings from the TLB. Don't tick TLB clock. */ -- asm volatile ( "mov %0, %%cr3" : : "r" (v->arch.cr3) : "memory" ); -+ write_cr3(v->arch.cr3); - - if ( !(v->arch.flags & TF_kernel_mode) ) - return; -diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c -index 642ca312bf..c281936af0 100644 ---- a/xen/arch/x86/pv/emul-priv-op.c -+++ b/xen/arch/x86/pv/emul-priv-op.c -@@ -813,26 +813,6 @@ static int write_cr(unsigned int reg, unsigned long val, - return X86EMUL_UNHANDLEABLE; - } - --static int read_dr(unsigned int reg, unsigned long *val, -- struct x86_emulate_ctxt *ctxt) --{ -- unsigned long res = do_get_debugreg(reg); -- -- if ( IS_ERR_VALUE(res) ) -- return X86EMUL_UNHANDLEABLE; -- -- *val = res; -- -- return X86EMUL_OKAY; --} -- --static int write_dr(unsigned int reg, unsigned long val, -- struct x86_emulate_ctxt *ctxt) --{ -- return do_set_debugreg(reg, val) == 0 -- ? X86EMUL_OKAY : X86EMUL_UNHANDLEABLE; --} -- - static inline uint64_t guest_misc_enable(uint64_t val) - { - val &= ~(MSR_IA32_MISC_ENABLE_PERF_AVAIL | -@@ -906,9 +886,16 @@ static int read_msr(unsigned int reg, uint64_t *val, - return X86EMUL_OKAY; - - case MSR_EFER: -- *val = read_efer(); -+ /* Hide unknown bits, and unconditionally hide SVME from guests. */ -+ *val = read_efer() & EFER_KNOWN_MASK & ~EFER_SVME; -+ /* -+ * Hide the 64-bit features from 32-bit guests. SCE has -+ * vendor-dependent behaviour. -+ */ - if ( is_pv_32bit_domain(currd) ) -- *val &= ~(EFER_LME | EFER_LMA | EFER_LMSLE); -+ *val &= ~(EFER_LME | EFER_LMA | EFER_LMSLE | -+ (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL -+ ? EFER_SCE : 0)); - return X86EMUL_OKAY; - - case MSR_K7_FID_VID_CTL: -@@ -1326,8 +1313,8 @@ static const struct x86_emulate_ops priv_op_ops = { - .read_segment = read_segment, - .read_cr = read_cr, - .write_cr = write_cr, -- .read_dr = read_dr, -- .write_dr = write_dr, -+ .read_dr = x86emul_read_dr, -+ .write_dr = x86emul_write_dr, - .read_msr = read_msr, - .write_msr = write_msr, - .cpuid = pv_emul_cpuid, -diff --git a/xen/arch/x86/pv/misc-hypercalls.c b/xen/arch/x86/pv/misc-hypercalls.c -index 5862130697..1619be7874 100644 ---- a/xen/arch/x86/pv/misc-hypercalls.c -+++ b/xen/arch/x86/pv/misc-hypercalls.c -@@ -30,22 +30,10 @@ long do_set_debugreg(int reg, unsigned long value) - - unsigned long do_get_debugreg(int reg) - { -- struct vcpu *curr = current; -+ unsigned long val; -+ int res = x86emul_read_dr(reg, &val, NULL); - -- switch ( reg ) -- { -- case 0 ... 3: -- case 6: -- return curr->arch.debugreg[reg]; -- case 7: -- return (curr->arch.debugreg[7] | -- curr->arch.debugreg[5]); -- case 4 ... 5: -- return ((curr->arch.pv_vcpu.ctrlreg[4] & X86_CR4_DE) ? -- curr->arch.debugreg[reg + 2] : 0); -- } -- -- return -EINVAL; -+ return res == X86EMUL_OKAY ? val : -ENODEV; - } - - long do_fpu_taskswitch(int set) -diff --git a/xen/arch/x86/pv/ro-page-fault.c b/xen/arch/x86/pv/ro-page-fault.c -index 6b2976d3df..622bb7dff0 100644 ---- a/xen/arch/x86/pv/ro-page-fault.c -+++ b/xen/arch/x86/pv/ro-page-fault.c -@@ -29,6 +29,7 @@ - #include <asm/mm.h> - #include <asm/pci.h> - #include <asm/pv/mm.h> -+#include <asm/shadow.h> - - #include "emulate.h" - #include "mm.h" -@@ -127,6 +128,10 @@ static int ptwr_emulated_update(unsigned long addr, paddr_t old, paddr_t val, - - /* Check the new PTE. */ - nl1e = l1e_from_intpte(val); -+ -+ if ( !(l1e_get_flags(nl1e) & _PAGE_PRESENT) && pv_l1tf_check_l1e(d, nl1e) ) -+ return X86EMUL_RETRY; -+ - switch ( ret = get_page_from_l1e(nl1e, d, d) ) - { - default: -diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c -index 482fe11669..1e9eecae04 100644 ---- a/xen/arch/x86/setup.c -+++ b/xen/arch/x86/setup.c -@@ -62,6 +62,14 @@ boolean_param("nosmp", opt_nosmp); - static unsigned int __initdata max_cpus; - integer_param("maxcpus", max_cpus); - -+int8_t __read_mostly opt_smt = -1; -+boolean_param("smt", opt_smt); -+ -+/* opt_invpcid: If false, don't use INVPCID instruction even if available. */ -+static bool __initdata opt_invpcid = true; -+boolean_param("invpcid", opt_invpcid); -+bool __read_mostly use_invpcid; -+ - unsigned long __read_mostly cr4_pv32_mask; - - /* **** Linux config option: propagated to domain0. */ -@@ -169,9 +177,6 @@ static int __init parse_smap_param(const char *s) - } - custom_param("smap", parse_smap_param); - --static int8_t __initdata opt_xpti = -1; --boolean_param("xpti", opt_xpti); -- - bool __read_mostly acpi_disabled; - bool __initdata acpi_force; - static char __initdata acpi_param[10] = ""; -@@ -663,7 +668,7 @@ void __init noreturn __start_xen(unsigned long mbi_p) - { - char *memmap_type = NULL; - char *cmdline, *kextra, *loader; -- unsigned int initrdidx, domcr_flags = DOMCRF_s3_integrity; -+ unsigned int initrdidx, num_parked = 0, domcr_flags = DOMCRF_s3_integrity; - multiboot_info_t *mbi; - module_t *mod; - unsigned long nr_pages, raw_max_page, modules_headroom, *module_map; -@@ -905,6 +910,18 @@ void __init noreturn __start_xen(unsigned long mbi_p) - /* Sanitise the raw E820 map to produce a final clean version. */ - max_page = raw_max_page = init_e820(memmap_type, &e820_raw); - -+ if ( !efi_enabled(EFI_BOOT) ) -+ { -+ /* -+ * Supplement the heuristics in l1tf_calculations() by assuming that -+ * anything referenced in the E820 may be cacheable. -+ */ -+ l1tf_safe_maddr = -+ max(l1tf_safe_maddr, -+ ROUNDUP(e820_raw.map[e820_raw.nr_map - 1].addr + -+ e820_raw.map[e820_raw.nr_map - 1].size, PAGE_SIZE)); -+ } -+ - /* Create a temporary copy of the E820 map. */ - memcpy(&boot_e820, &e820, sizeof(e820)); - -@@ -1485,7 +1502,8 @@ void __init noreturn __start_xen(unsigned long mbi_p) - else - { - set_nr_cpu_ids(max_cpus); -- max_cpus = nr_cpu_ids; -+ if ( !max_cpus ) -+ max_cpus = nr_cpu_ids; - } - - if ( xen_guest ) -@@ -1539,25 +1557,12 @@ void __init noreturn __start_xen(unsigned long mbi_p) - - cr4_pv32_mask = mmu_cr4_features & XEN_CR4_PV32_BITS; - -- if ( opt_xpti < 0 ) -- { -- uint64_t caps = 0; -- -- if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD ) -- caps = ARCH_CAPABILITIES_RDCL_NO; -- else if ( boot_cpu_has(X86_FEATURE_ARCH_CAPS) ) -- rdmsrl(MSR_ARCH_CAPABILITIES, caps); -- -- opt_xpti = !(caps & ARCH_CAPABILITIES_RDCL_NO); -- } -- if ( opt_xpti ) -- setup_clear_cpu_cap(X86_FEATURE_NO_XPTI); -- else -- setup_force_cpu_cap(X86_FEATURE_NO_XPTI); -- - if ( cpu_has_fsgsbase ) - set_in_cr4(X86_CR4_FSGSBASE); - -+ if ( opt_invpcid && cpu_has_invpcid ) -+ use_invpcid = true; -+ - init_speculation_mitigations(); - - init_idle_domain(); -@@ -1621,16 +1626,30 @@ void __init noreturn __start_xen(unsigned long mbi_p) - /* Set up node_to_cpumask based on cpu_to_node[]. */ - numa_add_cpu(i); - -- if ( (num_online_cpus() < max_cpus) && !cpu_online(i) ) -+ if ( (park_offline_cpus || num_online_cpus() < max_cpus) && -+ !cpu_online(i) ) - { - int ret = cpu_up(i); - if ( ret != 0 ) - printk("Failed to bring up CPU %u (error %d)\n", i, ret); -+ else if ( num_online_cpus() > max_cpus || -+ (!opt_smt && -+ cpu_data[i].compute_unit_id == INVALID_CUID && -+ cpumask_weight(per_cpu(cpu_sibling_mask, i)) > 1) ) -+ { -+ ret = cpu_down(i); -+ if ( !ret ) -+ ++num_parked; -+ else -+ printk("Could not re-offline CPU%u (%d)\n", i, ret); -+ } - } - } - } - - printk("Brought up %ld CPUs\n", (long)num_online_cpus()); -+ if ( num_parked ) -+ printk(XENLOG_INFO "Parked %u CPUs\n", num_parked); - smp_cpus_done(); - - do_initcalls(); -@@ -1746,6 +1765,13 @@ void __init noreturn __start_xen(unsigned long mbi_p) - - setup_io_bitmap(dom0); - -+ if ( bsp_delay_spec_ctrl ) -+ { -+ get_cpu_info()->spec_ctrl_flags &= ~SCF_use_shadow; -+ barrier(); -+ wrmsrl(MSR_SPEC_CTRL, default_xen_spec_ctrl); -+ } -+ - /* Jump to the 1:1 virtual mappings of cpu0_stack. */ - asm volatile ("mov %[stk], %%rsp; jmp %c[fn]" :: - [stk] "g" (__va(__pa(get_stack_bottom()))), -diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c -index fd6d254812..517ba2f70d 100644 ---- a/xen/arch/x86/smp.c -+++ b/xen/arch/x86/smp.c -@@ -208,7 +208,7 @@ void invalidate_interrupt(struct cpu_user_regs *regs) - ack_APIC_irq(); - perfc_incr(ipis); - if ( __sync_local_execstate() ) -- flags &= ~(FLUSH_TLB | FLUSH_TLB_GLOBAL); -+ flags &= ~(FLUSH_TLB | FLUSH_TLB_GLOBAL | FLUSH_ROOT_PGTBL); - flush_area_local(flush_va, flags); - cpumask_clear_cpu(smp_processor_id(), &flush_cpumask); - } -diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c -index e1d023428c..b0496eb66e 100644 ---- a/xen/arch/x86/smpboot.c -+++ b/xen/arch/x86/smpboot.c -@@ -69,6 +69,8 @@ static cpumask_t scratch_cpu0mask; - cpumask_t cpu_online_map __read_mostly; - EXPORT_SYMBOL(cpu_online_map); - -+bool __read_mostly park_offline_cpus; -+ - unsigned int __read_mostly nr_sockets; - cpumask_t **__read_mostly socket_cpumask; - static cpumask_t *secondary_socket_cpumask; -@@ -228,33 +230,41 @@ static void link_thread_siblings(int cpu1, int cpu2) - cpumask_set_cpu(cpu2, per_cpu(cpu_core_mask, cpu1)); - } - --static void set_cpu_sibling_map(int cpu) -+static void set_cpu_sibling_map(unsigned int cpu) - { -- int i; -+ unsigned int i; - struct cpuinfo_x86 *c = cpu_data; - - cpumask_set_cpu(cpu, &cpu_sibling_setup_map); - - cpumask_set_cpu(cpu, socket_cpumask[cpu_to_socket(cpu)]); -+ cpumask_set_cpu(cpu, per_cpu(cpu_core_mask, cpu)); -+ cpumask_set_cpu(cpu, per_cpu(cpu_sibling_mask, cpu)); - - if ( c[cpu].x86_num_siblings > 1 ) - { - for_each_cpu ( i, &cpu_sibling_setup_map ) - { -- if ( cpu_has(c, X86_FEATURE_TOPOEXT) ) { -- if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) && -- (c[cpu].compute_unit_id == c[i].compute_unit_id) ) -+ if ( cpu == i || c[cpu].phys_proc_id != c[i].phys_proc_id ) -+ continue; -+ if ( c[cpu].compute_unit_id != INVALID_CUID && -+ c[i].compute_unit_id != INVALID_CUID ) -+ { -+ if ( c[cpu].compute_unit_id == c[i].compute_unit_id ) -+ link_thread_siblings(cpu, i); -+ } -+ else if ( c[cpu].cpu_core_id != XEN_INVALID_CORE_ID && -+ c[i].cpu_core_id != XEN_INVALID_CORE_ID ) -+ { -+ if ( c[cpu].cpu_core_id == c[i].cpu_core_id ) - link_thread_siblings(cpu, i); -- } else if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) && -- (c[cpu].cpu_core_id == c[i].cpu_core_id) ) { -- link_thread_siblings(cpu, i); - } -+ else -+ printk(XENLOG_WARNING -+ "CPU%u: unclear relationship with CPU%u\n", -+ cpu, i); - } - } -- else -- { -- cpumask_set_cpu(cpu, per_cpu(cpu_sibling_mask, cpu)); -- } - - if ( c[cpu].x86_max_cores == 1 ) - { -@@ -330,8 +340,9 @@ void start_secondary(void *unused) - */ - spin_debug_disable(); - -+ get_cpu_info()->use_pv_cr3 = false; - get_cpu_info()->xen_cr3 = 0; -- get_cpu_info()->pv_cr3 = this_cpu(root_pgt) ? __pa(this_cpu(root_pgt)) : 0; -+ get_cpu_info()->pv_cr3 = 0; - - load_system_tables(); - -@@ -351,6 +362,14 @@ void start_secondary(void *unused) - else - microcode_resume_cpu(cpu); - -+ /* -+ * If MSR_SPEC_CTRL is available, apply Xen's default setting and discard -+ * any firmware settings. Note: MSR_SPEC_CTRL may only become available -+ * after loading microcode. -+ */ -+ if ( boot_cpu_has(X86_FEATURE_IBRSB) ) -+ wrmsrl(MSR_SPEC_CTRL, default_xen_spec_ctrl); -+ - if ( xen_guest ) - hypervisor_ap_setup(); - -@@ -870,11 +889,18 @@ static void cleanup_cpu_root_pgt(unsigned int cpu) - l2_pgentry_t *l2t = l3e_to_l2e(l3t[l3_table_offset(stub_linear)]); - l1_pgentry_t *l1t = l2e_to_l1e(l2t[l2_table_offset(stub_linear)]); - -- l1t[l2_table_offset(stub_linear)] = l1e_empty(); -+ l1t[l1_table_offset(stub_linear)] = l1e_empty(); - } - } - --static void cpu_smpboot_free(unsigned int cpu) -+/* -+ * The 'remove' boolean controls whether a CPU is just getting offlined (and -+ * parked), or outright removed / offlined without parking. Parked CPUs need -+ * things like their stack, GDT, IDT, TSS, and per-CPU data still available. -+ * A few other items, in particular CPU masks, are also retained, as it's -+ * difficult to prove that they're entirely unreferenced from parked CPUs. -+ */ -+static void cpu_smpboot_free(unsigned int cpu, bool remove) - { - unsigned int order, socket = cpu_to_socket(cpu); - struct cpuinfo_x86 *c = cpu_data; -@@ -885,15 +911,19 @@ static void cpu_smpboot_free(unsigned int cpu) - socket_cpumask[socket] = NULL; - } - -- c[cpu].phys_proc_id = XEN_INVALID_SOCKET_ID; -- c[cpu].cpu_core_id = XEN_INVALID_CORE_ID; -- c[cpu].compute_unit_id = INVALID_CUID; - cpumask_clear_cpu(cpu, &cpu_sibling_setup_map); - -- free_cpumask_var(per_cpu(cpu_sibling_mask, cpu)); -- free_cpumask_var(per_cpu(cpu_core_mask, cpu)); -- if ( per_cpu(scratch_cpumask, cpu) != &scratch_cpu0mask ) -- free_cpumask_var(per_cpu(scratch_cpumask, cpu)); -+ if ( remove ) -+ { -+ c[cpu].phys_proc_id = XEN_INVALID_SOCKET_ID; -+ c[cpu].cpu_core_id = XEN_INVALID_CORE_ID; -+ c[cpu].compute_unit_id = INVALID_CUID; -+ -+ FREE_CPUMASK_VAR(per_cpu(cpu_sibling_mask, cpu)); -+ FREE_CPUMASK_VAR(per_cpu(cpu_core_mask, cpu)); -+ if ( per_cpu(scratch_cpumask, cpu) != &scratch_cpu0mask ) -+ FREE_CPUMASK_VAR(per_cpu(scratch_cpumask, cpu)); -+ } - - cleanup_cpu_root_pgt(cpu); - -@@ -915,19 +945,21 @@ static void cpu_smpboot_free(unsigned int cpu) - } - - order = get_order_from_pages(NR_RESERVED_GDT_PAGES); -- free_xenheap_pages(per_cpu(gdt_table, cpu), order); -+ if ( remove ) -+ FREE_XENHEAP_PAGES(per_cpu(gdt_table, cpu), order); - - free_xenheap_pages(per_cpu(compat_gdt_table, cpu), order); - -- order = get_order_from_bytes(IDT_ENTRIES * sizeof(idt_entry_t)); -- free_xenheap_pages(idt_tables[cpu], order); -- idt_tables[cpu] = NULL; -- -- if ( stack_base[cpu] != NULL ) -+ if ( remove ) - { -- memguard_unguard_stack(stack_base[cpu]); -- free_xenheap_pages(stack_base[cpu], STACK_ORDER); -- stack_base[cpu] = NULL; -+ order = get_order_from_bytes(IDT_ENTRIES * sizeof(idt_entry_t)); -+ FREE_XENHEAP_PAGES(idt_tables[cpu], order); -+ -+ if ( stack_base[cpu] ) -+ { -+ memguard_unguard_stack(stack_base[cpu]); -+ FREE_XENHEAP_PAGES(stack_base[cpu], STACK_ORDER); -+ } - } - } - -@@ -941,15 +973,17 @@ static int cpu_smpboot_alloc(unsigned int cpu) - if ( node != NUMA_NO_NODE ) - memflags = MEMF_node(node); - -- stack_base[cpu] = alloc_xenheap_pages(STACK_ORDER, memflags); -+ if ( stack_base[cpu] == NULL ) -+ stack_base[cpu] = alloc_xenheap_pages(STACK_ORDER, memflags); - if ( stack_base[cpu] == NULL ) - goto oom; - memguard_guard_stack(stack_base[cpu]); - - order = get_order_from_pages(NR_RESERVED_GDT_PAGES); -- per_cpu(gdt_table, cpu) = gdt = alloc_xenheap_pages(order, memflags); -+ gdt = per_cpu(gdt_table, cpu) ?: alloc_xenheap_pages(order, memflags); - if ( gdt == NULL ) - goto oom; -+ per_cpu(gdt_table, cpu) = gdt; - memcpy(gdt, boot_cpu_gdt_table, NR_RESERVED_GDT_PAGES * PAGE_SIZE); - BUILD_BUG_ON(NR_CPUS > 0x10000); - gdt[PER_CPU_GDT_ENTRY - FIRST_RESERVED_GDT_ENTRY].a = cpu; -@@ -961,13 +995,15 @@ static int cpu_smpboot_alloc(unsigned int cpu) - gdt[PER_CPU_GDT_ENTRY - FIRST_RESERVED_GDT_ENTRY].a = cpu; - - order = get_order_from_bytes(IDT_ENTRIES * sizeof(idt_entry_t)); -- idt_tables[cpu] = alloc_xenheap_pages(order, memflags); -+ if ( idt_tables[cpu] == NULL ) -+ idt_tables[cpu] = alloc_xenheap_pages(order, memflags); - if ( idt_tables[cpu] == NULL ) - goto oom; - memcpy(idt_tables[cpu], idt_table, IDT_ENTRIES * sizeof(idt_entry_t)); - set_ist(&idt_tables[cpu][TRAP_double_fault], IST_NONE); - set_ist(&idt_tables[cpu][TRAP_nmi], IST_NONE); - set_ist(&idt_tables[cpu][TRAP_machine_check], IST_NONE); -+ set_ist(&idt_tables[cpu][TRAP_debug], IST_NONE); - - for ( stub_page = 0, i = cpu & ~(STUBS_PER_PAGE - 1); - i < nr_cpu_ids && i <= (cpu | (STUBS_PER_PAGE - 1)); ++i ) -@@ -989,13 +1025,13 @@ static int cpu_smpboot_alloc(unsigned int cpu) - (secondary_socket_cpumask = xzalloc(cpumask_t)) == NULL ) - goto oom; - -- if ( zalloc_cpumask_var(&per_cpu(cpu_sibling_mask, cpu)) && -- zalloc_cpumask_var(&per_cpu(cpu_core_mask, cpu)) && -- alloc_cpumask_var(&per_cpu(scratch_cpumask, cpu)) ) -+ if ( cond_zalloc_cpumask_var(&per_cpu(cpu_sibling_mask, cpu)) && -+ cond_zalloc_cpumask_var(&per_cpu(cpu_core_mask, cpu)) && -+ cond_alloc_cpumask_var(&per_cpu(scratch_cpumask, cpu)) ) - return 0; - - oom: -- cpu_smpboot_free(cpu); -+ cpu_smpboot_free(cpu, true); - return -ENOMEM; - } - -@@ -1012,9 +1048,10 @@ static int cpu_smpboot_callback( - break; - case CPU_UP_CANCELED: - case CPU_DEAD: -- cpu_smpboot_free(cpu); -+ cpu_smpboot_free(cpu, !park_offline_cpus); - break; -- default: -+ case CPU_REMOVE: -+ cpu_smpboot_free(cpu, true); - break; - } - -@@ -1047,7 +1084,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) - panic("Error %d setting up PV root page table\n", rc); - if ( per_cpu(root_pgt, 0) ) - { -- get_cpu_info()->pv_cr3 = __pa(per_cpu(root_pgt, 0)); -+ get_cpu_info()->pv_cr3 = 0; - - /* - * All entry points which may need to switch page tables have to start -@@ -1126,6 +1163,7 @@ void __init smp_prepare_boot_cpu(void) - per_cpu(scratch_cpumask, cpu) = &scratch_cpu0mask; - #endif - -+ get_cpu_info()->use_pv_cr3 = false; - get_cpu_info()->xen_cr3 = 0; - get_cpu_info()->pv_cr3 = 0; - } -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 3c7447bfe6..14e01faff9 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -19,13 +19,23 @@ - #include <xen/errno.h> - #include <xen/init.h> - #include <xen/lib.h> -+#include <xen/warning.h> - - #include <asm/microcode.h> - #include <asm/msr.h> - #include <asm/processor.h> -+#include <asm/pv/shim.h> -+#include <asm/setup.h> - #include <asm/spec_ctrl.h> - #include <asm/spec_ctrl_asm.h> - -+/* Cmdline controls for Xen's alternative blocks. */ -+static bool __initdata opt_msr_sc_pv = true; -+static bool __initdata opt_msr_sc_hvm = true; -+static bool __initdata opt_rsb_pv = true; -+static bool __initdata opt_rsb_hvm = true; -+ -+/* Cmdline controls for Xen's speculative settings. */ - static enum ind_thunk { - THUNK_DEFAULT, /* Decide which thunk to use at boot time. */ - THUNK_NONE, /* Missing compiler support for thunks. */ -@@ -35,10 +45,18 @@ static enum ind_thunk { - THUNK_JMP, - } opt_thunk __initdata = THUNK_DEFAULT; - static int8_t __initdata opt_ibrs = -1; --static bool __initdata opt_rsb_native = true; --static bool __initdata opt_rsb_vmexit = true; - bool __read_mostly opt_ibpb = true; --uint8_t __read_mostly default_bti_ist_info; -+bool __read_mostly opt_ssbd = false; -+int8_t __read_mostly opt_eager_fpu = -1; -+int8_t __read_mostly opt_l1d_flush = -1; -+ -+bool __initdata bsp_delay_spec_ctrl; -+uint8_t __read_mostly default_xen_spec_ctrl; -+uint8_t __read_mostly default_spec_ctrl_flags; -+ -+paddr_t __read_mostly l1tf_addr_mask, __read_mostly l1tf_safe_maddr; -+static bool __initdata cpu_has_bug_l1tf; -+static unsigned int __initdata l1d_maxphysaddr; - - static int __init parse_bti(const char *s) - { -@@ -68,9 +86,9 @@ static int __init parse_bti(const char *s) - else if ( (val = parse_boolean("ibpb", s, ss)) >= 0 ) - opt_ibpb = val; - else if ( (val = parse_boolean("rsb_native", s, ss)) >= 0 ) -- opt_rsb_native = val; -+ opt_rsb_pv = val; - else if ( (val = parse_boolean("rsb_vmexit", s, ss)) >= 0 ) -- opt_rsb_vmexit = val; -+ opt_rsb_hvm = val; - else - rc = -EINVAL; - -@@ -81,50 +99,244 @@ static int __init parse_bti(const char *s) - } - custom_param("bti", parse_bti); - --static void __init print_details(enum ind_thunk thunk) -+static int __init parse_spec_ctrl(const char *s) -+{ -+ const char *ss; -+ int val, rc = 0; -+ -+ do { -+ ss = strchr(s, ','); -+ if ( !ss ) -+ ss = strchr(s, '\0'); -+ -+ /* Global and Xen-wide disable. */ -+ val = parse_bool(s, ss); -+ if ( !val ) -+ { -+ opt_msr_sc_pv = false; -+ opt_msr_sc_hvm = false; -+ -+ opt_eager_fpu = 0; -+ -+ if ( opt_xpti < 0 ) -+ opt_xpti = 0; -+ -+ if ( opt_smt < 0 ) -+ opt_smt = 1; -+ -+ if ( opt_pv_l1tf < 0 ) -+ opt_pv_l1tf = 0; -+ -+ disable_common: -+ opt_rsb_pv = false; -+ opt_rsb_hvm = false; -+ -+ opt_thunk = THUNK_JMP; -+ opt_ibrs = 0; -+ opt_ibpb = false; -+ opt_ssbd = false; -+ opt_l1d_flush = 0; -+ } -+ else if ( val > 0 ) -+ rc = -EINVAL; -+ else if ( (val = parse_boolean("xen", s, ss)) >= 0 ) -+ { -+ if ( !val ) -+ goto disable_common; -+ -+ rc = -EINVAL; -+ } -+ -+ /* Xen's alternative blocks. */ -+ else if ( (val = parse_boolean("pv", s, ss)) >= 0 ) -+ { -+ opt_msr_sc_pv = val; -+ opt_rsb_pv = val; -+ } -+ else if ( (val = parse_boolean("hvm", s, ss)) >= 0 ) -+ { -+ opt_msr_sc_hvm = val; -+ opt_rsb_hvm = val; -+ } -+ else if ( (val = parse_boolean("msr-sc", s, ss)) >= 0 ) -+ { -+ opt_msr_sc_pv = val; -+ opt_msr_sc_hvm = val; -+ } -+ else if ( (val = parse_boolean("rsb", s, ss)) >= 0 ) -+ { -+ opt_rsb_pv = val; -+ opt_rsb_hvm = val; -+ } -+ -+ /* Xen's speculative sidechannel mitigation settings. */ -+ else if ( !strncmp(s, "bti-thunk=", 10) ) -+ { -+ s += 10; -+ -+ if ( !strncmp(s, "retpoline", ss - s) ) -+ opt_thunk = THUNK_RETPOLINE; -+ else if ( !strncmp(s, "lfence", ss - s) ) -+ opt_thunk = THUNK_LFENCE; -+ else if ( !strncmp(s, "jmp", ss - s) ) -+ opt_thunk = THUNK_JMP; -+ else -+ rc = -EINVAL; -+ } -+ else if ( (val = parse_boolean("ibrs", s, ss)) >= 0 ) -+ opt_ibrs = val; -+ else if ( (val = parse_boolean("ibpb", s, ss)) >= 0 ) -+ opt_ibpb = val; -+ else if ( (val = parse_boolean("ssbd", s, ss)) >= 0 ) -+ opt_ssbd = val; -+ else if ( (val = parse_boolean("eager-fpu", s, ss)) >= 0 ) -+ opt_eager_fpu = val; -+ else if ( (val = parse_boolean("l1d-flush", s, ss)) >= 0 ) -+ opt_l1d_flush = val; -+ else -+ rc = -EINVAL; -+ -+ s = ss + 1; -+ } while ( *ss ); -+ -+ return rc; -+} -+custom_param("spec-ctrl", parse_spec_ctrl); -+ -+int8_t __read_mostly opt_pv_l1tf = -1; -+ -+static __init int parse_pv_l1tf(const char *s) -+{ -+ const char *ss; -+ int val, rc = 0; -+ -+ /* Inhibit the defaults as an explicit choice has been given. */ -+ if ( opt_pv_l1tf == -1 ) -+ opt_pv_l1tf = 0; -+ -+ /* Interpret 'pv-l1tf' alone in its positive boolean form. */ -+ if ( *s == '\0' ) -+ opt_pv_l1tf = OPT_PV_L1TF_DOM0 | OPT_PV_L1TF_DOMU; -+ -+ do { -+ ss = strchr(s, ','); -+ if ( !ss ) -+ ss = strchr(s, '\0'); -+ -+ switch ( parse_bool(s, ss) ) -+ { -+ case 0: -+ opt_pv_l1tf = 0; -+ break; -+ -+ case 1: -+ opt_pv_l1tf = OPT_PV_L1TF_DOM0 | OPT_PV_L1TF_DOMU; -+ break; -+ -+ default: -+ if ( (val = parse_boolean("dom0", s, ss)) >= 0 ) -+ opt_pv_l1tf = ((opt_pv_l1tf & ~OPT_PV_L1TF_DOM0) | -+ (val ? OPT_PV_L1TF_DOM0 : 0)); -+ else if ( (val = parse_boolean("domu", s, ss)) >= 0 ) -+ opt_pv_l1tf = ((opt_pv_l1tf & ~OPT_PV_L1TF_DOMU) | -+ (val ? OPT_PV_L1TF_DOMU : 0)); -+ else -+ rc = -EINVAL; -+ break; -+ } -+ -+ s = ss + 1; -+ } while ( *ss ); -+ -+ return rc; -+} -+custom_param("pv-l1tf", parse_pv_l1tf); -+ -+static void __init print_details(enum ind_thunk thunk, uint64_t caps) - { - unsigned int _7d0 = 0, e8b = 0, tmp; -- uint64_t caps = 0; - - /* Collect diagnostics about available mitigations. */ - if ( boot_cpu_data.cpuid_level >= 7 ) - cpuid_count(7, 0, &tmp, &tmp, &tmp, &_7d0); - if ( boot_cpu_data.extended_cpuid_level >= 0x80000008 ) - cpuid(0x80000008, &tmp, &e8b, &tmp, &tmp); -- if ( _7d0 & cpufeat_mask(X86_FEATURE_ARCH_CAPS) ) -- rdmsrl(MSR_ARCH_CAPABILITIES, caps); - -- printk(XENLOG_DEBUG "Speculative mitigation facilities:\n"); -+ printk("Speculative mitigation facilities:\n"); - - /* Hardware features which pertain to speculative mitigations. */ -- printk(XENLOG_DEBUG " Hardware features:%s%s%s%s%s\n", -+ printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s\n", - (_7d0 & cpufeat_mask(X86_FEATURE_IBRSB)) ? " IBRS/IBPB" : "", - (_7d0 & cpufeat_mask(X86_FEATURE_STIBP)) ? " STIBP" : "", -+ (_7d0 & cpufeat_mask(X86_FEATURE_L1D_FLUSH)) ? " L1D_FLUSH" : "", -+ (_7d0 & cpufeat_mask(X86_FEATURE_SSBD)) ? " SSBD" : "", - (e8b & cpufeat_mask(X86_FEATURE_IBPB)) ? " IBPB" : "", - (caps & ARCH_CAPABILITIES_IBRS_ALL) ? " IBRS_ALL" : "", -- (caps & ARCH_CAPABILITIES_RDCL_NO) ? " RDCL_NO" : ""); -- -- /* Compiled-in support which pertains to BTI mitigations. */ -- if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) ) -- printk(XENLOG_DEBUG " Compiled-in support: INDIRECT_THUNK\n"); -- -- printk("BTI mitigations: Thunk %s, Others:%s%s%s%s\n", -+ (caps & ARCH_CAPABILITIES_RDCL_NO) ? " RDCL_NO" : "", -+ (caps & ARCH_CAPS_RSBA) ? " RSBA" : "", -+ (caps & ARCH_CAPS_SKIP_L1DFL) ? " SKIP_L1DFL": "", -+ (caps & ARCH_CAPS_SSB_NO) ? " SSB_NO" : ""); -+ -+ /* Compiled-in support which pertains to mitigations. */ -+ if ( IS_ENABLED(CONFIG_INDIRECT_THUNK) || IS_ENABLED(CONFIG_SHADOW_PAGING) ) -+ printk(" Compiled-in support:" -+#ifdef CONFIG_INDIRECT_THUNK -+ " INDIRECT_THUNK" -+#endif -+#ifdef CONFIG_SHADOW_PAGING -+ " SHADOW_PAGING" -+#endif -+ "\n"); -+ -+ /* Settings for Xen's protection, irrespective of guests. */ -+ printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s, Other:%s%s\n", - thunk == THUNK_NONE ? "N/A" : - thunk == THUNK_RETPOLINE ? "RETPOLINE" : - thunk == THUNK_LFENCE ? "LFENCE" : - thunk == THUNK_JMP ? "JMP" : "?", -- boot_cpu_has(X86_FEATURE_XEN_IBRS_SET) ? " IBRS+" : -- boot_cpu_has(X86_FEATURE_XEN_IBRS_CLEAR) ? " IBRS-" : "", -- opt_ibpb ? " IBPB" : "", -- boot_cpu_has(X86_FEATURE_RSB_NATIVE) ? " RSB_NATIVE" : "", -- boot_cpu_has(X86_FEATURE_RSB_VMEXIT) ? " RSB_VMEXIT" : ""); -- -- printk("XPTI: %s\n", -- boot_cpu_has(X86_FEATURE_NO_XPTI) ? "disabled" : "enabled"); -+ !boot_cpu_has(X86_FEATURE_IBRSB) ? "No" : -+ (default_xen_spec_ctrl & SPEC_CTRL_IBRS) ? "IBRS+" : "IBRS-", -+ !boot_cpu_has(X86_FEATURE_SSBD) ? "" : -+ (default_xen_spec_ctrl & SPEC_CTRL_SSBD) ? " SSBD+" : " SSBD-", -+ opt_ibpb ? " IBPB" : "", -+ opt_l1d_flush ? " L1D_FLUSH" : ""); -+ -+ /* L1TF diagnostics, printed if vulnerable or PV shadowing is in use. */ -+ if ( cpu_has_bug_l1tf || opt_pv_l1tf ) -+ printk(" L1TF: believed%s vulnerable, maxphysaddr L1D %u, CPUID %u" -+ ", Safe address %"PRIx64"\n", -+ cpu_has_bug_l1tf ? "" : " not", -+ l1d_maxphysaddr, paddr_bits, l1tf_safe_maddr); -+ -+ /* -+ * Alternatives blocks for protecting against and/or virtualising -+ * mitigation support for guests. -+ */ -+ printk(" Support for VMs: PV:%s%s%s%s, HVM:%s%s%s%s\n", -+ (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || -+ boot_cpu_has(X86_FEATURE_SC_RSB_PV) || -+ opt_eager_fpu) ? "" : " None", -+ boot_cpu_has(X86_FEATURE_SC_MSR_PV) ? " MSR_SPEC_CTRL" : "", -+ boot_cpu_has(X86_FEATURE_SC_RSB_PV) ? " RSB" : "", -+ opt_eager_fpu ? " EAGER_FPU" : "", -+ (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) || -+ boot_cpu_has(X86_FEATURE_SC_RSB_HVM) || -+ opt_eager_fpu) ? "" : " None", -+ boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ? " MSR_SPEC_CTRL" : "", -+ boot_cpu_has(X86_FEATURE_SC_RSB_HVM) ? " RSB" : "", -+ opt_eager_fpu ? " EAGER_FPU" : ""); -+ -+ printk(" XPTI (64-bit PV only): Dom0 %s, DomU %s\n", -+ opt_xpti & OPT_XPTI_DOM0 ? "enabled" : "disabled", -+ opt_xpti & OPT_XPTI_DOMU ? "enabled" : "disabled"); -+ -+ printk(" PV L1TF shadowing: Dom0 %s, DomU %s\n", -+ opt_pv_l1tf & OPT_PV_L1TF_DOM0 ? "enabled" : "disabled", -+ opt_pv_l1tf & OPT_PV_L1TF_DOMU ? "enabled" : "disabled"); - } - - /* Calculate whether Retpoline is known-safe on this CPU. */ --static bool __init retpoline_safe(void) -+static bool __init retpoline_safe(uint64_t caps) - { - unsigned int ucode_rev = this_cpu(ucode_cpu_info).cpu_sig.rev; - -@@ -135,6 +347,13 @@ static bool __init retpoline_safe(void) - boot_cpu_data.x86 != 6 ) - return false; - -+ /* -+ * RSBA may be set by a hypervisor to indicate that we may move to a -+ * processor which isn't retpoline-safe. -+ */ -+ if ( caps & ARCH_CAPS_RSBA ) -+ return false; -+ - switch ( boot_cpu_data.x86_model ) - { - case 0x17: /* Penryn */ -@@ -161,26 +380,337 @@ static bool __init retpoline_safe(void) - * versions. - */ - case 0x3d: /* Broadwell */ -- return ucode_rev >= 0x28; -+ return ucode_rev >= 0x2a; - case 0x47: /* Broadwell H */ -- return ucode_rev >= 0x1b; -+ return ucode_rev >= 0x1d; - case 0x4f: /* Broadwell EP/EX */ -- return ucode_rev >= 0xb000025; -+ return ucode_rev >= 0xb000021; - case 0x56: /* Broadwell D */ -- return false; /* TBD. */ -+ switch ( boot_cpu_data.x86_mask ) -+ { -+ case 2: return ucode_rev >= 0x15; -+ case 3: return ucode_rev >= 0x7000012; -+ case 4: return ucode_rev >= 0xf000011; -+ case 5: return ucode_rev >= 0xe000009; -+ default: -+ printk("Unrecognised CPU stepping %#x - assuming not reptpoline safe\n", -+ boot_cpu_data.x86_mask); -+ return false; -+ } -+ break; - - /* -- * Skylake and later processors are not retpoline-safe. -+ * Skylake, Kabylake and Cannonlake processors are not retpoline-safe. - */ -+ case 0x4e: -+ case 0x55: -+ case 0x5e: -+ case 0x66: -+ case 0x67: -+ case 0x8e: -+ case 0x9e: -+ return false; -+ - default: -+ printk("Unrecognised CPU model %#x - assuming not reptpoline safe\n", -+ boot_cpu_data.x86_model); - return false; - } - } - -+/* Calculate whether this CPU speculates past #NM */ -+static bool __init should_use_eager_fpu(void) -+{ -+ /* -+ * Assume all unrecognised processors are ok. This is only known to -+ * affect Intel Family 6 processors. -+ */ -+ if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || -+ boot_cpu_data.x86 != 6 ) -+ return false; -+ -+ switch ( boot_cpu_data.x86_model ) -+ { -+ /* -+ * Core processors since at least Nehalem are vulnerable. -+ */ -+ case 0x1e: /* Nehalem */ -+ case 0x1f: /* Auburndale / Havendale */ -+ case 0x1a: /* Nehalem EP */ -+ case 0x2e: /* Nehalem EX */ -+ case 0x25: /* Westmere */ -+ case 0x2c: /* Westmere EP */ -+ case 0x2f: /* Westmere EX */ -+ case 0x2a: /* SandyBridge */ -+ case 0x2d: /* SandyBridge EP/EX */ -+ case 0x3a: /* IvyBridge */ -+ case 0x3e: /* IvyBridge EP/EX */ -+ case 0x3c: /* Haswell */ -+ case 0x3f: /* Haswell EX/EP */ -+ case 0x45: /* Haswell D */ -+ case 0x46: /* Haswell H */ -+ case 0x3d: /* Broadwell */ -+ case 0x47: /* Broadwell H */ -+ case 0x4f: /* Broadwell EP/EX */ -+ case 0x56: /* Broadwell D */ -+ case 0x4e: /* Skylake M */ -+ case 0x55: /* Skylake X */ -+ case 0x5e: /* Skylake D */ -+ case 0x66: /* Cannonlake */ -+ case 0x67: /* Cannonlake? */ -+ case 0x8e: /* Kabylake M */ -+ case 0x9e: /* Kabylake D */ -+ return true; -+ -+ /* -+ * Atom processors are not vulnerable. -+ */ -+ case 0x1c: /* Pineview */ -+ case 0x26: /* Lincroft */ -+ case 0x27: /* Penwell */ -+ case 0x35: /* Cloverview */ -+ case 0x36: /* Cedarview */ -+ case 0x37: /* Baytrail / Valleyview (Silvermont) */ -+ case 0x4d: /* Avaton / Rangely (Silvermont) */ -+ case 0x4c: /* Cherrytrail / Brasswell */ -+ case 0x4a: /* Merrifield */ -+ case 0x5a: /* Moorefield */ -+ case 0x5c: /* Goldmont */ -+ case 0x5f: /* Denverton */ -+ case 0x7a: /* Gemini Lake */ -+ return false; -+ -+ /* -+ * Knights processors are not vulnerable. -+ */ -+ case 0x57: /* Knights Landing */ -+ case 0x85: /* Knights Mill */ -+ return false; -+ -+ default: -+ printk("Unrecognised CPU model %#x - assuming vulnerable to LazyFPU\n", -+ boot_cpu_data.x86_model); -+ return true; -+ } -+} -+ -+/* Calculate whether this CPU is vulnerable to L1TF. */ -+static __init void l1tf_calculations(uint64_t caps) -+{ -+ bool hit_default = false; -+ -+ l1d_maxphysaddr = paddr_bits; -+ -+ /* L1TF is only known to affect Intel Family 6 processors at this time. */ -+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && -+ boot_cpu_data.x86 == 6 ) -+ { -+ switch ( boot_cpu_data.x86_model ) -+ { -+ /* -+ * Core processors since at least Penryn are vulnerable. -+ */ -+ case 0x17: /* Penryn */ -+ case 0x1d: /* Dunnington */ -+ cpu_has_bug_l1tf = true; -+ break; -+ -+ case 0x1f: /* Auburndale / Havendale */ -+ case 0x1e: /* Nehalem */ -+ case 0x1a: /* Nehalem EP */ -+ case 0x2e: /* Nehalem EX */ -+ case 0x25: /* Westmere */ -+ case 0x2c: /* Westmere EP */ -+ case 0x2f: /* Westmere EX */ -+ cpu_has_bug_l1tf = true; -+ l1d_maxphysaddr = 44; -+ break; -+ -+ case 0x2a: /* SandyBridge */ -+ case 0x2d: /* SandyBridge EP/EX */ -+ case 0x3a: /* IvyBridge */ -+ case 0x3e: /* IvyBridge EP/EX */ -+ case 0x3c: /* Haswell */ -+ case 0x3f: /* Haswell EX/EP */ -+ case 0x45: /* Haswell D */ -+ case 0x46: /* Haswell H */ -+ case 0x3d: /* Broadwell */ -+ case 0x47: /* Broadwell H */ -+ case 0x4f: /* Broadwell EP/EX */ -+ case 0x56: /* Broadwell D */ -+ case 0x4e: /* Skylake M */ -+ case 0x55: /* Skylake X */ -+ case 0x5e: /* Skylake D */ -+ case 0x66: /* Cannonlake */ -+ case 0x67: /* Cannonlake? */ -+ case 0x8e: /* Kabylake M */ -+ case 0x9e: /* Kabylake D */ -+ cpu_has_bug_l1tf = true; -+ l1d_maxphysaddr = 46; -+ break; -+ -+ /* -+ * Atom processors are not vulnerable. -+ */ -+ case 0x1c: /* Pineview */ -+ case 0x26: /* Lincroft */ -+ case 0x27: /* Penwell */ -+ case 0x35: /* Cloverview */ -+ case 0x36: /* Cedarview */ -+ case 0x37: /* Baytrail / Valleyview (Silvermont) */ -+ case 0x4d: /* Avaton / Rangely (Silvermont) */ -+ case 0x4c: /* Cherrytrail / Brasswell */ -+ case 0x4a: /* Merrifield */ -+ case 0x5a: /* Moorefield */ -+ case 0x5c: /* Goldmont */ -+ case 0x5f: /* Denverton */ -+ case 0x7a: /* Gemini Lake */ -+ break; -+ -+ /* -+ * Knights processors are not vulnerable. -+ */ -+ case 0x57: /* Knights Landing */ -+ case 0x85: /* Knights Mill */ -+ break; -+ -+ default: -+ /* Defer printk() until we've accounted for RDCL_NO. */ -+ hit_default = true; -+ cpu_has_bug_l1tf = true; -+ break; -+ } -+ } -+ -+ /* Any processor advertising RDCL_NO should be not vulnerable to L1TF. */ -+ if ( caps & ARCH_CAPABILITIES_RDCL_NO ) -+ cpu_has_bug_l1tf = false; -+ -+ if ( cpu_has_bug_l1tf && hit_default ) -+ printk("Unrecognised CPU model %#x - assuming vulnerable to L1TF\n", -+ boot_cpu_data.x86_model); -+ -+ /* -+ * L1TF safe address heuristics. These apply to the real hardware we are -+ * running on, and are best-effort-only if Xen is virtualised. -+ * -+ * The address mask which the L1D cache uses, which might be wider than -+ * the CPUID-reported maxphysaddr. -+ */ -+ l1tf_addr_mask = ((1ul << l1d_maxphysaddr) - 1) & PAGE_MASK; -+ -+ /* -+ * To be safe, l1tf_safe_maddr must be above the highest cacheable entity -+ * in system physical address space. However, to preserve space for -+ * paged-out metadata, it should be as low as possible above the highest -+ * cacheable address, so as to require fewer high-order bits being set. -+ * -+ * These heuristics are based on some guesswork to improve the likelihood -+ * of safety in the common case, including Linux's L1TF mitigation of -+ * inverting all address bits in a non-present PTE. -+ * -+ * - If L1D is wider than CPUID (Nehalem and later mobile/desktop/low end -+ * server), setting any address bit beyond CPUID maxphysaddr guarantees -+ * to make the PTE safe. This case doesn't require all the high-order -+ * bits being set, and doesn't require any other source of information -+ * for safety. -+ * -+ * - If L1D is the same as CPUID (Pre-Nehalem, or high end server), we -+ * must sacrifice high order bits from the real address space for -+ * safety. Therefore, make a blind guess that there is nothing -+ * cacheable in the top quarter of physical address space. -+ * -+ * It is exceedingly unlikely for machines to be populated with this -+ * much RAM (likely 512G on pre-Nehalem, 16T on Nehalem/Westmere, 64T on -+ * Sandybridge and later) due to the sheer volume of DIMMs this would -+ * actually take. -+ * -+ * However, it is possible to find machines this large, so the "top -+ * quarter" guess is supplemented to push the limit higher if references -+ * to cacheable mappings (E820/SRAT/EFI/etc) are found above the top -+ * quarter boundary. -+ * -+ * Finally, this top quarter guess gives us a good chance of being safe -+ * when running virtualised (and the CPUID maxphysaddr hasn't been -+ * levelled for heterogeneous migration safety), where the safety -+ * consideration is still in terms of host details, but all E820/etc -+ * information is in terms of guest physical layout. -+ */ -+ l1tf_safe_maddr = max(l1tf_safe_maddr, ((l1d_maxphysaddr > paddr_bits) -+ ? (1ul << paddr_bits) -+ : (3ul << (paddr_bits - 2)))); -+} -+ -+int8_t __read_mostly opt_xpti = -1; -+ -+static __init void xpti_init_default(uint64_t caps) -+{ -+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD ) -+ caps = ARCH_CAPABILITIES_RDCL_NO; -+ -+ if ( caps & ARCH_CAPABILITIES_RDCL_NO ) -+ opt_xpti = 0; -+ else -+ opt_xpti = OPT_XPTI_DOM0 | OPT_XPTI_DOMU; -+} -+ -+static __init int parse_xpti(const char *s) -+{ -+ const char *ss; -+ int val, rc = 0; -+ -+ /* Inhibit the defaults as an explicit choice has been given. */ -+ if ( opt_xpti == -1 ) -+ opt_xpti = 0; -+ -+ /* Interpret 'xpti' alone in its positive boolean form. */ -+ if ( *s == '\0' ) -+ opt_xpti = OPT_XPTI_DOM0 | OPT_XPTI_DOMU; -+ -+ do { -+ ss = strchr(s, ','); -+ if ( !ss ) -+ ss = strchr(s, '\0'); -+ -+ switch ( parse_bool(s, ss) ) -+ { -+ case 0: -+ opt_xpti = 0; -+ break; -+ -+ case 1: -+ opt_xpti = OPT_XPTI_DOM0 | OPT_XPTI_DOMU; -+ break; -+ -+ default: -+ if ( !strcmp(s, "default") ) -+ opt_xpti = -1; -+ else if ( (val = parse_boolean("dom0", s, ss)) >= 0 ) -+ opt_xpti = (opt_xpti & ~OPT_XPTI_DOM0) | -+ (val ? OPT_XPTI_DOM0 : 0); -+ else if ( (val = parse_boolean("domu", s, ss)) >= 0 ) -+ opt_xpti = (opt_xpti & ~OPT_XPTI_DOMU) | -+ (val ? OPT_XPTI_DOMU : 0); -+ else -+ rc = -EINVAL; -+ break; -+ } -+ -+ s = ss + 1; -+ } while ( *ss ); -+ -+ return rc; -+} -+custom_param("xpti", parse_xpti); -+ - void __init init_speculation_mitigations(void) - { - enum ind_thunk thunk = THUNK_DEFAULT; -- bool ibrs = false; -+ bool use_spec_ctrl = false, ibrs = false; -+ uint64_t caps = 0; -+ -+ if ( boot_cpu_has(X86_FEATURE_ARCH_CAPS) ) -+ rdmsrl(MSR_ARCH_CAPABILITIES, caps); - - /* - * Has the user specified any custom BTI mitigations? If so, follow their -@@ -209,7 +739,7 @@ void __init init_speculation_mitigations(void) - * On Intel hardware, we'd like to use retpoline in preference to - * IBRS, but only if it is safe on this hardware. - */ -- else if ( retpoline_safe() ) -+ else if ( retpoline_safe(caps) ) - thunk = THUNK_RETPOLINE; - else if ( boot_cpu_has(X86_FEATURE_IBRSB) ) - ibrs = true; -@@ -246,21 +776,35 @@ void __init init_speculation_mitigations(void) - else if ( thunk == THUNK_JMP ) - setup_force_cpu_cap(X86_FEATURE_IND_THUNK_JMP); - -+ /* -+ * If we are on hardware supporting MSR_SPEC_CTRL, see about setting up -+ * the alternatives blocks so we can virtualise support for guests. -+ */ - if ( boot_cpu_has(X86_FEATURE_IBRSB) ) - { -- /* -- * Even if we've chosen to not have IBRS set in Xen context, we still -- * need the IBRS entry/exit logic to virtualise IBRS support for -- * guests. -- */ -- if ( ibrs ) -- setup_force_cpu_cap(X86_FEATURE_XEN_IBRS_SET); -- else -- setup_force_cpu_cap(X86_FEATURE_XEN_IBRS_CLEAR); -+ if ( opt_msr_sc_pv ) -+ { -+ use_spec_ctrl = true; -+ setup_force_cpu_cap(X86_FEATURE_SC_MSR_PV); -+ } -+ -+ if ( opt_msr_sc_hvm ) -+ { -+ use_spec_ctrl = true; -+ setup_force_cpu_cap(X86_FEATURE_SC_MSR_HVM); -+ } -+ -+ if ( use_spec_ctrl ) -+ default_spec_ctrl_flags |= SCF_ist_wrmsr; - -- default_bti_ist_info |= BTI_IST_WRMSR | ibrs; -+ if ( ibrs ) -+ default_xen_spec_ctrl |= SPEC_CTRL_IBRS; - } - -+ /* If we have SSBD available, see whether we should use it. */ -+ if ( boot_cpu_has(X86_FEATURE_SSBD) && opt_ssbd ) -+ default_xen_spec_ctrl |= SPEC_CTRL_SSBD; -+ - /* - * PV guests can poison the RSB to any virtual address from which - * they can execute a call instruction. This is necessarily outside -@@ -274,33 +818,123 @@ void __init init_speculation_mitigations(void) - * If a processors speculates to 32bit PV guest kernel mappings, it is - * speculating in 64bit supervisor mode, and can leak data. - */ -- if ( opt_rsb_native ) -+ if ( opt_rsb_pv ) - { -- setup_force_cpu_cap(X86_FEATURE_RSB_NATIVE); -- default_bti_ist_info |= BTI_IST_RSB; -+ setup_force_cpu_cap(X86_FEATURE_SC_RSB_PV); -+ default_spec_ctrl_flags |= SCF_ist_rsb; - } - - /* - * HVM guests can always poison the RSB to point at Xen supervisor - * mappings. - */ -- if ( opt_rsb_vmexit ) -- setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT); -+ if ( opt_rsb_hvm ) -+ setup_force_cpu_cap(X86_FEATURE_SC_RSB_HVM); - - /* Check we have hardware IBPB support before using it... */ - if ( !boot_cpu_has(X86_FEATURE_IBRSB) && !boot_cpu_has(X86_FEATURE_IBPB) ) - opt_ibpb = false; - -- /* (Re)init BSP state now that default_bti_ist_info has been calculated. */ -+ /* Check whether Eager FPU should be enabled by default. */ -+ if ( opt_eager_fpu == -1 ) -+ opt_eager_fpu = should_use_eager_fpu(); -+ -+ /* (Re)init BSP state now that default_spec_ctrl_flags has been calculated. */ - init_shadow_spec_ctrl_state(); - -- print_details(thunk); -+ /* If Xen is using any MSR_SPEC_CTRL settings, adjust the idle path. */ -+ if ( default_xen_spec_ctrl ) -+ setup_force_cpu_cap(X86_FEATURE_SC_MSR_IDLE); -+ -+ if ( opt_xpti == -1 ) -+ xpti_init_default(caps); -+ -+ if ( opt_xpti == 0 ) -+ setup_force_cpu_cap(X86_FEATURE_NO_XPTI); -+ else -+ setup_clear_cpu_cap(X86_FEATURE_NO_XPTI); -+ -+ l1tf_calculations(caps); -+ -+ /* -+ * By default, enable PV domU L1TF mitigations on all L1TF-vulnerable -+ * hardware, except when running in shim mode. -+ * -+ * In shim mode, SHADOW is expected to be compiled out, and a malicious -+ * guest kernel can only attack the shim Xen, not the host Xen. -+ */ -+ if ( opt_pv_l1tf == -1 ) -+ { -+ if ( pv_shim || !cpu_has_bug_l1tf ) -+ opt_pv_l1tf = 0; -+ else -+ opt_pv_l1tf = OPT_PV_L1TF_DOMU; -+ } -+ -+ /* -+ * By default, enable L1D_FLUSH on L1TF-vulnerable hardware, unless -+ * instructed to skip the flush on vmentry by our outer hypervisor. -+ */ -+ if ( !boot_cpu_has(X86_FEATURE_L1D_FLUSH) ) -+ opt_l1d_flush = 0; -+ else if ( opt_l1d_flush == -1 ) -+ opt_l1d_flush = cpu_has_bug_l1tf && !(caps & ARCH_CAPS_SKIP_L1DFL); -+ -+ /* -+ * We do not disable HT by default on affected hardware. -+ * -+ * Firstly, if the user intends to use exclusively PV, or HVM shadow -+ * guests, HT isn't a concern and should remain fully enabled. Secondly, -+ * safety for HVM HAP guests can be arranged by the toolstack with core -+ * parking, pinning or cpupool configurations, including mixed setups. -+ * -+ * However, if we are on affected hardware, with HT enabled, and the user -+ * hasn't explicitly chosen whether to use HT or not, nag them to do so. -+ */ -+ if ( opt_smt == -1 && cpu_has_bug_l1tf && !pv_shim && -+ boot_cpu_data.x86_num_siblings > 1 ) -+ warning_add( -+ "Booted on L1TF-vulnerable hardware with SMT/Hyperthreading\n" -+ "enabled. Please assess your configuration and choose an\n" -+ "explicit 'smt=<bool>' setting. See XSA-273.\n"); -+ -+ print_details(thunk, caps); -+ -+ /* -+ * If MSR_SPEC_CTRL is available, apply Xen's default setting and discard -+ * any firmware settings. For performance reasons, when safe to do so, we -+ * delay applying non-zero settings until after dom0 has been constructed. -+ * -+ * "when safe to do so" is based on whether we are virtualised. A native -+ * boot won't have any other code running in a position to mount an -+ * attack. -+ */ -+ if ( boot_cpu_has(X86_FEATURE_IBRSB) ) -+ { -+ bsp_delay_spec_ctrl = !cpu_has_hypervisor && default_xen_spec_ctrl; -+ -+ /* -+ * If delaying MSR_SPEC_CTRL setup, use the same mechanism as -+ * spec_ctrl_enter_idle(), by using a shadow value of zero. -+ */ -+ if ( bsp_delay_spec_ctrl ) -+ { -+ struct cpu_info *info = get_cpu_info(); -+ -+ info->shadow_spec_ctrl = 0; -+ barrier(); -+ info->spec_ctrl_flags |= SCF_use_shadow; -+ barrier(); -+ } -+ -+ wrmsrl(MSR_SPEC_CTRL, bsp_delay_spec_ctrl ? 0 : default_xen_spec_ctrl); -+ } - } - - static void __init __maybe_unused build_assertions(void) - { - /* The optimised assembly relies on this alias. */ -- BUILD_BUG_ON(BTI_IST_IBRS != SPEC_CTRL_IBRS); -+ BUILD_BUG_ON(SCF_use_shadow != 1); - } - - /* -diff --git a/xen/arch/x86/srat.c b/xen/arch/x86/srat.c -index 166eb44fe2..2d70b45909 100644 ---- a/xen/arch/x86/srat.c -+++ b/xen/arch/x86/srat.c -@@ -20,6 +20,7 @@ - #include <xen/pfn.h> - #include <asm/e820.h> - #include <asm/page.h> -+#include <asm/spec_ctrl.h> - - static struct acpi_table_slit *__read_mostly acpi_slit; - -@@ -284,6 +285,11 @@ acpi_numa_memory_affinity_init(const struct acpi_srat_mem_affinity *ma) - if (!(ma->flags & ACPI_SRAT_MEM_ENABLED)) - return; - -+ start = ma->base_address; -+ end = start + ma->length; -+ /* Supplement the heuristics in l1tf_calculations(). */ -+ l1tf_safe_maddr = max(l1tf_safe_maddr, ROUNDUP(end, PAGE_SIZE)); -+ - if (num_node_memblks >= NR_NODE_MEMBLKS) - { - dprintk(XENLOG_WARNING, -@@ -292,8 +298,6 @@ acpi_numa_memory_affinity_init(const struct acpi_srat_mem_affinity *ma) - return; - } - -- start = ma->base_address; -- end = start + ma->length; - pxm = ma->proximity_domain; - if (srat_rev < 2) - pxm &= 0xff; -diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c -index 6ba823ca69..e726eee974 100644 ---- a/xen/arch/x86/sysctl.c -+++ b/xen/arch/x86/sysctl.c -@@ -23,6 +23,7 @@ - #include <asm/hvm/hvm.h> - #include <asm/hvm/support.h> - #include <asm/processor.h> -+#include <asm/setup.h> - #include <asm/smp.h> - #include <asm/numa.h> - #include <xen/nodemask.h> -@@ -48,14 +49,27 @@ static void l3_cache_get(void *arg) - - long cpu_up_helper(void *data) - { -- int cpu = (unsigned long)data; -+ unsigned int cpu = (unsigned long)data; - int ret = cpu_up(cpu); -+ - if ( ret == -EBUSY ) - { - /* On EBUSY, flush RCU work and have one more go. */ - rcu_barrier(); - ret = cpu_up(cpu); - } -+ -+ if ( !ret && !opt_smt && -+ cpu_data[cpu].compute_unit_id == INVALID_CUID && -+ cpumask_weight(per_cpu(cpu_sibling_mask, cpu)) > 1 ) -+ { -+ ret = cpu_down_helper(data); -+ if ( ret ) -+ printk("Could not re-offline CPU%u (%d)\n", cpu, ret); -+ else -+ ret = -EPERM; -+ } -+ - return ret; - } - -diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c -index 906124331b..e8f85f716e 100644 ---- a/xen/arch/x86/traps.c -+++ b/xen/arch/x86/traps.c -@@ -96,8 +96,6 @@ string_param("nmi", opt_nmi); - DEFINE_PER_CPU(u64, efer); - static DEFINE_PER_CPU(unsigned long, last_extable_addr); - --DEFINE_PER_CPU_READ_MOSTLY(u32, ler_msr); -- - DEFINE_PER_CPU_READ_MOSTLY(struct desc_struct *, gdt_table); - DEFINE_PER_CPU_READ_MOSTLY(struct desc_struct *, compat_gdt_table); - -@@ -117,6 +115,9 @@ integer_param("debug_stack_lines", debug_stack_lines); - static bool opt_ler; - boolean_param("ler", opt_ler); - -+/* LastExceptionFromIP on this hardware. Zero if LER is not in use. */ -+unsigned int __read_mostly ler_msr; -+ - #define stack_words_per_line 4 - #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp) - -@@ -325,13 +326,13 @@ static void show_guest_stack(struct vcpu *v, const struct cpu_user_regs *regs) - /* - * Notes for get_stack_trace_bottom() and get_stack_dump_bottom() - * -- * Stack pages 0, 1 and 2: -+ * Stack pages 0 - 3: - * These are all 1-page IST stacks. Each of these stacks have an exception - * frame and saved register state at the top. The interesting bound for a - * trace is the word adjacent to this, while the bound for a dump is the - * very top, including the exception frame. - * -- * Stack pages 3, 4 and 5: -+ * Stack pages 4 and 5: - * None of these are particularly interesting. With MEMORY_GUARD, page 5 is - * explicitly not present, so attempting to dump or trace it is - * counterproductive. Without MEMORY_GUARD, it is possible for a call chain -@@ -352,12 +353,12 @@ unsigned long get_stack_trace_bottom(unsigned long sp) - { - switch ( get_stack_page(sp) ) - { -- case 0 ... 2: -+ case 0 ... 3: - return ROUNDUP(sp, PAGE_SIZE) - - offsetof(struct cpu_user_regs, es) - sizeof(unsigned long); - - #ifndef MEMORY_GUARD -- case 3 ... 5: -+ case 4 ... 5: - #endif - case 6 ... 7: - return ROUNDUP(sp, STACK_SIZE) - -@@ -372,11 +373,11 @@ unsigned long get_stack_dump_bottom(unsigned long sp) - { - switch ( get_stack_page(sp) ) - { -- case 0 ... 2: -+ case 0 ... 3: - return ROUNDUP(sp, PAGE_SIZE) - sizeof(unsigned long); - - #ifndef MEMORY_GUARD -- case 3 ... 5: -+ case 4 ... 5: - #endif - case 6 ... 7: - return ROUNDUP(sp, STACK_SIZE) - sizeof(unsigned long); -@@ -1722,7 +1723,21 @@ void do_device_not_available(struct cpu_user_regs *regs) - { - struct vcpu *curr = current; - -- BUG_ON(!guest_mode(regs)); -+ if ( !guest_mode(regs) ) -+ { -+ unsigned long fixup = search_exception_table(regs); -+ -+ gprintk(XENLOG_ERR, "#NM: %p [%ps] -> %p\n", -+ _p(regs->rip), _p(regs->rip), _p(fixup)); -+ /* -+ * We shouldn't be able to reach here, but for release builds have -+ * the recovery logic in place nevertheless. -+ */ -+ ASSERT_UNREACHABLE(); -+ BUG_ON(!fixup); -+ regs->rip = fixup; -+ return; -+ } - - vcpu_restore_fpu_lazy(curr); - -@@ -1748,26 +1763,51 @@ void write_efer(u64 val) - wrmsrl(MSR_EFER, val); - } - --static void ler_enable(void) --{ -- u64 debugctl; -- -- if ( !this_cpu(ler_msr) ) -- return; -- -- rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); -- wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl | IA32_DEBUGCTLMSR_LBR); --} -- - void do_debug(struct cpu_user_regs *regs) - { -+ unsigned long dr6; - struct vcpu *v = current; - -+ /* Stash dr6 as early as possible. */ -+ dr6 = read_debugreg(6); -+ - if ( debugger_trap_entry(TRAP_debug, regs) ) - return; - -+ /* -+ * At the time of writing (March 2018), on the subject of %dr6: -+ * -+ * The Intel manual says: -+ * Certain debug exceptions may clear bits 0-3. The remaining contents -+ * of the DR6 register are never cleared by the processor. To avoid -+ * confusion in identifying debug exceptions, debug handlers should -+ * clear the register (except bit 16, which they should set) before -+ * returning to the interrupted task. -+ * -+ * The AMD manual says: -+ * Bits 15:13 of the DR6 register are not cleared by the processor and -+ * must be cleared by software after the contents have been read. -+ * -+ * Some bits are reserved set, some are reserved clear, and some bits -+ * which were previously reserved set are reused and cleared by hardware. -+ * For future compatibility, reset to the default value, which will allow -+ * us to spot any bit being changed by hardware to its non-default value. -+ */ -+ write_debugreg(6, X86_DR6_DEFAULT); -+ -+ /* #DB automatically disabled LBR. Reinstate it if debugging Xen. */ -+ if ( cpu_has_xen_lbr ) -+ wrmsrl(MSR_IA32_DEBUGCTLMSR, IA32_DEBUGCTLMSR_LBR); -+ - if ( !guest_mode(regs) ) - { -+ /* -+ * !!! WARNING !!! -+ * -+ * %dr6 is mostly guest controlled at this point. Any decsions base -+ * on its value must be crosschecked with non-guest controlled state. -+ */ -+ - if ( regs->eflags & X86_EFLAGS_TF ) - { - /* In SYSENTER entry path we can't zap TF until EFLAGS is saved. */ -@@ -1776,7 +1816,7 @@ void do_debug(struct cpu_user_regs *regs) - { - if ( regs->rip == (unsigned long)sysenter_eflags_saved ) - regs->eflags &= ~X86_EFLAGS_TF; -- goto out; -+ return; - } - if ( !debugger_trap_fatal(TRAP_debug, regs) ) - { -@@ -1784,29 +1824,63 @@ void do_debug(struct cpu_user_regs *regs) - regs->eflags &= ~X86_EFLAGS_TF; - } - } -- else -+ -+ /* -+ * Check for fault conditions. General Detect, and instruction -+ * breakpoints are faults rather than traps, at which point attempting -+ * to ignore and continue will result in a livelock. -+ * -+ * However, on entering the #DB handler, hardware clears %dr7.gd for -+ * us (as confirmed by the earlier %dr6 accesses succeeding), meaning -+ * that a real General Detect exception is restartable. -+ * -+ * PV guests are not permitted to point %dr{0..3} at Xen linear -+ * addresses, and Instruction Breakpoints (being faults) don't get -+ * delayed by a MovSS shadow, so we should never encounter one in -+ * hypervisor context. -+ * -+ * If however we do, safety measures need to be enacted. Use a big -+ * hammer and clear all debug settings. -+ */ -+ if ( dr6 & (DR_TRAP3 | DR_TRAP2 | DR_TRAP1 | DR_TRAP0) ) - { -- /* -- * We ignore watchpoints when they trigger within Xen. This may -- * happen when a buffer is passed to us which previously had a -- * watchpoint set on it. No need to bump EIP; the only faulting -- * trap is an instruction breakpoint, which can't happen to us. -- */ -- WARN_ON(!search_exception_table(regs)); -+ unsigned int bp, dr7 = read_debugreg(7); -+ -+ for ( bp = 0; bp < 4; ++bp ) -+ { -+ if ( (dr6 & (1u << bp)) && /* Breakpoint triggered? */ -+ (dr7 & (3u << (bp * DR_ENABLE_SIZE))) && /* Enabled? */ -+ ((dr7 & (3u << ((bp * DR_CONTROL_SIZE) + /* Insn? */ -+ DR_CONTROL_SHIFT))) == DR_RW_EXECUTE) ) -+ { -+ ASSERT_UNREACHABLE(); -+ -+ printk(XENLOG_ERR -+ "Hit instruction breakpoint in Xen context\n"); -+ write_debugreg(7, 0); -+ break; -+ } -+ } - } -- goto out; -+ -+ /* -+ * Whatever caused this #DB should be restartable by this point. Note -+ * it and continue. Guests can trigger this in certain corner cases, -+ * so ensure the message is ratelimited. -+ */ -+ gprintk(XENLOG_WARNING, -+ "Hit #DB in Xen context: %04x:%p [%ps], stk %04x:%p, dr6 %lx\n", -+ regs->cs, _p(regs->rip), _p(regs->rip), -+ regs->ss, _p(regs->rsp), dr6); -+ -+ return; - } - - /* Save debug status register where guest OS can peek at it */ -- v->arch.debugreg[6] = read_debugreg(6); -+ v->arch.debugreg[6] |= (dr6 & ~X86_DR6_DEFAULT); -+ v->arch.debugreg[6] &= (dr6 | ~X86_DR6_DEFAULT); - -- ler_enable(); - pv_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC); -- return; -- -- out: -- ler_enable(); -- return; - } - - static void __init noinline __set_intr_gate(unsigned int n, -@@ -1850,38 +1924,46 @@ void load_TR(void) - : "=m" (old_gdt) : "rm" (TSS_ENTRY << 3), "m" (tss_gdt) : "memory" ); - } - --void percpu_traps_init(void) -+static unsigned int calc_ler_msr(void) - { -- subarch_percpu_traps_init(); -- -- if ( !opt_ler ) -- return; -- - switch ( boot_cpu_data.x86_vendor ) - { - case X86_VENDOR_INTEL: - switch ( boot_cpu_data.x86 ) - { - case 6: -- this_cpu(ler_msr) = MSR_IA32_LASTINTFROMIP; -- break; -+ return MSR_IA32_LASTINTFROMIP; -+ - case 15: -- this_cpu(ler_msr) = MSR_P4_LER_FROM_LIP; -- break; -+ return MSR_P4_LER_FROM_LIP; - } - break; -+ - case X86_VENDOR_AMD: - switch ( boot_cpu_data.x86 ) - { - case 6: - case 0xf ... 0x17: -- this_cpu(ler_msr) = MSR_IA32_LASTINTFROMIP; -- break; -+ return MSR_IA32_LASTINTFROMIP; - } - break; - } - -- ler_enable(); -+ return 0; -+} -+ -+void percpu_traps_init(void) -+{ -+ subarch_percpu_traps_init(); -+ -+ if ( !opt_ler ) -+ return; -+ -+ if ( !ler_msr && (ler_msr = calc_ler_msr()) ) -+ setup_force_cpu_cap(X86_FEATURE_XEN_LBR); -+ -+ if ( cpu_has_xen_lbr ) -+ wrmsrl(MSR_IA32_DEBUGCTLMSR, IA32_DEBUGCTLMSR_LBR); - } - - void __init init_idt_traps(void) -@@ -1917,6 +1999,7 @@ void __init init_idt_traps(void) - set_ist(&idt_table[TRAP_double_fault], IST_DF); - set_ist(&idt_table[TRAP_nmi], IST_NMI); - set_ist(&idt_table[TRAP_machine_check], IST_MCE); -+ set_ist(&idt_table[TRAP_debug], IST_DB); - - /* CPU0 uses the master IDT. */ - idt_tables[0] = idt_table; -@@ -1984,6 +2067,12 @@ void activate_debugregs(const struct vcpu *curr) - } - } - -+/* -+ * Used by hypercalls and the emulator. -+ * -ENODEV => #UD -+ * -EINVAL => #GP Invalid bit -+ * -EPERM => #GP Valid bit, but not permitted to use -+ */ - long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) - { - int i; -@@ -2015,7 +2104,17 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) - if ( v == curr ) - write_debugreg(3, value); - break; -+ -+ case 4: -+ if ( v->arch.pv_vcpu.ctrlreg[4] & X86_CR4_DE ) -+ return -ENODEV; -+ -+ /* Fallthrough */ - case 6: -+ /* The upper 32 bits are strictly reserved. */ -+ if ( value != (uint32_t)value ) -+ return -EINVAL; -+ - /* - * DR6: Bits 4-11,16-31 reserved (set to 1). - * Bit 12 reserved (set to 0). -@@ -2025,7 +2124,17 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) - if ( v == curr ) - write_debugreg(6, value); - break; -+ -+ case 5: -+ if ( v->arch.pv_vcpu.ctrlreg[4] & X86_CR4_DE ) -+ return -ENODEV; -+ -+ /* Fallthrough */ - case 7: -+ /* The upper 32 bits are strictly reserved. */ -+ if ( value != (uint32_t)value ) -+ return -EINVAL; -+ - /* - * DR7: Bit 10 reserved (set to 1). - * Bits 11-12,14-15 reserved (set to 0). -@@ -2038,6 +2147,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) - */ - if ( value & DR_GENERAL_DETECT ) - return -EPERM; -+ - /* DR7.{G,L}E = 0 => debugging disabled for this domain. */ - if ( value & DR7_ACTIVE_MASK ) - { -@@ -2066,11 +2176,15 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) - !(v->arch.debugreg[7] & DR7_ACTIVE_MASK) ) - activate_debugregs(v); - } -+ else -+ /* Zero the emulated controls if %dr7 isn't active. */ -+ v->arch.debugreg[5] = 0; -+ - if ( v == curr ) - write_debugreg(7, value); - break; - default: -- return -EINVAL; -+ return -ENODEV; - } - - v->arch.debugreg[reg] = value; -diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c -index 13478d4fc1..10c243a039 100644 ---- a/xen/arch/x86/x86_64/asm-offsets.c -+++ b/xen/arch/x86/x86_64/asm-offsets.c -@@ -142,8 +142,10 @@ void __dummy__(void) - OFFSET(CPUINFO_xen_cr3, struct cpu_info, xen_cr3); - OFFSET(CPUINFO_pv_cr3, struct cpu_info, pv_cr3); - OFFSET(CPUINFO_shadow_spec_ctrl, struct cpu_info, shadow_spec_ctrl); -- OFFSET(CPUINFO_use_shadow_spec_ctrl, struct cpu_info, use_shadow_spec_ctrl); -- OFFSET(CPUINFO_bti_ist_info, struct cpu_info, bti_ist_info); -+ OFFSET(CPUINFO_xen_spec_ctrl, struct cpu_info, xen_spec_ctrl); -+ OFFSET(CPUINFO_spec_ctrl_flags, struct cpu_info, spec_ctrl_flags); -+ OFFSET(CPUINFO_root_pgt_changed, struct cpu_info, root_pgt_changed); -+ OFFSET(CPUINFO_use_pv_cr3, struct cpu_info, use_pv_cr3); - DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info)); - BLANK(); - -diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S -index 75497bc292..1c4cd795d2 100644 ---- a/xen/arch/x86/x86_64/compat/entry.S -+++ b/xen/arch/x86/x86_64/compat/entry.S -@@ -39,6 +39,12 @@ ENTRY(compat_test_all_events) - leaq irq_stat+IRQSTAT_softirq_pending(%rip),%rcx - cmpl $0,(%rcx,%rax,1) - jne compat_process_softirqs -+ -+ /* Inject exception if pending. */ -+ lea VCPU_trap_bounce(%rbx), %rdx -+ testb $TBF_EXCEPTION, TRAPBOUNCE_flags(%rdx) -+ jnz .Lcompat_process_trapbounce -+ - testb $1,VCPU_mce_pending(%rbx) - jnz compat_process_mce - .Lcompat_test_guest_nmi: -@@ -68,15 +74,24 @@ compat_process_softirqs: - call do_softirq - jmp compat_test_all_events - -+ ALIGN -+/* %rbx: struct vcpu, %rdx: struct trap_bounce */ -+.Lcompat_process_trapbounce: -+ sti -+.Lcompat_bounce_exception: -+ call compat_create_bounce_frame -+ movb $0, TRAPBOUNCE_flags(%rdx) -+ jmp compat_test_all_events -+ - ALIGN - /* %rbx: struct vcpu */ - compat_process_mce: - testb $1 << VCPU_TRAP_MCE,VCPU_async_exception_mask(%rbx) - jnz .Lcompat_test_guest_nmi - sti -- movb $0,VCPU_mce_pending(%rbx) -- call set_guest_machinecheck_trapbounce -- testl %eax,%eax -+ movb $0, VCPU_mce_pending(%rbx) -+ call set_guest_machinecheck_trapbounce -+ test %al, %al - jz compat_test_all_events - movzbl VCPU_async_exception_mask(%rbx),%edx # save mask for the - movb %dl,VCPU_mce_old_mask(%rbx) # iret hypercall -@@ -88,11 +103,11 @@ compat_process_mce: - /* %rbx: struct vcpu */ - compat_process_nmi: - testb $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%rbx) -- jnz compat_test_guest_events -+ jnz compat_test_guest_events - sti -- movb $0,VCPU_nmi_pending(%rbx) -+ movb $0, VCPU_nmi_pending(%rbx) - call set_guest_nmi_trapbounce -- testl %eax,%eax -+ test %al, %al - jz compat_test_all_events - movzbl VCPU_async_exception_mask(%rbx),%edx # save mask for the - movb %dl,VCPU_nmi_old_mask(%rbx) # iret hypercall -@@ -151,7 +166,7 @@ ENTRY(compat_restore_all_guest) - mov VCPUMSR_spec_ctrl_raw(%rax), %eax - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_GUEST /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ -+ SPEC_CTRL_EXIT_TO_PV /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ - - RESTORE_ALL adj=8 compat=1 - .Lft0: iretq -@@ -189,15 +204,6 @@ ENTRY(cr4_pv32_restore) - xor %eax, %eax - ret - --/* %rdx: trap_bounce, %rbx: struct vcpu */ --ENTRY(compat_post_handle_exception) -- testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%rdx) -- jz compat_test_all_events --.Lcompat_bounce_exception: -- call compat_create_bounce_frame -- movb $0,TRAPBOUNCE_flags(%rdx) -- jmp compat_test_all_events -- - .section .text.entry, "ax", @progbits - - /* See lstar_enter for entry register state. */ -@@ -218,10 +224,9 @@ ENTRY(cstar_enter) - - GET_STACK_END(bx) - mov STACK_CPUINFO_FIELD(xen_cr3)(%rbx), %rcx -- neg %rcx -+ test %rcx, %rcx - jz .Lcstar_cr3_okay -- mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) -- neg %rcx -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) - mov %rcx, %cr3 - movq $0, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) - .Lcstar_cr3_okay: -diff --git a/xen/arch/x86/x86_64/compat/mm.c b/xen/arch/x86/x86_64/compat/mm.c -index c2aa6f2fdb..02bc75b91e 100644 ---- a/xen/arch/x86/x86_64/compat/mm.c -+++ b/xen/arch/x86/x86_64/compat/mm.c -@@ -163,19 +163,6 @@ int compat_arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) - return rc; - } - --int compat_update_va_mapping(unsigned int va, u32 lo, u32 hi, -- unsigned int flags) --{ -- return do_update_va_mapping(va, lo | ((u64)hi << 32), flags); --} -- --int compat_update_va_mapping_otherdomain(unsigned long va, u32 lo, u32 hi, -- unsigned long flags, -- domid_t domid) --{ -- return do_update_va_mapping_otherdomain(va, lo | ((u64)hi << 32), flags, domid); --} -- - DEFINE_XEN_GUEST_HANDLE(mmuext_op_compat_t); - - int compat_mmuext_op(XEN_GUEST_HANDLE_PARAM(void) arg, -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index bdd33e727f..c163c31a60 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -42,6 +42,12 @@ test_all_events: - leaq irq_stat+IRQSTAT_softirq_pending(%rip), %rcx - cmpl $0, (%rcx, %rax, 1) - jne process_softirqs -+ -+ /* Inject exception if pending. */ -+ lea VCPU_trap_bounce(%rbx), %rdx -+ testb $TBF_EXCEPTION, TRAPBOUNCE_flags(%rdx) -+ jnz .Lprocess_trapbounce -+ - cmpb $0, VCPU_mce_pending(%rbx) - jne process_mce - .Ltest_guest_nmi: -@@ -69,6 +75,15 @@ process_softirqs: - call do_softirq - jmp test_all_events - -+ ALIGN -+/* %rbx: struct vcpu, %rdx struct trap_bounce */ -+.Lprocess_trapbounce: -+ sti -+.Lbounce_exception: -+ call create_bounce_frame -+ movb $0, TRAPBOUNCE_flags(%rdx) -+ jmp test_all_events -+ - ALIGN - /* %rbx: struct vcpu */ - process_mce: -@@ -77,7 +92,7 @@ process_mce: - sti - movb $0, VCPU_mce_pending(%rbx) - call set_guest_machinecheck_trapbounce -- test %eax, %eax -+ test %al, %al - jz test_all_events - movzbl VCPU_async_exception_mask(%rbx), %edx # save mask for the - movb %dl, VCPU_mce_old_mask(%rbx) # iret hypercall -@@ -93,7 +108,7 @@ process_nmi: - sti - movb $0, VCPU_nmi_pending(%rbx) - call set_guest_nmi_trapbounce -- test %eax, %eax -+ test %al, %al - jz test_all_events - movzbl VCPU_async_exception_mask(%rbx), %edx # save mask for the - movb %dl, VCPU_nmi_old_mask(%rbx) # iret hypercall -@@ -149,11 +164,15 @@ restore_all_guest: - mov VCPU_cr3(%rbx), %r9 - GET_STACK_END(dx) - mov STACK_CPUINFO_FIELD(pv_cr3)(%rdx), %rdi -+ test %rdi, %rdi -+ jz .Lrag_keep_cr3 -+ mov %rdi, %rax -+ cmpb $0, STACK_CPUINFO_FIELD(root_pgt_changed)(%rdx) -+ je .Lrag_copy_done -+ movb $0, STACK_CPUINFO_FIELD(root_pgt_changed)(%rdx) - movabs $PADDR_MASK & PAGE_MASK, %rsi - movabs $DIRECTMAP_VIRT_START, %rcx -- mov %rdi, %rax - and %rsi, %rdi -- jz .Lrag_keep_cr3 - and %r9, %rsi - add %rcx, %rdi - add %rcx, %rsi -@@ -168,20 +187,17 @@ restore_all_guest: - sub $(ROOT_PAGETABLE_FIRST_XEN_SLOT - \ - ROOT_PAGETABLE_LAST_XEN_SLOT - 1) * 8, %rdi - rep movsq -- mov STACK_CPUINFO_FIELD(cr4)(%rdx), %rdi -+.Lrag_copy_done: - mov %r9, STACK_CPUINFO_FIELD(xen_cr3)(%rdx) -- mov %rdi, %rsi -- and $~X86_CR4_PGE, %rdi -- mov %rdi, %cr4 -+ movb $1, STACK_CPUINFO_FIELD(use_pv_cr3)(%rdx) - mov %rax, %cr3 -- mov %rsi, %cr4 - .Lrag_keep_cr3: - - /* Restore stashed SPEC_CTRL value. */ - mov %r15d, %eax - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -- SPEC_CTRL_EXIT_TO_GUEST /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ -+ SPEC_CTRL_EXIT_TO_PV /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */ - - RESTORE_ALL - testw $TRAP_syscall,4(%rsp) -@@ -222,20 +238,10 @@ restore_all_xen: - * case we return to late PV exit code (from an NMI or #MC). - */ - GET_STACK_END(bx) -- mov STACK_CPUINFO_FIELD(xen_cr3)(%rbx), %rdx -+ cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) -+UNLIKELY_START(ne, exit_cr3) - mov STACK_CPUINFO_FIELD(pv_cr3)(%rbx), %rax -- test %rdx, %rdx -- /* -- * Ideally the condition would be "nsz", but such doesn't exist, -- * so "g" will have to do. -- */ --UNLIKELY_START(g, exit_cr3) -- mov %cr4, %rdi -- mov %rdi, %rsi -- and $~X86_CR4_PGE, %rdi -- mov %rdi, %cr4 - mov %rax, %cr3 -- mov %rsi, %cr4 - UNLIKELY_END(exit_cr3) - - /* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */ -@@ -276,10 +282,9 @@ ENTRY(lstar_enter) - - GET_STACK_END(bx) - mov STACK_CPUINFO_FIELD(xen_cr3)(%rbx), %rcx -- neg %rcx -+ test %rcx, %rcx - jz .Llstar_cr3_okay -- mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) -- neg %rcx -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) - mov %rcx, %cr3 - movq $0, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) - .Llstar_cr3_okay: -@@ -313,10 +318,9 @@ GLOBAL(sysenter_eflags_saved) - /* PUSHF above has saved EFLAGS.IF clear (the caller had it set). */ - orl $X86_EFLAGS_IF, UREGS_eflags(%rsp) - mov STACK_CPUINFO_FIELD(xen_cr3)(%rbx), %rcx -- neg %rcx -+ test %rcx, %rcx - jz .Lsyse_cr3_okay -- mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) -- neg %rcx -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) - mov %rcx, %cr3 - movq $0, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) - .Lsyse_cr3_okay: -@@ -363,10 +367,9 @@ ENTRY(int80_direct_trap) - - GET_STACK_END(bx) - mov STACK_CPUINFO_FIELD(xen_cr3)(%rbx), %rcx -- neg %rcx -+ test %rcx, %rcx - jz .Lint80_cr3_okay -- mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) -- neg %rcx -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx) - mov %rcx, %cr3 - movq $0, STACK_CPUINFO_FIELD(xen_cr3)(%rbx) - .Lint80_cr3_okay: -@@ -553,24 +556,24 @@ ENTRY(common_interrupt) - /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ - - mov STACK_CPUINFO_FIELD(xen_cr3)(%r14), %rcx -+ mov STACK_CPUINFO_FIELD(use_pv_cr3)(%r14), %bl - mov %rcx, %r15 -- neg %rcx -+ test %rcx, %rcx - jz .Lintr_cr3_okay -- jns .Lintr_cr3_load -- mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%r14) -- neg %rcx --.Lintr_cr3_load: -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - mov %rcx, %cr3 - xor %ecx, %ecx - mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%r14) - testb $3, UREGS_cs(%rsp) - cmovnz %rcx, %r15 -+ cmovnz %rcx, %rbx - .Lintr_cr3_okay: - - CR4_PV32_RESTORE - movq %rsp,%rdi - callq do_IRQ - mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) -+ mov %bl, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - jmp ret_from_intr - - ENTRY(page_fault) -@@ -585,18 +588,17 @@ GLOBAL(handle_exception) - /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ - - mov STACK_CPUINFO_FIELD(xen_cr3)(%r14), %rcx -+ mov STACK_CPUINFO_FIELD(use_pv_cr3)(%r14), %r13b - mov %rcx, %r15 -- neg %rcx -+ test %rcx, %rcx - jz .Lxcpt_cr3_okay -- jns .Lxcpt_cr3_load -- mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%r14) -- neg %rcx --.Lxcpt_cr3_load: -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - mov %rcx, %cr3 - xor %ecx, %ecx - mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%r14) - testb $3, UREGS_cs(%rsp) - cmovnz %rcx, %r15 -+ cmovnz %rcx, %r13 - .Lxcpt_cr3_okay: - - handle_exception_saved: -@@ -665,17 +667,12 @@ handle_exception_saved: - mov (%rdx, %rax, 8), %rdx - INDIRECT_CALL %rdx - mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) -+ mov %r13b, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - testb $3,UREGS_cs(%rsp) - jz restore_all_xen -- leaq VCPU_trap_bounce(%rbx),%rdx - movq VCPU_domain(%rbx),%rax - testb $1,DOMAIN_is_32bit_pv(%rax) -- jnz compat_post_handle_exception -- testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%rdx) -- jz test_all_events --.Lbounce_exception: -- call create_bounce_frame -- movb $0,TRAPBOUNCE_flags(%rdx) -+ jnz compat_test_all_events - jmp test_all_events - - /* No special register assumptions. */ -@@ -698,6 +695,7 @@ exception_with_ints_disabled: - 1: movq UREGS_error_code(%rsp),%rax # ec/ev - movq %rax,UREGS_kernel_sizeof(%rsp) - mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) -+ mov %r13b, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - jmp restore_all_xen # return to fixup code - - /* No special register assumptions. */ -@@ -730,7 +728,7 @@ ENTRY(device_not_available) - ENTRY(debug) - pushq $0 - movl $TRAP_debug,4(%rsp) -- jmp handle_exception -+ jmp handle_ist_exception - - ENTRY(int3) - pushq $0 -@@ -785,10 +783,9 @@ ENTRY(double_fault) - mov STACK_CPUINFO_FIELD(xen_cr3)(%r14), %rbx - test %rbx, %rbx - jz .Ldblf_cr3_okay -- jns .Ldblf_cr3_load -- neg %rbx --.Ldblf_cr3_load: -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - mov %rbx, %cr3 -+ movq $0, STACK_CPUINFO_FIELD(xen_cr3)(%r14) - .Ldblf_cr3_okay: - - movq %rsp,%rdi -@@ -816,13 +813,11 @@ handle_ist_exception: - /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ - - mov STACK_CPUINFO_FIELD(xen_cr3)(%r14), %rcx -+ mov STACK_CPUINFO_FIELD(use_pv_cr3)(%r14), %bl - mov %rcx, %r15 -- neg %rcx -+ test %rcx, %rcx - jz .List_cr3_okay -- jns .List_cr3_load -- mov %rcx, STACK_CPUINFO_FIELD(xen_cr3)(%r14) -- neg %rcx --.List_cr3_load: -+ movb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - mov %rcx, %cr3 - movq $0, STACK_CPUINFO_FIELD(xen_cr3)(%r14) - .List_cr3_okay: -@@ -835,6 +830,7 @@ handle_ist_exception: - * and copy the context to stack bottom. - */ - xor %r15, %r15 -+ xor %ebx, %ebx - GET_CPUINFO_FIELD(guest_cpu_user_regs,di) - movq %rsp,%rsi - movl $UREGS_kernel_sizeof/8,%ecx -@@ -846,6 +842,7 @@ handle_ist_exception: - mov (%rdx, %rax, 8), %rdx - INDIRECT_CALL %rdx - mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) -+ mov %bl, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) - cmpb $TRAP_nmi,UREGS_entry_vector(%rsp) - jne ret_from_intr - -diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c -index 3652f5ff21..7e8c5de70d 100644 ---- a/xen/arch/x86/x86_64/traps.c -+++ b/xen/arch/x86/x86_64/traps.c -@@ -144,11 +144,12 @@ void show_registers(const struct cpu_user_regs *regs) - printk("CPU: %d\n", smp_processor_id()); - _show_registers(&fault_regs, fault_crs, context, v); - -- if ( this_cpu(ler_msr) && !guest_mode(regs) ) -+ if ( ler_msr && !guest_mode(regs) ) - { - u64 from, to; -- rdmsrl(this_cpu(ler_msr), from); -- rdmsrl(this_cpu(ler_msr) + 1, to); -+ -+ rdmsrl(ler_msr, from); -+ rdmsrl(ler_msr + 1, to); - printk("ler: %016lx -> %016lx\n", from, to); - } - } -diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c -index c7ba221d11..9125c67c9e 100644 ---- a/xen/arch/x86/x86_emulate.c -+++ b/xen/arch/x86/x86_emulate.c -@@ -14,6 +14,7 @@ - #include <asm/processor.h> /* current_cpu_info */ - #include <asm/xstate.h> - #include <asm/amd.h> /* cpu_has_amd_erratum() */ -+#include <asm/debugreg.h> - - /* Avoid namespace pollution. */ - #undef cmpxchg -@@ -41,3 +42,75 @@ - }) - - #include "x86_emulate/x86_emulate.c" -+ -+/* Called with NULL ctxt in hypercall context. */ -+int x86emul_read_dr(unsigned int reg, unsigned long *val, -+ struct x86_emulate_ctxt *ctxt) -+{ -+ struct vcpu *curr = current; -+ -+ /* HVM support requires a bit more plumbing before it will work. */ -+ ASSERT(is_pv_vcpu(curr)); -+ -+ switch ( reg ) -+ { -+ case 0 ... 3: -+ case 6: -+ *val = curr->arch.debugreg[reg]; -+ break; -+ -+ case 7: -+ *val = (curr->arch.debugreg[7] | -+ curr->arch.debugreg[5]); -+ break; -+ -+ case 4 ... 5: -+ if ( !(curr->arch.pv_vcpu.ctrlreg[4] & X86_CR4_DE) ) -+ { -+ *val = curr->arch.debugreg[reg + 2]; -+ break; -+ } -+ -+ /* Fallthrough */ -+ default: -+ if ( ctxt ) -+ x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt); -+ -+ return X86EMUL_EXCEPTION; -+ } -+ -+ return X86EMUL_OKAY; -+} -+ -+int x86emul_write_dr(unsigned int reg, unsigned long val, -+ struct x86_emulate_ctxt *ctxt) -+{ -+ struct vcpu *curr = current; -+ -+ /* HVM support requires a bit more plumbing before it will work. */ -+ ASSERT(is_pv_vcpu(curr)); -+ -+ switch ( set_debugreg(curr, reg, val) ) -+ { -+ case 0: -+ return X86EMUL_OKAY; -+ -+ case -ENODEV: -+ x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt); -+ return X86EMUL_EXCEPTION; -+ -+ default: -+ x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); -+ return X86EMUL_EXCEPTION; -+ } -+} -+ -+/* -+ * Local variables: -+ * mode: C -+ * c-file-style: "BSD" -+ * c-basic-offset: 4 -+ * tab-width: 4 -+ * indent-tabs-mode: nil -+ * End: -+ */ -diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h -index 0c8c80ad5a..9c2bb8157c 100644 ---- a/xen/arch/x86/x86_emulate/x86_emulate.h -+++ b/xen/arch/x86/x86_emulate/x86_emulate.h -@@ -662,6 +662,11 @@ static inline void x86_emulate_free_state(struct x86_emulate_state *state) {} - void x86_emulate_free_state(struct x86_emulate_state *state); - #endif - -+int x86emul_read_dr(unsigned int reg, unsigned long *val, -+ struct x86_emulate_ctxt *ctxt); -+int x86emul_write_dr(unsigned int reg, unsigned long val, -+ struct x86_emulate_ctxt *ctxt); -+ - #endif - - static inline void x86_emul_hw_exception( -diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c -index 845208c189..ebd464e83a 100644 ---- a/xen/arch/x86/xstate.c -+++ b/xen/arch/x86/xstate.c -@@ -670,12 +670,17 @@ static bool valid_xcr0(u64 xcr0) - return !(xcr0 & XSTATE_BNDREGS) == !(xcr0 & XSTATE_BNDCSR); - } - --int validate_xstate(u64 xcr0, u64 xcr0_accum, const struct xsave_hdr *hdr) -+int validate_xstate(const struct domain *d, uint64_t xcr0, uint64_t xcr0_accum, -+ const struct xsave_hdr *hdr) - { -+ const struct cpuid_policy *cp = d->arch.cpuid; -+ uint64_t xcr0_max = -+ ((uint64_t)cp->xstate.xcr0_high << 32) | cp->xstate.xcr0_low; - unsigned int i; - - if ( (hdr->xstate_bv & ~xcr0_accum) || - (xcr0 & ~xcr0_accum) || -+ (xcr0_accum & ~xcr0_max) || - !valid_xcr0(xcr0) || - !valid_xcr0(xcr0_accum) ) - return -EINVAL; -@@ -694,20 +699,40 @@ int validate_xstate(u64 xcr0, u64 xcr0_accum, const struct xsave_hdr *hdr) - int handle_xsetbv(u32 index, u64 new_bv) - { - struct vcpu *curr = current; -+ const struct cpuid_policy *cp = curr->domain->arch.cpuid; -+ uint64_t xcr0_max = -+ ((uint64_t)cp->xstate.xcr0_high << 32) | cp->xstate.xcr0_low; - u64 mask; - - if ( index != XCR_XFEATURE_ENABLED_MASK ) - return -EOPNOTSUPP; - -- if ( (new_bv & ~xfeature_mask) || !valid_xcr0(new_bv) ) -+ /* -+ * The CPUID logic shouldn't be able to hand out an XCR0 exceeding Xen's -+ * maximum features, but keep the check for robustness. -+ */ -+ if ( unlikely(xcr0_max & ~xfeature_mask) ) -+ { -+ gprintk(XENLOG_ERR, -+ "xcr0_max %016" PRIx64 " exceeds hardware max %016" PRIx64 "\n", -+ xcr0_max, xfeature_mask); -+ domain_crash(curr->domain); -+ -+ return -EINVAL; -+ } -+ -+ if ( (new_bv & ~xcr0_max) || !valid_xcr0(new_bv) ) - return -EINVAL; - -- /* XCR0.PKRU is disabled on PV mode. */ -- if ( is_pv_vcpu(curr) && (new_bv & XSTATE_PKRU) ) -- return -EOPNOTSUPP; -+ /* By this point, new_bv really should be accepted by hardware. */ -+ if ( unlikely(!set_xcr0(new_bv)) ) -+ { -+ gprintk(XENLOG_ERR, "new_bv %016" PRIx64 " rejected by hardware\n", -+ new_bv); -+ domain_crash(curr->domain); - -- if ( !set_xcr0(new_bv) ) - return -EFAULT; -+ } - - mask = new_bv & ~curr->arch.xcr0_accum; - curr->arch.xcr0 = new_bv; -diff --git a/xen/common/cpu.c b/xen/common/cpu.c -index 6350f150bd..653a56b840 100644 ---- a/xen/common/cpu.c -+++ b/xen/common/cpu.c -@@ -67,12 +67,17 @@ void __init register_cpu_notifier(struct notifier_block *nb) - spin_unlock(&cpu_add_remove_lock); - } - --static int take_cpu_down(void *unused) -+static void _take_cpu_down(void *unused) - { - void *hcpu = (void *)(long)smp_processor_id(); - int notifier_rc = notifier_call_chain(&cpu_chain, CPU_DYING, hcpu, NULL); - BUG_ON(notifier_rc != NOTIFY_DONE); - __cpu_disable(); -+} -+ -+static int take_cpu_down(void *arg) -+{ -+ _take_cpu_down(arg); - return 0; - } - -@@ -98,7 +103,9 @@ int cpu_down(unsigned int cpu) - goto fail; - } - -- if ( (err = stop_machine_run(take_cpu_down, NULL, cpu)) < 0 ) -+ if ( unlikely(system_state < SYS_STATE_active) ) -+ on_selected_cpus(cpumask_of(cpu), _take_cpu_down, NULL, true); -+ else if ( (err = stop_machine_run(take_cpu_down, NULL, cpu)) < 0 ) - goto fail; - - __cpu_die(cpu); -diff --git a/xen/common/cpupool.c b/xen/common/cpupool.c -index 999839444e..1e8edcbd57 100644 ---- a/xen/common/cpupool.c -+++ b/xen/common/cpupool.c -@@ -490,7 +490,7 @@ static int cpupool_cpu_add(unsigned int cpu) - cpumask_clear_cpu(cpu, &cpupool_locked_cpus); - cpumask_set_cpu(cpu, &cpupool_free_cpus); - -- if ( system_state == SYS_STATE_resume ) -+ if ( system_state == SYS_STATE_suspend || system_state == SYS_STATE_resume ) - { - struct cpupool **c; - -@@ -522,6 +522,7 @@ static int cpupool_cpu_add(unsigned int cpu) - * (or unplugging would have failed) and that is the default behavior - * anyway. - */ -+ per_cpu(cpupool, cpu) = NULL; - ret = cpupool_assign_cpu_locked(cpupool0, cpu); - } - out: -diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c -index 01d33004e0..f1d724bd06 100644 ---- a/xen/common/efi/boot.c -+++ b/xen/common/efi/boot.c -@@ -1304,6 +1304,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) - - #ifndef CONFIG_ARM /* TODO - runtime service support */ - -+#include <asm/spec_ctrl.h> -+ - static bool __initdata efi_map_uc; - - static int __init parse_efi_param(const char *s) -@@ -1419,6 +1421,16 @@ void __init efi_init_memory(void) - desc->PhysicalStart, desc->PhysicalStart + len - 1, - desc->Type, desc->Attribute); - -+ if ( (desc->Attribute & (EFI_MEMORY_WB | EFI_MEMORY_WT)) || -+ (efi_bs_revision >= EFI_REVISION(2, 5) && -+ (desc->Attribute & EFI_MEMORY_WP)) ) -+ { -+ /* Supplement the heuristics in l1tf_calculations(). */ -+ l1tf_safe_maddr = -+ max(l1tf_safe_maddr, -+ ROUNDUP(desc->PhysicalStart + len, PAGE_SIZE)); -+ } -+ - if ( !efi_enabled(EFI_RS) || - (!(desc->Attribute & EFI_MEMORY_RUNTIME) && - (!map_bs || -diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c -index c38f00a64b..9aa070e77c 100644 ---- a/xen/common/efi/runtime.c -+++ b/xen/common/efi/runtime.c -@@ -111,21 +111,23 @@ struct efi_rs_state efi_rs_enter(void) - asm volatile ( "lgdt %0" : : "m" (gdt_desc) ); - } - -- write_cr3(virt_to_maddr(efi_l4_pgtable)); -+ switch_cr3_cr4(virt_to_maddr(efi_l4_pgtable), read_cr4()); - - return state; - } - - void efi_rs_leave(struct efi_rs_state *state) - { -+ struct vcpu *curr = current; -+ - if ( !state->cr3 ) - return; -- write_cr3(state->cr3); -- if ( is_pv_vcpu(current) && !is_idle_vcpu(current) ) -+ switch_cr3_cr4(state->cr3, read_cr4()); -+ if ( is_pv_vcpu(curr) && !is_idle_vcpu(curr) ) - { - struct desc_ptr gdt_desc = { - .limit = LAST_RESERVED_GDT_BYTE, -- .base = GDT_VIRT_START(current) -+ .base = GDT_VIRT_START(curr) - }; - - asm volatile ( "lgdt %0" : : "m" (gdt_desc) ); -@@ -133,7 +135,7 @@ void efi_rs_leave(struct efi_rs_state *state) - irq_exit(); - efi_rs_on_cpu = NR_CPUS; - spin_unlock(&efi_rs_lock); -- stts(); -+ vcpu_restore_fpu_nonlazy(curr, true); - } - - bool efi_rs_using_pgtables(void) -diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c -index 7650e6d449..64f58fc815 100644 ---- a/xen/common/grant_table.c -+++ b/xen/common/grant_table.c -@@ -97,6 +97,45 @@ static unsigned int __read_mostly max_maptrack_frames = - DEFAULT_MAX_MAPTRACK_FRAMES; - integer_runtime_param("gnttab_max_maptrack_frames", max_maptrack_frames); - -+#ifndef GNTTAB_MAX_VERSION -+#define GNTTAB_MAX_VERSION 2 -+#endif -+ -+static unsigned int __read_mostly opt_gnttab_max_version = GNTTAB_MAX_VERSION; -+static bool __read_mostly opt_transitive_grants = true; -+ -+static int __init parse_gnttab(const char *s) -+{ -+ const char *ss, *e; -+ int val, rc = 0; -+ -+ do { -+ ss = strchr(s, ','); -+ if ( !ss ) -+ ss = strchr(s, '\0'); -+ -+ if ( !strncmp(s, "max-ver:", 8) || -+ !strncmp(s, "max_ver:", 8) ) /* Alias for original XSA-226 patch */ -+ { -+ long ver = simple_strtol(s + 8, &e, 10); -+ -+ if ( e == ss && ver >= 1 && ver <= 2 ) -+ opt_gnttab_max_version = ver; -+ else -+ rc = -EINVAL; -+ } -+ else if ( (val = parse_boolean("transitive", s, ss)) >= 0 ) -+ opt_transitive_grants = val; -+ else -+ rc = -EINVAL; -+ -+ s = ss + 1; -+ } while ( *ss ); -+ -+ return rc; -+} -+custom_param("gnttab", parse_gnttab); -+ - /* - * Note that the three values below are effectively part of the ABI, even if - * we don't need to make them a formal part of it: A guest suspended for -@@ -2725,7 +2764,8 @@ static int gnttab_copy_claim_buf(const struct gnttab_copy *op, - current->domain->domain_id, - buf->read_only, - &buf->frame, &buf->page, -- &buf->ptr.offset, &buf->len, true); -+ &buf->ptr.offset, &buf->len, -+ opt_transitive_grants); - if ( rc != GNTST_okay ) - goto out; - buf->ptr.u.ref = ptr->u.ref; -@@ -2927,6 +2967,10 @@ gnttab_set_version(XEN_GUEST_HANDLE_PARAM(gnttab_set_version_t) uop) - if ( op.version != 1 && op.version != 2 ) - goto out; - -+ res = -ENOSYS; -+ if ( op.version == 2 && opt_gnttab_max_version == 1 ) -+ goto out; /* Behave as before set_version was introduced. */ -+ - res = 0; - if ( gt->gt_version == op.version ) - goto out; -diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c -index 49b2a91751..6d6f2a0628 100644 ---- a/xen/common/page_alloc.c -+++ b/xen/common/page_alloc.c -@@ -1424,7 +1424,7 @@ static void free_heap_pages( - - page_list_del(predecessor, &heap(node, zone, order)); - -- /* Keep predecessor's first_dirty if it is already set. */ -+ /* Update predecessor's first_dirty if necessary. */ - if ( predecessor->u.free.first_dirty == INVALID_DIRTY_IDX && - pg->u.free.first_dirty != INVALID_DIRTY_IDX ) - predecessor->u.free.first_dirty = (1U << order) + -@@ -1445,6 +1445,12 @@ static void free_heap_pages( - - check_and_stop_scrub(successor); - -+ /* Update pg's first_dirty if necessary. */ -+ if ( pg->u.free.first_dirty == INVALID_DIRTY_IDX && -+ successor->u.free.first_dirty != INVALID_DIRTY_IDX ) -+ pg->u.free.first_dirty = (1U << order) + -+ successor->u.free.first_dirty; -+ - page_list_del(successor, &heap(node, zone, order)); - } - -diff --git a/xen/common/schedule.c b/xen/common/schedule.c -index b7884263f2..f21c3e5a64 100644 ---- a/xen/common/schedule.c -+++ b/xen/common/schedule.c -@@ -436,14 +436,9 @@ void sched_destroy_domain(struct domain *d) - cpupool_rm_domain(d); - } - --void vcpu_sleep_nosync(struct vcpu *v) -+void vcpu_sleep_nosync_locked(struct vcpu *v) - { -- unsigned long flags; -- spinlock_t *lock; -- -- TRACE_2D(TRC_SCHED_SLEEP, v->domain->domain_id, v->vcpu_id); -- -- lock = vcpu_schedule_lock_irqsave(v, &flags); -+ ASSERT(spin_is_locked(per_cpu(schedule_data,v->processor).schedule_lock)); - - if ( likely(!vcpu_runnable(v)) ) - { -@@ -452,6 +447,18 @@ void vcpu_sleep_nosync(struct vcpu *v) - - SCHED_OP(vcpu_scheduler(v), sleep, v); - } -+} -+ -+void vcpu_sleep_nosync(struct vcpu *v) -+{ -+ unsigned long flags; -+ spinlock_t *lock; -+ -+ TRACE_2D(TRC_SCHED_SLEEP, v->domain->domain_id, v->vcpu_id); -+ -+ lock = vcpu_schedule_lock_irqsave(v, &flags); -+ -+ vcpu_sleep_nosync_locked(v); - - vcpu_schedule_unlock_irqrestore(lock, flags, v); - } -@@ -567,13 +574,54 @@ static void vcpu_move_nosched(struct vcpu *v, unsigned int new_cpu) - sched_move_irqs(v); - } - --static void vcpu_migrate(struct vcpu *v) -+/* -+ * Initiating migration -+ * -+ * In order to migrate, we need the vcpu in question to have stopped -+ * running and had SCHED_OP(sleep) called (to take it off any -+ * runqueues, for instance); and if it is currently running, it needs -+ * to be scheduled out. Finally, we need to hold the scheduling locks -+ * for both the processor we're migrating from, and the processor -+ * we're migrating to. -+ * -+ * In order to avoid deadlock while satisfying the final requirement, -+ * we must release any scheduling lock we hold, then try to grab both -+ * locks we want, then double-check to make sure that what we started -+ * to do hasn't been changed in the mean time. -+ * -+ * These steps are encapsulated in the following two functions; they -+ * should be called like this: -+ * -+ * lock = vcpu_schedule_lock_irq(v); -+ * vcpu_migrate_start(v); -+ * vcpu_schedule_unlock_irq(lock, v) -+ * vcpu_migrate_finish(v); -+ * -+ * vcpu_migrate_finish() will do the work now if it can, or simply -+ * return if it can't (because v is still running); in that case -+ * vcpu_migrate_finish() will be called by context_saved(). -+ */ -+void vcpu_migrate_start(struct vcpu *v) -+{ -+ set_bit(_VPF_migrating, &v->pause_flags); -+ vcpu_sleep_nosync_locked(v); -+} -+ -+static void vcpu_migrate_finish(struct vcpu *v) - { - unsigned long flags; - unsigned int old_cpu, new_cpu; - spinlock_t *old_lock, *new_lock; - bool_t pick_called = 0; - -+ /* -+ * If the vcpu is currently running, this will be handled by -+ * context_saved(); and in any case, if the bit is cleared, then -+ * someone else has already done the work so we don't need to. -+ */ -+ if ( v->is_running || !test_bit(_VPF_migrating, &v->pause_flags) ) -+ return; -+ - old_cpu = new_cpu = v->processor; - for ( ; ; ) - { -@@ -653,14 +701,11 @@ void vcpu_force_reschedule(struct vcpu *v) - spinlock_t *lock = vcpu_schedule_lock_irq(v); - - if ( v->is_running ) -- set_bit(_VPF_migrating, &v->pause_flags); -+ vcpu_migrate_start(v); -+ - vcpu_schedule_unlock_irq(lock, v); - -- if ( v->pause_flags & VPF_migrating ) -- { -- vcpu_sleep_nosync(v); -- vcpu_migrate(v); -- } -+ vcpu_migrate_finish(v); - } - - void restore_vcpu_affinity(struct domain *d) -@@ -812,10 +857,10 @@ int cpu_disable_scheduler(unsigned int cpu) - * * the scheduler will always fine a suitable solution, or - * things would have failed before getting in here. - */ -- set_bit(_VPF_migrating, &v->pause_flags); -+ vcpu_migrate_start(v); - vcpu_schedule_unlock_irqrestore(lock, flags, v); -- vcpu_sleep_nosync(v); -- vcpu_migrate(v); -+ -+ vcpu_migrate_finish(v); - - /* - * The only caveat, in this case, is that if a vcpu active in -@@ -849,18 +894,14 @@ static int vcpu_set_affinity( - * Always ask the scheduler to re-evaluate placement - * when changing the affinity. - */ -- set_bit(_VPF_migrating, &v->pause_flags); -+ vcpu_migrate_start(v); - } - - vcpu_schedule_unlock_irq(lock, v); - - domain_update_node_affinity(v->domain); - -- if ( v->pause_flags & VPF_migrating ) -- { -- vcpu_sleep_nosync(v); -- vcpu_migrate(v); -- } -+ vcpu_migrate_finish(v); - - return ret; - } -@@ -1088,7 +1129,6 @@ int vcpu_pin_override(struct vcpu *v, int cpu) - { - cpumask_copy(v->cpu_hard_affinity, v->cpu_hard_affinity_saved); - v->affinity_broken = 0; -- set_bit(_VPF_migrating, &v->pause_flags); - ret = 0; - } - } -@@ -1101,20 +1141,18 @@ int vcpu_pin_override(struct vcpu *v, int cpu) - cpumask_copy(v->cpu_hard_affinity_saved, v->cpu_hard_affinity); - v->affinity_broken = 1; - cpumask_copy(v->cpu_hard_affinity, cpumask_of(cpu)); -- set_bit(_VPF_migrating, &v->pause_flags); - ret = 0; - } - } - -+ if ( ret == 0 ) -+ vcpu_migrate_start(v); -+ - vcpu_schedule_unlock_irq(lock, v); - - domain_update_node_affinity(v->domain); - -- if ( v->pause_flags & VPF_migrating ) -- { -- vcpu_sleep_nosync(v); -- vcpu_migrate(v); -- } -+ vcpu_migrate_finish(v); - - return ret; - } -@@ -1501,8 +1539,7 @@ void context_saved(struct vcpu *prev) - - SCHED_OP(vcpu_scheduler(prev), context_saved, prev); - -- if ( unlikely(prev->pause_flags & VPF_migrating) ) -- vcpu_migrate(prev); -+ vcpu_migrate_finish(prev); - } - - /* The scheduler timer: force a run through the scheduler */ -diff --git a/xen/common/tasklet.c b/xen/common/tasklet.c -index 0f0a6f8365..d4fea3151c 100644 ---- a/xen/common/tasklet.c -+++ b/xen/common/tasklet.c -@@ -156,6 +156,10 @@ void tasklet_kill(struct tasklet *t) - - spin_lock_irqsave(&tasklet_lock, flags); - -+ /* Cope with uninitialised tasklets. */ -+ if ( list_head_is_null(&t->list) ) -+ goto unlock; -+ - if ( !list_empty(&t->list) ) - { - BUG_ON(t->is_dead || t->is_running || (t->scheduled_on < 0)); -@@ -172,6 +176,7 @@ void tasklet_kill(struct tasklet *t) - spin_lock_irqsave(&tasklet_lock, flags); - } - -+ unlock: - spin_unlock_irqrestore(&tasklet_lock, flags); - } - -diff --git a/xen/include/asm-arm/arm32/system.h b/xen/include/asm-arm/arm32/system.h -index c617b40438..ab57abfbc5 100644 ---- a/xen/include/asm-arm/arm32/system.h -+++ b/xen/include/asm-arm/arm32/system.h -@@ -48,6 +48,24 @@ static inline int local_fiq_is_enabled(void) - return !(flags & PSR_FIQ_MASK); - } - -+#define CSDB ".inst 0xe320f014" -+ -+static inline unsigned long array_index_mask_nospec(unsigned long idx, -+ unsigned long sz) -+{ -+ unsigned long mask; -+ -+ asm volatile( "cmp %1, %2\n" -+ "sbc %0, %1, %1\n" -+ CSDB -+ : "=r" (mask) -+ : "r" (idx), "Ir" (sz) -+ : "cc" ); -+ -+ return mask; -+} -+#define array_index_mask_nospec array_index_mask_nospec -+ - #endif - /* - * Local variables: -diff --git a/xen/include/asm-arm/arm64/system.h b/xen/include/asm-arm/arm64/system.h -index 2e2ee212a1..2e36573ac6 100644 ---- a/xen/include/asm-arm/arm64/system.h -+++ b/xen/include/asm-arm/arm64/system.h -@@ -58,6 +58,28 @@ static inline int local_fiq_is_enabled(void) - return !(flags & PSR_FIQ_MASK); - } - -+#define csdb() asm volatile ( "hint #20" : : : "memory" ) -+ -+/* -+ * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz -+ * and 0 otherwise. -+ */ -+static inline unsigned long array_index_mask_nospec(unsigned long idx, -+ unsigned long sz) -+{ -+ unsigned long mask; -+ -+ asm volatile ( "cmp %1, %2\n" -+ "sbc %0, xzr, xzr\n" -+ : "=r" (mask) -+ : "r" (idx), "Ir" (sz) -+ : "cc" ); -+ csdb(); -+ -+ return mask; -+} -+#define array_index_mask_nospec array_index_mask_nospec -+ - #endif - /* - * Local variables: -diff --git a/xen/include/asm-arm/grant_table.h b/xen/include/asm-arm/grant_table.h -index 5b8994cbd5..619721f121 100644 ---- a/xen/include/asm-arm/grant_table.h -+++ b/xen/include/asm-arm/grant_table.h -@@ -7,6 +7,7 @@ - #include <xen/sched.h> - - #define INITIAL_NR_GRANT_FRAMES 1U -+#define GNTTAB_MAX_VERSION 1 - - struct grant_table_arch { - gfn_t *shared_gfn; -diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h -index 62465b20c7..ff6f969e74 100644 ---- a/xen/include/asm-x86/cpufeature.h -+++ b/xen/include/asm-x86/cpufeature.h -@@ -90,6 +90,7 @@ - #define cpu_has_avx2 boot_cpu_has(X86_FEATURE_AVX2) - #define cpu_has_smep boot_cpu_has(X86_FEATURE_SMEP) - #define cpu_has_bmi2 boot_cpu_has(X86_FEATURE_BMI2) -+#define cpu_has_invpcid boot_cpu_has(X86_FEATURE_INVPCID) - #define cpu_has_rtm boot_cpu_has(X86_FEATURE_RTM) - #define cpu_has_fpu_sel (!boot_cpu_has(X86_FEATURE_NO_FPU_SEL)) - #define cpu_has_mpx boot_cpu_has(X86_FEATURE_MPX) -@@ -106,6 +107,7 @@ - #define cpu_has_aperfmperf boot_cpu_has(X86_FEATURE_APERFMPERF) - #define cpu_has_lfence_dispatch boot_cpu_has(X86_FEATURE_LFENCE_DISPATCH) - #define cpu_has_no_xpti boot_cpu_has(X86_FEATURE_NO_XPTI) -+#define cpu_has_xen_lbr boot_cpu_has(X86_FEATURE_XEN_LBR) - - enum _cache_type { - CACHE_TYPE_NULL = 0, -diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h -index c9b1a48807..8e5cc53dde 100644 ---- a/xen/include/asm-x86/cpufeatures.h -+++ b/xen/include/asm-x86/cpufeatures.h -@@ -26,8 +26,10 @@ XEN_CPUFEATURE(LFENCE_DISPATCH, (FSCAPINTS+0)*32+12) /* lfence set as Dispatch S - XEN_CPUFEATURE(IND_THUNK_LFENCE,(FSCAPINTS+0)*32+13) /* Use IND_THUNK_LFENCE */ - XEN_CPUFEATURE(IND_THUNK_JMP, (FSCAPINTS+0)*32+14) /* Use IND_THUNK_JMP */ - XEN_CPUFEATURE(XEN_IBPB, (FSCAPINTS+0)*32+15) /* IBRSB || IBPB */ --XEN_CPUFEATURE(XEN_IBRS_SET, (FSCAPINTS+0)*32+16) /* IBRSB && IRBS set in Xen */ --XEN_CPUFEATURE(XEN_IBRS_CLEAR, (FSCAPINTS+0)*32+17) /* IBRSB && IBRS clear in Xen */ --XEN_CPUFEATURE(RSB_NATIVE, (FSCAPINTS+0)*32+18) /* RSB overwrite needed for native */ --XEN_CPUFEATURE(RSB_VMEXIT, (FSCAPINTS+0)*32+19) /* RSB overwrite needed for vmexit */ -+XEN_CPUFEATURE(SC_MSR_PV, (FSCAPINTS+0)*32+16) /* MSR_SPEC_CTRL used by Xen for PV */ -+XEN_CPUFEATURE(SC_MSR_HVM, (FSCAPINTS+0)*32+17) /* MSR_SPEC_CTRL used by Xen for HVM */ -+XEN_CPUFEATURE(SC_RSB_PV, (FSCAPINTS+0)*32+18) /* RSB overwrite needed for PV */ -+XEN_CPUFEATURE(SC_RSB_HVM, (FSCAPINTS+0)*32+19) /* RSB overwrite needed for HVM */ - XEN_CPUFEATURE(NO_XPTI, (FSCAPINTS+0)*32+20) /* XPTI mitigation not in use */ -+XEN_CPUFEATURE(SC_MSR_IDLE, (FSCAPINTS+0)*32+21) /* (SC_MSR_PV || SC_MSR_HVM) && default_xen_spec_ctrl */ -+XEN_CPUFEATURE(XEN_LBR, (FSCAPINTS+0)*32+22) /* Xen uses MSR_DEBUGCTL.LBR */ -diff --git a/xen/include/asm-x86/current.h b/xen/include/asm-x86/current.h -index 4678a0fcf5..9a137a1311 100644 ---- a/xen/include/asm-x86/current.h -+++ b/xen/include/asm-x86/current.h -@@ -44,20 +44,33 @@ struct cpu_info { - /* - * Of the two following fields the latter is being set to the CR3 value - * to be used on the given pCPU for loading whenever 64-bit PV guest -- * context is being entered. The value never changes once set. -+ * context is being entered. A value of zero indicates no setting of CR3 -+ * is to be performed. - * The former is the value to restore when re-entering Xen, if any. IOW -- * its value being zero means there's nothing to restore. However, its -- * value can also be negative, indicating to the exit-to-Xen code that -- * restoring is not necessary, but allowing any nested entry code paths -- * to still know the value to put back into CR3. -+ * its value being zero means there's nothing to restore. - */ - unsigned long xen_cr3; - unsigned long pv_cr3; - - /* See asm-x86/spec_ctrl_asm.h for usage. */ - unsigned int shadow_spec_ctrl; -- bool use_shadow_spec_ctrl; -- uint8_t bti_ist_info; -+ uint8_t xen_spec_ctrl; -+ uint8_t spec_ctrl_flags; -+ -+ /* -+ * The following field controls copying of the L4 page table of 64-bit -+ * PV guests to the per-cpu root page table on entering the guest context. -+ * If set the L4 page table is being copied to the root page table and -+ * the field will be reset. -+ */ -+ bool root_pgt_changed; -+ -+ /* -+ * use_pv_cr3 is set in case the value of pv_cr3 is to be written into -+ * CR3 when returning from an interrupt. The main use is when returning -+ * from a NMI or MCE to hypervisor code where pv_cr3 was active. -+ */ -+ bool use_pv_cr3; - - unsigned long __pad; - /* get_stack_bottom() must be 16-byte aligned */ -diff --git a/xen/include/asm-x86/debugreg.h b/xen/include/asm-x86/debugreg.h -index c57914efc6..b3b10eaf40 100644 ---- a/xen/include/asm-x86/debugreg.h -+++ b/xen/include/asm-x86/debugreg.h -@@ -24,6 +24,8 @@ - #define DR_STATUS_RESERVED_ZERO (~0xffffeffful) /* Reserved, read as zero */ - #define DR_STATUS_RESERVED_ONE 0xffff0ff0ul /* Reserved, read as one */ - -+#define X86_DR6_DEFAULT 0xffff0ff0ul /* Default %dr6 value. */ -+ - /* Now define a bunch of things for manipulating the control register. - The top two bytes of the control register consist of 4 fields of 4 - bits - each field corresponds to one of the four debug registers, -diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h -index 4679d5477d..0fbd36bf48 100644 ---- a/xen/include/asm-x86/domain.h -+++ b/xen/include/asm-x86/domain.h -@@ -121,6 +121,11 @@ struct shadow_domain { - - /* Has this domain ever used HVMOP_pagetable_dying? */ - bool_t pagetable_dying_op; -+ -+#ifdef CONFIG_PV -+ /* PV L1 Terminal Fault mitigation. */ -+ struct tasklet pv_l1tf_tasklet; -+#endif /* CONFIG_PV */ - #endif - }; - -@@ -253,6 +258,13 @@ struct pv_domain - - atomic_t nr_l4_pages; - -+ /* XPTI active? */ -+ bool xpti; -+ /* Use PCID feature? */ -+ bool pcid; -+ /* Mitigate L1TF with shadow/crashing? */ -+ bool check_l1tf; -+ - /* map_domain_page() mapping cache. */ - struct mapcache_domain mapcache; - -@@ -564,6 +576,9 @@ struct arch_vcpu - * and thus should be saved/restored. */ - bool_t nonlazy_xstate_used; - -+ /* Restore all FPU state (lazy and non-lazy state) on context switch? */ -+ bool fully_eager_fpu; -+ - /* - * The SMAP check policy when updating runstate_guest(v) and the - * secondary system time. -@@ -612,18 +627,12 @@ void vcpu_show_registers(const struct vcpu *); - unsigned long pv_guest_cr4_fixup(const struct vcpu *, unsigned long guest_cr4); - - /* Convert between guest-visible and real CR4 values. */ --#define pv_guest_cr4_to_real_cr4(v) \ -- (((v)->arch.pv_vcpu.ctrlreg[4] \ -- | (mmu_cr4_features \ -- & (X86_CR4_PGE | X86_CR4_PSE | X86_CR4_SMEP | \ -- X86_CR4_SMAP | X86_CR4_OSXSAVE | \ -- X86_CR4_FSGSBASE)) \ -- | ((v)->domain->arch.vtsc ? X86_CR4_TSD : 0)) \ -- & ~X86_CR4_DE) -+unsigned long pv_guest_cr4_to_real_cr4(const struct vcpu *v); -+ - #define real_cr4_to_pv_guest_cr4(c) \ - ((c) & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_TSD | \ - X86_CR4_OSXSAVE | X86_CR4_SMEP | \ -- X86_CR4_FSGSBASE | X86_CR4_SMAP)) -+ X86_CR4_FSGSBASE | X86_CR4_SMAP | X86_CR4_PCIDE)) - - #define domain_max_vcpus(d) (is_hvm_domain(d) ? HVM_MAX_VCPUS : MAX_VIRT_CPUS) - -diff --git a/xen/include/asm-x86/flushtlb.h b/xen/include/asm-x86/flushtlb.h -index 413db692e1..4a930448da 100644 ---- a/xen/include/asm-x86/flushtlb.h -+++ b/xen/include/asm-x86/flushtlb.h -@@ -84,7 +84,7 @@ static inline unsigned long read_cr3(void) - } - - /* Write pagetable base and implicitly tick the tlbflush clock. */ --void write_cr3(unsigned long cr3); -+void switch_cr3_cr4(unsigned long cr3, unsigned long cr4); - - /* flush_* flag fields: */ - /* -@@ -101,6 +101,8 @@ void write_cr3(unsigned long cr3); - #define FLUSH_CACHE 0x400 - /* VA for the flush has a valid mapping */ - #define FLUSH_VA_VALID 0x800 -+ /* Flush the per-cpu root page table */ -+#define FLUSH_ROOT_PGTBL 0x2000 - - /* Flush local TLBs/caches. */ - unsigned int flush_area_local(const void *va, unsigned int flags); -@@ -132,6 +134,12 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags); - #define flush_tlb_one_all(v) \ - flush_tlb_one_mask(&cpu_online_map, v) - -+#define flush_root_pgtbl_domain(d) \ -+{ \ -+ if ( is_pv_domain(d) && (d)->arch.pv_domain.xpti ) \ -+ flush_mask((d)->domain_dirty_cpumask, FLUSH_ROOT_PGTBL); \ -+} -+ - static inline void flush_page_to_ram(unsigned long mfn, bool sync_icache) {} - static inline int invalidate_dcache_va_range(const void *p, - unsigned long size) -diff --git a/xen/include/asm-x86/hvm/irq.h b/xen/include/asm-x86/hvm/irq.h -index f756cb5a0d..1a52ec6045 100644 ---- a/xen/include/asm-x86/hvm/irq.h -+++ b/xen/include/asm-x86/hvm/irq.h -@@ -207,6 +207,9 @@ int hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq); - - int hvm_inject_msi(struct domain *d, uint64_t addr, uint32_t data); - -+/* Assert an IO APIC pin. */ -+int hvm_ioapic_assert(struct domain *d, unsigned int gsi, bool level); -+ - void hvm_maybe_deassert_evtchn_irq(void); - void hvm_assert_evtchn_irq(struct vcpu *v); - void hvm_set_callback_via(struct domain *d, uint64_t via); -diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h -index 8fb9e3ceee..e216c4ac35 100644 ---- a/xen/include/asm-x86/hvm/vmx/vmcs.h -+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h -@@ -130,10 +130,18 @@ struct arch_vmx_struct { - uint64_t sfmask; - - struct vmx_msr_bitmap *msr_bitmap; -- unsigned int msr_count; -+ -+ /* -+ * Most accesses to the MSR host/guest load/save lists are in current -+ * context. However, the data can be modified by toolstack/migration -+ * actions. Remote access is only permitted for paused vcpus, and is -+ * protected under the domctl lock. -+ */ - struct vmx_msr_entry *msr_area; -- unsigned int host_msr_count; - struct vmx_msr_entry *host_msr_area; -+ unsigned int msr_load_count; -+ unsigned int msr_save_count; -+ unsigned int host_msr_count; - - unsigned long eoi_exitmap_changed; - DECLARE_BITMAP(eoi_exit_bitmap, NR_VECTORS); -@@ -149,7 +157,7 @@ struct arch_vmx_struct { - /* Are we emulating rather than VMENTERing? */ - uint8_t vmx_emulate; - -- uint8_t lbr_fixup_enabled; -+ uint8_t lbr_flags; - - /* Bitmask of segments that we can't safely use in virtual 8086 mode */ - uint16_t vm86_segment_mask; -@@ -511,9 +519,6 @@ enum vmcs_field { - - #define VMCS_VPID_WIDTH 16 - --#define VMX_GUEST_MSR 0 --#define VMX_HOST_MSR 1 -- - /* VM Instruction error numbers */ - enum vmx_insn_errno - { -@@ -531,6 +536,67 @@ enum vmx_insn_errno - VMX_INSN_FAIL_INVALID = ~0, - }; - -+/* MSR load/save list infrastructure. */ -+enum vmx_msr_list_type { -+ VMX_MSR_HOST, /* MSRs loaded on VMExit. */ -+ VMX_MSR_GUEST, /* MSRs saved on VMExit, loaded on VMEntry. */ -+ VMX_MSR_GUEST_LOADONLY, /* MSRs loaded on VMEntry only. */ -+}; -+ -+/** -+ * Add an MSR to an MSR list (inserting space for the entry if necessary), and -+ * set the MSRs value. -+ * -+ * It is undefined behaviour to try and insert the same MSR into both the -+ * GUEST and GUEST_LOADONLY list. -+ * -+ * May fail if unable to allocate memory for the list, or the total number of -+ * entries exceeds the memory allocated. -+ */ -+int vmx_add_msr(struct vcpu *v, uint32_t msr, uint64_t val, -+ enum vmx_msr_list_type type); -+ -+static inline int vmx_add_guest_msr(struct vcpu *v, uint32_t msr, uint64_t val) -+{ -+ return vmx_add_msr(v, msr, val, VMX_MSR_GUEST); -+} -+static inline int vmx_add_host_load_msr(struct vcpu *v, uint32_t msr, -+ uint64_t val) -+{ -+ return vmx_add_msr(v, msr, val, VMX_MSR_HOST); -+} -+ -+struct vmx_msr_entry *vmx_find_msr(const struct vcpu *v, uint32_t msr, -+ enum vmx_msr_list_type type); -+ -+static inline int vmx_read_guest_msr(const struct vcpu *v, uint32_t msr, -+ uint64_t *val) -+{ -+ const struct vmx_msr_entry *ent = vmx_find_msr(v, msr, VMX_MSR_GUEST); -+ -+ if ( !ent ) -+ return -ESRCH; -+ -+ *val = ent->data; -+ -+ return 0; -+} -+ -+static inline int vmx_write_guest_msr(struct vcpu *v, uint32_t msr, -+ uint64_t val) -+{ -+ struct vmx_msr_entry *ent = vmx_find_msr(v, msr, VMX_MSR_GUEST); -+ -+ if ( !ent ) -+ return -ESRCH; -+ -+ ent->data = val; -+ -+ return 0; -+} -+ -+ -+/* MSR intercept bitmap infrastructure. */ - enum vmx_msr_intercept_type { - VMX_MSR_R = 1, - VMX_MSR_W = 2, -@@ -541,10 +607,6 @@ void vmx_clear_msr_intercept(struct vcpu *v, unsigned int msr, - enum vmx_msr_intercept_type type); - void vmx_set_msr_intercept(struct vcpu *v, unsigned int msr, - enum vmx_msr_intercept_type type); --int vmx_read_guest_msr(u32 msr, u64 *val); --int vmx_write_guest_msr(u32 msr, u64 val); --struct vmx_msr_entry *vmx_find_msr(u32 msr, int type); --int vmx_add_msr(u32 msr, int type); - void vmx_vmcs_switch(paddr_t from, paddr_t to); - void vmx_set_eoi_exit_bitmap(struct vcpu *v, u8 vector); - void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector); -@@ -559,15 +621,6 @@ void virtual_vmcs_vmwrite(const struct vcpu *, u32 encoding, u64 val); - enum vmx_insn_errno virtual_vmcs_vmwrite_safe(const struct vcpu *v, - u32 vmcs_encoding, u64 val); - --static inline int vmx_add_guest_msr(u32 msr) --{ -- return vmx_add_msr(msr, VMX_GUEST_MSR); --} --static inline int vmx_add_host_load_msr(u32 msr) --{ -- return vmx_add_msr(msr, VMX_HOST_MSR); --} -- - DECLARE_PER_CPU(bool_t, vmxon); - - bool_t vmx_vcpu_pml_enabled(const struct vcpu *v); -diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h -index 21166edd06..0eb5ff632e 100644 ---- a/xen/include/asm-x86/hvm/vpt.h -+++ b/xen/include/asm-x86/hvm/vpt.h -@@ -44,6 +44,7 @@ struct periodic_time { - bool_t warned_timeout_too_short; - #define PTSRC_isa 1 /* ISA time source */ - #define PTSRC_lapic 2 /* LAPIC time source */ -+#define PTSRC_ioapic 3 /* IOAPIC time source */ - u8 source; /* PTSRC_ */ - u8 irq; - struct vcpu *vcpu; /* vcpu timer interrupt delivers to */ -diff --git a/xen/include/asm-x86/hypercall.h b/xen/include/asm-x86/hypercall.h -index b9f3ecf9a3..0e1092845b 100644 ---- a/xen/include/asm-x86/hypercall.h -+++ b/xen/include/asm-x86/hypercall.h -@@ -165,7 +165,7 @@ extern int compat_update_va_mapping( - unsigned int va, u32 lo, u32 hi, unsigned int flags); - - extern int compat_update_va_mapping_otherdomain( -- unsigned long va, u32 lo, u32 hi, unsigned long flags, domid_t domid); -+ unsigned int va, u32 lo, u32 hi, unsigned int flags, domid_t domid); - - DEFINE_XEN_GUEST_HANDLE(trap_info_compat_t); - extern int compat_set_trap_table(XEN_GUEST_HANDLE(trap_info_compat_t) traps); -diff --git a/xen/include/asm-x86/i387.h b/xen/include/asm-x86/i387.h -index 7cfa215d30..243de672eb 100644 ---- a/xen/include/asm-x86/i387.h -+++ b/xen/include/asm-x86/i387.h -@@ -28,7 +28,7 @@ struct ix87_env { - uint16_t fds, _res6; - }; - --void vcpu_restore_fpu_eager(struct vcpu *v); -+void vcpu_restore_fpu_nonlazy(struct vcpu *v, bool need_stts); - void vcpu_restore_fpu_lazy(struct vcpu *v); - void vcpu_save_fpu(struct vcpu *v); - void save_fpu_enable(void); -diff --git a/xen/include/asm-x86/invpcid.h b/xen/include/asm-x86/invpcid.h -new file mode 100644 -index 0000000000..edd8b68706 ---- /dev/null -+++ b/xen/include/asm-x86/invpcid.h -@@ -0,0 +1,72 @@ -+#ifndef _ASM_X86_INVPCID_H_ -+#define _ASM_X86_INVPCID_H_ -+ -+#include <xen/types.h> -+ -+extern bool use_invpcid; -+ -+#define INVPCID_TYPE_INDIV_ADDR 0 -+#define INVPCID_TYPE_SINGLE_CTXT 1 -+#define INVPCID_TYPE_ALL_INCL_GLOBAL 2 -+#define INVPCID_TYPE_ALL_NON_GLOBAL 3 -+ -+#define INVPCID_OPCODE ".byte 0x66, 0x0f, 0x38, 0x82\n" -+#define MODRM_ECX_01 ".byte 0x01\n" -+ -+static inline void invpcid(unsigned int pcid, unsigned long addr, -+ unsigned int type) -+{ -+ struct { -+ uint64_t pcid:12; -+ uint64_t reserved:52; -+ uint64_t addr; -+ } desc = { .pcid = pcid, .addr = addr }; -+ -+ asm volatile ( -+#ifdef HAVE_AS_INVPCID -+ "invpcid %[desc], %q[type]" -+ : /* No output */ -+ : [desc] "m" (desc), [type] "r" (type) -+#else -+ INVPCID_OPCODE MODRM_ECX_01 -+ : /* No output */ -+ : "a" (type), "c" (&desc) -+#endif -+ : "memory" ); -+} -+ -+/* Flush all mappings for a given PCID and addr, not including globals */ -+static inline void invpcid_flush_one(unsigned int pcid, unsigned long addr) -+{ -+ invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR); -+} -+ -+/* Flush all mappings for a given PCID, not including globals */ -+static inline void invpcid_flush_single_context(unsigned int pcid) -+{ -+ invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT); -+} -+ -+/* Flush all mappings, including globals, for all PCIDs */ -+static inline void invpcid_flush_all(void) -+{ -+ invpcid(0, 0, INVPCID_TYPE_ALL_INCL_GLOBAL); -+} -+ -+/* Flush all mappings for all PCIDs, excluding globals */ -+static inline void invpcid_flush_all_nonglobals(void) -+{ -+ invpcid(0, 0, INVPCID_TYPE_ALL_NON_GLOBAL); -+} -+ -+#endif /* _ASM_X86_INVPCID_H_ */ -+ -+/* -+ * Local variables: -+ * mode: C -+ * c-file-style: "BSD" -+ * c-basic-offset: 4 -+ * tab-width: 4 -+ * indent-tabs-mode: nil -+ * End: -+ */ -diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h -index a8ceecf3e2..dfeba2821d 100644 ---- a/xen/include/asm-x86/msr-index.h -+++ b/xen/include/asm-x86/msr-index.h -@@ -31,10 +31,14 @@ - #define EFER_LMSLE (1<<_EFER_LMSLE) - #define EFER_FFXSE (1<<_EFER_FFXSE) - -+#define EFER_KNOWN_MASK (EFER_SCE | EFER_LME | EFER_LMA | EFER_NX | \ -+ EFER_SVME | EFER_LMSLE | EFER_FFXSE) -+ - /* Speculation Controls. */ - #define MSR_SPEC_CTRL 0x00000048 - #define SPEC_CTRL_IBRS (_AC(1, ULL) << 0) - #define SPEC_CTRL_STIBP (_AC(1, ULL) << 1) -+#define SPEC_CTRL_SSBD (_AC(1, ULL) << 2) - - #define MSR_PRED_CMD 0x00000049 - #define PRED_CMD_IBPB (_AC(1, ULL) << 0) -@@ -42,6 +46,12 @@ - #define MSR_ARCH_CAPABILITIES 0x0000010a - #define ARCH_CAPABILITIES_RDCL_NO (_AC(1, ULL) << 0) - #define ARCH_CAPABILITIES_IBRS_ALL (_AC(1, ULL) << 1) -+#define ARCH_CAPS_RSBA (_AC(1, ULL) << 2) -+#define ARCH_CAPS_SKIP_L1DFL (_AC(1, ULL) << 3) -+#define ARCH_CAPS_SSB_NO (_AC(1, ULL) << 4) -+ -+#define MSR_FLUSH_CMD 0x0000010b -+#define FLUSH_CMD_L1D (_AC(1, ULL) << 0) - - /* Intel MSRs. Some also available on other CPUs */ - #define MSR_IA32_PERFCTR0 0x000000c1 -diff --git a/xen/include/asm-x86/msr.h b/xen/include/asm-x86/msr.h -index 2c9277b6d5..22d5b7181e 100644 ---- a/xen/include/asm-x86/msr.h -+++ b/xen/include/asm-x86/msr.h -@@ -198,7 +198,7 @@ DECLARE_PER_CPU(u64, efer); - u64 read_efer(void); - void write_efer(u64 val); - --DECLARE_PER_CPU(u32, ler_msr); -+extern unsigned int ler_msr; - - DECLARE_PER_CPU(uint32_t, tsc_aux); - -diff --git a/xen/include/asm-x86/nops.h b/xen/include/asm-x86/nops.h -index 37f9819e82..0016075616 100644 ---- a/xen/include/asm-x86/nops.h -+++ b/xen/include/asm-x86/nops.h -@@ -61,11 +61,12 @@ - #define ASM_NOP7 _ASM_MK_NOP(K8_NOP7) - #define ASM_NOP8 _ASM_MK_NOP(K8_NOP8) - -+#define ASM_NOP14 ASM_NOP8; ASM_NOP6 - #define ASM_NOP17 ASM_NOP8; ASM_NOP7; ASM_NOP2 --#define ASM_NOP21 ASM_NOP8; ASM_NOP8; ASM_NOP5 - #define ASM_NOP24 ASM_NOP8; ASM_NOP8; ASM_NOP8 --#define ASM_NOP29 ASM_NOP8; ASM_NOP8; ASM_NOP8; ASM_NOP5 --#define ASM_NOP32 ASM_NOP8; ASM_NOP8; ASM_NOP8; ASM_NOP8 -+#define ASM_NOP25 ASM_NOP8; ASM_NOP8; ASM_NOP7; ASM_NOP2 -+#define ASM_NOP33 ASM_NOP8; ASM_NOP8; ASM_NOP8; ASM_NOP7; ASM_NOP2 -+#define ASM_NOP36 ASM_NOP8; ASM_NOP8; ASM_NOP8; ASM_NOP8; ASM_NOP4 - #define ASM_NOP40 ASM_NOP8; ASM_NOP8; ASM_NOP8; ASM_NOP8; ASM_NOP8 - - #define ASM_NOP_MAX 8 -diff --git a/xen/include/asm-x86/paging.h b/xen/include/asm-x86/paging.h -index 5607ab4b1f..fc326fe616 100644 ---- a/xen/include/asm-x86/paging.h -+++ b/xen/include/asm-x86/paging.h -@@ -37,11 +37,14 @@ - - #define PG_SH_shift 20 - #define PG_HAP_shift 21 -+#define PG_SHF_shift 22 - /* We're in one of the shadow modes */ - #ifdef CONFIG_SHADOW_PAGING - #define PG_SH_enable (1U << PG_SH_shift) -+#define PG_SH_forced (1U << PG_SHF_shift) - #else - #define PG_SH_enable 0 -+#define PG_SH_forced 0 - #endif - #define PG_HAP_enable (1U << PG_HAP_shift) - -@@ -62,6 +65,7 @@ - - #define paging_mode_enabled(_d) (!!(_d)->arch.paging.mode) - #define paging_mode_shadow(_d) (!!((_d)->arch.paging.mode & PG_SH_enable)) -+#define paging_mode_sh_forced(_d) (!!((_d)->arch.paging.mode & PG_SH_forced)) - #define paging_mode_hap(_d) (!!((_d)->arch.paging.mode & PG_HAP_enable)) - - #define paging_mode_refcounts(_d) (!!((_d)->arch.paging.mode & PG_refcounts)) -diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h -index 80f8411355..90a2701d26 100644 ---- a/xen/include/asm-x86/processor.h -+++ b/xen/include/asm-x86/processor.h -@@ -293,6 +293,21 @@ static inline unsigned long read_cr2(void) - return cr2; - } - -+static inline void write_cr3(unsigned long val) -+{ -+ asm volatile ( "mov %0, %%cr3" : : "r" (val) : "memory" ); -+} -+ -+static inline unsigned long cr3_pa(unsigned long cr3) -+{ -+ return cr3 & X86_CR3_ADDR_MASK; -+} -+ -+static inline unsigned long cr3_pcid(unsigned long cr3) -+{ -+ return cr3 & X86_CR3_PCID_MASK; -+} -+ - static inline unsigned long read_cr4(void) - { - return get_cpu_info()->cr4; -@@ -300,6 +315,9 @@ static inline unsigned long read_cr4(void) - - static inline void write_cr4(unsigned long val) - { -+ /* No global pages in case of PCIDs enabled! */ -+ ASSERT(!(val & X86_CR4_PGE) || !(val & X86_CR4_PCIDE)); -+ - get_cpu_info()->cr4 = val; - asm volatile ( "mov %0,%%cr4" : : "r" (val) ); - } -@@ -329,12 +347,6 @@ static always_inline void set_in_cr4 (unsigned long mask) - write_cr4(read_cr4() | mask); - } - --static always_inline void clear_in_cr4 (unsigned long mask) --{ -- mmu_cr4_features &= ~mask; -- write_cr4(read_cr4() & ~mask); --} -- - static inline unsigned int read_pkru(void) - { - unsigned int pkru; -@@ -445,7 +457,8 @@ struct __packed __cacheline_aligned tss_struct { - #define IST_DF 1UL - #define IST_NMI 2UL - #define IST_MCE 3UL --#define IST_MAX 3UL -+#define IST_DB 4UL -+#define IST_MAX 4UL - - /* Set the interrupt stack table used by a particular interrupt - * descriptor table entry. */ -diff --git a/xen/include/asm-x86/pv/domain.h b/xen/include/asm-x86/pv/domain.h -index acdf140fbd..6778e1bb75 100644 ---- a/xen/include/asm-x86/pv/domain.h -+++ b/xen/include/asm-x86/pv/domain.h -@@ -21,6 +21,37 @@ - #ifndef __X86_PV_DOMAIN_H__ - #define __X86_PV_DOMAIN_H__ - -+/* -+ * PCID values for the address spaces of 64-bit pv domains: -+ * -+ * We are using 4 PCID values for a 64 bit pv domain subject to XPTI: -+ * - hypervisor active and guest in kernel mode PCID 0 -+ * - hypervisor active and guest in user mode PCID 1 -+ * - guest active and in kernel mode PCID 2 -+ * - guest active and in user mode PCID 3 -+ * -+ * Without XPTI only 2 values are used: -+ * - guest in kernel mode PCID 0 -+ * - guest in user mode PCID 1 -+ */ -+ -+#define PCID_PV_PRIV 0x0000 /* Used for other domains, too. */ -+#define PCID_PV_USER 0x0001 -+#define PCID_PV_XPTI 0x0002 /* To be ORed to above values. */ -+ -+/* -+ * Return additional PCID specific cr3 bits. -+ * -+ * Note that X86_CR3_NOFLUSH will not be readable in cr3. Anyone consuming -+ * v->arch.cr3 should mask away X86_CR3_NOFLUSH and X86_CR3_PCIDMASK in case -+ * the value is used to address the root page table. -+ */ -+static inline unsigned long get_pcid_bits(const struct vcpu *v, bool is_xpti) -+{ -+ return X86_CR3_NOFLUSH | (is_xpti ? PCID_PV_XPTI : 0) | -+ ((v->arch.flags & TF_kernel_mode) ? PCID_PV_PRIV : PCID_PV_USER); -+} -+ - #ifdef CONFIG_PV - - void pv_vcpu_destroy(struct vcpu *v); -diff --git a/xen/include/asm-x86/setup.h b/xen/include/asm-x86/setup.h -index b68ec9de4d..ecfd0c2e7b 100644 ---- a/xen/include/asm-x86/setup.h -+++ b/xen/include/asm-x86/setup.h -@@ -66,6 +66,8 @@ extern uint8_t kbd_shift_flags; - extern unsigned long highmem_start; - #endif - -+extern int8_t opt_smt; -+ - #ifdef CONFIG_SHADOW_PAGING - extern bool opt_dom0_shadow; - #else -diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h -index 94a34fd16a..f40f411871 100644 ---- a/xen/include/asm-x86/shadow.h -+++ b/xen/include/asm-x86/shadow.h -@@ -29,6 +29,7 @@ - #include <asm/flushtlb.h> - #include <asm/paging.h> - #include <asm/p2m.h> -+#include <asm/spec_ctrl.h> - - /***************************************************************************** - * Macros to tell which shadow paging mode a domain is in*/ -@@ -115,6 +116,131 @@ static inline int shadow_domctl(struct domain *d, - - #endif /* CONFIG_SHADOW_PAGING */ - -+/* -+ * Mitigations for L1TF / CVE-2018-3620 for PV guests. -+ * -+ * We cannot alter an architecturally-legitimate PTE which a PV guest has -+ * chosen to write, as traditional paged-out metadata is L1TF-vulnerable. -+ * What we can do is force a PV guest which writes a vulnerable PTE into -+ * shadow mode, so Xen controls the pagetables which are reachable by the CPU -+ * pagewalk. -+ * -+ * The core of the L1TF vulnerability is that the address bits of the PTE -+ * (accounting for PSE and factoring in the level-relevant part of the linear -+ * access) are sent for an L1D lookup (to retrieve the next-level PTE, or -+ * eventual memory address) before the Present or reserved bits (which would -+ * cause a terminal fault) are accounted for. If an L1D hit occurs, the -+ * resulting data is available for potentially dependent instructions. -+ * -+ * For Present PTEs, the PV type-count safety logic ensures that the address -+ * bits always point at a guest-accessible frame, which is safe WRT L1TF from -+ * Xen's point of view. In practice, a PV guest should be unable to set any -+ * reserved bits, so should be unable to create any present L1TF-vulnerable -+ * PTEs at all. -+ * -+ * Therefore, these safety checks apply to Not-Present PTEs only, where -+ * traditionally, Xen would have let the guest write any value it chose. -+ * -+ * The all-zero PTE potentially leaks mfn 0. All software on the system is -+ * expected to cooperate and not put any secrets there. In a Xen system, -+ * neither Xen nor dom0 are expected to touch mfn 0, as it typically contains -+ * the real mode IVT and Bios Data Area. Therefore, mfn 0 is considered safe. -+ * -+ * Any PTE whose address is higher than the maximum cacheable address is safe, -+ * as it won't get an L1D hit. -+ * -+ * Speculative superpages also need accounting for, as PSE is considered -+ * irrespective of Present. We disallow PSE being set, as it allows an -+ * attacker to leak 2M or 1G of data starting from mfn 0. Also, because of -+ * recursive/linear pagetables, we must consider PSE even at L4, as hardware -+ * will interpret an L4e as an L3e during a recursive walk. -+ */ -+ -+static inline bool is_l1tf_safe_maddr(intpte_t pte) -+{ -+ paddr_t maddr = pte & l1tf_addr_mask; -+ -+ return maddr == 0 || maddr >= l1tf_safe_maddr; -+} -+ -+static inline bool pv_l1tf_check_pte(struct domain *d, unsigned int level, -+ intpte_t pte) -+{ -+ ASSERT(is_pv_domain(d)); -+ ASSERT(!(pte & _PAGE_PRESENT)); -+ -+ if ( d->arch.pv_domain.check_l1tf && !paging_mode_sh_forced(d) && -+ (((level > 1) && (pte & _PAGE_PSE)) || !is_l1tf_safe_maddr(pte)) ) -+ { -+#ifdef CONFIG_SHADOW_PAGING -+ struct tasklet *t = &d->arch.paging.shadow.pv_l1tf_tasklet; -+ -+ printk(XENLOG_G_WARNING -+ "d%d L1TF-vulnerable L%ue %016"PRIx64" - Shadowing\n", -+ d->domain_id, level, pte); -+ /* -+ * Safety consideration for accessing tasklet.scheduled_on without the -+ * tasklet lock. This is a singleshot tasklet with the side effect of -+ * setting PG_SH_forced (checked just above). Multiple vcpus can race -+ * to schedule the tasklet, but if we observe it scheduled anywhere, -+ * that is good enough. -+ */ -+ smp_rmb(); -+ if ( !tasklet_is_scheduled(t) ) -+ tasklet_schedule(t); -+#else -+ printk(XENLOG_G_ERR -+ "d%d L1TF-vulnerable L%ue %016"PRIx64" - Crashing\n", -+ d->domain_id, level, pte); -+ domain_crash(d); -+#endif -+ return true; -+ } -+ -+ return false; -+} -+ -+static inline bool pv_l1tf_check_l1e(struct domain *d, l1_pgentry_t l1e) -+{ -+ return pv_l1tf_check_pte(d, 1, l1e.l1); -+} -+ -+static inline bool pv_l1tf_check_l2e(struct domain *d, l2_pgentry_t l2e) -+{ -+ return pv_l1tf_check_pte(d, 2, l2e.l2); -+} -+ -+static inline bool pv_l1tf_check_l3e(struct domain *d, l3_pgentry_t l3e) -+{ -+ return pv_l1tf_check_pte(d, 3, l3e.l3); -+} -+ -+static inline bool pv_l1tf_check_l4e(struct domain *d, l4_pgentry_t l4e) -+{ -+ return pv_l1tf_check_pte(d, 4, l4e.l4); -+} -+ -+void pv_l1tf_tasklet(unsigned long data); -+ -+static inline void pv_l1tf_domain_init(struct domain *d) -+{ -+ d->arch.pv_domain.check_l1tf = -+ opt_pv_l1tf & (is_hardware_domain(d) -+ ? OPT_PV_L1TF_DOM0 : OPT_PV_L1TF_DOMU); -+ -+#if defined(CONFIG_SHADOW_PAGING) && defined(CONFIG_PV) -+ tasklet_init(&d->arch.paging.shadow.pv_l1tf_tasklet, -+ pv_l1tf_tasklet, (unsigned long)d); -+#endif -+} -+ -+static inline void pv_l1tf_domain_destroy(struct domain *d) -+{ -+#if defined(CONFIG_SHADOW_PAGING) && defined(CONFIG_PV) -+ tasklet_kill(&d->arch.paging.shadow.pv_l1tf_tasklet); -+#endif -+} -+ - /* Remove all shadows of the guest mfn. */ - static inline void shadow_remove_all_shadows(struct domain *d, mfn_t gmfn) - { -diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h -index 4e5f673fec..09c55458df 100644 ---- a/xen/include/asm-x86/smp.h -+++ b/xen/include/asm-x86/smp.h -@@ -26,6 +26,8 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_mask); - DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask); - DECLARE_PER_CPU(cpumask_var_t, scratch_cpumask); - -+extern bool park_offline_cpus; -+ - void smp_send_nmi_allbutself(void); - - void send_IPI_mask(const cpumask_t *, int vector); -diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h -index 5ab4ff3f68..8f8aad40bb 100644 ---- a/xen/include/asm-x86/spec_ctrl.h -+++ b/xen/include/asm-x86/spec_ctrl.h -@@ -27,14 +27,36 @@ - void init_speculation_mitigations(void); - - extern bool opt_ibpb; --extern uint8_t default_bti_ist_info; -+extern bool opt_ssbd; -+extern int8_t opt_eager_fpu; -+extern int8_t opt_l1d_flush; -+ -+extern bool bsp_delay_spec_ctrl; -+extern uint8_t default_xen_spec_ctrl; -+extern uint8_t default_spec_ctrl_flags; -+ -+extern int8_t opt_xpti; -+#define OPT_XPTI_DOM0 0x01 -+#define OPT_XPTI_DOMU 0x02 -+ -+extern int8_t opt_pv_l1tf; -+#define OPT_PV_L1TF_DOM0 0x01 -+#define OPT_PV_L1TF_DOMU 0x02 -+ -+/* -+ * The L1D address mask, which might be wider than reported in CPUID, and the -+ * system physical address above which there are believed to be no cacheable -+ * memory regions, thus unable to leak data via the L1TF vulnerability. -+ */ -+extern paddr_t l1tf_addr_mask, l1tf_safe_maddr; - - static inline void init_shadow_spec_ctrl_state(void) - { - struct cpu_info *info = get_cpu_info(); - -- info->shadow_spec_ctrl = info->use_shadow_spec_ctrl = 0; -- info->bti_ist_info = default_bti_ist_info; -+ info->shadow_spec_ctrl = 0; -+ info->xen_spec_ctrl = default_xen_spec_ctrl; -+ info->spec_ctrl_flags = default_spec_ctrl_flags; - } - - /* WARNING! `ret`, `call *`, `jmp *` not safe after this call. */ -@@ -48,24 +70,24 @@ static always_inline void spec_ctrl_enter_idle(struct cpu_info *info) - */ - info->shadow_spec_ctrl = val; - barrier(); -- info->use_shadow_spec_ctrl = true; -+ info->spec_ctrl_flags |= SCF_use_shadow; - barrier(); -- asm volatile ( ALTERNATIVE(ASM_NOP3, "wrmsr", X86_FEATURE_XEN_IBRS_SET) -+ asm volatile ( ALTERNATIVE(ASM_NOP3, "wrmsr", X86_FEATURE_SC_MSR_IDLE) - :: "a" (val), "c" (MSR_SPEC_CTRL), "d" (0) : "memory" ); - } - - /* WARNING! `ret`, `call *`, `jmp *` not safe before this call. */ - static always_inline void spec_ctrl_exit_idle(struct cpu_info *info) - { -- uint32_t val = SPEC_CTRL_IBRS; -+ uint32_t val = info->xen_spec_ctrl; - - /* - * Disable shadowing before updating the MSR. There are no SMP issues - * here; only local processor ordering concerns. - */ -- info->use_shadow_spec_ctrl = false; -+ info->spec_ctrl_flags &= ~SCF_use_shadow; - barrier(); -- asm volatile ( ALTERNATIVE(ASM_NOP3, "wrmsr", X86_FEATURE_XEN_IBRS_SET) -+ asm volatile ( ALTERNATIVE(ASM_NOP3, "wrmsr", X86_FEATURE_SC_MSR_IDLE) - :: "a" (val), "c" (MSR_SPEC_CTRL), "d" (0) : "memory" ); - } - -diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h -index 1f2b6f3552..c659f3f146 100644 ---- a/xen/include/asm-x86/spec_ctrl_asm.h -+++ b/xen/include/asm-x86/spec_ctrl_asm.h -@@ -20,10 +20,10 @@ - #ifndef __X86_SPEC_CTRL_ASM_H__ - #define __X86_SPEC_CTRL_ASM_H__ - --/* Encoding of the bottom bits in cpuinfo.bti_ist_info */ --#define BTI_IST_IBRS (1 << 0) --#define BTI_IST_WRMSR (1 << 1) --#define BTI_IST_RSB (1 << 2) -+/* Encoding of cpuinfo.spec_ctrl_flags */ -+#define SCF_use_shadow (1 << 0) -+#define SCF_ist_wrmsr (1 << 1) -+#define SCF_ist_rsb (1 << 2) - - #ifdef __ASSEMBLY__ - #include <asm/msr-index.h> -@@ -50,20 +50,20 @@ - * after VMEXIT. The VMEXIT-specific code reads MSR_SPEC_CTRL and updates - * current before loading Xen's MSR_SPEC_CTRL setting. - * -- * Factor 2 is harder. We maintain a shadow_spec_ctrl value, and -- * use_shadow_spec_ctrl boolean per cpu. The synchronous use is: -+ * Factor 2 is harder. We maintain a shadow_spec_ctrl value, and a use_shadow -+ * boolean in the per cpu spec_ctrl_flags. The synchronous use is: - * - * 1) Store guest value in shadow_spec_ctrl -- * 2) Set use_shadow_spec_ctrl boolean -+ * 2) Set the use_shadow boolean - * 3) Load guest value into MSR_SPEC_CTRL - * 4) Exit to guest - * 5) Entry from guest -- * 6) Clear use_shadow_spec_ctrl boolean -+ * 6) Clear the use_shadow boolean - * 7) Load Xen's value into MSR_SPEC_CTRL - * - * The asynchronous use for interrupts/exceptions is: - * - Set/clear IBRS on entry to Xen -- * - On exit to Xen, check use_shadow_spec_ctrl -+ * - On exit to Xen, check use_shadow - * - If set, load shadow_spec_ctrl - * - * Therefore, an interrupt/exception which hits the synchronous path between -@@ -72,11 +72,14 @@ - * - * The following ASM fragments implement this algorithm. See their local - * comments for further details. -- * - SPEC_CTRL_ENTRY_FROM_VMEXIT -+ * - SPEC_CTRL_ENTRY_FROM_HVM - * - SPEC_CTRL_ENTRY_FROM_PV - * - SPEC_CTRL_ENTRY_FROM_INTR -+ * - SPEC_CTRL_ENTRY_FROM_INTR_IST -+ * - SPEC_CTRL_EXIT_TO_XEN_IST - * - SPEC_CTRL_EXIT_TO_XEN -- * - SPEC_CTRL_EXIT_TO_GUEST -+ * - SPEC_CTRL_EXIT_TO_PV -+ * - SPEC_CTRL_EXIT_TO_HVM - */ - - .macro DO_OVERWRITE_RSB tmp=rax -@@ -117,7 +120,7 @@ - mov %\tmp, %rsp /* Restore old %rsp */ - .endm - --.macro DO_SPEC_CTRL_ENTRY_FROM_VMEXIT ibrs_val:req -+.macro DO_SPEC_CTRL_ENTRY_FROM_HVM - /* - * Requires %rbx=current, %rsp=regs/cpuinfo - * Clobbers %rax, %rcx, %rdx -@@ -135,14 +138,14 @@ - xor %edx, %edx - - /* Clear SPEC_CTRL shadowing *before* loading Xen's value. */ -- movb %dl, CPUINFO_use_shadow_spec_ctrl(%rsp) -+ andb $~SCF_use_shadow, CPUINFO_spec_ctrl_flags(%rsp) - - /* Load Xen's intended value. */ -- mov $\ibrs_val, %eax -+ movzbl CPUINFO_xen_spec_ctrl(%rsp), %eax - wrmsr - .endm - --.macro DO_SPEC_CTRL_ENTRY maybexen:req ibrs_val:req -+.macro DO_SPEC_CTRL_ENTRY maybexen:req - /* - * Requires %rsp=regs (also cpuinfo if !maybexen) - * Requires %r14=stack_end (if maybexen) -@@ -161,16 +164,18 @@ - * block so calculate the position directly. - */ - .if \maybexen -+ xor %eax, %eax - /* Branchless `if ( !xen ) clear_shadowing` */ - testb $3, UREGS_cs(%rsp) -- setz %al -- and %al, STACK_CPUINFO_FIELD(use_shadow_spec_ctrl)(%r14) -+ setnz %al -+ not %eax -+ and %al, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) -+ movzbl STACK_CPUINFO_FIELD(xen_spec_ctrl)(%r14), %eax - .else -- movb %dl, CPUINFO_use_shadow_spec_ctrl(%rsp) -+ andb $~SCF_use_shadow, CPUINFO_spec_ctrl_flags(%rsp) -+ movzbl CPUINFO_xen_spec_ctrl(%rsp), %eax - .endif - -- /* Load Xen's intended value. */ -- mov $\ibrs_val, %eax - wrmsr - .endm - -@@ -185,8 +190,8 @@ - */ - xor %edx, %edx - -- cmpb %dl, STACK_CPUINFO_FIELD(use_shadow_spec_ctrl)(%rbx) -- je .L\@_skip -+ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) -+ jz .L\@_skip - - mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax - mov $MSR_SPEC_CTRL, %ecx -@@ -207,7 +212,7 @@ - mov %eax, CPUINFO_shadow_spec_ctrl(%rsp) - - /* Set SPEC_CTRL shadowing *before* loading the guest value. */ -- movb $1, CPUINFO_use_shadow_spec_ctrl(%rsp) -+ orb $SCF_use_shadow, CPUINFO_spec_ctrl_flags(%rsp) - - mov $MSR_SPEC_CTRL, %ecx - xor %edx, %edx -@@ -215,52 +220,47 @@ - .endm - - /* Use after a VMEXIT from an HVM guest. */ --#define SPEC_CTRL_ENTRY_FROM_VMEXIT \ -+#define SPEC_CTRL_ENTRY_FROM_HVM \ - ALTERNATIVE __stringify(ASM_NOP40), \ -- DO_OVERWRITE_RSB, X86_FEATURE_RSB_VMEXIT; \ -- ALTERNATIVE_2 __stringify(ASM_NOP32), \ -- __stringify(DO_SPEC_CTRL_ENTRY_FROM_VMEXIT \ -- ibrs_val=SPEC_CTRL_IBRS), \ -- X86_FEATURE_XEN_IBRS_SET, \ -- __stringify(DO_SPEC_CTRL_ENTRY_FROM_VMEXIT \ -- ibrs_val=0), \ -- X86_FEATURE_XEN_IBRS_CLEAR -+ DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_HVM; \ -+ ALTERNATIVE __stringify(ASM_NOP36), \ -+ DO_SPEC_CTRL_ENTRY_FROM_HVM, X86_FEATURE_SC_MSR_HVM - - /* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */ - #define SPEC_CTRL_ENTRY_FROM_PV \ - ALTERNATIVE __stringify(ASM_NOP40), \ -- DO_OVERWRITE_RSB, X86_FEATURE_RSB_NATIVE; \ -- ALTERNATIVE_2 __stringify(ASM_NOP21), \ -- __stringify(DO_SPEC_CTRL_ENTRY maybexen=0 \ -- ibrs_val=SPEC_CTRL_IBRS), \ -- X86_FEATURE_XEN_IBRS_SET, \ -- __stringify(DO_SPEC_CTRL_ENTRY maybexen=0 ibrs_val=0), \ -- X86_FEATURE_XEN_IBRS_CLEAR -+ DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ -+ ALTERNATIVE __stringify(ASM_NOP25), \ -+ __stringify(DO_SPEC_CTRL_ENTRY maybexen=0), X86_FEATURE_SC_MSR_PV - - /* Use in interrupt/exception context. May interrupt Xen or PV context. */ - #define SPEC_CTRL_ENTRY_FROM_INTR \ - ALTERNATIVE __stringify(ASM_NOP40), \ -- DO_OVERWRITE_RSB, X86_FEATURE_RSB_NATIVE; \ -- ALTERNATIVE_2 __stringify(ASM_NOP29), \ -- __stringify(DO_SPEC_CTRL_ENTRY maybexen=1 \ -- ibrs_val=SPEC_CTRL_IBRS), \ -- X86_FEATURE_XEN_IBRS_SET, \ -- __stringify(DO_SPEC_CTRL_ENTRY maybexen=1 ibrs_val=0), \ -- X86_FEATURE_XEN_IBRS_CLEAR -+ DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \ -+ ALTERNATIVE __stringify(ASM_NOP33), \ -+ __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), X86_FEATURE_SC_MSR_PV - - /* Use when exiting to Xen context. */ - #define SPEC_CTRL_EXIT_TO_XEN \ -- ALTERNATIVE_2 __stringify(ASM_NOP17), \ -- DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_XEN_IBRS_SET, \ -- DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_XEN_IBRS_CLEAR -+ ALTERNATIVE __stringify(ASM_NOP17), \ -+ DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_SC_MSR_PV - --/* Use when exiting to guest context. */ --#define SPEC_CTRL_EXIT_TO_GUEST \ -- ALTERNATIVE_2 __stringify(ASM_NOP24), \ -- DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_XEN_IBRS_SET, \ -- DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_XEN_IBRS_CLEAR -+/* Use when exiting to PV guest context. */ -+#define SPEC_CTRL_EXIT_TO_PV \ -+ ALTERNATIVE __stringify(ASM_NOP24), \ -+ DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV - --/* TODO: Drop these when the alternatives infrastructure is NMI/#MC safe. */ -+/* Use when exiting to HVM guest context. */ -+#define SPEC_CTRL_EXIT_TO_HVM \ -+ ALTERNATIVE __stringify(ASM_NOP24), \ -+ DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_HVM -+ -+/* -+ * Use in IST interrupt/exception context. May interrupt Xen or PV context. -+ * Fine grain control of SCF_ist_wrmsr is needed for safety in the S3 resume -+ * path to avoid using MSR_SPEC_CTRL before the microcode introducing it has -+ * been reloaded. -+ */ - .macro SPEC_CTRL_ENTRY_FROM_INTR_IST - /* - * Requires %rsp=regs, %r14=stack_end -@@ -269,29 +269,27 @@ - * This is logical merge of DO_OVERWRITE_RSB and DO_SPEC_CTRL_ENTRY - * maybexen=1, but with conditionals rather than alternatives. - */ -- movzbl STACK_CPUINFO_FIELD(bti_ist_info)(%r14), %eax -+ movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %eax - -- testb $BTI_IST_RSB, %al -+ test $SCF_ist_rsb, %al - jz .L\@_skip_rsb - - DO_OVERWRITE_RSB tmp=rdx /* Clobbers %rcx/%rdx */ - - .L\@_skip_rsb: - -- testb $BTI_IST_WRMSR, %al -+ test $SCF_ist_wrmsr, %al - jz .L\@_skip_wrmsr - - xor %edx, %edx - testb $3, UREGS_cs(%rsp) -- setz %dl -- and %dl, STACK_CPUINFO_FIELD(use_shadow_spec_ctrl)(%r14) -+ setnz %dl -+ not %edx -+ and %dl, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14) - -- /* -- * Load Xen's intended value. SPEC_CTRL_IBRS vs 0 is encoded in the -- * bottom bit of bti_ist_info, via a deliberate alias with BTI_IST_IBRS. -- */ -+ /* Load Xen's intended value. */ - mov $MSR_SPEC_CTRL, %ecx -- and $BTI_IST_IBRS, %eax -+ movzbl STACK_CPUINFO_FIELD(xen_spec_ctrl)(%r14), %eax - xor %edx, %edx - wrmsr - -@@ -309,12 +307,13 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise): - UNLIKELY_END(\@_serialise) - .endm - -+/* Use when exiting to Xen in IST context. */ - .macro SPEC_CTRL_EXIT_TO_XEN_IST - /* - * Requires %rbx=stack_end - * Clobbers %rax, %rcx, %rdx - */ -- testb $BTI_IST_WRMSR, STACK_CPUINFO_FIELD(bti_ist_info)(%rbx) -+ testb $SCF_ist_wrmsr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx) - jz .L\@_skip - - DO_SPEC_CTRL_EXIT_TO_XEN -diff --git a/xen/include/asm-x86/system.h b/xen/include/asm-x86/system.h -index eb498f5e71..605768be12 100644 ---- a/xen/include/asm-x86/system.h -+++ b/xen/include/asm-x86/system.h -@@ -185,6 +185,30 @@ static always_inline unsigned long __xadd( - #define set_mb(var, value) do { xchg(&var, value); } while (0) - #define set_wmb(var, value) do { var = value; wmb(); } while (0) - -+/** -+ * array_index_mask_nospec() - generate a mask that is ~0UL when the -+ * bounds check succeeds and 0 otherwise -+ * @index: array element index -+ * @size: number of elements in array -+ * -+ * Returns: -+ * 0 - (index < size) -+ */ -+static inline unsigned long array_index_mask_nospec(unsigned long index, -+ unsigned long size) -+{ -+ unsigned long mask; -+ -+ asm volatile ( "cmp %[size], %[index]; sbb %[mask], %[mask];" -+ : [mask] "=r" (mask) -+ : [size] "g" (size), [index] "r" (index) ); -+ -+ return mask; -+} -+ -+/* Override default implementation in nospec.h. */ -+#define array_index_mask_nospec array_index_mask_nospec -+ - #define local_irq_disable() asm volatile ( "cli" : : : "memory" ) - #define local_irq_enable() asm volatile ( "sti" : : : "memory" ) - -diff --git a/xen/include/asm-x86/x86-defns.h b/xen/include/asm-x86/x86-defns.h -index 70453e8dfb..10b366a07d 100644 ---- a/xen/include/asm-x86/x86-defns.h -+++ b/xen/include/asm-x86/x86-defns.h -@@ -42,6 +42,13 @@ - #define X86_CR0_CD 0x40000000 /* Cache Disable (RW) */ - #define X86_CR0_PG 0x80000000 /* Paging (RW) */ - -+/* -+ * Intel CPU flags in CR3 -+ */ -+#define X86_CR3_NOFLUSH (_AC(1, ULL) << 63) -+#define X86_CR3_ADDR_MASK (PAGE_MASK & PADDR_MASK) -+#define X86_CR3_PCID_MASK _AC(0x0fff, ULL) /* Mask for PCID */ -+ - /* - * Intel CPU features in CR4 - */ -diff --git a/xen/include/asm-x86/xstate.h b/xen/include/asm-x86/xstate.h -index d36f422b59..9ba2a04c74 100644 ---- a/xen/include/asm-x86/xstate.h -+++ b/xen/include/asm-x86/xstate.h -@@ -116,8 +116,9 @@ void xsave(struct vcpu *v, uint64_t mask); - void xrstor(struct vcpu *v, uint64_t mask); - void xstate_set_init(uint64_t mask); - bool xsave_enabled(const struct vcpu *v); --int __must_check validate_xstate(u64 xcr0, u64 xcr0_accum, -- const struct xsave_hdr *); -+int __must_check validate_xstate(const struct domain *d, -+ uint64_t xcr0, uint64_t xcr0_accum, -+ const struct xsave_hdr *hdr); - int __must_check handle_xsetbv(u32 index, u64 new_bv); - void expand_xsave_states(struct vcpu *v, void *dest, unsigned int size); - void compress_xsave_states(struct vcpu *v, const void *src, unsigned int size); -diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h -index 8da5783f7a..6c82816fd3 100644 ---- a/xen/include/public/arch-x86/cpufeatureset.h -+++ b/xen/include/public/arch-x86/cpufeatureset.h -@@ -243,8 +243,10 @@ XEN_CPUFEATURE(IBPB, 8*32+12) /*A IBPB support only (no IBRS, used by - XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A AVX512 Neural Network Instructions */ - XEN_CPUFEATURE(AVX512_4FMAPS, 9*32+ 3) /*A AVX512 Multiply Accumulation Single Precision */ - XEN_CPUFEATURE(IBRSB, 9*32+26) /*A IBRS and IBPB support (used by Intel) */ --XEN_CPUFEATURE(STIBP, 9*32+27) /*A! STIBP */ -+XEN_CPUFEATURE(STIBP, 9*32+27) /*A STIBP */ -+XEN_CPUFEATURE(L1D_FLUSH, 9*32+28) /*S MSR_FLUSH_CMD and L1D flush. */ - XEN_CPUFEATURE(ARCH_CAPS, 9*32+29) /* IA32_ARCH_CAPABILITIES MSR */ -+XEN_CPUFEATURE(SSBD, 9*32+31) /*A MSR_SPEC_CTRL.SSBD available */ - - #endif /* XEN_CPUFEATURE */ - -diff --git a/xen/include/xen/compiler.h b/xen/include/xen/compiler.h -index 533a8ea0f3..a7e05681c9 100644 ---- a/xen/include/xen/compiler.h -+++ b/xen/include/xen/compiler.h -@@ -81,6 +81,9 @@ - #pragma GCC visibility push(hidden) - #endif - -+/* Make the optimizer believe the variable can be manipulated arbitrarily. */ -+#define OPTIMIZER_HIDE_VAR(var) __asm__ ( "" : "+g" (var) ) -+ - /* This macro obfuscates arithmetic on a variable address so that gcc - shouldn't recognize the original var, and make assumptions about it */ - /* -diff --git a/xen/include/xen/cpu.h b/xen/include/xen/cpu.h -index ffefc09f8e..2fe3ec05d8 100644 ---- a/xen/include/xen/cpu.h -+++ b/xen/include/xen/cpu.h -@@ -47,6 +47,8 @@ void register_cpu_notifier(struct notifier_block *nb); - #define CPU_DYING (0x0007 | NOTIFY_REVERSE) - /* CPU_DEAD: CPU is dead. */ - #define CPU_DEAD (0x0008 | NOTIFY_REVERSE) -+/* CPU_REMOVE: CPU was removed. */ -+#define CPU_REMOVE (0x0009 | NOTIFY_REVERSE) - - /* Perform CPU hotplug. May return -EAGAIN. */ - int cpu_down(unsigned int cpu); -diff --git a/xen/include/xen/cpumask.h b/xen/include/xen/cpumask.h -index 3f340d619a..ee4399865a 100644 ---- a/xen/include/xen/cpumask.h -+++ b/xen/include/xen/cpumask.h -@@ -349,16 +349,35 @@ static inline bool_t alloc_cpumask_var(cpumask_var_t *mask) - return *mask != NULL; - } - -+static inline bool cond_alloc_cpumask_var(cpumask_var_t *mask) -+{ -+ if (*mask == NULL) -+ *mask = _xmalloc(nr_cpumask_bits / 8, sizeof(long)); -+ return *mask != NULL; -+} -+ - static inline bool_t zalloc_cpumask_var(cpumask_var_t *mask) - { - *(void **)mask = _xzalloc(nr_cpumask_bits / 8, sizeof(long)); - return *mask != NULL; - } - -+static inline bool cond_zalloc_cpumask_var(cpumask_var_t *mask) -+{ -+ if (*mask == NULL) -+ *mask = _xzalloc(nr_cpumask_bits / 8, sizeof(long)); -+ else -+ cpumask_clear(*mask); -+ return *mask != NULL; -+} -+ - static inline void free_cpumask_var(cpumask_var_t mask) - { - xfree(mask); - } -+ -+/* Free an allocated mask, and zero the pointer to it. */ -+#define FREE_CPUMASK_VAR(m) XFREE(m) - #else - typedef cpumask_t cpumask_var_t[1]; - -@@ -366,16 +385,20 @@ static inline bool_t alloc_cpumask_var(cpumask_var_t *mask) - { - return 1; - } -+#define cond_alloc_cpumask_var alloc_cpumask_var - - static inline bool_t zalloc_cpumask_var(cpumask_var_t *mask) - { - cpumask_clear(*mask); - return 1; - } -+#define cond_zalloc_cpumask_var zalloc_cpumask_var - - static inline void free_cpumask_var(cpumask_var_t mask) - { - } -+ -+#define FREE_CPUMASK_VAR(m) free_cpumask_var(m) - #endif - - #if NR_CPUS > 1 -diff --git a/xen/include/xen/list.h b/xen/include/xen/list.h -index fa07d720ee..1387abb211 100644 ---- a/xen/include/xen/list.h -+++ b/xen/include/xen/list.h -@@ -51,6 +51,11 @@ static inline void INIT_LIST_HEAD(struct list_head *list) - list->prev = list; - } - -+static inline bool list_head_is_null(const struct list_head *list) -+{ -+ return !list->next && !list->prev; -+} -+ - /* - * Insert a new entry between two known consecutive entries. - * -diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h -index e813c07b22..fdcb90841a 100644 ---- a/xen/include/xen/mm.h -+++ b/xen/include/xen/mm.h -@@ -162,6 +162,14 @@ void free_xenheap_pages(void *v, unsigned int order); - bool scrub_free_pages(void); - #define alloc_xenheap_page() (alloc_xenheap_pages(0,0)) - #define free_xenheap_page(v) (free_xenheap_pages(v,0)) -+ -+/* Free an allocation, and zero the pointer to it. */ -+#define FREE_XENHEAP_PAGES(p, o) do { \ -+ free_xenheap_pages(p, o); \ -+ (p) = NULL; \ -+} while ( false ) -+#define FREE_XENHEAP_PAGE(p) FREE_XENHEAP_PAGES(p, 0) -+ - /* Map machine page range in Xen virtual address space. */ - int map_pages_to_xen( - unsigned long virt, -diff --git a/xen/include/xen/nospec.h b/xen/include/xen/nospec.h -new file mode 100644 -index 0000000000..48793996e8 ---- /dev/null -+++ b/xen/include/xen/nospec.h -@@ -0,0 +1,70 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright(c) 2018 Linus Torvalds. All rights reserved. */ -+/* Copyright(c) 2018 Alexei Starovoitov. All rights reserved. */ -+/* Copyright(c) 2018 Intel Corporation. All rights reserved. */ -+/* Copyright(c) 2018 Citrix Systems R&D Ltd. All rights reserved. */ -+ -+#ifndef XEN_NOSPEC_H -+#define XEN_NOSPEC_H -+ -+#include <asm/system.h> -+ -+/** -+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise -+ * @index: array element index -+ * @size: number of elements in array -+ * -+ * When @index is out of bounds (@index >= @size), the sign bit will be -+ * set. Extend the sign bit to all bits and invert, giving a result of -+ * zero for an out of bounds index, or ~0 if within bounds [0, @size). -+ */ -+#ifndef array_index_mask_nospec -+static inline unsigned long array_index_mask_nospec(unsigned long index, -+ unsigned long size) -+{ -+ /* -+ * Always calculate and emit the mask even if the compiler -+ * thinks the mask is not needed. The compiler does not take -+ * into account the value of @index under speculation. -+ */ -+ OPTIMIZER_HIDE_VAR(index); -+ return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1); -+} -+#endif -+ -+/* -+ * array_index_nospec - sanitize an array index after a bounds check -+ * -+ * For a code sequence like: -+ * -+ * if (index < size) { -+ * index = array_index_nospec(index, size); -+ * val = array[index]; -+ * } -+ * -+ * ...if the CPU speculates past the bounds check then -+ * array_index_nospec() will clamp the index within the range of [0, -+ * size). -+ */ -+#define array_index_nospec(index, size) \ -+({ \ -+ typeof(index) _i = (index); \ -+ typeof(size) _s = (size); \ -+ unsigned long _mask = array_index_mask_nospec(_i, _s); \ -+ \ -+ BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \ -+ BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \ -+ \ -+ (typeof(_i)) (_i & _mask); \ -+}) -+ -+#endif /* XEN_NOSPEC_H */ -+ -+/* -+ * Local variables: -+ * mode: C -+ * c-file-style: "BSD" -+ * c-basic-offset: 4 -+ * indent-tabs-mode: nil -+ * End: -+ */ -diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h -index 2541ecb04f..eaa83dc97e 100644 ---- a/xen/include/xen/sched.h -+++ b/xen/include/xen/sched.h -@@ -796,7 +796,7 @@ static inline struct domain *next_domain_in_cpupool( - #define _VPF_parked 8 - #define VPF_parked (1UL<<_VPF_parked) - --static inline int vcpu_runnable(struct vcpu *v) -+static inline bool vcpu_runnable(const struct vcpu *v) - { - return !(v->pause_flags | - atomic_read(&v->pause_count) | -diff --git a/xen/include/xen/tasklet.h b/xen/include/xen/tasklet.h -index 23d69c738e..bc9ddace6d 100644 ---- a/xen/include/xen/tasklet.h -+++ b/xen/include/xen/tasklet.h -@@ -50,6 +50,11 @@ static inline bool tasklet_work_to_do(unsigned int cpu) - TASKLET_scheduled); - } - -+static inline bool tasklet_is_scheduled(const struct tasklet *t) -+{ -+ return t->scheduled_on != -1; -+} -+ - void tasklet_schedule_on_cpu(struct tasklet *t, unsigned int cpu); - void tasklet_schedule(struct tasklet *t); - void do_tasklet(void); -diff --git a/xen/include/xen/xmalloc.h b/xen/include/xen/xmalloc.h -index cc2673d8ae..9aa5edf593 100644 ---- a/xen/include/xen/xmalloc.h -+++ b/xen/include/xen/xmalloc.h -@@ -26,6 +26,12 @@ - /* Free any of the above. */ - extern void xfree(void *); - -+/* Free an allocation, and zero the pointer to it. */ -+#define XFREE(p) do { \ -+ xfree(p); \ -+ (p) = NULL; \ -+} while ( false ) -+ - /* Underlying functions */ - extern void *_xmalloc(unsigned long size, unsigned long align); - extern void *_xzalloc(unsigned long size, unsigned long align); -diff --git a/xen/tools/gen-cpuid.py b/xen/tools/gen-cpuid.py -index 613b909c3d..65526ff120 100755 ---- a/xen/tools/gen-cpuid.py -+++ b/xen/tools/gen-cpuid.py -@@ -257,10 +257,19 @@ def crunch_numbers(state): - AVX512BW, AVX512VL, AVX512VBMI, AVX512_4VNNIW, - AVX512_4FMAPS, AVX512_VPOPCNTDQ], - -- # Single Thread Indirect Branch Predictors enumerates a new bit in the -- # MSR enumerated by Indirect Branch Restricted Speculation/Indirect -- # Branch Prediction Barrier enumeration. -- IBRSB: [STIBP], -+ # The features: -+ # * Single Thread Indirect Branch Predictors -+ # * Speculative Store Bypass Disable -+ # -+ # enumerate new bits in MSR_SPEC_CTRL, which is enumerated by Indirect -+ # Branch Restricted Speculation/Indirect Branch Prediction Barrier. -+ # -+ # In practice, these features also enumerate the presense of -+ # MSR_SPEC_CTRL. However, no real hardware will exist with SSBD but -+ # not IBRSB, and we pass this MSR directly to guests. Treating them -+ # as dependent features simplifies Xen's logic, and prevents the guest -+ # from seeing implausible configurations. -+ IBRSB: [STIBP, SSBD], - } - - deep_features = tuple(sorted(deps.keys())) |