mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-19 07:39:54 +02:00

When memory protection is enabled, the EL2 code needs the ability to create and manage its own page-table. To do so, introduce a new set of hypercalls to bootstrap a memory management system at EL2. This leads to the following boot flow in nVHE Protected mode: 1. the host allocates memory for the hypervisor very early on, using the memblock API; 2. the host creates a set of stage 1 page-table for EL2, installs the EL2 vectors, and issues the __pkvm_init hypercall; 3. during __pkvm_init, the hypervisor re-creates its stage 1 page-table and stores it in the memory pool provided by the host; 4. the hypervisor then extends its stage 1 mappings to include a vmemmap in the EL2 VA space, hence allowing to use the buddy allocator introduced in a previous patch; 5. the hypervisor jumps back in the idmap page, switches from the host-provided page-table to the new one, and wraps up its initialization by enabling the new allocator, before returning to the host. 6. the host can free the now unused page-table created for EL2, and will now need to issue hypercalls to make changes to the EL2 stage 1 mappings instead of modifying them directly. Note that for the sake of simplifying the review, this patch focuses on the hypervisor side of things. In other words, this only implements the new hypercalls, but does not make use of them from the host yet. The host-side changes will follow in a subsequent patch. Credits to Will for __pkvm_init_switch_pgd. Acked-by: Will Deacon <will@kernel.org> Co-authored-by: Will Deacon <will@kernel.org> Signed-off-by: Will Deacon <will@kernel.org> Signed-off-by: Quentin Perret <qperret@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20210319100146.1149909-18-qperret@google.com
120 lines
4.0 KiB
C
120 lines
4.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (C) 2015 - ARM Ltd
|
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
*/
|
|
|
|
#ifndef __ARM64_KVM_HYP_H__
|
|
#define __ARM64_KVM_HYP_H__
|
|
|
|
#include <linux/compiler.h>
|
|
#include <linux/kvm_host.h>
|
|
#include <asm/alternative.h>
|
|
#include <asm/sysreg.h>
|
|
|
|
DECLARE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
|
|
DECLARE_PER_CPU(unsigned long, kvm_hyp_vector);
|
|
DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
|
|
|
|
#define read_sysreg_elx(r,nvh,vh) \
|
|
({ \
|
|
u64 reg; \
|
|
asm volatile(ALTERNATIVE(__mrs_s("%0", r##nvh), \
|
|
__mrs_s("%0", r##vh), \
|
|
ARM64_HAS_VIRT_HOST_EXTN) \
|
|
: "=r" (reg)); \
|
|
reg; \
|
|
})
|
|
|
|
#define write_sysreg_elx(v,r,nvh,vh) \
|
|
do { \
|
|
u64 __val = (u64)(v); \
|
|
asm volatile(ALTERNATIVE(__msr_s(r##nvh, "%x0"), \
|
|
__msr_s(r##vh, "%x0"), \
|
|
ARM64_HAS_VIRT_HOST_EXTN) \
|
|
: : "rZ" (__val)); \
|
|
} while (0)
|
|
|
|
/*
|
|
* Unified accessors for registers that have a different encoding
|
|
* between VHE and non-VHE. They must be specified without their "ELx"
|
|
* encoding, but with the SYS_ prefix, as defined in asm/sysreg.h.
|
|
*/
|
|
|
|
#define read_sysreg_el0(r) read_sysreg_elx(r, _EL0, _EL02)
|
|
#define write_sysreg_el0(v,r) write_sysreg_elx(v, r, _EL0, _EL02)
|
|
#define read_sysreg_el1(r) read_sysreg_elx(r, _EL1, _EL12)
|
|
#define write_sysreg_el1(v,r) write_sysreg_elx(v, r, _EL1, _EL12)
|
|
#define read_sysreg_el2(r) read_sysreg_elx(r, _EL2, _EL1)
|
|
#define write_sysreg_el2(v,r) write_sysreg_elx(v, r, _EL2, _EL1)
|
|
|
|
/*
|
|
* Without an __arch_swab32(), we fall back to ___constant_swab32(), but the
|
|
* static inline can allow the compiler to out-of-line this. KVM always wants
|
|
* the macro version as its always inlined.
|
|
*/
|
|
#define __kvm_swab32(x) ___constant_swab32(x)
|
|
|
|
int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
|
|
|
|
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_aprs(struct vgic_v3_cpu_if *cpu_if);
|
|
void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if);
|
|
int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
|
|
|
|
#ifdef __KVM_NVHE_HYPERVISOR__
|
|
void __timer_enable_traps(struct kvm_vcpu *vcpu);
|
|
void __timer_disable_traps(struct kvm_vcpu *vcpu);
|
|
#endif
|
|
|
|
#ifdef __KVM_NVHE_HYPERVISOR__
|
|
void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt);
|
|
void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt);
|
|
#else
|
|
void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt);
|
|
void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt);
|
|
void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt);
|
|
void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt);
|
|
#endif
|
|
|
|
void __debug_switch_to_guest(struct kvm_vcpu *vcpu);
|
|
void __debug_switch_to_host(struct kvm_vcpu *vcpu);
|
|
|
|
#ifdef __KVM_NVHE_HYPERVISOR__
|
|
void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu);
|
|
void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu);
|
|
#endif
|
|
|
|
void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
|
|
void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
|
|
void __sve_save_state(void *sve_pffr, u32 *fpsr);
|
|
void __sve_restore_state(void *sve_pffr, u32 *fpsr);
|
|
|
|
#ifndef __KVM_NVHE_HYPERVISOR__
|
|
void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
|
|
void deactivate_traps_vhe_put(void);
|
|
#endif
|
|
|
|
u64 __guest_enter(struct kvm_vcpu *vcpu);
|
|
|
|
bool kvm_host_psci_handler(struct kvm_cpu_context *host_ctxt);
|
|
|
|
void __noreturn hyp_panic(void);
|
|
#ifdef __KVM_NVHE_HYPERVISOR__
|
|
void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr,
|
|
u64 elr, u64 par);
|
|
#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);
|
|
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);
|
|
#endif
|
|
|
|
#endif /* __ARM64_KVM_HYP_H__ */
|