u-boot/arch/arm/cpu/armv7/smccc-call.S
Heinrich Schuchardt 81ea00838c efi_loader: PSCI reset and shutdown
When an operating system started via bootefi tries to reset or power off
this is done by calling the EFI runtime ResetSystem(). On most ARMv8 system
the actual reset relies on PSCI. Depending on whether the PSCI firmware
resides the hypervisor (EL2) or in the secure monitor (EL3) either an HVC
or an SMC command has to be issued.

The current implementation always uses SMC. This results in crashes on
systems where the PSCI firmware is implemented in the hypervisor, e.g.
qemu-arm64_defconfig.

The logic to decide which call is needed based on the device tree is
already implemented in the PSCI firmware driver. During the EFI runtime
the device driver model is not available. But we can minimize code
duplication by merging the EFI runtime reset and poweroff code with
the PSCI firmware driver.

As the same HVC/SMC problem is also evident for the ARMv8 do_poweroff
and reset_misc routines let's move them into the same code module.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Sumit Garg <sumit.garg@linaro.org>
Tested-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
2018-12-02 21:59:37 +01:00

57 lines
1.2 KiB
ArmAsm

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2015, Linaro Limited
*/
#include <linux/linkage.h>
#include <asm/opcodes-sec.h>
#include <asm/opcodes-virt.h>
.section .text.efi_runtime
#define UNWIND(x...)
/*
* Wrap c macros in asm macros to delay expansion until after the
* SMCCC asm macro is expanded.
*/
.macro SMCCC_SMC
__SMC(0)
.endm
.macro SMCCC_HVC
__HVC(0)
.endm
.macro SMCCC instr
UNWIND( .fnstart)
mov r12, sp
push {r4-r7}
UNWIND( .save {r4-r7})
ldm r12, {r4-r7}
\instr
pop {r4-r7}
ldr r12, [sp, #(4 * 4)]
stm r12, {r0-r3}
bx lr
UNWIND( .fnend)
.endm
/*
* void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
* unsigned long a3, unsigned long a4, unsigned long a5,
* unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
* struct arm_smccc_quirk *quirk)
*/
ENTRY(__arm_smccc_smc)
SMCCC SMCCC_SMC
ENDPROC(__arm_smccc_smc)
/*
* void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
* unsigned long a3, unsigned long a4, unsigned long a5,
* unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
* struct arm_smccc_quirk *quirk)
*/
ENTRY(__arm_smccc_hvc)
SMCCC SMCCC_HVC
ENDPROC(__arm_smccc_hvc)