ACPICA: Abort AML bytecode execution when executing AML_FATAL_OP

The ACPI specification states that when executing AML_FATAL_OP,
the OS should log the fatal error event and shutdown in a timely
fashion.

Windows complies with this requirement by immediatly entering a
Bso_d, effectively aborting the execution of the AML bytecode in
question.

ACPICA however might continue with the AML bytecode execution
should acpi_os_signal() simply return AE_OK. This will cause issues
because ACPI BIOS implementations might assume that the Fatal()
operator does not return.

Fix this by aborting the AML bytecode execution in such a case
by returning AE_ERROR. Also turn struct acpi_signal_fatal_info into a
local variable because of its small size (12 bytes) and to ensure
that acpi_os_signal() always receives valid information about the
fatal ACPI BIOS error.

Link: https://github.com/acpica/acpica/commit/d516c7758ba6
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/3325491.5fSG56mABF@rafael.j.wysocki
This commit is contained in:
Armin Wolf 2026-01-14 13:25:33 +01:00 committed by Rafael J. Wysocki
parent 30c2a333aa
commit 026ad376a6
1 changed files with 17 additions and 27 deletions

View File

@ -10,6 +10,7 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "acinterp.h"
#include <acpi/acoutput.h>
#include "acparser.h"
#include "amlcode.h"
@ -51,8 +52,7 @@ ACPI_MODULE_NAME("exoparg3")
acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
{
union acpi_operand_object **operand = &walk_state->operands[0];
struct acpi_signal_fatal_info *fatal;
acpi_status status = AE_OK;
struct acpi_signal_fatal_info fatal;
ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R,
acpi_ps_get_opcode_name(walk_state->opcode));
@ -60,28 +60,23 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
switch (walk_state->opcode) {
case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"FatalOp: Type %X Code %X Arg %X "
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
(u32)operand[0]->integer.value,
(u32)operand[1]->integer.value,
(u32)operand[2]->integer.value));
fatal.type = (u32)operand[0]->integer.value;
fatal.code = (u32)operand[1]->integer.value;
fatal.argument = (u32)operand[2]->integer.value;
fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info));
if (fatal) {
fatal->type = (u32) operand[0]->integer.value;
fatal->code = (u32) operand[1]->integer.value;
fatal->argument = (u32) operand[2]->integer.value;
}
ACPI_BIOS_ERROR((AE_INFO,
"Fatal ACPI BIOS error (Type 0x%X Code 0x%X Arg 0x%X)\n",
fatal.type, fatal.code, fatal.argument));
/* Always signal the OS! */
status = acpi_os_signal(ACPI_SIGNAL_FATAL, fatal);
acpi_os_signal(ACPI_SIGNAL_FATAL, &fatal);
/* Might return while OS is shutting down, just continue */
ACPI_FREE(fatal);
goto cleanup;
/*
* Might return while OS is shutting down, so abort the AML execution
* by returning an error.
*/
return_ACPI_STATUS(AE_ERROR);
case AML_EXTERNAL_OP:
/*
@ -93,21 +88,16 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
* wrong if an external opcode ever gets here.
*/
ACPI_ERROR((AE_INFO, "Executed External Op"));
status = AE_OK;
goto cleanup;
return_ACPI_STATUS(AE_OK);
default:
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
walk_state->opcode));
status = AE_AML_BAD_OPCODE;
goto cleanup;
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
}
cleanup:
return_ACPI_STATUS(status);
}
/*******************************************************************************