diff --git a/block_int.h b/block_int.h index 3c3adb5c85..0a0e47d56c 100644 --- a/block_int.h +++ b/block_int.h @@ -227,6 +227,7 @@ typedef struct BlockConf { uint16_t logical_block_size; uint16_t min_io_size; uint32_t opt_io_size; + int32_t bootindex; } BlockConf; static inline unsigned int get_physical_block_exp(BlockConf *conf) @@ -249,6 +250,7 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) DEFINE_PROP_UINT16("physical_block_size", _state, \ _conf.physical_block_size, 512), \ DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \ - DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0) + DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \ + DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1) \ #endif /* BLOCK_INT_H */ diff --git a/hw/e1000.c b/hw/e1000.c index a697abd754..af101bd7b7 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -30,6 +30,7 @@ #include "net.h" #include "net/checksum.h" #include "loader.h" +#include "sysemu.h" #include "e1000_hw.h" @@ -1147,6 +1148,9 @@ static int pci_e1000_init(PCIDevice *pci_dev) d->dev.qdev.info->name, d->dev.qdev.id, d); qemu_format_nic_info_str(&d->nic->nc, macaddr); + + add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); + return 0; } diff --git a/hw/eepro100.c b/hw/eepro100.c index b31ad3e70c..edf48f61d1 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -46,6 +46,7 @@ #include "pci.h" #include "net.h" #include "eeprom93xx.h" +#include "sysemu.h" #define KiB 1024 @@ -1908,6 +1909,8 @@ static int e100_nic_init(PCIDevice *pci_dev) s->vmstate->name = s->nic->nc.model; vmstate_register(&pci_dev->qdev, -1, s->vmstate, s); + add_boot_device_path(s->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); + return 0; } diff --git a/hw/fdc.c b/hw/fdc.c index 9d92e93c37..4bbcc4715f 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -35,6 +35,7 @@ #include "sysbus.h" #include "qdev-addr.h" #include "blockdev.h" +#include "sysemu.h" /********************************************************/ /* debug Floppy devices */ @@ -523,6 +524,8 @@ typedef struct FDCtrlSysBus { typedef struct FDCtrlISABus { ISADevice busdev; struct FDCtrl state; + int32_t bootindexA; + int32_t bootindexB; } FDCtrlISABus; static uint32_t fdctrl_read (void *opaque, uint32_t reg) @@ -1992,6 +1995,9 @@ static int isabus_fdc_init1(ISADevice *dev) qdev_set_legacy_instance_id(&dev->qdev, iobase, 2); ret = fdctrl_init_common(fdctrl); + add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy@0"); + add_boot_device_path(isa->bootindexB, &dev->qdev, "/floppy@1"); + return ret; } @@ -2053,6 +2059,8 @@ static ISADeviceInfo isa_fdc_info = { .qdev.props = (Property[]) { DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs), DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs), + DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1), + DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 01a181bb45..2bb5c27341 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -21,6 +21,7 @@ #include "qemu-error.h" #include #include "blockdev.h" +#include "sysemu.h" /* --------------------------------- */ @@ -143,6 +144,10 @@ static int ide_drive_initfn(IDEDevice *dev) if (!dev->serial) { dev->serial = qemu_strdup(s->drive_serial_str); } + + add_boot_device_path(dev->conf.bootindex, &dev->qdev, + dev->unit ? "/disk@1" : "/disk@0"); + return 0; } diff --git a/hw/ne2000.c b/hw/ne2000.c index 126e7cfeaf..a030106fa5 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -26,6 +26,7 @@ #include "net.h" #include "ne2000.h" #include "loader.h" +#include "sysemu.h" /* debug NE2000 card */ //#define DEBUG_NE2000 @@ -746,6 +747,8 @@ static int pci_ne2000_init(PCIDevice *pci_dev) } } + add_boot_device_path(s->c.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); + return 0; } diff --git a/hw/pcnet.c b/hw/pcnet.c index 37010b8fcf..db52dc59e1 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -39,6 +39,7 @@ #include "net.h" #include "qemu-timer.h" #include "qemu_socket.h" +#include "sysemu.h" #include "pcnet.h" @@ -1740,5 +1741,8 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + + add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0"); + return 0; } diff --git a/hw/qdev.c b/hw/qdev.c index b65b63e10e..10e28df7a1 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -889,3 +889,35 @@ int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data) } return qdev_unplug(dev); } + +static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) +{ + int l = 0; + + if (dev && dev->parent_bus) { + char *d; + l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size); + if (dev->parent_bus->info->get_fw_dev_path) { + d = dev->parent_bus->info->get_fw_dev_path(dev); + l += snprintf(p + l, size - l, "%s", d); + qemu_free(d); + } else { + l += snprintf(p + l, size - l, "%s", dev->info->name); + } + } + l += snprintf(p + l , size - l, "/"); + + return l; +} + +char* qdev_get_fw_dev_path(DeviceState *dev) +{ + char path[128]; + int l; + + l = qdev_get_fw_dev_path_helper(dev, path, 128); + + path[l-1] = '\0'; + + return strdup(path); +} diff --git a/hw/qdev.h b/hw/qdev.h index f72fbdeecb..aaaf55ab26 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -319,6 +319,7 @@ static inline const char *qdev_fw_name(DeviceState *dev) return dev->info->fw_name ? : dev->info->alias ? : dev->info->name; } +char *qdev_get_fw_dev_path(DeviceState *dev); /* This is a nasty hack to allow passing a NULL bus to qdev_create. */ extern struct BusInfo system_bus_info; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 4a73f6f491..a8aed89074 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -52,6 +52,7 @@ #include "qemu-timer.h" #include "net.h" #include "loader.h" +#include "sysemu.h" /* debug RTL8139 card */ //#define DEBUG_RTL8139 1 @@ -3376,6 +3377,9 @@ static int pci_rtl8139_init(PCIDevice *dev) s->TimerExpire = 0; s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock)); + + add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy@0"); + return 0; } diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 851046fd55..87f9e8677e 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1225,6 +1225,7 @@ static int scsi_disk_initfn(SCSIDevice *dev) s->qdev.type = TYPE_DISK; qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); bdrv_set_removable(s->bs, is_cd); + add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0"); return 0; } diff --git a/hw/usb-net.c b/hw/usb-net.c index f6bed2184e..84924550fd 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -27,6 +27,7 @@ #include "usb.h" #include "net.h" #include "qemu-queue.h" +#include "sysemu.h" /*#define TRAFFIC_DEBUG*/ /* Thanks to NetChip Technologies for donating this product ID. @@ -1463,6 +1464,7 @@ static int usb_net_initfn(USBDevice *dev) s->conf.macaddr.a[4], s->conf.macaddr.a[5]); + add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet@0"); return 0; } diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index e5f9b2795a..f62ccd1fe8 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -548,6 +548,8 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf) bdrv_set_removable(s->bs, 0); s->bs->buffer_alignment = conf->logical_block_size; + add_boot_device_path(conf->bootindex, dev, "/disk@0,0"); + return &s->vdev; } diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 1d61f191b6..3472f6b28d 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1017,6 +1017,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, virtio_net_save, virtio_net_load, n); n->vmstate = qemu_add_vm_change_state_handler(virtio_net_vmstate_change, n); + add_boot_device_path(conf->bootindex, dev, "/ethernet-phy@0"); + return &n->vdev; } diff --git a/net.h b/net.h index 44c31a9b32..6ceca50fc3 100644 --- a/net.h +++ b/net.h @@ -17,12 +17,14 @@ typedef struct NICConf { MACAddr macaddr; VLANState *vlan; VLANClientState *peer; + int32_t bootindex; } NICConf; #define DEFINE_NIC_PROPERTIES(_state, _conf) \ DEFINE_PROP_MACADDR("mac", _state, _conf.macaddr), \ DEFINE_PROP_VLAN("vlan", _state, _conf.vlan), \ - DEFINE_PROP_NETDEV("netdev", _state, _conf.peer) + DEFINE_PROP_NETDEV("netdev", _state, _conf.peer), \ + DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1) /* VLANs support */ diff --git a/sysemu.h b/sysemu.h index b81a70ec3e..fe9a5827b2 100644 --- a/sysemu.h +++ b/sysemu.h @@ -188,4 +188,6 @@ void rtc_change_mon_event(struct tm *tm); void register_devices(void); +void add_boot_device_path(int32_t bootindex, DeviceState *dev, + const char *suffix); #endif diff --git a/vl.c b/vl.c index 2cd263eda4..dadc161fdf 100644 --- a/vl.c +++ b/vl.c @@ -229,6 +229,17 @@ unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; int boot_menu; +typedef struct FWBootEntry FWBootEntry; + +struct FWBootEntry { + QTAILQ_ENTRY(FWBootEntry) link; + int32_t bootindex; + DeviceState *dev; + char *suffix; +}; + +QTAILQ_HEAD(, FWBootEntry) fw_boot_order = QTAILQ_HEAD_INITIALIZER(fw_boot_order); + int nb_numa_nodes; uint64_t node_mem[MAX_NODES]; uint64_t node_cpumask[MAX_NODES]; @@ -693,6 +704,35 @@ static void restore_boot_devices(void *opaque) qemu_free(standard_boot_devices); } +void add_boot_device_path(int32_t bootindex, DeviceState *dev, + const char *suffix) +{ + FWBootEntry *node, *i; + + if (bootindex < 0) { + return; + } + + assert(dev != NULL || suffix != NULL); + + node = qemu_mallocz(sizeof(FWBootEntry)); + node->bootindex = bootindex; + node->suffix = strdup(suffix); + node->dev = dev; + + QTAILQ_FOREACH(i, &fw_boot_order, link) { + if (i->bootindex == bootindex) { + fprintf(stderr, "Two devices with same boot index %d\n", bootindex); + exit(1); + } else if (i->bootindex < bootindex) { + continue; + } + QTAILQ_INSERT_BEFORE(i, node, link); + return; + } + QTAILQ_INSERT_TAIL(&fw_boot_order, node, link); +} + static void numa_add(const char *optarg) { char option[128];