[MODERATED] Re: [GIT pull] The Annoying Affair has No Excuses

Tyler Hicks <[email protected]> Mon, 11 Nov 2019 14:55:12 -0600
Newsgroups org.kernel.lore.historical-speck
Message-ID <20191111205512.GF28235@elm>
On 2019-11-11 21:49:18, speck for Thomas Gleixner wrote:
> 
> From: Thomas Gleixner <[email protected]>
> 
> Subject: [GIT pull] x86: TSX Async Abort and iTLB Multihit mitigations
> 
> Linus,
> 
> please pull the latest x86/pti git tree from:
> 
>    git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-pti-for-linus
> 
> up to:  012206a822a8: x86/speculation/taa: Fix printing of TAA_MSG_SMT on IBRS_ALL CPUs
> 
> to be published on Tuesday Nov. 12th, 2019 1700 UTC (0900 PTC)

Greg asked about the time in keybase last week and Intel said 18:00 UTC.

Tyler

> 
> The performance deterioration departement is not proud at all of presenting
> the seventh installment of speculation mitigations and hardware misfeature
> workarounds:
> 
>   1) TSX Async Abort (TAA) - 'The Annoying Affair'
> 
>      TAA is a hardware vulnerability that allows unprivileged speculative
>      access to data which is available in various CPU internal buffers by
>      using asynchronous aborts within an Intel TSX transactional region.
> 
>      The mitigation depends on a microcode update providing a new MSR which
>      allows to disable TSX in the CPU. CPUs which have no microcode update
>      can be mitigated by disabling TSX in the BIOS if the BIOS provides a
>      tunable.
> 
>      Newer CPUs will have a bit set which indicates that the CPU is not
>      vulnerable, but the MSR to disable TSX will be available nevertheless
>      as it is an architected MSR. That means the kernel provides the
>      ability to disable TSX on the kernel command line, which is useful as
>      TSX is a truly useful mechanism to accelerate side channel attacks of
>      all sorts.
> 
>   2) iITLB Multihit (NX) - 'No eXcuses'
> 
>      iTLB Multihit is an erratum where some Intel processors may incur a
>      machine check error, possibly resulting in an unrecoverable CPU
>      lockup, when an instruction fetch hits multiple entries in the
>      instruction TLB. This can occur when the page size is changed along
>      with either the physical address or cache type. A malicious guest
>      running on a virtualized system can exploit this erratum to perform a
>      denial of service attack.
> 
>      The workaround is that KVM marks huge pages in the extended page
>      tables as not executable (NX). If the guest attempts to execute in
>      such a page, the page is broken down into 4k pages which are marked
>      executable. The workaround comes with a mechanism to recover these
>      shattered huge pages over time.
> 
> Both issues come with full documentation in the hardware vulnerabilities
> section of the Linux kernel user's and administrator's guide.
> 
> Thanks to all patch authors and reviewers who had the extraordinary
> priviledge to be exposed to this nuisance.
> 
> Special thanks to Borislav Petkov for polishing the final TAA patch set and
> to Paolo Bonzini for shepherding the KVM iTLB workarounds and providing
> also the backports to stable kernels for those!
> 
> Thanks,
> 
> 	tglx
> 
> ------------------>
> Gomez Iglesias, Antonio (1):
>       Documentation: Add ITLB_MULTIHIT documentation
> 
> Josh Poimboeuf (1):
>       x86/speculation/taa: Fix printing of TAA_MSG_SMT on IBRS_ALL CPUs
> 
> Junaid Shahid (2):
>       kvm: Add helper function for creating VM worker threads
>       kvm: x86: mmu: Recovery of shattered NX large pages
> 
> Michal Hocko (1):
>       x86/tsx: Add config options to set tsx=on|off|auto
> 
> Paolo Bonzini (1):
>       kvm: mmu: ITLB_MULTIHIT mitigation
> 
> Pawan Gupta (9):
>       x86/msr: Add the IA32_TSX_CTRL MSR
>       x86/cpu: Add a helper function x86_read_arch_cap_msr()
>       x86/cpu: Add a "tsx=" cmdline option with TSX disabled by default
>       x86/speculation/taa: Add mitigation for TSX Async Abort
>       x86/speculation/taa: Add sysfs reporting for TSX Async Abort
>       kvm/x86: Export MDS_NO=0 to guests when TSX is enabled
>       x86/tsx: Add "auto" option to the tsx= cmdline parameter
>       x86/speculation/taa: Add documentation for TSX Async Abort
>       x86/cpu: Add Tremont to the cpu vulnerability whitelist
> 
> Tyler Hicks (1):
>       cpu/speculation: Uninline and export CPU mitigations helpers
> 
> Vineela Tummalapalli (1):
>       x86/bugs: Add ITLB_MULTIHIT bug infrastructure
> 
> 
>  Documentation/ABI/testing/sysfs-devices-system-cpu |   2 +
>  Documentation/admin-guide/hw-vuln/index.rst        |   2 +
>  Documentation/admin-guide/hw-vuln/multihit.rst     | 163 ++++++++++++
>  .../admin-guide/hw-vuln/tsx_async_abort.rst        | 276 +++++++++++++++++++++
>  Documentation/admin-guide/kernel-parameters.txt    |  92 +++++++
>  Documentation/x86/index.rst                        |   1 +
>  Documentation/x86/tsx_async_abort.rst              | 117 +++++++++
>  arch/x86/Kconfig                                   |  45 ++++
>  arch/x86/include/asm/cpufeatures.h                 |   2 +
>  arch/x86/include/asm/kvm_host.h                    |   6 +
>  arch/x86/include/asm/msr-index.h                   |  16 ++
>  arch/x86/include/asm/nospec-branch.h               |   4 +-
>  arch/x86/include/asm/processor.h                   |   7 +
>  arch/x86/kernel/cpu/Makefile                       |   2 +-
>  arch/x86/kernel/cpu/bugs.c                         | 159 +++++++++++-
>  arch/x86/kernel/cpu/common.c                       |  99 +++++---
>  arch/x86/kernel/cpu/cpu.h                          |  18 ++
>  arch/x86/kernel/cpu/intel.c                        |   5 +
>  arch/x86/kernel/cpu/tsx.c                          | 140 +++++++++++
>  arch/x86/kvm/mmu.c                                 | 270 +++++++++++++++++++-
>  arch/x86/kvm/mmu.h                                 |   4 +
>  arch/x86/kvm/paging_tmpl.h                         |  29 ++-
>  arch/x86/kvm/x86.c                                 |  39 +++
>  drivers/base/cpu.c                                 |  17 ++
>  include/linux/cpu.h                                |  30 +--
>  include/linux/kvm_host.h                           |   6 +
>  kernel/cpu.c                                       |  27 +-
>  virt/kvm/kvm_main.c                                | 112 +++++++++
>  28 files changed, 1613 insertions(+), 77 deletions(-)
>  create mode 100644 Documentation/admin-guide/hw-vuln/multihit.rst
>  create mode 100644 Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
>  create mode 100644 Documentation/x86/tsx_async_abort.rst
>  create mode 100644 arch/x86/kernel/cpu/tsx.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
> index 06d0931119cc..fc20cde63d1e 100644
> --- a/Documentation/ABI/testing/sysfs-devices-system-cpu
> +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
> @@ -486,6 +486,8 @@ What:		/sys/devices/system/cpu/vulnerabilities
>  		/sys/devices/system/cpu/vulnerabilities/spec_store_bypass
>  		/sys/devices/system/cpu/vulnerabilities/l1tf
>  		/sys/devices/system/cpu/vulnerabilities/mds
> +		/sys/devices/system/cpu/vulnerabilities/tsx_async_abort
> +		/sys/devices/system/cpu/vulnerabilities/itlb_multihit
>  Date:		January 2018
>  Contact:	Linux kernel mailing list <[email protected]>
>  Description:	Information about CPU vulnerabilities
> diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst
> index 49311f3da6f2..0795e3c2643f 100644
> --- a/Documentation/admin-guide/hw-vuln/index.rst
> +++ b/Documentation/admin-guide/hw-vuln/index.rst
> @@ -12,3 +12,5 @@ are configurable at compile, boot or run time.
>     spectre
>     l1tf
>     mds
> +   tsx_async_abort
> +   multihit.rst
> diff --git a/Documentation/admin-guide/hw-vuln/multihit.rst b/Documentation/admin-guide/hw-vuln/multihit.rst
> new file mode 100644
> index 000000000000..ba9988d8bce5
> --- /dev/null
> +++ b/Documentation/admin-guide/hw-vuln/multihit.rst
> @@ -0,0 +1,163 @@
> +iTLB multihit
> +=============
> +
> +iTLB multihit is an erratum where some processors may incur a machine check
> +error, possibly resulting in an unrecoverable CPU lockup, when an
> +instruction fetch hits multiple entries in the instruction TLB. This can
> +occur when the page size is changed along with either the physical address
> +or cache type. A malicious guest running on a virtualized system can
> +exploit this erratum to perform a denial of service attack.
> +
> +
> +Affected processors
> +-------------------
> +
> +Variations of this erratum are present on most Intel Core and Xeon processor
> +models. The erratum is not present on:
> +
> +   - non-Intel processors
> +
> +   - Some Atoms (Airmont, Bonnell, Goldmont, GoldmontPlus, Saltwell, Silvermont)
> +
> +   - Intel processors that have the PSCHANGE_MC_NO bit set in the
> +     IA32_ARCH_CAPABILITIES MSR.
> +
> +
> +Related CVEs
> +------------
> +
> +The following CVE entry is related to this issue:
> +
> +   ==============  =================================================
> +   CVE-2018-12207  Machine Check Error Avoidance on Page Size Change
> +   ==============  =================================================
> +
> +
> +Problem
> +-------
> +
> +Privileged software, including OS and virtual machine managers (VMM), are in
> +charge of memory management. A key component in memory management is the control
> +of the page tables. Modern processors use virtual memory, a technique that creates
> +the illusion of a very large memory for processors. This virtual space is split
> +into pages of a given size. Page tables translate virtual addresses to physical
> +addresses.
> +
> +To reduce latency when performing a virtual to physical address translation,
> +processors include a structure, called TLB, that caches recent translations.
> +There are separate TLBs for instruction (iTLB) and data (dTLB).
> +
> +Under this errata, instructions are fetched from a linear address translated
> +using a 4 KB translation cached in the iTLB. Privileged software modifies the
> +paging structure so that the same linear address using large page size (2 MB, 4
> +MB, 1 GB) with a different physical address or memory type.  After the page
> +structure modification but before the software invalidates any iTLB entries for
> +the linear address, a code fetch that happens on the same linear address may
> +cause a machine-check error which can result in a system hang or shutdown.
> +
> +
> +Attack scenarios
> +----------------
> +
> +Attacks against the iTLB multihit erratum can be mounted from malicious
> +guests in a virtualized system.
> +
> +
> +iTLB multihit system information
> +--------------------------------
> +
> +The Linux kernel provides a sysfs interface to enumerate the current iTLB
> +multihit status of the system:whether the system is vulnerable and which
> +mitigations are active. The relevant sysfs file is:
> +
> +/sys/devices/system/cpu/vulnerabilities/itlb_multihit
> +
> +The possible values in this file are:
> +
> +.. list-table::
> +
> +     * - Not affected
> +       - The processor is not vulnerable.
> +     * - KVM: Mitigation: Split huge pages
> +       - Software changes mitigate this issue.
> +     * - KVM: Vulnerable
> +       - The processor is vulnerable, but no mitigation enabled
> +
> +
> +Enumeration of the erratum
> +--------------------------------
> +
> +A new bit has been allocated in the IA32_ARCH_CAPABILITIES (PSCHANGE_MC_NO) msr
> +and will be set on CPU's which are mitigated against this issue.
> +
> +   =======================================   ===========   ===============================
> +   IA32_ARCH_CAPABILITIES MSR                Not present   Possibly vulnerable,check model
> +   IA32_ARCH_CAPABILITIES[PSCHANGE_MC_NO]    '0'           Likely vulnerable,check model
> +   IA32_ARCH_CAPABILITIES[PSCHANGE_MC_NO]    '1'           Not vulnerable
> +   =======================================   ===========   ===============================
> +
> +
> +Mitigation mechanism
> +-------------------------
> +
> +This erratum can be mitigated by restricting the use of large page sizes to
> +non-executable pages.  This forces all iTLB entries to be 4K, and removes
> +the possibility of multiple hits.
> +
> +In order to mitigate the vulnerability, KVM initially marks all huge pages
> +as non-executable. If the guest attempts to execute in one of those pages,
> +the page is broken down into 4K pages, which are then marked executable.
> +
> +If EPT is disabled or not available on the host, KVM is in control of TLB
> +flushes and the problematic situation cannot happen.  However, the shadow
> +EPT paging mechanism used by nested virtualization is vulnerable, because
> +the nested guest can trigger multiple iTLB hits by modifying its own
> +(non-nested) page tables.  For simplicity, KVM will make large pages
> +non-executable in all shadow paging modes.
> +
> +Mitigation control on the kernel command line and KVM - module parameter
> +------------------------------------------------------------------------
> +
> +The KVM hypervisor mitigation mechanism for marking huge pages as
> +non-executable can be controlled with a module parameter "nx_huge_pages=".
> +The kernel command line allows to control the iTLB multihit mitigations at
> +boot time with the option "kvm.nx_huge_pages=".
> +
> +The valid arguments for these options are:
> +
> +  ==========  ================================================================
> +  force       Mitigation is enabled. In this case, the mitigation implements
> +              non-executable huge pages in Linux kernel KVM module. All huge
> +              pages in the EPT are marked as non-executable.
> +              If a guest attempts to execute in one of those pages, the page is
> +              broken down into 4K pages, which are then marked executable.
> +
> +  off	      Mitigation is disabled.
> +
> +  auto        Enable mitigation only if the platform is affected and the kernel
> +              was not booted with the "mitigations=off" command line parameter.
> +	      This is the default option.
> +  ==========  ================================================================
> +
> +
> +Mitigation selection guide
> +--------------------------
> +
> +1. No virtualization in use
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +   The system is protected by the kernel unconditionally and no further
> +   action is required.
> +
> +2. Virtualization with trusted guests
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +   If the guest comes from a trusted source, you may assume that the guest will
> +   not attempt to maliciously exploit these errata and no further action is
> +   required.
> +
> +3. Virtualization with untrusted guests
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +   If the guest comes from an untrusted source, the guest host kernel will need
> +   to apply iTLB multihit mitigation via the kernel command line or kvm
> +   module parameter.
> diff --git a/Documentation/admin-guide/hw-vuln/tsx_async_abort.rst b/Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
> new file mode 100644
> index 000000000000..fddbd7579c53
> --- /dev/null
> +++ b/Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
> @@ -0,0 +1,276 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +TAA - TSX Asynchronous Abort
> +======================================
> +
> +TAA is a hardware vulnerability that allows unprivileged speculative access to
> +data which is available in various CPU internal buffers by using asynchronous
> +aborts within an Intel TSX transactional region.
> +
> +Affected processors
> +-------------------
> +
> +This vulnerability only affects Intel processors that support Intel
> +Transactional Synchronization Extensions (TSX) when the TAA_NO bit (bit 8)
> +is 0 in the IA32_ARCH_CAPABILITIES MSR.  On processors where the MDS_NO bit
> +(bit 5) is 0 in the IA32_ARCH_CAPABILITIES MSR, the existing MDS mitigations
> +also mitigate against TAA.
> +
> +Whether a processor is affected or not can be read out from the TAA
> +vulnerability file in sysfs. See :ref:`tsx_async_abort_sys_info`.
> +
> +Related CVEs
> +------------
> +
> +The following CVE entry is related to this TAA issue:
> +
> +   ==============  =====  ===================================================
> +   CVE-2019-11135  TAA    TSX Asynchronous Abort (TAA) condition on some
> +                          microprocessors utilizing speculative execution may
> +                          allow an authenticated user to potentially enable
> +                          information disclosure via a side channel with
> +                          local access.
> +   ==============  =====  ===================================================
> +
> +Problem
> +-------
> +
> +When performing store, load or L1 refill operations, processors write
> +data into temporary microarchitectural structures (buffers). The data in
> +those buffers can be forwarded to load operations as an optimization.
> +
> +Intel TSX is an extension to the x86 instruction set architecture that adds
> +hardware transactional memory support to improve performance of multi-threaded
> +software. TSX lets the processor expose and exploit concurrency hidden in an
> +application due to dynamically avoiding unnecessary synchronization.
> +
> +TSX supports atomic memory transactions that are either committed (success) or
> +aborted. During an abort, operations that happened within the transactional region
> +are rolled back. An asynchronous abort takes place, among other options, when a
> +different thread accesses a cache line that is also used within the transactional
> +region when that access might lead to a data race.
> +
> +Immediately after an uncompleted asynchronous abort, certain speculatively
> +executed loads may read data from those internal buffers and pass it to dependent
> +operations. This can be then used to infer the value via a cache side channel
> +attack.
> +
> +Because the buffers are potentially shared between Hyper-Threads cross
> +Hyper-Thread attacks are possible.
> +
> +The victim of a malicious actor does not need to make use of TSX. Only the
> +attacker needs to begin a TSX transaction and raise an asynchronous abort
> +which in turn potenitally leaks data stored in the buffers.
> +
> +More detailed technical information is available in the TAA specific x86
> +architecture section: :ref:`Documentation/x86/tsx_async_abort.rst <tsx_async_abort>`.
> +
> +
> +Attack scenarios
> +----------------
> +
> +Attacks against the TAA vulnerability can be implemented from unprivileged
> +applications running on hosts or guests.
> +
> +As for MDS, the attacker has no control over the memory addresses that can
> +be leaked. Only the victim is responsible for bringing data to the CPU. As
> +a result, the malicious actor has to sample as much data as possible and
> +then postprocess it to try to infer any useful information from it.
> +
> +A potential attacker only has read access to the data. Also, there is no direct
> +privilege escalation by using this technique.
> +
> +
> +.. _tsx_async_abort_sys_info:
> +
> +TAA system information
> +-----------------------
> +
> +The Linux kernel provides a sysfs interface to enumerate the current TAA status
> +of mitigated systems. The relevant sysfs file is:
> +
> +/sys/devices/system/cpu/vulnerabilities/tsx_async_abort
> +
> +The possible values in this file are:
> +
> +.. list-table::
> +
> +   * - 'Vulnerable'
> +     - The CPU is affected by this vulnerability and the microcode and kernel mitigation are not applied.
> +   * - 'Vulnerable: Clear CPU buffers attempted, no microcode'
> +     - The system tries to clear the buffers but the microcode might not support the operation.
> +   * - 'Mitigation: Clear CPU buffers'
> +     - The microcode has been updated to clear the buffers. TSX is still enabled.
> +   * - 'Mitigation: TSX disabled'
> +     - TSX is disabled.
> +   * - 'Not affected'
> +     - The CPU is not affected by this issue.
> +
> +.. _ucode_needed:
> +
> +Best effort mitigation mode
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +If the processor is vulnerable, but the availability of the microcode-based
> +mitigation mechanism is not advertised via CPUID the kernel selects a best
> +effort mitigation mode.  This mode invokes the mitigation instructions
> +without a guarantee that they clear the CPU buffers.
> +
> +This is done to address virtualization scenarios where the host has the
> +microcode update applied, but the hypervisor is not yet updated to expose the
> +CPUID to the guest. If the host has updated microcode the protection takes
> +effect; otherwise a few CPU cycles are wasted pointlessly.
> +
> +The state in the tsx_async_abort sysfs file reflects this situation
> +accordingly.
> +
> +
> +Mitigation mechanism
> +--------------------
> +
> +The kernel detects the affected CPUs and the presence of the microcode which is
> +required. If a CPU is affected and the microcode is available, then the kernel
> +enables the mitigation by default.
> +
> +
> +The mitigation can be controlled at boot time via a kernel command line option.
> +See :ref:`taa_mitigation_control_command_line`.
> +
> +.. _virt_mechanism:
> +
> +Virtualization mitigation
> +^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +Affected systems where the host has TAA microcode and TAA is mitigated by
> +having disabled TSX previously, are not vulnerable regardless of the status
> +of the VMs.
> +
> +In all other cases, if the host either does not have the TAA microcode or
> +the kernel is not mitigated, the system might be vulnerable.
> +
> +
> +.. _taa_mitigation_control_command_line:
> +
> +Mitigation control on the kernel command line
> +---------------------------------------------
> +
> +The kernel command line allows to control the TAA mitigations at boot time with
> +the option "tsx_async_abort=". The valid arguments for this option are:
> +
> +  ============  =============================================================
> +  off		This option disables the TAA mitigation on affected platforms.
> +                If the system has TSX enabled (see next parameter) and the CPU
> +                is affected, the system is vulnerable.
> +
> +  full	        TAA mitigation is enabled. If TSX is enabled, on an affected
> +                system it will clear CPU buffers on ring transitions. On
> +                systems which are MDS-affected and deploy MDS mitigation,
> +                TAA is also mitigated. Specifying this option on those
> +                systems will have no effect.
> +
> +  full,nosmt    The same as tsx_async_abort=full, with SMT disabled on
> +                vulnerable CPUs that have TSX enabled. This is the complete
> +                mitigation. When TSX is disabled, SMT is not disabled because
> +                CPU is not vulnerable to cross-thread TAA attacks.
> +  ============  =============================================================
> +
> +Not specifying this option is equivalent to "tsx_async_abort=full".
> +
> +The kernel command line also allows to control the TSX feature using the
> +parameter "tsx=" on CPUs which support TSX control. MSR_IA32_TSX_CTRL is used
> +to control the TSX feature and the enumeration of the TSX feature bits (RTM
> +and HLE) in CPUID.
> +
> +The valid options are:
> +
> +  ============  =============================================================
> +  off		Disables TSX on the system.
> +
> +                Note that this option takes effect only on newer CPUs which are
> +                not vulnerable to MDS, i.e., have MSR_IA32_ARCH_CAPABILITIES.MDS_NO=1
> +                and which get the new IA32_TSX_CTRL MSR through a microcode
> +                update. This new MSR allows for the reliable deactivation of
> +                the TSX functionality.
> +
> +  on		Enables TSX.
> +
> +                Although there are mitigations for all known security
> +                vulnerabilities, TSX has been known to be an accelerator for
> +                several previous speculation-related CVEs, and so there may be
> +                unknown security risks associated with leaving it enabled.
> +
> +  auto		Disables TSX if X86_BUG_TAA is present, otherwise enables TSX
> +                on the system.
> +  ============  =============================================================
> +
> +Not specifying this option is equivalent to "tsx=off".
> +
> +The following combinations of the "tsx_async_abort" and "tsx" are possible. For
> +affected platforms tsx=auto is equivalent to tsx=off and the result will be:
> +
> +  =========  ==========================   =========================================
> +  tsx=on     tsx_async_abort=full         The system will use VERW to clear CPU
> +                                          buffers. Cross-thread attacks are still
> +					  possible on SMT machines.
> +  tsx=on     tsx_async_abort=full,nosmt   As above, cross-thread attacks on SMT
> +                                          mitigated.
> +  tsx=on     tsx_async_abort=off          The system is vulnerable.
> +  tsx=off    tsx_async_abort=full         TSX might be disabled if microcode
> +                                          provides a TSX control MSR. If so,
> +					  system is not vulnerable.
> +  tsx=off    tsx_async_abort=full,nosmt   Ditto
> +  tsx=off    tsx_async_abort=off          ditto
> +  =========  ==========================   =========================================
> +
> +
> +For unaffected platforms "tsx=on" and "tsx_async_abort=full" does not clear CPU
> +buffers.  For platforms without TSX control (MSR_IA32_ARCH_CAPABILITIES.MDS_NO=0)
> +"tsx" command line argument has no effect.
> +
> +For the affected platforms below table indicates the mitigation status for the
> +combinations of CPUID bit MD_CLEAR and IA32_ARCH_CAPABILITIES MSR bits MDS_NO
> +and TSX_CTRL_MSR.
> +
> +  =======  =========  =============  ========================================
> +  MDS_NO   MD_CLEAR   TSX_CTRL_MSR   Status
> +  =======  =========  =============  ========================================
> +    0          0            0        Vulnerable (needs microcode)
> +    0          1            0        MDS and TAA mitigated via VERW
> +    1          1            0        MDS fixed, TAA vulnerable if TSX enabled
> +                                     because MD_CLEAR has no meaning and
> +                                     VERW is not guaranteed to clear buffers
> +    1          X            1        MDS fixed, TAA can be mitigated by
> +                                     VERW or TSX_CTRL_MSR
> +  =======  =========  =============  ========================================
> +
> +Mitigation selection guide
> +--------------------------
> +
> +1. Trusted userspace and guests
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +If all user space applications are from a trusted source and do not execute
> +untrusted code which is supplied externally, then the mitigation can be
> +disabled. The same applies to virtualized environments with trusted guests.
> +
> +
> +2. Untrusted userspace and guests
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +If there are untrusted applications or guests on the system, enabling TSX
> +might allow a malicious actor to leak data from the host or from other
> +processes running on the same physical core.
> +
> +If the microcode is available and the TSX is disabled on the host, attacks
> +are prevented in a virtualized environment as well, even if the VMs do not
> +explicitly enable the mitigation.
> +
> +
> +.. _taa_default_mitigations:
> +
> +Default mitigations
> +-------------------
> +
> +The kernel's default action for vulnerable processors is:
> +
> +  - Deploy TSX disable mitigation (tsx_async_abort=full tsx=off).
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index a84a83f8881e..8dee8f68fe15 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -2055,6 +2055,25 @@
>  			KVM MMU at runtime.
>  			Default is 0 (off)
>  
> +	kvm.nx_huge_pages=
> +			[KVM] Controls the software workaround for the
> +			X86_BUG_ITLB_MULTIHIT bug.
> +			force	: Always deploy workaround.
> +			off	: Never deploy workaround.
> +			auto    : Deploy workaround based on the presence of
> +				  X86_BUG_ITLB_MULTIHIT.
> +
> +			Default is 'auto'.
> +
> +			If the software workaround is enabled for the host,
> +			guests do need not to enable it for nested guests.
> +
> +	kvm.nx_huge_pages_recovery_ratio=
> +			[KVM] Controls how many 4KiB pages are periodically zapped
> +			back to huge pages.  0 disables the recovery, otherwise if
> +			the value is N KVM will zap 1/Nth of the 4KiB pages every
> +			minute.  The default is 60.
> +
>  	kvm-amd.nested=	[KVM,AMD] Allow nested virtualization in KVM/SVM.
>  			Default is 1 (enabled)
>  
> @@ -2636,6 +2655,13 @@
>  					       ssbd=force-off [ARM64]
>  					       l1tf=off [X86]
>  					       mds=off [X86]
> +					       tsx_async_abort=off [X86]
> +					       kvm.nx_huge_pages=off [X86]
> +
> +				Exceptions:
> +					       This does not have any effect on
> +					       kvm.nx_huge_pages when
> +					       kvm.nx_huge_pages=force.
>  
>  			auto (default)
>  				Mitigate all CPU vulnerabilities, but leave SMT
> @@ -2651,6 +2677,7 @@
>  				be fully mitigated, even if it means losing SMT.
>  				Equivalent to: l1tf=flush,nosmt [X86]
>  					       mds=full,nosmt [X86]
> +					       tsx_async_abort=full,nosmt [X86]
>  
>  	mminit_loglevel=
>  			[KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
> @@ -4848,6 +4875,71 @@
>  			interruptions from clocksource watchdog are not
>  			acceptable).
>  
> +	tsx=		[X86] Control Transactional Synchronization
> +			Extensions (TSX) feature in Intel processors that
> +			support TSX control.
> +
> +			This parameter controls the TSX feature. The options are:
> +
> +			on	- Enable TSX on the system. Although there are
> +				mitigations for all known security vulnerabilities,
> +				TSX has been known to be an accelerator for
> +				several previous speculation-related CVEs, and
> +				so there may be unknown	security risks associated
> +				with leaving it enabled.
> +
> +			off	- Disable TSX on the system. (Note that this
> +				option takes effect only on newer CPUs which are
> +				not vulnerable to MDS, i.e., have
> +				MSR_IA32_ARCH_CAPABILITIES.MDS_NO=1 and which get
> +				the new IA32_TSX_CTRL MSR through a microcode
> +				update. This new MSR allows for the reliable
> +				deactivation of the TSX functionality.)
> +
> +			auto	- Disable TSX if X86_BUG_TAA is present,
> +				  otherwise enable TSX on the system.
> +
> +			Not specifying this option is equivalent to tsx=off.
> +
> +			See Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
> +			for more details.
> +
> +	tsx_async_abort= [X86,INTEL] Control mitigation for the TSX Async
> +			Abort (TAA) vulnerability.
> +
> +			Similar to Micro-architectural Data Sampling (MDS)
> +			certain CPUs that support Transactional
> +			Synchronization Extensions (TSX) are vulnerable to an
> +			exploit against CPU internal buffers which can forward
> +			information to a disclosure gadget under certain
> +			conditions.
> +
> +			In vulnerable processors, the speculatively forwarded
> +			data can be used in a cache side channel attack, to
> +			access data to which the attacker does not have direct
> +			access.
> +
> +			This parameter controls the TAA mitigation.  The
> +			options are:
> +
> +			full       - Enable TAA mitigation on vulnerable CPUs
> +				     if TSX is enabled.
> +
> +			full,nosmt - Enable TAA mitigation and disable SMT on
> +				     vulnerable CPUs. If TSX is disabled, SMT
> +				     is not disabled because CPU is not
> +				     vulnerable to cross-thread TAA attacks.
> +			off        - Unconditionally disable TAA mitigation
> +
> +			Not specifying this option is equivalent to
> +			tsx_async_abort=full.  On CPUs which are MDS affected
> +			and deploy MDS mitigation, TAA mitigation is not
> +			required and doesn't provide any additional
> +			mitigation.
> +
> +			For details see:
> +			Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
> +
>  	turbografx.map[2|3]=	[HW,JOY]
>  			TurboGraFX parallel port interface
>  			Format:
> diff --git a/Documentation/x86/index.rst b/Documentation/x86/index.rst
> index af64c4bb4447..a8de2fbc1caa 100644
> --- a/Documentation/x86/index.rst
> +++ b/Documentation/x86/index.rst
> @@ -27,6 +27,7 @@ x86-specific Documentation
>     mds
>     microcode
>     resctrl_ui
> +   tsx_async_abort
>     usb-legacy-support
>     i386/index
>     x86_64/index
> diff --git a/Documentation/x86/tsx_async_abort.rst b/Documentation/x86/tsx_async_abort.rst
> new file mode 100644
> index 000000000000..583ddc185ba2
> --- /dev/null
> +++ b/Documentation/x86/tsx_async_abort.rst
> @@ -0,0 +1,117 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +TSX Async Abort (TAA) mitigation
> +================================
> +
> +.. _tsx_async_abort:
> +
> +Overview
> +--------
> +
> +TSX Async Abort (TAA) is a side channel attack on internal buffers in some
> +Intel processors similar to Microachitectural Data Sampling (MDS).  In this
> +case certain loads may speculatively pass invalid data to dependent operations
> +when an asynchronous abort condition is pending in a Transactional
> +Synchronization Extensions (TSX) transaction.  This includes loads with no
> +fault or assist condition. Such loads may speculatively expose stale data from
> +the same uarch data structures as in MDS, with same scope of exposure i.e.
> +same-thread and cross-thread. This issue affects all current processors that
> +support TSX.
> +
> +Mitigation strategy
> +-------------------
> +
> +a) TSX disable - one of the mitigations is to disable TSX. A new MSR
> +IA32_TSX_CTRL will be available in future and current processors after
> +microcode update which can be used to disable TSX. In addition, it
> +controls the enumeration of the TSX feature bits (RTM and HLE) in CPUID.
> +
> +b) Clear CPU buffers - similar to MDS, clearing the CPU buffers mitigates this
> +vulnerability. More details on this approach can be found in
> +:ref:`Documentation/admin-guide/hw-vuln/mds.rst <mds>`.
> +
> +Kernel internal mitigation modes
> +--------------------------------
> +
> + =============    ============================================================
> + off              Mitigation is disabled. Either the CPU is not affected or
> +                  tsx_async_abort=off is supplied on the kernel command line.
> +
> + tsx disabled     Mitigation is enabled. TSX feature is disabled by default at
> +                  bootup on processors that support TSX control.
> +
> + verw             Mitigation is enabled. CPU is affected and MD_CLEAR is
> +                  advertised in CPUID.
> +
> + ucode needed     Mitigation is enabled. CPU is affected and MD_CLEAR is not
> +                  advertised in CPUID. That is mainly for virtualization
> +                  scenarios where the host has the updated microcode but the
> +                  hypervisor does not expose MD_CLEAR in CPUID. It's a best
> +                  effort approach without guarantee.
> + =============    ============================================================
> +
> +If the CPU is affected and the "tsx_async_abort" kernel command line parameter is
> +not provided then the kernel selects an appropriate mitigation depending on the
> +status of RTM and MD_CLEAR CPUID bits.
> +
> +Below tables indicate the impact of tsx=on|off|auto cmdline options on state of
> +TAA mitigation, VERW behavior and TSX feature for various combinations of
> +MSR_IA32_ARCH_CAPABILITIES bits.
> +
> +1. "tsx=off"
> +
> +=========  =========  ============  ============  ==============  ===================  ======================
> +MSR_IA32_ARCH_CAPABILITIES bits     Result with cmdline tsx=off
> +----------------------------------  -------------------------------------------------------------------------
> +TAA_NO     MDS_NO     TSX_CTRL_MSR  TSX state     VERW can clear  TAA mitigation       TAA mitigation
> +                                    after bootup  CPU buffers     tsx_async_abort=off  tsx_async_abort=full
> +=========  =========  ============  ============  ==============  ===================  ======================
> +    0          0           0         HW default         Yes           Same as MDS           Same as MDS
> +    0          0           1        Invalid case   Invalid case       Invalid case          Invalid case
> +    0          1           0         HW default         No         Need ucode update     Need ucode update
> +    0          1           1          Disabled          Yes           TSX disabled          TSX disabled
> +    1          X           1          Disabled           X             None needed           None needed
> +=========  =========  ============  ============  ==============  ===================  ======================
> +
> +2. "tsx=on"
> +
> +=========  =========  ============  ============  ==============  ===================  ======================
> +MSR_IA32_ARCH_CAPABILITIES bits     Result with cmdline tsx=on
> +----------------------------------  -------------------------------------------------------------------------
> +TAA_NO     MDS_NO     TSX_CTRL_MSR  TSX state     VERW can clear  TAA mitigation       TAA mitigation
> +                                    after bootup  CPU buffers     tsx_async_abort=off  tsx_async_abort=full
> +=========  =========  ============  ============  ==============  ===================  ======================
> +    0          0           0         HW default        Yes            Same as MDS          Same as MDS
> +    0          0           1        Invalid case   Invalid case       Invalid case         Invalid case
> +    0          1           0         HW default        No          Need ucode update     Need ucode update
> +    0          1           1          Enabled          Yes               None              Same as MDS
> +    1          X           1          Enabled          X              None needed          None needed
> +=========  =========  ============  ============  ==============  ===================  ======================
> +
> +3. "tsx=auto"
> +
> +=========  =========  ============  ============  ==============  ===================  ======================
> +MSR_IA32_ARCH_CAPABILITIES bits     Result with cmdline tsx=auto
> +----------------------------------  -------------------------------------------------------------------------
> +TAA_NO     MDS_NO     TSX_CTRL_MSR  TSX state     VERW can clear  TAA mitigation       TAA mitigation
> +                                    after bootup  CPU buffers     tsx_async_abort=off  tsx_async_abort=full
> +=========  =========  ============  ============  ==============  ===================  ======================
> +    0          0           0         HW default    Yes                Same as MDS           Same as MDS
> +    0          0           1        Invalid case  Invalid case        Invalid case          Invalid case
> +    0          1           0         HW default    No              Need ucode update     Need ucode update
> +    0          1           1          Disabled      Yes               TSX disabled          TSX disabled
> +    1          X           1          Enabled       X                 None needed           None needed
> +=========  =========  ============  ============  ==============  ===================  ======================
> +
> +In the tables, TSX_CTRL_MSR is a new bit in MSR_IA32_ARCH_CAPABILITIES that
> +indicates whether MSR_IA32_TSX_CTRL is supported.
> +
> +There are two control bits in IA32_TSX_CTRL MSR:
> +
> +      Bit 0: When set it disables the Restricted Transactional Memory (RTM)
> +             sub-feature of TSX (will force all transactions to abort on the
> +             XBEGIN instruction).
> +
> +      Bit 1: When set it disables the enumeration of the RTM and HLE feature
> +             (i.e. it will make CPUID(EAX=7).EBX{bit4} and
> +             CPUID(EAX=7).EBX{bit11} read as 0).
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index d6e1faa28c58..8ef85139553f 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1940,6 +1940,51 @@ config X86_INTEL_MEMORY_PROTECTION_KEYS
>  
>  	  If unsure, say y.
>  
> +choice
> +	prompt "TSX enable mode"
> +	depends on CPU_SUP_INTEL
> +	default X86_INTEL_TSX_MODE_OFF
> +	help
> +	  Intel's TSX (Transactional Synchronization Extensions) feature
> +	  allows to optimize locking protocols through lock elision which
> +	  can lead to a noticeable performance boost.
> +
> +	  On the other hand it has been shown that TSX can be exploited
> +	  to form side channel attacks (e.g. TAA) and chances are there
> +	  will be more of those attacks discovered in the future.
> +
> +	  Therefore TSX is not enabled by default (aka tsx=off). An admin
> +	  might override this decision by tsx=on the command line parameter.
> +	  Even with TSX enabled, the kernel will attempt to enable the best
> +	  possible TAA mitigation setting depending on the microcode available
> +	  for the particular machine.
> +
> +	  This option allows to set the default tsx mode between tsx=on, =off
> +	  and =auto. See Documentation/admin-guide/kernel-parameters.txt for more
> +	  details.
> +
> +	  Say off if not sure, auto if TSX is in use but it should be used on safe
> +	  platforms or on if TSX is in use and the security aspect of tsx is not
> +	  relevant.
> +
> +config X86_INTEL_TSX_MODE_OFF
> +	bool "off"
> +	help
> +	  TSX is disabled if possible - equals to tsx=off command line parameter.
> +
> +config X86_INTEL_TSX_MODE_ON
> +	bool "on"
> +	help
> +	  TSX is always enabled on TSX capable HW - equals the tsx=on command
> +	  line parameter.
> +
> +config X86_INTEL_TSX_MODE_AUTO
> +	bool "auto"
> +	help
> +	  TSX is enabled on TSX capable HW that is believed to be safe against
> +	  side channel attacks- equals the tsx=auto command line parameter.
> +endchoice
> +
>  config EFI
>  	bool "EFI runtime service support"
>  	depends on ACPI
> diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
> index 0652d3eed9bd..c4fbe379cc0b 100644
> --- a/arch/x86/include/asm/cpufeatures.h
> +++ b/arch/x86/include/asm/cpufeatures.h
> @@ -399,5 +399,7 @@
>  #define X86_BUG_MDS			X86_BUG(19) /* CPU is affected by Microarchitectural data sampling */
>  #define X86_BUG_MSBDS_ONLY		X86_BUG(20) /* CPU is only affected by the  MSDBS variant of BUG_MDS */
>  #define X86_BUG_SWAPGS			X86_BUG(21) /* CPU is affected by speculation through SWAPGS */
> +#define X86_BUG_TAA			X86_BUG(22) /* CPU is affected by TSX Async Abort(TAA) */
> +#define X86_BUG_ITLB_MULTIHIT		X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
>  
>  #endif /* _ASM_X86_CPUFEATURES_H */
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 24d6598dea29..4fc61483919a 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -312,9 +312,12 @@ struct kvm_rmap_head {
>  struct kvm_mmu_page {
>  	struct list_head link;
>  	struct hlist_node hash_link;
> +	struct list_head lpage_disallowed_link;
> +
>  	bool unsync;
>  	u8 mmu_valid_gen;
>  	bool mmio_cached;
> +	bool lpage_disallowed; /* Can't be replaced by an equiv large page */
>  
>  	/*
>  	 * The following two entries are used to key the shadow page in the
> @@ -859,6 +862,7 @@ struct kvm_arch {
>  	 */
>  	struct list_head active_mmu_pages;
>  	struct list_head zapped_obsolete_pages;
> +	struct list_head lpage_disallowed_mmu_pages;
>  	struct kvm_page_track_notifier_node mmu_sp_tracker;
>  	struct kvm_page_track_notifier_head track_notifier_head;
>  
> @@ -933,6 +937,7 @@ struct kvm_arch {
>  	bool exception_payload_enabled;
>  
>  	struct kvm_pmu_event_filter *pmu_event_filter;
> +	struct task_struct *nx_lpage_recovery_thread;
>  };
>  
>  struct kvm_vm_stat {
> @@ -946,6 +951,7 @@ struct kvm_vm_stat {
>  	ulong mmu_unsync;
>  	ulong remote_tlb_flush;
>  	ulong lpages;
> +	ulong nx_lpage_splits;
>  	ulong max_mmu_page_hash_collisions;
>  };
>  
> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
> index 20ce682a2540..6a3124664289 100644
> --- a/arch/x86/include/asm/msr-index.h
> +++ b/arch/x86/include/asm/msr-index.h
> @@ -93,6 +93,18 @@
>  						  * Microarchitectural Data
>  						  * Sampling (MDS) vulnerabilities.
>  						  */
> +#define ARCH_CAP_PSCHANGE_MC_NO		BIT(6)	 /*
> +						  * The processor is not susceptible to a
> +						  * machine check error due to modifying the
> +						  * code page size along with either the
> +						  * physical address or cache type
> +						  * without TLB invalidation.
> +						  */
> +#define ARCH_CAP_TSX_CTRL_MSR		BIT(7)	/* MSR for TSX control is available. */
> +#define ARCH_CAP_TAA_NO			BIT(8)	/*
> +						 * Not susceptible to
> +						 * TSX Async Abort (TAA) vulnerabilities.
> +						 */
>  
>  #define MSR_IA32_FLUSH_CMD		0x0000010b
>  #define L1D_FLUSH			BIT(0)	/*
> @@ -103,6 +115,10 @@
>  #define MSR_IA32_BBL_CR_CTL		0x00000119
>  #define MSR_IA32_BBL_CR_CTL3		0x0000011e
>  
> +#define MSR_IA32_TSX_CTRL		0x00000122
> +#define TSX_CTRL_RTM_DISABLE		BIT(0)	/* Disable RTM feature */
> +#define TSX_CTRL_CPUID_CLEAR		BIT(1)	/* Disable TSX enumeration */
> +
>  #define MSR_IA32_SYSENTER_CS		0x00000174
>  #define MSR_IA32_SYSENTER_ESP		0x00000175
>  #define MSR_IA32_SYSENTER_EIP		0x00000176
> diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
> index 80bc209c0708..5c24a7b35166 100644
> --- a/arch/x86/include/asm/nospec-branch.h
> +++ b/arch/x86/include/asm/nospec-branch.h
> @@ -314,7 +314,7 @@ DECLARE_STATIC_KEY_FALSE(mds_idle_clear);
>  #include <asm/segment.h>
>  
>  /**
> - * mds_clear_cpu_buffers - Mitigation for MDS vulnerability
> + * mds_clear_cpu_buffers - Mitigation for MDS and TAA vulnerability
>   *
>   * This uses the otherwise unused and obsolete VERW instruction in
>   * combination with microcode which triggers a CPU buffer flush when the
> @@ -337,7 +337,7 @@ static inline void mds_clear_cpu_buffers(void)
>  }
>  
>  /**
> - * mds_user_clear_cpu_buffers - Mitigation for MDS vulnerability
> + * mds_user_clear_cpu_buffers - Mitigation for MDS and TAA vulnerability
>   *
>   * Clear CPU buffers if the corresponding static key is enabled
>   */
> diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
> index 6e0a3b43d027..54f5d54280f6 100644
> --- a/arch/x86/include/asm/processor.h
> +++ b/arch/x86/include/asm/processor.h
> @@ -988,4 +988,11 @@ enum mds_mitigations {
>  	MDS_MITIGATION_VMWERV,
>  };
>  
> +enum taa_mitigations {
> +	TAA_MITIGATION_OFF,
> +	TAA_MITIGATION_UCODE_NEEDED,
> +	TAA_MITIGATION_VERW,
> +	TAA_MITIGATION_TSX_DISABLED,
> +};
> +
>  #endif /* _ASM_X86_PROCESSOR_H */
> diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
> index d7a1e5a9331c..890f60083eca 100644
> --- a/arch/x86/kernel/cpu/Makefile
> +++ b/arch/x86/kernel/cpu/Makefile
> @@ -30,7 +30,7 @@ obj-$(CONFIG_PROC_FS)	+= proc.o
>  obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
>  
>  ifdef CONFIG_CPU_SUP_INTEL
> -obj-y			+= intel.o intel_pconfig.o
> +obj-y			+= intel.o intel_pconfig.o tsx.o
>  obj-$(CONFIG_PM)	+= intel_epb.o
>  endif
>  obj-$(CONFIG_CPU_SUP_AMD)		+= amd.o
> diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
> index 91c2561b905f..4c7b0fa15a19 100644
> --- a/arch/x86/kernel/cpu/bugs.c
> +++ b/arch/x86/kernel/cpu/bugs.c
> @@ -39,6 +39,7 @@ static void __init spectre_v2_select_mitigation(void);
>  static void __init ssb_select_mitigation(void);
>  static void __init l1tf_select_mitigation(void);
>  static void __init mds_select_mitigation(void);
> +static void __init taa_select_mitigation(void);
>  
>  /* The base value of the SPEC_CTRL MSR that always has to be preserved. */
>  u64 x86_spec_ctrl_base;
> @@ -105,6 +106,7 @@ void __init check_bugs(void)
>  	ssb_select_mitigation();
>  	l1tf_select_mitigation();
>  	mds_select_mitigation();
> +	taa_select_mitigation();
>  
>  	arch_smt_update();
>  
> @@ -268,6 +270,100 @@ static int __init mds_cmdline(char *str)
>  }
>  early_param("mds", mds_cmdline);
>  
> +#undef pr_fmt
> +#define pr_fmt(fmt)	"TAA: " fmt
> +
> +/* Default mitigation for TAA-affected CPUs */
> +static enum taa_mitigations taa_mitigation __ro_after_init = TAA_MITIGATION_VERW;
> +static bool taa_nosmt __ro_after_init;
> +
> +static const char * const taa_strings[] = {
> +	[TAA_MITIGATION_OFF]		= "Vulnerable",
> +	[TAA_MITIGATION_UCODE_NEEDED]	= "Vulnerable: Clear CPU buffers attempted, no microcode",
> +	[TAA_MITIGATION_VERW]		= "Mitigation: Clear CPU buffers",
> +	[TAA_MITIGATION_TSX_DISABLED]	= "Mitigation: TSX disabled",
> +};
> +
> +static void __init taa_select_mitigation(void)
> +{
> +	u64 ia32_cap;
> +
> +	if (!boot_cpu_has_bug(X86_BUG_TAA)) {
> +		taa_mitigation = TAA_MITIGATION_OFF;
> +		return;
> +	}
> +
> +	/* TSX previously disabled by tsx=off */
> +	if (!boot_cpu_has(X86_FEATURE_RTM)) {
> +		taa_mitigation = TAA_MITIGATION_TSX_DISABLED;
> +		goto out;
> +	}
> +
> +	if (cpu_mitigations_off()) {
> +		taa_mitigation = TAA_MITIGATION_OFF;
> +		return;
> +	}
> +
> +	/* TAA mitigation is turned off on the cmdline (tsx_async_abort=off) */
> +	if (taa_mitigation == TAA_MITIGATION_OFF)
> +		goto out;
> +
> +	if (boot_cpu_has(X86_FEATURE_MD_CLEAR))
> +		taa_mitigation = TAA_MITIGATION_VERW;
> +	else
> +		taa_mitigation = TAA_MITIGATION_UCODE_NEEDED;
> +
> +	/*
> +	 * VERW doesn't clear the CPU buffers when MD_CLEAR=1 and MDS_NO=1.
> +	 * A microcode update fixes this behavior to clear CPU buffers. It also
> +	 * adds support for MSR_IA32_TSX_CTRL which is enumerated by the
> +	 * ARCH_CAP_TSX_CTRL_MSR bit.
> +	 *
> +	 * On MDS_NO=1 CPUs if ARCH_CAP_TSX_CTRL_MSR is not set, microcode
> +	 * update is required.
> +	 */
> +	ia32_cap = x86_read_arch_cap_msr();
> +	if ( (ia32_cap & ARCH_CAP_MDS_NO) &&
> +	    !(ia32_cap & ARCH_CAP_TSX_CTRL_MSR))
> +		taa_mitigation = TAA_MITIGATION_UCODE_NEEDED;
> +
> +	/*
> +	 * TSX is enabled, select alternate mitigation for TAA which is
> +	 * the same as MDS. Enable MDS static branch to clear CPU buffers.
> +	 *
> +	 * For guests that can't determine whether the correct microcode is
> +	 * present on host, enable the mitigation for UCODE_NEEDED as well.
> +	 */
> +	static_branch_enable(&mds_user_clear);
> +
> +	if (taa_nosmt || cpu_mitigations_auto_nosmt())
> +		cpu_smt_disable(false);
> +
> +out:
> +	pr_info("%s\n", taa_strings[taa_mitigation]);
> +}
> +
> +static int __init tsx_async_abort_parse_cmdline(char *str)
> +{
> +	if (!boot_cpu_has_bug(X86_BUG_TAA))
> +		return 0;
> +
> +	if (!str)
> +		return -EINVAL;
> +
> +	if (!strcmp(str, "off")) {
> +		taa_mitigation = TAA_MITIGATION_OFF;
> +	} else if (!strcmp(str, "full")) {
> +		taa_mitigation = TAA_MITIGATION_VERW;
> +	} else if (!strcmp(str, "full,nosmt")) {
> +		taa_mitigation = TAA_MITIGATION_VERW;
> +		taa_nosmt = true;
> +	}
> +
> +	return 0;
> +}
> +early_param("tsx_async_abort", tsx_async_abort_parse_cmdline);
> +
>  #undef pr_fmt
>  #define pr_fmt(fmt)     "Spectre V1 : " fmt
>  
> @@ -786,13 +882,10 @@ static void update_mds_branch_idle(void)
>  }
>  
>  #define MDS_MSG_SMT "MDS CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html for more details.\n"
> +#define TAA_MSG_SMT "TAA CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/tsx_async_abort.html for more details.\n"
>  
>  void cpu_bugs_smt_update(void)
>  {
> -	/* Enhanced IBRS implies STIBP. No update required. */
> -	if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
> -		return;
> -
>  	mutex_lock(&spec_ctrl_mutex);
>  
>  	switch (spectre_v2_user) {
> @@ -819,6 +912,17 @@ void cpu_bugs_smt_update(void)
>  		break;
>  	}
>  
> +	switch (taa_mitigation) {
> +	case TAA_MITIGATION_VERW:
> +	case TAA_MITIGATION_UCODE_NEEDED:
> +		if (sched_smt_active())
> +			pr_warn_once(TAA_MSG_SMT);
> +		break;
> +	case TAA_MITIGATION_TSX_DISABLED:
> +	case TAA_MITIGATION_OFF:
> +		break;
> +	}
> +
>  	mutex_unlock(&spec_ctrl_mutex);
>  }
>  
> @@ -1149,6 +1253,9 @@ void x86_spec_ctrl_setup_ap(void)
>  		x86_amd_ssb_disable();
>  }
>  
> +bool itlb_multihit_kvm_mitigation;
> +EXPORT_SYMBOL_GPL(itlb_multihit_kvm_mitigation);
> +
>  #undef pr_fmt
>  #define pr_fmt(fmt)	"L1TF: " fmt
>  
> @@ -1304,11 +1411,24 @@ static ssize_t l1tf_show_state(char *buf)
>  		       l1tf_vmx_states[l1tf_vmx_mitigation],
>  		       sched_smt_active() ? "vulnerable" : "disabled");
>  }
> +
> +static ssize_t itlb_multihit_show_state(char *buf)
> +{
> +	if (itlb_multihit_kvm_mitigation)
> +		return sprintf(buf, "KVM: Mitigation: Split huge pages\n");
> +	else
> +		return sprintf(buf, "KVM: Vulnerable\n");
> +}
>  #else
>  static ssize_t l1tf_show_state(char *buf)
>  {
>  	return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG);
>  }
> +
> +static ssize_t itlb_multihit_show_state(char *buf)
> +{
> +	return sprintf(buf, "Processor vulnerable\n");
> +}
>  #endif
>  
>  static ssize_t mds_show_state(char *buf)
> @@ -1328,6 +1448,21 @@ static ssize_t mds_show_state(char *buf)
>  		       sched_smt_active() ? "vulnerable" : "disabled");
>  }
>  
> +static ssize_t tsx_async_abort_show_state(char *buf)
> +{
> +	if ((taa_mitigation == TAA_MITIGATION_TSX_DISABLED) ||
> +	    (taa_mitigation == TAA_MITIGATION_OFF))
> +		return sprintf(buf, "%s\n", taa_strings[taa_mitigation]);
> +
> +	if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
> +		return sprintf(buf, "%s; SMT Host state unknown\n",
> +			       taa_strings[taa_mitigation]);
> +	}
> +
> +	return sprintf(buf, "%s; SMT %s\n", taa_strings[taa_mitigation],
> +		       sched_smt_active() ? "vulnerable" : "disabled");
> +}
> +
>  static char *stibp_state(void)
>  {
>  	if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
> @@ -1398,6 +1533,12 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
>  	case X86_BUG_MDS:
>  		return mds_show_state(buf);
>  
> +	case X86_BUG_TAA:
> +		return tsx_async_abort_show_state(buf);
> +
> +	case X86_BUG_ITLB_MULTIHIT:
> +		return itlb_multihit_show_state(buf);
> +
>  	default:
>  		break;
>  	}
> @@ -1434,4 +1575,14 @@ ssize_t cpu_show_mds(struct device *dev, struct device_attribute *attr, char *bu
>  {
>  	return cpu_show_common(dev, attr, buf, X86_BUG_MDS);
>  }
> +
> +ssize_t cpu_show_tsx_async_abort(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	return cpu_show_common(dev, attr, buf, X86_BUG_TAA);
> +}
> +
> +ssize_t cpu_show_itlb_multihit(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	return cpu_show_common(dev, attr, buf, X86_BUG_ITLB_MULTIHIT);
> +}
>  #endif
> diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
> index 9ae7d1bcd4f4..fffe21945374 100644
> --- a/arch/x86/kernel/cpu/common.c
> +++ b/arch/x86/kernel/cpu/common.c
> @@ -1016,13 +1016,14 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
>  #endif
>  }
>  
> -#define NO_SPECULATION	BIT(0)
> -#define NO_MELTDOWN	BIT(1)
> -#define NO_SSB		BIT(2)
> -#define NO_L1TF		BIT(3)
> -#define NO_MDS		BIT(4)
> -#define MSBDS_ONLY	BIT(5)
> -#define NO_SWAPGS	BIT(6)
> +#define NO_SPECULATION		BIT(0)
> +#define NO_MELTDOWN		BIT(1)
> +#define NO_SSB			BIT(2)
> +#define NO_L1TF			BIT(3)
> +#define NO_MDS			BIT(4)
> +#define MSBDS_ONLY		BIT(5)
> +#define NO_SWAPGS		BIT(6)
> +#define NO_ITLB_MULTIHIT	BIT(7)
>  
>  #define VULNWL(_vendor, _family, _model, _whitelist)	\
>  	{ X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
> @@ -1043,27 +1044,27 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
>  	VULNWL(NSC,	5, X86_MODEL_ANY,	NO_SPECULATION),
>  
>  	/* Intel Family 6 */
> -	VULNWL_INTEL(ATOM_SALTWELL,		NO_SPECULATION),
> -	VULNWL_INTEL(ATOM_SALTWELL_TABLET,	NO_SPECULATION),
> -	VULNWL_INTEL(ATOM_SALTWELL_MID,		NO_SPECULATION),
> -	VULNWL_INTEL(ATOM_BONNELL,		NO_SPECULATION),
> -	VULNWL_INTEL(ATOM_BONNELL_MID,		NO_SPECULATION),
> -
> -	VULNWL_INTEL(ATOM_SILVERMONT,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
> -	VULNWL_INTEL(ATOM_SILVERMONT_D,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
> -	VULNWL_INTEL(ATOM_SILVERMONT_MID,	NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
> -	VULNWL_INTEL(ATOM_AIRMONT,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
> -	VULNWL_INTEL(XEON_PHI_KNL,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
> -	VULNWL_INTEL(XEON_PHI_KNM,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
> +	VULNWL_INTEL(ATOM_SALTWELL,		NO_SPECULATION | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_SALTWELL_TABLET,	NO_SPECULATION | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_SALTWELL_MID,		NO_SPECULATION | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_BONNELL,		NO_SPECULATION | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_BONNELL_MID,		NO_SPECULATION | NO_ITLB_MULTIHIT),
> +
> +	VULNWL_INTEL(ATOM_SILVERMONT,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_SILVERMONT_D,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_SILVERMONT_MID,	NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_AIRMONT,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(XEON_PHI_KNL,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(XEON_PHI_KNM,		NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
>  
>  	VULNWL_INTEL(CORE_YONAH,		NO_SSB),
>  
> -	VULNWL_INTEL(ATOM_AIRMONT_MID,		NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
> -	VULNWL_INTEL(ATOM_AIRMONT_NP,		NO_L1TF | NO_SWAPGS),
> +	VULNWL_INTEL(ATOM_AIRMONT_MID,		NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_AIRMONT_NP,		NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
>  
> -	VULNWL_INTEL(ATOM_GOLDMONT,		NO_MDS | NO_L1TF | NO_SWAPGS),
> -	VULNWL_INTEL(ATOM_GOLDMONT_D,		NO_MDS | NO_L1TF | NO_SWAPGS),
> -	VULNWL_INTEL(ATOM_GOLDMONT_PLUS,	NO_MDS | NO_L1TF | NO_SWAPGS),
> +	VULNWL_INTEL(ATOM_GOLDMONT,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_GOLDMONT_D,		NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_INTEL(ATOM_GOLDMONT_PLUS,	NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
>  
>  	/*
>  	 * Technically, swapgs isn't serializing on AMD (despite it previously
> @@ -1073,15 +1074,17 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
>  	 * good enough for our purposes.
>  	 */
>  
> +	VULNWL_INTEL(ATOM_TREMONT_D,		NO_ITLB_MULTIHIT),
> +
>  	/* AMD Family 0xf - 0x12 */
> -	VULNWL_AMD(0x0f,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
> -	VULNWL_AMD(0x10,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
> -	VULNWL_AMD(0x11,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
> -	VULNWL_AMD(0x12,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
> +	VULNWL_AMD(0x0f,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_AMD(0x10,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_AMD(0x11,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_AMD(0x12,	NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
>  
>  	/* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
> -	VULNWL_AMD(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS),
> -	VULNWL_HYGON(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS),
> +	VULNWL_AMD(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
> +	VULNWL_HYGON(X86_FAMILY_ANY,	NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT),
>  	{}
>  };
>  
> @@ -1092,19 +1095,30 @@ static bool __init cpu_matches(unsigned long which)
>  	return m && !!(m->driver_data & which);
>  }
>  
> -static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
> +u64 x86_read_arch_cap_msr(void)
>  {
>  	u64 ia32_cap = 0;
>  
> +	if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
> +		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap);
> +
> +	return ia32_cap;
> +}
> +
> +static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
> +{
> +	u64 ia32_cap = x86_read_arch_cap_msr();
> +
> +	/* Set ITLB_MULTIHIT bug if cpu is not in the whitelist and not mitigated */
> +	if (!cpu_matches(NO_ITLB_MULTIHIT) && !(ia32_cap & ARCH_CAP_PSCHANGE_MC_NO))
> +		setup_force_cpu_bug(X86_BUG_ITLB_MULTIHIT);
> +
>  	if (cpu_matches(NO_SPECULATION))
>  		return;
>  
>  	setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
>  	setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
>  
> -	if (cpu_has(c, X86_FEATURE_ARCH_CAPABILITIES))
> -		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap);
> -
>  	if (!cpu_matches(NO_SSB) && !(ia32_cap & ARCH_CAP_SSB_NO) &&
>  	   !cpu_has(c, X86_FEATURE_AMD_SSB_NO))
>  		setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS);
> @@ -1121,6 +1135,21 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
>  	if (!cpu_matches(NO_SWAPGS))
>  		setup_force_cpu_bug(X86_BUG_SWAPGS);
>  
> +	/*
> +	 * When the CPU is not mitigated for TAA (TAA_NO=0) set TAA bug when:
> +	 *	- TSX is supported or
> +	 *	- TSX_CTRL is present
> +	 *
> +	 * TSX_CTRL check is needed for cases when TSX could be disabled before
> +	 * the kernel boot e.g. kexec.
> +	 * TSX_CTRL check alone is not sufficient for cases when the microcode
> +	 * update is not present or running as guest that don't get TSX_CTRL.
> +	 */
> +	if (!(ia32_cap & ARCH_CAP_TAA_NO) &&
> +	    (cpu_has(c, X86_FEATURE_RTM) ||
> +	     (ia32_cap & ARCH_CAP_TSX_CTRL_MSR)))
> +		setup_force_cpu_bug(X86_BUG_TAA);
> +
>  	if (cpu_matches(NO_MELTDOWN))
>  		return;
>  
> @@ -1554,6 +1583,8 @@ void __init identify_boot_cpu(void)
>  #endif
>  	cpu_detect_tlb(&boot_cpu_data);
>  	setup_cr_pinning();
> +
> +	tsx_init();
>  }
>  
>  void identify_secondary_cpu(struct cpuinfo_x86 *c)
> diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h
> index c0e2407abdd6..38ab6e115eac 100644
> --- a/arch/x86/kernel/cpu/cpu.h
> +++ b/arch/x86/kernel/cpu/cpu.h
> @@ -44,6 +44,22 @@ struct _tlb_table {
>  extern const struct cpu_dev *const __x86_cpu_dev_start[],
>  			    *const __x86_cpu_dev_end[];
>  
> +#ifdef CONFIG_CPU_SUP_INTEL
> +enum tsx_ctrl_states {
> +	TSX_CTRL_ENABLE,
> +	TSX_CTRL_DISABLE,
> +	TSX_CTRL_NOT_SUPPORTED,
> +};
> +
> +extern __ro_after_init enum tsx_ctrl_states tsx_ctrl_state;
> +
> +extern void __init tsx_init(void);
> +extern void tsx_enable(void);
> +extern void tsx_disable(void);
> +#else
> +static inline void tsx_init(void) { }
> +#endif /* CONFIG_CPU_SUP_INTEL */
> +
>  extern void get_cpu_cap(struct cpuinfo_x86 *c);
>  extern void get_cpu_address_sizes(struct cpuinfo_x86 *c);
>  extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
> @@ -62,4 +78,6 @@ unsigned int aperfmperf_get_khz(int cpu);
>  
>  extern void x86_spec_ctrl_setup_ap(void);
>  
> +extern u64 x86_read_arch_cap_msr(void);
> +
>  #endif /* ARCH_X86_CPU_H */
> diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
> index c2fdc00df163..11d5c5950e2d 100644
> --- a/arch/x86/kernel/cpu/intel.c
> +++ b/arch/x86/kernel/cpu/intel.c
> @@ -762,6 +762,11 @@ static void init_intel(struct cpuinfo_x86 *c)
>  		detect_tme(c);
>  
>  	init_intel_misc_features(c);
> +
> +	if (tsx_ctrl_state == TSX_CTRL_ENABLE)
> +		tsx_enable();
> +	if (tsx_ctrl_state == TSX_CTRL_DISABLE)
> +		tsx_disable();
>  }
>  
>  #ifdef CONFIG_X86_32
> diff --git a/arch/x86/kernel/cpu/tsx.c b/arch/x86/kernel/cpu/tsx.c
> new file mode 100644
> index 000000000000..3e20d322bc98
> --- /dev/null
> +++ b/arch/x86/kernel/cpu/tsx.c
> @@ -0,0 +1,140 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intel Transactional Synchronization Extensions (TSX) control.
> + *
> + * Copyright (C) 2019 Intel Corporation
> + *
> + * Author:
> + *	Pawan Gupta <[email protected]>
> + */
> +
> +#include <linux/cpufeature.h>
> +
> +#include <asm/cmdline.h>
> +
> +#include "cpu.h"
> +
> +enum tsx_ctrl_states tsx_ctrl_state __ro_after_init = TSX_CTRL_NOT_SUPPORTED;
> +
> +void tsx_disable(void)
> +{
> +	u64 tsx;
> +
> +	rdmsrl(MSR_IA32_TSX_CTRL, tsx);
> +
> +	/* Force all transactions to immediately abort */
> +	tsx |= TSX_CTRL_RTM_DISABLE;
> +
> +	/*
> +	 * Ensure TSX support is not enumerated in CPUID.
> +	 * This is visible to userspace and will ensure they
> +	 * do not waste resources trying TSX transactions that
> +	 * will always abort.
> +	 */
> +	tsx |= TSX_CTRL_CPUID_CLEAR;
> +
> +	wrmsrl(MSR_IA32_TSX_CTRL, tsx);
> +}
> +
> +void tsx_enable(void)
> +{
> +	u64 tsx;
> +
> +	rdmsrl(MSR_IA32_TSX_CTRL, tsx);
> +
> +	/* Enable the RTM feature in the cpu */
> +	tsx &= ~TSX_CTRL_RTM_DISABLE;
> +
> +	/*
> +	 * Ensure TSX support is enumerated in CPUID.
> +	 * This is visible to userspace and will ensure they
> +	 * can enumerate and use the TSX feature.
> +	 */
> +	tsx &= ~TSX_CTRL_CPUID_CLEAR;
> +
> +	wrmsrl(MSR_IA32_TSX_CTRL, tsx);
> +}
> +
> +static bool __init tsx_ctrl_is_supported(void)
> +{
> +	u64 ia32_cap = x86_read_arch_cap_msr();
> +
> +	/*
> +	 * TSX is controlled via MSR_IA32_TSX_CTRL.  However, support for this
> +	 * MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
> +	 *
> +	 * TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
> +	 * microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
> +	 * bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
> +	 * MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
> +	 * tsx= cmdline requests will do nothing on CPUs without
> +	 * MSR_IA32_TSX_CTRL support.
> +	 */
> +	return !!(ia32_cap & ARCH_CAP_TSX_CTRL_MSR);
> +}
> +
> +static enum tsx_ctrl_states x86_get_tsx_auto_mode(void)
> +{
> +	if (boot_cpu_has_bug(X86_BUG_TAA))
> +		return TSX_CTRL_DISABLE;
> +
> +	return TSX_CTRL_ENABLE;
> +}
> +
> +void __init tsx_init(void)
> +{
> +	char arg[5] = {};
> +	int ret;
> +
> +	if (!tsx_ctrl_is_supported())
> +		return;
> +
> +	ret = cmdline_find_option(boot_command_line, "tsx", arg, sizeof(arg));
> +	if (ret >= 0) {
> +		if (!strcmp(arg, "on")) {
> +			tsx_ctrl_state = TSX_CTRL_ENABLE;
> +		} else if (!strcmp(arg, "off")) {
> +			tsx_ctrl_state = TSX_CTRL_DISABLE;
> +		} else if (!strcmp(arg, "auto")) {
> +			tsx_ctrl_state = x86_get_tsx_auto_mode();
> +		} else {
> +			tsx_ctrl_state = TSX_CTRL_DISABLE;
> +			pr_err("tsx: invalid option, defaulting to off\n");
> +		}
> +	} else {
> +		/* tsx= not provided */
> +		if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_AUTO))
> +			tsx_ctrl_state = x86_get_tsx_auto_mode();
> +		else if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_OFF))
> +			tsx_ctrl_state = TSX_CTRL_DISABLE;
> +		else
> +			tsx_ctrl_state = TSX_CTRL_ENABLE;
> +	}
> +
> +	if (tsx_ctrl_state == TSX_CTRL_DISABLE) {
> +		tsx_disable();
> +
> +		/*
> +		 * tsx_disable() will change the state of the
> +		 * RTM CPUID bit.  Clear it here since it is now
> +		 * expected to be not set.
> +		 */
> +		setup_clear_cpu_cap(X86_FEATURE_RTM);
> +	} else if (tsx_ctrl_state == TSX_CTRL_ENABLE) {
> +
> +		/*
> +		 * HW defaults TSX to be enabled at bootup.
> +		 * We may still need the TSX enable support
> +		 * during init for special cases like
> +		 * kexec after TSX is disabled.
> +		 */
> +		tsx_enable();
> +
> +		/*
> +		 * tsx_enable() will change the state of the
> +		 * RTM CPUID bit.  Force it here since it is now
> +		 * expected to be set.
> +		 */
> +		setup_force_cpu_cap(X86_FEATURE_RTM);
> +	}
> +}
> diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> index 24c23c66b226..529589a42afb 100644
> --- a/arch/x86/kvm/mmu.c
> +++ b/arch/x86/kvm/mmu.c
> @@ -37,6 +37,7 @@
>  #include <linux/uaccess.h>
>  #include <linux/hash.h>
>  #include <linux/kern_levels.h>
> +#include <linux/kthread.h>
>  
>  #include <asm/page.h>
>  #include <asm/pat.h>
> @@ -47,6 +48,30 @@
>  #include <asm/kvm_page_track.h>
>  #include "trace.h"
>  
> +extern bool itlb_multihit_kvm_mitigation;
> +
> +static int __read_mostly nx_huge_pages = -1;
> +static uint __read_mostly nx_huge_pages_recovery_ratio = 60;
> +
> +static int set_nx_huge_pages(const char *val, const struct kernel_param *kp);
> +static int set_nx_huge_pages_recovery_ratio(const char *val, const struct kernel_param *kp);
> +
> +static struct kernel_param_ops nx_huge_pages_ops = {
> +	.set = set_nx_huge_pages,
> +	.get = param_get_bool,
> +};
> +
> +static struct kernel_param_ops nx_huge_pages_recovery_ratio_ops = {
> +	.set = set_nx_huge_pages_recovery_ratio,
> +	.get = param_get_uint,
> +};
> +
> +module_param_cb(nx_huge_pages, &nx_huge_pages_ops, &nx_huge_pages, 0644);
> +__MODULE_PARM_TYPE(nx_huge_pages, "bool");
> +module_param_cb(nx_huge_pages_recovery_ratio, &nx_huge_pages_recovery_ratio_ops,
> +		&nx_huge_pages_recovery_ratio, 0644);
> +__MODULE_PARM_TYPE(nx_huge_pages_recovery_ratio, "uint");
> +
>  /*
>   * When setting this variable to true it enables Two-Dimensional-Paging
>   * where the hardware walks 2 page tables:
> @@ -352,6 +377,11 @@ static inline bool spte_ad_need_write_protect(u64 spte)
>  	return (spte & SPTE_SPECIAL_MASK) != SPTE_AD_ENABLED_MASK;
>  }
>  
> +static bool is_nx_huge_page_enabled(void)
> +{
> +	return READ_ONCE(nx_huge_pages);
> +}
> +
>  static inline u64 spte_shadow_accessed_mask(u64 spte)
>  {
>  	MMU_WARN_ON(is_mmio_spte(spte));
> @@ -1190,6 +1220,17 @@ static void account_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp)
>  	kvm_mmu_gfn_disallow_lpage(slot, gfn);
>  }
>  
> +static void account_huge_nx_page(struct kvm *kvm, struct kvm_mmu_page *sp)
> +{
> +	if (sp->lpage_disallowed)
> +		return;
> +
> +	++kvm->stat.nx_lpage_splits;
> +	list_add_tail(&sp->lpage_disallowed_link,
> +		      &kvm->arch.lpage_disallowed_mmu_pages);
> +	sp->lpage_disallowed = true;
> +}
> +
>  static void unaccount_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp)
>  {
>  	struct kvm_memslots *slots;
> @@ -1207,6 +1248,13 @@ static void unaccount_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp)
>  	kvm_mmu_gfn_allow_lpage(slot, gfn);
>  }
>  
> +static void unaccount_huge_nx_page(struct kvm *kvm, struct kvm_mmu_page *sp)
> +{
> +	--kvm->stat.nx_lpage_splits;
> +	sp->lpage_disallowed = false;
> +	list_del(&sp->lpage_disallowed_link);
> +}
> +
>  static bool __mmu_gfn_lpage_is_disallowed(gfn_t gfn, int level,
>  					  struct kvm_memory_slot *slot)
>  {
> @@ -2792,6 +2840,9 @@ static bool __kvm_mmu_prepare_zap_page(struct kvm *kvm,
>  			kvm_reload_remote_mmus(kvm);
>  	}
>  
> +	if (sp->lpage_disallowed)
> +		unaccount_huge_nx_page(kvm, sp);
> +
>  	sp->role.invalid = 1;
>  	return list_unstable;
>  }
> @@ -3013,6 +3064,11 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
>  	if (!speculative)
>  		spte |= spte_shadow_accessed_mask(spte);
>  
> +	if (level > PT_PAGE_TABLE_LEVEL && (pte_access & ACC_EXEC_MASK) &&
> +	    is_nx_huge_page_enabled()) {
> +		pte_access &= ~ACC_EXEC_MASK;
> +	}
> +
>  	if (pte_access & ACC_EXEC_MASK)
>  		spte |= shadow_x_mask;
>  	else
> @@ -3233,9 +3289,32 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
>  	__direct_pte_prefetch(vcpu, sp, sptep);
>  }
>  
> +static void disallowed_hugepage_adjust(struct kvm_shadow_walk_iterator it,
> +				       gfn_t gfn, kvm_pfn_t *pfnp, int *levelp)
> +{
> +	int level = *levelp;
> +	u64 spte = *it.sptep;
> +
> +	if (it.level == level && level > PT_PAGE_TABLE_LEVEL &&
> +	    is_nx_huge_page_enabled() &&
> +	    is_shadow_present_pte(spte) &&
> +	    !is_large_pte(spte)) {
> +		/*
> +		 * A small SPTE exists for this pfn, but FNAME(fetch)
> +		 * and __direct_map would like to create a large PTE
> +		 * instead: just force them to go down another level,
> +		 * patching back for them into pfn the next 9 bits of
> +		 * the address.
> +		 */
> +		u64 page_mask = KVM_PAGES_PER_HPAGE(level) - KVM_PAGES_PER_HPAGE(level - 1);
> +		*pfnp |= gfn & page_mask;
> +		(*levelp)--;
> +	}
> +}
> +
>  static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, int write,
>  			int map_writable, int level, kvm_pfn_t pfn,
> -			bool prefault)
> +			bool prefault, bool lpage_disallowed)
>  {
>  	struct kvm_shadow_walk_iterator it;
>  	struct kvm_mmu_page *sp;
> @@ -3248,6 +3327,12 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, int write,
>  
>  	trace_kvm_mmu_spte_requested(gpa, level, pfn);
>  	for_each_shadow_entry(vcpu, gpa, it) {
> +		/*
> +		 * We cannot overwrite existing page tables with an NX
> +		 * large page, as the leaf could be executable.
> +		 */
> +		disallowed_hugepage_adjust(it, gfn, &pfn, &level);
> +
>  		base_gfn = gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
>  		if (it.level == level)
>  			break;
> @@ -3258,6 +3343,8 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, int write,
>  					      it.level - 1, true, ACC_ALL);
>  
>  			link_shadow_page(vcpu, it.sptep, sp);
> +			if (lpage_disallowed)
> +				account_huge_nx_page(vcpu->kvm, sp);
>  		}
>  	}
>  
> @@ -3550,11 +3637,14 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
>  {
>  	int r;
>  	int level;
> -	bool force_pt_level = false;
> +	bool force_pt_level;
>  	kvm_pfn_t pfn;
>  	unsigned long mmu_seq;
>  	bool map_writable, write = error_code & PFERR_WRITE_MASK;
> +	bool lpage_disallowed = (error_code & PFERR_FETCH_MASK) &&
> +				is_nx_huge_page_enabled();
>  
> +	force_pt_level = lpage_disallowed;
>  	level = mapping_level(vcpu, gfn, &force_pt_level);
>  	if (likely(!force_pt_level)) {
>  		/*
> @@ -3588,7 +3678,8 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
>  		goto out_unlock;
>  	if (likely(!force_pt_level))
>  		transparent_hugepage_adjust(vcpu, gfn, &pfn, &level);
> -	r = __direct_map(vcpu, v, write, map_writable, level, pfn, prefault);
> +	r = __direct_map(vcpu, v, write, map_writable, level, pfn,
> +			 prefault, false);
>  out_unlock:
>  	spin_unlock(&vcpu->kvm->mmu_lock);
>  	kvm_release_pfn_clean(pfn);
> @@ -4174,6 +4265,8 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
>  	unsigned long mmu_seq;
>  	int write = error_code & PFERR_WRITE_MASK;
>  	bool map_writable;
> +	bool lpage_disallowed = (error_code & PFERR_FETCH_MASK) &&
> +				is_nx_huge_page_enabled();
>  
>  	MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu->root_hpa));
>  
> @@ -4184,8 +4277,9 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
>  	if (r)
>  		return r;
>  
> -	force_pt_level = !check_hugepage_cache_consistency(vcpu, gfn,
> -							   PT_DIRECTORY_LEVEL);
> +	force_pt_level =
> +		lpage_disallowed ||
> +		!check_hugepage_cache_consistency(vcpu, gfn, PT_DIRECTORY_LEVEL);
>  	level = mapping_level(vcpu, gfn, &force_pt_level);
>  	if (likely(!force_pt_level)) {
>  		if (level > PT_DIRECTORY_LEVEL &&
> @@ -4214,7 +4308,8 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
>  		goto out_unlock;
>  	if (likely(!force_pt_level))
>  		transparent_hugepage_adjust(vcpu, gfn, &pfn, &level);
> -	r = __direct_map(vcpu, gpa, write, map_writable, level, pfn, prefault);
> +	r = __direct_map(vcpu, gpa, write, map_writable, level, pfn,
> +			 prefault, lpage_disallowed);
>  out_unlock:
>  	spin_unlock(&vcpu->kvm->mmu_lock);
>  	kvm_release_pfn_clean(pfn);
> @@ -6155,10 +6250,60 @@ static void kvm_set_mmio_spte_mask(void)
>  	kvm_mmu_set_mmio_spte_mask(mask, mask, ACC_WRITE_MASK | ACC_USER_MASK);
>  }
>  
> +static bool get_nx_auto_mode(void)
> +{
> +	/* Return true when CPU has the bug, and mitigations are ON */
> +	return boot_cpu_has_bug(X86_BUG_ITLB_MULTIHIT) && !cpu_mitigations_off();
> +}
> +
> +static void __set_nx_huge_pages(bool val)
> +{
> +	nx_huge_pages = itlb_multihit_kvm_mitigation = val;
> +}
> +
> +static int set_nx_huge_pages(const char *val, const struct kernel_param *kp)
> +{
> +	bool old_val = nx_huge_pages;
> +	bool new_val;
> +
> +	/* In "auto" mode deploy workaround only if CPU has the bug. */
> +	if (sysfs_streq(val, "off"))
> +		new_val = 0;
> +	else if (sysfs_streq(val, "force"))
> +		new_val = 1;
> +	else if (sysfs_streq(val, "auto"))
> +		new_val = get_nx_auto_mode();
> +	else if (strtobool(val, &new_val) < 0)
> +		return -EINVAL;
> +
> +	__set_nx_huge_pages(new_val);
> +
> +	if (new_val != old_val) {
> +		struct kvm *kvm;
> +		int idx;
> +
> +		mutex_lock(&kvm_lock);
> +
> +		list_for_each_entry(kvm, &vm_list, vm_list) {
> +			idx = srcu_read_lock(&kvm->srcu);
> +			kvm_mmu_zap_all_fast(kvm);
> +			srcu_read_unlock(&kvm->srcu, idx);
> +
> +			wake_up_process(kvm->arch.nx_lpage_recovery_thread);
> +		}
> +		mutex_unlock(&kvm_lock);
> +	}
> +
> +	return 0;
> +}
> +
>  int kvm_mmu_module_init(void)
>  {
>  	int ret = -ENOMEM;
>  
> +	if (nx_huge_pages == -1)
> +		__set_nx_huge_pages(get_nx_auto_mode());
> +
>  	/*
>  	 * MMU roles use union aliasing which is, generally speaking, an
>  	 * undefined behavior. However, we supposedly know how compilers behave
> @@ -6238,3 +6383,116 @@ void kvm_mmu_module_exit(void)
>  	unregister_shrinker(&mmu_shrinker);
>  	mmu_audit_disable();
>  }
> +
> +static int set_nx_huge_pages_recovery_ratio(const char *val, const struct kernel_param *kp)
> +{
> +	unsigned int old_val;
> +	int err;
> +
> +	old_val = nx_huge_pages_recovery_ratio;
> +	err = param_set_uint(val, kp);
> +	if (err)
> +		return err;
> +
> +	if (READ_ONCE(nx_huge_pages) &&
> +	    !old_val && nx_huge_pages_recovery_ratio) {
> +		struct kvm *kvm;
> +
> +		mutex_lock(&kvm_lock);
> +
> +		list_for_each_entry(kvm, &vm_list, vm_list)
> +			wake_up_process(kvm->arch.nx_lpage_recovery_thread);
> +
> +		mutex_unlock(&kvm_lock);
> +	}
> +
> +	return err;
> +}
> +
> +static void kvm_recover_nx_lpages(struct kvm *kvm)
> +{
> +	int rcu_idx;
> +	struct kvm_mmu_page *sp;
> +	unsigned int ratio;
> +	LIST_HEAD(invalid_list);
> +	ulong to_zap;
> +
> +	rcu_idx = srcu_read_lock(&kvm->srcu);
> +	spin_lock(&kvm->mmu_lock);
> +
> +	ratio = READ_ONCE(nx_huge_pages_recovery_ratio);
> +	to_zap = ratio ? DIV_ROUND_UP(kvm->stat.nx_lpage_splits, ratio) : 0;
> +	while (to_zap && !list_empty(&kvm->arch.lpage_disallowed_mmu_pages)) {
> +		/*
> +		 * We use a separate list instead of just using active_mmu_pages
> +		 * because the number of lpage_disallowed pages is expected to
> +		 * be relatively small compared to the total.
> +		 */
> +		sp = list_first_entry(&kvm->arch.lpage_disallowed_mmu_pages,
> +				      struct kvm_mmu_page,
> +				      lpage_disallowed_link);
> +		WARN_ON_ONCE(!sp->lpage_disallowed);
> +		kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
> +		WARN_ON_ONCE(sp->lpage_disallowed);
> +
> +		if (!--to_zap || need_resched() || spin_needbreak(&kvm->mmu_lock)) {
> +			kvm_mmu_commit_zap_page(kvm, &invalid_list);
> +			if (to_zap)
> +				cond_resched_lock(&kvm->mmu_lock);
> +		}
> +	}
> +
> +	spin_unlock(&kvm->mmu_lock);
> +	srcu_read_unlock(&kvm->srcu, rcu_idx);
> +}
> +
> +static long get_nx_lpage_recovery_timeout(u64 start_time)
> +{
> +	return READ_ONCE(nx_huge_pages) && READ_ONCE(nx_huge_pages_recovery_ratio)
> +		? start_time + 60 * HZ - get_jiffies_64()
> +		: MAX_SCHEDULE_TIMEOUT;
> +}
> +
> +static int kvm_nx_lpage_recovery_worker(struct kvm *kvm, uintptr_t data)
> +{
> +	u64 start_time;
> +	long remaining_time;
> +
> +	while (true) {
> +		start_time = get_jiffies_64();
> +		remaining_time = get_nx_lpage_recovery_timeout(start_time);
> +
> +		set_current_state(TASK_INTERRUPTIBLE);
> +		while (!kthread_should_stop() && remaining_time > 0) {
> +			schedule_timeout(remaining_time);
> +			remaining_time = get_nx_lpage_recovery_timeout(start_time);
> +			set_current_state(TASK_INTERRUPTIBLE);
> +		}
> +
> +		set_current_state(TASK_RUNNING);
> +
> +		if (kthread_should_stop())
> +			return 0;
> +
> +		kvm_recover_nx_lpages(kvm);
> +	}
> +}
> +
> +int kvm_mmu_post_init_vm(struct kvm *kvm)
> +{
> +	int err;
> +
> +	err = kvm_vm_create_worker_thread(kvm, kvm_nx_lpage_recovery_worker, 0,
> +					  "kvm-nx-lpage-recovery",
> +					  &kvm->arch.nx_lpage_recovery_thread);
> +	if (!err)
> +		kthread_unpark(kvm->arch.nx_lpage_recovery_thread);
> +
> +	return err;
> +}
> +
> +void kvm_mmu_pre_destroy_vm(struct kvm *kvm)
> +{
> +	if (kvm->arch.nx_lpage_recovery_thread)
> +		kthread_stop(kvm->arch.nx_lpage_recovery_thread);
> +}
> diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
> index 11f8ec89433b..d55674f44a18 100644
> --- a/arch/x86/kvm/mmu.h
> +++ b/arch/x86/kvm/mmu.h
> @@ -210,4 +210,8 @@ void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
>  bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
>  				    struct kvm_memory_slot *slot, u64 gfn);
>  int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu);
> +
> +int kvm_mmu_post_init_vm(struct kvm *kvm);
> +void kvm_mmu_pre_destroy_vm(struct kvm *kvm);
> +
>  #endif
> diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
> index 7d5cdb3af594..97b21e7fd013 100644
> --- a/arch/x86/kvm/paging_tmpl.h
> +++ b/arch/x86/kvm/paging_tmpl.h
> @@ -614,13 +614,14 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
>  static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
>  			 struct guest_walker *gw,
>  			 int write_fault, int hlevel,
> -			 kvm_pfn_t pfn, bool map_writable, bool prefault)
> +			 kvm_pfn_t pfn, bool map_writable, bool prefault,
> +			 bool lpage_disallowed)
>  {
>  	struct kvm_mmu_page *sp = NULL;
>  	struct kvm_shadow_walk_iterator it;
>  	unsigned direct_access, access = gw->pt_access;
>  	int top_level, ret;
> -	gfn_t base_gfn;
> +	gfn_t gfn, base_gfn;
>  
>  	direct_access = gw->pte_access;
>  
> @@ -665,13 +666,25 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
>  			link_shadow_page(vcpu, it.sptep, sp);
>  	}
>  
> -	base_gfn = gw->gfn;
> +	/*
> +	 * FNAME(page_fault) might have clobbered the bottom bits of
> +	 * gw->gfn, restore them from the virtual address.
> +	 */
> +	gfn = gw->gfn | ((addr & PT_LVL_OFFSET_MASK(gw->level)) >> PAGE_SHIFT);
> +	base_gfn = gfn;
>  
>  	trace_kvm_mmu_spte_requested(addr, gw->level, pfn);
>  
>  	for (; shadow_walk_okay(&it); shadow_walk_next(&it)) {
>  		clear_sp_write_flooding_count(it.sptep);
> -		base_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
> +
> +		/*
> +		 * We cannot overwrite existing page tables with an NX
> +		 * large page, as the leaf could be executable.
> +		 */
> +		disallowed_hugepage_adjust(it, gfn, &pfn, &hlevel);
> +
> +		base_gfn = gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
>  		if (it.level == hlevel)
>  			break;
>  
> @@ -683,6 +696,8 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
>  			sp = kvm_mmu_get_page(vcpu, base_gfn, addr,
>  					      it.level - 1, true, direct_access);
>  			link_shadow_page(vcpu, it.sptep, sp);
> +			if (lpage_disallowed)
> +				account_huge_nx_page(vcpu->kvm, sp);
>  		}
>  	}
>  
> @@ -759,9 +774,11 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
>  	int r;
>  	kvm_pfn_t pfn;
>  	int level = PT_PAGE_TABLE_LEVEL;
> -	bool force_pt_level = false;
>  	unsigned long mmu_seq;
>  	bool map_writable, is_self_change_mapping;
> +	bool lpage_disallowed = (error_code & PFERR_FETCH_MASK) &&
> +				is_nx_huge_page_enabled();
> +	bool force_pt_level = lpage_disallowed;
>  
>  	pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
>  
> @@ -851,7 +868,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
>  	if (!force_pt_level)
>  		transparent_hugepage_adjust(vcpu, walker.gfn, &pfn, &level);
>  	r = FNAME(fetch)(vcpu, addr, &walker, write_fault,
> -			 level, pfn, map_writable, prefault);
> +			 level, pfn, map_writable, prefault, lpage_disallowed);
>  	kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
>  
>  out_unlock:
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index ff395f812719..a30e9962a6ef 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -213,6 +213,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
>  	{ "mmu_unsync", VM_STAT(mmu_unsync) },
>  	{ "remote_tlb_flush", VM_STAT(remote_tlb_flush) },
>  	{ "largepages", VM_STAT(lpages, .mode = 0444) },
> +	{ "nx_largepages_splitted", VM_STAT(nx_lpage_splits, .mode = 0444) },
>  	{ "max_mmu_page_hash_collisions",
>  		VM_STAT(max_mmu_page_hash_collisions) },
>  	{ NULL }
> @@ -1279,6 +1280,14 @@ static u64 kvm_get_arch_capabilities(void)
>  	if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES))
>  		rdmsrl(MSR_IA32_ARCH_CAPABILITIES, data);
>  
> +	/*
> +	 * If nx_huge_pages is enabled, KVM's shadow paging will ensure that
> +	 * the nested hypervisor runs with NX huge pages.  If it is not,
> +	 * L1 is anyway vulnerable to ITLB_MULTIHIT explots from other
> +	 * L1 guests, so it need not worry about its own (L2) guests.
> +	 */
> +	data |= ARCH_CAP_PSCHANGE_MC_NO;
> +
>  	/*
>  	 * If we're doing cache flushes (either "always" or "cond")
>  	 * we will do one whenever the guest does a vmlaunch/vmresume.
> @@ -1298,6 +1307,25 @@ static u64 kvm_get_arch_capabilities(void)
>  	if (!boot_cpu_has_bug(X86_BUG_MDS))
>  		data |= ARCH_CAP_MDS_NO;
>  
> +	/*
> +	 * On TAA affected systems, export MDS_NO=0 when:
> +	 *	- TSX is enabled on the host, i.e. X86_FEATURE_RTM=1.
> +	 *	- Updated microcode is present. This is detected by
> +	 *	  the presence of ARCH_CAP_TSX_CTRL_MSR and ensures
> +	 *	  that VERW clears CPU buffers.
> +	 *
> +	 * When MDS_NO=0 is exported, guests deploy clear CPU buffer
> +	 * mitigation and don't complain:
> +	 *
> +	 *	"Vulnerable: Clear CPU buffers attempted, no microcode"
> +	 *
> +	 * If TSX is disabled on the system, guests are also mitigated against
> +	 * TAA and clear CPU buffer mitigation is not required for guests.
> +	 */
> +	if (boot_cpu_has_bug(X86_BUG_TAA) && boot_cpu_has(X86_FEATURE_RTM) &&
> +	    (data & ARCH_CAP_TSX_CTRL_MSR))
> +		data &= ~ARCH_CAP_MDS_NO;
> +
>  	return data;
>  }
>  
> @@ -9428,6 +9456,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>  	INIT_HLIST_HEAD(&kvm->arch.mask_notifier_list);
>  	INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
>  	INIT_LIST_HEAD(&kvm->arch.zapped_obsolete_pages);
> +	INIT_LIST_HEAD(&kvm->arch.lpage_disallowed_mmu_pages);
>  	INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
>  	atomic_set(&kvm->arch.noncoherent_dma_count, 0);
>  
> @@ -9456,6 +9485,11 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>  	return kvm_x86_ops->vm_init(kvm);
>  }
>  
> +int kvm_arch_post_init_vm(struct kvm *kvm)
> +{
> +	return kvm_mmu_post_init_vm(kvm);
> +}
> +
>  static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
>  {
>  	vcpu_load(vcpu);
> @@ -9557,6 +9591,11 @@ int x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size)
>  }
>  EXPORT_SYMBOL_GPL(x86_set_memory_region);
>  
> +void kvm_arch_pre_destroy_vm(struct kvm *kvm)
> +{
> +	kvm_mmu_pre_destroy_vm(kvm);
> +}
> +
>  void kvm_arch_destroy_vm(struct kvm *kvm)
>  {
>  	if (current->mm == kvm->mm) {
> diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
> index cc37511de866..6265871a4af2 100644
> --- a/drivers/base/cpu.c
> +++ b/drivers/base/cpu.c
> @@ -554,12 +554,27 @@ ssize_t __weak cpu_show_mds(struct device *dev,
>  	return sprintf(buf, "Not affected\n");
>  }
>  
> +ssize_t __weak cpu_show_tsx_async_abort(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	return sprintf(buf, "Not affected\n");
> +}
> +
> +ssize_t __weak cpu_show_itlb_multihit(struct device *dev,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	return sprintf(buf, "Not affected\n");
> +}
> +
>  static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
>  static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
>  static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
>  static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL);
>  static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL);
>  static DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL);
> +static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL);
> +static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL);
>  
>  static struct attribute *cpu_root_vulnerabilities_attrs[] = {
>  	&dev_attr_meltdown.attr,
> @@ -568,6 +583,8 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
>  	&dev_attr_spec_store_bypass.attr,
>  	&dev_attr_l1tf.attr,
>  	&dev_attr_mds.attr,
> +	&dev_attr_tsx_async_abort.attr,
> +	&dev_attr_itlb_multihit.attr,
>  	NULL
>  };
>  
> diff --git a/include/linux/cpu.h b/include/linux/cpu.h
> index d0633ebdaa9c..bc6c879bd110 100644
> --- a/include/linux/cpu.h
> +++ b/include/linux/cpu.h
> @@ -59,6 +59,11 @@ extern ssize_t cpu_show_l1tf(struct device *dev,
>  			     struct device_attribute *attr, char *buf);
>  extern ssize_t cpu_show_mds(struct device *dev,
>  			    struct device_attribute *attr, char *buf);
> +extern ssize_t cpu_show_tsx_async_abort(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf);
> +extern ssize_t cpu_show_itlb_multihit(struct device *dev,
> +				      struct device_attribute *attr, char *buf);
>  
>  extern __printf(4, 5)
>  struct device *cpu_device_create(struct device *parent, void *drvdata,
> @@ -213,28 +218,7 @@ static inline int cpuhp_smt_enable(void) { return 0; }
>  static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; }
>  #endif
>  
> -/*
> - * These are used for a global "mitigations=" cmdline option for toggling
> - * optional CPU mitigations.
> - */
> -enum cpu_mitigations {
> -	CPU_MITIGATIONS_OFF,
> -	CPU_MITIGATIONS_AUTO,
> -	CPU_MITIGATIONS_AUTO_NOSMT,
> -};
> -
> -extern enum cpu_mitigations cpu_mitigations;
> -
> -/* mitigations=off */
> -static inline bool cpu_mitigations_off(void)
> -{
> -	return cpu_mitigations == CPU_MITIGATIONS_OFF;
> -}
> -
> -/* mitigations=auto,nosmt */
> -static inline bool cpu_mitigations_auto_nosmt(void)
> -{
> -	return cpu_mitigations == CPU_MITIGATIONS_AUTO_NOSMT;
> -}
> +extern bool cpu_mitigations_off(void);
> +extern bool cpu_mitigations_auto_nosmt(void);
>  
>  #endif /* _LINUX_CPU_H_ */
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 719fc3e15ea4..52ed5f66e8f9 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1382,4 +1382,10 @@ static inline int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
>  }
>  #endif /* CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE */
>  
> +typedef int (*kvm_vm_thread_fn_t)(struct kvm *kvm, uintptr_t data);
> +
> +int kvm_vm_create_worker_thread(struct kvm *kvm, kvm_vm_thread_fn_t thread_fn,
> +				uintptr_t data, const char *name,
> +				struct task_struct **thread_ptr);
> +
>  #endif
> diff --git a/kernel/cpu.c b/kernel/cpu.c
> index fc28e17940e0..e2cad3ee2ead 100644
> --- a/kernel/cpu.c
> +++ b/kernel/cpu.c
> @@ -2373,7 +2373,18 @@ void __init boot_cpu_hotplug_init(void)
>  	this_cpu_write(cpuhp_state.state, CPUHP_ONLINE);
>  }
>  
> -enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO;
> +/*
> + * These are used for a global "mitigations=" cmdline option for toggling
> + * optional CPU mitigations.
> + */
> +enum cpu_mitigations {
> +	CPU_MITIGATIONS_OFF,
> +	CPU_MITIGATIONS_AUTO,
> +	CPU_MITIGATIONS_AUTO_NOSMT,
> +};
> +
> +static enum cpu_mitigations cpu_mitigations __ro_after_init =
> +	CPU_MITIGATIONS_AUTO;
>  
>  static int __init mitigations_parse_cmdline(char *arg)
>  {
> @@ -2390,3 +2401,17 @@ static int __init mitigations_parse_cmdline(char *arg)
>  	return 0;
>  }
>  early_param("mitigations", mitigations_parse_cmdline);
> +
> +/* mitigations=off */
> +bool cpu_mitigations_off(void)
> +{
> +	return cpu_mitigations == CPU_MITIGATIONS_OFF;
> +}
> +EXPORT_SYMBOL_GPL(cpu_mitigations_off);
> +
> +/* mitigations=auto,nosmt */
> +bool cpu_mitigations_auto_nosmt(void)
> +{
> +	return cpu_mitigations == CPU_MITIGATIONS_AUTO_NOSMT;
> +}
> +EXPORT_SYMBOL_GPL(cpu_mitigations_auto_nosmt);
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index d6f0696d98ef..4aab3547a165 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -50,6 +50,7 @@
>  #include <linux/bsearch.h>
>  #include <linux/io.h>
>  #include <linux/lockdep.h>
> +#include <linux/kthread.h>
>  
>  #include <asm/processor.h>
>  #include <asm/ioctl.h>
> @@ -625,6 +626,23 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd)
>  	return 0;
>  }
>  
> +/*
> + * Called after the VM is otherwise initialized, but just before adding it to
> + * the vm_list.
> + */
> +int __weak kvm_arch_post_init_vm(struct kvm *kvm)
> +{
> +	return 0;
> +}
> +
> +/*
> + * Called just after removing the VM from the vm_list, but before doing any
> + * other destruction.
> + */
> +void __weak kvm_arch_pre_destroy_vm(struct kvm *kvm)
> +{
> +}
> +
>  static struct kvm *kvm_create_vm(unsigned long type)
>  {
>  	struct kvm *kvm = kvm_arch_alloc_vm();
> @@ -681,6 +699,10 @@ static struct kvm *kvm_create_vm(unsigned long type)
>  		goto out_err_no_irq_srcu;
>  
>  	r = kvm_init_mmu_notifier(kvm);
> +	if (r)
> +		goto out_err_no_mmu_notifier;
> +
> +	r = kvm_arch_post_init_vm(kvm);
>  	if (r)
>  		goto out_err;
>  
> @@ -693,6 +715,11 @@ static struct kvm *kvm_create_vm(unsigned long type)
>  	return kvm;
>  
>  out_err:
> +#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
> +	if (kvm->mmu_notifier.ops)
> +		mmu_notifier_unregister(&kvm->mmu_notifier, current->mm);
> +#endif
> +out_err_no_mmu_notifier:
>  	cleanup_srcu_struct(&kvm->irq_srcu);
>  out_err_no_irq_srcu:
>  	cleanup_srcu_struct(&kvm->srcu);
> @@ -737,6 +764,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
>  	mutex_lock(&kvm_lock);
>  	list_del(&kvm->vm_list);
>  	mutex_unlock(&kvm_lock);
> +	kvm_arch_pre_destroy_vm(kvm);
> +
>  	kvm_free_irq_routing(kvm);
>  	for (i = 0; i < KVM_NR_BUSES; i++) {
>  		struct kvm_io_bus *bus = kvm_get_bus(kvm, i);
> @@ -4371,3 +4400,86 @@ void kvm_exit(void)
>  	kvm_vfio_ops_exit();
>  }
>  EXPORT_SYMBOL_GPL(kvm_exit);
> +
> +struct kvm_vm_worker_thread_context {
> +	struct kvm *kvm;
> +	struct task_struct *parent;
> +	struct completion init_done;
> +	kvm_vm_thread_fn_t thread_fn;
> +	uintptr_t data;
> +	int err;
> +};
> +
> +static int kvm_vm_worker_thread(void *context)
> +{
> +	/*
> +	 * The init_context is allocated on the stack of the parent thread, so
> +	 * we have to locally copy anything that is needed beyond initialization
> +	 */
> +	struct kvm_vm_worker_thread_context *init_context = context;
> +	struct kvm *kvm = init_context->kvm;
> +	kvm_vm_thread_fn_t thread_fn = init_context->thread_fn;
> +	uintptr_t data = init_context->data;
> +	int err;
> +
> +	err = kthread_park(current);
> +	/* kthread_park(current) is never supposed to return an error */
> +	WARN_ON(err != 0);
> +	if (err)
> +		goto init_complete;
> +
> +	err = cgroup_attach_task_all(init_context->parent, current);
> +	if (err) {
> +		kvm_err("%s: cgroup_attach_task_all failed with err %d\n",
> +			__func__, err);
> +		goto init_complete;
> +	}
> +
> +	set_user_nice(current, task_nice(init_context->parent));
> +
> +init_complete:
> +	init_context->err = err;
> +	complete(&init_context->init_done);
> +	init_context = NULL;
> +
> +	if (err)
> +		return err;
> +
> +	/* Wait to be woken up by the spawner before proceeding. */
> +	kthread_parkme();
> +
> +	if (!kthread_should_stop())
> +		err = thread_fn(kvm, data);
> +
> +	return err;
> +}
> +
> +int kvm_vm_create_worker_thread(struct kvm *kvm, kvm_vm_thread_fn_t thread_fn,
> +				uintptr_t data, const char *name,
> +				struct task_struct **thread_ptr)
> +{
> +	struct kvm_vm_worker_thread_context init_context = {};
> +	struct task_struct *thread;
> +
> +	*thread_ptr = NULL;
> +	init_context.kvm = kvm;
> +	init_context.parent = current;
> +	init_context.thread_fn = thread_fn;
> +	init_context.data = data;
> +	init_completion(&init_context.init_done);
> +
> +	thread = kthread_run(kvm_vm_worker_thread, &init_context,
> +			     "%s-%d", name, task_pid_nr(current));
> +	if (IS_ERR(thread))
> +		return PTR_ERR(thread);
> +
> +	/* kthread_run is never supposed to return NULL */
> +	WARN_ON(thread == NULL);
> +
> +	wait_for_completion(&init_context.init_done);
> +
> +	if (!init_context.err)
> +		*thread_ptr = thread;
> +
> +	return init_context.err;
> +}