acpi/prmt: Use EFI runtime sandbox to invoke PRM handlers
authorArd Biesheuvel <ardb@kernel.org>
Sun, 2 Jul 2023 09:57:34 +0000 (11:57 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Tue, 22 Aug 2023 08:39:26 +0000 (10:39 +0200)
Instead of bypassing the kernel's adaptation layer for performing EFI
runtime calls, wire up ACPI PRM handling into it. This means these calls
can no longer occur concurrently with EFI runtime calls, and will be
made from the EFI runtime workqueue. It also means any page faults
occurring during PRM handling will be identified correctly as
originating in firmware code.

Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
drivers/acpi/Kconfig
drivers/acpi/prmt.c
drivers/firmware/efi/runtime-wrappers.c
include/linux/efi.h

index 00dd309b668281826a6d5328c8dde36c6f5dbd02..cee82b473dc50921c31e6dcfc0b573cdcf0962e9 100644 (file)
@@ -581,7 +581,7 @@ config ACPI_VIOT
 
 config ACPI_PRMT
        bool "Platform Runtime Mechanism Support"
-       depends on EFI && (X86_64 || ARM64)
+       depends on EFI_RUNTIME_WRAPPERS && (X86_64 || ARM64)
        default y
        help
          Platform Runtime Mechanism (PRM) is a firmware interface exposing a
index 71b9adaaf33b93cf19f52b85c10cf93b84f3700e..7020584096bfaaaf0532e0330e2698485e983e87 100644 (file)
@@ -260,9 +260,9 @@ static acpi_status acpi_platformrt_space_handler(u32 function,
                context.static_data_buffer = handler->static_data_buffer_addr;
                context.mmio_ranges = module->mmio_info;
 
-               status = efi_call_virt_pointer(handler, handler_addr,
-                                              handler->acpi_param_buffer_addr,
-                                              &context);
+               status = efi_call_acpi_prm_handler(handler->handler_addr,
+                                                  handler->acpi_param_buffer_addr,
+                                                  &context);
                if (status == EFI_SUCCESS) {
                        buffer->prm_status = PRM_HANDLER_SUCCESS;
                } else {
index afe9248cc5bc61bab4c6c3813274260f0fe569ae..e89484af9740f63789f5c6e1d30baf76c25c167f 100644 (file)
@@ -108,6 +108,12 @@ union efi_rts_args {
                u64             *max_size;
                int             *reset_type;
        } QUERY_CAPSULE_CAPS;
+
+       struct {
+               efi_status_t    (__efiapi *acpi_prm_handler)(u64, void *);
+               u64             param_buffer_addr;
+               void            *context;
+       } ACPI_PRM_HANDLER;
 };
 
 struct efi_runtime_work efi_rts_work;
@@ -283,6 +289,13 @@ static void efi_call_rts(struct work_struct *work)
                                       args->QUERY_CAPSULE_CAPS.max_size,
                                       args->QUERY_CAPSULE_CAPS.reset_type);
                break;
+       case EFI_ACPI_PRM_HANDLER:
+#ifdef CONFIG_ACPI_PRMT
+               status = arch_efi_call_virt(args, ACPI_PRM_HANDLER.acpi_prm_handler,
+                                           args->ACPI_PRM_HANDLER.param_buffer_addr,
+                                           args->ACPI_PRM_HANDLER.context);
+               break;
+#endif
        default:
                /*
                 * Ideally, we should never reach here because a caller of this
@@ -560,3 +573,21 @@ void efi_native_runtime_setup(void)
        efi.update_capsule = virt_efi_update_capsule;
        efi.query_capsule_caps = virt_efi_query_capsule_caps;
 }
+
+#ifdef CONFIG_ACPI_PRMT
+
+efi_status_t
+efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *),
+                         u64 param_buffer_addr, void *context)
+{
+       efi_status_t status;
+
+       if (down_interruptible(&efi_runtime_lock))
+               return EFI_ABORTED;
+       status = efi_queue_work(ACPI_PRM_HANDLER, handler_addr,
+                               param_buffer_addr, context);
+       up(&efi_runtime_lock);
+       return status;
+}
+
+#endif
index e0b346b014dff9cd1ec4ebcf862f762158c2738f..5a1e39df8b26487bab8cd29d42b2b6174a66791b 100644 (file)
@@ -1228,6 +1228,10 @@ extern int efi_tpm_final_log_size;
 
 extern unsigned long rci2_table_phys;
 
+efi_status_t
+efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *),
+                         u64 param_buffer_addr, void *context);
+
 /*
  * efi_runtime_service() function identifiers.
  * "NONE" is used by efi_recover_from_page_fault() to check if the page
@@ -1247,6 +1251,7 @@ enum efi_rts_ids {
        EFI_RESET_SYSTEM,
        EFI_UPDATE_CAPSULE,
        EFI_QUERY_CAPSULE_CAPS,
+       EFI_ACPI_PRM_HANDLER,
 };
 
 union efi_rts_args;