mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
The existing arm64 hcall implementations are limited in that they only allow for two distinct hcalls; with the x0 register either zero or not zero. Also, the API of the hyp-stub exception vector routines and the KVM exception vector routines differ; hyp-stub uses a non-zero value in x0 to implement __hyp_set_vectors, whereas KVM uses it to implement kvm_call_hyp. To allow for additional hcalls to be defined and to make the arm64 hcall API more consistent across exception vector routines, change the hcall implementations to reserve all x0 values below 0xfff for hcalls such as {s,g}et_vectors(). Define two new preprocessor macros HVC_GET_VECTORS, and HVC_SET_VECTORS to be used as hcall type specifiers and convert the existing __hyp_get_vectors() and __hyp_set_vectors() routines to use these new macros when executing an HVC call. Also, change the corresponding hyp-stub and KVM el1_sync exception vector routines to use these new macros. Signed-off-by: Geoff Levand <geoff@infradead.org> [Merged two hcall patches, moved immediate value from esr to x0, use lr as a scratch register, changed limit to 0xfff] Signed-off-by: James Morse <james.morse@arm.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
131 lines
3.4 KiB
ArmAsm
131 lines
3.4 KiB
ArmAsm
/*
|
|
* 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 <linux/irqchip/arm-gic-v3.h>
|
|
|
|
#include <asm/assembler.h>
|
|
#include <asm/kvm_arm.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 x30, esr_el2
|
|
lsr x30, x30, #ESR_ELx_EC_SHIFT
|
|
|
|
cmp x30, #ESR_ELx_EC_HVC64
|
|
b.ne 9f // Not an HVC trap
|
|
|
|
cmp x0, #HVC_GET_VECTORS
|
|
b.ne 1f
|
|
mrs x0, vbar_el2
|
|
b 9f
|
|
|
|
1: cmp x0, #HVC_SET_VECTORS
|
|
b.ne 2f
|
|
msr vbar_el2, x1
|
|
b 9f
|
|
|
|
/* Unrecognised call type */
|
|
2: mov x0, xzr
|
|
|
|
9: 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)
|
|
str lr, [sp, #-16]!
|
|
mov x0, #HVC_GET_VECTORS
|
|
hvc #0
|
|
ldr lr, [sp], #16
|
|
ret
|
|
ENDPROC(__hyp_get_vectors)
|
|
|
|
ENTRY(__hyp_set_vectors)
|
|
str lr, [sp, #-16]!
|
|
mov x1, x0
|
|
mov x0, #HVC_SET_VECTORS
|
|
hvc #0
|
|
ldr lr, [sp], #16
|
|
ret
|
|
ENDPROC(__hyp_set_vectors)
|