Commit f6d10793 authored by Andrew Jones's avatar Andrew Jones Committed by Marcelo Tosatti
Browse files

arm/arm64: add per thread user_mode flag



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's avatarAndrew Jones <drjones@redhat.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent 1693644d
......@@ -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;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment