On 7/23/25 12:23 PM, Michael S. Tsirkin wrote:

On Wed, Jul 23, 2025 at 12:16:08PM +0300, Daniil Tatianin wrote:
On 7/23/25 12:14 PM, Michael S. Tsirkin wrote:
On Wed, Jul 23, 2025 at 12:01:28PM +0300, Daniil Tatianin wrote:
This is useful to be able to indicate various supported features to the
guest, or freeze a specific version of SeaBIOS to prevent guest visible
changes between BIOS updates. This is currently not possible since the
extension bytes indicated by SeaBIOS are slightly different than those
QEMU sets by default.

Signed-off-by: Daniil Tatianin <d-tatia...@yandex-team.ru>
---
   hw/smbios/smbios.c           | 66 +++++++++++++++++++++++++++++++++---
   include/hw/firmware/smbios.h |  3 ++
   2 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index ad4cd6721e..73699e8a62 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -178,6 +178,14 @@ static const QemuOptDesc qemu_smbios_type0_opts[] = {
           .name = "uefi",
           .type = QEMU_OPT_BOOL,
           .help = "uefi support",
+    },{
+        .name = "extension_byte_1",
+        .type = QEMU_OPT_NUMBER,
+        .help = "BIOS characteristics extension byte 1"
+    },{
+        .name = "extension_byte_2",
+        .type = QEMU_OPT_NUMBER,
+        .help = "BIOS characteristics extension byte 2"
       },
       { /* end of list */ }
   };
@@ -572,10 +580,23 @@ static void smbios_build_type_0_table(void)
       t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
       t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
-    t->bios_characteristics_extension_bytes[0] = 0;
-    t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
-    if (smbios_type0.uefi) {
-        t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
+
+    if (smbios_type0.have_extension_bytes[0]) {
+        t->bios_characteristics_extension_bytes[0] =
+            smbios_type0.extension_bytes[0];
+    } else {
+        t->bios_characteristics_extension_bytes[0] = 0;
+    }
+
+    if (smbios_type0.have_extension_bytes[1]) {
+        t->bios_characteristics_extension_bytes[1] =
+            smbios_type0.extension_bytes[1];
+    } else {
+        t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
+
+        if (smbios_type0.uefi) {
+            t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
+        }
should we not or these in, anyway?
That's fair enough, but I thought since you're specifying the entire byte
anyway you don't
want a different option modifying your value, that would most likely be a
bug IMO.

But specifying uefi on command line is also user's choice.

Maybe we just want flags for all the options. Which ones do
you actually have a practicall need to tweak, and why?

As far as I can see, QEMU unconditionally sets the VM flag, which SeaBIOS doesn't set. I want it cleared to make sure no guest visible changes are introduced. Technically there is 14 feature bits, out of which we already have one. Do you think it would be better to just make the one specific bit I want customizable? There might be a need in the future to extend this further, so we will have to either introduce all 14 flags, or just allow the user to specify the entire value
like this patch does.



       }
       if (smbios_type0.have_major_minor) {
@@ -1403,7 +1424,42 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
               save_opt(&smbios_type0.vendor, opts, "vendor");
               save_opt(&smbios_type0.version, opts, "version");
               save_opt(&smbios_type0.date, opts, "date");
-            smbios_type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
+
+            if (qemu_opt_get(opts, "extension_byte_1")) {
+                uint64_t ex_val;
+
+                ex_val = qemu_opt_get_number(opts, "extension_byte_1", 0);
+                if (ex_val > 0xFF) {
+                    error_setg(errp, "Invalid extension_byte_1");
+                    return;
+                }
+
+                smbios_type0.extension_bytes[0] = ex_val;
+                smbios_type0.have_extension_bytes[0] = true;
+            }
+
+            if (qemu_opt_get(opts, "extension_byte_2")) {
+                uint64_t ex_val;
+
+                ex_val = qemu_opt_get_number(opts, "extension_byte_2", 0);
+                if (ex_val > 0xFF) {
+                    error_setg(errp, "Invalid extension_byte_2");
+                    return;
+                }
+
+                smbios_type0.extension_bytes[1] = ex_val;
+                smbios_type0.have_extension_bytes[1] = true;
+            }
+
+            if (qemu_opt_get(opts, "uefi")) {
+                if (smbios_type0.have_extension_bytes[1]) {
+                    error_setg(errp, "'uefi' and 'extension_byte_2' are "
+                                     "mutually exclusive");
+                    return;
+                }
+
+                smbios_type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
+            }
               val = qemu_opt_get(opts, "release");
               if (val) {
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
index f066ab7262..67b3b28471 100644
--- a/include/hw/firmware/smbios.h
+++ b/include/hw/firmware/smbios.h
@@ -24,6 +24,9 @@ typedef struct {
       const char *vendor, *version, *date;
       bool have_major_minor, uefi;
       uint8_t major, minor;
+
+    bool have_extension_bytes[2];
+    uint8_t extension_bytes[2];
   } smbios_type0_t;
   extern smbios_type0_t smbios_type0;
--
2.34.1

Reply via email to