
From: Simon Glass <sjg@chromium.org> Add support for creating a BGRT so that Linux will show a logo on startup and shutdown. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/acpi/acpi_table.h | 13 ++++- lib/acpi/Makefile | 1 + lib/acpi/acpi_extra.c | 103 ++++++++++++++++++++++++++++++++++++++ lib/acpi/acpi_table.c | 11 ++++ test/dm/acpi.c | 62 +++++++++++++++++++++++ 5 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 lib/acpi/acpi_extra.c diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index 7a75e3afc49..850cb8db816 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -750,7 +750,7 @@ struct acpi_gtdt { * * See ACPI Spec v6.3 section 5.2.22 for details */ -struct acpi_bgrt { +struct __packed acpi_bgrt { struct acpi_table_header header; u16 version; u8 status; @@ -758,7 +758,7 @@ struct acpi_bgrt { u64 addr; u32 offset_x; u32 offset_y; -} __packed; +}; /* Types for PPTT */ #define ACPI_PPTT_TYPE_PROC 0 @@ -1298,6 +1298,15 @@ void acpi_update_checksum(struct acpi_table_header *header); */ void *acpi_get_end(void); +/** + * acpi_write_bgrt() - Write a BGRT + * + * @ctx: ACPI context + * Return 0 if OK, -ENOTSUPP if there is no video-device or not log, -EIO if + * the video device could not be probed, -ENOENT if there is no logo + */ +int acpi_write_bgrt(struct acpi_ctx *ctx); + #endif /* !__ACPI__*/ #include <asm/acpi_table.h> diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile index 56009fb222e..a4850fcc108 100644 --- a/lib/acpi/Makefile +++ b/lib/acpi/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpigen.o obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi_device.o obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi_dp.o obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi_table.o +obj-y += acpi_extra.o obj-y += acpi_writer.o obj-y += bgrt_image.o diff --git a/lib/acpi/acpi_extra.c b/lib/acpi/acpi_extra.c new file mode 100644 index 00000000000..7620f953add --- /dev/null +++ b/lib/acpi/acpi_extra.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generation of tables for particular device types + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#define LOG_CATEGORY LOGC_ACPI + +#include <dm.h> +#include <efi_loader.h> +#include <mapmem.h> +#include <video.h> +#include <acpi/acpi_table.h> + +#define BGRT_DECL(_name) \ + extern u8 __bgrt_ ## _name ## _begin[]; \ + extern u8 __bgrt_ ## _name ## _end[] + +#define BGRT_START(_name) __bgrt_ ## _name ## _begin +#define BGRT_END(_name) __bgrt_ ## _name ## _end + +BGRT_DECL(image); + +static void *bgrt_get_image(int *sizep) +{ + if (sizep) + *sizep = BGRT_END(image) - BGRT_START(image); + + return BGRT_START(image); +} + +int acpi_write_bgrt(struct acpi_ctx *ctx) +{ + struct udevice *dev; + struct acpi_bgrt *bgrt; + efi_status_t eret; + void *logo, *buf; + bool have_video; + int size; + + /* If video is available, use the screen size to centre the logo */ + have_video = !uclass_first_device_err(UCLASS_VIDEO, &dev); + + logo = bgrt_get_image(&size); + + /* If there's no logo data, there's nothing to report */ + if (!logo) + return -ENOENT; + + bgrt = ctx->current; + ctx->tab_start = ctx->current; + memset(bgrt, '\0', sizeof(struct acpi_table_iort)); + + acpi_fill_header(&bgrt->header, "BGRT"); + bgrt->version = 1; + + /* Status: Bit 0 (Displayed) = 1, Bits 1-2 (Orientation) = 0 */ + bgrt->status = 1; + + /* Image Type: 0 = Bitmap */ + bgrt->image_type = 0; + + /* Mark space used for tables */ + eret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size, &buf); + if (eret) + return -ENOMEM; + memcpy(buf, logo, size); + + /* The physical address of the in-memory logo bitmap */ + bgrt->addr = nomap_to_sysmem(buf); + + /* Calculate offsets to center the logo on the screen */ + bgrt->offset_x = 0; + bgrt->offset_y = 0; + + /* + * centering is disabled for now, since it seems to be done by the + * startup code + */ + if (0 && IS_ENABLED(CONFIG_VIDEO) && have_video) { + struct video_priv *priv = dev_get_uclass_priv(dev); + ulong width, height; + uint bpix; + + video_bmp_get_info(logo, &width, &height, &bpix); + + if (priv->xsize > width) + bgrt->offset_x = (priv->xsize - width) / 2; + if (priv->ysize > height) + bgrt->offset_y = (priv->ysize - height) / 2; + } + acpi_inc(ctx, sizeof(*bgrt)); + + /* Calculate length and checksum */ + bgrt->header.length = (ulong)ctx->current - (ulong)bgrt; + acpi_update_checksum(&bgrt->header); + log_debug("BGRT at %p length %x logo copied to bs-data at %p\n", bgrt, + bgrt->header.length, buf); + acpi_add_table(ctx, bgrt); + + return 0; +} diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 8423786fff3..f2dadd792bd 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -699,3 +699,14 @@ static int alloc_write_acpi_tables(void) } EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, alloc_write_acpi_tables); + +#ifdef CONFIG_EFI_LOADER +static int acpi_create_bgrt(struct acpi_ctx *ctx, + const struct acpi_writer *entry) +{ + acpi_write_bgrt(ctx); + + return 0; +} +ACPI_WRITER(6bgrt, "BGRT", acpi_create_bgrt, 0); +#endif diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 6c157de0e3b..db9c13a2af8 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -6,8 +6,10 @@ * Written by Simon Glass <sjg@chromium.org> */ +#include <bloblist.h> #include <console.h> #include <dm.h> +#include <efi_log.h> #include <malloc.h> #include <mapmem.h> #include <tables_csum.h> @@ -899,3 +901,63 @@ static int dm_test_acpi_get_end(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_get_end, 0); + +/* Test generating the BGRT */ +static int dm_test_acpi_bgrt(struct unit_test_state *uts) +{ + struct efil_hdr *hdr = bloblist_find(BLOBLISTT_EFI_LOG, 0); + struct acpi_table_header *table; + struct efil_rec_hdr *rec_hdr; + struct acpi_ctx ctx; + ulong acpi_start, addr; + struct acpi_bgrt *bgrt; + void *buf; + + /* Keep reference to original ACPI tables */ + acpi_start = gd_acpi_start(); + + /* Setup new ACPI tables */ + addr = 0; + buf = map_sysmem(addr, BUF_SIZE); + ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr)); + + if (IS_ENABLED(CONFIG_EFI_LOG)) + ut_assertok(efi_log_reset()); + + ut_assertok(acpi_write_bgrt(&ctx)); + table = acpi_find_table("BGRT"); + ut_assertnonnull(table); + bgrt = (struct acpi_bgrt *)table; + + ut_asserteq(sizeof(*bgrt), table->length); + ut_asserteq_strn("BGRT", table->signature); + ut_asserteq(1, bgrt->version); + ut_asserteq(1, bgrt->status); + ut_asserteq(0, bgrt->image_type); + ut_asserteq(0, bgrt->offset_x); + ut_asserteq(0, bgrt->offset_y); + + if (!IS_ENABLED(CONFIG_EFI_LOG)) + return 0; + + /* check the BGRT has been allocated in the EFI pool */ + for (rec_hdr = (void *)hdr + sizeof(*hdr); + (void *)rec_hdr - (void *)hdr < hdr->upto; + rec_hdr = (void *)rec_hdr + rec_hdr->size) { + void *start = (void *)rec_hdr + sizeof(struct efil_rec_hdr); + + switch (rec_hdr->tag) { + case EFILT_ALLOCATE_POOL: { + struct efil_allocate_pool *rec = start; + + ut_asserteq(bgrt->addr, nomap_to_sysmem(rec->e_buffer)); + break; + } + default: + break; + } + } + + return 0; +} +DM_TEST(dm_test_acpi_bgrt, UTF_SCAN_FDT); -- 2.43.0