@@ -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
@@ -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) ::);
@@ -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_ */
@@ -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_ */
@@ -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;
+}
@@ -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);
}
@@ -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_ */
@@ -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;
+}
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@redhat.com> --- 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(-)