[RESEND PATCH v1 5/7] acpi: rhct: Add tests for ACPI RHCT table
Ivan Hu
ivan.hu at canonical.com
Thu Jul 24 06:47:25 UTC 2025
Thanks for the patch.
The RHCT tests look good to me, except for some formatting issues in FWTS.
I'll accept this patch and send out a follow-up patch to address them.
Acked-by: Ivan Hu <ivan.hu at canonical.com>
On Tue, Jul 15, 2025 at 11:29 PM Sunil V L <sunilvl at ventanamicro.com> wrote:
> 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ubuntu.com/archives/fwts-devel/attachments/20250724/f478279d/attachment-0001.html>
More information about the fwts-devel
mailing list