If bootindex is specified on command line a string that describes device in firmware readable way is added into sorted list. Later this list will be passed into firmware to control boot order. Signed-off-by: Gleb Natapov <gleb@xxxxxxxxxx> --- block_int.h | 4 +++- hw/e1000.c | 7 +++++++ hw/eepro100.c | 6 ++++++ hw/fdc.c | 13 +++++++++++++ hw/ide/qdev.c | 7 +++++++ hw/ne2000.c | 6 ++++++ hw/pcnet.c | 6 ++++++ hw/qdev.c | 32 ++++++++++++++++++++++++++++++++ hw/qdev.h | 1 + hw/rtl8139.c | 7 +++++++ hw/usb-net.c | 4 ++++ hw/virtio-blk.c | 4 ++++ hw/virtio-net.c | 4 ++++ net.h | 4 +++- sysemu.h | 2 ++ vl.c | 35 +++++++++++++++++++++++++++++++++++ 16 files changed, 140 insertions(+), 2 deletions(-) diff --git a/block_int.h b/block_int.h index 87e60b8..f9042a8 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 532efdc..009e24b 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" @@ -1148,6 +1149,12 @@ 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); + + if (d->conf.bootindex >= 0) { + 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 218472d..2a7c6cb 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 @@ -1907,6 +1908,11 @@ static int e100_nic_init(PCIDevice *pci_dev) s->vmstate->name = s->nic->nc.model; vmstate_register(&pci_dev->qdev, -1, s->vmstate, s); + if (s->conf.bootindex >= 0) { + 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 5ab754b..732728e 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,14 @@ static int isabus_fdc_init1(ISADevice *dev) qdev_set_legacy_instance_id(&dev->qdev, iobase, 2); ret = fdctrl_init_common(fdctrl); + if (isa->bootindexA >= 0) { + add_boot_device_path(isa->bootindexA, &dev->qdev, "floppy@0"); + } + + if (isa->bootindexB >= 0) { + add_boot_device_path(isa->bootindexB, &dev->qdev, "floppy@1"); + } + return ret; } @@ -2051,6 +2062,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 01a181b..dcd49aa 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -21,6 +21,7 @@ #include "qemu-error.h" #include <hw/ide/internal.h> #include "blockdev.h" +#include "sysemu.h" /* --------------------------------- */ @@ -143,6 +144,12 @@ static int ide_drive_initfn(IDEDevice *dev) if (!dev->serial) { dev->serial = qemu_strdup(s->drive_serial_str); } + + if (dev->conf.bootindex >= 0) { + 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 126e7cf..d0a0dc6 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,11 @@ static int pci_ne2000_init(PCIDevice *pci_dev) } } + if (s->c.bootindex >= 0) { + 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 b52935a..93595cb 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -40,6 +40,7 @@ #include "loader.h" #include "qemu-timer.h" #include "qemu_socket.h" +#include "sysemu.h" #include "pcnet.h" @@ -1898,6 +1899,11 @@ 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); + + if (s->conf.bootindex >= 0) { + add_boot_device_path(s->conf.bootindex, dev, "ethernet-phy@0"); + } + return 0; } diff --git a/hw/qdev.c b/hw/qdev.c index 35858cb..cc9bf43 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -820,3 +820,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 dc669b3..13f3597 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -296,6 +296,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 d92981d..56a3621 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 @@ -3387,6 +3388,12 @@ 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)); + + if (s->conf.bootindex >= 0) { + add_boot_device_path(s->conf.bootindex, &dev->qdev, + "ethernet-phy@0"); + } + return 0; } diff --git a/hw/usb-net.c b/hw/usb-net.c index 2287ee1..55d69f0 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,9 @@ static int usb_net_initfn(USBDevice *dev) s->conf.macaddr.a[4], s->conf.macaddr.a[5]); + if (s->conf.bootindex >= 0) + 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 dbe2070..c8f0843 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -548,6 +548,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf) bdrv_set_removable(s->bs, 0); s->bs->buffer_alignment = conf->logical_block_size; + if (conf->bootindex >= 0) { + add_boot_device_path(conf->bootindex, dev, "disk@0"); + } + return &s->vdev; } diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 7e1688c..69d48f4 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1018,6 +1018,10 @@ 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); + if (conf->bootindex >= 0) { + add_boot_device_path(conf->bootindex, dev, "ethernet-phy@0"); + } + return &n->vdev; } diff --git a/net.h b/net.h index 44c31a9..6ceca50 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 849dc8c..6b85d86 100644 --- a/sysemu.h +++ b/sysemu.h @@ -193,4 +193,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 4bad675..8edf27a 100644 --- a/vl.c +++ b/vl.c @@ -232,6 +232,17 @@ const char *prom_envs[MAX_PROM_ENVS]; const char *nvram = NULL; 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]; @@ -696,6 +707,30 @@ 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 = qemu_mallocz(sizeof(FWBootEntry)), *i; + + assert(dev != NULL || suffix != NULL); + + 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]; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html