|  | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 | 
|  | /****************************************************************************** | 
|  | * | 
|  | * Module Name: tbprint - Table output utilities | 
|  | * | 
|  | * Copyright (C) 2000 - 2019, Intel Corp. | 
|  | * | 
|  | *****************************************************************************/ | 
|  |  | 
|  | #include <acpi/acpi.h> | 
|  | #include "accommon.h" | 
|  | #include "actables.h" | 
|  |  | 
|  | #define _COMPONENT          ACPI_TABLES | 
|  | ACPI_MODULE_NAME("tbprint") | 
|  |  | 
|  | /* Local prototypes */ | 
|  | static void acpi_tb_fix_string(char *string, acpi_size length); | 
|  |  | 
|  | static void | 
|  | acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, | 
|  | struct acpi_table_header *header); | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * FUNCTION:    acpi_tb_fix_string | 
|  | * | 
|  | * PARAMETERS:  string              - String to be repaired | 
|  | *              length              - Maximum length | 
|  | * | 
|  | * RETURN:      None | 
|  | * | 
|  | * DESCRIPTION: Replace every non-printable or non-ascii byte in the string | 
|  | *              with a question mark '?'. | 
|  | * | 
|  | ******************************************************************************/ | 
|  |  | 
|  | static void acpi_tb_fix_string(char *string, acpi_size length) | 
|  | { | 
|  |  | 
|  | while (length && *string) { | 
|  | if (!isprint((int)*string)) { | 
|  | *string = '?'; | 
|  | } | 
|  |  | 
|  | string++; | 
|  | length--; | 
|  | } | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * FUNCTION:    acpi_tb_cleanup_table_header | 
|  | * | 
|  | * PARAMETERS:  out_header          - Where the cleaned header is returned | 
|  | *              header              - Input ACPI table header | 
|  | * | 
|  | * RETURN:      Returns the cleaned header in out_header | 
|  | * | 
|  | * DESCRIPTION: Copy the table header and ensure that all "string" fields in | 
|  | *              the header consist of printable characters. | 
|  | * | 
|  | ******************************************************************************/ | 
|  |  | 
|  | static void | 
|  | acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, | 
|  | struct acpi_table_header *header) | 
|  | { | 
|  |  | 
|  | memcpy(out_header, header, sizeof(struct acpi_table_header)); | 
|  |  | 
|  | acpi_tb_fix_string(out_header->signature, ACPI_NAMESEG_SIZE); | 
|  | acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE); | 
|  | acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE); | 
|  | acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAMESEG_SIZE); | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * FUNCTION:    acpi_tb_print_table_header | 
|  | * | 
|  | * PARAMETERS:  address             - Table physical address | 
|  | *              header              - Table header | 
|  | * | 
|  | * RETURN:      None | 
|  | * | 
|  | * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP. | 
|  | * | 
|  | ******************************************************************************/ | 
|  |  | 
|  | void | 
|  | acpi_tb_print_table_header(acpi_physical_address address, | 
|  | struct acpi_table_header *header) | 
|  | { | 
|  | struct acpi_table_header local_header; | 
|  |  | 
|  | if (ACPI_COMPARE_NAMESEG(header->signature, ACPI_SIG_FACS)) { | 
|  |  | 
|  | /* FACS only has signature and length fields */ | 
|  |  | 
|  | ACPI_INFO(("%-4.4s 0x%8.8X%8.8X %06X", | 
|  | header->signature, ACPI_FORMAT_UINT64(address), | 
|  | header->length)); | 
|  | } else if (ACPI_VALIDATE_RSDP_SIG(header->signature)) { | 
|  |  | 
|  | /* RSDP has no common fields */ | 
|  |  | 
|  | memcpy(local_header.oem_id, | 
|  | ACPI_CAST_PTR(struct acpi_table_rsdp, header)->oem_id, | 
|  | ACPI_OEM_ID_SIZE); | 
|  | acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE); | 
|  |  | 
|  | ACPI_INFO(("RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)", | 
|  | ACPI_FORMAT_UINT64(address), | 
|  | (ACPI_CAST_PTR(struct acpi_table_rsdp, header)-> | 
|  | revision > | 
|  | 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp, | 
|  | header)->length : 20, | 
|  | ACPI_CAST_PTR(struct acpi_table_rsdp, | 
|  | header)->revision, | 
|  | local_header.oem_id)); | 
|  | } else { | 
|  | /* Standard ACPI table with full common header */ | 
|  |  | 
|  | acpi_tb_cleanup_table_header(&local_header, header); | 
|  |  | 
|  | ACPI_INFO(("%-4.4s 0x%8.8X%8.8X" | 
|  | " %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)", | 
|  | local_header.signature, ACPI_FORMAT_UINT64(address), | 
|  | local_header.length, local_header.revision, | 
|  | local_header.oem_id, local_header.oem_table_id, | 
|  | local_header.oem_revision, | 
|  | local_header.asl_compiler_id, | 
|  | local_header.asl_compiler_revision)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * FUNCTION:    acpi_tb_validate_checksum | 
|  | * | 
|  | * PARAMETERS:  table               - ACPI table to verify | 
|  | *              length              - Length of entire table | 
|  | * | 
|  | * RETURN:      Status | 
|  | * | 
|  | * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns | 
|  | *              exception on bad checksum. | 
|  | * | 
|  | ******************************************************************************/ | 
|  |  | 
|  | acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length) | 
|  | { | 
|  | u8 checksum; | 
|  |  | 
|  | /* | 
|  | * FACS/S3PT: | 
|  | * They are the odd tables, have no standard ACPI header and no checksum | 
|  | */ | 
|  |  | 
|  | if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_S3PT) || | 
|  | ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_FACS)) { | 
|  | return (AE_OK); | 
|  | } | 
|  |  | 
|  | /* Compute the checksum on the table */ | 
|  |  | 
|  | checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length); | 
|  |  | 
|  | /* Checksum ok? (should be zero) */ | 
|  |  | 
|  | if (checksum) { | 
|  | ACPI_BIOS_WARNING((AE_INFO, | 
|  | "Incorrect checksum in table [%4.4s] - 0x%2.2X, " | 
|  | "should be 0x%2.2X", | 
|  | table->signature, table->checksum, | 
|  | (u8)(table->checksum - checksum))); | 
|  |  | 
|  | #if (ACPI_CHECKSUM_ABORT) | 
|  | return (AE_BAD_CHECKSUM); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | return (AE_OK); | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | * | 
|  | * FUNCTION:    acpi_tb_checksum | 
|  | * | 
|  | * PARAMETERS:  buffer          - Pointer to memory region to be checked | 
|  | *              length          - Length of this memory region | 
|  | * | 
|  | * RETURN:      Checksum (u8) | 
|  | * | 
|  | * DESCRIPTION: Calculates circular checksum of memory region. | 
|  | * | 
|  | ******************************************************************************/ | 
|  |  | 
|  | u8 acpi_tb_checksum(u8 *buffer, u32 length) | 
|  | { | 
|  | u8 sum = 0; | 
|  | u8 *end = buffer + length; | 
|  |  | 
|  | while (buffer < end) { | 
|  | sum = (u8)(sum + *(buffer++)); | 
|  | } | 
|  |  | 
|  | return (sum); | 
|  | } |