// SPDX-License-Identifier: GPL-2.0+ /* * Handles writing the declared ACPI tables * * Copyright 2021 Google LLC */ #define LOG_CATEGORY LOGC_ACPI #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; int acpi_write_one(struct acpi_ctx *ctx, const struct acpi_writer *entry) { int ret; log_debug("%s: writing table '%s'\n", entry->name, entry->table); ctx->tab_start = ctx->current; ret = entry->h_write(ctx, entry); if (ret == -ENOENT) { log_debug("%s: Omitted due to being empty\n", entry->name); ret = 0; ctx->current = ctx->tab_start; /* drop the table */ return ret; } if (ret) return log_msg_ret("write", ret); if (entry->flags & ACPIWF_ALIGN64) acpi_align64(ctx); else acpi_align(ctx); /* Add the item to the internal list */ ret = acpi_add_other_item(ctx, entry, ctx->tab_start); if (ret) return log_msg_ret("add", ret); return 0; } #ifndef CONFIG_QEMU static int acpi_write_all(struct acpi_ctx *ctx) { const struct acpi_writer *writer = ll_entry_start(struct acpi_writer, acpi_writer); const int n_ents = ll_entry_count(struct acpi_writer, acpi_writer); const struct acpi_writer *entry; int ret; for (entry = writer; entry != writer + n_ents; entry++) { ret = acpi_write_one(ctx, entry); if (ret && ret != -ENOENT) return log_msg_ret("one", ret); } return 0; } /* * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c */ ulong write_acpi_tables(ulong start_addr) { struct acpi_ctx *ctx; ulong addr; int ret; ctx = malloc(sizeof(*ctx)); if (!ctx) return log_msg_ret("mem", -ENOMEM); log_debug("ACPI: Writing ACPI tables at %lx\n", start_addr); acpi_reset_items(); acpi_setup_ctx(ctx, start_addr); ret = acpi_write_all(ctx); if (ret) { log_err("Failed to write ACPI tables (err=%d)\n", ret); return log_msg_ret("write", -ENOMEM); } addr = map_to_sysmem(ctx->current); log_debug("ACPI current = %lx\n", addr); return addr; } int write_dev_tables(struct acpi_ctx *ctx, const struct acpi_writer *entry) { int ret; ret = acpi_write_dev_tables(ctx); if (ret) return log_msg_ret("write", ret); return 0; } ACPI_WRITER(8dev, NULL, write_dev_tables, 0); ulong acpi_get_rsdp_addr(void) { if (!gd->acpi_ctx) return 0; return map_to_sysmem(gd->acpi_ctx->rsdp); } #endif /* QEMU */ void acpi_setup_ctx(struct acpi_ctx *ctx, ulong start) { gd->acpi_ctx = ctx; memset(ctx, '\0', sizeof(*ctx)); /* Align ACPI tables to 16-byte boundary */ start = ALIGN(start, 16); ctx->base = map_sysmem(start, 0); ctx->current = ctx->base; gd_set_acpi_start(start); }