hw/i386/pc: reflect any FDC @ ioport 0x3f0 in the CMOS
With the pc-q35-2.4 machine type, if the user creates an ISA FDC manually: -device isa-fdc,driveA=drive-fdc0-0-0 \ -drive file=...,if=none,id=drive-fdc0-0-0,format=raw then the board-default FDC will be skipped, and only the explicitly requested FDC will exist. qtree-wise, this is correct; however such an FDC is currently not registered in the CMOS, because that code is only reached for the board-default FDC. The pc_cmos_init_late() one-shot reset handler -- one-shot because the CMOS is not reprogrammed during warm reset -- should search for any ISA FDC devices, created implicitly (by board code) or explicitly, and set the CMOS accordingly to the ISA FDC(s) with iobase=0x3f0: - if there is no such FDC, report both drives absent, - if there is exactly one such FDC, report its drives in the CMOS, - if there are more than one such FDCs, then pick one (it is not specified which one), and print a warning about the ambiguity. Cc: Jan Tomko <jtomko@redhat.com> Cc: John Snow <jsnow@redhat.com> Cc: Markus Armbruster <armbru@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Reported-by: Jan Tomko <jtomko@redhat.com> Suggested-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: John Snow <jsnow@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
7444ca4ee2
commit
b86f46132c
57
hw/i386/pc.c
57
hw/i386/pc.c
|
@ -334,6 +334,41 @@ typedef struct pc_cmos_init_late_arg {
|
||||||
BusState *idebus[2];
|
BusState *idebus[2];
|
||||||
} pc_cmos_init_late_arg;
|
} pc_cmos_init_late_arg;
|
||||||
|
|
||||||
|
typedef struct check_fdc_state {
|
||||||
|
ISADevice *floppy;
|
||||||
|
bool multiple;
|
||||||
|
} CheckFdcState;
|
||||||
|
|
||||||
|
static int check_fdc(Object *obj, void *opaque)
|
||||||
|
{
|
||||||
|
CheckFdcState *state = opaque;
|
||||||
|
Object *fdc;
|
||||||
|
uint32_t iobase;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
fdc = object_dynamic_cast(obj, TYPE_ISA_FDC);
|
||||||
|
if (!fdc) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iobase = object_property_get_int(obj, "iobase", &local_err);
|
||||||
|
if (local_err || iobase != 0x3f0) {
|
||||||
|
error_free(local_err);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->floppy) {
|
||||||
|
state->multiple = true;
|
||||||
|
} else {
|
||||||
|
state->floppy = ISA_DEVICE(obj);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const fdc_container_path[] = {
|
||||||
|
"/unattached", "/peripheral", "/peripheral-anon"
|
||||||
|
};
|
||||||
|
|
||||||
static void pc_cmos_init_late(void *opaque)
|
static void pc_cmos_init_late(void *opaque)
|
||||||
{
|
{
|
||||||
pc_cmos_init_late_arg *arg = opaque;
|
pc_cmos_init_late_arg *arg = opaque;
|
||||||
|
@ -342,6 +377,8 @@ static void pc_cmos_init_late(void *opaque)
|
||||||
int8_t heads, sectors;
|
int8_t heads, sectors;
|
||||||
int val;
|
int val;
|
||||||
int i, trans;
|
int i, trans;
|
||||||
|
Object *container;
|
||||||
|
CheckFdcState state = { 0 };
|
||||||
|
|
||||||
val = 0;
|
val = 0;
|
||||||
if (ide_get_geometry(arg->idebus[0], 0,
|
if (ide_get_geometry(arg->idebus[0], 0,
|
||||||
|
@ -371,6 +408,23 @@ static void pc_cmos_init_late(void *opaque)
|
||||||
}
|
}
|
||||||
rtc_set_memory(s, 0x39, val);
|
rtc_set_memory(s, 0x39, val);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Locate the FDC at IO address 0x3f0, and configure the CMOS registers
|
||||||
|
* accordingly.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(fdc_container_path); i++) {
|
||||||
|
container = container_get(qdev_get_machine(), fdc_container_path[i]);
|
||||||
|
object_child_foreach(container, check_fdc, &state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.multiple) {
|
||||||
|
error_report("warning: multiple floppy disk controllers with "
|
||||||
|
"iobase=0x3f0 have been found;\n"
|
||||||
|
"the one being picked for CMOS setup might not reflect "
|
||||||
|
"your intent");
|
||||||
|
}
|
||||||
|
pc_cmos_init_floppy(s, state.floppy);
|
||||||
|
|
||||||
qemu_unregister_reset(pc_cmos_init_late, opaque);
|
qemu_unregister_reset(pc_cmos_init_late, opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,9 +494,8 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||||
val |= 0x02; /* FPU is there */
|
val |= 0x02; /* FPU is there */
|
||||||
val |= 0x04; /* PS/2 mouse installed */
|
val |= 0x04; /* PS/2 mouse installed */
|
||||||
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
|
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
|
||||||
pc_cmos_init_floppy(s, floppy);
|
|
||||||
|
|
||||||
/* hard drives */
|
/* hard drives and FDC */
|
||||||
arg.rtc_state = s;
|
arg.rtc_state = s;
|
||||||
arg.idebus[0] = idebus0;
|
arg.idebus[0] = idebus0;
|
||||||
arg.idebus[1] = idebus1;
|
arg.idebus[1] = idebus1;
|
||||||
|
|
Loading…
Reference in a new issue