mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-22 18:09:03 +09:00
![Heinrich Schuchardt](/assets/img/avatar_default.png)
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>
116 lines
2.2 KiB
C
116 lines
2.2 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/**
|
|
* (C) Copyright 2014, Cavium Inc.
|
|
* (C) Copyright 2017, Xilinx Inc.
|
|
*
|
|
**/
|
|
|
|
#include <asm-offsets.h>
|
|
#include <config.h>
|
|
#include <version.h>
|
|
#include <asm/macro.h>
|
|
#include <asm/psci.h>
|
|
#include <asm/system.h>
|
|
|
|
/*
|
|
* Issue the hypervisor call
|
|
*
|
|
* x0~x7: input arguments
|
|
* x0~x3: output arguments
|
|
*/
|
|
static void hvc_call(struct pt_regs *args)
|
|
{
|
|
asm volatile(
|
|
"ldr x0, %0\n"
|
|
"ldr x1, %1\n"
|
|
"ldr x2, %2\n"
|
|
"ldr x3, %3\n"
|
|
"ldr x4, %4\n"
|
|
"ldr x5, %5\n"
|
|
"ldr x6, %6\n"
|
|
"ldr x7, %7\n"
|
|
"hvc #0\n"
|
|
"str x0, %0\n"
|
|
"str x1, %1\n"
|
|
"str x2, %2\n"
|
|
"str x3, %3\n"
|
|
: "+m" (args->regs[0]), "+m" (args->regs[1]),
|
|
"+m" (args->regs[2]), "+m" (args->regs[3])
|
|
: "m" (args->regs[4]), "m" (args->regs[5]),
|
|
"m" (args->regs[6]), "m" (args->regs[7])
|
|
: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
|
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
|
"x16", "x17");
|
|
}
|
|
|
|
/*
|
|
* void smc_call(arg0, arg1...arg7)
|
|
*
|
|
* issue the secure monitor call
|
|
*
|
|
* x0~x7: input arguments
|
|
* x0~x3: output arguments
|
|
*/
|
|
|
|
void smc_call(struct pt_regs *args)
|
|
{
|
|
asm volatile(
|
|
"ldr x0, %0\n"
|
|
"ldr x1, %1\n"
|
|
"ldr x2, %2\n"
|
|
"ldr x3, %3\n"
|
|
"ldr x4, %4\n"
|
|
"ldr x5, %5\n"
|
|
"ldr x6, %6\n"
|
|
"smc #0\n"
|
|
"str x0, %0\n"
|
|
"str x1, %1\n"
|
|
"str x2, %2\n"
|
|
"str x3, %3\n"
|
|
: "+m" (args->regs[0]), "+m" (args->regs[1]),
|
|
"+m" (args->regs[2]), "+m" (args->regs[3])
|
|
: "m" (args->regs[4]), "m" (args->regs[5]),
|
|
"m" (args->regs[6])
|
|
: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
|
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
|
"x16", "x17");
|
|
}
|
|
|
|
/*
|
|
* For now, all systems we support run at least in EL2 and thus
|
|
* trigger PSCI calls to EL3 using SMC. If anyone ever wants to
|
|
* use PSCI on U-Boot running below a hypervisor, please detect
|
|
* this and set the flag accordingly.
|
|
*/
|
|
static const bool use_smc_for_psci = true;
|
|
|
|
void __noreturn psci_system_reset(void)
|
|
{
|
|
struct pt_regs regs;
|
|
|
|
regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET;
|
|
|
|
if (use_smc_for_psci)
|
|
smc_call(®s);
|
|
else
|
|
hvc_call(®s);
|
|
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
void __noreturn psci_system_off(void)
|
|
{
|
|
struct pt_regs regs;
|
|
|
|
regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_OFF;
|
|
|
|
if (use_smc_for_psci)
|
|
smc_call(®s);
|
|
else
|
|
hvc_call(®s);
|
|
|
|
while (1)
|
|
;
|
|
}
|