mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
arm64: context switch POR_EL0 register
POR_EL0 is a register that can be modified by userspace directly, so it must be context switched. Signed-off-by: Joey Gouly <joey.gouly@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Link: https://lore.kernel.org/r/20240822151113.1479789-7-joey.gouly@arm.com [will: Dropped unnecessary isb()s] Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
3496f69391
commit
160a8e13de
@ -832,6 +832,12 @@ static inline bool system_supports_lpa2(void)
|
||||
return cpus_have_final_cap(ARM64_HAS_LPA2);
|
||||
}
|
||||
|
||||
static inline bool system_supports_poe(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_ARM64_POE) &&
|
||||
alternative_has_cap_unlikely(ARM64_HAS_S1POE);
|
||||
}
|
||||
|
||||
int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
|
||||
bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
|
||||
|
||||
|
@ -184,6 +184,7 @@ struct thread_struct {
|
||||
u64 sctlr_user;
|
||||
u64 svcr;
|
||||
u64 tpidr2_el0;
|
||||
u64 por_el0;
|
||||
};
|
||||
|
||||
static inline unsigned int thread_get_vl(struct thread_struct *thread,
|
||||
|
@ -1077,6 +1077,9 @@
|
||||
#define POE_RXW UL(0x7)
|
||||
#define POE_MASK UL(0xf)
|
||||
|
||||
/* Initial value for Permission Overlay Extension for EL0 */
|
||||
#define POR_EL0_INIT POE_RXW
|
||||
|
||||
#define ARM64_FEATURE_FIELD_BITS 4
|
||||
|
||||
/* Defined for compatibility only, do not add new users. */
|
||||
|
@ -271,12 +271,21 @@ static void flush_tagged_addr_state(void)
|
||||
clear_thread_flag(TIF_TAGGED_ADDR);
|
||||
}
|
||||
|
||||
static void flush_poe(void)
|
||||
{
|
||||
if (!system_supports_poe())
|
||||
return;
|
||||
|
||||
write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
|
||||
}
|
||||
|
||||
void flush_thread(void)
|
||||
{
|
||||
fpsimd_flush_thread();
|
||||
tls_thread_flush();
|
||||
flush_ptrace_hw_breakpoint(current);
|
||||
flush_tagged_addr_state();
|
||||
flush_poe();
|
||||
}
|
||||
|
||||
void arch_release_task_struct(struct task_struct *tsk)
|
||||
@ -371,6 +380,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
||||
if (system_supports_tpidr2())
|
||||
p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
|
||||
|
||||
if (system_supports_poe())
|
||||
p->thread.por_el0 = read_sysreg_s(SYS_POR_EL0);
|
||||
|
||||
if (stack_start) {
|
||||
if (is_compat_thread(task_thread_info(p)))
|
||||
childregs->compat_sp = stack_start;
|
||||
@ -495,6 +507,17 @@ static void erratum_1418040_new_exec(void)
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static void permission_overlay_switch(struct task_struct *next)
|
||||
{
|
||||
if (!system_supports_poe())
|
||||
return;
|
||||
|
||||
current->thread.por_el0 = read_sysreg_s(SYS_POR_EL0);
|
||||
if (current->thread.por_el0 != next->thread.por_el0) {
|
||||
write_sysreg_s(next->thread.por_el0, SYS_POR_EL0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __switch_to() checks current->thread.sctlr_user as an optimisation. Therefore
|
||||
* this function must be called with preemption disabled and the update to
|
||||
@ -530,6 +553,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
||||
ssbs_thread_switch(next);
|
||||
erratum_1418040_thread_switch(next);
|
||||
ptrauth_thread_switch_user(next);
|
||||
permission_overlay_switch(next);
|
||||
|
||||
/*
|
||||
* Complete any pending TLB or cache maintenance on this CPU in case
|
||||
|
Loading…
Reference in New Issue
Block a user