问题
Linux supports running 32-bit application, as long as
- kernel enables
CONFIG_COMPAT
- the hardware supports the AArch32
I assume that 32-bit application must run in arm AArch32 execution state and if the environment has 32-bit application and 64-bit application.
32-bit application process -> arm state is AArch32
64-bit application process and kernel -> arm state is AArch64
Is it correct?
If so,
how does the Linux handle the AArch32 and AArch64 switch?
Does the kernel know the running process is 32-bit or 64-bit?
回答1:
The link 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 posted in comments by 0andriy (kernel developer) has explanation of switching between AArch32 user-space process and AArch64 linux kernel by Martin Weidmann. The 32->64 mode switch is done at exceptions; and 64->32 switch is done at exception return.
If you are currently running one of the 32-bit apps and you take an exception (e.g. IRQ, SVC from a system call, abort from a page fault,....) you enter the 64-bit OS. So a AArch32 --> AArch64 transition. When the OS performs an exception return back into the app, that's an AArch64-->AArch32 transition. ... Any exception type in AArch32 state could potentially lead to Execution state changing to AArch64. ... For exceptions returns the reverse is true. An exception return in AArch64 might cause execution state to change to AArch32.
For both exceptions and exception returns, a change of Execution state can only occur if there is also a change in EL. That is an exception from EL0 to EL1 could lead to a change in Execution state. But an exception from EL1 to EL1 could not.
The 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 thread has some more details. Or there is much simpler explanation in https://medium.com/@om.nara/aarch64-exception-levels-60d3a74280e6 in "Moving between AArch32 and AArch64"
On taking an exception, if the Exception level changes, the Execution state can: Remain unchanged, OR Change from AArch32 to AArch64.
On returning from an exception, if the Exception level changes, the Execution state can: Remain unchanged, OR Change from AArch64 to AArch32.
Same in https://events.static.linuxfound.org/images/stories/pdf/lcna_co2012_marinas.pdf presentation (slide 5) or in https://developer.arm.com/architectures/learn-the-architecture/exception-model/execution-and-security-states or in https://www.realworldtech.com/arm64/2/:
AArch64 Exception Model
- Privilege levels: EL3 – highest, EL0 – lowest
Transition to higher levels via exceptions
Register width cannot be higher in lower levels
- E.g. no 64-bit EL0 with 32-bit EL1
- Transition between AArch32 and AArch64 via exceptions
- AArch32/AArch64 interworking not possible
Now for your questions:
how does the Linux handle the AArch32 and AArch64 switch?
By using hardware capability of exception handling (and return) with EL0/EL1 switch with different PSTATE values.
Does the kernel know the running process is 32-bit or 64-bit?
Yes, there is the check in kernel for 32-bit processes ("tasks") on 64-bit kernels (compat syscalls): 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();
}
Test is defined in include/asm/compat.h and arch/arm64/include/asm/thread_info.h as
#define TIF_32BIT 22 /* 32bit process */
static inline int is_compat_task(void)
{
return test_thread_flag(TIF_32BIT);
}
TIF_32BIT is set by in fs/compat_binfmt_elf.c on 32-bit elf loading with several personality macro:
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);
来源:https://stackoverflow.com/questions/60220759/how-linux-arm64-switch-between-aarch32-and-aarch64