mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 15:18:19 +00:00
arm64: Provide an 'upgrade to VHE' stub hypercall
As we are about to change the way a VHE system boots, let's provide the core helper, in the form of a stub hypercall that enables VHE and replicates the full EL1 context at EL2, thanks to EL1 and VHE-EL2 being extremely similar. On exception return, the kernel carries on at EL2. Fancy! Nothing calls this new hypercall yet, so no functional change. Signed-off-by: Marc Zyngier <maz@kernel.org> Acked-by: David Brazdil <dbrazdil@google.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Link: https://lore.kernel.org/r/20210208095732.3267263-5-maz@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
8cc8a32415
commit
f359182291
2 changed files with 80 additions and 3 deletions
|
@ -35,8 +35,13 @@
|
||||||
*/
|
*/
|
||||||
#define HVC_RESET_VECTORS 2
|
#define HVC_RESET_VECTORS 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HVC_VHE_RESTART - Upgrade the CPU from EL1 to EL2, if possible
|
||||||
|
*/
|
||||||
|
#define HVC_VHE_RESTART 3
|
||||||
|
|
||||||
/* Max number of HYP stub hypercalls */
|
/* Max number of HYP stub hypercalls */
|
||||||
#define HVC_STUB_HCALL_NR 3
|
#define HVC_STUB_HCALL_NR 4
|
||||||
|
|
||||||
/* Error returned when an invalid stub number is passed into x0 */
|
/* Error returned when an invalid stub number is passed into x0 */
|
||||||
#define HVC_STUB_ERR 0xbadca11
|
#define HVC_STUB_ERR 0xbadca11
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/irqchip/arm-gic-v3.h>
|
|
||||||
|
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
|
#include <asm/el2_setup.h>
|
||||||
#include <asm/kvm_arm.h>
|
#include <asm/kvm_arm.h>
|
||||||
#include <asm/kvm_asm.h>
|
#include <asm/kvm_asm.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
@ -47,10 +47,13 @@ SYM_CODE_END(__hyp_stub_vectors)
|
||||||
|
|
||||||
SYM_CODE_START_LOCAL(el1_sync)
|
SYM_CODE_START_LOCAL(el1_sync)
|
||||||
cmp x0, #HVC_SET_VECTORS
|
cmp x0, #HVC_SET_VECTORS
|
||||||
b.ne 2f
|
b.ne 1f
|
||||||
msr vbar_el2, x1
|
msr vbar_el2, x1
|
||||||
b 9f
|
b 9f
|
||||||
|
|
||||||
|
1: cmp x0, #HVC_VHE_RESTART
|
||||||
|
b.eq mutate_to_vhe
|
||||||
|
|
||||||
2: cmp x0, #HVC_SOFT_RESTART
|
2: cmp x0, #HVC_SOFT_RESTART
|
||||||
b.ne 3f
|
b.ne 3f
|
||||||
mov x0, x2
|
mov x0, x2
|
||||||
|
@ -70,6 +73,75 @@ SYM_CODE_START_LOCAL(el1_sync)
|
||||||
eret
|
eret
|
||||||
SYM_CODE_END(el1_sync)
|
SYM_CODE_END(el1_sync)
|
||||||
|
|
||||||
|
// nVHE? No way! Give me the real thing!
|
||||||
|
SYM_CODE_START_LOCAL(mutate_to_vhe)
|
||||||
|
// Be prepared to fail
|
||||||
|
mov_q x0, HVC_STUB_ERR
|
||||||
|
|
||||||
|
// Sanity check: MMU *must* be off
|
||||||
|
mrs x1, sctlr_el2
|
||||||
|
tbnz x1, #0, 1f
|
||||||
|
|
||||||
|
// Needs to be VHE capable, obviously
|
||||||
|
mrs x1, id_aa64mmfr1_el1
|
||||||
|
ubfx x1, x1, #ID_AA64MMFR1_VHE_SHIFT, #4
|
||||||
|
cbz x1, 1f
|
||||||
|
|
||||||
|
// Engage the VHE magic!
|
||||||
|
mov_q x0, HCR_HOST_VHE_FLAGS
|
||||||
|
msr hcr_el2, x0
|
||||||
|
isb
|
||||||
|
|
||||||
|
// Doesn't do much on VHE, but still, worth a shot
|
||||||
|
init_el2_state vhe
|
||||||
|
|
||||||
|
// Use the EL1 allocated stack, per-cpu offset
|
||||||
|
mrs x0, sp_el1
|
||||||
|
mov sp, x0
|
||||||
|
mrs x0, tpidr_el1
|
||||||
|
msr tpidr_el2, x0
|
||||||
|
|
||||||
|
// FP configuration, vectors
|
||||||
|
mrs_s x0, SYS_CPACR_EL12
|
||||||
|
msr cpacr_el1, x0
|
||||||
|
mrs_s x0, SYS_VBAR_EL12
|
||||||
|
msr vbar_el1, x0
|
||||||
|
|
||||||
|
// Transfer the MM state from EL1 to EL2
|
||||||
|
mrs_s x0, SYS_TCR_EL12
|
||||||
|
msr tcr_el1, x0
|
||||||
|
mrs_s x0, SYS_TTBR0_EL12
|
||||||
|
msr ttbr0_el1, x0
|
||||||
|
mrs_s x0, SYS_TTBR1_EL12
|
||||||
|
msr ttbr1_el1, x0
|
||||||
|
mrs_s x0, SYS_MAIR_EL12
|
||||||
|
msr mair_el1, x0
|
||||||
|
isb
|
||||||
|
|
||||||
|
// Invalidate TLBs before enabling the MMU
|
||||||
|
tlbi vmalle1
|
||||||
|
dsb nsh
|
||||||
|
|
||||||
|
// Enable the EL2 S1 MMU, as set up from EL1
|
||||||
|
mrs_s x0, SYS_SCTLR_EL12
|
||||||
|
set_sctlr_el1 x0
|
||||||
|
|
||||||
|
// Disable the EL1 S1 MMU for a good measure
|
||||||
|
mov_q x0, INIT_SCTLR_EL1_MMU_OFF
|
||||||
|
msr_s SYS_SCTLR_EL12, x0
|
||||||
|
|
||||||
|
// Hack the exception return to stay at EL2
|
||||||
|
mrs x0, spsr_el1
|
||||||
|
and x0, x0, #~PSR_MODE_MASK
|
||||||
|
mov x1, #PSR_MODE_EL2h
|
||||||
|
orr x0, x0, x1
|
||||||
|
msr spsr_el1, x0
|
||||||
|
|
||||||
|
mov x0, xzr
|
||||||
|
|
||||||
|
1: eret
|
||||||
|
SYM_CODE_END(mutate_to_vhe)
|
||||||
|
|
||||||
.macro invalid_vector label
|
.macro invalid_vector label
|
||||||
SYM_CODE_START_LOCAL(\label)
|
SYM_CODE_START_LOCAL(\label)
|
||||||
b \label
|
b \label
|
||||||
|
|
Loading…
Reference in a new issue