diff --git a/arch/arm/core/aarch64/thread.c b/arch/arm/core/aarch64/thread.c index c9977d0b497..37576bf79a0 100644 --- a/arch/arm/core/aarch64/thread.c +++ b/arch/arm/core/aarch64/thread.c @@ -52,6 +52,8 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, } else { pInitCtx->elr = (uint64_t)z_thread_entry; } + + pInitCtx->tpidrro_el0 = 0x0; #else pInitCtx->elr = (uint64_t)z_thread_entry; #endif @@ -95,6 +97,9 @@ FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, pInitCtx->spsr = DAIF_FIQ_BIT | SPSR_MODE_EL0T; pInitCtx->elr = (uint64_t)z_thread_entry; + /* The thread will be in user context */ + pInitCtx->tpidrro_el0 = 0x1; + pInitCtx->x0 = (uint64_t)user_entry; pInitCtx->x1 = (uint64_t)p1; pInitCtx->x2 = (uint64_t)p2; diff --git a/arch/arm/core/aarch64/vector_table.S b/arch/arm/core/aarch64/vector_table.S index 3443246571d..ec5e8959321 100644 --- a/arch/arm/core/aarch64/vector_table.S +++ b/arch/arm/core/aarch64/vector_table.S @@ -55,6 +55,15 @@ _ASM_FILE_PROLOGUE mrs \xreg1, elr_el1 stp \xreg0, \xreg1, [sp, ___esf_t_spsr_elr_OFFSET] +#ifdef CONFIG_USERSPACE + /* Save the current kernel/user mode in the context */ + mrs \xreg0, tpidrro_el0 + str \xreg0, [sp, ___esf_t_tpidrro_el0_OFFSET] + + /* Switch TPIDRRO_EL0 to kernel mode */ + msr tpidrro_el0, xzr +#endif + .endm /* @@ -201,6 +210,12 @@ SECTION_FUNC(TEXT, z_arm64_exit_exc) msr spsr_el1, x0 msr elr_el1, x1 +#ifdef CONFIG_USERSPACE + /* Restore the kernel/user mode flag */ + ldr x0, [sp, ___esf_t_tpidrro_el0_OFFSET] + msr tpidrro_el0, x0 +#endif + ldp x0, x1, [sp, ___esf_t_x0_x1_OFFSET] ldp x2, x3, [sp, ___esf_t_x2_x3_OFFSET] ldp x4, x5, [sp, ___esf_t_x4_x5_OFFSET] diff --git a/arch/arm/core/offsets/offsets_aarch64.c b/arch/arm/core/offsets/offsets_aarch64.c index 3de9c04d9ae..fc986be4949 100644 --- a/arch/arm/core/offsets/offsets_aarch64.c +++ b/arch/arm/core/offsets/offsets_aarch64.c @@ -39,6 +39,9 @@ GEN_NAMED_OFFSET_SYM(_callee_saved_t, x29, x29_sp); GEN_ABSOLUTE_SYM(___callee_saved_t_SIZEOF, sizeof(struct _callee_saved)); GEN_NAMED_OFFSET_SYM(_esf_t, spsr, spsr_elr); +#ifdef CONFIG_USERSPACE +GEN_NAMED_OFFSET_SYM(_esf_t, tpidrro_el0, tpidrro_el0); +#endif GEN_NAMED_OFFSET_SYM(_esf_t, x18, x18_x30); GEN_NAMED_OFFSET_SYM(_esf_t, x16, x16_x17); GEN_NAMED_OFFSET_SYM(_esf_t, x14, x14_x15); diff --git a/include/arch/arm/aarch64/exc.h b/include/arch/arm/aarch64/exc.h index ea8a244d062..04e504049c2 100644 --- a/include/arch/arm/aarch64/exc.h +++ b/include/arch/arm/aarch64/exc.h @@ -47,6 +47,9 @@ struct __esf { uint64_t x30; uint64_t spsr; uint64_t elr; +#ifdef CONFIG_USERSPACE + uint64_t tpidrro_el0; +#endif }; typedef struct __esf z_arch_esf_t; diff --git a/include/arch/arm/aarch64/syscall.h b/include/arch/arm/aarch64/syscall.h index a7cc517165b..784fda80b40 100644 --- a/include/arch/arm/aarch64/syscall.h +++ b/include/arch/arm/aarch64/syscall.h @@ -6,9 +6,9 @@ /** * @file - * @brief ARM specific syscall header + * @brief ARM64 specific syscall header * - * This header contains the ARM specific syscall interface. It is + * This header contains the ARM64 specific syscall interface. It is * included by the syscall interface architecture-abstraction header * (include/arch/aarch64/syscall.h) */ @@ -20,4 +20,31 @@ #define _SVC_CALL_IRQ_OFFLOAD 1 #define _SVC_CALL_RUNTIME_EXCEPT 2 +#ifdef CONFIG_USERSPACE +#ifndef _ASMLANGUAGE + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline bool arch_is_user_context(void) +{ + uint64_t tpidrro_el0; + + __asm__ volatile("mrs %0, tpidrro_el0" : "=r" (tpidrro_el0)); + + return (tpidrro_el0 != 0x0); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ +#endif /* CONFIG_USERSPACE */ + #endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH64_SYSCALL_H_ */ diff --git a/include/arch/syscall.h b/include/arch/syscall.h index 584a41b7035..e93e011244e 100644 --- a/include/arch/syscall.h +++ b/include/arch/syscall.h @@ -15,6 +15,8 @@ #else #include #endif +#elif defined(CONFIG_ARM64) +#include #elif defined(CONFIG_ARM) #include #elif defined(CONFIG_ARC)