Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 729df0f8 authored by Lin Ming's avatar Lin Ming Committed by Len Brown
Browse files

ACPICA: Add detection of corrupted/replaced DSDT

This change adds support to detect a DSDT that has been corrupted
and/or replaced from outside the OS (by firmware). This is
typically catastrophic for the system, but has been seen on
some machines.

https://bugzilla.kernel.org/show_bug.cgi?id=14679



Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent c1637e9c
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -165,6 +165,11 @@ ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;


/* DSDT information. Used to check for DSDT corruption */

ACPI_EXTERN struct acpi_table_desc *acpi_gbl_DSDT;
ACPI_EXTERN struct acpi_table_header acpi_gbl_original_dsdt_header;

/*
/*
 * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
 * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
 * determined by the revision of the DSDT: If the DSDT revision is less than
 * determined by the revision of the DSDT: If the DSDT revision is less than
+2 −0
Original line number Original line Diff line number Diff line
@@ -107,6 +107,8 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length);
acpi_status
acpi_status
acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);


void acpi_tb_check_dsdt_header(void);

void
void
acpi_tb_install_table(acpi_physical_address address,
acpi_tb_install_table(acpi_physical_address address,
		      char *signature, u32 table_index);
		      char *signature, u32 table_index);
+4 −0
Original line number Original line Diff line number Diff line
@@ -220,6 +220,10 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)


	ACPI_FUNCTION_TRACE(ps_execute_method);
	ACPI_FUNCTION_TRACE(ps_execute_method);


	/* Quick validation of DSDT header */

	acpi_tb_check_dsdt_header();

	/* Validate the Info and method Node */
	/* Validate the Info and method Node */


	if (!info || !info->resolved_node) {
	if (!info || !info->resolved_node) {
+38 −0
Original line number Original line Diff line number Diff line
@@ -347,6 +347,44 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length)
	return sum;
	return sum;
}
}


/*******************************************************************************
 *
 * FUNCTION:    acpi_tb_check_dsdt_header
 *
 * PARAMETERS:  None
 *
 * RETURN:      None
 *
 * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect
 *              if the DSDT has been replaced from outside the OS and/or if
 *              the DSDT header has been corrupted.
 *
 ******************************************************************************/

void acpi_tb_check_dsdt_header(void)
{

	/* Compare original length and checksum to current values */

	if (acpi_gbl_original_dsdt_header.length !=
	    acpi_gbl_DSDT->pointer->length
	    || acpi_gbl_original_dsdt_header.checksum !=
	    acpi_gbl_DSDT->pointer->checksum) {
		ACPI_ERROR((AE_INFO,
			    "The DSDT has been corrupted or replaced - old, new headers below"));
		acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header);
		acpi_tb_print_table_header(acpi_gbl_DSDT->address,
					   acpi_gbl_DSDT->pointer);

		/* Disable further error messages */

		acpi_gbl_original_dsdt_header.length =
		    acpi_gbl_DSDT->pointer->length;
		acpi_gbl_original_dsdt_header.checksum =
		    acpi_gbl_DSDT->pointer->checksum;
	}
}

/*******************************************************************************
/*******************************************************************************
 *
 *
 * FUNCTION:    acpi_tb_install_table
 * FUNCTION:    acpi_tb_install_table
+12 −20
Original line number Original line Diff line number Diff line
@@ -518,33 +518,25 @@ static acpi_status acpi_tb_load_namespace(void)


	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);


	acpi_gbl_DSDT = &acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT];

	/*
	/*
	 * Load the namespace. The DSDT is required, but any SSDT and PSDT tables
	 * Load the namespace. The DSDT is required, but any SSDT and
	 * are optional.
	 * PSDT tables are optional. Verify the DSDT.
	 */
	 */
	if (!acpi_gbl_root_table_list.count ||
	if (!acpi_gbl_root_table_list.count ||
	    !ACPI_COMPARE_NAME(&
	    !ACPI_COMPARE_NAME(&acpi_gbl_DSDT->signature, ACPI_SIG_DSDT) ||
			       (acpi_gbl_root_table_list.
	    ACPI_FAILURE(acpi_tb_verify_table(acpi_gbl_DSDT))) {
				tables[ACPI_TABLE_INDEX_DSDT].signature),
			       ACPI_SIG_DSDT)
	    ||
	    ACPI_FAILURE(acpi_tb_verify_table
			 (&acpi_gbl_root_table_list.
			  tables[ACPI_TABLE_INDEX_DSDT]))) {
		status = AE_NO_ACPI_TABLES;
		status = AE_NO_ACPI_TABLES;
		goto unlock_and_exit;
		goto unlock_and_exit;
	}
	}


	/* A valid DSDT is required */
	/*

	 * Save the original DSDT header for detection of table corruption
	status =
	 * and/or replacement of the DSDT from outside the OS.
	    acpi_tb_verify_table(&acpi_gbl_root_table_list.
	 */
				 tables[ACPI_TABLE_INDEX_DSDT]);
	ACPI_MEMCPY(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT->pointer,
	if (ACPI_FAILURE(status)) {
		    sizeof(struct acpi_table_header));

		status = AE_NO_ACPI_TABLES;
		goto unlock_and_exit;
	}


	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);