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 <ccaione@baylibre.com>
This commit is contained in:
Carlo Caione 2020-11-25 15:54:12 +01:00 committed by Anas Nashif
commit 6978160427
6 changed files with 57 additions and 2 deletions

View file

@ -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;

View file

@ -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]

View file

@ -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);

View file

@ -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;

View file

@ -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 <zephyr/types.h>
#include <stdbool.h>
#include <arch/arm/aarch64/cpu.h>
#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_ */

View file

@ -15,6 +15,8 @@
#else
#include <arch/x86/ia32/syscall.h>
#endif
#elif defined(CONFIG_ARM64)
#include <arch/arm/aarch64/syscall.h>
#elif defined(CONFIG_ARM)
#include <arch/arm/aarch32/syscall.h>
#elif defined(CONFIG_ARC)