[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