({                                                                     \
        efi_virtmap_load();                                             \
        __efi_fpsimd_begin();                                           \
+       spin_lock(&efi_rt_lock);                                        \
 })
 
 #undef arch_efi_call_virt
 
 #define arch_efi_call_virt_teardown()                                  \
 ({                                                                     \
+       spin_unlock(&efi_rt_lock);                                      \
        __efi_fpsimd_end();                                             \
        efi_virtmap_unload();                                           \
 })
 
+extern spinlock_t efi_rt_lock;
 efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
 
 #define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
 
         */
        stp     x1, x18, [sp, #16]
 
+       ldr_l   x16, efi_rt_stack_top
+       mov     sp, x16
+#ifdef CONFIG_SHADOW_CALL_STACK
+       str     x18, [sp, #-16]!
+#endif
+
        /*
         * We are lucky enough that no EFI runtime services take more than
         * 5 arguments, so all are passed in registers rather than via the
        mov     x4, x6
        blr     x8
 
+       mov     sp, x29
        ldp     x1, x2, [sp, #16]
        cmp     x2, x18
        ldp     x29, x30, [sp], #32
         * called with preemption disabled and a separate shadow stack is used
         * for interrupts.
         */
-       mov     x18, x2
+#ifdef CONFIG_SHADOW_CALL_STACK
+       ldr_l   x18, efi_rt_stack_top
+       ldr     x18, [x18, #-16]
+#endif
+
        b       efi_handle_corrupted_x18        // tail call
 SYM_FUNC_END(__efi_rt_asm_wrapper)
 
        pr_err_ratelimited(FW_BUG "register x18 corrupted by EFI %s\n", f);
        return s;
 }
+
+DEFINE_SPINLOCK(efi_rt_lock);
+
+asmlinkage u64 *efi_rt_stack_top __ro_after_init;
+
+/* EFI requires 8 KiB of stack space for runtime services */
+static_assert(THREAD_SIZE >= SZ_8K);
+
+static int __init arm64_efi_rt_init(void)
+{
+       void *p;
+
+       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+               return 0;
+
+       p = __vmalloc_node(THREAD_SIZE, THREAD_ALIGN, GFP_KERNEL,
+                          NUMA_NO_NODE, &&l);
+l:     if (!p) {
+               pr_warn("Failed to allocate EFI runtime stack\n");
+               clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+               return -ENOMEM;
+       }
+
+       efi_rt_stack_top = p + THREAD_SIZE;
+       return 0;
+}
+core_initcall(arm64_efi_rt_init);