mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
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];
|
||||
|
||||
void __hyp_set_vectors(phys_addr_t phys_vector_base);
|
||||
phys_addr_t __hyp_get_vectors(void);
|
||||
|
||||
/* Reports the availability of HYP mode */
|
||||
static inline bool is_hyp_mode_available(void)
|
||||
{
|
||||
|
@ -8,7 +8,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
# Object file lists.
|
||||
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 \
|
||||
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 \
|
||||
sys_compat.o
|
||||
|
@ -185,6 +185,10 @@ ENTRY(el2_setup)
|
||||
msr hstr_el2, xzr // Disable CP15 traps to EL2
|
||||
#endif
|
||||
|
||||
/* Hypervisor stub */
|
||||
adr x0, __hyp_stub_vectors
|
||||
msr vbar_el2, x0
|
||||
|
||||
/* spsr */
|
||||
mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
|
||||
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