mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm updates from Paolo Bonzini:
"ARM:
- Initial infrastructure for shadow stage-2 MMUs, as part of nested
virtualization enablement
- Support for userspace changes to the guest CTR_EL0 value, enabling
(in part) migration of VMs between heterogenous hardware
- Fixes + improvements to pKVM's FF-A proxy, adding support for v1.1
of the protocol
- FPSIMD/SVE support for nested, including merged trap configuration
and exception routing
- New command-line parameter to control the WFx trap behavior under
KVM
- Introduce kCFI hardening in the EL2 hypervisor
- Fixes + cleanups for handling presence/absence of FEAT_TCRX
- Miscellaneous fixes + documentation updates
LoongArch:
- Add paravirt steal time support
- Add support for KVM_DIRTY_LOG_INITIALLY_SET
- Add perf kvm-stat support for loongarch
RISC-V:
- Redirect AMO load/store access fault traps to guest
- perf kvm stat support
- Use guest files for IMSIC virtualization, when available
s390:
- Assortment of tiny fixes which are not time critical
x86:
- Fixes for Xen emulation
- Add a global struct to consolidate tracking of host values, e.g.
EFER
- Add KVM_CAP_X86_APIC_BUS_CYCLES_NS to allow configuring the
effective APIC bus frequency, because TDX
- Print the name of the APICv/AVIC inhibits in the relevant
tracepoint
- Clean up KVM's handling of vendor specific emulation to
consistently act on "compatible with Intel/AMD", versus checking
for a specific vendor
- Drop MTRR virtualization, and instead always honor guest PAT on
CPUs that support self-snoop
- Update to the newfangled Intel CPU FMS infrastructure
- Don't advertise IA32_PERF_GLOBAL_OVF_CTRL as an MSR-to-be-saved, as
it reads '0' and writes from userspace are ignored
- Misc cleanups
x86 - MMU:
- Small cleanups, renames and refactoring extracted from the upcoming
Intel TDX support
- Don't allocate kvm_mmu_page.shadowed_translation for shadow pages
that can't hold leafs SPTEs
- Unconditionally drop mmu_lock when allocating TDP MMU page tables
for eager page splitting, to avoid stalling vCPUs when splitting
huge pages
- Bug the VM instead of simply warning if KVM tries to split a SPTE
that is non-present or not-huge. KVM is guaranteed to end up in a
broken state because the callers fully expect a valid SPTE, it's
all but dangerous to let more MMU changes happen afterwards
x86 - AMD:
- Make per-CPU save_area allocations NUMA-aware
- Force sev_es_host_save_area() to be inlined to avoid calling into
an instrumentable function from noinstr code
- Base support for running SEV-SNP guests. API-wise, this includes a
new KVM_X86_SNP_VM type, encrypting/measure the initial image into
guest memory, and finalizing it before launching it. Internally,
there are some gmem/mmu hooks needed to prepare gmem-allocated
pages before mapping them into guest private memory ranges
This includes basic support for attestation guest requests, enough
to say that KVM supports the GHCB 2.0 specification
There is no support yet for loading into the firmware those signing
keys to be used for attestation requests, and therefore no need yet
for the host to provide certificate data for those keys.
To support fetching certificate data from userspace, a new KVM exit
type will be needed to handle fetching the certificate from
userspace.
An attempt to define a new KVM_EXIT_COCO / KVM_EXIT_COCO_REQ_CERTS
exit type to handle this was introduced in v1 of this patchset, but
is still being discussed by community, so for now this patchset
only implements a stub version of SNP Extended Guest Requests that
does not provide certificate data
x86 - Intel:
- Remove an unnecessary EPT TLB flush when enabling hardware
- Fix a series of bugs that cause KVM to fail to detect nested
pending posted interrupts as valid wake eents for a vCPU executing
HLT in L2 (with HLT-exiting disable by L1)
- KVM: x86: Suppress MMIO that is triggered during task switch
emulation
Explicitly suppress userspace emulated MMIO exits that are
triggered when emulating a task switch as KVM doesn't support
userspace MMIO during complex (multi-step) emulation
Silently ignoring the exit request can result in the
WARN_ON_ONCE(vcpu->mmio_needed) firing if KVM exits to userspace
for some other reason prior to purging mmio_needed
See commit 0dc902267c ("KVM: x86: Suppress pending MMIO write
exits if emulator detects exception") for more details on KVM's
limitations with respect to emulated MMIO during complex emulator
flows
Generic:
- Rename the AS_UNMOVABLE flag that was introduced for KVM to
AS_INACCESSIBLE, because the special casing needed by these pages
is not due to just unmovability (and in fact they are only
unmovable because the CPU cannot access them)
- New ioctl to populate the KVM page tables in advance, which is
useful to mitigate KVM page faults during guest boot or after live
migration. The code will also be used by TDX, but (probably) not
through the ioctl
- Enable halt poll shrinking by default, as Intel found it to be a
clear win
- Setup empty IRQ routing when creating a VM to avoid having to
synchronize SRCU when creating a split IRQCHIP on x86
- Rework the sched_in/out() paths to replace kvm_arch_sched_in() with
a flag that arch code can use for hooking both sched_in() and
sched_out()
- Take the vCPU @id as an "unsigned long" instead of "u32" to avoid
truncating a bogus value from userspace, e.g. to help userspace
detect bugs
- Mark a vCPU as preempted if and only if it's scheduled out while in
the KVM_RUN loop, e.g. to avoid marking it preempted and thus
writing guest memory when retrieving guest state during live
migration blackout
Selftests:
- Remove dead code in the memslot modification stress test
- Treat "branch instructions retired" as supported on all AMD Family
17h+ CPUs
- Print the guest pseudo-RNG seed only when it changes, to avoid
spamming the log for tests that create lots of VMs
- Make the PMU counters test less flaky when counting LLC cache
misses by doing CLFLUSH{OPT} in every loop iteration"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (227 commits)
crypto: ccp: Add the SNP_VLEK_LOAD command
KVM: x86/pmu: Add kvm_pmu_call() to simplify static calls of kvm_pmu_ops
KVM: x86: Introduce kvm_x86_call() to simplify static calls of kvm_x86_ops
KVM: x86: Replace static_call_cond() with static_call()
KVM: SEV: Provide support for SNP_EXTENDED_GUEST_REQUEST NAE event
x86/sev: Move sev_guest.h into common SEV header
KVM: SEV: Provide support for SNP_GUEST_REQUEST NAE event
KVM: x86: Suppress MMIO that is triggered during task switch emulation
KVM: x86/mmu: Clean up make_huge_page_split_spte() definition and intro
KVM: x86/mmu: Bug the VM if KVM tries to split a !hugepage SPTE
KVM: selftests: x86: Add test for KVM_PRE_FAULT_MEMORY
KVM: x86: Implement kvm_arch_vcpu_pre_fault_memory()
KVM: x86/mmu: Make kvm_mmu_do_page_fault() return mapped level
KVM: x86/mmu: Account pf_{fixed,emulate,spurious} in callers of "do page fault"
KVM: x86/mmu: Bump pf_taken stat only in the "real" page fault handler
KVM: Add KVM_PRE_FAULT_MEMORY vcpu ioctl to pre-populate guest memory
KVM: Document KVM_PRE_FAULT_MEMORY ioctl
mm, virt: merge AS_UNMOVABLE and AS_INACCESSIBLE
perf kvm: Add kvm-stat for loongarch64
LoongArch: KVM: Add PV steal time support in guest side
...
This commit is contained in:
@@ -2722,6 +2722,24 @@
|
||||
[KVM,ARM,EARLY] Allow use of GICv4 for direct
|
||||
injection of LPIs.
|
||||
|
||||
kvm-arm.wfe_trap_policy=
|
||||
[KVM,ARM] Control when to set WFE instruction trap for
|
||||
KVM VMs. Traps are allowed but not guaranteed by the
|
||||
CPU architecture.
|
||||
|
||||
trap: set WFE instruction trap
|
||||
|
||||
notrap: clear WFE instruction trap
|
||||
|
||||
kvm-arm.wfi_trap_policy=
|
||||
[KVM,ARM] Control when to set WFI instruction trap for
|
||||
KVM VMs. Traps are allowed but not guaranteed by the
|
||||
CPU architecture.
|
||||
|
||||
trap: set WFI instruction trap
|
||||
|
||||
notrap: clear WFI instruction trap
|
||||
|
||||
kvm_cma_resv_ratio=n [PPC,EARLY]
|
||||
Reserves given percentage from system memory area for
|
||||
contiguous memory allocation for KVM hash pagetable
|
||||
@@ -4036,9 +4054,9 @@
|
||||
prediction) vulnerability. System may allow data
|
||||
leaks with this option.
|
||||
|
||||
no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV,EARLY] Disable
|
||||
paravirtualized steal time accounting. steal time is
|
||||
computed, but won't influence scheduler behaviour
|
||||
no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV,LOONGARCH,EARLY]
|
||||
Disable paravirtualized steal time accounting. steal time
|
||||
is computed, but won't influence scheduler behaviour
|
||||
|
||||
nosync [HW,M68K] Disables sync negotiation for all devices.
|
||||
|
||||
|
||||
@@ -176,6 +176,25 @@ to SNP_CONFIG command defined in the SEV-SNP spec. The current values of
|
||||
the firmware parameters affected by this command can be queried via
|
||||
SNP_PLATFORM_STATUS.
|
||||
|
||||
2.7 SNP_VLEK_LOAD
|
||||
-----------------
|
||||
:Technology: sev-snp
|
||||
:Type: hypervisor ioctl cmd
|
||||
:Parameters (in): struct sev_user_data_snp_vlek_load
|
||||
:Returns (out): 0 on success, -negative on error
|
||||
|
||||
When requesting an attestation report a guest is able to specify whether
|
||||
it wants SNP firmware to sign the report using either a Versioned Chip
|
||||
Endorsement Key (VCEK), which is derived from chip-unique secrets, or a
|
||||
Versioned Loaded Endorsement Key (VLEK) which is obtained from an AMD
|
||||
Key Derivation Service (KDS) and derived from seeds allocated to
|
||||
enrolled cloud service providers.
|
||||
|
||||
In the case of VLEK keys, the SNP_VLEK_LOAD SNP command is used to load
|
||||
them into the system after obtaining them from the KDS, and corresponds
|
||||
closely to the SNP_VLEK_LOAD firmware command specified in the SEV-SNP
|
||||
spec.
|
||||
|
||||
3. SEV-SNP CPUID Enforcement
|
||||
============================
|
||||
|
||||
|
||||
@@ -891,12 +891,12 @@ like this::
|
||||
|
||||
The irq_type field has the following values:
|
||||
|
||||
- irq_type[0]:
|
||||
- KVM_ARM_IRQ_TYPE_CPU:
|
||||
out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
|
||||
- irq_type[1]:
|
||||
- KVM_ARM_IRQ_TYPE_SPI:
|
||||
in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
|
||||
(the vcpu_index field is ignored)
|
||||
- irq_type[2]:
|
||||
- KVM_ARM_IRQ_TYPE_PPI:
|
||||
in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
|
||||
|
||||
(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
|
||||
@@ -1403,6 +1403,12 @@ Instead, an abort (data abort if the cause of the page-table update
|
||||
was a load or a store, instruction abort if it was an instruction
|
||||
fetch) is injected in the guest.
|
||||
|
||||
S390:
|
||||
^^^^^
|
||||
|
||||
Returns -EINVAL if the VM has the KVM_VM_S390_UCONTROL flag set.
|
||||
Returns -EINVAL if called on a protected VM.
|
||||
|
||||
4.36 KVM_SET_TSS_ADDR
|
||||
---------------------
|
||||
|
||||
@@ -1921,7 +1927,7 @@ flags:
|
||||
|
||||
If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
|
||||
for the device that wrote the MSI message. For PCI, this is usually a
|
||||
BFD identifier in the lower 16 bits.
|
||||
BDF identifier in the lower 16 bits.
|
||||
|
||||
On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
|
||||
feature of KVM_CAP_X2APIC_API capability is enabled. If it is enabled,
|
||||
@@ -2989,7 +2995,7 @@ flags:
|
||||
|
||||
If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
|
||||
for the device that wrote the MSI message. For PCI, this is usually a
|
||||
BFD identifier in the lower 16 bits.
|
||||
BDF identifier in the lower 16 bits.
|
||||
|
||||
On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
|
||||
feature of KVM_CAP_X2APIC_API capability is enabled. If it is enabled,
|
||||
@@ -6276,6 +6282,12 @@ state. At VM creation time, all memory is shared, i.e. the PRIVATE attribute
|
||||
is '0' for all gfns. Userspace can control whether memory is shared/private by
|
||||
toggling KVM_MEMORY_ATTRIBUTE_PRIVATE via KVM_SET_MEMORY_ATTRIBUTES as needed.
|
||||
|
||||
S390:
|
||||
^^^^^
|
||||
|
||||
Returns -EINVAL if the VM has the KVM_VM_S390_UCONTROL flag set.
|
||||
Returns -EINVAL if called on a protected VM.
|
||||
|
||||
4.141 KVM_SET_MEMORY_ATTRIBUTES
|
||||
-------------------------------
|
||||
|
||||
@@ -6355,6 +6367,61 @@ a single guest_memfd file, but the bound ranges must not overlap).
|
||||
|
||||
See KVM_SET_USER_MEMORY_REGION2 for additional details.
|
||||
|
||||
4.143 KVM_PRE_FAULT_MEMORY
|
||||
------------------------
|
||||
|
||||
:Capability: KVM_CAP_PRE_FAULT_MEMORY
|
||||
:Architectures: none
|
||||
:Type: vcpu ioctl
|
||||
:Parameters: struct kvm_pre_fault_memory (in/out)
|
||||
:Returns: 0 if at least one page is processed, < 0 on error
|
||||
|
||||
Errors:
|
||||
|
||||
========== ===============================================================
|
||||
EINVAL The specified `gpa` and `size` were invalid (e.g. not
|
||||
page aligned, causes an overflow, or size is zero).
|
||||
ENOENT The specified `gpa` is outside defined memslots.
|
||||
EINTR An unmasked signal is pending and no page was processed.
|
||||
EFAULT The parameter address was invalid.
|
||||
EOPNOTSUPP Mapping memory for a GPA is unsupported by the
|
||||
hypervisor, and/or for the current vCPU state/mode.
|
||||
EIO unexpected error conditions (also causes a WARN)
|
||||
========== ===============================================================
|
||||
|
||||
::
|
||||
|
||||
struct kvm_pre_fault_memory {
|
||||
/* in/out */
|
||||
__u64 gpa;
|
||||
__u64 size;
|
||||
/* in */
|
||||
__u64 flags;
|
||||
__u64 padding[5];
|
||||
};
|
||||
|
||||
KVM_PRE_FAULT_MEMORY populates KVM's stage-2 page tables used to map memory
|
||||
for the current vCPU state. KVM maps memory as if the vCPU generated a
|
||||
stage-2 read page fault, e.g. faults in memory as needed, but doesn't break
|
||||
CoW. However, KVM does not mark any newly created stage-2 PTE as Accessed.
|
||||
|
||||
In some cases, multiple vCPUs might share the page tables. In this
|
||||
case, the ioctl can be called in parallel.
|
||||
|
||||
When the ioctl returns, the input values are updated to point to the
|
||||
remaining range. If `size` > 0 on return, the caller can just issue
|
||||
the ioctl again with the same `struct kvm_map_memory` argument.
|
||||
|
||||
Shadow page tables cannot support this ioctl because they
|
||||
are indexed by virtual address or nested guest physical address.
|
||||
Calling this ioctl when the guest is using shadow page tables (for
|
||||
example because it is running a nested guest with nested page tables)
|
||||
will fail with `EOPNOTSUPP` even if `KVM_CHECK_EXTENSION` reports
|
||||
the capability to be present.
|
||||
|
||||
`flags` must currently be zero.
|
||||
|
||||
|
||||
5. The kvm_run structure
|
||||
========================
|
||||
|
||||
@@ -6419,9 +6486,12 @@ More architecture-specific flags detailing state of the VCPU that may
|
||||
affect the device's behavior. Current defined flags::
|
||||
|
||||
/* x86, set if the VCPU is in system management mode */
|
||||
#define KVM_RUN_X86_SMM (1 << 0)
|
||||
#define KVM_RUN_X86_SMM (1 << 0)
|
||||
/* x86, set if bus lock detected in VM */
|
||||
#define KVM_RUN_BUS_LOCK (1 << 1)
|
||||
#define KVM_RUN_X86_BUS_LOCK (1 << 1)
|
||||
/* x86, set if the VCPU is executing a nested (L2) guest */
|
||||
#define KVM_RUN_X86_GUEST_MODE (1 << 2)
|
||||
|
||||
/* arm64, set for KVM_EXIT_DEBUG */
|
||||
#define KVM_DEBUG_ARCH_HSR_HIGH_VALID (1 << 0)
|
||||
|
||||
@@ -7767,29 +7837,31 @@ Valid bits in args[0] are::
|
||||
#define KVM_BUS_LOCK_DETECTION_OFF (1 << 0)
|
||||
#define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1)
|
||||
|
||||
Enabling this capability on a VM provides userspace with a way to select
|
||||
a policy to handle the bus locks detected in guest. Userspace can obtain
|
||||
the supported modes from the result of KVM_CHECK_EXTENSION and define it
|
||||
through the KVM_ENABLE_CAP.
|
||||
Enabling this capability on a VM provides userspace with a way to select a
|
||||
policy to handle the bus locks detected in guest. Userspace can obtain the
|
||||
supported modes from the result of KVM_CHECK_EXTENSION and define it through
|
||||
the KVM_ENABLE_CAP. The supported modes are mutually-exclusive.
|
||||
|
||||
KVM_BUS_LOCK_DETECTION_OFF and KVM_BUS_LOCK_DETECTION_EXIT are supported
|
||||
currently and mutually exclusive with each other. More bits can be added in
|
||||
the future.
|
||||
This capability allows userspace to force VM exits on bus locks detected in the
|
||||
guest, irrespective whether or not the host has enabled split-lock detection
|
||||
(which triggers an #AC exception that KVM intercepts). This capability is
|
||||
intended to mitigate attacks where a malicious/buggy guest can exploit bus
|
||||
locks to degrade the performance of the whole system.
|
||||
|
||||
With KVM_BUS_LOCK_DETECTION_OFF set, bus locks in guest will not cause vm exits
|
||||
so that no additional actions are needed. This is the default mode.
|
||||
If KVM_BUS_LOCK_DETECTION_OFF is set, KVM doesn't force guest bus locks to VM
|
||||
exit, although the host kernel's split-lock #AC detection still applies, if
|
||||
enabled.
|
||||
|
||||
With KVM_BUS_LOCK_DETECTION_EXIT set, vm exits happen when bus lock detected
|
||||
in VM. KVM just exits to userspace when handling them. Userspace can enforce
|
||||
its own throttling or other policy based mitigations.
|
||||
If KVM_BUS_LOCK_DETECTION_EXIT is set, KVM enables a CPU feature that ensures
|
||||
bus locks in the guest trigger a VM exit, and KVM exits to userspace for all
|
||||
such VM exits, e.g. to allow userspace to throttle the offending guest and/or
|
||||
apply some other policy-based mitigation. When exiting to userspace, KVM sets
|
||||
KVM_RUN_X86_BUS_LOCK in vcpu-run->flags, and conditionally sets the exit_reason
|
||||
to KVM_EXIT_X86_BUS_LOCK.
|
||||
|
||||
This capability is aimed to address the thread that VM can exploit bus locks to
|
||||
degree the performance of the whole system. Once the userspace enable this
|
||||
capability and select the KVM_BUS_LOCK_DETECTION_EXIT mode, KVM will set the
|
||||
KVM_RUN_BUS_LOCK flag in vcpu-run->flags field and exit to userspace. Concerning
|
||||
the bus lock vm exit can be preempted by a higher priority VM exit, the exit
|
||||
notifications to userspace can be KVM_EXIT_BUS_LOCK or other reasons.
|
||||
KVM_RUN_BUS_LOCK flag is used to distinguish between them.
|
||||
Note! Detected bus locks may be coincident with other exits to userspace, i.e.
|
||||
KVM_RUN_X86_BUS_LOCK should be checked regardless of the primary exit reason if
|
||||
userspace wants to take action on all detected bus locks.
|
||||
|
||||
7.23 KVM_CAP_PPC_DAWR1
|
||||
----------------------
|
||||
@@ -7905,10 +7977,10 @@ perform a bulk copy of tags to/from the guest.
|
||||
7.29 KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM
|
||||
-------------------------------------
|
||||
|
||||
Architectures: x86 SEV enabled
|
||||
Type: vm
|
||||
Parameters: args[0] is the fd of the source vm
|
||||
Returns: 0 on success
|
||||
:Architectures: x86 SEV enabled
|
||||
:Type: vm
|
||||
:Parameters: args[0] is the fd of the source vm
|
||||
:Returns: 0 on success
|
||||
|
||||
This capability enables userspace to migrate the encryption context from the VM
|
||||
indicated by the fd to the VM this is called on.
|
||||
@@ -7956,7 +8028,11 @@ The valid bits in cap.args[0] are:
|
||||
When this quirk is disabled, the reset value
|
||||
is 0x10000 (APIC_LVT_MASKED).
|
||||
|
||||
KVM_X86_QUIRK_CD_NW_CLEARED By default, KVM clears CR0.CD and CR0.NW.
|
||||
KVM_X86_QUIRK_CD_NW_CLEARED By default, KVM clears CR0.CD and CR0.NW on
|
||||
AMD CPUs to workaround buggy guest firmware
|
||||
that runs in perpetuity with CR0.CD, i.e.
|
||||
with caches in "no fill" mode.
|
||||
|
||||
When this quirk is disabled, KVM does not
|
||||
change the value of CR0.CD and CR0.NW.
|
||||
|
||||
@@ -8073,6 +8149,37 @@ error/annotated fault.
|
||||
|
||||
See KVM_EXIT_MEMORY_FAULT for more information.
|
||||
|
||||
7.35 KVM_CAP_X86_APIC_BUS_CYCLES_NS
|
||||
-----------------------------------
|
||||
|
||||
:Architectures: x86
|
||||
:Target: VM
|
||||
:Parameters: args[0] is the desired APIC bus clock rate, in nanoseconds
|
||||
:Returns: 0 on success, -EINVAL if args[0] contains an invalid value for the
|
||||
frequency or if any vCPUs have been created, -ENXIO if a virtual
|
||||
local APIC has not been created using KVM_CREATE_IRQCHIP.
|
||||
|
||||
This capability sets the VM's APIC bus clock frequency, used by KVM's in-kernel
|
||||
virtual APIC when emulating APIC timers. KVM's default value can be retrieved
|
||||
by KVM_CHECK_EXTENSION.
|
||||
|
||||
Note: Userspace is responsible for correctly configuring CPUID 0x15, a.k.a. the
|
||||
core crystal clock frequency, if a non-zero CPUID 0x15 is exposed to the guest.
|
||||
|
||||
7.36 KVM_CAP_X86_GUEST_MODE
|
||||
------------------------------
|
||||
|
||||
:Architectures: x86
|
||||
:Returns: Informational only, -EINVAL on direct KVM_ENABLE_CAP.
|
||||
|
||||
The presence of this capability indicates that KVM_RUN will update the
|
||||
KVM_RUN_X86_GUEST_MODE bit in kvm_run.flags to indicate whether the
|
||||
vCPU was executing nested guest code when it exited.
|
||||
|
||||
KVM exits with the register state of either the L1 or L2 guest
|
||||
depending on which executed at the time of an exit. Userspace must
|
||||
take care to differentiate between these cases.
|
||||
|
||||
8. Other capabilities.
|
||||
======================
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Groups:
|
||||
KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit)
|
||||
Base address in the guest physical address space of the GIC virtual cpu
|
||||
interface register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V2.
|
||||
This address needs to be 4K aligned and the region covers 4 KByte.
|
||||
This address needs to be 4K aligned and the region covers 8 KByte.
|
||||
|
||||
Errors:
|
||||
|
||||
|
||||
@@ -79,11 +79,11 @@ adjustment of the polling interval.
|
||||
Module Parameters
|
||||
=================
|
||||
|
||||
The kvm module has 3 tuneable module parameters to adjust the global max
|
||||
polling interval as well as the rate at which the polling interval is grown and
|
||||
shrunk. These variables are defined in include/linux/kvm_host.h and as module
|
||||
parameters in virt/kvm/kvm_main.c, or arch/powerpc/kvm/book3s_hv.c in the
|
||||
powerpc kvm-hv case.
|
||||
The kvm module has 4 tunable module parameters to adjust the global max polling
|
||||
interval, the initial value (to grow from 0), and the rate at which the polling
|
||||
interval is grown and shrunk. These variables are defined in
|
||||
include/linux/kvm_host.h and as module parameters in virt/kvm/kvm_main.c, or
|
||||
arch/powerpc/kvm/book3s_hv.c in the powerpc kvm-hv case.
|
||||
|
||||
+-----------------------+---------------------------+-------------------------+
|
||||
|Module Parameter | Description | Default Value |
|
||||
@@ -105,7 +105,7 @@ powerpc kvm-hv case.
|
||||
| | grow_halt_poll_ns() | |
|
||||
| | function. | |
|
||||
+-----------------------+---------------------------+-------------------------+
|
||||
|halt_poll_ns_shrink | The value by which the | 0 |
|
||||
|halt_poll_ns_shrink | The value by which the | 2 |
|
||||
| | halt polling interval is | |
|
||||
| | divided in the | |
|
||||
| | shrink_halt_poll_ns() | |
|
||||
|
||||
@@ -466,6 +466,112 @@ issued by the hypervisor to make the guest ready for execution.
|
||||
|
||||
Returns: 0 on success, -negative on error
|
||||
|
||||
18. KVM_SEV_SNP_LAUNCH_START
|
||||
----------------------------
|
||||
|
||||
The KVM_SNP_LAUNCH_START command is used for creating the memory encryption
|
||||
context for the SEV-SNP guest. It must be called prior to issuing
|
||||
KVM_SEV_SNP_LAUNCH_UPDATE or KVM_SEV_SNP_LAUNCH_FINISH;
|
||||
|
||||
Parameters (in): struct kvm_sev_snp_launch_start
|
||||
|
||||
Returns: 0 on success, -negative on error
|
||||
|
||||
::
|
||||
|
||||
struct kvm_sev_snp_launch_start {
|
||||
__u64 policy; /* Guest policy to use. */
|
||||
__u8 gosvw[16]; /* Guest OS visible workarounds. */
|
||||
__u16 flags; /* Must be zero. */
|
||||
__u8 pad0[6];
|
||||
__u64 pad1[4];
|
||||
};
|
||||
|
||||
See SNP_LAUNCH_START in the SEV-SNP specification [snp-fw-abi]_ for further
|
||||
details on the input parameters in ``struct kvm_sev_snp_launch_start``.
|
||||
|
||||
19. KVM_SEV_SNP_LAUNCH_UPDATE
|
||||
-----------------------------
|
||||
|
||||
The KVM_SEV_SNP_LAUNCH_UPDATE command is used for loading userspace-provided
|
||||
data into a guest GPA range, measuring the contents into the SNP guest context
|
||||
created by KVM_SEV_SNP_LAUNCH_START, and then encrypting/validating that GPA
|
||||
range so that it will be immediately readable using the encryption key
|
||||
associated with the guest context once it is booted, after which point it can
|
||||
attest the measurement associated with its context before unlocking any
|
||||
secrets.
|
||||
|
||||
It is required that the GPA ranges initialized by this command have had the
|
||||
KVM_MEMORY_ATTRIBUTE_PRIVATE attribute set in advance. See the documentation
|
||||
for KVM_SET_MEMORY_ATTRIBUTES for more details on this aspect.
|
||||
|
||||
Upon success, this command is not guaranteed to have processed the entire
|
||||
range requested. Instead, the ``gfn_start``, ``uaddr``, and ``len`` fields of
|
||||
``struct kvm_sev_snp_launch_update`` will be updated to correspond to the
|
||||
remaining range that has yet to be processed. The caller should continue
|
||||
calling this command until those fields indicate the entire range has been
|
||||
processed, e.g. ``len`` is 0, ``gfn_start`` is equal to the last GFN in the
|
||||
range plus 1, and ``uaddr`` is the last byte of the userspace-provided source
|
||||
buffer address plus 1. In the case where ``type`` is KVM_SEV_SNP_PAGE_TYPE_ZERO,
|
||||
``uaddr`` will be ignored completely.
|
||||
|
||||
Parameters (in): struct kvm_sev_snp_launch_update
|
||||
|
||||
Returns: 0 on success, < 0 on error, -EAGAIN if caller should retry
|
||||
|
||||
::
|
||||
|
||||
struct kvm_sev_snp_launch_update {
|
||||
__u64 gfn_start; /* Guest page number to load/encrypt data into. */
|
||||
__u64 uaddr; /* Userspace address of data to be loaded/encrypted. */
|
||||
__u64 len; /* 4k-aligned length in bytes to copy into guest memory.*/
|
||||
__u8 type; /* The type of the guest pages being initialized. */
|
||||
__u8 pad0;
|
||||
__u16 flags; /* Must be zero. */
|
||||
__u32 pad1;
|
||||
__u64 pad2[4];
|
||||
|
||||
};
|
||||
|
||||
where the allowed values for page_type are #define'd as::
|
||||
|
||||
KVM_SEV_SNP_PAGE_TYPE_NORMAL
|
||||
KVM_SEV_SNP_PAGE_TYPE_ZERO
|
||||
KVM_SEV_SNP_PAGE_TYPE_UNMEASURED
|
||||
KVM_SEV_SNP_PAGE_TYPE_SECRETS
|
||||
KVM_SEV_SNP_PAGE_TYPE_CPUID
|
||||
|
||||
See the SEV-SNP spec [snp-fw-abi]_ for further details on how each page type is
|
||||
used/measured.
|
||||
|
||||
20. KVM_SEV_SNP_LAUNCH_FINISH
|
||||
-----------------------------
|
||||
|
||||
After completion of the SNP guest launch flow, the KVM_SEV_SNP_LAUNCH_FINISH
|
||||
command can be issued to make the guest ready for execution.
|
||||
|
||||
Parameters (in): struct kvm_sev_snp_launch_finish
|
||||
|
||||
Returns: 0 on success, -negative on error
|
||||
|
||||
::
|
||||
|
||||
struct kvm_sev_snp_launch_finish {
|
||||
__u64 id_block_uaddr;
|
||||
__u64 id_auth_uaddr;
|
||||
__u8 id_block_en;
|
||||
__u8 auth_key_en;
|
||||
__u8 vcek_disabled;
|
||||
__u8 host_data[32];
|
||||
__u8 pad0[3];
|
||||
__u16 flags; /* Must be zero */
|
||||
__u64 pad1[4];
|
||||
};
|
||||
|
||||
|
||||
See SNP_LAUNCH_FINISH in the SEV-SNP specification [snp-fw-abi]_ for further
|
||||
details on the input parameters in ``struct kvm_sev_snp_launch_finish``.
|
||||
|
||||
Device attribute API
|
||||
====================
|
||||
|
||||
@@ -497,9 +603,11 @@ References
|
||||
==========
|
||||
|
||||
|
||||
See [white-paper]_, [api-spec]_, [amd-apm]_ and [kvm-forum]_ for more info.
|
||||
See [white-paper]_, [api-spec]_, [amd-apm]_, [kvm-forum]_, and [snp-fw-abi]_
|
||||
for more info.
|
||||
|
||||
.. [white-paper] https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
|
||||
.. [api-spec] https://support.amd.com/TechDocs/55766_SEV-KM_API_Specification.pdf
|
||||
.. [amd-apm] https://support.amd.com/TechDocs/24593.pdf (section 15.34)
|
||||
.. [kvm-forum] https://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
|
||||
.. [snp-fw-abi] https://www.amd.com/system/files/TechDocs/56860.pdf
|
||||
|
||||
@@ -48,3 +48,21 @@ have the same physical APIC ID, KVM will deliver events targeting that APIC ID
|
||||
only to the vCPU with the lowest vCPU ID. If KVM_X2APIC_API_USE_32BIT_IDS is
|
||||
not enabled, KVM follows x86 architecture when processing interrupts (all vCPUs
|
||||
matching the target APIC ID receive the interrupt).
|
||||
|
||||
MTRRs
|
||||
-----
|
||||
KVM does not virtualize guest MTRR memory types. KVM emulates accesses to MTRR
|
||||
MSRs, i.e. {RD,WR}MSR in the guest will behave as expected, but KVM does not
|
||||
honor guest MTRRs when determining the effective memory type, and instead
|
||||
treats all of guest memory as having Writeback (WB) MTRRs.
|
||||
|
||||
CR0.CD
|
||||
------
|
||||
KVM does not virtualize CR0.CD on Intel CPUs. Similar to MTRR MSRs, KVM
|
||||
emulates CR0.CD accesses so that loads and stores from/to CR0 behave as
|
||||
expected, but setting CR0.CD=1 has no impact on the cachaeability of guest
|
||||
memory.
|
||||
|
||||
Note, this erratum does not affect AMD CPUs, which fully virtualize CR0.CD in
|
||||
hardware, i.e. put the CPU caches into "no fill" mode when CR0.CD=1, even when
|
||||
running in the guest.
|
||||
@@ -12248,6 +12248,8 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: kvmarm@lists.linux.dev
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
|
||||
F: Documentation/virt/kvm/arm/
|
||||
F: Documentation/virt/kvm/devices/arm*
|
||||
F: arch/arm64/include/asm/kvm*
|
||||
F: arch/arm64/include/uapi/asm/kvm*
|
||||
F: arch/arm64/kvm/
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
#define ESR_ELx_Xs_MASK (GENMASK_ULL(4, 0))
|
||||
|
||||
/* ISS field definitions for exceptions taken in to Hyp */
|
||||
#define ESR_ELx_FSC_ADDRSZ (0x00)
|
||||
#define ESR_ELx_CV (UL(1) << 24)
|
||||
#define ESR_ELx_COND_SHIFT (20)
|
||||
#define ESR_ELx_COND_MASK (UL(0xF) << ESR_ELx_COND_SHIFT)
|
||||
@@ -387,6 +388,11 @@
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/types.h>
|
||||
|
||||
static inline unsigned long esr_brk_comment(unsigned long esr)
|
||||
{
|
||||
return esr & ESR_ELx_BRK64_ISS_COMMENT_MASK;
|
||||
}
|
||||
|
||||
static inline bool esr_is_data_abort(unsigned long esr)
|
||||
{
|
||||
const unsigned long ec = ESR_ELx_EC(esr);
|
||||
@@ -394,6 +400,12 @@ static inline bool esr_is_data_abort(unsigned long esr)
|
||||
return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR;
|
||||
}
|
||||
|
||||
static inline bool esr_is_cfi_brk(unsigned long esr)
|
||||
{
|
||||
return ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 &&
|
||||
(esr_brk_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE;
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_translation_fault(unsigned long esr)
|
||||
{
|
||||
esr = esr & ESR_ELx_FSC;
|
||||
|
||||
@@ -102,7 +102,6 @@
|
||||
#define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
|
||||
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
|
||||
|
||||
#define HCRX_GUEST_FLAGS (HCRX_EL2_SMPME | HCRX_EL2_TCR2En)
|
||||
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En | HCRX_EL2_EnFPM)
|
||||
|
||||
/* TCR_EL2 Registers bits */
|
||||
|
||||
@@ -232,6 +232,8 @@ extern void __kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,
|
||||
phys_addr_t start, unsigned long pages);
|
||||
extern void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu);
|
||||
|
||||
extern int __kvm_tlbi_s1e2(struct kvm_s2_mmu *mmu, u64 va, u64 sys_encoding);
|
||||
|
||||
extern void __kvm_timer_set_cntvoff(u64 cntvoff);
|
||||
|
||||
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#ifndef __ARM64_KVM_EMULATE_H__
|
||||
#define __ARM64_KVM_EMULATE_H__
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kvm_host.h>
|
||||
|
||||
#include <asm/debug-monitors.h>
|
||||
@@ -55,6 +56,14 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
|
||||
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
|
||||
int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline void kvm_inject_nested_sve_trap(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 esr = FIELD_PREP(ESR_ELx_EC_MASK, ESR_ELx_EC_SVE) |
|
||||
ESR_ELx_IL;
|
||||
|
||||
kvm_inject_nested_sync(vcpu, esr);
|
||||
}
|
||||
|
||||
#if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__)
|
||||
static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -69,39 +78,17 @@ static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
|
||||
|
||||
static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
|
||||
if (has_vhe() || has_hvhe())
|
||||
vcpu->arch.hcr_el2 |= HCR_E2H;
|
||||
if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN)) {
|
||||
/* route synchronous external abort exceptions to EL2 */
|
||||
vcpu->arch.hcr_el2 |= HCR_TEA;
|
||||
/* trap error record accesses */
|
||||
vcpu->arch.hcr_el2 |= HCR_TERR;
|
||||
}
|
||||
if (!vcpu_has_run_once(vcpu))
|
||||
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
|
||||
|
||||
if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB)) {
|
||||
vcpu->arch.hcr_el2 |= HCR_FWB;
|
||||
} else {
|
||||
/*
|
||||
* For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C
|
||||
* get set in SCTLR_EL1 such that we can detect when the guest
|
||||
* MMU gets turned on and do the necessary cache maintenance
|
||||
* then.
|
||||
*/
|
||||
/*
|
||||
* For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C
|
||||
* get set in SCTLR_EL1 such that we can detect when the guest
|
||||
* MMU gets turned on and do the necessary cache maintenance
|
||||
* then.
|
||||
*/
|
||||
if (!cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
|
||||
vcpu->arch.hcr_el2 |= HCR_TVM;
|
||||
}
|
||||
|
||||
if (cpus_have_final_cap(ARM64_HAS_EVT) &&
|
||||
!cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE))
|
||||
vcpu->arch.hcr_el2 |= HCR_TID4;
|
||||
else
|
||||
vcpu->arch.hcr_el2 |= HCR_TID2;
|
||||
|
||||
if (vcpu_el1_is_32bit(vcpu))
|
||||
vcpu->arch.hcr_el2 &= ~HCR_RW;
|
||||
|
||||
if (kvm_has_mte(vcpu->kvm))
|
||||
vcpu->arch.hcr_el2 |= HCR_ATA;
|
||||
}
|
||||
|
||||
static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
|
||||
@@ -660,4 +647,50 @@ static __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu)
|
||||
|
||||
kvm_write_cptr_el2(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
|
||||
* format if E2H isn't set.
|
||||
*/
|
||||
static inline u64 vcpu_sanitised_cptr_el2(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 cptr = __vcpu_sys_reg(vcpu, CPTR_EL2);
|
||||
|
||||
if (!vcpu_el2_e2h_is_set(vcpu))
|
||||
cptr = translate_cptr_el2_to_cpacr_el1(cptr);
|
||||
|
||||
return cptr;
|
||||
}
|
||||
|
||||
static inline bool ____cptr_xen_trap_enabled(const struct kvm_vcpu *vcpu,
|
||||
unsigned int xen)
|
||||
{
|
||||
switch (xen) {
|
||||
case 0b00:
|
||||
case 0b10:
|
||||
return true;
|
||||
case 0b01:
|
||||
return vcpu_el2_tge_is_set(vcpu) && !vcpu_is_el2(vcpu);
|
||||
case 0b11:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#define __guest_hyp_cptr_xen_trap_enabled(vcpu, xen) \
|
||||
(!vcpu_has_nv(vcpu) ? false : \
|
||||
____cptr_xen_trap_enabled(vcpu, \
|
||||
SYS_FIELD_GET(CPACR_ELx, xen, \
|
||||
vcpu_sanitised_cptr_el2(vcpu))))
|
||||
|
||||
static inline bool guest_hyp_fpsimd_traps_enabled(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return __guest_hyp_cptr_xen_trap_enabled(vcpu, FPEN);
|
||||
}
|
||||
|
||||
static inline bool guest_hyp_sve_traps_enabled(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return __guest_hyp_cptr_xen_trap_enabled(vcpu, ZEN);
|
||||
}
|
||||
|
||||
#endif /* __ARM64_KVM_EMULATE_H__ */
|
||||
|
||||
@@ -189,6 +189,33 @@ struct kvm_s2_mmu {
|
||||
uint64_t split_page_chunk_size;
|
||||
|
||||
struct kvm_arch *arch;
|
||||
|
||||
/*
|
||||
* For a shadow stage-2 MMU, the virtual vttbr used by the
|
||||
* host to parse the guest S2.
|
||||
* This either contains:
|
||||
* - the virtual VTTBR programmed by the guest hypervisor with
|
||||
* CnP cleared
|
||||
* - The value 1 (VMID=0, BADDR=0, CnP=1) if invalid
|
||||
*
|
||||
* We also cache the full VTCR which gets used for TLB invalidation,
|
||||
* taking the ARM ARM's "Any of the bits in VTCR_EL2 are permitted
|
||||
* to be cached in a TLB" to the letter.
|
||||
*/
|
||||
u64 tlb_vttbr;
|
||||
u64 tlb_vtcr;
|
||||
|
||||
/*
|
||||
* true when this represents a nested context where virtual
|
||||
* HCR_EL2.VM == 1
|
||||
*/
|
||||
bool nested_stage2_enabled;
|
||||
|
||||
/*
|
||||
* 0: Nobody is currently using this, check vttbr for validity
|
||||
* >0: Somebody is actively using this.
|
||||
*/
|
||||
atomic_t refcnt;
|
||||
};
|
||||
|
||||
struct kvm_arch_memory_slot {
|
||||
@@ -256,6 +283,14 @@ struct kvm_arch {
|
||||
*/
|
||||
u64 fgu[__NR_FGT_GROUP_IDS__];
|
||||
|
||||
/*
|
||||
* Stage 2 paging state for VMs with nested S2 using a virtual
|
||||
* VMID.
|
||||
*/
|
||||
struct kvm_s2_mmu *nested_mmus;
|
||||
size_t nested_mmus_size;
|
||||
int nested_mmus_next;
|
||||
|
||||
/* Interrupt controller */
|
||||
struct vgic_dist vgic;
|
||||
|
||||
@@ -327,11 +362,11 @@ struct kvm_arch {
|
||||
* Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
|
||||
*/
|
||||
#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
|
||||
#define IDX_IDREG(idx) sys_reg(3, 0, 0, ((idx) >> 3) + 1, (idx) & Op2_mask)
|
||||
#define IDREG(kvm, id) ((kvm)->arch.id_regs[IDREG_IDX(id)])
|
||||
#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
|
||||
u64 id_regs[KVM_ARM_ID_REG_NUM];
|
||||
|
||||
u64 ctr_el0;
|
||||
|
||||
/* Masks for VNCR-baked sysregs */
|
||||
struct kvm_sysreg_masks *sysreg_masks;
|
||||
|
||||
@@ -423,6 +458,7 @@ enum vcpu_sysreg {
|
||||
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
|
||||
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
|
||||
HACR_EL2, /* Hypervisor Auxiliary Control Register */
|
||||
ZCR_EL2, /* SVE Control Register (EL2) */
|
||||
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
|
||||
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
|
||||
TCR_EL2, /* Translation Control Register (EL2) */
|
||||
@@ -867,6 +903,9 @@ struct kvm_vcpu_arch {
|
||||
|
||||
#define vcpu_sve_max_vq(vcpu) sve_vq_from_vl((vcpu)->arch.sve_max_vl)
|
||||
|
||||
#define vcpu_sve_zcr_elx(vcpu) \
|
||||
(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
|
||||
|
||||
#define vcpu_sve_state_size(vcpu) ({ \
|
||||
size_t __size_ret; \
|
||||
unsigned int __vcpu_vq; \
|
||||
@@ -991,6 +1030,7 @@ static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
|
||||
case DACR32_EL2: *val = read_sysreg_s(SYS_DACR32_EL2); break;
|
||||
case IFSR32_EL2: *val = read_sysreg_s(SYS_IFSR32_EL2); break;
|
||||
case DBGVCR32_EL2: *val = read_sysreg_s(SYS_DBGVCR32_EL2); break;
|
||||
case ZCR_EL1: *val = read_sysreg_s(SYS_ZCR_EL12); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
@@ -1036,6 +1076,7 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
|
||||
case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break;
|
||||
case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break;
|
||||
case DBGVCR32_EL2: write_sysreg_s(val, SYS_DBGVCR32_EL2); break;
|
||||
case ZCR_EL1: write_sysreg_s(val, SYS_ZCR_EL12); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
@@ -1145,7 +1186,7 @@ int __init populate_nv_trap_config(void);
|
||||
bool lock_all_vcpus(struct kvm *kvm);
|
||||
void unlock_all_vcpus(struct kvm *kvm);
|
||||
|
||||
void kvm_init_sysreg(struct kvm_vcpu *);
|
||||
void kvm_calculate_traps(struct kvm_vcpu *vcpu);
|
||||
|
||||
/* MMIO helpers */
|
||||
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
|
||||
@@ -1248,7 +1289,6 @@ static inline bool kvm_system_needs_idmapped_vectors(void)
|
||||
}
|
||||
|
||||
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
|
||||
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
|
||||
|
||||
void kvm_arm_init_debug(void);
|
||||
void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu);
|
||||
@@ -1306,6 +1346,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu);
|
||||
void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu);
|
||||
|
||||
int __init kvm_set_ipa_limit(void);
|
||||
u32 kvm_get_pa_bits(struct kvm *kvm);
|
||||
|
||||
#define __KVM_HAVE_ARCH_VM_ALLOC
|
||||
struct kvm *kvm_arch_alloc_vm(void);
|
||||
@@ -1355,6 +1396,24 @@ static inline void kvm_hyp_reserve(void) { }
|
||||
void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu);
|
||||
bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7):
|
||||
return &ka->id_regs[IDREG_IDX(reg)];
|
||||
case SYS_CTR_EL0:
|
||||
return &ka->ctr_el0;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define kvm_read_vm_id_reg(kvm, reg) \
|
||||
({ u64 __val = *__vm_id_reg(&(kvm)->arch, reg); __val; })
|
||||
|
||||
void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
|
||||
|
||||
#define __expand_field_sign_unsigned(id, fld, val) \
|
||||
((u64)SYS_FIELD_VALUE(id, fld, val))
|
||||
|
||||
@@ -1371,7 +1430,7 @@ bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);
|
||||
|
||||
#define get_idreg_field_unsigned(kvm, id, fld) \
|
||||
({ \
|
||||
u64 __val = IDREG((kvm), SYS_##id); \
|
||||
u64 __val = kvm_read_vm_id_reg((kvm), SYS_##id); \
|
||||
FIELD_GET(id##_##fld##_MASK, __val); \
|
||||
})
|
||||
|
||||
|
||||
@@ -124,8 +124,8 @@ void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr,
|
||||
#endif
|
||||
|
||||
#ifdef __KVM_NVHE_HYPERVISOR__
|
||||
void __pkvm_init_switch_pgd(phys_addr_t phys, unsigned long size,
|
||||
phys_addr_t pgd, void *sp, void *cont_fn);
|
||||
void __pkvm_init_switch_pgd(phys_addr_t pgd, unsigned long sp,
|
||||
void (*fn)(void));
|
||||
int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long nr_cpus,
|
||||
unsigned long *per_cpu_base, u32 hyp_va_bits);
|
||||
void __noreturn __host_enter(struct kvm_cpu_context *host_ctxt);
|
||||
|
||||
@@ -98,6 +98,7 @@ alternative_cb_end
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_host.h>
|
||||
#include <asm/kvm_nested.h>
|
||||
|
||||
void kvm_update_va_mask(struct alt_instr *alt,
|
||||
__le32 *origptr, __le32 *updptr, int nr_inst);
|
||||
@@ -165,6 +166,10 @@ int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
|
||||
int create_hyp_stack(phys_addr_t phys_addr, unsigned long *haddr);
|
||||
void __init free_hyp_pgds(void);
|
||||
|
||||
void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size);
|
||||
void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end);
|
||||
void kvm_stage2_wp_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end);
|
||||
|
||||
void stage2_unmap_vm(struct kvm *kvm);
|
||||
int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type);
|
||||
void kvm_uninit_stage2_mmu(struct kvm *kvm);
|
||||
@@ -326,5 +331,26 @@ static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
|
||||
{
|
||||
return container_of(mmu->arch, struct kvm, arch);
|
||||
}
|
||||
|
||||
static inline u64 get_vmid(u64 vttbr)
|
||||
{
|
||||
return (vttbr & VTTBR_VMID_MASK(kvm_get_vmid_bits())) >>
|
||||
VTTBR_VMID_SHIFT;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2_mmu_valid(struct kvm_s2_mmu *mmu)
|
||||
{
|
||||
return !(mmu->tlb_vttbr & VTTBR_CNP_BIT);
|
||||
}
|
||||
|
||||
static inline bool kvm_is_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
|
||||
{
|
||||
/*
|
||||
* Be careful, mmu may not be fully initialised so do look at
|
||||
* *any* of its fields.
|
||||
*/
|
||||
return &kvm->arch.mmu != mmu;
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARM64_KVM_MMU_H__ */
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_pgtable.h>
|
||||
|
||||
static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -32,7 +33,7 @@ static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr)
|
||||
|
||||
static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
|
||||
{
|
||||
u64 cpacr_el1 = 0;
|
||||
u64 cpacr_el1 = CPACR_ELx_RES1;
|
||||
|
||||
if (cptr_el2 & CPTR_EL2_TTA)
|
||||
cpacr_el1 |= CPACR_ELx_TTA;
|
||||
@@ -41,6 +42,8 @@ static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
|
||||
if (!(cptr_el2 & CPTR_EL2_TZ))
|
||||
cpacr_el1 |= CPACR_ELx_ZEN;
|
||||
|
||||
cpacr_el1 |= cptr_el2 & (CPTR_EL2_TCPAC | CPTR_EL2_TAM);
|
||||
|
||||
return cpacr_el1;
|
||||
}
|
||||
|
||||
@@ -61,6 +64,125 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)
|
||||
}
|
||||
|
||||
extern bool forward_smc_trap(struct kvm_vcpu *vcpu);
|
||||
extern void kvm_init_nested(struct kvm *kvm);
|
||||
extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu);
|
||||
extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu);
|
||||
extern struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu);
|
||||
|
||||
union tlbi_info;
|
||||
|
||||
extern void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
|
||||
const union tlbi_info *info,
|
||||
void (*)(struct kvm_s2_mmu *,
|
||||
const union tlbi_info *));
|
||||
extern void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu);
|
||||
extern void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct kvm_s2_trans {
|
||||
phys_addr_t output;
|
||||
unsigned long block_size;
|
||||
bool writable;
|
||||
bool readable;
|
||||
int level;
|
||||
u32 esr;
|
||||
u64 upper_attr;
|
||||
};
|
||||
|
||||
static inline phys_addr_t kvm_s2_trans_output(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return trans->output;
|
||||
}
|
||||
|
||||
static inline unsigned long kvm_s2_trans_size(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return trans->block_size;
|
||||
}
|
||||
|
||||
static inline u32 kvm_s2_trans_esr(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return trans->esr;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2_trans_readable(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return trans->readable;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2_trans_writable(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return trans->writable;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2_trans_executable(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return !(trans->upper_attr & BIT(54));
|
||||
}
|
||||
|
||||
extern int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
|
||||
struct kvm_s2_trans *result);
|
||||
extern int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu,
|
||||
struct kvm_s2_trans *trans);
|
||||
extern int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2);
|
||||
extern void kvm_nested_s2_wp(struct kvm *kvm);
|
||||
extern void kvm_nested_s2_unmap(struct kvm *kvm);
|
||||
extern void kvm_nested_s2_flush(struct kvm *kvm);
|
||||
|
||||
unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val);
|
||||
|
||||
static inline bool kvm_supported_tlbi_s1e1_op(struct kvm_vcpu *vpcu, u32 instr)
|
||||
{
|
||||
struct kvm *kvm = vpcu->kvm;
|
||||
u8 CRm = sys_reg_CRm(instr);
|
||||
|
||||
if (!(sys_reg_Op0(instr) == TLBI_Op0 &&
|
||||
sys_reg_Op1(instr) == TLBI_Op1_EL1))
|
||||
return false;
|
||||
|
||||
if (!(sys_reg_CRn(instr) == TLBI_CRn_XS ||
|
||||
(sys_reg_CRn(instr) == TLBI_CRn_nXS &&
|
||||
kvm_has_feat(kvm, ID_AA64ISAR1_EL1, XS, IMP))))
|
||||
return false;
|
||||
|
||||
if (CRm == TLBI_CRm_nROS &&
|
||||
!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS))
|
||||
return false;
|
||||
|
||||
if ((CRm == TLBI_CRm_RIS || CRm == TLBI_CRm_ROS ||
|
||||
CRm == TLBI_CRm_RNS) &&
|
||||
!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool kvm_supported_tlbi_s1e2_op(struct kvm_vcpu *vpcu, u32 instr)
|
||||
{
|
||||
struct kvm *kvm = vpcu->kvm;
|
||||
u8 CRm = sys_reg_CRm(instr);
|
||||
|
||||
if (!(sys_reg_Op0(instr) == TLBI_Op0 &&
|
||||
sys_reg_Op1(instr) == TLBI_Op1_EL2))
|
||||
return false;
|
||||
|
||||
if (!(sys_reg_CRn(instr) == TLBI_CRn_XS ||
|
||||
(sys_reg_CRn(instr) == TLBI_CRn_nXS &&
|
||||
kvm_has_feat(kvm, ID_AA64ISAR1_EL1, XS, IMP))))
|
||||
return false;
|
||||
|
||||
if (CRm == TLBI_CRm_IPAIS || CRm == TLBI_CRm_IPAONS)
|
||||
return false;
|
||||
|
||||
if (CRm == TLBI_CRm_nROS &&
|
||||
!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS))
|
||||
return false;
|
||||
|
||||
if ((CRm == TLBI_CRm_RIS || CRm == TLBI_CRm_ROS ||
|
||||
CRm == TLBI_CRm_RNS) &&
|
||||
!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int kvm_init_nv_sysregs(struct kvm *kvm);
|
||||
|
||||
@@ -76,4 +198,11 @@ static inline bool kvm_auth_eretax(struct kvm_vcpu *vcpu, u64 *elr)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define KVM_NV_GUEST_MAP_SZ (KVM_PGTABLE_PROT_SW1 | KVM_PGTABLE_PROT_SW0)
|
||||
|
||||
static inline u64 kvm_encode_nested_level(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return FIELD_PREP(KVM_NV_GUEST_MAP_SZ, trans->level);
|
||||
}
|
||||
|
||||
#endif /* __ARM64_KVM_NESTED_H */
|
||||
|
||||
@@ -654,6 +654,23 @@
|
||||
#define OP_AT_S12E0W sys_insn(AT_Op0, 4, AT_CRn, 8, 7)
|
||||
|
||||
/* TLBI instructions */
|
||||
#define TLBI_Op0 1
|
||||
|
||||
#define TLBI_Op1_EL1 0 /* Accessible from EL1 or higher */
|
||||
#define TLBI_Op1_EL2 4 /* Accessible from EL2 or higher */
|
||||
|
||||
#define TLBI_CRn_XS 8 /* Extra Slow (the common one) */
|
||||
#define TLBI_CRn_nXS 9 /* not Extra Slow (which nobody uses)*/
|
||||
|
||||
#define TLBI_CRm_IPAIS 0 /* S2 Inner-Shareable */
|
||||
#define TLBI_CRm_nROS 1 /* non-Range, Outer-Sharable */
|
||||
#define TLBI_CRm_RIS 2 /* Range, Inner-Sharable */
|
||||
#define TLBI_CRm_nRIS 3 /* non-Range, Inner-Sharable */
|
||||
#define TLBI_CRm_IPAONS 4 /* S2 Outer and Non-Shareable */
|
||||
#define TLBI_CRm_ROS 5 /* Range, Outer-Sharable */
|
||||
#define TLBI_CRm_RNS 6 /* Range, Non-Sharable */
|
||||
#define TLBI_CRm_nRNS 7 /* non-Range, Non-Sharable */
|
||||
|
||||
#define OP_TLBI_VMALLE1OS sys_insn(1, 0, 8, 1, 0)
|
||||
#define OP_TLBI_VAE1OS sys_insn(1, 0, 8, 1, 1)
|
||||
#define OP_TLBI_ASIDE1OS sys_insn(1, 0, 8, 1, 2)
|
||||
|
||||
@@ -128,6 +128,7 @@ int main(void)
|
||||
DEFINE(VCPU_FAULT_DISR, offsetof(struct kvm_vcpu, arch.fault.disr_el1));
|
||||
DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2));
|
||||
DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_cpu_context, regs));
|
||||
DEFINE(CPU_ELR_EL2, offsetof(struct kvm_cpu_context, sys_regs[ELR_EL2]));
|
||||
DEFINE(CPU_RGSR_EL1, offsetof(struct kvm_cpu_context, sys_regs[RGSR_EL1]));
|
||||
DEFINE(CPU_GCR_EL1, offsetof(struct kvm_cpu_context, sys_regs[GCR_EL1]));
|
||||
DEFINE(CPU_APIAKEYLO_EL1, offsetof(struct kvm_cpu_context, sys_regs[APIAKEYLO_EL1]));
|
||||
|
||||
@@ -312,9 +312,7 @@ static int call_break_hook(struct pt_regs *regs, unsigned long esr)
|
||||
* entirely not preemptible, and we can use rcu list safely here.
|
||||
*/
|
||||
list_for_each_entry_rcu(hook, list, node) {
|
||||
unsigned long comment = esr & ESR_ELx_BRK64_ISS_COMMENT_MASK;
|
||||
|
||||
if ((comment & ~hook->mask) == hook->imm)
|
||||
if ((esr_brk_comment(esr) & ~hook->mask) == hook->imm)
|
||||
fn = hook->fn;
|
||||
}
|
||||
|
||||
|
||||
@@ -1105,8 +1105,6 @@ static struct break_hook ubsan_break_hook = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#define esr_comment(esr) ((esr) & ESR_ELx_BRK64_ISS_COMMENT_MASK)
|
||||
|
||||
/*
|
||||
* Initial handler for AArch64 BRK exceptions
|
||||
* This handler only used until debug_traps_init().
|
||||
@@ -1115,15 +1113,15 @@ int __init early_brk64(unsigned long addr, unsigned long esr,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_CFI_CLANG
|
||||
if ((esr_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE)
|
||||
if (esr_is_cfi_brk(esr))
|
||||
return cfi_handler(regs, esr) != DBG_HOOK_HANDLED;
|
||||
#endif
|
||||
#ifdef CONFIG_KASAN_SW_TAGS
|
||||
if ((esr_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM)
|
||||
if ((esr_brk_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM)
|
||||
return kasan_handler(regs, esr) != DBG_HOOK_HANDLED;
|
||||
#endif
|
||||
#ifdef CONFIG_UBSAN_TRAP
|
||||
if ((esr_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM)
|
||||
if ((esr_brk_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM)
|
||||
return ubsan_handler(regs, esr) != DBG_HOOK_HANDLED;
|
||||
#endif
|
||||
return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user