diff options
Diffstat (limited to 'arch/x86/lib/tables.c')
-rw-r--r-- | arch/x86/lib/tables.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c new file mode 100644 index 00000000000..44fe80c5224 --- /dev/null +++ b/arch/x86/lib/tables.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + */ + +#define LOG_CATEGORY LOGC_ACPI + +#include <bloblist.h> +#include <log.h> +#include <malloc.h> +#include <smbios.h> +#include <acpi/acpi_table.h> +#include <asm/global_data.h> +#include <asm/sfi.h> +#include <asm/mpspec.h> +#include <asm/tables.h> +#include <asm/coreboot_tables.h> +#include <linux/log2.h> +#include <linux/sizes.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * Function prototype to write a specific configuration table + * + * @addr: start address to write the table + * @return: end address of the table + */ +typedef ulong (*table_write)(ulong addr); + +/** + * struct table_info - Information about each table to write + * + * @name: Name of table (for debugging) + * @write: Function to call to write this table + * @tag: Bloblist tag if using CONFIG_BLOBLIST_TABLES + * @size: Maximum table size + * @align: Table alignment in bytes + */ +struct table_info { + const char *name; + table_write write; + enum bloblist_tag_t tag; + int size; + int align; +}; + +static struct table_info table_list[] = { +#ifdef CONFIG_GENERATE_PIRQ_TABLE + { "pirq", write_pirq_routing_table }, +#endif +#ifdef CONFIG_GENERATE_SFI_TABLE + { "sfi", write_sfi_table, }, +#endif +#ifdef CONFIG_GENERATE_MP_TABLE + { "mp", write_mp_table, }, +#endif + /* + * tables which can go in the bloblist must be last in this list, so + * that the calculation of gd->table_end works properly + */ +#ifdef CONFIG_GENERATE_ACPI_TABLE + { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, SZ_64K, SZ_4K}, +#endif +#ifdef CONFIG_GENERATE_SMBIOS_TABLE + /* + * align this to a 4K boundary, since UPL adds a reserved-memory node + * for it + */ + { "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, SZ_4K, SZ_4K}, +#endif +}; + +void table_fill_string(char *dest, const char *src, size_t n, char pad) +{ + int start, len; + int i; + + strncpy(dest, src, n); + + /* Fill the remaining bytes with pad */ + len = strlen(src); + start = len < n ? len : n; + for (i = start; i < n; i++) + dest[i] = pad; +} + +int write_tables(void) +{ + u32 high_table, table_size; + struct memory_area cfg_tables[ARRAY_SIZE(table_list) + 1]; + bool use_high = false; + u32 rom_addr; + int i; + + gd->arch.table_start = ROM_TABLE_ADDR; + rom_addr = gd->arch.table_start; + + debug("Writing tables to %x:\n", rom_addr); + for (i = 0; i < ARRAY_SIZE(table_list); i++) { + const struct table_info *table = &table_list[i]; + int size = table->size ? : CONFIG_ROM_TABLE_SIZE; + u32 rom_table_end; + + rom_addr = ALIGN(rom_addr, 16); + + if (!strcmp("smbios", table->name)) + gd->arch.smbios_start = rom_addr; + + if (IS_ENABLED(CONFIG_BLOBLIST_TABLES) && table->tag) { + if (!gd->arch.table_end) + gd->arch.table_end = rom_addr; + rom_addr = (ulong)bloblist_add(table->tag, size, + ilog2(table->align)); + if (!rom_addr) + return log_msg_ret("bloblist", -ENOBUFS); + + /* the bloblist is always in high memory */ + use_high = true; + if (!gd->arch.table_start_high) + gd->arch.table_start_high = rom_addr; + } + rom_table_end = table->write(rom_addr); + if (!rom_table_end) { + log_err("Can't create configuration table %d\n", i); + return -EINTR; + } + + if (IS_ENABLED(CONFIG_SEABIOS)) { + table_size = rom_table_end - rom_addr; + high_table = (u32)(ulong)high_table_malloc(table_size); + if (high_table) { + if (!table->write(high_table)) { + log_err("Can't create configuration table %d\n", + i); + return -EINTR; + } + + cfg_tables[i].start = high_table; + cfg_tables[i].size = table_size; + } else { + printf("%d: no memory for configuration tables\n", + i); + return -ENOSPC; + } + } + + debug("- wrote '%s' to %x, end %x\n", table->name, + rom_addr, rom_table_end); + if (rom_table_end - rom_addr > size) { + log_err("Out of space for configuration tables: need %x, have %x\n", + rom_table_end - rom_addr, size); + return log_msg_ret("bloblist", -ENOSPC); + } + rom_addr = rom_table_end; + } + + if (use_high) + gd->arch.table_end_high = rom_addr; + else + gd->arch.table_end = rom_addr; + + if (IS_ENABLED(CONFIG_SEABIOS)) { + /* make sure the last item is zero */ + cfg_tables[i].size = 0; + write_coreboot_table(CB_TABLE_ADDR, cfg_tables); + } + + if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) { + void *ptr = (void *)CONFIG_ROM_TABLE_ADDR; + + /* Write an RSDP pointing to the tables */ + if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) { + struct acpi_ctx *ctx = gd_acpi_ctx(); + + acpi_write_rsdp(ptr, ctx->rsdt, ctx->xsdt); + ptr += ALIGN(sizeof(struct acpi_rsdp), 16); + } + if (IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE)) { + void *smbios; + + smbios = bloblist_find(BLOBLISTT_SMBIOS_TABLES, 0); + if (!smbios) + return log_msg_ret("smbios", -ENOENT); + memcpy(ptr, smbios, sizeof(struct smbios_entry)); + } + } + + debug("- done writing tables\n"); + + return 0; +} |