@@ -49,6 +49,8 @@ typedef struct VMBusDeviceClass {
int (*open_channel) (VMBusDevice *vdev);
void (*close_channel) (VMBusDevice *vdev);
VMBusChannelNotifyCb chan_notify_cb;
+
+ const char *romfile;
} VMBusDeviceClass;
typedef struct VMBusDevice {
@@ -57,6 +59,7 @@ typedef struct VMBusDevice {
uint16_t num_channels;
VMBusChannel *channels;
AddressSpace *dma_as;
+ char *romfile;
} VMBusDevice;
extern const VMStateDescription vmstate_vmbus_dev;
@@ -12,6 +12,7 @@
#include "qapi/error.h"
#include "hw/vmbus/vmbus.h"
#include "hw/sysbus.h"
+#include "hw/loader.h"
#include "trace.h"
#define TYPE_VMBUS "vmbus"
@@ -2061,6 +2062,36 @@ unmap:
cpu_physical_memory_unmap(int_map, len, 1, is_dirty);
}
+static void vmbus_install_rom(VMBusDevice *vdev)
+{
+ VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev);
+ VMBus *vmbus = VMBUS(qdev_get_parent_bus(DEVICE(vdev)));
+ BusChild *child;
+ char uuid[UUID_FMT_LEN + 1];
+ char romname[10 + UUID_FMT_LEN + 4 + 1];
+
+ if (vdev->romfile) {
+ /* device-specific rom */
+ qemu_uuid_unparse(&vdc->instanceid, uuid);
+ snprintf(romname, sizeof(romname), "vmbus/dev/%s.rom", uuid);
+ rom_add_file(vdev->romfile, romname, 0, -1, true, NULL, NULL);
+ } else if (vdc->romfile) {
+ /* class-wide rom */
+ QTAILQ_FOREACH(child, &BUS(vmbus)->children, sibling) {
+ VMBusDevice *chlddev = VMBUS_DEVICE(child->child);
+
+ /* another device of the same class has already installed it */
+ if (chlddev != vdev && !chlddev->romfile &&
+ VMBUS_DEVICE_GET_CLASS(chlddev) == vdc) {
+ return;
+ }
+ }
+ qemu_uuid_unparse(&vdc->classid, uuid);
+ snprintf(romname, sizeof(romname), "vmbus/%s.rom", uuid);
+ rom_add_file(vdc->romfile, romname, 0, -1, true, NULL, NULL);
+ }
+}
+
static void vmbus_dev_realize(DeviceState *dev, Error **errp)
{
VMBusDevice *vdev = VMBUS_DEVICE(dev);
@@ -2098,6 +2129,8 @@ static void vmbus_dev_realize(DeviceState *dev, Error **errp)
goto error_out;
}
+ vmbus_install_rom(vdev);
+
if (vdc->vmdev_realize) {
vdc->vmdev_realize(vdev, &err);
if (err) {
@@ -2145,6 +2178,11 @@ static void vmbus_dev_unrealize(DeviceState *dev, Error **errp)
free_channels(vmbus, vdev);
}
+static Property vmbus_dev_props[] = {
+ DEFINE_PROP_STRING("romfile", VMBusDevice, romfile),
+ DEFINE_PROP_END_OF_LIST()
+};
+
static void vmbus_dev_class_init(ObjectClass *klass, void *data)
{
DeviceClass *kdev = DEVICE_CLASS(klass);
@@ -2152,6 +2190,7 @@ static void vmbus_dev_class_init(ObjectClass *klass, void *data)
kdev->realize = vmbus_dev_realize;
kdev->unrealize = vmbus_dev_unrealize;
kdev->reset = vmbus_dev_reset;
+ kdev->props = vmbus_dev_props;
}
static int vmbus_dev_post_load(void *opaque, int version_id)
In order to leverage third-party drivers for VMBus devices in firmware (in particular, there's a case with iPXE driver for hv-net in SeaBIOS and OVMF), introduce an infrastructure to supply such drivers as option ROMs. To make it easy for the firmware to locate such ROMs, they are stored in fw_cfg with names "vmbus/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.rom" for default class ROMs (where xxx... is the class GUID) and "vmbus/dev/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy.rom" for per-device (i.e. specified via .romfile property) ROMs (where yyy... is the device instance GUID). The format and the calling convention for the ROMs is out of scope for this patch: QEMU doesn't try to interpret them. Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> --- include/hw/vmbus/vmbus.h | 3 +++ hw/vmbus/vmbus.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+)