aboutsummaryrefslogtreecommitdiff
path: root/hw/smbios
diff options
context:
space:
mode:
authorVincent Bernat <vincent@bernat.ch>2021-04-01 19:11:38 +0200
committerMichael S. Tsirkin <mst@redhat.com>2021-05-14 10:26:18 -0400
commit05dfb447a4e11b32d4ed94f73629c497235fc3dc (patch)
tree42181c2c331590cb9e01b750dff67454559001bc /hw/smbios
parent43bea443575772bdabd13781be043468c205d6cf (diff)
hw/smbios: support for type 41 (onboard devices extended information)
Type 41 defines the attributes of devices that are onboard. The original intent was to imply the BIOS had some level of control over the enablement of the associated devices. If network devices are present in this table, by default, udev will name the corresponding interfaces enoX, X being the instance number. Without such information, udev will fallback to using the PCI ID and this usually gives ens3 or ens4. This can be a bit annoying as the name of the network card may depend on the order of options and may change if a new PCI device is added earlier on the commande line. Being able to provide SMBIOS type 41 entry ensure the name of the interface won't change and helps the user guess the right name without booting a first time. This can be invoked with: $QEMU -netdev user,id=internet -device virtio-net-pci,mac=50:54:00:00:00:42,netdev=internet,id=internet-dev \ -smbios type=41,designation='Onboard LAN',instance=1,kind=ethernet,pcidev=internet-dev The PCI segment is assumed to be 0. This should hold true for most cases. $ dmidecode -t 41 # dmidecode 3.3 Getting SMBIOS data from sysfs. SMBIOS 2.8 present. Handle 0x2900, DMI type 41, 11 bytes Onboard Device Reference Designation: Onboard LAN Type: Ethernet Status: Enabled Type Instance: 1 Bus Address: 0000:00:09.0 $ ip -brief a lo UNKNOWN 127.0.0.1/8 ::1/128 eno1 UP 10.0.2.14/24 fec0::5254:ff:fe00:42/64 fe80::5254:ff:fe00:42/64 Signed-off-by: Vincent Bernat <vincent@bernat.ch> Message-Id: <20210401171138.62970-1-vincent@bernat.ch> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/smbios')
-rw-r--r--hw/smbios/smbios.c124
1 files changed, 123 insertions, 1 deletions
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index f22c4f5b73..7397e56737 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -27,6 +27,7 @@
#include "hw/firmware/smbios.h"
#include "hw/loader.h"
#include "hw/boards.h"
+#include "hw/pci/pci_bus.h"
#include "smbios_build.h"
/* legacy structures and constants for <= 2.0 machines */
@@ -118,6 +119,28 @@ static struct {
uint16_t speed;
} type17;
+static QEnumLookup type41_kind_lookup = {
+ .array = (const char *const[]) {
+ "other",
+ "unknown",
+ "video",
+ "scsi",
+ "ethernet",
+ "tokenring",
+ "sound",
+ "pata",
+ "sata",
+ "sas",
+ },
+ .size = 10
+};
+struct type41_instance {
+ const char *designation, *pcidev;
+ uint8_t instance, kind;
+ QTAILQ_ENTRY(type41_instance) next;
+};
+static QTAILQ_HEAD(, type41_instance) type41 = QTAILQ_HEAD_INITIALIZER(type41);
+
static QemuOptsList qemu_smbios_opts = {
.name = "smbios",
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
@@ -358,6 +381,32 @@ static const QemuOptDesc qemu_smbios_type17_opts[] = {
{ /* end of list */ }
};
+static const QemuOptDesc qemu_smbios_type41_opts[] = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_NUMBER,
+ .help = "SMBIOS element type",
+ },{
+ .name = "designation",
+ .type = QEMU_OPT_STRING,
+ .help = "reference designation string",
+ },{
+ .name = "kind",
+ .type = QEMU_OPT_STRING,
+ .help = "device type",
+ .def_value_str = "other",
+ },{
+ .name = "instance",
+ .type = QEMU_OPT_NUMBER,
+ .help = "device type instance",
+ },{
+ .name = "pcidev",
+ .type = QEMU_OPT_STRING,
+ .help = "PCI device",
+ },
+ { /* end of list */ }
+};
+
static void smbios_register_config(void)
{
qemu_add_opts(&qemu_smbios_opts);
@@ -773,6 +822,53 @@ static void smbios_build_type_32_table(void)
SMBIOS_BUILD_TABLE_POST;
}
+static void smbios_build_type_41_table(Error **errp)
+{
+ unsigned instance = 0;
+ struct type41_instance *t41;
+
+ QTAILQ_FOREACH(t41, &type41, next) {
+ SMBIOS_BUILD_TABLE_PRE(41, 0x2900 + instance, true);
+
+ SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation);
+ t->device_type = t41->kind;
+ t->device_type_instance = t41->instance;
+ t->segment_group_number = cpu_to_le16(0);
+ t->bus_number = 0;
+ t->device_number = 0;
+
+ if (t41->pcidev) {
+ PCIDevice *pdev = NULL;
+ int rc = pci_qdev_find_device(t41->pcidev, &pdev);
+ if (rc != 0) {
+ error_setg(errp,
+ "No PCI device %s for SMBIOS type 41 entry %s",
+ t41->pcidev, t41->designation);
+ return;
+ }
+ /*
+ * We only handle the case were the device is attached to
+ * the PCI root bus. The general case is more complex as
+ * bridges are enumerated later and the table would need
+ * to be updated at this moment.
+ */
+ if (!pci_bus_is_root(pci_get_bus(pdev))) {
+ error_setg(errp,
+ "Cannot create type 41 entry for PCI device %s: "
+ "not attached to the root bus",
+ t41->pcidev);
+ return;
+ }
+ t->segment_group_number = cpu_to_le16(0);
+ t->bus_number = pci_dev_bus_num(pdev);
+ t->device_number = pdev->devfn;
+ }
+
+ SMBIOS_BUILD_TABLE_POST;
+ instance++;
+ }
+}
+
static void smbios_build_type_127_table(void)
{
SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
@@ -883,7 +979,8 @@ void smbios_get_tables(MachineState *ms,
const struct smbios_phys_mem_area *mem_array,
const unsigned int mem_array_size,
uint8_t **tables, size_t *tables_len,
- uint8_t **anchor, size_t *anchor_len)
+ uint8_t **anchor, size_t *anchor_len,
+ Error **errp)
{
unsigned i, dimm_cnt;
@@ -928,6 +1025,7 @@ void smbios_get_tables(MachineState *ms,
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);
@@ -1224,6 +1322,30 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
save_opt(&type17.part, opts, "part");
type17.speed = qemu_opt_get_number(opts, "speed", 0);
return;
+ case 41: {
+ struct type41_instance *t;
+ Error *local_err = NULL;
+
+ if (!qemu_opts_validate(opts, qemu_smbios_type41_opts, errp)) {
+ return;
+ }
+ t = g_new0(struct type41_instance, 1);
+ save_opt(&t->designation, opts, "designation");
+ t->kind = qapi_enum_parse(&type41_kind_lookup,
+ qemu_opt_get(opts, "kind"),
+ 0, &local_err) + 1;
+ t->kind |= 0x80; /* enabled */
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ g_free(t);
+ return;
+ }
+ t->instance = qemu_opt_get_number(opts, "instance", 1);
+ save_opt(&t->pcidev, opts, "pcidev");
+
+ QTAILQ_INSERT_TAIL(&type41, t, next);
+ return;
+ }
default:
error_setg(errp,
"Don't know how to build fields for SMBIOS type %ld",