From 6978160427648fba996d681db656676fdfe90562 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 25 Nov 2020 15:54:12 +0100 Subject: [PATCH] aarch64: userspace: Introduce arch_is_user_context The arch_is_user_context() function is relying on the content of the tpidrro_el0 register to determine whether we are in user context or not. This register is set to '1' when in EL1 and set back to '0' when user threads are running in userspace. Signed-off-by: Carlo Caione --- arch/arm/core/aarch64/thread.c | 5 ++++ arch/arm/core/aarch64/vector_table.S | 15 ++++++++++++ arch/arm/core/offsets/offsets_aarch64.c | 3 +++ include/arch/arm/aarch64/exc.h | 3 +++ include/arch/arm/aarch64/syscall.h | 31 +++++++++++++++++++++++-- include/arch/syscall.h | 2 ++ 6 files changed, 57 insertions(+), 2 deletions(-) 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)