[RESEND PATCH v1 5/7] acpi: rhct: Add tests for ACPI RHCT table
Sunil V L
sunilvl at ventanamicro.com
Tue Jul 15 15:29:11 UTC 2025
From: Haibo Xu <haibo1.xu at intel.com>
RHCT is a new static table introduced in ACPI 6.6 release for RISC-V.
Add test cases for it.
Signed-off-by: Haibo Xu <haibo1.xu at intel.com>
Signed-off-by: Sunil V L <sunilvl at ventanamicro.com>
---
src/Makefile.am | 1 +
src/acpi/rhct/rhct.c | 278 ++++++++++++++++++++++++++++++++++++
src/lib/include/fwts_acpi.h | 46 ++++++
3 files changed, 325 insertions(+)
create mode 100644 src/acpi/rhct/rhct.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 749be642..2cdbe60f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -137,6 +137,7 @@ fwts_SOURCES = main.c \
acpi/rasf/rasf.c \
acpi/ras2/ras2.c \
acpi/rgrt/rgrt.c \
+ acpi/rhct/rhct.c \
acpi/rsdp/rsdp.c \
sbbr/rsdp/rsdp.c \
acpi/rsdt/rsdt.c \
diff --git a/src/acpi/rhct/rhct.c b/src/acpi/rhct/rhct.c
new file mode 100644
index 00000000..0b5887e6
--- /dev/null
+++ b/src/acpi/rhct/rhct.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2023 Intel Corporation
+ * Copyright (C) 2025 Ventana Micro Systems Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#include "fwts.h"
+
+#if defined(FWTS_HAS_ACPI)
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <string.h>
+
+static fwts_acpi_table_info *table;
+acpi_table_init(RHCT, &table)
+
+static void rhct_check_node_isa_string(fwts_framework *fw,
+ fwts_acpi_rhct_node_header *hdr,
+ ssize_t *length,
+ uint8_t **data,
+ bool *passed)
+{
+ fwts_acpi_rhct_node_isa_string *node =
+ (fwts_acpi_rhct_node_isa_string *)*data;
+
+ if (sizeof(fwts_acpi_rhct_node_isa_string) + node->isa_length > *length) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTNodeISAStringShort",
+ "RHCT isa string node structure too short, got "
+ "%zu bytes, expecting %zu bytes",
+ *length, sizeof(fwts_acpi_rhct_node_isa_string) + node->isa_length);
+ *passed = false;
+ goto done;
+ }
+
+ if (node->isa_length != strlen(node->isa) + 1) {
+ fwts_failed(fw, LOG_LEVEL_CRITICAL,
+ "RHCTBadISAStringLength",
+ "RHCT isa string should have length %d"
+ " ,got %zu",
+ node->isa_length, strlen(node->isa) + 1);
+ *passed = false;
+ goto done;
+ }
+
+ fwts_log_info_verbatim(fw, "RHCT Node ISA String Structure:");
+ fwts_log_info_simp_int(fw, " Type: ", hdr->type);
+ fwts_log_info_simp_int(fw, " Length: ", hdr->length);
+ fwts_log_info_simp_int(fw, " Revision: ", hdr->revision);
+ fwts_log_info_simp_int(fw, " ISA Length: ", node->isa_length);
+ fwts_log_info_verbatim(fw, " ISA String: %s", node->isa);
+ fwts_log_nl(fw);
+
+done:
+ *length -= (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+ *data += (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+}
+
+static void rhct_check_node_cmo(fwts_framework *fw,
+ fwts_acpi_rhct_node_header *hdr,
+ ssize_t *length,
+ uint8_t **data,
+ bool *passed)
+{
+ fwts_acpi_rhct_node_cmo *node =
+ (fwts_acpi_rhct_node_cmo *)*data;
+
+ if (sizeof(fwts_acpi_rhct_node_cmo) > *length) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTNodeCMOShort",
+ "RHCT cmo node structure too short, got "
+ "%zu bytes, expecting %zu bytes",
+ *length, sizeof(fwts_acpi_rhct_node_cmo));
+ *passed = false;
+ goto done;
+ }
+
+ if (node->reserved) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTNodeCMOReserved",
+ "RHCT cmo node structure reserved field should be zero, got "
+ "0x%" PRIx8, node->reserved);
+ *passed = false;
+ goto done;
+ }
+
+ fwts_log_info_verbatim(fw, "RHCT Node CMO:");
+ fwts_log_info_simp_int(fw, " Type: ", hdr->type);
+ fwts_log_info_simp_int(fw, " Length: ", hdr->length);
+ fwts_log_info_simp_int(fw, " Revision: ", hdr->revision);
+ fwts_log_info_simp_int(fw, " Reserved: ", node->reserved);
+ fwts_log_info_simp_int(fw, " CBOM block size: ", node->cbom_size);
+ fwts_log_info_simp_int(fw, " CBOP block size: ", node->cbop_size);
+ fwts_log_info_simp_int(fw, " CBOZ block size: ", node->cboz_size);
+ fwts_log_nl(fw);
+
+done:
+ *length -= (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+ *data += (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+}
+
+static void rhct_check_node_mmu(fwts_framework *fw,
+ fwts_acpi_rhct_node_header *hdr,
+ ssize_t *length,
+ uint8_t **data,
+ bool *passed)
+{
+ fwts_acpi_rhct_node_mmu *node =
+ (fwts_acpi_rhct_node_mmu *)*data;
+
+ if (sizeof(fwts_acpi_rhct_node_mmu) > *length) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTNodeMMUShort",
+ "RHCT mmu node structure too short, got "
+ "%zu bytes, expecting %zu bytes",
+ *length, sizeof(fwts_acpi_rhct_node_mmu));
+ *passed = false;
+ goto done;
+ }
+
+ if (node->reserved) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTNodeMMUReserved",
+ "RHCT mmu node structure reserved field should be zero, got "
+ "0x%" PRIx8, node->reserved);
+ *passed = false;
+ goto done;
+ }
+
+ if (node->mmu_type > 2) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTNodeMMUType",
+ "RHCT mmu node structure type field should be 0..2, got "
+ "0x%" PRIx8, node->mmu_type);
+ *passed = false;
+ goto done;
+ }
+
+ fwts_log_info_verbatim(fw, "RHCT Node MMU:");
+ fwts_log_info_simp_int(fw, " Type: ", hdr->type);
+ fwts_log_info_simp_int(fw, " Length: ", hdr->length);
+ fwts_log_info_simp_int(fw, " Revision: ", hdr->revision);
+ fwts_log_info_simp_int(fw, " Reserved: ", node->reserved);
+ fwts_log_info_simp_int(fw, " MMU Type: ", node->mmu_type);
+ fwts_log_nl(fw);
+
+done:
+ *length -= (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+ *data += (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+}
+
+static void rhct_check_node_hart_info(fwts_framework *fw,
+ fwts_acpi_rhct_node_header *hdr,
+ ssize_t *length,
+ uint8_t **data,
+ bool *passed)
+{
+ fwts_acpi_rhct_node_hart_info *node =
+ (fwts_acpi_rhct_node_hart_info *)*data;
+
+ if (sizeof(fwts_acpi_rhct_node_hart_info) + 4 * node->num_offsets > *length) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTNodeHartInfoShort",
+ "RHCT hart info node structure too short, got "
+ "%zu bytes, expecting %zu bytes", *length,
+ sizeof(fwts_acpi_rhct_node_hart_info) + 4 * node->num_offsets);
+ *passed = false;
+ goto done;
+ }
+
+ fwts_log_info_verbatim(fw, "RHCT Node Hart Info Structure:");
+ fwts_log_info_simp_int(fw, " Type: ", hdr->type);
+ fwts_log_info_simp_int(fw, " Length: ", hdr->length);
+ fwts_log_info_simp_int(fw, " Revision: ", hdr->revision);
+ fwts_log_info_simp_int(fw, " Number of offsets: ", node->num_offsets);
+ fwts_log_info_simp_int(fw, " ACPI Processor UID: ", node->uid);
+ fwts_log_nl(fw);
+
+done:
+ *length -= (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+ *data += (hdr->length - sizeof(fwts_acpi_rhct_node_header));
+}
+
+/*
+ * See ACPI 6.5+, Section 5.2.36
+ */
+static int rhct_test1(fwts_framework *fw)
+{
+ const fwts_acpi_table_rhct *rhct = (const fwts_acpi_table_rhct *)table->data;
+ fwts_acpi_rhct_node_header *hdr;
+ uint8_t *data = (uint8_t *)table->data;
+ bool passed = true;
+ ssize_t length = (ssize_t)rhct->header.length;
+
+ if (fwts_checksum(data, length) != 0)
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "SPECRHCTChecksum",
+ "RHCT Check Sum is incorrect");
+
+ if (rhct->flags & 0xfffe)
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "RHCTFlagsNonZero",
+ "RHCT flags field, bit 1..31 are reserved and "
+ "should be zero, but are set as: 0x%" PRIx32 ".\n",
+ rhct->flags);
+
+ data += sizeof(fwts_acpi_table_rhct);
+ length -= sizeof(fwts_acpi_table_rhct);
+
+ while (length > 0) {
+ hdr = (fwts_acpi_rhct_node_header *)data;
+
+ fwts_acpi_fixed_value(fw, LOG_LEVEL_MEDIUM, "RHCT", "revision", hdr->revision, 1, &passed);
+
+ data += sizeof(fwts_acpi_rhct_node_header);
+ length -= sizeof(fwts_acpi_rhct_node_header);
+
+ switch (hdr->type) {
+ case FWTS_RHCT_NODE_ISA_STRING:
+ rhct_check_node_isa_string(fw, hdr, &length, &data, &passed);
+ break;
+ case FWTS_RHCT_NODE_CMO:
+ rhct_check_node_cmo(fw, hdr, &length, &data, &passed);
+ break;
+ case FWTS_RHCT_NODE_MMU:
+ rhct_check_node_mmu(fw, hdr, &length, &data, &passed);
+ break;
+ case FWTS_RHCT_NODE_HART_INFO:
+ rhct_check_node_hart_info(fw, hdr, &length, &data, &passed);
+ break;
+ default:
+ fwts_failed(fw, LOG_LEVEL_HIGH,
+ "RHCTInvalidType",
+ "RHCT Node Structure Type 0x%" PRIx16
+ " is an invalid type, expecting 0x00..0x02,0xFFFF",
+ hdr->type);
+ passed = false;
+ length = 0;
+ break;
+ }
+ }
+
+ if (passed)
+ fwts_passed(fw, "No issues found in RHCT table.");
+
+ return FWTS_OK;
+}
+
+static fwts_framework_minor_test rhct_tests[] = {
+ { rhct_test1, "RHCT RISC-V Hart Capabilities Table test." },
+ { NULL, NULL }
+};
+
+static fwts_framework_ops rhct_ops = {
+ .description = "RHCT RISC-V Hart Capabilities Table test.",
+ .init = RHCT_init,
+ .minor_tests = rhct_tests
+};
+
+FWTS_REGISTER("rhct", &rhct_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ACPI)
+
+#endif
diff --git a/src/lib/include/fwts_acpi.h b/src/lib/include/fwts_acpi.h
index 6f3fe445..2fcb2cba 100644
--- a/src/lib/include/fwts_acpi.h
+++ b/src/lib/include/fwts_acpi.h
@@ -3027,4 +3027,50 @@ typedef struct {
fwts_acpi_apmt_node entry[0];
} __attribute__ ((packed)) fwts_acpi_table_apmt;
+/*
+ * ACPI RHCT (RISC-V Hart Capabilities Table), 5.2.37
+ */
+typedef struct {
+ fwts_acpi_table_header header;
+ uint32_t flags;
+ uint64_t time_base_freq;
+ uint32_t node_count;
+ uint32_t node_offset;
+} __attribute__ ((packed)) fwts_acpi_table_rhct;
+
+typedef struct {
+ uint16_t type;
+ uint16_t length;
+ uint16_t revision;
+} __attribute__ ((packed)) fwts_acpi_rhct_node_header;
+
+typedef enum {
+ FWTS_RHCT_NODE_ISA_STRING = 0x0,
+ FWTS_RHCT_NODE_CMO,
+ FWTS_RHCT_NODE_MMU,
+ FWTS_RHCT_NODE_HART_INFO = 0xFFFF
+} fwts_acpi_rhct_node_type;
+
+typedef struct {
+ uint16_t isa_length;
+ char isa[];
+} __attribute__ ((packed)) fwts_acpi_rhct_node_isa_string;
+
+typedef struct {
+ uint8_t reserved;
+ uint8_t cbom_size;
+ uint8_t cbop_size;
+ uint8_t cboz_size;
+} __attribute__ ((packed)) fwts_acpi_rhct_node_cmo;
+
+typedef struct {
+ uint8_t reserved;
+ uint8_t mmu_type;
+} __attribute__ ((packed)) fwts_acpi_rhct_node_mmu;
+
+typedef struct {
+ uint16_t num_offsets;
+ uint32_t uid;
+} __attribute__ ((packed)) fwts_acpi_rhct_node_hart_info;
+
#endif
--
2.43.0
More information about the fwts-devel
mailing list