Skip to content

Commit

Permalink
core: arm64: preserve PSTATE.PAN when making SPSR
Browse files Browse the repository at this point in the history
When setup_unwind_user_mode() prepares to resume execution after
syscall_sys_return() or when a thread is suspended a new SPSR is
fabricated base on the current PSTATE.

Until now when remaining in S-EL1 to fabricate an SPSR only the
PSTATE.DAIF bits had to be taken into account. However, with PSTATE.PAN
there's yet another bit to consider. Since PSTATE has a few more bits
and more may be added as AArch64 evolves this problem is only go to get
worse. So implement this in a single internal C function to replace
current open codes C and assembly versions.

The AArch64 assembly versions of thread_rpc() are renamed to
thread_rpc_spsr() to indicate that SPSR is passed in the second argument
instead of having it open coded internally in the assembly function.

New C wrapper functions are added to preserve the old thread_rpc()
interface as needed.

handle_user_mode_panic() is still basing its created SPSR on the saved
SPSR from S-EL0, but now PAN bit is copied too.

Fixes: 6fa59c9 ("arm64: Introduce permissive PAN implementation")
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
  • Loading branch information
jenswi-linaro committed Jul 20, 2023
1 parent 40d8456 commit f7d0f2e
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 21 deletions.
21 changes: 18 additions & 3 deletions core/arch/arm/include/kernel/thread_private_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,18 @@ void thread_resume_from_rpc(uint32_t thread_id, uint32_t a0, uint32_t a1,
uint32_t a2, uint32_t a3);

/*
* Suspends current thread and temorarily exits to non-secure world.
* This function returns later when non-secure world returns.
* The thread_rpc() function suspends current thread and temporarily exits
* to non-secure world. This function returns later when non-secure world
* returns.
*
* The purpose of this function is to request services from non-secure
* world.
*/
#define THREAD_RPC_NUM_ARGS 4
#ifdef ARM64
void thread_rpc_spsr(uint32_t rv[THREAD_RPC_NUM_ARGS], uint64_t spsr);
void __thread_rpc(uint32_t rv[THREAD_RPC_NUM_ARGS]);

#ifdef CFG_CORE_FFA
struct thread_rpc_arg {
union {
Expand All @@ -216,8 +221,18 @@ struct thread_rpc_arg {
};
};

void thread_rpc(struct thread_rpc_arg *rpc_arg);
static inline void thread_rpc(struct thread_rpc_arg *rpc_arg)
{
__thread_rpc(rpc_arg->pad);
}
#else
static inline void thread_rpc(uint32_t rv[THREAD_RPC_NUM_ARGS])
{
__thread_rpc(rv);
}
#endif
#endif
#ifdef ARM32
void thread_rpc(uint32_t rv[THREAD_RPC_NUM_ARGS]);
#endif

Expand Down
6 changes: 5 additions & 1 deletion core/arch/arm/kernel/abort.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ static void handle_user_mode_panic(struct abort_info *ai)
{
struct thread_ctx *tc __maybe_unused = NULL;
uint32_t daif = 0;
uint32_t pan_bit = 0;

/*
* It was a user exception, stop user execution and return
Expand All @@ -380,9 +381,12 @@ static void handle_user_mode_panic(struct abort_info *ai)
ai->regs->apiakey_lo = tc->keys.apia_lo;
#endif

/* Unless PAN is supported the PAN bit in SPSR is RES0 */
pan_bit = ai->regs->spsr & SPSR_64_PAN;
daif = (ai->regs->spsr >> SPSR_32_AIF_SHIFT) & SPSR_32_AIF_MASK;
/* XXX what about DAIF_D? */
ai->regs->spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, daif);
ai->regs->spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, daif) |
pan_bit;
}
#endif /*ARM64*/

Expand Down
20 changes: 18 additions & 2 deletions core/arch/arm/kernel/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,23 @@ void thread_resume_from_rpc(uint32_t thread_id, uint32_t a0, uint32_t a1,
}

#ifdef ARM64
static uint64_t spsr_from_pstate(void)
{
uint64_t spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, 0);

spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, 0);
spsr |= read_daif();
if (IS_ENABLED(CFG_PAN) && feat_pan_implemented() && read_pan())
spsr |= SPSR_64_PAN;

return spsr;
}

void __thread_rpc(uint32_t rv[THREAD_RPC_NUM_ARGS])
{
thread_rpc_spsr(rv, spsr_from_pstate());
}

vaddr_t thread_get_saved_thread_sp(void)
{
struct thread_core_local *l = thread_get_core_local();
Expand Down Expand Up @@ -1072,8 +1089,7 @@ static void setup_unwind_user_mode(struct thread_scall_regs *regs)
#endif
#ifdef ARM64
regs->elr = (uintptr_t)thread_unwind_user_mode;
regs->spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, 0);
regs->spsr |= read_daif();
regs->spsr = spsr_from_pstate();
/*
* Regs is the value of stack pointer before calling the SVC
* handler. By the addition matches for the reserved space at the
Expand Down
12 changes: 4 additions & 8 deletions core/arch/arm/kernel/thread_optee_smc_a64.S
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,8 @@ FUNC thread_std_smc_entry , :
panic_at_smc_return
END_FUNC thread_std_smc_entry

/* void thread_rpc(uint32_t rv[THREAD_RPC_NUM_ARGS]) */
FUNC thread_rpc , :
/* Read daif and create an SPSR */
mrs x1, daif
orr x1, x1, #(SPSR_64_MODE_EL1 << SPSR_64_MODE_EL_SHIFT)

/* void thread_rpc_spsr(uint32_t rv[THREAD_RPC_NUM_ARGS], uint64_t spsr) */
FUNC thread_rpc_spsr , :
/* Mask all maskable exceptions before switching to temporary stack */
msr daifset, #DAIFBIT_ALL
push x0, xzr
Expand Down Expand Up @@ -236,8 +232,8 @@ FUNC thread_rpc , :
pop x16, xzr /* Get pointer to rv[] */
store_wregs x16, 0, 0, 3 /* Store w0-w3 into rv[] */
ret
END_FUNC thread_rpc
DECLARE_KEEP_PAGER thread_rpc
END_FUNC thread_rpc_spsr
DECLARE_KEEP_PAGER thread_rpc_spsr

/*
* void thread_foreign_intr_exit(uint32_t thread_index)
Expand Down
10 changes: 3 additions & 7 deletions core/arch/arm/kernel/thread_spmc_a64.S
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,8 @@ FUNC spmc_sp_thread_entry , :
END_FUNC spmc_sp_thread_entry
#endif

/* void thread_rpc(struct thread_rpc_arg *rpc_arg) */
FUNC thread_rpc , :
/* Read daif and create an SPSR */
mrs x1, daif
orr x1, x1, #(SPSR_64_MODE_EL1 << SPSR_64_MODE_EL_SHIFT)

/* void thread_rpc_spsr(uint32_t rv[THREAD_RPC_NUM_ARGS], uint64_t spsr) */
FUNC thread_rpc_spsr , :
/* Mask all maskable exceptions before switching to temporary stack */
msr daifset, #DAIFBIT_ALL
push x0, xzr
Expand Down Expand Up @@ -176,7 +172,7 @@ FUNC thread_rpc , :
pop x16, xzr /* Get pointer to rv[] */
store_wregs x16, 0, 0, 3 /* Store w0-w3 into rv[] */
ret
END_FUNC thread_rpc
END_FUNC thread_rpc_spsr

/*
* void thread_foreign_intr_exit(uint32_t thread_index)
Expand Down

0 comments on commit f7d0f2e

Please sign in to comment.