Linux支持运行32位应用程序,只要
CONFIG_COMPAT
我假设32位应用程序必须在arm AArch32执行状态下运行,并且该环境具有32位应用程序和64位应用程序。
32位应用程序过程->手臂状态为AArch32
64位应用程序进程和内核-> arm状态为AArch64
正确吗?
如果是这样,Linux如何处理AArch32和AArch64开关?内核知道运行的进程是32位还是64位吗?
[如果您当前正在运行32位应用程序之一,并且遇到异常(例如IRQ,系统调用中的SVC,由于页面错误而中止...。),请输入64位OS。所以是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线程有更多详细信息。或者在https://medium.com/@om.nara/aarch64-exception-levels-60d3a74280e6中的“在AArch32和AArch64之间移动”中有更简单的解释]在发生异常时,如果异常级别更改,则执行状态可以:保持不变,或从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-states或https://www.realworldtech.com/arm64/2/中相同:
AArch64异常模型
特权级别:EL3-最高,EL0-最低
- 通过异常过渡到更高级别
寄存器宽度不能在较低的级别中更大
- 例如没有带有32位EL1的64位EL0
通过异常在AArch32和AArch64之间进行转换
- 无法与AArch32 / AArch64互通
现在回答您的问题:
Linux如何处理AArch32和AArch64开关?
通过使用具有不同PSTATE值的EL0 / EL1开关使用异常处理(和返回)的硬件功能。内核是否知道正在运行的进程是32位还是64位?
是,在64位内核(compat syscalls)上有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.h和arch/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);