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);
|
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);
|
int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
|
||||||
bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
|
bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
|
||||||
|
|
||||||
|
@ -184,6 +184,7 @@ struct thread_struct {
|
|||||||
u64 sctlr_user;
|
u64 sctlr_user;
|
||||||
u64 svcr;
|
u64 svcr;
|
||||||
u64 tpidr2_el0;
|
u64 tpidr2_el0;
|
||||||
|
u64 por_el0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline unsigned int thread_get_vl(struct thread_struct *thread,
|
static inline unsigned int thread_get_vl(struct thread_struct *thread,
|
||||||
|
@ -1077,6 +1077,9 @@
|
|||||||
#define POE_RXW UL(0x7)
|
#define POE_RXW UL(0x7)
|
||||||
#define POE_MASK UL(0xf)
|
#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
|
#define ARM64_FEATURE_FIELD_BITS 4
|
||||||
|
|
||||||
/* Defined for compatibility only, do not add new users. */
|
/* 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);
|
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)
|
void flush_thread(void)
|
||||||
{
|
{
|
||||||
fpsimd_flush_thread();
|
fpsimd_flush_thread();
|
||||||
tls_thread_flush();
|
tls_thread_flush();
|
||||||
flush_ptrace_hw_breakpoint(current);
|
flush_ptrace_hw_breakpoint(current);
|
||||||
flush_tagged_addr_state();
|
flush_tagged_addr_state();
|
||||||
|
flush_poe();
|
||||||
}
|
}
|
||||||
|
|
||||||
void arch_release_task_struct(struct task_struct *tsk)
|
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())
|
if (system_supports_tpidr2())
|
||||||
p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
|
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 (stack_start) {
|
||||||
if (is_compat_thread(task_thread_info(p)))
|
if (is_compat_thread(task_thread_info(p)))
|
||||||
childregs->compat_sp = stack_start;
|
childregs->compat_sp = stack_start;
|
||||||
@ -495,6 +507,17 @@ static void erratum_1418040_new_exec(void)
|
|||||||
preempt_enable();
|
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
|
* __switch_to() checks current->thread.sctlr_user as an optimisation. Therefore
|
||||||
* this function must be called with preemption disabled and the update to
|
* 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);
|
ssbs_thread_switch(next);
|
||||||
erratum_1418040_thread_switch(next);
|
erratum_1418040_thread_switch(next);
|
||||||
ptrauth_thread_switch_user(next);
|
ptrauth_thread_switch_user(next);
|
||||||
|
permission_overlay_switch(next);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Complete any pending TLB or cache maintenance on this CPU in case
|
* Complete any pending TLB or cache maintenance on this CPU in case
|
||||||
|
Loading…
Reference in New Issue
Block a user