While current_mode() == USR_MODE works on armv7 from PL0 to check if we're in user mode, current_mode() would require reading a privileged register on armv8. To work around this, on arm64 we introduced a 'user_mode' variable. This variable needs to be per thread now. Rather than starting to pollute thread_info with a bunch of bools, create a flags field and a TIF_USER_MODE flag to replace it. Use it on armv7 too for consistency. Also, now that we need to create a thread_info initializer, add mpidr utilities for setting thread_info->cpu. Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx> --- arm/cstart64.S | 16 +--------------- arm/selftest.c | 2 +- lib/arm/asm/processor.h | 11 +++++++++++ lib/arm/asm/thread_info.h | 13 +++++++++++-- lib/arm/processor.c | 14 ++++++++++++++ lib/arm/setup.c | 3 +++ lib/arm64/asm/processor.h | 14 +++++++++++++- lib/arm64/processor.c | 15 +++++++++++++-- 8 files changed, 67 insertions(+), 21 deletions(-) diff --git a/arm/cstart64.S b/arm/cstart64.S index 2fe15eb1d3972..58e4040cfb40f 100644 --- a/arm/cstart64.S +++ b/arm/cstart64.S @@ -156,13 +156,7 @@ asm_mmu_enable: mrs x2, spsr_el1 stp x1, x2, [sp, #S_PC] - and x2, x2, #PSR_MODE_MASK - cmp x2, #PSR_MODE_EL0t - b.ne 1f - adr x2, user_mode - str xzr, [x2] /* we're in kernel mode now */ - -1: mov x0, \vec + mov x0, \vec mov x1, sp mrs x2, esr_el1 bl do_handle_exception @@ -171,14 +165,6 @@ asm_mmu_enable: msr spsr_el1, x2 msr elr_el1, x1 - and x2, x2, #PSR_MODE_MASK - cmp x2, #PSR_MODE_EL0t - b.ne 1f - adr x2, user_mode - mov x1, #1 - str x1, [x2] /* we're going back to user mode */ - -1: .if \vec >= 8 ldr x1, [sp, #S_SP] msr sp_el0, x1 diff --git a/arm/selftest.c b/arm/selftest.c index 05ca7efe95f83..d77495747b08a 100644 --- a/arm/selftest.c +++ b/arm/selftest.c @@ -240,7 +240,7 @@ static enum vector check_vector_prep(void) { unsigned long daif; - if (user_mode) + if (is_user()) return EL0_SYNC_64; asm volatile("mrs %0, daif" : "=r" (daif) ::); diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h index 9c37db66640e8..f25e7eee3666c 100644 --- a/lib/arm/asm/processor.h +++ b/lib/arm/asm/processor.h @@ -33,6 +33,17 @@ static inline unsigned long current_cpsr(void) #define current_mode() (current_cpsr() & MODE_MASK) +static inline unsigned int get_mpidr(void) +{ + unsigned int mpidr; + asm volatile("mrc p15, 0, %0, c0, c0, 5" : "=r" (mpidr)); + return mpidr; +} + +/* Only support Aff0 for now, up to 4 cpus */ +#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff)) + extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr); +extern bool is_user(void); #endif /* _ASMARM_PROCESSOR_H_ */ diff --git a/lib/arm/asm/thread_info.h b/lib/arm/asm/thread_info.h index ea86f142a7d93..17997e21d1274 100644 --- a/lib/arm/asm/thread_info.h +++ b/lib/arm/asm/thread_info.h @@ -11,17 +11,26 @@ #define THREAD_SIZE 16384 #define THREAD_START_SP (THREAD_SIZE - 16) +#define TIF_USER_MODE (1U << 0) + struct thread_info { int cpu; + unsigned int flags; char ext[0]; /* allow unit tests to add extended info */ }; +static inline struct thread_info *thread_info_sp(unsigned long sp) +{ + return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); +} + register unsigned long current_stack_pointer asm("sp"); static inline struct thread_info *current_thread_info(void) { - return (struct thread_info *) - (current_stack_pointer & ~(THREAD_SIZE - 1)); + return thread_info_sp(current_stack_pointer); } +extern void thread_info_init(struct thread_info *ti, unsigned int flags); + #endif /* _ASMARM_THREAD_INFO_H_ */ diff --git a/lib/arm/processor.c b/lib/arm/processor.c index d2fd597fcd139..8a514a29c063b 100644 --- a/lib/arm/processor.c +++ b/lib/arm/processor.c @@ -100,10 +100,19 @@ void do_handle_exception(enum vector v, struct pt_regs *regs) abort(); } +void thread_info_init(struct thread_info *ti, unsigned int flags) +{ + memset(ti, 0, sizeof(struct thread_info)); + ti->cpu = mpidr_to_cpu(get_mpidr()); + ti->flags = flags; +} + void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) { sp_usr &= (~7UL); /* stack ptr needs 8-byte alignment */ + thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE); + asm volatile( "mrs r0, cpsr\n" "bic r0, #" xstr(MODE_MASK) "\n" @@ -115,3 +124,8 @@ void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) "mov pc, %2\n" :: "r" (arg), "r" (sp_usr), "r" (func) : "r0"); } + +bool is_user(void) +{ + return current_thread_info()->flags & TIF_USER_MODE; +} diff --git a/lib/arm/setup.c b/lib/arm/setup.c index 8f58802e958ac..b30c8696f6539 100644 --- a/lib/arm/setup.c +++ b/lib/arm/setup.c @@ -14,6 +14,7 @@ #include <libfdt/libfdt.h> #include <devicetree.h> #include <alloc.h> +#include <asm/thread_info.h> #include <asm/setup.h> #include <asm/page.h> #include <asm/mmu.h> @@ -79,6 +80,8 @@ void setup(const void *fdt) io_init(); cpu_init(); + thread_info_init(current_thread_info(), 0); + assert(dt_get_bootargs(&bootargs) == 0); setup_args(bootargs); } diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h index d287f55b8dac6..c1326351d201f 100644 --- a/lib/arm64/asm/processor.h +++ b/lib/arm64/asm/processor.h @@ -60,8 +60,20 @@ static inline unsigned long current_level(void) return el & 0xc; } -extern bool user_mode; +#define DEFINE_GET_SYSREG32(reg) \ +static inline unsigned int get_##reg(void) \ +{ \ + unsigned int reg; \ + asm volatile("mrs %0, " #reg "_el1" : "=r" (reg)); \ + return reg; \ +} +DEFINE_GET_SYSREG32(mpidr) + +/* Only support Aff0 for now, gicv2 only */ +#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff)) + extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr); +extern bool is_user(void); #endif /* !__ASSEMBLY__ */ #endif /* _ASMARM64_PROCESSOR_H_ */ diff --git a/lib/arm64/processor.c b/lib/arm64/processor.c index 7f61b3fff281f..152767eecf062 100644 --- a/lib/arm64/processor.c +++ b/lib/arm64/processor.c @@ -168,12 +168,18 @@ void install_vector_handler(enum vector v, vector_fn fn) vector_handlers[v] = fn; } -bool user_mode; +void thread_info_init(struct thread_info *ti, unsigned int flags) +{ + memset(ti, 0, sizeof(struct thread_info)); + ti->cpu = mpidr_to_cpu(get_mpidr()); + ti->flags = flags; +} + void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) { sp_usr &= (~15UL); /* stack ptr needs 16-byte alignment */ - user_mode = true; + thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE); asm volatile( "mov x0, %0\n" @@ -184,3 +190,8 @@ void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) "eret\n" :: "r" (arg), "r" (sp_usr), "r" (func) : "x0", "x3"); } + +bool is_user(void) +{ + return current_thread_info()->flags & TIF_USER_MODE; +} -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html