Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

acpi/prmt: Use EFI runtime sandbox to invoke PRM handlers

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>

+40 -4
+1 -1
drivers/acpi/Kconfig
··· 581 581 582 582 config ACPI_PRMT 583 583 bool "Platform Runtime Mechanism Support" 584 - depends on EFI && (X86_64 || ARM64) 584 + depends on EFI_RUNTIME_WRAPPERS && (X86_64 || ARM64) 585 585 default y 586 586 help 587 587 Platform Runtime Mechanism (PRM) is a firmware interface exposing a
+3 -3
drivers/acpi/prmt.c
··· 260 260 context.static_data_buffer = handler->static_data_buffer_addr; 261 261 context.mmio_ranges = module->mmio_info; 262 262 263 - status = efi_call_virt_pointer(handler, handler_addr, 264 - handler->acpi_param_buffer_addr, 265 - &context); 263 + status = efi_call_acpi_prm_handler(handler->handler_addr, 264 + handler->acpi_param_buffer_addr, 265 + &context); 266 266 if (status == EFI_SUCCESS) { 267 267 buffer->prm_status = PRM_HANDLER_SUCCESS; 268 268 } else {
+31
drivers/firmware/efi/runtime-wrappers.c
··· 108 108 u64 *max_size; 109 109 int *reset_type; 110 110 } QUERY_CAPSULE_CAPS; 111 + 112 + struct { 113 + efi_status_t (__efiapi *acpi_prm_handler)(u64, void *); 114 + u64 param_buffer_addr; 115 + void *context; 116 + } ACPI_PRM_HANDLER; 111 117 }; 112 118 113 119 struct efi_runtime_work efi_rts_work; ··· 289 283 args->QUERY_CAPSULE_CAPS.max_size, 290 284 args->QUERY_CAPSULE_CAPS.reset_type); 291 285 break; 286 + case EFI_ACPI_PRM_HANDLER: 287 + #ifdef CONFIG_ACPI_PRMT 288 + status = arch_efi_call_virt(args, ACPI_PRM_HANDLER.acpi_prm_handler, 289 + args->ACPI_PRM_HANDLER.param_buffer_addr, 290 + args->ACPI_PRM_HANDLER.context); 291 + break; 292 + #endif 292 293 default: 293 294 /* 294 295 * Ideally, we should never reach here because a caller of this ··· 573 560 efi.update_capsule = virt_efi_update_capsule; 574 561 efi.query_capsule_caps = virt_efi_query_capsule_caps; 575 562 } 563 + 564 + #ifdef CONFIG_ACPI_PRMT 565 + 566 + efi_status_t 567 + efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *), 568 + u64 param_buffer_addr, void *context) 569 + { 570 + efi_status_t status; 571 + 572 + if (down_interruptible(&efi_runtime_lock)) 573 + return EFI_ABORTED; 574 + status = efi_queue_work(ACPI_PRM_HANDLER, handler_addr, 575 + param_buffer_addr, context); 576 + up(&efi_runtime_lock); 577 + return status; 578 + } 579 + 580 + #endif
+5
include/linux/efi.h
··· 1228 1228 1229 1229 extern unsigned long rci2_table_phys; 1230 1230 1231 + efi_status_t 1232 + efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *), 1233 + u64 param_buffer_addr, void *context); 1234 + 1231 1235 /* 1232 1236 * efi_runtime_service() function identifiers. 1233 1237 * "NONE" is used by efi_recover_from_page_fault() to check if the page ··· 1251 1247 EFI_RESET_SYSTEM, 1252 1248 EFI_UPDATE_CAPSULE, 1253 1249 EFI_QUERY_CAPSULE_CAPS, 1250 + EFI_ACPI_PRM_HANDLER, 1254 1251 }; 1255 1252 1256 1253 union efi_rts_args;