Skip to content

Commit

Permalink
arm64: efi: Avoid workqueue to check whether EFI runtime is live
Browse files Browse the repository at this point in the history
Comparing current_work() against efi_rts_work.work is sufficient to
decide whether current is currently running EFI runtime services code at
any level in its call stack.

However, there are other potential users of the EFI runtime stack, such
as the ACPI subsystem, which may invoke efi_call_virt_pointer()
directly, and so any sync exceptions occurring in firmware during those
calls are currently misidentified.

So instead, let's check whether the stashed value of the thread stack
pointer points into current's thread stack. This can only be the case if
current was interrupted while running EFI runtime code. Note that this
implies that we should clear the stashed value after switching back, to
avoid false positives.

Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
  • Loading branch information
Ard Biesheuvel committed Jan 16, 2023
1 parent d3f4505 commit 8a9a1a1
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 1 deletion.
9 changes: 9 additions & 0 deletions arch/arm64/include/asm/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,17 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
})

extern spinlock_t efi_rt_lock;
extern u64 *efi_rt_stack_top;
efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);

/*
* efi_rt_stack_top[-1] contains the value the stack pointer had before
* switching to the EFI runtime stack.
*/
#define current_in_efi() \
(!preemptible() && efi_rt_stack_top != NULL && \
on_task_stack(current, READ_ONCE(efi_rt_stack_top[-1]), 1))

#define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)

/*
Expand Down
6 changes: 6 additions & 0 deletions arch/arm64/kernel/efi-rt-wrapper.S
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
mov x4, x6
blr x8

mov x16, sp
mov sp, x29
str xzr, [x16, #8] // clear recorded task SP value

ldp x1, x2, [sp, #16]
cmp x2, x18
ldp x29, x30, [sp], #112
Expand All @@ -71,6 +74,9 @@ SYM_FUNC_END(__efi_rt_asm_wrapper)
SYM_CODE_START(__efi_rt_asm_recover)
mov sp, x30

ldr_l x16, efi_rt_stack_top // clear recorded task SP value
str xzr, [x16, #-8]

ldp x19, x20, [sp, #32]
ldp x21, x22, [sp, #48]
ldp x23, x24, [sp, #64]
Expand Down
3 changes: 2 additions & 1 deletion arch/arm64/kernel/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/init.h>

#include <asm/efi.h>
#include <asm/stacktrace.h>

static bool region_is_misaligned(const efi_memory_desc_t *md)
{
Expand Down Expand Up @@ -154,7 +155,7 @@ asmlinkage efi_status_t __efi_rt_asm_recover(void);
bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
{
/* Check whether the exception occurred while running the firmware */
if (current_work() != &efi_rts_work.work || regs->pc >= TASK_SIZE_64)
if (!current_in_efi() || regs->pc >= TASK_SIZE_64)
return false;

pr_err(FW_BUG "Unable to handle %s in EFI runtime service\n", msg);
Expand Down

0 comments on commit 8a9a1a1

Please sign in to comment.