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