The branch main has been updated by chuck:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=cbd442efe85d9ae371581565670dfc0287afbf8e

commit cbd442efe85d9ae371581565670dfc0287afbf8e
Author:     John De Boskey <[email protected]>
AuthorDate: 2026-07-18 21:39:33 +0000
Commit:     Chuck Tuffli <[email protected]>
CommitDate: 2026-07-18 22:07:07 +0000

    bhyve: add configurable SMBIOS OEM Strings
    
    Add the option "oemstring" to allow setting the DMI type 11 ("OEM
    Strings") SMBIOS structure. These are free-form strings, available for
    any purpose, but can be especially useful to pass configuration,
    secrets, and credential information into a Linux guest and consumed by
    systemd.
    
    MFC after:      1 month
    Relnotes:       yes
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D57516
---
 usr.sbin/bhyve/bhyve_config.5 |   3 +
 usr.sbin/bhyve/smbiostbl.c    | 124 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 127 insertions(+)

diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5
index dd82bea61d20..ae84aba1fe57 100644
--- a/usr.sbin/bhyve/bhyve_config.5
+++ b/usr.sbin/bhyve/bhyve_config.5
@@ -226,6 +226,9 @@ This value is used for the guest's System Management BIOS 
System Information str
 Stock keeping unit of the chassis.
 It's also called product ID or purchase order number.
 This value is used for the guest's System Management BIOS System Information 
structure.
+.It Va oemstring.N Ta string Ta none Ta
+This value is returned for the guest's Nth System Management BIOS System 
Information OEM Strings structure.
+Configuration can specify up to 255 strings.
 .It Va rundir Ta String Ta Pa /var/run/bhyve/ Ta
 Path to the runtime directory for
 .Xr bhyve 8
diff --git a/usr.sbin/bhyve/smbiostbl.c b/usr.sbin/bhyve/smbiostbl.c
index e09fbc95fc9e..8bb2415318bb 100644
--- a/usr.sbin/bhyve/smbiostbl.c
+++ b/usr.sbin/bhyve/smbiostbl.c
@@ -29,10 +29,13 @@
 #include <sys/param.h>
 
 #include <assert.h>
+#include <err.h>
 #include <errno.h>
 #include <md5.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <sysexits.h>
 #include <unistd.h>
 #include <uuid.h>
 
@@ -61,6 +64,7 @@
 #define        SMBIOS_TYPE_BOARD       2
 #define        SMBIOS_TYPE_CHASSIS     3
 #define        SMBIOS_TYPE_PROCESSOR   4
+#define        SMBIOS_TYPE_OEM         11
 #define        SMBIOS_TYPE_MEMARRAY    16
 #define        SMBIOS_TYPE_MEMDEVICE   17
 #define        SMBIOS_TYPE_MEMARRAYMAP 19
@@ -250,6 +254,13 @@ struct smbios_table_type4 {
        uint16_t                family2;        /* processor family 2 */
 } __packed;
 
+#define SMBIOS_TYPE11_MAX_COUNT        255
+
+struct smbios_table_type11 {
+       struct smbios_structure header;
+       uint8_t                 nstrings;       /* number of oem strings to 
follow */
+} __packed;
+
 /*
  * Physical Memory Array
  */
@@ -479,6 +490,15 @@ static int smbios_type4_initializer(
     const struct smbios_string *template_strings, char *curaddr, char 
**endaddr,
     uint16_t *n);
 
+static const struct smbios_table_type11 smbios_type11_template = {
+       { SMBIOS_TYPE_OEM, sizeof(struct smbios_table_type11),  0 },
+       0               /* first string */
+};
+
+static int smbios_type11_initializer(const struct smbios_structure 
*template_entry,
+    const struct smbios_string *template_strings, char *curaddr, char 
**endaddr,
+    uint16_t *n);
+
 static const struct smbios_table_type16 smbios_type16_template = {
        { SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16),  0 },
        SMBIOS_MAL_SYSMB,
@@ -582,6 +602,9 @@ static struct smbios_template_entry smbios_template[] = {
        { (const struct smbios_structure *)&smbios_type4_template,
          smbios_type4_strings,
          smbios_type4_initializer },
+       { (const struct smbios_structure *)&smbios_type11_template,
+         NULL,
+         smbios_type11_initializer },
        { (const struct smbios_structure *)&smbios_type16_template,
          NULL,
          smbios_type16_initializer },
@@ -750,6 +773,107 @@ smbios_type4_initializer(const struct smbios_structure 
*template_entry,
        return (0);
 }
 
+/*
+ * Gather oemstring values from oemstring node of config kvlist
+ *
+ * Notes: The keys must be numeric and greater than zero.
+ *
+ *        Any missing number keys will be added with a value
+ *        of "N/A"
+ *
+ *        The maximum number of strings allowed is 255
+ */
+
+static struct smbios_string *
+smbios_gather_type11_strings(void)
+{
+       const char *na = "N/A";
+       struct smbios_string *strings;
+       const char *name;
+       char *np;
+       void *cookie = NULL;
+       nvlist_t *node;
+       long maxnumber = 0;
+       long number;
+       char keystr[4];         /* SMBIOS_TYPE11_MAX_COUNT is a 3 digit number 
*/
+       char canonical[4];
+       int key, type;
+
+       /* find any oemstrings */
+       node = find_config_node("oemstring");
+       /* nothing to do if none */
+       if (!node)
+               return NULL;
+
+       while ((name = nvlist_next(node, &type, &cookie)) != NULL) {
+               if (type != NV_TYPE_STRING)
+                       errx(BHYVE_EXIT_ERROR, "Unexpected entry type for %s", 
name);
+
+               errno = 0;
+               number = strtol(name, &np, 10);
+               if ((*np != '\0') || (errno == EINVAL))
+                       errx(BHYVE_EXIT_ERROR, "Invalid format: %s should be a 
decimal number", name);
+               if (number <= 0 || number > SMBIOS_TYPE11_MAX_COUNT)
+                       errx(BHYVE_EXIT_ERROR, "Invalid range: %s should be in 
1-%d", name,
+                           SMBIOS_TYPE11_MAX_COUNT);
+               /* strtol accepts leading zeros and signed values which will 
break search */
+               snprintf(canonical, sizeof(canonical), "%ld", number);
+               if (strcmp(name, canonical) != 0)
+                       errx(BHYVE_EXIT_ERROR, "Invalid format: %s should be 
%s", name, canonical);
+               if (number > maxnumber)
+                       maxnumber = number;
+       }
+       strings = calloc(maxnumber + 1, sizeof(struct smbios_string));
+       if (strings == NULL)
+               err(BHYVE_EXIT_ERROR, "oemstring allocation failed");
+
+       /*
+        * The returned smbios_string should leave the node field as NULL to
+        * avoid creating a new node in the config tree.
+        */
+       for (key = 1; key <= maxnumber; key++) {
+               const char *vp;
+
+               snprintf(keystr, sizeof(keystr), "%d", key);
+               if (nvlist_exists(node, keystr))
+                       vp = nvlist_get_string(node, keystr);
+               else
+                       vp = na;
+               strings[key - 1].value = strdup(vp);
+               if (strings[key - 1].value == NULL)
+                       err(BHYVE_EXIT_ERROR, "oemstring value allocation 
failed");
+       }
+
+       /* return data */
+       return (strings);
+}
+
+static int
+smbios_type11_initializer(const struct smbios_structure *template_entry,
+    const struct smbios_string *template_strings __unused, char *curaddr,
+    char **endaddr, uint16_t *n)
+{
+       struct smbios_table_type11 *type11;
+       struct smbios_string *type11_strings;
+       int i = 0;
+
+       type11_strings = smbios_gather_type11_strings();
+
+       smbios_generic_initializer(template_entry, type11_strings, curaddr,
+           endaddr, n);
+
+       if (type11_strings != NULL) {
+               /* count up strings */
+               type11 = (struct smbios_table_type11 *)curaddr;
+               for (i = 0; type11_strings[i].value != NULL; i++) {
+                       free(__DECONST(char *, type11_strings[i].value));
+               }
+               type11->nstrings = i;
+       }
+       free(type11_strings);
+       return (0);
+}
+
 static int
 smbios_type16_initializer(const struct smbios_structure *template_entry,
     const struct smbios_string *template_strings, char *curaddr, char 
**endaddr,

Reply via email to