From: Corey Minyard <cminy...@mvista.com> There was no way to directly add a table entry to the SMBIOS table, even though the BIOS supports this. So add a function to do this. This is in preparation for the IPMI handler adding it's SMBIOS table entry.
Signed-off-by: Corey Minyard <cminy...@mvista.com> --- hw/i386/smbios.c | 153 +++++++++++++++++++++++++++++++---------------- include/hw/i386/smbios.h | 8 +++ 2 files changed, 109 insertions(+), 52 deletions(-) diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index 1341e02..68ad0be 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -831,6 +831,92 @@ static void smbios_entry_point_setup(void) ep.structure_table_address = cpu_to_le32(0); } +struct smbios_table_entry { + void *data; + int size; + bool append_zeros; + QSLIST_ENTRY(smbios_table_entry) next; +}; + +static QSLIST_HEAD(, smbios_table_entry) table_entries; + +void smbios_add_table_entry(void *data, int size, bool append_zeros) +{ + struct smbios_table_entry *e = g_malloc(sizeof(*e)); + + e->data = g_malloc(size); + memcpy(e->data, data, size); + e->size = size; + e->append_zeros = append_zeros; + QSLIST_INSERT_HEAD(&table_entries, e, next); +} + +static void smbios_table_entry_append(void *data, int size, bool append_zeros) +{ + struct smbios_structure_header *header; + struct smbios_table *table; /* legacy mode only */ + + /* + * NOTE: standard double '\0' terminator expected, per smbios spec. + * (except in legacy mode, where the second '\0' is implicit and + * will be inserted by the BIOS). + */ + if (append_zeros) { + size += 2; + } + smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size); + header = (struct smbios_structure_header *)(smbios_tables + + smbios_tables_len); + + memcpy(header, data, size); + if (append_zeros) { + memset(smbios_tables + smbios_tables_len + size - 2, 0, 2); + } + + if (test_bit(header->type, have_fields_bitmap)) { + error_report("can't load type %d struct, fields already specified!", + header->type); + exit(1); + } + set_bit(header->type, have_binfile_bitmap); + + if (header->type == 4) { + smbios_type4_count++; + } + + smbios_tables_len += size; + if (size > smbios_table_max) { + smbios_table_max = size; + } + smbios_table_cnt++; + + /* add a copy of the newly loaded blob to legacy smbios_entries */ + /* NOTE: This code runs before smbios_set_defaults(), so we don't + * yet know which mode (legacy vs. aggregate-table) will be + * required. We therefore add the binary blob to both legacy + * (smbios_entries) and aggregate (smbios_tables) tables, and + * delete the one we don't need from smbios_set_defaults(), + * once we know which machine version has been requested. + */ + if (!smbios_entries) { + smbios_entries_len = sizeof(uint16_t); + smbios_entries = g_malloc0(smbios_entries_len); + } + if (append_zeros) { + size -= 1; /* The BIOS adds the second zero in legacy mode. */ + } + smbios_entries = g_realloc(smbios_entries, smbios_entries_len + + size + sizeof(*table)); + table = (struct smbios_table *)(smbios_entries + smbios_entries_len); + table->header.type = SMBIOS_TABLE_ENTRY; + table->header.length = cpu_to_le16(sizeof(*table) + size); + memcpy(table->data, header, size); + smbios_entries_len += sizeof(*table) + size; + (*(uint16_t *)smbios_entries) = + cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); + /* end: add a copy of the newly loaded blob to legacy smbios_entries */ +} + void smbios_get_tables(uint8_t **tables, size_t *tables_len, uint8_t **anchor, size_t *anchor_len) { @@ -875,6 +961,16 @@ void smbios_get_tables(uint8_t **tables, size_t *tables_len, } smbios_build_type_32_table(); + + while (!QSLIST_EMPTY(&table_entries)) { + struct smbios_table_entry *e = QSLIST_FIRST(&table_entries); + + QSLIST_REMOVE_HEAD(&table_entries, next); + smbios_table_entry_append(e->data, e->size, e->append_zeros); + g_free(e->data); + g_free(e); + } + smbios_build_type_127_table(); smbios_validate_table(); @@ -907,9 +1003,8 @@ void smbios_entry_add(QemuOpts *opts) val = qemu_opt_get(opts, "file"); if (val) { - struct smbios_structure_header *header; int size; - struct smbios_table *table; /* legacy mode only */ + uint8_t *data; qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err); if (local_err) { @@ -923,60 +1018,14 @@ void smbios_entry_add(QemuOpts *opts) exit(1); } - /* - * NOTE: standard double '\0' terminator expected, per smbios spec. - * (except in legacy mode, where the second '\0' is implicit and - * will be inserted by the BIOS). - */ - smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size); - header = (struct smbios_structure_header *)(smbios_tables + - smbios_tables_len); - - if (load_image(val, (uint8_t *)header) != size) { + data = g_malloc(size); + if (load_image(val, data) != size) { error_report("Failed to load SMBIOS file %s", val); exit(1); } - if (test_bit(header->type, have_fields_bitmap)) { - error_report("can't load type %d struct, fields already specified!", - header->type); - exit(1); - } - set_bit(header->type, have_binfile_bitmap); - - if (header->type == 4) { - smbios_type4_count++; - } - - smbios_tables_len += size; - if (size > smbios_table_max) { - smbios_table_max = size; - } - smbios_table_cnt++; - - /* add a copy of the newly loaded blob to legacy smbios_entries */ - /* NOTE: This code runs before smbios_set_defaults(), so we don't - * yet know which mode (legacy vs. aggregate-table) will be - * required. We therefore add the binary blob to both legacy - * (smbios_entries) and aggregate (smbios_tables) tables, and - * delete the one we don't need from smbios_set_defaults(), - * once we know which machine version has been requested. - */ - if (!smbios_entries) { - smbios_entries_len = sizeof(uint16_t); - smbios_entries = g_malloc0(smbios_entries_len); - } - smbios_entries = g_realloc(smbios_entries, smbios_entries_len + - size + sizeof(*table)); - table = (struct smbios_table *)(smbios_entries + smbios_entries_len); - table->header.type = SMBIOS_TABLE_ENTRY; - table->header.length = cpu_to_le16(sizeof(*table) + size); - memcpy(table->data, header, size); - smbios_entries_len += sizeof(*table) + size; - (*(uint16_t *)smbios_entries) = - cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); - /* end: add a copy of the newly loaded blob to legacy smbios_entries */ - + smbios_table_entry_append(data, size, false); + g_free(data); return; } diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h index d2850be..9f3e920 100644 --- a/include/hw/i386/smbios.h +++ b/include/hw/i386/smbios.h @@ -27,6 +27,14 @@ void smbios_get_tables(uint8_t **tables, size_t *tables_len, uint8_t **anchor, size_t *anchor_len); /* + * Add an external entry to the SMBIOS table. Can only be called + * from a registered device table handler. This will store the + * given data in a queue and append it when the SMBIOS table is + * built. + */ +void smbios_add_table_entry(void *data, int size, bool append_zeros); + +/* * SMBIOS spec defined tables */ -- 1.8.3.1