Merge tag 'kvmarm-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmar...
authorPaolo Bonzini <pbonzini@redhat.com>
Fri, 23 Apr 2021 11:41:17 +0000 (07:41 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 23 Apr 2021 11:41:17 +0000 (07:41 -0400)
KVM/arm64 updates for Linux 5.13

New features:

- Stage-2 isolation for the host kernel when running in protected mode
- Guest SVE support when running in nVHE mode
- Force W^X hypervisor mappings in nVHE mode
- ITS save/restore for guests using direct injection with GICv4.1
- nVHE panics now produce readable backtraces
- Guest support for PTP using the ptp_kvm driver
- Performance improvements in the S2 fault handler
- Alexandru is now a reviewer (not really a new feature...)

Fixes:
- Proper emulation of the GICR_TYPER register
- Handle the complete set of relocation in the nVHE EL2 object
- Get rid of the oprofile dependency in the PMU code (and of the
  oprofile body parts at the same time)
- Debug and SPE fixes
- Fix vcpu reset

13 files changed:
1  2 
Documentation/virt/kvm/api.rst
MAINTAINERS
arch/arm64/Kconfig
arch/arm64/include/asm/kvm_host.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/guest.c
arch/arm64/kvm/mmu.c
include/uapi/linux/kvm.h
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/kvm_util.c

@@@ -204,7 -204,7 +204,7 @@@ Errors
  
    ======     ============================================================
    EFAULT     the msr index list cannot be read from or written to
 -  E2BIG      the msr index list is to be to fit in the array specified by
 +  E2BIG      the msr index list is too big to fit in the array specified by
               the user.
    ======     ============================================================
  
@@@ -1495,8 -1495,7 +1495,8 @@@ Fails if any VCPU has already been crea
  
  Define which vcpu is the Bootstrap Processor (BSP).  Values are the same
  as the vcpu id in KVM_CREATE_VCPU.  If this ioctl is not called, the default
 -is vcpu 0.
 +is vcpu 0. This ioctl has to be called before vcpu creation,
 +otherwise it will return EBUSY error.
  
  
  4.42 KVM_GET_XSAVE
@@@ -3116,6 -3115,18 +3116,18 @@@ optional features it should have.  Thi
  registers to their initial values.  If this is not called, KVM_RUN will
  return ENOEXEC for that vcpu.
  
+ The initial values are defined as:
+       - Processor state:
+               * AArch64: EL1h, D, A, I and F bits set. All other bits
+                 are cleared.
+               * AArch32: SVC, A, I and F bits set. All other bits are
+                 cleared.
+       - General Purpose registers, including PC and SP: set to 0
+       - FPSIMD/NEON registers: set to 0
+       - SVE registers: set to 0
+       - System registers: Reset to their architecturally defined
+         values as for a warm reset to EL1 (resp. SVC)
  Note that because some registers reflect machine topology, all vcpus
  should be created before this ioctl is invoked.
  
@@@ -3335,7 -3346,8 +3347,8 @@@ The top 16 bits of the control field ar
  flags which can include the following:
  
    - KVM_GUESTDBG_USE_SW_BP:     using software breakpoints [x86, arm64]
-   - KVM_GUESTDBG_USE_HW_BP:     using hardware breakpoints [x86, s390, arm64]
+   - KVM_GUESTDBG_USE_HW_BP:     using hardware breakpoints [x86, s390]
+   - KVM_GUESTDBG_USE_HW:        using hardware debug events [arm64]
    - KVM_GUESTDBG_INJECT_DB:     inject DB type exception [x86]
    - KVM_GUESTDBG_INJECT_BP:     inject BP type exception [x86]
    - KVM_GUESTDBG_EXIT_PENDING:  trigger an immediate guest exit [s390]
@@@ -3358,9 -3370,6 +3371,9 @@@ indicating the number of supported regi
  For ppc, the KVM_CAP_PPC_GUEST_DEBUG_SSTEP capability indicates whether
  the single-step debug event (KVM_GUESTDBG_SINGLESTEP) is supported.
  
 +Also when supported, KVM_CAP_SET_GUEST_DEBUG2 capability indicates the
 +supported KVM_GUESTDBG_* bits in the control field.
 +
  When debug events exit the main run loop with the reason
  KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run
  structure containing architecture specific debug information.
@@@ -3693,105 -3702,31 +3706,105 @@@ which is the maximum number of possibl
  
  Queues an SMI on the thread's vcpu.
  
 -4.97 KVM_CAP_PPC_MULTITCE
 --------------------------
 +4.97 KVM_X86_SET_MSR_FILTER
 +----------------------------
  
 -:Capability: KVM_CAP_PPC_MULTITCE
 -:Architectures: ppc
 -:Type: vm
 +:Capability: KVM_X86_SET_MSR_FILTER
 +:Architectures: x86
 +:Type: vm ioctl
 +:Parameters: struct kvm_msr_filter
 +:Returns: 0 on success, < 0 on error
  
 -This capability means the kernel is capable of handling hypercalls
 -H_PUT_TCE_INDIRECT and H_STUFF_TCE without passing those into the user
 -space. This significantly accelerates DMA operations for PPC KVM guests.
 -User space should expect that its handlers for these hypercalls
 -are not going to be called if user space previously registered LIOBN
 -in KVM (via KVM_CREATE_SPAPR_TCE or similar calls).
 +::
  
 -In order to enable H_PUT_TCE_INDIRECT and H_STUFF_TCE use in the guest,
 -user space might have to advertise it for the guest. For example,
 -IBM pSeries (sPAPR) guest starts using them if "hcall-multi-tce" is
 -present in the "ibm,hypertas-functions" device-tree property.
 +  struct kvm_msr_filter_range {
 +  #define KVM_MSR_FILTER_READ  (1 << 0)
 +  #define KVM_MSR_FILTER_WRITE (1 << 1)
 +      __u32 flags;
 +      __u32 nmsrs; /* number of msrs in bitmap */
 +      __u32 base;  /* MSR index the bitmap starts at */
 +      __u8 *bitmap; /* a 1 bit allows the operations in flags, 0 denies */
 +  };
  
 -The hypercalls mentioned above may or may not be processed successfully
 -in the kernel based fast path. If they can not be handled by the kernel,
 -they will get passed on to user space. So user space still has to have
 -an implementation for these despite the in kernel acceleration.
 +  #define KVM_MSR_FILTER_MAX_RANGES 16
 +  struct kvm_msr_filter {
 +  #define KVM_MSR_FILTER_DEFAULT_ALLOW (0 << 0)
 +  #define KVM_MSR_FILTER_DEFAULT_DENY  (1 << 0)
 +      __u32 flags;
 +      struct kvm_msr_filter_range ranges[KVM_MSR_FILTER_MAX_RANGES];
 +  };
  
 -This capability is always enabled.
 +flags values for ``struct kvm_msr_filter_range``:
 +
 +``KVM_MSR_FILTER_READ``
 +
 +  Filter read accesses to MSRs using the given bitmap. A 0 in the bitmap
 +  indicates that a read should immediately fail, while a 1 indicates that
 +  a read for a particular MSR should be handled regardless of the default
 +  filter action.
 +
 +``KVM_MSR_FILTER_WRITE``
 +
 +  Filter write accesses to MSRs using the given bitmap. A 0 in the bitmap
 +  indicates that a write should immediately fail, while a 1 indicates that
 +  a write for a particular MSR should be handled regardless of the default
 +  filter action.
 +
 +``KVM_MSR_FILTER_READ | KVM_MSR_FILTER_WRITE``
 +
 +  Filter both read and write accesses to MSRs using the given bitmap. A 0
 +  in the bitmap indicates that both reads and writes should immediately fail,
 +  while a 1 indicates that reads and writes for a particular MSR are not
 +  filtered by this range.
 +
 +flags values for ``struct kvm_msr_filter``:
 +
 +``KVM_MSR_FILTER_DEFAULT_ALLOW``
 +
 +  If no filter range matches an MSR index that is getting accessed, KVM will
 +  fall back to allowing access to the MSR.
 +
 +``KVM_MSR_FILTER_DEFAULT_DENY``
 +
 +  If no filter range matches an MSR index that is getting accessed, KVM will
 +  fall back to rejecting access to the MSR. In this mode, all MSRs that should
 +  be processed by KVM need to explicitly be marked as allowed in the bitmaps.
 +
 +This ioctl allows user space to define up to 16 bitmaps of MSR ranges to
 +specify whether a certain MSR access should be explicitly filtered for or not.
 +
 +If this ioctl has never been invoked, MSR accesses are not guarded and the
 +default KVM in-kernel emulation behavior is fully preserved.
 +
 +Calling this ioctl with an empty set of ranges (all nmsrs == 0) disables MSR
 +filtering. In that mode, ``KVM_MSR_FILTER_DEFAULT_DENY`` is invalid and causes
 +an error.
 +
 +As soon as the filtering is in place, every MSR access is processed through
 +the filtering except for accesses to the x2APIC MSRs (from 0x800 to 0x8ff);
 +x2APIC MSRs are always allowed, independent of the ``default_allow`` setting,
 +and their behavior depends on the ``X2APIC_ENABLE`` bit of the APIC base
 +register.
 +
 +If a bit is within one of the defined ranges, read and write accesses are
 +guarded by the bitmap's value for the MSR index if the kind of access
 +is included in the ``struct kvm_msr_filter_range`` flags.  If no range
 +cover this particular access, the behavior is determined by the flags
 +field in the kvm_msr_filter struct: ``KVM_MSR_FILTER_DEFAULT_ALLOW``
 +and ``KVM_MSR_FILTER_DEFAULT_DENY``.
 +
 +Each bitmap range specifies a range of MSRs to potentially allow access on.
 +The range goes from MSR index [base .. base+nmsrs]. The flags field
 +indicates whether reads, writes or both reads and writes are filtered
 +by setting a 1 bit in the bitmap for the corresponding MSR index.
 +
 +If an MSR access is not permitted through the filtering, it generates a
 +#GP inside the guest. When combined with KVM_CAP_X86_USER_SPACE_MSR, that
 +allows user space to deflect and potentially handle various MSR accesses
 +into user space.
 +
 +If a vCPU is in running state while this ioctl is invoked, the vCPU may
 +experience inconsistent filtering behavior on MSR accesses.
  
  4.98 KVM_CREATE_SPAPR_TCE_64
  ----------------------------
@@@ -4884,10 -4819,8 +4897,10 @@@ If an MSR access is not permitted throu
  allows user space to deflect and potentially handle various MSR accesses
  into user space.
  
 -If a vCPU is in running state while this ioctl is invoked, the vCPU may
 -experience inconsistent filtering behavior on MSR accesses.
 +Note, invoking this ioctl with a vCPU is running is inherently racy.  However,
 +KVM does guarantee that vCPUs will see either the previous filter or the new
 +filter, e.g. MSRs with identical settings in both the old and new filter will
 +have deterministic behavior.
  
  4.127 KVM_XEN_HVM_SET_ATTR
  --------------------------
@@@ -4932,7 -4865,7 +4945,7 @@@ KVM_XEN_ATTR_TYPE_SHARED_INF
  KVM_XEN_ATTR_TYPE_UPCALL_VECTOR
    Sets the exception vector used to deliver Xen event channel upcalls.
  
 -4.128 KVM_XEN_HVM_GET_ATTR
 +4.127 KVM_XEN_HVM_GET_ATTR
  --------------------------
  
  :Capability: KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO
  Allows Xen VM attributes to be read. For the structure and types,
  see KVM_XEN_HVM_SET_ATTR above.
  
 -4.129 KVM_XEN_VCPU_SET_ATTR
 +4.128 KVM_XEN_VCPU_SET_ATTR
  ---------------------------
  
  :Capability: KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO
@@@ -5006,7 -4939,7 +5019,7 @@@ KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUS
    or RUNSTATE_offline) to set the current accounted state as of the
    adjusted state_entry_time.
  
 -4.130 KVM_XEN_VCPU_GET_ATTR
 +4.129 KVM_XEN_VCPU_GET_ATTR
  ---------------------------
  
  :Capability: KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO
@@@ -6310,45 -6243,6 +6323,45 @@@ KVM_RUN_BUS_LOCK flag is used to distin
  This capability can be used to check / enable 2nd DAWR feature provided
  by POWER10 processor.
  
 +7.24 KVM_CAP_VM_COPY_ENC_CONTEXT_FROM
 +-------------------------------------
 +
 +Architectures: x86 SEV enabled
 +Type: vm
 +Parameters: args[0] is the fd of the source vm
 +Returns: 0 on success; ENOTTY on error
 +
 +This capability enables userspace to copy encryption context from the vm
 +indicated by the fd to the vm this is called on.
 +
 +This is intended to support in-guest workloads scheduled by the host. This
 +allows the in-guest workload to maintain its own NPTs and keeps the two vms
 +from accidentally clobbering each other with interrupts and the like (separate
 +APIC/MSRs/etc).
 +
 +7.25 KVM_CAP_SGX_ATTRIBUTE
 +----------------------
 +
 +:Architectures: x86
 +:Target: VM
 +:Parameters: args[0] is a file handle of a SGX attribute file in securityfs
 +:Returns: 0 on success, -EINVAL if the file handle is invalid or if a requested
 +          attribute is not supported by KVM.
 +
 +KVM_CAP_SGX_ATTRIBUTE enables a userspace VMM to grant a VM access to one or
 +more priveleged enclave attributes.  args[0] must hold a file handle to a valid
 +SGX attribute file corresponding to an attribute that is supported/restricted
 +by KVM (currently only PROVISIONKEY).
 +
 +The SGX subsystem restricts access to a subset of enclave attributes to provide
 +additional security for an uncompromised kernel, e.g. use of the PROVISIONKEY
 +is restricted to deter malware from using the PROVISIONKEY to obtain a stable
 +system fingerprint.  To prevent userspace from circumventing such restrictions
 +by running an enclave in a VM, KVM prevents access to privileged attributes by
 +default.
 +
 +See Documentation/x86/sgx/2.Kernel-internals.rst for more details.
 +
  8. Other capabilities.
  ======================
  
@@@ -6844,28 -6738,12 +6857,37 @@@ The KVM_XEN_HVM_CONFIG_RUNSTATE flag in
  features KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST are
  supported by the KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctls.
  
 -8.31 KVM_CAP_PTP_KVM
 +8.31 KVM_CAP_PPC_MULTITCE
 +-------------------------
 +
 +:Capability: KVM_CAP_PPC_MULTITCE
 +:Architectures: ppc
 +:Type: vm
 +
 +This capability means the kernel is capable of handling hypercalls
 +H_PUT_TCE_INDIRECT and H_STUFF_TCE without passing those into the user
 +space. This significantly accelerates DMA operations for PPC KVM guests.
 +User space should expect that its handlers for these hypercalls
 +are not going to be called if user space previously registered LIOBN
 +in KVM (via KVM_CREATE_SPAPR_TCE or similar calls).
 +
 +In order to enable H_PUT_TCE_INDIRECT and H_STUFF_TCE use in the guest,
 +user space might have to advertise it for the guest. For example,
 +IBM pSeries (sPAPR) guest starts using them if "hcall-multi-tce" is
 +present in the "ibm,hypertas-functions" device-tree property.
 +
 +The hypercalls mentioned above may or may not be processed successfully
 +in the kernel based fast path. If they can not be handled by the kernel,
 +they will get passed on to user space. So user space still has to have
 +an implementation for these despite the in kernel acceleration.
 +
 +This capability is always enabled.
++
++8.32 KVM_CAP_PTP_KVM
+ --------------------
+ :Architectures: arm64
+ This capability indicates that the KVM virtual PTP service is
+ supported in the host. A VMM can check whether the service is
+ available to the guest on migration.
 -
diff --combined MAINTAINERS
@@@ -1181,7 -1181,7 +1181,7 @@@ M:      Joel Fernandes <joel@joelfernandes.o
  M:    Christian Brauner <christian@brauner.io>
  M:    Hridya Valsaraju <hridya@google.com>
  M:    Suren Baghdasaryan <surenb@google.com>
 -L:    devel@driverdev.osuosl.org
 +L:    linux-kernel@vger.kernel.org
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
  F:    drivers/android/
@@@ -1761,6 -1761,8 +1761,8 @@@ F:      Documentation/ABI/testing/sysfs-bus-
  F:    Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt
  F:    Documentation/devicetree/bindings/arm/coresight-cti.yaml
  F:    Documentation/devicetree/bindings/arm/coresight.txt
+ F:    Documentation/devicetree/bindings/arm/ete.yaml
+ F:    Documentation/devicetree/bindings/arm/trbe.yaml
  F:    Documentation/trace/coresight/*
  F:    drivers/hwtracing/coresight/*
  F:    include/dt-bindings/arm/coresight-cti-dt.h
@@@ -2489,7 -2491,7 +2491,7 @@@ N:      sc27x
  N:    sc2731
  
  ARM/STI ARCHITECTURE
 -M:    Patrice Chotard <patrice.chotard@st.com>
 +M:    Patrice Chotard <patrice.chotard@foss.st.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  W:    http://www.stlinux.com
@@@ -2522,7 -2524,7 +2524,7 @@@ F:      include/linux/remoteproc/st_slim_rpr
  
  ARM/STM32 ARCHITECTURE
  M:    Maxime Coquelin <mcoquelin.stm32@gmail.com>
 -M:    Alexandre Torgue <alexandre.torgue@st.com>
 +M:    Alexandre Torgue <alexandre.torgue@foss.st.com>
  L:    linux-stm32@st-md-mailman.stormreply.com (moderated for non-subscribers)
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
@@@ -3115,7 -3117,7 +3117,7 @@@ C:      irc://irc.oftc.net/bcach
  F:    drivers/md/bcache/
  
  BDISP ST MEDIA DRIVER
 -M:    Fabien Dessenne <fabien.dessenne@st.com>
 +M:    Fabien Dessenne <fabien.dessenne@foss.st.com>
  L:    linux-media@vger.kernel.org
  S:    Supported
  W:    https://linuxtv.org
@@@ -3675,7 -3677,7 +3677,7 @@@ M:      bcm-kernel-feedback-list@broadcom.co
  L:    linux-pm@vger.kernel.org
  S:    Maintained
  T:    git git://github.com/broadcom/stblinux.git
 -F:    drivers/soc/bcm/bcm-pmb.c
 +F:    drivers/soc/bcm/bcm63xx/bcm-pmb.c
  F:    include/dt-bindings/soc/bcm-pmb.h
  
  BROADCOM SPECIFIC AMBA DRIVER (BCMA)
@@@ -5080,7 -5082,7 +5082,7 @@@ S:      Maintaine
  F:    drivers/platform/x86/dell/dell-wmi.c
  
  DELTA ST MEDIA DRIVER
 -M:    Hugues Fruchet <hugues.fruchet@st.com>
 +M:    Hugues Fruchet <hugues.fruchet@foss.st.com>
  L:    linux-media@vger.kernel.org
  S:    Supported
  W:    https://linuxtv.org
@@@ -6006,6 -6008,7 +6008,6 @@@ F:      drivers/gpu/drm/rockchip
  
  DRM DRIVERS FOR STI
  M:    Benjamin Gaignard <benjamin.gaignard@linaro.org>
 -M:    Vincent Abriou <vincent.abriou@st.com>
  L:    dri-devel@lists.freedesktop.org
  S:    Maintained
  T:    git git://anongit.freedesktop.org/drm/drm-misc
@@@ -6013,9 -6016,10 +6015,9 @@@ F:     Documentation/devicetree/bindings/di
  F:    drivers/gpu/drm/sti
  
  DRM DRIVERS FOR STM
 -M:    Yannick Fertre <yannick.fertre@st.com>
 -M:    Philippe Cornu <philippe.cornu@st.com>
 +M:    Yannick Fertre <yannick.fertre@foss.st.com>
 +M:    Philippe Cornu <philippe.cornu@foss.st.com>
  M:    Benjamin Gaignard <benjamin.gaignard@linaro.org>
 -M:    Vincent Abriou <vincent.abriou@st.com>
  L:    dri-devel@lists.freedesktop.org
  S:    Maintained
  T:    git git://anongit.freedesktop.org/drm/drm-misc
@@@ -7474,9 -7478,8 +7476,9 @@@ F:      include/uapi/asm-generic
  GENERIC PHY FRAMEWORK
  M:    Kishon Vijay Abraham I <kishon@ti.com>
  M:    Vinod Koul <vkoul@kernel.org>
 -L:    linux-kernel@vger.kernel.org
 +L:    linux-phy@lists.infradead.org
  S:    Supported
 +Q:    https://patchwork.kernel.org/project/linux-phy/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git
  F:    Documentation/devicetree/bindings/phy/
  F:    drivers/phy/
@@@ -8115,6 -8118,7 +8117,6 @@@ F:      drivers/crypto/hisilicon/sec2/sec_ma
  
  HISILICON STAGING DRIVERS FOR HIKEY 960/970
  M:    Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
 -L:    devel@driverdev.osuosl.org
  S:    Maintained
  F:    drivers/staging/hikey9xx/
  
@@@ -8229,7 -8233,7 +8231,7 @@@ F:      include/linux/hugetlb.
  F:    mm/hugetlb.c
  
  HVA ST MEDIA DRIVER
 -M:    Jean-Christophe Trotin <jean-christophe.trotin@st.com>
 +M:    Jean-Christophe Trotin <jean-christophe.trotin@foss.st.com>
  L:    linux-media@vger.kernel.org
  S:    Supported
  W:    https://linuxtv.org
@@@ -8519,7 -8523,6 +8521,7 @@@ IBM Power SRIOV Virtual NIC Device Driv
  M:    Dany Madden <drt@linux.ibm.com>
  M:    Lijun Pan <ljp@linux.ibm.com>
  M:    Sukadev Bhattiprolu <sukadev@linux.ibm.com>
 +R:    Thomas Falcon <tlfalcon@linux.ibm.com>
  L:    netdev@vger.kernel.org
  S:    Supported
  F:    drivers/net/ethernet/ibm/ibmvnic.*
@@@ -9273,7 -9276,6 +9275,7 @@@ Q:      https://patchwork.kernel.org/project
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/sgx
  F:    Documentation/x86/sgx.rst
  F:    arch/x86/entry/vdso/vsgx.S
 +F:    arch/x86/include/asm/sgx.h
  F:    arch/x86/include/uapi/asm/sgx.h
  F:    arch/x86/kernel/cpu/sgx/*
  F:    tools/testing/selftests/sgx/*
@@@ -9765,10 -9767,10 +9767,10 @@@ F:   virt/kvm/
  KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
  M:    Marc Zyngier <maz@kernel.org>
  R:    James Morse <james.morse@arm.com>
- R:    Julien Thierry <julien.thierry.kdev@gmail.com>
+ R:    Alexandru Elisei <alexandru.elisei@arm.com>
  R:    Suzuki K Poulose <suzuki.poulose@arm.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
- L:    kvmarm@lists.cs.columbia.edu
+ L:    kvmarm@lists.cs.columbia.edu (moderated for non-subscribers)
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
  F:    arch/arm64/include/asm/kvm*
@@@ -10030,6 -10032,7 +10032,6 @@@ F:   scripts/leaking_addresses.p
  
  LED SUBSYSTEM
  M:    Pavel Machek <pavel@ucw.cz>
 -R:    Dan Murphy <dmurphy@ti.com>
  L:    linux-leds@vger.kernel.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git
@@@ -10905,6 -10908,7 +10907,6 @@@ T:   git git://linuxtv.org/media_tree.gi
  F:    drivers/media/radio/radio-maxiradio*
  
  MCAN MMIO DEVICE DRIVER
 -M:    Dan Murphy <dmurphy@ti.com>
  M:    Pankaj Sharma <pankj.sharma@samsung.com>
  L:    linux-can@vger.kernel.org
  S:    Maintained
@@@ -11165,7 -11169,7 +11167,7 @@@ T:   git git://linuxtv.org/media_tree.gi
  F:    drivers/media/dvb-frontends/stv6111*
  
  MEDIA DRIVERS FOR STM32 - DCMI
 -M:    Hugues Fruchet <hugues.fruchet@st.com>
 +M:    Hugues Fruchet <hugues.fruchet@foss.st.com>
  L:    linux-media@vger.kernel.org
  S:    Supported
  T:    git git://linuxtv.org/media_tree.git
@@@ -12536,7 -12540,7 +12538,7 @@@ NETWORKING [MPTCP
  M:    Mat Martineau <mathew.j.martineau@linux.intel.com>
  M:    Matthieu Baerts <matthieu.baerts@tessares.net>
  L:    netdev@vger.kernel.org
 -L:    mptcp@lists.01.org
 +L:    mptcp@lists.linux.dev
  S:    Maintained
  W:    https://github.com/multipath-tcp/mptcp_net-next/wiki
  B:    https://github.com/multipath-tcp/mptcp_net-next/issues
@@@ -14707,11 -14711,15 +14709,11 @@@ F:        drivers/net/ethernet/qlogic/qlcnic
  QLOGIC QLGE 10Gb ETHERNET DRIVER
  M:    Manish Chopra <manishc@marvell.com>
  M:    GR-Linux-NIC-Dev@marvell.com
 -L:    netdev@vger.kernel.org
 -S:    Supported
 -F:    drivers/staging/qlge/
 -
 -QLOGIC QLGE 10Gb ETHERNET DRIVER
  M:    Coiby Xu <coiby.xu@gmail.com>
  L:    netdev@vger.kernel.org
 -S:    Maintained
 +S:    Supported
  F:    Documentation/networking/device_drivers/qlogic/qlge.rst
 +F:    drivers/staging/qlge/
  
  QM1D1B0004 MEDIA DRIVER
  M:    Akihiro Tsukada <tskd08@gmail.com>
@@@ -15629,8 -15637,8 +15631,8 @@@ F:   Documentation/s390/pci.rs
  
  S390 VFIO AP DRIVER
  M:    Tony Krowiak <akrowiak@linux.ibm.com>
 -M:    Pierre Morel <pmorel@linux.ibm.com>
  M:    Halil Pasic <pasic@linux.ibm.com>
 +M:    Jason Herne <jjherne@linux.ibm.com>
  L:    linux-s390@vger.kernel.org
  S:    Supported
  W:    http://www.ibm.com/developerworks/linux/linux390/
@@@ -15642,7 -15650,6 +15644,7 @@@ F:   drivers/s390/crypto/vfio_ap_private.
  S390 VFIO-CCW DRIVER
  M:    Cornelia Huck <cohuck@redhat.com>
  M:    Eric Farman <farman@linux.ibm.com>
 +M:    Matthew Rosato <mjrosato@linux.ibm.com>
  R:    Halil Pasic <pasic@linux.ibm.com>
  L:    linux-s390@vger.kernel.org
  L:    kvm@vger.kernel.org
@@@ -15653,7 -15660,6 +15655,7 @@@ F:   include/uapi/linux/vfio_ccw.
  
  S390 VFIO-PCI DRIVER
  M:    Matthew Rosato <mjrosato@linux.ibm.com>
 +M:    Eric Farman <farman@linux.ibm.com>
  L:    linux-s390@vger.kernel.org
  L:    kvm@vger.kernel.org
  S:    Supported
@@@ -16883,10 -16889,8 +16885,10 @@@ F: tools/spi
  
  SPIDERNET NETWORK DRIVER for CELL
  M:    Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
 +M:    Geoff Levand <geoff@infradead.org>
  L:    netdev@vger.kernel.org
 -S:    Supported
 +L:    linuxppc-dev@lists.ozlabs.org
 +S:    Maintained
  F:    Documentation/networking/device_drivers/ethernet/toshiba/spider_net.rst
  F:    drivers/net/ethernet/toshiba/spider_net*
  
@@@ -16940,8 -16944,7 +16942,8 @@@ F:   Documentation/devicetree/bindings/me
  F:    drivers/media/i2c/st-mipid02.c
  
  ST STM32 I2C/SMBUS DRIVER
 -M:    Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
 +M:    Pierre-Yves MORDRET <pierre-yves.mordret@foss.st.com>
 +M:    Alain Volmat <alain.volmat@foss.st.com>
  L:    linux-i2c@vger.kernel.org
  S:    Maintained
  F:    drivers/i2c/busses/i2c-stm32*
@@@ -17039,7 -17042,7 +17041,7 @@@ F:   drivers/staging/vt665?
  
  STAGING SUBSYSTEM
  M:    Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -L:    devel@driverdev.osuosl.org
 +L:    linux-staging@lists.linux.dev
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
  F:    drivers/staging/
@@@ -17066,7 -17069,7 +17068,7 @@@ F:   kernel/jump_label.
  F:    kernel/static_call.c
  
  STI AUDIO (ASoC) DRIVERS
 -M:    Arnaud Pouliquen <arnaud.pouliquen@st.com>
 +M:    Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
  S:    Maintained
  F:    Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
@@@ -17086,15 -17089,15 +17088,15 @@@ T:        git git://linuxtv.org/media_tree.gi
  F:    drivers/media/usb/stk1160/
  
  STM32 AUDIO (ASoC) DRIVERS
 -M:    Olivier Moysan <olivier.moysan@st.com>
 -M:    Arnaud Pouliquen <arnaud.pouliquen@st.com>
 +M:    Olivier Moysan <olivier.moysan@foss.st.com>
 +M:    Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
  S:    Maintained
  F:    Documentation/devicetree/bindings/iio/adc/st,stm32-*.yaml
  F:    sound/soc/stm/
  
  STM32 TIMER/LPTIMER DRIVERS
 -M:    Fabrice Gasnier <fabrice.gasnier@st.com>
 +M:    Fabrice Gasnier <fabrice.gasnier@foss.st.com>
  S:    Maintained
  F:    Documentation/ABI/testing/*timer-stm32
  F:    Documentation/devicetree/bindings/*/*stm32-*timer*
@@@ -17104,7 -17107,7 +17106,7 @@@ F:   include/linux/*/stm32-*tim
  
  STMMAC ETHERNET DRIVER
  M:    Giuseppe Cavallaro <peppe.cavallaro@st.com>
 -M:    Alexandre Torgue <alexandre.torgue@st.com>
 +M:    Alexandre Torgue <alexandre.torgue@foss.st.com>
  M:    Jose Abreu <joabreu@synopsys.com>
  L:    netdev@vger.kernel.org
  S:    Supported
@@@ -17846,6 -17849,7 +17848,6 @@@ S:   Maintaine
  F:    drivers/thermal/ti-soc-thermal/
  
  TI BQ27XXX POWER SUPPLY DRIVER
 -R:    Dan Murphy <dmurphy@ti.com>
  F:    drivers/power/supply/bq27xxx_battery.c
  F:    drivers/power/supply/bq27xxx_battery_i2c.c
  F:    include/linux/power/bq27xxx_battery.h
@@@ -17980,6 -17984,7 +17982,6 @@@ S:   Odd Fixe
  F:    sound/soc/codecs/tas571x*
  
  TI TCAN4X5X DEVICE DRIVER
 -M:    Dan Murphy <dmurphy@ti.com>
  L:    linux-can@vger.kernel.org
  S:    Maintained
  F:    Documentation/devicetree/bindings/net/can/tcan4x5x.txt
@@@ -19132,7 -19137,7 +19134,7 @@@ VME SUBSYSTE
  M:    Martyn Welch <martyn@welchs.me.uk>
  M:    Manohar Vanga <manohar.vanga@gmail.com>
  M:    Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -L:    devel@driverdev.osuosl.org
 +L:    linux-kernel@vger.kernel.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
  F:    Documentation/driver-api/vme.rst
diff --combined arch/arm64/Kconfig
@@@ -810,16 -810,6 +810,16 @@@ config QCOM_FALKOR_ERRATUM_E104
  
          If unsure, say Y.
  
 +config NVIDIA_CARMEL_CNP_ERRATUM
 +      bool "NVIDIA Carmel CNP: CNP on Carmel semantically different than ARM cores"
 +      default y
 +      help
 +        If CNP is enabled on Carmel cores, non-sharable TLBIs on a core will not
 +        invalidate shared TLB entries installed by a different core, as it would
 +        on standard ARM cores.
 +
 +        If unsure, say Y.
 +
  config SOCIONEXT_SYNQUACER_PREITS
        bool "Socionext Synquacer: Workaround for GICv3 pre-ITS"
        default y
@@@ -1426,19 -1416,6 +1426,6 @@@ config ARM64_USE_LSE_ATOMIC
          built with binutils >= 2.25 in order for the new instructions
          to be used.
  
- config ARM64_VHE
-       bool "Enable support for Virtualization Host Extensions (VHE)"
-       default y
-       help
-         Virtualization Host Extensions (VHE) allow the kernel to run
-         directly at EL2 (instead of EL1) on processors that support
-         it. This leads to better performance for KVM, as they reduce
-         the cost of the world switch.
-         Selecting this option allows the VHE feature to be detected
-         at runtime, and does not affect processors that do not
-         implement this feature.
  endmenu
  
  menu "ARMv8.2 architectural features"
@@@ -1694,7 -1671,6 +1681,6 @@@ endmen
  config ARM64_SVE
        bool "ARM Scalable Vector Extension support"
        default y
-       depends on !KVM || ARM64_VHE
        help
          The Scalable Vector Extension (SVE) is an extension to the AArch64
          execution state which complements and extends the SIMD functionality
          booting the kernel.  If unsure and you are not observing these
          symptoms, you should assume that it is safe to say Y.
  
-         CPUs that support SVE are architecturally required to support the
-         Virtualization Host Extensions (VHE), so the kernel makes no
-         provision for supporting SVE alongside KVM without VHE enabled.
-         Thus, you will need to enable CONFIG_ARM64_VHE if you want to support
-         KVM in the same kernel image.
  config ARM64_MODULE_PLTS
        bool "Use PLTs to allow module memory to spill over into vmalloc area"
        depends on MODULES
@@@ -94,7 -94,7 +94,7 @@@ struct kvm_s2_mmu 
        /* The last vcpu id that ran on each physical CPU */
        int __percpu *last_vcpu_ran;
  
-       struct kvm *kvm;
+       struct kvm_arch *arch;
  };
  
  struct kvm_arch_memory_slot {
@@@ -315,6 -315,8 +315,8 @@@ struct kvm_vcpu_arch 
                struct kvm_guest_debug_arch regs;
                /* Statistical profiling extension */
                u64 pmscr_el1;
+               /* Self-hosted trace */
+               u64 trfcr_el1;
        } host_debug_state;
  
        /* VGIC state */
  };
  
  /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
- #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
-                                     sve_ffr_offset((vcpu)->arch.sve_max_vl)))
+ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) +    \
+                            sve_ffr_offset((vcpu)->arch.sve_max_vl))
+ #define vcpu_sve_max_vq(vcpu) sve_vq_from_vl((vcpu)->arch.sve_max_vl)
  
  #define vcpu_sve_state_size(vcpu) ({                                  \
        size_t __size_ret;                                              \
        if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {          \
                __size_ret = 0;                                         \
        } else {                                                        \
-               __vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);    \
+               __vcpu_vq = vcpu_sve_max_vq(vcpu);                      \
                __size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);              \
        }                                                               \
                                                                        \
  #define KVM_ARM64_GUEST_HAS_PTRAUTH   (1 << 7) /* PTRAUTH exposed to guest */
  #define KVM_ARM64_PENDING_EXCEPTION   (1 << 8) /* Exception pending */
  #define KVM_ARM64_EXCEPT_MASK         (7 << 9) /* Target EL/MODE */
+ #define KVM_ARM64_DEBUG_STATE_SAVE_SPE        (1 << 12) /* Save SPE context if active  */
+ #define KVM_ARM64_DEBUG_STATE_SAVE_TRBE       (1 << 13) /* Save TRBE context if active  */
  
 +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
 +                               KVM_GUESTDBG_USE_SW_BP | \
 +                               KVM_GUESTDBG_USE_HW | \
 +                               KVM_GUESTDBG_SINGLESTEP)
  /*
   * When KVM_ARM64_PENDING_EXCEPTION is set, KVM_ARM64_EXCEPT_MASK can
   * take the following values:
@@@ -586,10 -588,16 +592,11 @@@ int __kvm_arm_vcpu_set_events(struct kv
                              struct kvm_vcpu_events *events);
  
  #define KVM_ARCH_WANT_MMU_NOTIFIER
 -int kvm_unmap_hva_range(struct kvm *kvm,
 -                      unsigned long start, unsigned long end, unsigned flags);
 -int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
 -int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 -int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
  
  void kvm_arm_halt_guest(struct kvm *kvm);
  void kvm_arm_resume_guest(struct kvm *kvm);
  
+ #ifndef __KVM_NVHE_HYPERVISOR__
  #define kvm_call_hyp_nvhe(f, ...)                                             \
        ({                                                              \
                struct arm_smccc_res res;                               \
                                                                        \
                ret;                                                    \
        })
+ #else /* __KVM_NVHE_HYPERVISOR__ */
+ #define kvm_call_hyp(f, ...) f(__VA_ARGS__)
+ #define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
+ #define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
+ #endif /* __KVM_NVHE_HYPERVISOR__ */
  
  void force_vm_exit(const cpumask_t *mask);
- void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
  
  int handle_exit(struct kvm_vcpu *vcpu, int exception_index);
  void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index);
@@@ -691,19 -703,6 +702,6 @@@ static inline void kvm_init_host_cpu_co
        ctxt_sys_reg(cpu_ctxt, MPIDR_EL1) = read_cpuid_mpidr();
  }
  
- static inline bool kvm_arch_requires_vhe(void)
- {
-       /*
-        * The Arm architecture specifies that implementation of SVE
-        * requires VHE also to be implemented.  The KVM code for arm64
-        * relies on this when SVE is present:
-        */
-       if (system_supports_sve())
-               return true;
-       return false;
- }
  void kvm_arm_vcpu_ptrauth_trap(struct kvm_vcpu *vcpu);
  
  static inline void kvm_arch_hardware_unsetup(void) {}
@@@ -712,6 -711,7 +710,7 @@@ static inline void kvm_arch_sched_in(st
  static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
  
  void kvm_arm_init_debug(void);
+ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu);
  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
  void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
  void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
@@@ -733,6 -733,10 +732,10 @@@ static inline bool kvm_pmu_counter_defe
        return (!has_vhe() && attr->exclude_host);
  }
  
+ /* Flags for host debug state */
+ void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu);
+ void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu);
  #ifdef CONFIG_KVM /* Avoid conflicts with core headers if CONFIG_KVM=n */
  static inline int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
  {
@@@ -770,5 -774,12 +773,12 @@@ bool kvm_arm_vcpu_is_finalized(struct k
        (test_bit(KVM_ARM_VCPU_PMU_V3, (vcpu)->arch.features))
  
  int kvm_trng_call(struct kvm_vcpu *vcpu);
+ #ifdef CONFIG_KVM
+ extern phys_addr_t hyp_mem_base;
+ extern phys_addr_t hyp_mem_size;
+ void __init kvm_hyp_reserve(void);
+ #else
+ static inline void kvm_hyp_reserve(void) { }
+ #endif
  
  #endif /* __ARM64_KVM_HOST_H__ */
@@@ -808,6 -808,12 +808,12 @@@ static void __init init_cpu_ftr_reg(u3
                                        reg->name,
                                        ftrp->shift + ftrp->width - 1,
                                        ftrp->shift, str, tmp);
+               } else if ((ftr_mask & reg->override->val) == ftr_mask) {
+                       reg->override->val &= ~ftr_mask;
+                       pr_warn("%s[%d:%d]: impossible override, ignored\n",
+                               reg->name,
+                               ftrp->shift + ftrp->width - 1,
+                               ftrp->shift);
                }
  
                val = arm64_ftr_set_value(ftrp, val, ftr_new);
@@@ -1320,10 -1326,7 +1326,10 @@@ has_useable_cnp(const struct arm64_cpu_
         * may share TLB entries with a CPU stuck in the crashed
         * kernel.
         */
 -       if (is_kdump_kernel())
 +      if (is_kdump_kernel())
 +              return false;
 +
 +      if (cpus_have_const_cap(ARM64_WORKAROUND_NVIDIA_CARMEL_CNP))
                return false;
  
        return has_cpuid_feature(entry, scope);
@@@ -1619,7 -1622,6 +1625,6 @@@ int get_cpu_with_amu_feat(void
  }
  #endif
  
- #ifdef CONFIG_ARM64_VHE
  static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
  {
        return is_kernel_in_hyp_mode();
@@@ -1638,7 -1640,6 +1643,6 @@@ static void cpu_copy_el2regs(const stru
        if (!alternative_is_applied(ARM64_HAS_VIRT_HOST_EXTN))
                write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
  }
- #endif
  
  static void cpu_has_fwb(const struct arm64_cpu_capabilities *__unused)
  {
@@@ -1841,7 -1842,6 +1845,6 @@@ static const struct arm64_cpu_capabilit
                .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
                .matches = has_no_hw_prefetch,
        },
- #ifdef CONFIG_ARM64_VHE
        {
                .desc = "Virtualization Host Extensions",
                .capability = ARM64_HAS_VIRT_HOST_EXTN,
                .matches = runs_at_el2,
                .cpu_enable = cpu_copy_el2regs,
        },
- #endif        /* CONFIG_ARM64_VHE */
        {
                .desc = "32-bit EL0 Support",
                .capability = ARM64_HAS_32BIT_EL0,
diff --combined arch/arm64/kvm/arm.c
@@@ -206,10 -206,9 +206,11 @@@ int kvm_vm_ioctl_check_extension(struc
        case KVM_CAP_ARM_INJECT_EXT_DABT:
        case KVM_CAP_SET_GUEST_DEBUG:
        case KVM_CAP_VCPU_ATTRIBUTES:
+       case KVM_CAP_PTP_KVM:
                r = 1;
                break;
 +      case KVM_CAP_SET_GUEST_DEBUG2:
 +              return KVM_GUESTDBG_VALID_MASK;
        case KVM_CAP_ARM_SET_DEVICE_ADDR:
                r = 1;
                break;
@@@ -418,10 -417,12 +419,12 @@@ void kvm_arch_vcpu_load(struct kvm_vcp
  
        if (vcpu_has_ptrauth(vcpu))
                vcpu_ptrauth_disable(vcpu);
+       kvm_arch_vcpu_load_debug_state_flags(vcpu);
  }
  
  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
  {
+       kvm_arch_vcpu_put_debug_state_flags(vcpu);
        kvm_arch_vcpu_put_fp(vcpu);
        if (has_vhe())
                kvm_vcpu_put_sysregs_vhe(vcpu);
@@@ -582,6 -583,8 +585,8 @@@ static int kvm_vcpu_first_run_init(stru
  
        vcpu->arch.has_run_once = true;
  
+       kvm_arm_vcpu_init_debug(vcpu);
        if (likely(irqchip_in_kernel(kvm))) {
                /*
                 * Map the VGIC hardware resources before running a vcpu the
@@@ -1270,7 -1273,7 +1275,7 @@@ void kvm_arch_sync_dirty_log(struct kv
  }
  
  void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
 -                                      struct kvm_memory_slot *memslot)
 +                                      const struct kvm_memory_slot *memslot)
  {
        kvm_flush_remote_tlbs(kvm);
  }
@@@ -1352,16 -1355,9 +1357,9 @@@ static unsigned long nvhe_percpu_order(
  /* A lookup table holding the hypervisor VA for each vector slot */
  static void *hyp_spectre_vector_selector[BP_HARDEN_EL2_SLOTS];
  
- static int __kvm_vector_slot2idx(enum arm64_hyp_spectre_vector slot)
- {
-       return slot - (slot != HYP_VECTOR_DIRECT);
- }
  static void kvm_init_vector_slot(void *base, enum arm64_hyp_spectre_vector slot)
  {
-       int idx = __kvm_vector_slot2idx(slot);
-       hyp_spectre_vector_selector[slot] = base + (idx * SZ_2K);
+       hyp_spectre_vector_selector[slot] = __kvm_vector_slot2addr(base, slot);
  }
  
  static int kvm_init_vector_slots(void)
        return 0;
  }
  
- static void cpu_init_hyp_mode(void)
+ static void cpu_prepare_hyp_mode(int cpu)
  {
-       struct kvm_nvhe_init_params *params = this_cpu_ptr_nvhe_sym(kvm_init_params);
-       struct arm_smccc_res res;
+       struct kvm_nvhe_init_params *params = per_cpu_ptr_nvhe_sym(kvm_init_params, cpu);
        unsigned long tcr;
  
-       /* Switch from the HYP stub to our own HYP init vector */
-       __hyp_set_vectors(kvm_get_idmap_vector());
        /*
         * Calculate the raw per-cpu offset without a translation from the
         * kernel's mapping to the linear mapping, and store it in tpidr_el2
         * so that we can use adr_l to access per-cpu variables in EL2.
         * Also drop the KASAN tag which gets in the way...
         */
-       params->tpidr_el2 = (unsigned long)kasan_reset_tag(this_cpu_ptr_nvhe_sym(__per_cpu_start)) -
+       params->tpidr_el2 = (unsigned long)kasan_reset_tag(per_cpu_ptr_nvhe_sym(__per_cpu_start, cpu)) -
                            (unsigned long)kvm_ksym_ref(CHOOSE_NVHE_SYM(__per_cpu_start));
  
        params->mair_el2 = read_sysreg(mair_el1);
        tcr |= (idmap_t0sz & GENMASK(TCR_TxSZ_WIDTH - 1, 0)) << TCR_T0SZ_OFFSET;
        params->tcr_el2 = tcr;
  
-       params->stack_hyp_va = kern_hyp_va(__this_cpu_read(kvm_arm_hyp_stack_page) + PAGE_SIZE);
+       params->stack_hyp_va = kern_hyp_va(per_cpu(kvm_arm_hyp_stack_page, cpu) + PAGE_SIZE);
        params->pgd_pa = kvm_mmu_get_httbr();
+       if (is_protected_kvm_enabled())
+               params->hcr_el2 = HCR_HOST_NVHE_PROTECTED_FLAGS;
+       else
+               params->hcr_el2 = HCR_HOST_NVHE_FLAGS;
+       params->vttbr = params->vtcr = 0;
  
        /*
         * Flush the init params from the data cache because the struct will
         * be read while the MMU is off.
         */
        kvm_flush_dcache_to_poc(params, sizeof(*params));
+ }
+ static void hyp_install_host_vector(void)
+ {
+       struct kvm_nvhe_init_params *params;
+       struct arm_smccc_res res;
+       /* Switch from the HYP stub to our own HYP init vector */
+       __hyp_set_vectors(kvm_get_idmap_vector());
  
        /*
         * Call initialization code, and switch to the full blown HYP code.
         * cpus_have_const_cap() wrapper.
         */
        BUG_ON(!system_capabilities_finalized());
+       params = this_cpu_ptr_nvhe_sym(kvm_init_params);
        arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(__kvm_hyp_init), virt_to_phys(params), &res);
        WARN_ON(res.a0 != SMCCC_RET_SUCCESS);
+ }
+ static void cpu_init_hyp_mode(void)
+ {
+       hyp_install_host_vector();
  
        /*
         * Disabling SSBD on a non-VHE system requires us to enable SSBS
@@@ -1489,7 -1501,10 +1503,10 @@@ static void cpu_set_hyp_vector(void
        struct bp_hardening_data *data = this_cpu_ptr(&bp_hardening_data);
        void *vector = hyp_spectre_vector_selector[data->slot];
  
-       *this_cpu_ptr_hyp_sym(kvm_hyp_vector) = (unsigned long)vector;
+       if (!is_protected_kvm_enabled())
+               *this_cpu_ptr_hyp_sym(kvm_hyp_vector) = (unsigned long)vector;
+       else
+               kvm_call_hyp_nvhe(__pkvm_cpu_set_vector, data->slot);
  }
  
  static void cpu_hyp_reinit(void)
        kvm_init_host_cpu_context(&this_cpu_ptr_hyp_sym(kvm_host_data)->host_ctxt);
  
        cpu_hyp_reset();
-       cpu_set_hyp_vector();
  
        if (is_kernel_in_hyp_mode())
                kvm_timer_init_vhe();
        else
                cpu_init_hyp_mode();
  
+       cpu_set_hyp_vector();
        kvm_arm_init_debug();
  
        if (vgic_present)
@@@ -1699,18 -1715,62 +1717,62 @@@ static void teardown_hyp_mode(void
        }
  }
  
+ static int do_pkvm_init(u32 hyp_va_bits)
+ {
+       void *per_cpu_base = kvm_ksym_ref(kvm_arm_hyp_percpu_base);
+       int ret;
+       preempt_disable();
+       hyp_install_host_vector();
+       ret = kvm_call_hyp_nvhe(__pkvm_init, hyp_mem_base, hyp_mem_size,
+                               num_possible_cpus(), kern_hyp_va(per_cpu_base),
+                               hyp_va_bits);
+       preempt_enable();
+       return ret;
+ }
+ static int kvm_hyp_init_protection(u32 hyp_va_bits)
+ {
+       void *addr = phys_to_virt(hyp_mem_base);
+       int ret;
+       kvm_nvhe_sym(id_aa64mmfr0_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+       kvm_nvhe_sym(id_aa64mmfr1_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+       ret = create_hyp_mappings(addr, addr + hyp_mem_size, PAGE_HYP);
+       if (ret)
+               return ret;
+       ret = do_pkvm_init(hyp_va_bits);
+       if (ret)
+               return ret;
+       free_hyp_pgds();
+       return 0;
+ }
  /**
   * Inits Hyp-mode on all online CPUs
   */
  static int init_hyp_mode(void)
  {
+       u32 hyp_va_bits;
        int cpu;
-       int err = 0;
+       int err = -ENOMEM;
+       /*
+        * The protected Hyp-mode cannot be initialized if the memory pool
+        * allocation has failed.
+        */
+       if (is_protected_kvm_enabled() && !hyp_mem_base)
+               goto out_err;
  
        /*
         * Allocate Hyp PGD and setup Hyp identity mapping
         */
-       err = kvm_mmu_init();
+       err = kvm_mmu_init(&hyp_va_bits);
        if (err)
                goto out_err;
  
                goto out_err;
        }
  
-       err = create_hyp_mappings(kvm_ksym_ref(__bss_start),
+       /*
+        * .hyp.bss is guaranteed to be placed at the beginning of the .bss
+        * section thanks to an assertion in the linker script. Map it RW and
+        * the rest of .bss RO.
+        */
+       err = create_hyp_mappings(kvm_ksym_ref(__hyp_bss_start),
+                                 kvm_ksym_ref(__hyp_bss_end), PAGE_HYP);
+       if (err) {
+               kvm_err("Cannot map hyp bss section: %d\n", err);
+               goto out_err;
+       }
+       err = create_hyp_mappings(kvm_ksym_ref(__hyp_bss_end),
                                  kvm_ksym_ref(__bss_stop), PAGE_HYP_RO);
        if (err) {
                kvm_err("Cannot map bss section\n");
                }
        }
  
-       /*
-        * Map Hyp percpu pages
-        */
        for_each_possible_cpu(cpu) {
                char *percpu_begin = (char *)kvm_arm_hyp_percpu_base[cpu];
                char *percpu_end = percpu_begin + nvhe_percpu_size();
  
+               /* Map Hyp percpu pages */
                err = create_hyp_mappings(percpu_begin, percpu_end, PAGE_HYP);
                if (err) {
                        kvm_err("Cannot map hyp percpu region\n");
                        goto out_err;
                }
+               /* Prepare the CPU initialization parameters */
+               cpu_prepare_hyp_mode(cpu);
        }
  
        if (is_protected_kvm_enabled()) {
                init_cpu_logical_map();
  
-               if (!init_psci_relay())
+               if (!init_psci_relay()) {
+                       err = -ENODEV;
+                       goto out_err;
+               }
+       }
+       if (is_protected_kvm_enabled()) {
+               err = kvm_hyp_init_protection(hyp_va_bits);
+               if (err) {
+                       kvm_err("Failed to init hyp memory protection\n");
                        goto out_err;
+               }
        }
  
        return 0;
@@@ -1822,6 -1904,72 +1906,72 @@@ out_err
        return err;
  }
  
+ static void _kvm_host_prot_finalize(void *discard)
+ {
+       WARN_ON(kvm_call_hyp_nvhe(__pkvm_prot_finalize));
+ }
+ static inline int pkvm_mark_hyp(phys_addr_t start, phys_addr_t end)
+ {
+       return kvm_call_hyp_nvhe(__pkvm_mark_hyp, start, end);
+ }
+ #define pkvm_mark_hyp_section(__section)              \
+       pkvm_mark_hyp(__pa_symbol(__section##_start),   \
+                       __pa_symbol(__section##_end))
+ static int finalize_hyp_mode(void)
+ {
+       int cpu, ret;
+       if (!is_protected_kvm_enabled())
+               return 0;
+       ret = pkvm_mark_hyp_section(__hyp_idmap_text);
+       if (ret)
+               return ret;
+       ret = pkvm_mark_hyp_section(__hyp_text);
+       if (ret)
+               return ret;
+       ret = pkvm_mark_hyp_section(__hyp_rodata);
+       if (ret)
+               return ret;
+       ret = pkvm_mark_hyp_section(__hyp_bss);
+       if (ret)
+               return ret;
+       ret = pkvm_mark_hyp(hyp_mem_base, hyp_mem_base + hyp_mem_size);
+       if (ret)
+               return ret;
+       for_each_possible_cpu(cpu) {
+               phys_addr_t start = virt_to_phys((void *)kvm_arm_hyp_percpu_base[cpu]);
+               phys_addr_t end = start + (PAGE_SIZE << nvhe_percpu_order());
+               ret = pkvm_mark_hyp(start, end);
+               if (ret)
+                       return ret;
+               start = virt_to_phys((void *)per_cpu(kvm_arm_hyp_stack_page, cpu));
+               end = start + PAGE_SIZE;
+               ret = pkvm_mark_hyp(start, end);
+               if (ret)
+                       return ret;
+       }
+       /*
+        * Flip the static key upfront as that may no longer be possible
+        * once the host stage 2 is installed.
+        */
+       static_branch_enable(&kvm_protected_mode_initialized);
+       on_each_cpu(_kvm_host_prot_finalize, NULL, 1);
+       return 0;
+ }
  static void check_kvm_target_cpu(void *ret)
  {
        *(int *)ret = kvm_target_cpu();
@@@ -1896,11 -2044,6 +2046,6 @@@ int kvm_arch_init(void *opaque
  
        in_hyp_mode = is_kernel_in_hyp_mode();
  
-       if (!in_hyp_mode && kvm_arch_requires_vhe()) {
-               kvm_pr_unimpl("CPU unsupported in non-VHE mode, not initializing\n");
-               return -ENODEV;
-       }
        if (cpus_have_final_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ||
            cpus_have_final_cap(ARM64_WORKAROUND_1508412))
                kvm_info("Guests without required CPU erratum workarounds can deadlock system!\n" \
        if (err)
                goto out_hyp;
  
+       if (!in_hyp_mode) {
+               err = finalize_hyp_mode();
+               if (err) {
+                       kvm_err("Failed to finalize Hyp protection\n");
+                       goto out_hyp;
+               }
+       }
        if (is_protected_kvm_enabled()) {
-               static_branch_enable(&kvm_protected_mode_initialized);
                kvm_info("Protected nVHE mode initialized successfully\n");
        } else if (in_hyp_mode) {
                kvm_info("VHE mode initialized successfully\n");
diff --combined arch/arm64/kvm/guest.c
@@@ -299,7 -299,7 +299,7 @@@ static int get_sve_vls(struct kvm_vcpu 
  
        memset(vqs, 0, sizeof(vqs));
  
-       max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+       max_vq = vcpu_sve_max_vq(vcpu);
        for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
                if (sve_vq_available(vq))
                        vqs[vq_word(vq)] |= vq_mask(vq);
@@@ -427,7 -427,7 +427,7 @@@ static int sve_reg_to_region(struct sve
                if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
                        return -ENOENT;
  
-               vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+               vq = vcpu_sve_max_vq(vcpu);
  
                reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
                                SVE_SIG_REGS_OFFSET;
                if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
                        return -ENOENT;
  
-               vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+               vq = vcpu_sve_max_vq(vcpu);
  
                reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
                                SVE_SIG_REGS_OFFSET;
@@@ -888,6 -888,11 +888,6 @@@ int kvm_arch_vcpu_ioctl_translate(struc
        return -EINVAL;
  }
  
 -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE |    \
 -                          KVM_GUESTDBG_USE_SW_BP | \
 -                          KVM_GUESTDBG_USE_HW | \
 -                          KVM_GUESTDBG_SINGLESTEP)
 -
  /**
   * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging
   * @kvm:      pointer to the KVM struct
diff --combined arch/arm64/kvm/mmu.c
@@@ -88,6 -88,44 +88,44 @@@ static bool kvm_is_device_pfn(unsigned 
        return !pfn_valid(pfn);
  }
  
+ static void *stage2_memcache_zalloc_page(void *arg)
+ {
+       struct kvm_mmu_memory_cache *mc = arg;
+       /* Allocated with __GFP_ZERO, so no need to zero */
+       return kvm_mmu_memory_cache_alloc(mc);
+ }
+ static void *kvm_host_zalloc_pages_exact(size_t size)
+ {
+       return alloc_pages_exact(size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+ }
+ static void kvm_host_get_page(void *addr)
+ {
+       get_page(virt_to_page(addr));
+ }
+ static void kvm_host_put_page(void *addr)
+ {
+       put_page(virt_to_page(addr));
+ }
+ static int kvm_host_page_count(void *addr)
+ {
+       return page_count(virt_to_page(addr));
+ }
+ static phys_addr_t kvm_host_pa(void *addr)
+ {
+       return __pa(addr);
+ }
+ static void *kvm_host_va(phys_addr_t phys)
+ {
+       return __va(phys);
+ }
  /*
   * Unmapping vs dcache management:
   *
  static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size,
                                 bool may_block)
  {
-       struct kvm *kvm = mmu->kvm;
+       struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
        phys_addr_t end = start + size;
  
        assert_spin_locked(&kvm->mmu_lock);
@@@ -183,15 -221,39 +221,39 @@@ void free_hyp_pgds(void
        if (hyp_pgtable) {
                kvm_pgtable_hyp_destroy(hyp_pgtable);
                kfree(hyp_pgtable);
+               hyp_pgtable = NULL;
        }
        mutex_unlock(&kvm_hyp_pgd_mutex);
  }
  
+ static bool kvm_host_owns_hyp_mappings(void)
+ {
+       if (static_branch_likely(&kvm_protected_mode_initialized))
+               return false;
+       /*
+        * This can happen at boot time when __create_hyp_mappings() is called
+        * after the hyp protection has been enabled, but the static key has
+        * not been flipped yet.
+        */
+       if (!hyp_pgtable && is_protected_kvm_enabled())
+               return false;
+       WARN_ON(!hyp_pgtable);
+       return true;
+ }
  static int __create_hyp_mappings(unsigned long start, unsigned long size,
                                 unsigned long phys, enum kvm_pgtable_prot prot)
  {
        int err;
  
+       if (!kvm_host_owns_hyp_mappings()) {
+               return kvm_call_hyp_nvhe(__pkvm_create_mappings,
+                                        start, size, phys, prot);
+       }
        mutex_lock(&kvm_hyp_pgd_mutex);
        err = kvm_pgtable_hyp_map(hyp_pgtable, start, size, phys, prot);
        mutex_unlock(&kvm_hyp_pgd_mutex);
@@@ -253,6 -315,16 +315,16 @@@ static int __create_hyp_private_mapping
        unsigned long base;
        int ret = 0;
  
+       if (!kvm_host_owns_hyp_mappings()) {
+               base = kvm_call_hyp_nvhe(__pkvm_create_private_mapping,
+                                        phys_addr, size, prot);
+               if (IS_ERR_OR_NULL((void *)base))
+                       return PTR_ERR((void *)base);
+               *haddr = base;
+               return 0;
+       }
        mutex_lock(&kvm_hyp_pgd_mutex);
  
        /*
@@@ -351,6 -423,17 +423,17 @@@ int create_hyp_exec_mappings(phys_addr_
        return 0;
  }
  
+ static struct kvm_pgtable_mm_ops kvm_s2_mm_ops = {
+       .zalloc_page            = stage2_memcache_zalloc_page,
+       .zalloc_pages_exact     = kvm_host_zalloc_pages_exact,
+       .free_pages_exact       = free_pages_exact,
+       .get_page               = kvm_host_get_page,
+       .put_page               = kvm_host_put_page,
+       .page_count             = kvm_host_page_count,
+       .phys_to_virt           = kvm_host_va,
+       .virt_to_phys           = kvm_host_pa,
+ };
  /**
   * kvm_init_stage2_mmu - Initialise a S2 MMU strucrure
   * @kvm:      The pointer to the KVM structure
@@@ -374,7 -457,7 +457,7 @@@ int kvm_init_stage2_mmu(struct kvm *kvm
        if (!pgt)
                return -ENOMEM;
  
-       err = kvm_pgtable_stage2_init(pgt, kvm);
+       err = kvm_pgtable_stage2_init(pgt, &kvm->arch, &kvm_s2_mm_ops);
        if (err)
                goto out_free_pgtable;
  
        for_each_possible_cpu(cpu)
                *per_cpu_ptr(mmu->last_vcpu_ran, cpu) = -1;
  
-       mmu->kvm = kvm;
+       mmu->arch = &kvm->arch;
        mmu->pgt = pgt;
        mmu->pgd_phys = __pa(pgt->pgd);
        mmu->vmid.vmid_gen = 0;
@@@ -421,10 -504,11 +504,11 @@@ static void stage2_unmap_memslot(struc
         *     +--------------------------------------------+
         */
        do {
-               struct vm_area_struct *vma = find_vma(current->mm, hva);
+               struct vm_area_struct *vma;
                hva_t vm_start, vm_end;
  
-               if (!vma || vma->vm_start >= reg_end)
+               vma = find_vma_intersection(current->mm, hva, reg_end);
+               if (!vma)
                        break;
  
                /*
@@@ -469,7 -553,7 +553,7 @@@ void stage2_unmap_vm(struct kvm *kvm
  
  void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
  {
-       struct kvm *kvm = mmu->kvm;
+       struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
        struct kvm_pgtable *pgt = NULL;
  
        spin_lock(&kvm->mmu_lock);
@@@ -538,7 -622,7 +622,7 @@@ int kvm_phys_addr_ioremap(struct kvm *k
   */
  static void stage2_wp_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end)
  {
-       struct kvm *kvm = mmu->kvm;
+       struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
        stage2_apply_range_resched(kvm, addr, end, kvm_pgtable_stage2_wrprotect);
  }
  
   * Acquires kvm_mmu_lock. Called with kvm->slots_lock mutex acquired,
   * serializing operations for VM memory regions.
   */
- void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot)
static void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot)
  {
        struct kvm_memslots *slots = kvm_memslots(kvm);
        struct kvm_memory_slot *memslot = id_to_memslot(slots, slot);
@@@ -839,13 -923,18 +923,18 @@@ static int user_mem_abort(struct kvm_vc
         * gfn_to_pfn_prot (which calls get_user_pages), so that we don't risk
         * the page we just got a reference to gets unmapped before we have a
         * chance to grab the mmu_lock, which ensure that if the page gets
 -       * unmapped afterwards, the call to kvm_unmap_hva will take it away
 +       * unmapped afterwards, the call to kvm_unmap_gfn will take it away
         * from us again properly. This smp_rmb() interacts with the smp_wmb()
         * in kvm_mmu_notifier_invalidate_<page|range_end>.
+        *
+        * Besides, __gfn_to_pfn_memslot() instead of gfn_to_pfn_prot() is
+        * used to avoid unnecessary overhead introduced to locate the memory
+        * slot because it's always fixed even @gfn is adjusted for huge pages.
         */
        smp_rmb();
  
-       pfn = gfn_to_pfn_prot(kvm, gfn, write_fault, &writable);
+       pfn = __gfn_to_pfn_memslot(memslot, gfn, false, NULL,
+                                  write_fault, &writable, NULL);
        if (pfn == KVM_PFN_ERR_HWPOISON) {
                kvm_send_hwpoison_signal(hva, vma_shift);
                return 0;
        /* Mark the page dirty only if the fault is handled successfully */
        if (writable && !ret) {
                kvm_set_pfn_dirty(pfn);
-               mark_page_dirty(kvm, gfn);
+               mark_page_dirty_in_slot(kvm, memslot, gfn);
        }
  
  out_unlock:
@@@ -1064,70 -1153,126 +1153,70 @@@ out_unlock
        return ret;
  }
  
 -static int handle_hva_to_gpa(struct kvm *kvm,
 -                           unsigned long start,
 -                           unsigned long end,
 -                           int (*handler)(struct kvm *kvm,
 -                                          gpa_t gpa, u64 size,
 -                                          void *data),
 -                           void *data)
 -{
 -      struct kvm_memslots *slots;
 -      struct kvm_memory_slot *memslot;
 -      int ret = 0;
 -
 -      slots = kvm_memslots(kvm);
 -
 -      /* we only care about the pages that the guest sees */
 -      kvm_for_each_memslot(memslot, slots) {
 -              unsigned long hva_start, hva_end;
 -              gfn_t gpa;
 -
 -              hva_start = max(start, memslot->userspace_addr);
 -              hva_end = min(end, memslot->userspace_addr +
 -                                      (memslot->npages << PAGE_SHIFT));
 -              if (hva_start >= hva_end)
 -                      continue;
 -
 -              gpa = hva_to_gfn_memslot(hva_start, memslot) << PAGE_SHIFT;
 -              ret |= handler(kvm, gpa, (u64)(hva_end - hva_start), data);
 -      }
 -
 -      return ret;
 -}
 -
 -static int kvm_unmap_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *data)
 -{
 -      unsigned flags = *(unsigned *)data;
 -      bool may_block = flags & MMU_NOTIFIER_RANGE_BLOCKABLE;
 -
 -      __unmap_stage2_range(&kvm->arch.mmu, gpa, size, may_block);
 -      return 0;
 -}
 -
 -int kvm_unmap_hva_range(struct kvm *kvm,
 -                      unsigned long start, unsigned long end, unsigned flags)
 +bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
  {
        if (!kvm->arch.mmu.pgt)
                return 0;
  
 -      trace_kvm_unmap_hva_range(start, end);
 -      handle_hva_to_gpa(kvm, start, end, &kvm_unmap_hva_handler, &flags);
 -      return 0;
 -}
 -
 -static int kvm_set_spte_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *data)
 -{
 -      kvm_pfn_t *pfn = (kvm_pfn_t *)data;
 -
 -      WARN_ON(size != PAGE_SIZE);
 +      __unmap_stage2_range(&kvm->arch.mmu, range->start << PAGE_SHIFT,
 +                           (range->end - range->start) << PAGE_SHIFT,
 +                           range->may_block);
  
 -      /*
 -       * The MMU notifiers will have unmapped a huge PMD before calling
 -       * ->change_pte() (which in turn calls kvm_set_spte_hva()) and
 -       * therefore we never need to clear out a huge PMD through this
 -       * calling path and a memcache is not required.
 -       */
 -      kvm_pgtable_stage2_map(kvm->arch.mmu.pgt, gpa, PAGE_SIZE,
 -                             __pfn_to_phys(*pfn), KVM_PGTABLE_PROT_R, NULL);
        return 0;
  }
  
 -int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
 +bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
  {
 -      unsigned long end = hva + PAGE_SIZE;
 -      kvm_pfn_t pfn = pte_pfn(pte);
 +      kvm_pfn_t pfn = pte_pfn(range->pte);
  
        if (!kvm->arch.mmu.pgt)
                return 0;
  
 -      trace_kvm_set_spte_hva(hva);
 +      WARN_ON(range->end - range->start != 1);
  
        /*
         * We've moved a page around, probably through CoW, so let's treat it
         * just like a translation fault and clean the cache to the PoC.
         */
        clean_dcache_guest_page(pfn, PAGE_SIZE);
 -      handle_hva_to_gpa(kvm, hva, end, &kvm_set_spte_handler, &pfn);
 +
 +      /*
 +       * The MMU notifiers will have unmapped a huge PMD before calling
 +       * ->change_pte() (which in turn calls kvm_set_spte_gfn()) and
 +       * therefore we never need to clear out a huge PMD through this
 +       * calling path and a memcache is not required.
 +       */
 +      kvm_pgtable_stage2_map(kvm->arch.mmu.pgt, range->start << PAGE_SHIFT,
 +                             PAGE_SIZE, __pfn_to_phys(pfn),
 +                             KVM_PGTABLE_PROT_R, NULL);
 +
        return 0;
  }
  
 -static int kvm_age_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *data)
 +bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
  {
 -      pte_t pte;
 +      u64 size = (range->end - range->start) << PAGE_SHIFT;
        kvm_pte_t kpte;
 +      pte_t pte;
 +
 +      if (!kvm->arch.mmu.pgt)
 +              return 0;
  
        WARN_ON(size != PAGE_SIZE && size != PMD_SIZE && size != PUD_SIZE);
 -      kpte = kvm_pgtable_stage2_mkold(kvm->arch.mmu.pgt, gpa);
 +
 +      kpte = kvm_pgtable_stage2_mkold(kvm->arch.mmu.pgt,
 +                                      range->start << PAGE_SHIFT);
        pte = __pte(kpte);
        return pte_valid(pte) && pte_young(pte);
  }
  
 -static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *data)
 -{
 -      WARN_ON(size != PAGE_SIZE && size != PMD_SIZE && size != PUD_SIZE);
 -      return kvm_pgtable_stage2_is_young(kvm->arch.mmu.pgt, gpa);
 -}
 -
 -int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
 +bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
  {
        if (!kvm->arch.mmu.pgt)
                return 0;
 -      trace_kvm_age_hva(start, end);
 -      return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL);
 -}
  
 -int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
 -{
 -      if (!kvm->arch.mmu.pgt)
 -              return 0;
 -      trace_kvm_test_age_hva(hva);
 -      return handle_hva_to_gpa(kvm, hva, hva + PAGE_SIZE,
 -                               kvm_test_age_hva_handler, NULL);
 +      return kvm_pgtable_stage2_is_young(kvm->arch.mmu.pgt,
 +                                         range->start << PAGE_SHIFT);
  }
  
  phys_addr_t kvm_mmu_get_httbr(void)
@@@ -1152,10 -1297,22 +1241,22 @@@ static int kvm_map_idmap_text(void
        return err;
  }
  
- int kvm_mmu_init(void)
+ static void *kvm_hyp_zalloc_page(void *arg)
+ {
+       return (void *)get_zeroed_page(GFP_KERNEL);
+ }
+ static struct kvm_pgtable_mm_ops kvm_hyp_mm_ops = {
+       .zalloc_page            = kvm_hyp_zalloc_page,
+       .get_page               = kvm_host_get_page,
+       .put_page               = kvm_host_put_page,
+       .phys_to_virt           = kvm_host_va,
+       .virt_to_phys           = kvm_host_pa,
+ };
+ int kvm_mmu_init(u32 *hyp_va_bits)
  {
        int err;
-       u32 hyp_va_bits;
  
        hyp_idmap_start = __pa_symbol(__hyp_idmap_text_start);
        hyp_idmap_start = ALIGN_DOWN(hyp_idmap_start, PAGE_SIZE);
         */
        BUG_ON((hyp_idmap_start ^ (hyp_idmap_end - 1)) & PAGE_MASK);
  
-       hyp_va_bits = 64 - ((idmap_t0sz & TCR_T0SZ_MASK) >> TCR_T0SZ_OFFSET);
-       kvm_debug("Using %u-bit virtual addresses at EL2\n", hyp_va_bits);
+       *hyp_va_bits = 64 - ((idmap_t0sz & TCR_T0SZ_MASK) >> TCR_T0SZ_OFFSET);
+       kvm_debug("Using %u-bit virtual addresses at EL2\n", *hyp_va_bits);
        kvm_debug("IDMAP page: %lx\n", hyp_idmap_start);
        kvm_debug("HYP VA range: %lx:%lx\n",
                  kern_hyp_va(PAGE_OFFSET),
                goto out;
        }
  
-       err = kvm_pgtable_hyp_init(hyp_pgtable, hyp_va_bits);
+       err = kvm_pgtable_hyp_init(hyp_pgtable, *hyp_va_bits, &kvm_hyp_mm_ops);
        if (err)
                goto out_free_pgtable;
  
@@@ -1273,10 -1430,11 +1374,11 @@@ int kvm_arch_prepare_memory_region(stru
         *     +--------------------------------------------+
         */
        do {
-               struct vm_area_struct *vma = find_vma(current->mm, hva);
+               struct vm_area_struct *vma;
                hva_t vm_start, vm_end;
  
-               if (!vma || vma->vm_start >= reg_end)
+               vma = find_vma_intersection(current->mm, hva, reg_end);
+               if (!vma)
                        break;
  
                /*
diff --combined include/uapi/linux/kvm.h
@@@ -1078,9 -1078,7 +1078,10 @@@ struct kvm_ppc_resize_hpt 
  #define KVM_CAP_DIRTY_LOG_RING 192
  #define KVM_CAP_X86_BUS_LOCK_EXIT 193
  #define KVM_CAP_PPC_DAWR1 194
 -#define KVM_CAP_PTP_KVM 195
 +#define KVM_CAP_SET_GUEST_DEBUG2 195
 +#define KVM_CAP_SGX_ATTRIBUTE 196
 +#define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 197
++#define KVM_CAP_PTP_KVM 198
  
  #ifdef KVM_CAP_IRQ_ROUTING
  
@@@ -1674,8 -1672,6 +1675,8 @@@ enum sev_cmd_id 
        KVM_SEV_CERT_EXPORT,
        /* Attestation report */
        KVM_SEV_GET_ATTESTATION_REPORT,
 +      /* Guest Migration Extension */
 +      KVM_SEV_SEND_CANCEL,
  
        KVM_SEV_NR_MAX,
  };
@@@ -1734,45 -1730,6 +1735,45 @@@ struct kvm_sev_attestation_report 
        __u32 len;
  };
  
 +struct kvm_sev_send_start {
 +      __u32 policy;
 +      __u64 pdh_cert_uaddr;
 +      __u32 pdh_cert_len;
 +      __u64 plat_certs_uaddr;
 +      __u32 plat_certs_len;
 +      __u64 amd_certs_uaddr;
 +      __u32 amd_certs_len;
 +      __u64 session_uaddr;
 +      __u32 session_len;
 +};
 +
 +struct kvm_sev_send_update_data {
 +      __u64 hdr_uaddr;
 +      __u32 hdr_len;
 +      __u64 guest_uaddr;
 +      __u32 guest_len;
 +      __u64 trans_uaddr;
 +      __u32 trans_len;
 +};
 +
 +struct kvm_sev_receive_start {
 +      __u32 handle;
 +      __u32 policy;
 +      __u64 pdh_uaddr;
 +      __u32 pdh_len;
 +      __u64 session_uaddr;
 +      __u32 session_len;
 +};
 +
 +struct kvm_sev_receive_update_data {
 +      __u64 hdr_uaddr;
 +      __u32 hdr_len;
 +      __u64 guest_uaddr;
 +      __u32 guest_len;
 +      __u64 trans_uaddr;
 +      __u32 trans_len;
 +};
 +
  #define KVM_DEV_ASSIGN_ENABLE_IOMMU   (1 << 0)
  #define KVM_DEV_ASSIGN_PCI_2_3                (1 << 1)
  #define KVM_DEV_ASSIGN_MASK_INTX      (1 << 2)
@@@ -1,6 -1,7 +1,7 @@@
  # SPDX-License-Identifier: GPL-2.0-only
  /aarch64/get-reg-list
  /aarch64/get-reg-list-sve
+ /aarch64/vgic_init
  /s390x/memop
  /s390x/resets
  /s390x/sync_regs_test
@@@ -8,13 -9,10 +9,13 @@@
  /x86_64/debug_regs
  /x86_64/evmcs_test
  /x86_64/get_cpuid_test
 +/x86_64/get_msr_index_features
  /x86_64/kvm_pv_test
 +/x86_64/hyperv_clock
  /x86_64/hyperv_cpuid
  /x86_64/mmio_warning_test
  /x86_64/platform_info_test
 +/x86_64/set_boot_cpu_id
  /x86_64/set_sregs_test
  /x86_64/smm_test
  /x86_64/state_test
@@@ -38,7 -36,6 +39,7 @@@
  /dirty_log_perf_test
  /hardware_disable_test
  /kvm_create_max_vcpus
 +/kvm_page_table_test
  /memslot_modification_stress_test
  /set_memory_region_test
  /steal_time
@@@ -39,15 -39,12 +39,15 @@@ LIBKVM_aarch64 = lib/aarch64/processor.
  LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c
  
  TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
 +TEST_GEN_PROGS_x86_64 += x86_64/get_msr_index_features
  TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
  TEST_GEN_PROGS_x86_64 += x86_64/get_cpuid_test
 +TEST_GEN_PROGS_x86_64 += x86_64/hyperv_clock
  TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
  TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
  TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
  TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
 +TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id
  TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
  TEST_GEN_PROGS_x86_64 += x86_64/smm_test
  TEST_GEN_PROGS_x86_64 += x86_64/state_test
@@@ -72,18 -69,17 +72,19 @@@ TEST_GEN_PROGS_x86_64 += dirty_log_tes
  TEST_GEN_PROGS_x86_64 += dirty_log_perf_test
  TEST_GEN_PROGS_x86_64 += hardware_disable_test
  TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
 +TEST_GEN_PROGS_x86_64 += kvm_page_table_test
  TEST_GEN_PROGS_x86_64 += memslot_modification_stress_test
  TEST_GEN_PROGS_x86_64 += set_memory_region_test
  TEST_GEN_PROGS_x86_64 += steal_time
  
  TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
  TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list-sve
+ TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
  TEST_GEN_PROGS_aarch64 += demand_paging_test
  TEST_GEN_PROGS_aarch64 += dirty_log_test
  TEST_GEN_PROGS_aarch64 += dirty_log_perf_test
  TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus
 +TEST_GEN_PROGS_aarch64 += kvm_page_table_test
  TEST_GEN_PROGS_aarch64 += set_memory_region_test
  TEST_GEN_PROGS_aarch64 += steal_time
  
@@@ -93,7 -89,6 +94,7 @@@ TEST_GEN_PROGS_s390x += s390x/sync_regs
  TEST_GEN_PROGS_s390x += demand_paging_test
  TEST_GEN_PROGS_s390x += dirty_log_test
  TEST_GEN_PROGS_s390x += kvm_create_max_vcpus
 +TEST_GEN_PROGS_s390x += kvm_page_table_test
  TEST_GEN_PROGS_s390x += set_memory_region_test
  
  TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M))
@@@ -16,7 -16,6 +16,7 @@@
  
  #include "sparsebit.h"
  
 +#define KVM_DEV_PATH "/dev/kvm"
  #define KVM_MAX_VCPUS 512
  
  /*
@@@ -69,6 -68,9 +69,6 @@@ enum vm_guest_mode 
  #define MIN_PAGE_SIZE         (1U << MIN_PAGE_SHIFT)
  #define PTES_PER_MIN_PAGE     ptes_per_page(MIN_PAGE_SIZE)
  
 -#define vm_guest_mode_string(m) vm_guest_mode_string[m]
 -extern const char * const vm_guest_mode_string[];
 -
  struct vm_guest_mode_params {
        unsigned int pa_bits;
        unsigned int va_bits;
@@@ -82,7 -84,6 +82,7 @@@ int vm_enable_cap(struct kvm_vm *vm, st
  int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id,
                    struct kvm_enable_cap *cap);
  void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size);
 +const char *vm_guest_mode_string(uint32_t i);
  
  struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm);
  void kvm_vm_free(struct kvm_vm *vmp);
@@@ -132,7 -133,6 +132,7 @@@ void vcpu_ioctl(struct kvm_vm *vm, uint
  int _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl,
                void *arg);
  void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
 +int _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg);
  void kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
  int _kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
  void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
@@@ -223,6 -223,15 +223,15 @@@ int vcpu_nested_state_set(struct kvm_v
  #endif
  void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid);
  
+ int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr);
+ int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr);
+ int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd);
+ int kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test);
+ int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr,
+                      void *val, bool write);
+ int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr,
+                     void *val, bool write);
  const char *exit_reason_str(unsigned int exit_reason);
  
  void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot);
@@@ -18,6 -18,7 +18,6 @@@
  #include <unistd.h>
  #include <linux/kernel.h>
  
 -#define KVM_UTIL_PGS_PER_HUGEPG 512
  #define KVM_UTIL_MIN_PFN      2
  
  static int vcpu_mmap_sz(void);
@@@ -142,24 -143,17 +142,24 @@@ static void vm_open(struct kvm_vm *vm, 
                "rc: %i errno: %i", vm->fd, errno);
  }
  
 -const char * const vm_guest_mode_string[] = {
 -      "PA-bits:52,  VA-bits:48,  4K pages",
 -      "PA-bits:52,  VA-bits:48, 64K pages",
 -      "PA-bits:48,  VA-bits:48,  4K pages",
 -      "PA-bits:48,  VA-bits:48, 64K pages",
 -      "PA-bits:40,  VA-bits:48,  4K pages",
 -      "PA-bits:40,  VA-bits:48, 64K pages",
 -      "PA-bits:ANY, VA-bits:48,  4K pages",
 -};
 -_Static_assert(sizeof(vm_guest_mode_string)/sizeof(char *) == NUM_VM_MODES,
 -             "Missing new mode strings?");
 +const char *vm_guest_mode_string(uint32_t i)
 +{
 +      static const char * const strings[] = {
 +              [VM_MODE_P52V48_4K]     = "PA-bits:52,  VA-bits:48,  4K pages",
 +              [VM_MODE_P52V48_64K]    = "PA-bits:52,  VA-bits:48, 64K pages",
 +              [VM_MODE_P48V48_4K]     = "PA-bits:48,  VA-bits:48,  4K pages",
 +              [VM_MODE_P48V48_64K]    = "PA-bits:48,  VA-bits:48, 64K pages",
 +              [VM_MODE_P40V48_4K]     = "PA-bits:40,  VA-bits:48,  4K pages",
 +              [VM_MODE_P40V48_64K]    = "PA-bits:40,  VA-bits:48, 64K pages",
 +              [VM_MODE_PXXV48_4K]     = "PA-bits:ANY, VA-bits:48,  4K pages",
 +      };
 +      _Static_assert(sizeof(strings)/sizeof(char *) == NUM_VM_MODES,
 +                     "Missing new mode strings?");
 +
 +      TEST_ASSERT(i < NUM_VM_MODES, "Guest mode ID %d too big", i);
 +
 +      return strings[i];
 +}
  
  const struct vm_guest_mode_params vm_guest_mode_params[] = {
        { 52, 48,  0x1000, 12 },
@@@ -687,7 -681,7 +687,7 @@@ void vm_userspace_mem_region_add(struc
  {
        int ret;
        struct userspace_mem_region *region;
 -      size_t huge_page_size = KVM_UTIL_PGS_PER_HUGEPG * vm->page_size;
 +      size_t backing_src_pagesz = get_backing_src_pagesz(src_type);
        size_t alignment;
  
        TEST_ASSERT(vm_adjust_num_guest_pages(vm->mode, npages) == npages,
  #endif
  
        if (src_type == VM_MEM_SRC_ANONYMOUS_THP)
 -              alignment = max(huge_page_size, alignment);
 +              alignment = max(backing_src_pagesz, alignment);
  
        /* Add enough memory to align up if necessary */
        if (alignment > 1)
        region->mmap_start = mmap(NULL, region->mmap_size,
                                  PROT_READ | PROT_WRITE,
                                  MAP_PRIVATE | MAP_ANONYMOUS
 -                                | (src_type == VM_MEM_SRC_ANONYMOUS_HUGETLB ? MAP_HUGETLB : 0),
 +                                | vm_mem_backing_src_alias(src_type)->flag,
                                  -1, 0);
        TEST_ASSERT(region->mmap_start != MAP_FAILED,
                    "test_malloc failed, mmap_start: %p errno: %i",
        region->host_mem = align(region->mmap_start, alignment);
  
        /* As needed perform madvise */
 -      if (src_type == VM_MEM_SRC_ANONYMOUS || src_type == VM_MEM_SRC_ANONYMOUS_THP) {
 -              struct stat statbuf;
 -
 -              ret = stat("/sys/kernel/mm/transparent_hugepage", &statbuf);
 -              TEST_ASSERT(ret == 0 || (ret == -1 && errno == ENOENT),
 -                          "stat /sys/kernel/mm/transparent_hugepage");
 -
 -              TEST_ASSERT(ret == 0 || src_type != VM_MEM_SRC_ANONYMOUS_THP,
 -                          "VM_MEM_SRC_ANONYMOUS_THP requires THP to be configured in the host kernel");
 -
 -              if (ret == 0) {
 -                      ret = madvise(region->host_mem, npages * vm->page_size,
 -                                    src_type == VM_MEM_SRC_ANONYMOUS ? MADV_NOHUGEPAGE : MADV_HUGEPAGE);
 -                      TEST_ASSERT(ret == 0, "madvise failed, addr: %p length: 0x%lx src_type: %x",
 -                                  region->host_mem, npages * vm->page_size, src_type);
 -              }
 +      if ((src_type == VM_MEM_SRC_ANONYMOUS ||
 +           src_type == VM_MEM_SRC_ANONYMOUS_THP) && thp_configured()) {
 +              ret = madvise(region->host_mem, npages * vm->page_size,
 +                            src_type == VM_MEM_SRC_ANONYMOUS ? MADV_NOHUGEPAGE : MADV_HUGEPAGE);
 +              TEST_ASSERT(ret == 0, "madvise failed, addr: %p length: 0x%lx src_type: %s",
 +                          region->host_mem, npages * vm->page_size,
 +                          vm_mem_backing_src_alias(src_type)->name);
        }
  
        region->unused_phy_pages = sparsebit_alloc();
@@@ -1694,16 -1697,11 +1694,16 @@@ void vm_ioctl(struct kvm_vm *vm, unsign
  {
        int ret;
  
 -      ret = ioctl(vm->fd, cmd, arg);
 +      ret = _vm_ioctl(vm, cmd, arg);
        TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)",
                cmd, ret, errno, strerror(errno));
  }
  
 +int _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg)
 +{
 +      return ioctl(vm->fd, cmd, arg);
 +}
 +
  /*
   * KVM system ioctl
   *
@@@ -1731,6 -1729,81 +1731,81 @@@ int _kvm_ioctl(struct kvm_vm *vm, unsig
  }
  
  /*
+  * Device Ioctl
+  */
+ int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr)
+ {
+       struct kvm_device_attr attribute = {
+               .group = group,
+               .attr = attr,
+               .flags = 0,
+       };
+       return ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute);
+ }
+ int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr)
+ {
+       int ret = _kvm_device_check_attr(dev_fd, group, attr);
+       TEST_ASSERT(ret >= 0, "KVM_HAS_DEVICE_ATTR failed, rc: %i errno: %i", ret, errno);
+       return ret;
+ }
+ int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd)
+ {
+       struct kvm_create_device create_dev;
+       int ret;
+       create_dev.type = type;
+       create_dev.fd = -1;
+       create_dev.flags = test ? KVM_CREATE_DEVICE_TEST : 0;
+       ret = ioctl(vm_get_fd(vm), KVM_CREATE_DEVICE, &create_dev);
+       *fd = create_dev.fd;
+       return ret;
+ }
+ int kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test)
+ {
+       int fd, ret;
+       ret = _kvm_create_device(vm, type, test, &fd);
+       if (!test) {
+               TEST_ASSERT(ret >= 0,
+                           "KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i", ret, errno);
+               return fd;
+       }
+       return ret;
+ }
+ int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr,
+                     void *val, bool write)
+ {
+       struct kvm_device_attr kvmattr = {
+               .group = group,
+               .attr = attr,
+               .flags = 0,
+               .addr = (uintptr_t)val,
+       };
+       int ret;
+       ret = ioctl(dev_fd, write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR,
+                   &kvmattr);
+       return ret;
+ }
+ int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr,
+                     void *val, bool write)
+ {
+       int ret = _kvm_device_access(dev_fd, group, attr, val, write);
+       TEST_ASSERT(ret >= 0, "KVM_SET|GET_DEVICE_ATTR IOCTL failed, rc: %i errno: %i", ret, errno);
+       return ret;
+ }
+ /*
   * VM Dump
   *
   * Input Args: