首页 > 解决方案 > Linux arm64 如何在 AArch32 和 AArch64 之间切换

问题描述

Linux 支持运行 32 位应用程序,只要

  1. 内核启用CONFIG_COMPAT
  2. 硬件支持 AArch32

我假设 32 位应用程序必须在 arm AArch32 执行状态下运行,并且如果环境有 32 位应用程序和 64 位应用程序。

32位应用进程->arm状态为AArch32

64 位应用程序进程和内核 -> arm 状态为 AArch64

这是对的吗?

如果是这样,
Linux 如何处理 AArch32 和 AArch64 切换?
内核是否知道正在运行的进程是 32 位还是 64 位?

标签: linuxlinux-kernelarmembedded-linux

解决方案


链接https://community.arm.com/developer/ip-products/processors/f/cortex-a-forum/6706/in-aarch32-state-what-is-the-mechanism-to-switch-to- 0andriy内核开发人员)在评论中发布的aarch64-in-software解释了Martin Weidmann在 AArch32 用户空间进程和 AArch64 linux 内核之间的切换。32->64模式切换在异常情况下完成;并且 64->32 切换在异常返回时完成。

如果您当前正在运行其中一个 32 位应用程序并且您遇到异常(例如 IRQ、来自系统调用的 SVC、因页面错误而中止......)您进入 64 位操作系统。所以一个 AArch32 --> AArch64 转换。当操作系统执行异常返回到应用程序时,这是一个 AArch64-->AArch32 转换。... AArch32 状态中的任何异常类型都可能导致执行状态更改为 AArch64。...对于异常返回,反之亦然。AArch64 中的异常返回可能会导致执行状态更改为 AArch32。
对于异常和异常返回,只有在 EL 也发生变化时才会发生执行状态的变化。这是从 EL0 到 EL1 的异常可能导致执行状态的变化。但是从 EL1 到 EL1 的例外不能。

https://community.arm.com/developer/ip-products/processors/f/cortex-a-forum/6706/in-aarch32-state-what-is-the-mechanism-to-switch-to-aarch64 _ -in-software线程有更多细节。或者在“在 AArch32 和 AArch64 之间移动”中的https://medium.com/@om.nara/aarch64-exception-levels-60d3a74280e6中有更简单的解释

在发生异常时,如果异常级别发生变化,则执行状态可以:保持不变,或从 AArch32 更改为 AArch64。

从异常返回时,如果异常级别发生更改,则执行状态可以:保持不变,或从 AArch64 更改为 AArch32。

https://events.static.linuxfound.org/images/stories/pdf/lcna_co2012_marinas.pdf演示文稿(幻灯片 5)或https://developer.arm.com/architectures/learn-the-architecture/exception-中相同model/execution-and-security-stateshttps://www.realworldtech.com/arm64/2/

AArch64 异常模型

  • 特权等级:EL3 – 最高,EL0 – 最低
  • 通过异常过渡到更高级别

  • 较低级别的寄存器宽度不能更高

    • 例如,没有 64 位 EL0 和 32 位 EL1
  • 通过异常在 AArch32 和 AArch64 之间转换
    • AArch32/AArch64 互通不可能

现在为您的问题:

Linux 如何处理 AArch32 和 AArch64 开关?

通过使用具有不同 PSTATE 值的 EL0/EL1 开关的异常处理(和返回)的硬件能力。

内核是否知道正在运行的进程是 32 位还是 64 位?

是的,在 64 位内核(兼容系统调用)上检查 32 位进程(“任务”)的内核:arch/arm64/kernel/syscall.c

static long do_ni_syscall(struct pt_regs *regs, int scno)
{
#ifdef CONFIG_COMPAT
    long ret;
    if (is_compat_task()) {
        ret = compat_arm_syscall(regs, scno);
        if (ret != -ENOSYS)
            return ret;
    }
#endif

    return sys_ni_syscall();
}

测试在include/asm/compat.harch/arm64/include/asm/thread_info.h中定义为

#define TIF_32BIT       22  /* 32bit process */
static inline int is_compat_task(void)
{
    return test_thread_flag(TIF_32BIT);
}

TIF_32BIT 由 fs/compat_binfmt_elf.c 中的 32 位 elf 加载设置,带有几个个性宏:

https://elixir.bootlin.com/linux/v4.19.107/source/arch/arm64/include/asm/elf.h#L208

/*
 * Unlike the native SET_PERSONALITY macro, the compat version maintains
 * READ_IMPLIES_EXEC across an execve() since this is the behaviour on
 * arch/arm/.
 */
#define COMPAT_SET_PERSONALITY(ex)                  \
({                                  \
    set_thread_flag(TIF_32BIT);                 \
 })

https://elixir.bootlin.com/linux/v4.19.107/source/fs/compat_binfmt_elf.c#L104

 #define    SET_PERSONALITY     COMPAT_SET_PERSONALITY

https://elixir.bootlin.com/linux/v4.19.107/source/fs/binfmt_elf.c#L690

#define SET_PERSONALITY2(ex, state) \
    SET_PERSONALITY(ex)
 static int load_elf_binary(struct linux_binprm *bprm)
    SET_PERSONALITY2(loc->elf_ex, &arch_state);

推荐阅读