mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull KVM updates from Paolo Bonzini:
"ARM:
- Support for userspace handling of synchronous external aborts
(SEAs), allowing the VMM to potentially handle the abort in a
non-fatal manner
- Large rework of the VGIC's list register handling with the goal of
supporting more active/pending IRQs than available list registers
in hardware. In addition, the VGIC now supports EOImode==1 style
deactivations for IRQs which may occur on a separate vCPU than the
one that acked the IRQ
- Support for FEAT_XNX (user / privileged execute permissions) and
FEAT_HAF (hardware update to the Access Flag) in the software page
table walkers and shadow MMU
- Allow page table destruction to reschedule, fixing long
need_resched latencies observed when destroying a large VM
- Minor fixes to KVM and selftests
Loongarch:
- Get VM PMU capability from HW GCFG register
- Add AVEC basic support
- Use 64-bit register definition for EIOINTC
- Add KVM timer test cases for tools/selftests
RISC/V:
- SBI message passing (MPXY) support for KVM guest
- Give a new, more specific error subcode for the case when in-kernel
AIA virtualization fails to allocate IMSIC VS-file
- Support KVM_DIRTY_LOG_INITIALLY_SET, enabling dirty log gradually
in small chunks
- Fix guest page fault within HLV* instructions
- Flush VS-stage TLB after VCPU migration for Andes cores
s390:
- Always allocate ESCA (Extended System Control Area), instead of
starting with the basic SCA and converting to ESCA with the
addition of the 65th vCPU. The price is increased number of exits
(and worse performance) on z10 and earlier processor; ESCA was
introduced by z114/z196 in 2010
- VIRT_XFER_TO_GUEST_WORK support
- Operation exception forwarding support
- Cleanups
x86:
- Skip the costly "zap all SPTEs" on an MMIO generation wrap if MMIO
SPTE caching is disabled, as there can't be any relevant SPTEs to
zap
- Relocate a misplaced export
- Fix an async #PF bug where KVM would clear the completion queue
when the guest transitioned in and out of paging mode, e.g. when
handling an SMI and then returning to paged mode via RSM
- Leave KVM's user-return notifier registered even when disabling
virtualization, as long as kvm.ko is loaded. On reboot/shutdown,
keeping the notifier registered is ok; the kernel does not use the
MSRs and the callback will run cleanly and restore host MSRs if the
CPU manages to return to userspace before the system goes down
- Use the checked version of {get,put}_user()
- Fix a long-lurking bug where KVM's lack of catch-up logic for
periodic APIC timers can result in a hard lockup in the host
- Revert the periodic kvmclock sync logic now that KVM doesn't use a
clocksource that's subject to NTP corrections
- Clean up KVM's handling of MMIO Stale Data and L1TF, and bury the
latter behind CONFIG_CPU_MITIGATIONS
- Context switch XCR0, XSS, and PKRU outside of the entry/exit fast
path; the only reason they were handled in the fast path was to
paper of a bug in the core #MC code, and that has long since been
fixed
- Add emulator support for AVX MOV instructions, to play nice with
emulated devices whose guest drivers like to access PCI BARs with
large multi-byte instructions
x86 (AMD):
- Fix a few missing "VMCB dirty" bugs
- Fix the worst of KVM's lack of EFER.LMSLE emulation
- Add AVIC support for addressing 4k vCPUs in x2AVIC mode
- Fix incorrect handling of selective CR0 writes when checking
intercepts during emulation of L2 instructions
- Fix a currently-benign bug where KVM would clobber SPEC_CTRL[63:32]
on VMRUN and #VMEXIT
- Fix a bug where KVM corrupt the guest code stream when re-injecting
a soft interrupt if the guest patched the underlying code after the
VM-Exit, e.g. when Linux patches code with a temporary INT3
- Add KVM_X86_SNP_POLICY_BITS to advertise supported SNP policy bits
to userspace, and extend KVM "support" to all policy bits that
don't require any actual support from KVM
x86 (Intel):
- Use the root role from kvm_mmu_page to construct EPTPs instead of
the current vCPU state, partly as worthwhile cleanup, but mostly to
pave the way for tracking per-root TLB flushes, and elide EPT
flushes on pCPU migration if the root is clean from a previous
flush
- Add a few missing nested consistency checks
- Rip out support for doing "early" consistency checks via hardware
as the functionality hasn't been used in years and is no longer
useful in general; replace it with an off-by-default module param
to WARN if hardware fails a check that KVM does not perform
- Fix a currently-benign bug where KVM would drop the guest's
SPEC_CTRL[63:32] on VM-Enter
- Misc cleanups
- Overhaul the TDX code to address systemic races where KVM (acting
on behalf of userspace) could inadvertantly trigger lock contention
in the TDX-Module; KVM was either working around these in weird,
ugly ways, or was simply oblivious to them (though even Yan's
devilish selftests could only break individual VMs, not the host
kernel)
- Fix a bug where KVM could corrupt a vCPU's cpu_list when freeing a
TDX vCPU, if creating said vCPU failed partway through
- Fix a few sparse warnings (bad annotation, 0 != NULL)
- Use struct_size() to simplify copying TDX capabilities to userspace
- Fix a bug where TDX would effectively corrupt user-return MSR
values if the TDX Module rejects VP.ENTER and thus doesn't clobber
host MSRs as expected
Selftests:
- Fix a math goof in mmu_stress_test when running on a single-CPU
system/VM
- Forcefully override ARCH from x86_64 to x86 to play nice with
specifying ARCH=x86_64 on the command line
- Extend a bunch of nested VMX to validate nested SVM as well
- Add support for LA57 in the core VM_MODE_xxx macro, and add a test
to verify KVM can save/restore nested VMX state when L1 is using
5-level paging, but L2 is not
- Clean up the guest paging code in anticipation of sharing the core
logic for nested EPT and nested NPT
guest_memfd:
- Add NUMA mempolicy support for guest_memfd, and clean up a variety
of rough edges in guest_memfd along the way
- Define a CLASS to automatically handle get+put when grabbing a
guest_memfd from a memslot to make it harder to leak references
- Enhance KVM selftests to make it easer to develop and debug
selftests like those added for guest_memfd NUMA support, e.g. where
test and/or KVM bugs often result in hard-to-debug SIGBUS errors
- Misc cleanups
Generic:
- Use the recently-added WQ_PERCPU when creating the per-CPU
workqueue for irqfd cleanup
- Fix a goof in the dirty ring documentation
- Fix choice of target for directed yield across different calls to
kvm_vcpu_on_spin(); the function was always starting from the first
vCPU instead of continuing the round-robin search"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (260 commits)
KVM: arm64: at: Update AF on software walk only if VM has FEAT_HAFDBS
KVM: arm64: at: Use correct HA bit in TCR_EL2 when regime is EL2
KVM: arm64: Document KVM_PGTABLE_PROT_{UX,PX}
KVM: arm64: Fix spelling mistake "Unexpeced" -> "Unexpected"
KVM: arm64: Add break to default case in kvm_pgtable_stage2_pte_prot()
KVM: arm64: Add endian casting to kvm_swap_s[12]_desc()
KVM: arm64: Fix compilation when CONFIG_ARM64_USE_LSE_ATOMICS=n
KVM: arm64: selftests: Add test for AT emulation
KVM: arm64: nv: Expose hardware access flag management to NV guests
KVM: arm64: nv: Implement HW access flag management in stage-2 SW PTW
KVM: arm64: Implement HW access flag management in stage-1 SW PTW
KVM: arm64: Propagate PTW errors up to AT emulation
KVM: arm64: Add helper for swapping guest descriptor
KVM: arm64: nv: Use pgtable definitions in stage-2 walk
KVM: arm64: Handle endianness in read helper for emulated PTW
KVM: arm64: nv: Stop passing vCPU through void ptr in S2 PTW
KVM: arm64: Call helper for reading descriptors directly
KVM: arm64: nv: Advertise support for FEAT_XNX
KVM: arm64: Teach ptdump about FEAT_XNX permissions
KVM: s390: Use generic VIRT_XFER_TO_GUEST_WORK functions
...
This commit is contained in:
@@ -7286,6 +7286,41 @@ exit, even without calls to ``KVM_ENABLE_CAP`` or similar. In this case,
|
||||
it will enter with output fields already valid; in the common case, the
|
||||
``unknown.ret`` field of the union will be ``TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED``.
|
||||
Userspace need not do anything if it does not wish to support a TDVMCALL.
|
||||
|
||||
::
|
||||
|
||||
/* KVM_EXIT_ARM_SEA */
|
||||
struct {
|
||||
#define KVM_EXIT_ARM_SEA_FLAG_GPA_VALID (1ULL << 0)
|
||||
__u64 flags;
|
||||
__u64 esr;
|
||||
__u64 gva;
|
||||
__u64 gpa;
|
||||
} arm_sea;
|
||||
|
||||
Used on arm64 systems. When the VM capability ``KVM_CAP_ARM_SEA_TO_USER`` is
|
||||
enabled, a KVM exits to userspace if a guest access causes a synchronous
|
||||
external abort (SEA) and the host APEI fails to handle the SEA.
|
||||
|
||||
``esr`` is set to a sanitized value of ESR_EL2 from the exception taken to KVM,
|
||||
consisting of the following fields:
|
||||
|
||||
- ``ESR_EL2.EC``
|
||||
- ``ESR_EL2.IL``
|
||||
- ``ESR_EL2.FnV``
|
||||
- ``ESR_EL2.EA``
|
||||
- ``ESR_EL2.CM``
|
||||
- ``ESR_EL2.WNR``
|
||||
- ``ESR_EL2.FSC``
|
||||
- ``ESR_EL2.SET`` (when FEAT_RAS is implemented for the VM)
|
||||
|
||||
``gva`` is set to the value of FAR_EL2 from the exception taken to KVM when
|
||||
``ESR_EL2.FnV == 0``. Otherwise, the value of ``gva`` is unknown.
|
||||
|
||||
``gpa`` is set to the faulting IPA from the exception taken to KVM when
|
||||
the ``KVM_EXIT_ARM_SEA_FLAG_GPA_VALID`` flag is set. Otherwise, the value of
|
||||
``gpa`` is unknown.
|
||||
|
||||
::
|
||||
|
||||
/* Fix the size of the union. */
|
||||
@@ -7820,7 +7855,7 @@ where 0xff represents CPUs 0-7 in cluster 0.
|
||||
:Architectures: s390
|
||||
:Parameters: none
|
||||
|
||||
With this capability enabled, all illegal instructions 0x0000 (2 bytes) will
|
||||
With this capability enabled, the illegal instruction 0x0000 (2 bytes) will
|
||||
be intercepted and forwarded to user space. User space can use this
|
||||
mechanism e.g. to realize 2-byte software breakpoints. The kernel will
|
||||
not inject an operating exception for these instructions, user space has
|
||||
@@ -8028,7 +8063,7 @@ will be initialized to 1 when created. This also improves performance because
|
||||
dirty logging can be enabled gradually in small chunks on the first call
|
||||
to KVM_CLEAR_DIRTY_LOG. KVM_DIRTY_LOG_INITIALLY_SET depends on
|
||||
KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (it is also only available on
|
||||
x86 and arm64 for now).
|
||||
x86, arm64 and riscv for now).
|
||||
|
||||
KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 was previously available under the name
|
||||
KVM_CAP_MANUAL_DIRTY_LOG_PROTECT, but the implementation had bugs that make
|
||||
@@ -8524,7 +8559,7 @@ Therefore, the ioctl must be called *before* reading the content of
|
||||
the dirty pages.
|
||||
|
||||
The dirty ring can get full. When it happens, the KVM_RUN of the
|
||||
vcpu will return with exit reason KVM_EXIT_DIRTY_LOG_FULL.
|
||||
vcpu will return with exit reason KVM_EXIT_DIRTY_RING_FULL.
|
||||
|
||||
The dirty ring interface has a major difference comparing to the
|
||||
KVM_GET_DIRTY_LOG interface in that, when reading the dirty ring from
|
||||
@@ -8692,7 +8727,7 @@ given VM.
|
||||
When this capability is enabled, KVM resets the VCPU when setting
|
||||
MP_STATE_INIT_RECEIVED through IOCTL. The original MP_STATE is preserved.
|
||||
|
||||
7.43 KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED
|
||||
7.44 KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED
|
||||
-------------------------------------------
|
||||
|
||||
:Architectures: arm64
|
||||
@@ -8703,6 +8738,33 @@ This capability indicate to the userspace whether a PFNMAP memory region
|
||||
can be safely mapped as cacheable. This relies on the presence of
|
||||
force write back (FWB) feature support on the hardware.
|
||||
|
||||
7.45 KVM_CAP_ARM_SEA_TO_USER
|
||||
----------------------------
|
||||
|
||||
:Architecture: arm64
|
||||
:Target: VM
|
||||
:Parameters: none
|
||||
:Returns: 0 on success, -EINVAL if unsupported.
|
||||
|
||||
When this capability is enabled, KVM may exit to userspace for SEAs taken to
|
||||
EL2 resulting from a guest access. See ``KVM_EXIT_ARM_SEA`` for more
|
||||
information.
|
||||
|
||||
7.46 KVM_CAP_S390_USER_OPEREXEC
|
||||
-------------------------------
|
||||
|
||||
:Architectures: s390
|
||||
:Parameters: none
|
||||
|
||||
When this capability is enabled KVM forwards all operation exceptions
|
||||
that it doesn't handle itself to user space. This also includes the
|
||||
0x0000 instructions managed by KVM_CAP_S390_USER_INSTR0. This is
|
||||
helpful if user space wants to emulate instructions which are not
|
||||
(yet) implemented in hardware.
|
||||
|
||||
This capability can be enabled dynamically even if VCPUs were already
|
||||
created and are running.
|
||||
|
||||
8. Other capabilities.
|
||||
======================
|
||||
|
||||
|
||||
@@ -48,7 +48,14 @@ versus "has_error_code", i.e. KVM's ABI follows AMD behavior.
|
||||
Nested virtualization features
|
||||
------------------------------
|
||||
|
||||
TBD
|
||||
On AMD CPUs, when GIF is cleared, #DB exceptions or traps due to a breakpoint
|
||||
register match are ignored and discarded by the CPU. The CPU relies on the VMM
|
||||
to fully virtualize this behavior, even when vGIF is enabled for the guest
|
||||
(i.e. vGIF=0 does not cause the CPU to drop #DBs when the guest is running).
|
||||
KVM does not virtualize this behavior as the complexity is unjustified given
|
||||
the rarity of the use case. One way to handle this would be for KVM to
|
||||
intercept the #DB, temporarily disable the breakpoint, single-step over the
|
||||
instruction, then re-enable the breakpoint.
|
||||
|
||||
x2APIC
|
||||
------
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
#define TCR_EL2_DS (1UL << 32)
|
||||
#define TCR_EL2_RES1 ((1U << 31) | (1 << 23))
|
||||
#define TCR_EL2_HPD (1 << 24)
|
||||
#define TCR_EL2_HA (1 << 21)
|
||||
#define TCR_EL2_TBI (1 << 20)
|
||||
#define TCR_EL2_PS_SHIFT 16
|
||||
#define TCR_EL2_PS_MASK (7 << TCR_EL2_PS_SHIFT)
|
||||
|
||||
@@ -79,7 +79,7 @@ enum __kvm_host_smccc_func {
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range,
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context,
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff,
|
||||
__KVM_HOST_SMCCC_FUNC___vgic_v3_save_vmcr_aprs,
|
||||
__KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs,
|
||||
__KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_reserve_vm,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_unreserve_vm,
|
||||
@@ -246,9 +246,9 @@ 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 void __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
extern void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
extern void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
extern int __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
extern int __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
extern int __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
|
||||
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#define KVM_REQ_NESTED_S2_UNMAP KVM_ARCH_REQ(8)
|
||||
#define KVM_REQ_GUEST_HYP_IRQ_PENDING KVM_ARCH_REQ(9)
|
||||
#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10)
|
||||
#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)
|
||||
|
||||
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
|
||||
KVM_DIRTY_LOG_INITIALLY_SET)
|
||||
@@ -350,6 +351,8 @@ struct kvm_arch {
|
||||
#define KVM_ARCH_FLAG_GUEST_HAS_SVE 9
|
||||
/* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
|
||||
#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
|
||||
/* Unhandled SEAs are taken to userspace */
|
||||
#define KVM_ARCH_FLAG_EXIT_SEA 11
|
||||
unsigned long flags;
|
||||
|
||||
/* VM-wide vCPU feature set */
|
||||
|
||||
@@ -77,12 +77,13 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
|
||||
int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
|
||||
|
||||
u64 __gic_v3_get_lr(unsigned int lr);
|
||||
void __gic_v3_set_lr(u64 val, int lr);
|
||||
|
||||
void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if);
|
||||
void __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if);
|
||||
void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if);
|
||||
void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if);
|
||||
void __vgic_v3_save_vmcr_aprs(struct vgic_v3_cpu_if *cpu_if);
|
||||
void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if);
|
||||
void __vgic_v3_restore_vmcr_aprs(struct vgic_v3_cpu_if *cpu_if);
|
||||
int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
||||
@@ -120,9 +120,42 @@ 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)
|
||||
static inline bool kvm_has_xnx(struct kvm *kvm)
|
||||
{
|
||||
return !(trans->desc & BIT(54));
|
||||
return cpus_have_final_cap(ARM64_HAS_XNX) &&
|
||||
kvm_has_feat(kvm, ID_AA64MMFR1_EL1, XNX, IMP);
|
||||
}
|
||||
|
||||
static inline bool kvm_s2_trans_exec_el0(struct kvm *kvm, struct kvm_s2_trans *trans)
|
||||
{
|
||||
u8 xn = FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, trans->desc);
|
||||
|
||||
if (!kvm_has_xnx(kvm))
|
||||
xn &= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, 0b10);
|
||||
|
||||
switch (xn) {
|
||||
case 0b00:
|
||||
case 0b01:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool kvm_s2_trans_exec_el1(struct kvm *kvm, struct kvm_s2_trans *trans)
|
||||
{
|
||||
u8 xn = FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, trans->desc);
|
||||
|
||||
if (!kvm_has_xnx(kvm))
|
||||
xn &= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, 0b10);
|
||||
|
||||
switch (xn) {
|
||||
case 0b00:
|
||||
case 0b11:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
|
||||
@@ -320,6 +353,7 @@ struct s1_walk_info {
|
||||
bool be;
|
||||
bool s2;
|
||||
bool pa52bit;
|
||||
bool ha;
|
||||
};
|
||||
|
||||
struct s1_walk_result {
|
||||
@@ -370,4 +404,6 @@ void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val);
|
||||
(FIX_VNCR - __c); \
|
||||
})
|
||||
|
||||
int __kvm_at_swap_desc(struct kvm *kvm, gpa_t ipa, u64 old, u64 new);
|
||||
|
||||
#endif /* __ARM64_KVM_NESTED_H */
|
||||
|
||||
@@ -89,7 +89,7 @@ typedef u64 kvm_pte_t;
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN BIT(54)
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN GENMASK(54, 53)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S1_GP BIT(50)
|
||||
|
||||
@@ -240,7 +240,9 @@ enum kvm_pgtable_stage2_flags {
|
||||
|
||||
/**
|
||||
* enum kvm_pgtable_prot - Page-table permissions and attributes.
|
||||
* @KVM_PGTABLE_PROT_X: Execute permission.
|
||||
* @KVM_PGTABLE_PROT_UX: Unprivileged execute permission.
|
||||
* @KVM_PGTABLE_PROT_PX: Privileged execute permission.
|
||||
* @KVM_PGTABLE_PROT_X: Privileged and unprivileged execute permission.
|
||||
* @KVM_PGTABLE_PROT_W: Write permission.
|
||||
* @KVM_PGTABLE_PROT_R: Read permission.
|
||||
* @KVM_PGTABLE_PROT_DEVICE: Device attributes.
|
||||
@@ -251,12 +253,15 @@ enum kvm_pgtable_stage2_flags {
|
||||
* @KVM_PGTABLE_PROT_SW3: Software bit 3.
|
||||
*/
|
||||
enum kvm_pgtable_prot {
|
||||
KVM_PGTABLE_PROT_X = BIT(0),
|
||||
KVM_PGTABLE_PROT_W = BIT(1),
|
||||
KVM_PGTABLE_PROT_R = BIT(2),
|
||||
KVM_PGTABLE_PROT_PX = BIT(0),
|
||||
KVM_PGTABLE_PROT_UX = BIT(1),
|
||||
KVM_PGTABLE_PROT_X = KVM_PGTABLE_PROT_PX |
|
||||
KVM_PGTABLE_PROT_UX,
|
||||
KVM_PGTABLE_PROT_W = BIT(2),
|
||||
KVM_PGTABLE_PROT_R = BIT(3),
|
||||
|
||||
KVM_PGTABLE_PROT_DEVICE = BIT(3),
|
||||
KVM_PGTABLE_PROT_NORMAL_NC = BIT(4),
|
||||
KVM_PGTABLE_PROT_DEVICE = BIT(4),
|
||||
KVM_PGTABLE_PROT_NORMAL_NC = BIT(5),
|
||||
|
||||
KVM_PGTABLE_PROT_SW0 = BIT(55),
|
||||
KVM_PGTABLE_PROT_SW1 = BIT(56),
|
||||
@@ -355,6 +360,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke
|
||||
return pteref;
|
||||
}
|
||||
|
||||
static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref)
|
||||
{
|
||||
return pteref;
|
||||
}
|
||||
|
||||
static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker)
|
||||
{
|
||||
/*
|
||||
@@ -384,6 +394,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke
|
||||
return rcu_dereference_check(pteref, !(walker->flags & KVM_PGTABLE_WALK_SHARED));
|
||||
}
|
||||
|
||||
static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref)
|
||||
{
|
||||
return rcu_dereference_raw(pteref);
|
||||
}
|
||||
|
||||
static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker)
|
||||
{
|
||||
if (walker->flags & KVM_PGTABLE_WALK_SHARED)
|
||||
@@ -551,6 +566,26 @@ static inline int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2
|
||||
*/
|
||||
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_destroy_range() - Destroy the unlinked range of addresses.
|
||||
* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*().
|
||||
* @addr: Intermediate physical address at which to place the mapping.
|
||||
* @size: Size of the mapping.
|
||||
*
|
||||
* The page-table is assumed to be unreachable by any hardware walkers prior
|
||||
* to freeing and therefore no TLB invalidation is performed.
|
||||
*/
|
||||
void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
|
||||
u64 addr, u64 size);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_destroy_pgd() - Destroy the PGD of guest stage-2 page-table.
|
||||
* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*().
|
||||
*
|
||||
* It is assumed that the rest of the page-table is freed before this operation.
|
||||
*/
|
||||
void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_free_unlinked() - Free an unlinked stage-2 paging structure.
|
||||
* @mm_ops: Memory management callbacks.
|
||||
|
||||
@@ -180,7 +180,9 @@ struct pkvm_mapping {
|
||||
|
||||
int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
|
||||
struct kvm_pgtable_mm_ops *mm_ops);
|
||||
void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
|
||||
void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
|
||||
u64 addr, u64 size);
|
||||
void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt);
|
||||
int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys,
|
||||
enum kvm_pgtable_prot prot, void *mc,
|
||||
enum kvm_pgtable_walk_flags flags);
|
||||
|
||||
@@ -40,8 +40,13 @@
|
||||
*/
|
||||
#define HVC_FINALISE_EL2 3
|
||||
|
||||
/*
|
||||
* HVC_GET_ICH_VTR_EL2 - Retrieve the ICH_VTR_EL2 value
|
||||
*/
|
||||
#define HVC_GET_ICH_VTR_EL2 4
|
||||
|
||||
/* Max number of HYP stub hypercalls */
|
||||
#define HVC_STUB_HCALL_NR 4
|
||||
#define HVC_STUB_HCALL_NR 5
|
||||
|
||||
/* Error returned when an invalid stub number is passed into x0 */
|
||||
#define HVC_STUB_ERR 0xbadca11
|
||||
|
||||
@@ -2304,6 +2304,49 @@ static bool has_gic_prio_relaxed_sync(const struct arm64_cpu_capabilities *entry
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool can_trap_icv_dir_el1(const struct arm64_cpu_capabilities *entry,
|
||||
int scope)
|
||||
{
|
||||
static const struct midr_range has_vgic_v3[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M1_ICESTORM),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M1_ICESTORM_PRO),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM_PRO),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M1_ICESTORM_MAX),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM_MAX),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_PRO),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_PRO),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_MAX),
|
||||
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_MAX),
|
||||
{},
|
||||
};
|
||||
struct arm_smccc_res res = {};
|
||||
|
||||
BUILD_BUG_ON(ARM64_HAS_ICH_HCR_EL2_TDIR <= ARM64_HAS_GICV3_CPUIF);
|
||||
BUILD_BUG_ON(ARM64_HAS_ICH_HCR_EL2_TDIR <= ARM64_HAS_GICV5_LEGACY);
|
||||
if (!this_cpu_has_cap(ARM64_HAS_GICV3_CPUIF) &&
|
||||
!is_midr_in_range_list(has_vgic_v3))
|
||||
return false;
|
||||
|
||||
if (!is_hyp_mode_available())
|
||||
return false;
|
||||
|
||||
if (this_cpu_has_cap(ARM64_HAS_GICV5_LEGACY))
|
||||
return true;
|
||||
|
||||
if (is_kernel_in_hyp_mode())
|
||||
res.a1 = read_sysreg_s(SYS_ICH_VTR_EL2);
|
||||
else
|
||||
arm_smccc_1_1_hvc(HVC_GET_ICH_VTR_EL2, &res);
|
||||
|
||||
if (res.a0 == HVC_STUB_ERR)
|
||||
return false;
|
||||
|
||||
return res.a1 & ICH_VTR_EL2_TDS;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64_BTI
|
||||
static void bti_enable(const struct arm64_cpu_capabilities *__unused)
|
||||
{
|
||||
@@ -2815,6 +2858,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||
.matches = has_gic_prio_relaxed_sync,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* Depends on having GICv3
|
||||
*/
|
||||
.desc = "ICV_DIR_EL1 trapping",
|
||||
.capability = ARM64_HAS_ICH_HCR_EL2_TDIR,
|
||||
.type = ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE,
|
||||
.matches = can_trap_icv_dir_el1,
|
||||
},
|
||||
#ifdef CONFIG_ARM64_E0PD
|
||||
{
|
||||
.desc = "E0PD",
|
||||
@@ -3089,6 +3141,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||
.capability = ARM64_HAS_GICV5_LEGACY,
|
||||
.matches = test_has_gicv5_legacy,
|
||||
},
|
||||
{
|
||||
.desc = "XNX",
|
||||
.capability = ARM64_HAS_XNX,
|
||||
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
|
||||
.matches = has_cpuid_feature,
|
||||
ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, XNX, IMP)
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
@@ -54,6 +54,11 @@ SYM_CODE_START_LOCAL(elx_sync)
|
||||
1: cmp x0, #HVC_FINALISE_EL2
|
||||
b.eq __finalise_el2
|
||||
|
||||
cmp x0, #HVC_GET_ICH_VTR_EL2
|
||||
b.ne 2f
|
||||
mrs_s x1, SYS_ICH_VTR_EL2
|
||||
b 9f
|
||||
|
||||
2: cmp x0, #HVC_SOFT_RESTART
|
||||
b.ne 3f
|
||||
mov x0, x2
|
||||
|
||||
@@ -91,6 +91,7 @@ KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);
|
||||
KVM_NVHE_ALIAS(spectre_bhb_patch_wa3);
|
||||
KVM_NVHE_ALIAS(spectre_bhb_patch_clearbhb);
|
||||
KVM_NVHE_ALIAS(alt_cb_patch_nops);
|
||||
KVM_NVHE_ALIAS(kvm_compute_ich_hcr_trap_bits);
|
||||
|
||||
/* Global kernel state accessed by nVHE hyp code. */
|
||||
KVM_NVHE_ALIAS(kvm_vgic_global_state);
|
||||
|
||||
+17
-3
@@ -132,6 +132,10 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
|
||||
}
|
||||
mutex_unlock(&kvm->lock);
|
||||
break;
|
||||
case KVM_CAP_ARM_SEA_TO_USER:
|
||||
r = 0;
|
||||
set_bit(KVM_ARCH_FLAG_EXIT_SEA, &kvm->arch.flags);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -327,6 +331,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
case KVM_CAP_IRQFD_RESAMPLE:
|
||||
case KVM_CAP_COUNTER_OFFSET:
|
||||
case KVM_CAP_ARM_WRITABLE_IMP_ID_REGS:
|
||||
case KVM_CAP_ARM_SEA_TO_USER:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_SET_GUEST_DEBUG2:
|
||||
@@ -440,7 +445,7 @@ struct kvm *kvm_arch_alloc_vm(void)
|
||||
if (!has_vhe())
|
||||
return kzalloc(sz, GFP_KERNEL_ACCOUNT);
|
||||
|
||||
return __vmalloc(sz, GFP_KERNEL_ACCOUNT | __GFP_HIGHMEM | __GFP_ZERO);
|
||||
return kvzalloc(sz, GFP_KERNEL_ACCOUNT);
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
|
||||
@@ -659,8 +664,7 @@ nommu:
|
||||
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (is_protected_kvm_enabled()) {
|
||||
kvm_call_hyp(__vgic_v3_save_vmcr_aprs,
|
||||
&vcpu->arch.vgic_cpu.vgic_v3);
|
||||
kvm_call_hyp(__vgic_v3_save_aprs, &vcpu->arch.vgic_cpu.vgic_v3);
|
||||
kvm_call_hyp_nvhe(__pkvm_vcpu_put);
|
||||
}
|
||||
|
||||
@@ -1042,6 +1046,10 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
kvm_check_request(KVM_REQ_IRQ_PENDING, vcpu);
|
||||
|
||||
/* Process interrupts deactivated through a trap */
|
||||
if (kvm_check_request(KVM_REQ_VGIC_PROCESS_UPDATE, vcpu))
|
||||
kvm_vgic_process_async_update(vcpu);
|
||||
|
||||
if (kvm_check_request(KVM_REQ_RECORD_STEAL, vcpu))
|
||||
kvm_update_stolen_time(vcpu);
|
||||
|
||||
@@ -1835,6 +1843,12 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
return r;
|
||||
}
|
||||
|
||||
long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
|
||||
unsigned long arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
|
||||
{
|
||||
|
||||
|
||||
+176
-20
@@ -346,6 +346,11 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
|
||||
wi->baddr &= GENMASK_ULL(wi->max_oa_bits - 1, x);
|
||||
|
||||
wi->ha = kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, HAFDBS, AF);
|
||||
wi->ha &= (wi->regime == TR_EL2 ?
|
||||
FIELD_GET(TCR_EL2_HA, tcr) :
|
||||
FIELD_GET(TCR_HA, tcr));
|
||||
|
||||
return 0;
|
||||
|
||||
addrsz:
|
||||
@@ -362,10 +367,42 @@ transfault:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int kvm_read_s1_desc(struct kvm_vcpu *vcpu, u64 pa, u64 *desc,
|
||||
struct s1_walk_info *wi)
|
||||
{
|
||||
u64 val;
|
||||
int r;
|
||||
|
||||
r = kvm_read_guest(vcpu->kvm, pa, &val, sizeof(val));
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (wi->be)
|
||||
*desc = be64_to_cpu((__force __be64)val);
|
||||
else
|
||||
*desc = le64_to_cpu((__force __le64)val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_swap_s1_desc(struct kvm_vcpu *vcpu, u64 pa, u64 old, u64 new,
|
||||
struct s1_walk_info *wi)
|
||||
{
|
||||
if (wi->be) {
|
||||
old = (__force u64)cpu_to_be64(old);
|
||||
new = (__force u64)cpu_to_be64(new);
|
||||
} else {
|
||||
old = (__force u64)cpu_to_le64(old);
|
||||
new = (__force u64)cpu_to_le64(new);
|
||||
}
|
||||
|
||||
return __kvm_at_swap_desc(vcpu->kvm, pa, old, new);
|
||||
}
|
||||
|
||||
static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
struct s1_walk_result *wr, u64 va)
|
||||
{
|
||||
u64 va_top, va_bottom, baddr, desc;
|
||||
u64 va_top, va_bottom, baddr, desc, new_desc, ipa;
|
||||
int level, stride, ret;
|
||||
|
||||
level = wi->sl;
|
||||
@@ -375,7 +412,7 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
va_top = get_ia_size(wi) - 1;
|
||||
|
||||
while (1) {
|
||||
u64 index, ipa;
|
||||
u64 index;
|
||||
|
||||
va_bottom = (3 - level) * stride + wi->pgshift;
|
||||
index = (va & GENMASK_ULL(va_top, va_bottom)) >> (va_bottom - 3);
|
||||
@@ -414,16 +451,13 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_read_guest(vcpu->kvm, ipa, &desc, sizeof(desc));
|
||||
ret = kvm_read_s1_desc(vcpu, ipa, &desc, wi);
|
||||
if (ret) {
|
||||
fail_s1_walk(wr, ESR_ELx_FSC_SEA_TTW(level), false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (wi->be)
|
||||
desc = be64_to_cpu((__force __be64)desc);
|
||||
else
|
||||
desc = le64_to_cpu((__force __le64)desc);
|
||||
new_desc = desc;
|
||||
|
||||
/* Invalid descriptor */
|
||||
if (!(desc & BIT(0)))
|
||||
@@ -477,6 +511,17 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
|
||||
if (check_output_size(baddr & GENMASK(52, va_bottom), wi))
|
||||
goto addrsz;
|
||||
|
||||
if (wi->ha)
|
||||
new_desc |= PTE_AF;
|
||||
|
||||
if (new_desc != desc) {
|
||||
ret = kvm_swap_s1_desc(vcpu, ipa, desc, new_desc, wi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
desc = new_desc;
|
||||
}
|
||||
|
||||
if (!(desc & PTE_AF)) {
|
||||
fail_s1_walk(wr, ESR_ELx_FSC_ACCESS_L(level), false);
|
||||
return -EACCES;
|
||||
@@ -1221,7 +1266,7 @@ static void compute_s1_permissions(struct kvm_vcpu *vcpu,
|
||||
wr->pr &= !pan;
|
||||
}
|
||||
|
||||
static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
static int handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr, u64 *par)
|
||||
{
|
||||
struct s1_walk_result wr = {};
|
||||
struct s1_walk_info wi = {};
|
||||
@@ -1246,6 +1291,11 @@ static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||||
|
||||
/*
|
||||
* Race to update a descriptor -- restart the walk.
|
||||
*/
|
||||
if (ret == -EAGAIN)
|
||||
return ret;
|
||||
if (ret)
|
||||
goto compute_par;
|
||||
|
||||
@@ -1279,7 +1329,8 @@ static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
fail_s1_walk(&wr, ESR_ELx_FSC_PERM_L(wr.level), false);
|
||||
|
||||
compute_par:
|
||||
return compute_par_s1(vcpu, &wi, &wr);
|
||||
*par = compute_par_s1(vcpu, &wi, &wr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1407,9 +1458,10 @@ static bool par_check_s1_access_fault(u64 par)
|
||||
!(par & SYS_PAR_EL1_S));
|
||||
}
|
||||
|
||||
void __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
int __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
{
|
||||
u64 par = __kvm_at_s1e01_fast(vcpu, op, vaddr);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If PAR_EL1 reports that AT failed on a S1 permission or access
|
||||
@@ -1421,15 +1473,20 @@ void __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
*/
|
||||
if ((par & SYS_PAR_EL1_F) &&
|
||||
!par_check_s1_perm_fault(par) &&
|
||||
!par_check_s1_access_fault(par))
|
||||
par = handle_at_slow(vcpu, op, vaddr);
|
||||
!par_check_s1_access_fault(par)) {
|
||||
ret = handle_at_slow(vcpu, op, vaddr, &par);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
vcpu_write_sys_reg(vcpu, par, PAR_EL1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
int __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
{
|
||||
u64 par;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We've trapped, so everything is live on the CPU. As we will be
|
||||
@@ -1476,13 +1533,17 @@ void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
}
|
||||
|
||||
/* We failed the translation, let's replay it in slow motion */
|
||||
if ((par & SYS_PAR_EL1_F) && !par_check_s1_perm_fault(par))
|
||||
par = handle_at_slow(vcpu, op, vaddr);
|
||||
if ((par & SYS_PAR_EL1_F) && !par_check_s1_perm_fault(par)) {
|
||||
ret = handle_at_slow(vcpu, op, vaddr, &par);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
vcpu_write_sys_reg(vcpu, par, PAR_EL1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
int __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
{
|
||||
struct kvm_s2_trans out = {};
|
||||
u64 ipa, par;
|
||||
@@ -1509,13 +1570,13 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__kvm_at_s1e01(vcpu, op, vaddr);
|
||||
par = vcpu_read_sys_reg(vcpu, PAR_EL1);
|
||||
if (par & SYS_PAR_EL1_F)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we only have a single stage of translation (EL2&0), exit
|
||||
@@ -1523,14 +1584,14 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
*/
|
||||
if (compute_translation_regime(vcpu, op) == TR_EL20 ||
|
||||
!(vcpu_read_sys_reg(vcpu, HCR_EL2) & (HCR_VM | HCR_DC)))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/* Do the stage-2 translation */
|
||||
ipa = (par & GENMASK_ULL(47, 12)) | (vaddr & GENMASK_ULL(11, 0));
|
||||
out.esr = 0;
|
||||
ret = kvm_walk_nested_s2(vcpu, ipa, &out);
|
||||
if (ret < 0)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
/* Check the access permission */
|
||||
if (!out.esr &&
|
||||
@@ -1539,6 +1600,7 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
|
||||
par = compute_par_s12(vcpu, par, &out);
|
||||
vcpu_write_sys_reg(vcpu, par, PAR_EL1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1637,3 +1699,97 @@ int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa, int *level)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64_LSE_ATOMICS
|
||||
static int __lse_swap_desc(u64 __user *ptep, u64 old, u64 new)
|
||||
{
|
||||
u64 tmp = old;
|
||||
int ret = 0;
|
||||
|
||||
uaccess_enable_privileged();
|
||||
|
||||
asm volatile(__LSE_PREAMBLE
|
||||
"1: cas %[old], %[new], %[addr]\n"
|
||||
"2:\n"
|
||||
_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w[ret])
|
||||
: [old] "+r" (old), [addr] "+Q" (*ptep), [ret] "+r" (ret)
|
||||
: [new] "r" (new)
|
||||
: "memory");
|
||||
|
||||
uaccess_disable_privileged();
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp != old)
|
||||
return -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int __lse_swap_desc(u64 __user *ptep, u64 old, u64 new)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __llsc_swap_desc(u64 __user *ptep, u64 old, u64 new)
|
||||
{
|
||||
int ret = 1;
|
||||
u64 tmp;
|
||||
|
||||
uaccess_enable_privileged();
|
||||
|
||||
asm volatile("prfm pstl1strm, %[addr]\n"
|
||||
"1: ldxr %[tmp], %[addr]\n"
|
||||
"sub %[tmp], %[tmp], %[old]\n"
|
||||
"cbnz %[tmp], 3f\n"
|
||||
"2: stlxr %w[ret], %[new], %[addr]\n"
|
||||
"3:\n"
|
||||
_ASM_EXTABLE_UACCESS_ERR(1b, 3b, %w[ret])
|
||||
_ASM_EXTABLE_UACCESS_ERR(2b, 3b, %w[ret])
|
||||
: [ret] "+r" (ret), [addr] "+Q" (*ptep), [tmp] "=&r" (tmp)
|
||||
: [old] "r" (old), [new] "r" (new)
|
||||
: "memory");
|
||||
|
||||
uaccess_disable_privileged();
|
||||
|
||||
/* STLXR didn't update the descriptor, or the compare failed */
|
||||
if (ret == 1)
|
||||
return -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __kvm_at_swap_desc(struct kvm *kvm, gpa_t ipa, u64 old, u64 new)
|
||||
{
|
||||
struct kvm_memory_slot *slot;
|
||||
unsigned long hva;
|
||||
u64 __user *ptep;
|
||||
bool writable;
|
||||
int offset;
|
||||
gfn_t gfn;
|
||||
int r;
|
||||
|
||||
lockdep_assert(srcu_read_lock_held(&kvm->srcu));
|
||||
|
||||
gfn = ipa >> PAGE_SHIFT;
|
||||
offset = offset_in_page(ipa);
|
||||
slot = gfn_to_memslot(kvm, gfn);
|
||||
hva = gfn_to_hva_memslot_prot(slot, gfn, &writable);
|
||||
if (kvm_is_error_hva(hva))
|
||||
return -EINVAL;
|
||||
if (!writable)
|
||||
return -EPERM;
|
||||
|
||||
ptep = (u64 __user *)hva + offset;
|
||||
if (cpus_have_final_cap(ARM64_HAS_LSE_ATOMICS))
|
||||
r = __lse_swap_desc(ptep, old, new);
|
||||
else
|
||||
r = __llsc_swap_desc(ptep, old, new);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
mark_page_dirty_in_slot(kvm, slot, gfn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -157,6 +157,7 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
host_vcpu->arch.iflags = hyp_vcpu->vcpu.arch.iflags;
|
||||
|
||||
host_cpu_if->vgic_hcr = hyp_cpu_if->vgic_hcr;
|
||||
host_cpu_if->vgic_vmcr = hyp_cpu_if->vgic_vmcr;
|
||||
for (i = 0; i < hyp_cpu_if->used_lrs; ++i)
|
||||
host_cpu_if->vgic_lr[i] = hyp_cpu_if->vgic_lr[i];
|
||||
}
|
||||
@@ -464,11 +465,11 @@ static void handle___vgic_v3_init_lrs(struct kvm_cpu_context *host_ctxt)
|
||||
__vgic_v3_init_lrs();
|
||||
}
|
||||
|
||||
static void handle___vgic_v3_save_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
|
||||
static void handle___vgic_v3_save_aprs(struct kvm_cpu_context *host_ctxt)
|
||||
{
|
||||
DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1);
|
||||
|
||||
__vgic_v3_save_vmcr_aprs(kern_hyp_va(cpu_if));
|
||||
__vgic_v3_save_aprs(kern_hyp_va(cpu_if));
|
||||
}
|
||||
|
||||
static void handle___vgic_v3_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
|
||||
@@ -616,7 +617,7 @@ static const hcall_t host_hcall[] = {
|
||||
HANDLE_FUNC(__kvm_tlb_flush_vmid_range),
|
||||
HANDLE_FUNC(__kvm_flush_cpu_context),
|
||||
HANDLE_FUNC(__kvm_timer_set_cntvoff),
|
||||
HANDLE_FUNC(__vgic_v3_save_vmcr_aprs),
|
||||
HANDLE_FUNC(__vgic_v3_save_aprs),
|
||||
HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
|
||||
HANDLE_FUNC(__pkvm_reserve_vm),
|
||||
HANDLE_FUNC(__pkvm_unreserve_vm),
|
||||
|
||||
@@ -337,6 +337,9 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
|
||||
/* CTR_EL0 is always under host control, even for protected VMs. */
|
||||
hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
|
||||
|
||||
/* Preserve the vgic model so that GICv3 emulation works */
|
||||
hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
|
||||
|
||||
if (test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &host_kvm->arch.flags))
|
||||
set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
|
||||
|
||||
|
||||
@@ -444,6 +444,8 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
|
||||
|
||||
/* Scalable Vector Registers are restricted. */
|
||||
|
||||
HOST_HANDLED(SYS_ICC_PMR_EL1),
|
||||
|
||||
RAZ_WI(SYS_ERRIDR_EL1),
|
||||
RAZ_WI(SYS_ERRSELR_EL1),
|
||||
RAZ_WI(SYS_ERXFR_EL1),
|
||||
@@ -457,9 +459,12 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
|
||||
|
||||
/* Limited Ordering Regions Registers are restricted. */
|
||||
|
||||
HOST_HANDLED(SYS_ICC_DIR_EL1),
|
||||
HOST_HANDLED(SYS_ICC_RPR_EL1),
|
||||
HOST_HANDLED(SYS_ICC_SGI1R_EL1),
|
||||
HOST_HANDLED(SYS_ICC_ASGI1R_EL1),
|
||||
HOST_HANDLED(SYS_ICC_SGI0R_EL1),
|
||||
HOST_HANDLED(SYS_ICC_CTLR_EL1),
|
||||
{ SYS_DESC(SYS_ICC_SRE_EL1), .access = pvm_gic_read_sre, },
|
||||
|
||||
HOST_HANDLED(SYS_CCSIDR_EL1),
|
||||
|
||||
+107
-21
@@ -661,11 +661,37 @@ void kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,
|
||||
|
||||
#define KVM_S2_MEMATTR(pgt, attr) PAGE_S2_MEMATTR(attr, stage2_has_fwb(pgt))
|
||||
|
||||
static int stage2_set_xn_attr(enum kvm_pgtable_prot prot, kvm_pte_t *attr)
|
||||
{
|
||||
bool px, ux;
|
||||
u8 xn;
|
||||
|
||||
px = prot & KVM_PGTABLE_PROT_PX;
|
||||
ux = prot & KVM_PGTABLE_PROT_UX;
|
||||
|
||||
if (!cpus_have_final_cap(ARM64_HAS_XNX) && px != ux)
|
||||
return -EINVAL;
|
||||
|
||||
if (px && ux)
|
||||
xn = 0b00;
|
||||
else if (!px && ux)
|
||||
xn = 0b01;
|
||||
else if (!px && !ux)
|
||||
xn = 0b10;
|
||||
else
|
||||
xn = 0b11;
|
||||
|
||||
*attr &= ~KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
*attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, xn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot prot,
|
||||
kvm_pte_t *ptep)
|
||||
{
|
||||
kvm_pte_t attr;
|
||||
u32 sh = KVM_PTE_LEAF_ATTR_LO_S2_SH_IS;
|
||||
int r;
|
||||
|
||||
switch (prot & (KVM_PGTABLE_PROT_DEVICE |
|
||||
KVM_PGTABLE_PROT_NORMAL_NC)) {
|
||||
@@ -685,8 +711,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
|
||||
attr = KVM_S2_MEMATTR(pgt, NORMAL);
|
||||
}
|
||||
|
||||
if (!(prot & KVM_PGTABLE_PROT_X))
|
||||
attr |= KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
r = stage2_set_xn_attr(prot, &attr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (prot & KVM_PGTABLE_PROT_R)
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;
|
||||
@@ -715,8 +742,20 @@ enum kvm_pgtable_prot kvm_pgtable_stage2_pte_prot(kvm_pte_t pte)
|
||||
prot |= KVM_PGTABLE_PROT_R;
|
||||
if (pte & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W)
|
||||
prot |= KVM_PGTABLE_PROT_W;
|
||||
if (!(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN))
|
||||
prot |= KVM_PGTABLE_PROT_X;
|
||||
|
||||
switch (FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, pte)) {
|
||||
case 0b00:
|
||||
prot |= KVM_PGTABLE_PROT_PX | KVM_PGTABLE_PROT_UX;
|
||||
break;
|
||||
case 0b01:
|
||||
prot |= KVM_PGTABLE_PROT_UX;
|
||||
break;
|
||||
case 0b11:
|
||||
prot |= KVM_PGTABLE_PROT_PX;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return prot;
|
||||
}
|
||||
@@ -1290,9 +1329,9 @@ bool kvm_pgtable_stage2_test_clear_young(struct kvm_pgtable *pgt, u64 addr,
|
||||
int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
|
||||
enum kvm_pgtable_prot prot, enum kvm_pgtable_walk_flags flags)
|
||||
{
|
||||
int ret;
|
||||
kvm_pte_t xn = 0, set = 0, clr = 0;
|
||||
s8 level;
|
||||
kvm_pte_t set = 0, clr = 0;
|
||||
int ret;
|
||||
|
||||
if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
|
||||
return -EINVAL;
|
||||
@@ -1303,8 +1342,12 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
|
||||
if (prot & KVM_PGTABLE_PROT_W)
|
||||
set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
|
||||
|
||||
if (prot & KVM_PGTABLE_PROT_X)
|
||||
clr |= KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
ret = stage2_set_xn_attr(prot, &xn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
set |= xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
clr |= ~xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
|
||||
ret = stage2_update_leaf_attrs(pgt, addr, 1, set, clr, NULL, &level, flags);
|
||||
if (!ret || ret == -EAGAIN)
|
||||
@@ -1535,37 +1578,80 @@ size_t kvm_pgtable_stage2_pgd_size(u64 vtcr)
|
||||
return kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
|
||||
}
|
||||
|
||||
static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
enum kvm_pgtable_walk_flags visit)
|
||||
static int stage2_free_leaf(const struct kvm_pgtable_visit_ctx *ctx)
|
||||
{
|
||||
struct kvm_pgtable_mm_ops *mm_ops = ctx->mm_ops;
|
||||
|
||||
if (!stage2_pte_is_counted(ctx->old))
|
||||
return 0;
|
||||
|
||||
mm_ops->put_page(ctx->ptep);
|
||||
|
||||
if (kvm_pte_table(ctx->old, ctx->level))
|
||||
mm_ops->put_page(kvm_pte_follow(ctx->old, mm_ops));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
static int stage2_free_table_post(const struct kvm_pgtable_visit_ctx *ctx)
|
||||
{
|
||||
struct kvm_pgtable_mm_ops *mm_ops = ctx->mm_ops;
|
||||
kvm_pte_t *childp = kvm_pte_follow(ctx->old, mm_ops);
|
||||
|
||||
if (mm_ops->page_count(childp) != 1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Drop references and clear the now stale PTE to avoid rewalking the
|
||||
* freed page table.
|
||||
*/
|
||||
mm_ops->put_page(ctx->ptep);
|
||||
mm_ops->put_page(childp);
|
||||
kvm_clear_pte(ctx->ptep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
enum kvm_pgtable_walk_flags visit)
|
||||
{
|
||||
if (!stage2_pte_is_counted(ctx->old))
|
||||
return 0;
|
||||
|
||||
switch (visit) {
|
||||
case KVM_PGTABLE_WALK_LEAF:
|
||||
return stage2_free_leaf(ctx);
|
||||
case KVM_PGTABLE_WALK_TABLE_POST:
|
||||
return stage2_free_table_post(ctx);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
|
||||
u64 addr, u64 size)
|
||||
{
|
||||
size_t pgd_sz;
|
||||
struct kvm_pgtable_walker walker = {
|
||||
.cb = stage2_free_walker,
|
||||
.flags = KVM_PGTABLE_WALK_LEAF |
|
||||
KVM_PGTABLE_WALK_TABLE_POST,
|
||||
};
|
||||
|
||||
WARN_ON(kvm_pgtable_walk(pgt, 0, BIT(pgt->ia_bits), &walker));
|
||||
WARN_ON(kvm_pgtable_walk(pgt, addr, size, &walker));
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt)
|
||||
{
|
||||
size_t pgd_sz;
|
||||
|
||||
pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level) * PAGE_SIZE;
|
||||
pgt->mm_ops->free_pages_exact(kvm_dereference_pteref(&walker, pgt->pgd), pgd_sz);
|
||||
|
||||
/*
|
||||
* Since the pgtable is unlinked at this point, and not shared with
|
||||
* other walkers, safely deference pgd with kvm_dereference_pteref_raw()
|
||||
*/
|
||||
pgt->mm_ops->free_pages_exact(kvm_dereference_pteref_raw(pgt->pgd), pgd_sz);
|
||||
pgt->pgd = NULL;
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
{
|
||||
kvm_pgtable_stage2_destroy_range(pgt, 0, BIT(pgt->ia_bits));
|
||||
kvm_pgtable_stage2_destroy_pgd(pgt);
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level)
|
||||
{
|
||||
kvm_pteref_t ptep = (kvm_pteref_t)pgtable;
|
||||
|
||||
@@ -63,6 +63,10 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Handle deactivation as a normal exit */
|
||||
if ((fault_ipa - vgic->vgic_cpu_base) >= GIC_CPU_DEACTIVATE)
|
||||
return 0;
|
||||
|
||||
rd = kvm_vcpu_dabt_get_rd(vcpu);
|
||||
addr = kvm_vgic_global_state.vcpu_hyp_va;
|
||||
addr += fault_ipa - vgic->vgic_cpu_base;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user