Re: [PATCH] ACPI: sysfs: Expose BDAT data region

From: Rafael J. Wysocki (Intel)

Date: Mon Oct 12 2026 - 14:22:43 EST


On Sat, Oct 10, 2026 at 1:30 AM Jamie Nguyen <jamien@xxxxxxxxxx> wrote:
>
> The BIOS Data ACPI Table (BDAT) points to a firmware data structure that
> carries memory training results and other boot-time data. The table is
> only a pointer: /sys/firmware/acpi/tables/BDAT holds the ACPI header and
> a Generic Address Structure, and the data itself lives in reserved
> memory.
>
> Expose the data as /sys/firmware/acpi/tables/data/BDAT, as is already
> done for BERT and CCEL. Unlike those tables, BDAT carries no length, so
> check the "BDATHEAD" signature at the start of the data structure and
> take the size from its BiosDataStructSize field. Reject sizes smaller
> than that header, and document the new file in Documentation/ABI.
>
> The BDAT specification is published by the UEFI Forum [1].
>
> Link: https://uefi.org/sites/default/files/resources/BDAT_Spec_v4_0_9%20%282%29.pdf # [1]
> Assisted-by: LLM
> Signed-off-by: Jamie Nguyen <jamien@xxxxxxxxxx>
> ---
> Tested on an arm64 server (64K pages):
>
> - The file matches a /dev/mem dump of the data region taken in the same
> boot, byte for byte, and decodes with valid CRCs.
> - With lockdown=integrity, /dev/mem is refused and the file still reads.
> - Malformed BDAT tables loaded via initrd table upgrade (test-only change
> adding BDAT to table_sigs[]) are rejected without creating a file: no
> "BDATHEAD" signature, size below the header, non-memory address space,
> zero address, and a table shorter than struct acpi_table_bdat.

Please see the Sashiko feedback on this patch:

https://sashiko.dev/#/patchset/20261009232955.866131-1-jamien%40nvidia.com

and let me know what you think about it.

Thanks!

> Documentation/ABI/testing/sysfs-firmware-acpi | 12 +++++
> drivers/acpi/sysfs.c | 49 +++++++++++++++++++
> 2 files changed, 61 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
> index fa33dda331f2440..5fb50a72d468f5c 100644
> --- a/Documentation/ABI/testing/sysfs-firmware-acpi
> +++ b/Documentation/ABI/testing/sysfs-firmware-acpi
> @@ -275,3 +275,15 @@ Description:
>
> remote_region_id: ID associated with access by agents
> non-local to this range of addresses.
> +
> +What: /sys/firmware/acpi/tables/data/BDAT
> +Date: October 2026
> +Contact: Jamie Nguyen <jamien@xxxxxxxxxx>
> +Description:
> + The BIOS data structure referenced by the ACPI BDAT (BIOS Data
> + ACPI Table). It starts with a "BDATHEAD" header and holds data
> + published by firmware, such as memory training results. The
> + file size is the structure size given in that header.
> +
> + The format is defined by the BDAT Interface Specification,
> + published by the UEFI Forum. The file is readable by root only.
> diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
> index dd4a99f09efea65..9d02733013996be 100644
> --- a/drivers/acpi/sysfs.c
> +++ b/drivers/acpi/sysfs.c
> @@ -473,12 +473,61 @@ static int acpi_ccel_data_init(void *th, struct acpi_data_attr *data_attr)
> return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
> }
>
> +/*
> + * The BDAT table only holds the address of the BIOS data structure. Its
> + * size is in the structure's own header ("BDAT Interface Specification"
> + * v4.0, section 4).
> + */
> +struct acpi_bdat_data_header {
> + char signature[8]; /* "BDATHEAD" */
> + u32 size; /* whole structure, including this header */
> + u16 crc16;
> + u16 reserved;
> + u16 primary_version;
> + u16 secondary_version;
> + u32 oem_offset;
> + u32 reserved1;
> + u32 reserved2;
> +} __packed;
> +
> +static int acpi_bdat_data_init(void *th, struct acpi_data_attr *data_attr)
> +{
> + struct acpi_table_bdat *bdat = th;
> + struct acpi_bdat_data_header hdr;
> + void __iomem *base;
> +
> + if (bdat->header.length < sizeof(struct acpi_table_bdat) ||
> + bdat->gas.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY ||
> + !bdat->gas.address)
> + goto err;
> +
> + base = acpi_os_map_iomem(bdat->gas.address, sizeof(hdr));
> + if (!base)
> + goto err;
> + memcpy_fromio(&hdr, base, sizeof(hdr));
> + acpi_os_unmap_iomem(base, sizeof(hdr));
> +
> + if (memcmp(hdr.signature, "BDATHEAD", sizeof(hdr.signature)) ||
> + hdr.size < sizeof(hdr))
> + goto err;
> +
> + data_attr->addr = bdat->gas.address;
> + data_attr->attr.size = hdr.size;
> +
> + return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
> +
> +err:
> + kfree(data_attr);
> + return -EINVAL;
> +}
> +
> static struct acpi_data_obj {
> char *name;
> int (*fn)(void *, struct acpi_data_attr *);
> } acpi_data_objs[] = {
> { ACPI_SIG_BERT, acpi_bert_data_init },
> { ACPI_SIG_CCEL, acpi_ccel_data_init },
> + { ACPI_SIG_BDAT, acpi_bdat_data_init },
> };
>
> #define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs)
>
> base-commit: af32da41b0327b9c6a37856ba82b6760d6c8d10e
> --
> 2.43.0
>