diff options
-rw-r--r-- | hw/smbios/smbios.c | 181 |
1 files changed, 93 insertions, 88 deletions
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 9f9087601c..aab4ffb4cb 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -57,6 +57,14 @@ static size_t smbios_entries_len; static bool smbios_uuid_encoded = true; /* end: legacy structures & constants for <= 2.0 machines */ +/* + * SMBIOS tables provided by user with '-smbios file=<foo>' option + */ +uint8_t *usr_blobs; +size_t usr_blobs_len; +static GArray *usr_blobs_sizes; +static unsigned usr_table_max; +static unsigned usr_table_cnt; uint8_t *smbios_tables; size_t smbios_tables_len; @@ -67,7 +75,6 @@ static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32; static SmbiosEntryPoint ep; static int smbios_type4_count = 0; -static bool smbios_immutable; static bool smbios_have_defaults; static uint32_t smbios_cpuid_version, smbios_cpuid_features; @@ -632,9 +639,8 @@ static void smbios_build_type_1_fields(void) uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length) { - /* drop unwanted version of command-line file blob(s) */ - g_free(smbios_tables); - smbios_tables = NULL; + int i; + size_t usr_offset; /* also complain if fields were given for types > 1 */ if (find_next_bit(have_fields_bitmap, @@ -644,12 +650,33 @@ uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length) exit(1); } - if (!smbios_immutable) { - smbios_build_type_0_fields(); - smbios_build_type_1_fields(); - smbios_validate_table(expected_t4_count); - smbios_immutable = true; + g_free(smbios_entries); + smbios_entries_len = sizeof(uint16_t); + smbios_entries = g_malloc0(smbios_entries_len); + + for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len; + i++) + { + struct smbios_table *table; + struct smbios_structure_header *header; + size_t size = g_array_index(usr_blobs_sizes, size_t, i); + + header = (struct smbios_structure_header *)(usr_blobs + usr_offset); + 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); + usr_offset += size; } + + smbios_build_type_0_fields(); + smbios_build_type_1_fields(); + smbios_validate_table(expected_t4_count); *length = smbios_entries_len; return smbios_entries; } @@ -1217,68 +1244,68 @@ void smbios_get_tables(MachineState *ms, { unsigned i, dimm_cnt, offset; - /* drop unwanted (legacy) version of command-line file blob(s) */ - g_free(smbios_entries); - smbios_entries = NULL; + g_free(smbios_tables); + smbios_tables = g_memdup2(usr_blobs, usr_blobs_len); + smbios_tables_len = usr_blobs_len; + smbios_table_max = usr_table_max; + smbios_table_cnt = usr_table_cnt; - if (!smbios_immutable) { - smbios_build_type_0_table(); - smbios_build_type_1_table(); - smbios_build_type_2_table(); - smbios_build_type_3_table(); + smbios_build_type_0_table(); + smbios_build_type_1_table(); + smbios_build_type_2_table(); + smbios_build_type_3_table(); - assert(ms->smp.sockets >= 1); + assert(ms->smp.sockets >= 1); - for (i = 0; i < ms->smp.sockets; i++) { - smbios_build_type_4_table(ms, i); - } + for (i = 0; i < ms->smp.sockets; i++) { + smbios_build_type_4_table(ms, i); + } - smbios_build_type_8_table(); - smbios_build_type_9_table(errp); - smbios_build_type_11_table(); + smbios_build_type_8_table(); + smbios_build_type_9_table(errp); + smbios_build_type_11_table(); #define MAX_DIMM_SZ (16 * GiB) #define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \ : ((current_machine->ram_size - 1) % MAX_DIMM_SZ) + 1) - dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ; + dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) / + MAX_DIMM_SZ; - /* - * The offset determines if we need to keep additional space between - * table 17 and table 19 header handle numbers so that they do - * not overlap. For example, for a VM with larger than 8 TB guest - * memory and DIMM like chunks of 16 GiB, the default space between - * the two tables (T19_BASE - T17_BASE = 512) is not enough. - */ - offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \ - dimm_cnt - (T19_BASE - T17_BASE) : 0; + /* + * The offset determines if we need to keep additional space between + * table 17 and table 19 header handle numbers so that they do + * not overlap. For example, for a VM with larger than 8 TB guest + * memory and DIMM like chunks of 16 GiB, the default space between + * the two tables (T19_BASE - T17_BASE = 512) is not enough. + */ + offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \ + dimm_cnt - (T19_BASE - T17_BASE) : 0; - smbios_build_type_16_table(dimm_cnt); + smbios_build_type_16_table(dimm_cnt); - for (i = 0; i < dimm_cnt; i++) { - smbios_build_type_17_table(i, GET_DIMM_SZ); - } + for (i = 0; i < dimm_cnt; i++) { + smbios_build_type_17_table(i, GET_DIMM_SZ); + } - for (i = 0; i < mem_array_size; i++) { - smbios_build_type_19_table(i, offset, mem_array[i].address, - mem_array[i].length); - } + for (i = 0; i < mem_array_size; i++) { + smbios_build_type_19_table(i, offset, mem_array[i].address, + mem_array[i].length); + } - /* - * make sure 16 bit handle numbers in the headers of tables 19 - * and 32 do not overlap. - */ - assert((mem_array_size + offset) < (T32_BASE - T19_BASE)); + /* + * make sure 16 bit handle numbers in the headers of tables 19 + * and 32 do not overlap. + */ + assert((mem_array_size + offset) < (T32_BASE - T19_BASE)); - smbios_build_type_32_table(); - smbios_build_type_38_table(); - smbios_build_type_41_table(errp); - smbios_build_type_127_table(); + smbios_build_type_32_table(); + smbios_build_type_38_table(); + smbios_build_type_41_table(errp); + smbios_build_type_127_table(); - smbios_validate_table(ms->smp.sockets); - smbios_entry_point_setup(); - smbios_immutable = true; - } + smbios_validate_table(ms->smp.sockets); + smbios_entry_point_setup(); /* return tables blob and entry point (anchor), and their sizes */ *tables = smbios_tables; @@ -1378,13 +1405,10 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) { const char *val; - assert(!smbios_immutable); - val = qemu_opt_get(opts, "file"); if (val) { struct smbios_structure_header *header; - int size; - struct smbios_table *table; /* legacy mode only */ + size_t size; if (!qemu_opts_validate(opts, qemu_smbios_file_opts, errp)) { return; @@ -1401,9 +1425,9 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) * (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); + usr_blobs = g_realloc(usr_blobs, usr_blobs_len + size); + header = (struct smbios_structure_header *)(usr_blobs + + usr_blobs_len); if (load_image_size(val, (uint8_t *)header, size) != size) { error_setg(errp, "Failed to load SMBIOS file %s", val); @@ -1424,34 +1448,15 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) smbios_type4_count++; } - smbios_tables_len += size; - if (size > smbios_table_max) { - smbios_table_max = size; + if (!usr_blobs_sizes) { + usr_blobs_sizes = g_array_new(false, false, sizeof(size_t)); } - 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); + g_array_append_val(usr_blobs_sizes, size); + usr_blobs_len += size; + if (size > usr_table_max) { + usr_table_max = size; } - 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 */ + usr_table_cnt++; return; } |