aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorMarkus Armbruster <armbru@redhat.com>2020-06-22 11:42:15 +0200
committerMarkus Armbruster <armbru@redhat.com>2020-06-23 16:07:07 +0200
commit6172e067a4f2a521ace14f7d0d88c6df76e26eab (patch)
tree2020ab75fed0332ad510cab203cc9b791566e98c /hw
parent02b83f7d7c0828bb03fe0324c0ec8388d7e711d4 (diff)
downloadqemu-6172e067a4f2a521ace14f7d0d88c6df76e26eab.zip
qemu-6172e067a4f2a521ace14f7d0d88c6df76e26eab.tar.gz
qemu-6172e067a4f2a521ace14f7d0d88c6df76e26eab.tar.bz2
fdc: Reject clash between -drive if=floppy and -global isa-fdc
The floppy controller devices desugar their drive properties into floppy devices (since commit a92bd191a4 "fdc: Move qdev properties to FloppyDrive", v2.8.0). This involves some bad magic in fdctrl_connect_drives(), and exists for backward compatibility. The functions for boards to create floppy controller devices fdctrl_init_isa(), fdctrl_init_sysbus(), and sun4m_fdctrl_init() desugar -drive if=floppy to these floppy controller drive properties. If you use both -drive if=floppy (or its -fda / -fdb sugar) and -global isa-fdc for the same floppy device, -global silently loses the conflict, and both backends involved end up with the floppy device frontend attached, as demonstrated by iotest 172 (see commit before previous). This is wrong. Desugar -drive if=floppy straight to floppy devices instead, with helper fdctrl_init_drives(). The conflict now gets rejected cleanly: first, fdctrl_connect_drives() creates the floppy for the controller's property, then fdctrl_init_drives() attempts to create the floppy for -drive if=floppy, but fails because the unit is already in use. Output of iotest 172 changes in three ways: 1. The clash gets rejected. 2. In one test case, "info qtree" has the floppy devices swapped, and "info block" has their QOM paths swapped. This is because the floppy device for -fda now gets created after the one for -global isa-fdc.driveB. 3. The error message for -global floppy.drive=floppy0 changes. Before the patch, we set isa-fdc.driveA to -fda's block backend, then create the floppy device for it, then move the backend from isa-fdc.driveA to floppy.drive. Floppy creation fails when applying -global floppy.drive=floppy0, because floppy0 is still attached to isa-fdc. After the patch, we create the floppy for -fda, then set its drive property to floppy0. Now floppy creation succeeds, but setting the drive property fails, because -global already set it. Yes, this is exasperatingly complicated. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20200622094227.1271650-5-armbru@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/block/fdc.c51
-rw-r--r--hw/isa/isa-superio.c18
-rw-r--r--hw/sparc64/sun4u.c9
3 files changed, 35 insertions, 43 deletions
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index be0674e..2650dcb 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -2497,6 +2497,29 @@ static void fdctrl_result_timer(void *opaque)
}
/* Init functions */
+
+static void fdctrl_init_drives(FloppyBus *bus, DriveInfo **fds)
+{
+ DeviceState *dev;
+ int i;
+
+ for (i = 0; i < MAX_FD; i++) {
+ if (fds[i]) {
+ dev = qdev_new("floppy");
+ qdev_prop_set_uint32(dev, "unit", i);
+ qdev_prop_set_enum(dev, "drive-type", FLOPPY_DRIVE_TYPE_AUTO);
+ qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[i]),
+ &error_fatal);
+ qdev_realize_and_unref(dev, &bus->bus, &error_fatal);
+ }
+ }
+}
+
+void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds)
+{
+ fdctrl_init_drives(&ISA_FDC(fdc)->state.bus, fds);
+}
+
static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev,
Error **errp)
{
@@ -2544,25 +2567,15 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev,
ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
{
- DeviceState *dev;
ISADevice *isadev;
isadev = isa_try_new(TYPE_ISA_FDC);
if (!isadev) {
return NULL;
}
- dev = DEVICE(isadev);
-
- if (fds[0]) {
- qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]),
- &error_fatal);
- }
- if (fds[1]) {
- qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]),
- &error_fatal);
- }
isa_realize_and_unref(isadev, bus, &error_fatal);
+ isa_fdc_init_drives(isadev, fds);
return isadev;
}
@@ -2578,18 +2591,12 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
sys = SYSBUS_FDC(dev);
fdctrl = &sys->state;
fdctrl->dma_chann = dma_chann; /* FIXME */
- if (fds[0]) {
- qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]),
- &error_fatal);
- }
- if (fds[1]) {
- qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]),
- &error_fatal);
- }
sbd = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sbd, &error_fatal);
sysbus_connect_irq(sbd, 0, irq);
sysbus_mmio_map(sbd, 0, mmio_base);
+
+ fdctrl_init_drives(&sys->state.bus, fds);
}
void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
@@ -2599,15 +2606,13 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
FDCtrlSysBus *sys;
dev = qdev_new("SUNW,fdtwo");
- if (fds[0]) {
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[0]),
- &error_fatal);
- }
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sys = SYSBUS_FDC(dev);
sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq);
sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base);
*fdc_tc = qdev_get_gpio_in(dev, 0);
+
+ fdctrl_init_drives(&sys->state.bus, fds);
}
static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl,
diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c
index d3d58f9..e2e47d8 100644
--- a/hw/isa/isa-superio.c
+++ b/hw/isa/isa-superio.c
@@ -17,6 +17,7 @@
#include "sysemu/sysemu.h"
#include "sysemu/blockdev.h"
#include "chardev/char.h"
+#include "hw/block/fdc.h"
#include "hw/isa/superio.h"
#include "hw/qdev-properties.h"
#include "hw/input/i8042.h"
@@ -31,7 +32,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp)
ISADevice *isa;
DeviceState *d;
Chardev *chr;
- DriveInfo *drive;
+ DriveInfo *fd[MAX_FD];
char *name;
int i;
@@ -115,7 +116,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp)
/* Floppy disc */
if (!k->floppy.is_enabled || k->floppy.is_enabled(sio, 0)) {
- isa = isa_new("isa-fdc");
+ isa = isa_new(TYPE_ISA_FDC);
d = DEVICE(isa);
if (k->floppy.get_iobase) {
qdev_prop_set_uint32(d, "iobase", k->floppy.get_iobase(sio, 0));
@@ -124,19 +125,12 @@ static void isa_superio_realize(DeviceState *dev, Error **errp)
qdev_prop_set_uint32(d, "irq", k->floppy.get_irq(sio, 0));
}
/* FIXME use a qdev drive property instead of drive_get() */
- drive = drive_get(IF_FLOPPY, 0, 0);
- if (drive != NULL) {
- qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive),
- &error_fatal);
- }
- /* FIXME use a qdev drive property instead of drive_get() */
- drive = drive_get(IF_FLOPPY, 0, 1);
- if (drive != NULL) {
- qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive),
- &error_fatal);
+ for (i = 0; i < MAX_FD; i++) {
+ fd[i] = drive_get(IF_FLOPPY, 0, i);
}
object_property_add_child(OBJECT(sio), "isa-fdc", OBJECT(isa));
isa_realize_and_unref(isa, bus, &error_fatal);
+ isa_fdc_init_drives(isa, fd);
sio->floppy = isa;
trace_superio_create_floppy(0,
k->floppy.get_iobase ?
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 97e6d3a..9c8655c 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -341,16 +341,9 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
}
isa_dev = isa_new(TYPE_ISA_FDC);
dev = DEVICE(isa_dev);
- if (fd[0]) {
- qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]),
- &error_abort);
- }
- if (fd[1]) {
- qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]),
- &error_abort);
- }
qdev_prop_set_uint32(dev, "dma", -1);
isa_realize_and_unref(isa_dev, s->isa_bus, &error_fatal);
+ isa_fdc_init_drives(isa_dev, fd);
/* Power */
dev = qdev_new(TYPE_SUN4U_POWER);