All of lore.kernel.org
 help / color / mirror / Atom feed
From: Igor Mammedov <imammedo@redhat.com>
To: qemu-devel@nongnu.org
Cc: imammedo@redhat.com, mst@redhat.com,
	Fiona Ebner <f.ebner@proxmox.com>,
	Ani Sinha <anisinha@redhat.com>
Subject: [PATCH v3 07/20] smbios: avoid mangling user provided tables
Date: Tue, 12 Mar 2024 17:10:37 +0100	[thread overview]
Message-ID: <20240312161050.2248814-8-imammedo@redhat.com> (raw)
In-Reply-To: <20240312161050.2248814-1-imammedo@redhat.com>

currently smbios_entry_add() preserves internally '-smbios type='
options but tables provided with '-smbios file=' are stored directly
into blob that eventually will be exposed to VM. And then later
QEMU adds default/'-smbios type' entries on top into the same blob.

It makes impossible to generate tables more than once, hence
'immutable' guard was used.
Make it possible to regenerate final blob by storing user provided
blobs into a dedicated area (usr_blobs) and then copy it when
composing final blob. Which also makes handling of -smbios
options consistent.

As side effect of this and previous commits there is no need to
generate legacy smbios_entries at the time options are parsed.
Instead compose smbios_entries on demand from  usr_blobs like
it is done for non-legacy SMBIOS tables.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
Reviewed-by: Ani Sinha <anisinha@redhat.com>
---
 hw/smbios/smbios.c | 179 +++++++++++++++++++++++----------------------
 1 file changed, 92 insertions(+), 87 deletions(-)

diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index c46fc93357..aa2cc5bdbd 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;
 
@@ -569,9 +576,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,
@@ -581,12 +587,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;
 }
@@ -1094,67 +1121,67 @@ 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_11_table();
+    smbios_build_type_8_table();
+    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;
@@ -1254,13 +1281,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;
@@ -1277,9 +1301,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);
@@ -1300,34 +1324,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;
     }
-- 
2.39.3



  parent reply	other threads:[~2024-03-12 16:14 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-12 16:10 [PATCH v3 00/20] Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 01/20] tests: smbios: make it possible to write SMBIOS only test Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 02/20] tests: smbios: add test for -smbios type=11 option Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 03/20] tests: smbios: add test for legacy mode CLI options Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 04/20] smbios: cleanup smbios_get_tables() from legacy handling Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 05/20] smbios: get rid of smbios_smp_sockets global Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 06/20] smbios: get rid of smbios_legacy global Igor Mammedov
2024-03-12 16:10 ` Igor Mammedov [this message]
2024-03-12 16:10 ` [PATCH v3 08/20] smbios: don't check type4 structures in legacy mode Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 09/20] smbios: add smbios_add_usr_blob_size() helper Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 10/20] smbios: rename/expose structures/bitmaps used by both legacy and modern code Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 11/20] smbios: build legacy mode code only for 'pc' machine Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 12/20] smbios: handle errors consistently Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 13/20] smbios: get rid of global smbios_ep_type Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 14/20] smbios: clear smbios_type4_count before building tables Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 15/20] smbios: extend smbios-entry-point-type with 'auto' value Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 16/20] smbios: in case of entry point is 'auto' try to build v2 tables 1st Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 17/20] smbios: error out when building type 4 table is not possible Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 18/20] tests: acpi/smbios: whitelist expected blobs Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 19/20] pc/q35: set SMBIOS entry point type to 'auto' by default Igor Mammedov
2024-03-12 16:10 ` [PATCH v3 20/20] tests: acpi: update expected SSDT.dimmpxm blob Igor Mammedov
2024-03-12 17:31 ` [PATCH v3 00/20] Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS Michael S. Tsirkin
2024-03-13  8:49   ` Igor Mammedov
2024-03-13  9:10     ` Michael S. Tsirkin
2024-03-13 22:51     ` Michael S. Tsirkin
2024-03-12 17:37 ` Michael S. Tsirkin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240312161050.2248814-8-imammedo@redhat.com \
    --to=imammedo@redhat.com \
    --cc=anisinha@redhat.com \
    --cc=f.ebner@proxmox.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.