#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 */
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),
{ /* 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);
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 */
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;
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);
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",
" specify SMBIOS type 11 fields\n"
"-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str]\n"
" [,asset=str][,part=str][,speed=%d]\n"
- " specify SMBIOS type 17 fields\n",
+ " specify SMBIOS type 17 fields\n"
+ "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n"
+ " specify SMBIOS type 41 fields\n",
QEMU_ARCH_I386 | QEMU_ARCH_ARM)
SRST
``-smbios file=binary``
``-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str][,asset=str][,part=str][,speed=%d]``
Specify SMBIOS type 17 fields
+
+``-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]``
+ Specify SMBIOS type 41 fields
+
+ This argument can be repeated multiple times. Its main use is to allow network interfaces be created
+ as ``enoX`` on Linux, with X being the instance number, instead of the name depending on the interface
+ position on the PCI bus.
+
+ Here is an example of use:
+
+ .. parsed-literal::
+
+ -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
+
+ In the guest OS, the device should then appear as ``eno1``:
+
+ ..parsed-literal::
+
+ $ ip -brief l
+ lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
+ eno1 UP 50:54:00:00:00:42 <BROADCAST,MULTICAST,UP,LOWER_UP>
+
+ Currently, the PCI device has to be attached to the root bus.
+
ERST
DEFHEADING()