On 12/16/2015 02:45 AM, Denis V. Lunev wrote: > From: Roman Kagan <rka...@virtuozzo.com> > > On x86-based systems Linux determines the presence and the type of > floppy drives via a query of a CMOS field. So does SeaBIOS when > populating the return data for int 0x13 function 0x08. > > Windows doesn't; instead, it requests this information from BIOS via int > 0x13/0x08 or through ACPI objects _FDE (Floppy Drive Enumerate) and _FDI > (Floppy Drive Information). On UEFI systems only ACPI-based detection > is supported. > > QEMU used not to provide those objects in its ACPI tables; as a result > floppy drives were invisible to Windows on UEFI/OVMF. > > This patch implements those objects in SSDT, populating them via AML > API. For that, a couple of functions are extern-ified to facilitate > populating those objects in acpi-build.c. > > Signed-off-by: Roman Kagan <rka...@virtuozzo.com> > Signed-off-by: Denis V. Lunev <d...@openvz.org> > CC: Michael S. Tsirkin <m...@redhat.com> > CC: Igor Mammedov <imamm...@redhat.com> > CC: Paolo Bonzini <pbonz...@redhat.com> > CC: Richard Henderson <r...@twiddle.net> > CC: Eduardo Habkost <ehabk...@redhat.com> > CC: John Snow <js...@redhat.com> > CC: Kevin Wolf <kw...@redhat.com> > --- > - The patch is made against QEMU upstream > > hw/block/fdc.c | 11 +++++++ > hw/i386/acpi-build.c | 78 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/i386/pc.c | 46 +++++++++++++++++------------ > include/hw/block/fdc.h | 2 ++ > include/hw/i386/pc.h | 3 ++ > 5 files changed, 121 insertions(+), 19 deletions(-) > > diff --git a/hw/block/fdc.c b/hw/block/fdc.c > index 4292ece..c858c5f 100644 > --- a/hw/block/fdc.c > +++ b/hw/block/fdc.c > @@ -2408,6 +2408,17 @@ FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int > i) > return isa->state.drives[i].drive; > } > > +void isa_fdc_get_drive_geometry(ISADevice *fdc, int i, uint8_t *cylinders, > + uint8_t *heads, uint8_t *sectors) > +{ > + FDCtrlISABus *isa = ISA_FDC(fdc); > + FDrive *drv = &isa->state.drives[i]; > + > + *cylinders = drv->max_track; > + *heads = (drv->flags & FDISK_DBL_SIDES) ? 2 : 1; > + *sectors = drv->last_sect; > +} > + > static const VMStateDescription vmstate_isa_fdc ={ > .name = "fdc", > .version_id = 2, > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index 95e0c65..7f902b1 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -38,6 +38,7 @@ > #include "hw/acpi/bios-linker-loader.h" > #include "hw/loader.h" > #include "hw/isa/isa.h" > +#include "hw/block/fdc.h" > #include "hw/acpi/memory_hotplug.h" > #include "sysemu/tpm.h" > #include "hw/acpi/tpm.h" > @@ -105,6 +106,13 @@ typedef struct AcpiPmInfo { > uint16_t pcihp_io_len; > } AcpiPmInfo; > > +typedef struct AcpiFDInfo { > + uint8_t type; > + uint8_t cylinders; > + uint8_t heads; > + uint8_t sectors; > +} AcpiFDInfo; > + > typedef struct AcpiMiscInfo { > bool has_hpet; > TPMVersion tpm_version; > @@ -112,6 +120,7 @@ typedef struct AcpiMiscInfo { > unsigned dsdt_size; > uint16_t pvpanic_port; > uint16_t applesmc_io_base; > + AcpiFDInfo fdinfo[2]; > } AcpiMiscInfo; > > typedef struct AcpiBuildPciBusHotplugState { > @@ -235,10 +244,25 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) > > static void acpi_get_misc_info(AcpiMiscInfo *info) > { > + int i; > + ISADevice *fdc; > + > info->has_hpet = hpet_find(); > info->tpm_version = tpm_get_version(); > info->pvpanic_port = pvpanic_port(); > info->applesmc_io_base = applesmc_port(); > + > + fdc = pc_find_fdc0(); > + if (fdc != NULL) { > + for (i = 0; i < ARRAY_SIZE(info->fdinfo); i++) { > + AcpiFDInfo *fdinfo = &info->fdinfo[i]; > + fdinfo->type = isa_fdc_get_drive_type(fdc, i); > + if (fdinfo->type < FDRIVE_DRV_NONE) { > + isa_fdc_get_drive_geometry(fdc, i, &fdinfo->cylinders, > + &fdinfo->heads, &fdinfo->sectors); > + } > + } > + } > } > > /* > @@ -900,6 +924,40 @@ static Aml *build_crs(PCIHostState *host, > return crs; > } > > +static Aml *build_fdinfo_aml(int idx, AcpiFDInfo *fdinfo) > +{ > + Aml *dev, *fdi; > + > + dev = aml_device("FLP%c", 'A' + idx); > + > + aml_append(dev, aml_name_decl("_ADR", aml_int(idx))); > + > + fdi = aml_package(0x10); > + aml_append(fdi, aml_int(idx)); /* Drive Number */ > + aml_append(fdi, > + aml_int(cmos_get_fd_drive_type(fdinfo->type))); /* Device Type */ > + aml_append(fdi, > + aml_int(fdinfo->cylinders - 1)); /* Maximum Cylinder Number */ > + aml_append(fdi, aml_int(fdinfo->sectors)); /* Maximum Sector Number */ > + aml_append(fdi, aml_int(fdinfo->heads - 1)); /* Maximum Head Number */ > + /* SeaBIOS returns the below values for int 0x13 func 0x08 regardless of > + * the drive type, so shall we */ > + aml_append(fdi, aml_int(0xAF)); /* disk_specify_1 */ > + aml_append(fdi, aml_int(0x02)); /* disk_specify_2 */ > + aml_append(fdi, aml_int(0x25)); /* disk_motor_wait */ > + aml_append(fdi, aml_int(0x02)); /* disk_sector_siz */ > + aml_append(fdi, aml_int(0x12)); /* disk_eot */ > + aml_append(fdi, aml_int(0x1B)); /* disk_rw_gap */ > + aml_append(fdi, aml_int(0xFF)); /* disk_dtl */ > + aml_append(fdi, aml_int(0x6C)); /* disk_formt_gap */ > + aml_append(fdi, aml_int(0xF6)); /* disk_fill */ > + aml_append(fdi, aml_int(0x0F)); /* disk_head_sttl */ > + aml_append(fdi, aml_int(0x08)); /* disk_motor_strt */ > + > + aml_append(dev, aml_name_decl("_FDI", fdi)); > + return dev; > +} > + > static void > build_ssdt(GArray *table_data, GArray *linker, > AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc, > @@ -1125,6 +1183,26 @@ build_ssdt(GArray *table_data, GArray *linker, > aml_append(ssdt, scope); > } > > + { > + uint32_t fde_buf[5] = {0, 0, 0, 0, 0x2}; > + > + scope = aml_scope("\\_SB.PCI0.ISA.FDC0"); > + > + for (i = 0; i < ARRAY_SIZE(misc->fdinfo); i++) { > + AcpiFDInfo *fdinfo = &misc->fdinfo[i]; > + if (fdinfo->type != FDRIVE_DRV_NONE) { > + fde_buf[i] = 0x1; > + aml_append(scope, build_fdinfo_aml(i, fdinfo)); > + } > + } > + > + aml_append(scope, > + aml_name_decl("_FDE", > + aml_buffer(sizeof(fde_buf), (uint8_t *) fde_buf))); > + > + aml_append(ssdt, scope); > + } > + > sb_scope = aml_scope("\\_SB"); > { > /* create PCI0.PRES device and its _CRS to reserve CPU hotplug MMIO > */ > diff --git a/hw/i386/pc.c b/hw/i386/pc.c > index 5e20e07..b7b8774 100644 > --- a/hw/i386/pc.c > +++ b/hw/i386/pc.c > @@ -207,7 +207,7 @@ static void pic_irq_request(void *opaque, int irq, int > level) > > #define REG_EQUIPMENT_BYTE 0x14 > > -static int cmos_get_fd_drive_type(FDriveType fd0) > +int cmos_get_fd_drive_type(FDriveType fd0) > { > int val; > > @@ -368,6 +368,31 @@ static const char * const fdc_container_path[] = { > "/unattached", "/peripheral", "/peripheral-anon" > }; > > +/* > + * Locate the FDC at IO address 0x3f0, in order to configure the CMOS > registers > + * and ACPI objects. > + */ > +ISADevice *pc_find_fdc0(void) > +{ > + int i; > + Object *container; > + CheckFdcState state = { 0 }; > + > + 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"); > + } > + > + return state.floppy; > +} > +
Hmm, Didn't Laszlo Ersek work on a similar problem for 2.4? Oh, yeah, that's literally his code you've factored out from below. :) > static void pc_cmos_init_late(void *opaque) > { > pc_cmos_init_late_arg *arg = opaque; > @@ -376,8 +401,6 @@ static void pc_cmos_init_late(void *opaque) > int8_t heads, sectors; > int val; > int i, trans; > - Object *container; > - CheckFdcState state = { 0 }; > > val = 0; > if (ide_get_geometry(arg->idebus[0], 0, > @@ -407,22 +430,7 @@ static void pc_cmos_init_late(void *opaque) > } > 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); > + pc_cmos_init_floppy(s, pc_find_fdc0()); > > qemu_unregister_reset(pc_cmos_init_late, opaque); > } > diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h > index d48b2f8..adaf3dc 100644 > --- a/include/hw/block/fdc.h > +++ b/include/hw/block/fdc.h > @@ -22,5 +22,7 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, > DriveInfo **fds, qemu_irq *fdc_tc); > > FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i); > +void isa_fdc_get_drive_geometry(ISADevice *fdc, int i, uint8_t *cylinders, > + uint8_t *heads, uint8_t *sectors); > > #endif > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h > index 854c330..32ceb2f 100644 > --- a/include/hw/i386/pc.h > +++ b/include/hw/i386/pc.h > @@ -211,6 +211,9 @@ typedef void (*cpu_set_smm_t)(int smm, void *arg); > > void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name); > > +ISADevice *pc_find_fdc0(void); > +int cmos_get_fd_drive_type(FDriveType fd0); > + > /* acpi_piix.c */ > > I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, > fdc.[ch]: Acked-by: John Snow <js...@redhat.com>