162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: utcksum - Support generating table checksums 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acutils.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* This module used for application-level code only */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define _COMPONENT ACPI_CA_DISASSEMBLER 1762306a36Sopenharmony_ciACPI_MODULE_NAME("utcksum") 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/******************************************************************************* 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * FUNCTION: acpi_ut_verify_checksum 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * PARAMETERS: table - ACPI table to verify 2462306a36Sopenharmony_ci * length - Length of entire table 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * RETURN: Status 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns 2962306a36Sopenharmony_ci * exception on bad checksum. 3062306a36Sopenharmony_ci * Note: We don't have to check for a CDAT here, since CDAT is 3162306a36Sopenharmony_ci * not in the RSDT/XSDT, and the CDAT table is never installed 3262306a36Sopenharmony_ci * via ACPICA. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci ******************************************************************************/ 3562306a36Sopenharmony_ciacpi_status acpi_ut_verify_checksum(struct acpi_table_header *table, u32 length) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci u8 checksum; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* 4062306a36Sopenharmony_ci * FACS/S3PT: 4162306a36Sopenharmony_ci * They are the odd tables, have no standard ACPI header and no checksum 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_S3PT) || 4462306a36Sopenharmony_ci ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_FACS)) { 4562306a36Sopenharmony_ci return (AE_OK); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Compute the checksum on the table */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci length = table->length; 5162306a36Sopenharmony_ci checksum = 5262306a36Sopenharmony_ci acpi_ut_generate_checksum(ACPI_CAST_PTR(u8, table), length, 5362306a36Sopenharmony_ci table->checksum); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Computed checksum matches table? */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (checksum != table->checksum) { 5862306a36Sopenharmony_ci ACPI_BIOS_WARNING((AE_INFO, 5962306a36Sopenharmony_ci "Incorrect checksum in table [%4.4s] - 0x%2.2X, " 6062306a36Sopenharmony_ci "should be 0x%2.2X", 6162306a36Sopenharmony_ci table->signature, table->checksum, 6262306a36Sopenharmony_ci table->checksum - checksum)); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#if (ACPI_CHECKSUM_ABORT) 6562306a36Sopenharmony_ci return (AE_BAD_CHECKSUM); 6662306a36Sopenharmony_ci#endif 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return (AE_OK); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/******************************************************************************* 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * FUNCTION: acpi_ut_verify_cdat_checksum 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * PARAMETERS: table - CDAT ACPI table to verify 7762306a36Sopenharmony_ci * length - Length of entire table 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * RETURN: Status 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * DESCRIPTION: Verifies that the CDAT table checksums to zero. Optionally 8262306a36Sopenharmony_ci * returns an exception on bad checksum. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci ******************************************************************************/ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciacpi_status 8762306a36Sopenharmony_ciacpi_ut_verify_cdat_checksum(struct acpi_table_cdat *cdat_table, u32 length) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci u8 checksum; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Compute the checksum on the table */ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci checksum = acpi_ut_generate_checksum(ACPI_CAST_PTR(u8, cdat_table), 9462306a36Sopenharmony_ci cdat_table->length, 9562306a36Sopenharmony_ci cdat_table->checksum); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Computed checksum matches table? */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (checksum != cdat_table->checksum) { 10062306a36Sopenharmony_ci ACPI_BIOS_WARNING((AE_INFO, 10162306a36Sopenharmony_ci "Incorrect checksum in table [%4.4s] - 0x%2.2X, " 10262306a36Sopenharmony_ci "should be 0x%2.2X", 10362306a36Sopenharmony_ci acpi_gbl_CDAT, cdat_table->checksum, 10462306a36Sopenharmony_ci checksum)); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#if (ACPI_CHECKSUM_ABORT) 10762306a36Sopenharmony_ci return (AE_BAD_CHECKSUM); 10862306a36Sopenharmony_ci#endif 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci cdat_table->checksum = checksum; 11262306a36Sopenharmony_ci return (AE_OK); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/******************************************************************************* 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * FUNCTION: acpi_ut_generate_checksum 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * PARAMETERS: table - Pointer to table to be checksummed 12062306a36Sopenharmony_ci * length - Length of the table 12162306a36Sopenharmony_ci * original_checksum - Value of the checksum field 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * RETURN: 8 bit checksum of buffer 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * DESCRIPTION: Computes an 8 bit checksum of the table. 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci ******************************************************************************/ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ciu8 acpi_ut_generate_checksum(void *table, u32 length, u8 original_checksum) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci u8 checksum; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Sum the entire table as-is */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci checksum = acpi_ut_checksum((u8 *)table, length); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Subtract off the existing checksum value in the table */ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci checksum = (u8)(checksum - original_checksum); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Compute and return the final checksum */ 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci checksum = (u8)(0 - checksum); 14462306a36Sopenharmony_ci return (checksum); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/******************************************************************************* 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * FUNCTION: acpi_ut_checksum 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * PARAMETERS: buffer - Pointer to memory region to be checked 15262306a36Sopenharmony_ci * length - Length of this memory region 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * RETURN: Checksum (u8) 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci * DESCRIPTION: Calculates circular checksum of memory region. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci ******************************************************************************/ 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciu8 acpi_ut_checksum(u8 *buffer, u32 length) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci u8 sum = 0; 16362306a36Sopenharmony_ci u8 *end = buffer + length; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci while (buffer < end) { 16662306a36Sopenharmony_ci sum = (u8)(sum + *(buffer++)); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return (sum); 17062306a36Sopenharmony_ci} 171