|
@@ -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;
|
|
|
}
|