From: Simon Glass <sjg@chromium.org> QEMU creates ACPI tables but doesn't include FPDT (Firmware Performance Data Table). Add FPDT generation in qfw_acpi.c following the same pattern as BGRT. Move the acpi_write_fpdt() function from acpi_table.c to acpi_extra.c so that is available even when CONFIG_ACPIGEN is disabled. This allows QEMU x86_64 builds to provide firmware boot timing information to the operating system. Disable this for qemu-riscv64_smode_acpi as it is near the code-size limit. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/qfw/qfw_acpi.c | 10 +++++ lib/acpi/acpi_extra.c | 92 ++++++++++++++++++++++++++++++++++++++++++ lib/acpi/acpi_table.c | 90 ----------------------------------------- 3 files changed, 102 insertions(+), 90 deletions(-) diff --git a/drivers/qfw/qfw_acpi.c b/drivers/qfw/qfw_acpi.c index 916a59be7fb..7f7dba73155 100644 --- a/drivers/qfw/qfw_acpi.c +++ b/drivers/qfw/qfw_acpi.c @@ -8,6 +8,7 @@ #include <abuf.h> #include <bloblist.h> +#include <bootstage.h> #include <errno.h> #include <malloc.h> #include <mapmem.h> @@ -256,6 +257,15 @@ out: return addr; } + if (!IS_ENABLED(CONFIG_TARGET_QEMU_VIRT)) { + ret = acpi_write_fpdt(ctx, + bootstage_get_time(BOOTSTAGE_ID_START_UBOOT_F)); + if (ret) { + printf("error: failed to write FPDT (err=%dE)\n", ret); + return addr; + } + } + return addr; } diff --git a/lib/acpi/acpi_extra.c b/lib/acpi/acpi_extra.c index 709f64305b5..09b8a251ca2 100644 --- a/lib/acpi/acpi_extra.c +++ b/lib/acpi/acpi_extra.c @@ -7,9 +7,11 @@ #define LOG_CATEGORY LOGC_ACPI +#include <bootstage.h> #include <dm.h> #include <efi_loader.h> #include <mapmem.h> +#include <tables_csum.h> #include <video.h> #include <acpi/acpi_table.h> @@ -87,3 +89,93 @@ int acpi_write_bgrt(struct acpi_ctx *ctx) return 0; } + +int acpi_write_fpdt(struct acpi_ctx *ctx, u64 uboot_start) +{ + struct acpi_fpdt *fpdt; + struct acpi_fpdt_boot *rec; + struct acpi_table_header *header; + u64 current_time; + int size; + + fpdt = ctx->current; + header = &fpdt->header; + + /* Calculate total size: FPDT header + boot performance record */ + size = sizeof(struct acpi_fpdt) + sizeof(struct acpi_fpdt_boot); + + memset(fpdt, '\0', size); + + /* Fill out FPDT header */ + acpi_fill_header(header, "FPDT"); + header->length = size; + header->revision = 1; /* ACPI 6.4+: 1 */ + + /* Add boot performance record right after FPDT header */ + rec = (struct acpi_fpdt_boot *)(fpdt + 1); + + /* Fill in record header */ + rec->hdr.type = FPDT_REC_BOOT; + rec->hdr.length = sizeof(struct acpi_fpdt_boot); + rec->hdr.revision = 2; /* FPDT Boot Performance Record revision */ + + /* Fill in timing data */ + current_time = timer_get_boot_us(); + rec->reset_end = uboot_start; + rec->loader_start = current_time; + rec->loader_exec = current_time; + rec->ebs_entry = current_time; + rec->ebs_exit = current_time; + + header->checksum = table_compute_checksum(fpdt, header->length); + + acpi_inc_align(ctx, size); + acpi_add_table(ctx, fpdt); + + return 0; +} + +struct acpi_fpdt_boot *acpi_get_fpdt_boot(void) +{ + struct acpi_table_header *header; + struct acpi_fpdt *fpdt; + + header = acpi_find_table("FPDT"); + if (!header) + return NULL; + + fpdt = (struct acpi_fpdt *)header; + return (struct acpi_fpdt_boot *)(fpdt + 1); +} + +int acpi_fix_fpdt_checksum(void) +{ + struct acpi_table_header *header; + + header = acpi_find_table("FPDT"); + if (!header) + return -ENOENT; + + header->checksum = 0; + header->checksum = table_compute_checksum(header, header->length); + + return 0; +} + +void acpi_final_fpdt(void) +{ + struct acpi_fpdt_boot *fpdt; + + if (IS_ENABLED(CONFIG_TARGET_QEMU_VIRT)) + return; + + fpdt = acpi_get_fpdt_boot(); + if (fpdt) { + u64 time; + + time = timer_get_boot_us(); + fpdt->ebs_entry = time; + fpdt->ebs_exit = time; + acpi_fix_fpdt_checksum(); + } +} diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 99251176d09..94e6647b666 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -715,96 +715,6 @@ static int acpi_create_bgrt(struct acpi_ctx *ctx, ACPI_WRITER(6bgrt, "BGRT", acpi_create_bgrt, 0); #endif -int acpi_write_fpdt(struct acpi_ctx *ctx, u64 uboot_start) -{ - struct acpi_fpdt *fpdt; - struct acpi_fpdt_boot *rec; - struct acpi_table_header *header; - u64 current_time; - int size; - - fpdt = ctx->current; - header = &fpdt->header; - - /* Calculate total size: FPDT header + boot performance record */ - size = sizeof(struct acpi_fpdt) + sizeof(struct acpi_fpdt_boot); - - memset(fpdt, '\0', size); - - /* Fill out FPDT header */ - acpi_fill_header(header, "FPDT"); - header->length = size; - header->revision = acpi_get_table_revision(ACPITAB_FPDT); - - /* Add boot performance record right after FPDT header */ - rec = (struct acpi_fpdt_boot *)(fpdt + 1); - - /* Fill in record header */ - rec->hdr.type = FPDT_REC_BOOT; - rec->hdr.length = sizeof(struct acpi_fpdt_boot); - rec->hdr.revision = 2; /* FPDT Boot Performance Record revision */ - - /* Fill in timing data */ - current_time = timer_get_boot_us(); - rec->reset_end = uboot_start; - rec->loader_start = current_time; - rec->loader_exec = current_time; - rec->ebs_entry = current_time; - rec->ebs_exit = current_time; - - header->checksum = table_compute_checksum(fpdt, header->length); - - acpi_inc_align(ctx, size); - acpi_add_table(ctx, fpdt); - - return 0; -} - -struct acpi_fpdt_boot *acpi_get_fpdt_boot(void) -{ - struct acpi_table_header *header; - struct acpi_fpdt *fpdt; - - header = acpi_find_table("FPDT"); - if (!header) - return NULL; - - fpdt = (struct acpi_fpdt *)header; - return (struct acpi_fpdt_boot *)(fpdt + 1); -} - -int acpi_fix_fpdt_checksum(void) -{ - struct acpi_table_header *header; - - header = acpi_find_table("FPDT"); - if (!header) - return -ENOENT; - - header->checksum = 0; - header->checksum = table_compute_checksum(header, header->length); - - return 0; -} - -void acpi_final_fpdt(void) -{ - struct acpi_fpdt_boot *fpdt; - - if (IS_ENABLED(CONFIG_TARGET_QEMU_VIRT)) - return; - - fpdt = acpi_get_fpdt_boot(); - if (fpdt) { - u64 time; - - time = timer_get_boot_us(); - fpdt->ebs_entry = time; - fpdt->ebs_exit = time; - acpi_fix_fpdt_checksum(); - } -} - /* this board lacks the bootstage timer */ #ifndef CONFIG_TARGET_QEMU_VIRT -- 2.43.0