From patchwork Wed Dec 16 07:45:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Denis V. Lunev" X-Patchwork-Id: 557337 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 371291402ED for ; Wed, 16 Dec 2015 18:45:59 +1100 (AEDT) Received: from localhost ([::1]:45847 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a96ma-0004Iu-Ta for incoming@patchwork.ozlabs.org; Wed, 16 Dec 2015 02:45:56 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59698) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a96mG-00041w-VS for qemu-devel@nongnu.org; Wed, 16 Dec 2015 02:45:38 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1a96mD-0002kQ-1A for qemu-devel@nongnu.org; Wed, 16 Dec 2015 02:45:36 -0500 Received: from mailhub.sw.ru ([195.214.232.25]:9880 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a96mC-0002kI-D0 for qemu-devel@nongnu.org; Wed, 16 Dec 2015 02:45:32 -0500 Received: from irbis.sw.ru ([10.30.2.139]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id tBG7j9Xg002974; Wed, 16 Dec 2015 10:45:10 +0300 (MSK) From: "Denis V. Lunev" To: Date: Wed, 16 Dec 2015 10:45:09 +0300 Message-Id: <1450251909-1599-1-git-send-email-den@openvz.org> X-Mailer: git-send-email 2.1.4 X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x X-Received-From: 195.214.232.25 Cc: Kevin Wolf , Eduardo Habkost , "Michael S. Tsirkin" , qemu-devel@nongnu.org, qemu-stable@nongnu.org, Paolo Bonzini , Roman Kagan , Igor Mammedov , "Denis V. Lunev" , John Snow , Richard Henderson Subject: [Qemu-devel] [PATCH v2 1/1] i386: expose floppy-related objects in SSDT X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Roman Kagan 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 Signed-off-by: Denis V. Lunev CC: Michael S. Tsirkin CC: Igor Mammedov CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: John Snow CC: Kevin Wolf Acked-by: John Snow Signed-off-by: Roman Kagan Signed-off-by: Denis V. Lunev Signed-off-by: Roman Kagan Signed-off-by: Denis V. Lunev --- - 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; +} + 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,