如何以及何时执行带有 LINUX_REBOOT_CMD_RESTART2 的 restart() 命令字符串 arg?

如何以及何时执行带有 LINUX_REBOOT_CMD_RESTART2 的 restart() 命令字符串 arg?

restart() 的联机帮助页

LINUX_REBOOT_CMD_RESTART2

(0xa1b2c3d4;自 Linux 2.1.30 起)。打印消息“Restarting system with command '%s'”,并立即执行重新启动(使用 arg 中给出的命令字符串)。如果前面没有同步(2),数据将会丢失。

在关机过程中,arg 中给出的命令字符串到底是如何以及何时执行的?

https://unix.stackexchange.com/a/489651/674说关于LINUX_REBOOT_CMD_RESTART2

这里的一个额外的混乱是由于reboot() 系统调用似乎能够运行一个进程来进行重新启动(但是这是有效的)

arg 中给出的命令字符串是在内核关闭之前运行的,那么该命令可以在内核关闭之前进行一些清理吗?

谢谢。

答案1

该命令是不是在关闭过程中执行。它不是 shell 命令或类似命令;它是一个字符串,应该作为回调数据(通过machine_restart()=> )传递给由某些驱动程序(看门狗等)do_kernel_restart()注册的重新启动处理程序。register_restart_handler()

但 x86 上并未使用该机制;那里的“命令”被完全忽略。从arch/x86/kernel/reboot.c:

void machine_restart(char *cmd)
{
        machine_ops.restart(cmd);

struct machine_ops machine_ops __ro_after_init = {
        ...
        .restart = native_machine_restart,

static void native_machine_restart(char *__unused)
{

该字符串也将传递给注册的处理程序register_reboot_notifier()。唯一(滥用)使用的驱动程序似乎是EFI 引导加载程序控制这是设置非挥发性LoaderEntryOneShot来自它的 EFI 变量,导致一些引导加载程序确定接下来应该引导哪个操作系统。我认为该驱动程序从未在 Android 之外使用过——但无论如何它看起来都很笨重,因为它在旧的 lkml 中也有详细介绍讨论关于同一件事的先前版本。

答案2

它没有被执行。该命令具有相应的数值,该数值被传递到重新启动模式驱动程序以写入重新启动原因寄存器。重新启动后,引导加载程序从寄存器中读取原因值,并根据所选命令决定启动,例如快速启动、恢复等。

例如,基于 Qualcomm MSM8916 SOC 的手机具有 Power On 设备,其中包含这样的重启原因寄存器。命令(以 形式mode-<command>)和相应的原因值在其中描述设备树:

pon@800 {
        compatible = "qcom,pm8916-pon";
        reg = <0x800>;
        mode-bootloader = <0x2>;
        mode-recovery = <0x1>;

因此,当reboot(2)使用bootloader命令字符串调用时,司机对于开机设备写入0x2重新启动原因寄存器。

下次启动时,引导加载程序(例如 lk2nd)会检查原因寄存器并启动到适当的模式(从aboot_init()inaboot.c):

#if USE_PON_REBOOT_REG
    reboot_mode = check_hard_reboot_mode();
#else
    reboot_mode = check_reboot_mode();
#endif
    if (reboot_mode == RECOVERY_MODE)
    {
        boot_into_recovery = 1;
    }
    else if(reboot_mode == FASTBOOT_MODE)
    {
        boot_into_fastboot = true;
    }

RECOVERY_MODEFASTBOOT_MODE在 lk2nd 中定义重新启动.h并具有与上面设备树中相同的值(除了“fastboot”被称为“bootloader”):

#define RECOVERY_MODE     0x01
#define FASTBOOT_MODE     0x02

我不知道可以使用命令重新启动来测试此行为的实用程序,但您可以使用 ctypes 在 python 中执行此操作:

python -c "import ctypes; ctypes.CDLL('libc.so').syscall(142, 0xfee1dead, 0x20112000, 0xa1b2c3d4, b'bootloader')"

142上面是reboot(2)arm64上的系统调用号。十六进制魔法数字来自man 2 reboot.

相关内容