arm64: add hypervisor stub
If booted in EL2, install an dummy hypervisor whose only purpose is to be replaced by a full fledged one. A minimal API allows to: - obtain the current HYP vectors (__hyp_get_vectors) - set new HYP vectors (__hyp_set_vectors) Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
parent
f35a92053b
commit
712c6ff4db
@ -33,6 +33,9 @@
|
|||||||
*/
|
*/
|
||||||
extern u32 __boot_cpu_mode[2];
|
extern u32 __boot_cpu_mode[2];
|
||||||
|
|
||||||
|
void __hyp_set_vectors(phys_addr_t phys_vector_base);
|
||||||
|
phys_addr_t __hyp_get_vectors(void);
|
||||||
|
|
||||||
/* Reports the availability of HYP mode */
|
/* Reports the availability of HYP mode */
|
||||||
static inline bool is_hyp_mode_available(void)
|
static inline bool is_hyp_mode_available(void)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
|||||||
# Object file lists.
|
# Object file lists.
|
||||||
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
|
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
|
||||||
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
|
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
|
||||||
sys.o stacktrace.o time.o traps.o io.o vdso.o
|
sys.o stacktrace.o time.o traps.o io.o vdso.o \
|
||||||
|
hyp-stub.o
|
||||||
|
|
||||||
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
|
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
|
||||||
sys_compat.o
|
sys_compat.o
|
||||||
|
@ -185,6 +185,10 @@ ENTRY(el2_setup)
|
|||||||
msr hstr_el2, xzr // Disable CP15 traps to EL2
|
msr hstr_el2, xzr // Disable CP15 traps to EL2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Hypervisor stub */
|
||||||
|
adr x0, __hyp_stub_vectors
|
||||||
|
msr vbar_el2, x0
|
||||||
|
|
||||||
/* spsr */
|
/* spsr */
|
||||||
mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
|
mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
|
||||||
PSR_MODE_EL1h)
|
PSR_MODE_EL1h)
|
||||||
|
109
arch/arm64/kernel/hyp-stub.S
Normal file
109
arch/arm64/kernel/hyp-stub.S
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Hypervisor stub
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
|
#include <asm/assembler.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
#include <asm/virt.h>
|
||||||
|
|
||||||
|
.text
|
||||||
|
.align 11
|
||||||
|
|
||||||
|
ENTRY(__hyp_stub_vectors)
|
||||||
|
ventry el2_sync_invalid // Synchronous EL2t
|
||||||
|
ventry el2_irq_invalid // IRQ EL2t
|
||||||
|
ventry el2_fiq_invalid // FIQ EL2t
|
||||||
|
ventry el2_error_invalid // Error EL2t
|
||||||
|
|
||||||
|
ventry el2_sync_invalid // Synchronous EL2h
|
||||||
|
ventry el2_irq_invalid // IRQ EL2h
|
||||||
|
ventry el2_fiq_invalid // FIQ EL2h
|
||||||
|
ventry el2_error_invalid // Error EL2h
|
||||||
|
|
||||||
|
ventry el1_sync // Synchronous 64-bit EL1
|
||||||
|
ventry el1_irq_invalid // IRQ 64-bit EL1
|
||||||
|
ventry el1_fiq_invalid // FIQ 64-bit EL1
|
||||||
|
ventry el1_error_invalid // Error 64-bit EL1
|
||||||
|
|
||||||
|
ventry el1_sync_invalid // Synchronous 32-bit EL1
|
||||||
|
ventry el1_irq_invalid // IRQ 32-bit EL1
|
||||||
|
ventry el1_fiq_invalid // FIQ 32-bit EL1
|
||||||
|
ventry el1_error_invalid // Error 32-bit EL1
|
||||||
|
ENDPROC(__hyp_stub_vectors)
|
||||||
|
|
||||||
|
.align 11
|
||||||
|
|
||||||
|
el1_sync:
|
||||||
|
mrs x1, esr_el2
|
||||||
|
lsr x1, x1, #26
|
||||||
|
cmp x1, #0x16
|
||||||
|
b.ne 2f // Not an HVC trap
|
||||||
|
cbz x0, 1f
|
||||||
|
msr vbar_el2, x0 // Set vbar_el2
|
||||||
|
b 2f
|
||||||
|
1: mrs x0, vbar_el2 // Return vbar_el2
|
||||||
|
2: eret
|
||||||
|
ENDPROC(el1_sync)
|
||||||
|
|
||||||
|
.macro invalid_vector label
|
||||||
|
\label:
|
||||||
|
b \label
|
||||||
|
ENDPROC(\label)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
invalid_vector el2_sync_invalid
|
||||||
|
invalid_vector el2_irq_invalid
|
||||||
|
invalid_vector el2_fiq_invalid
|
||||||
|
invalid_vector el2_error_invalid
|
||||||
|
invalid_vector el1_sync_invalid
|
||||||
|
invalid_vector el1_irq_invalid
|
||||||
|
invalid_vector el1_fiq_invalid
|
||||||
|
invalid_vector el1_error_invalid
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __hyp_set_vectors: Call this after boot to set the initial hypervisor
|
||||||
|
* vectors as part of hypervisor installation. On an SMP system, this should
|
||||||
|
* be called on each CPU.
|
||||||
|
*
|
||||||
|
* x0 must be the physical address of the new vector table, and must be
|
||||||
|
* 2KB aligned.
|
||||||
|
*
|
||||||
|
* Before calling this, you must check that the stub hypervisor is installed
|
||||||
|
* everywhere, by waiting for any secondary CPUs to be brought up and then
|
||||||
|
* checking that is_hyp_mode_available() is true.
|
||||||
|
*
|
||||||
|
* If not, there is a pre-existing hypervisor, some CPUs failed to boot, or
|
||||||
|
* something else went wrong... in such cases, trying to install a new
|
||||||
|
* hypervisor is unlikely to work as desired.
|
||||||
|
*
|
||||||
|
* When you call into your shiny new hypervisor, sp_el2 will contain junk,
|
||||||
|
* so you will need to set that to something sensible at the new hypervisor's
|
||||||
|
* initialisation entry point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ENTRY(__hyp_get_vectors)
|
||||||
|
mov x0, xzr
|
||||||
|
// fall through
|
||||||
|
ENTRY(__hyp_set_vectors)
|
||||||
|
hvc #0
|
||||||
|
ret
|
||||||
|
ENDPROC(__hyp_get_vectors)
|
||||||
|
ENDPROC(__hyp_set_vectors)
|
Loading…
Reference in New Issue
Block a user