From patchwork Sat Apr 10 16:36:03 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bruce Rogers X-Patchwork-Id: 49905 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 02C15B7D82 for ; Sun, 11 Apr 2010 02:37:19 +1000 (EST) Received: from localhost ([127.0.0.1]:34866 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O0dfz-0003Dl-A9 for incoming@patchwork.ozlabs.org; Sat, 10 Apr 2010 12:36:55 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1O0dfL-0003Dg-4K for qemu-devel@nongnu.org; Sat, 10 Apr 2010 12:36:15 -0400 Received: from [140.186.70.92] (port=49125 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O0dfH-0003DY-Of for qemu-devel@nongnu.org; Sat, 10 Apr 2010 12:36:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1O0dfF-0000ed-6h for qemu-devel@nongnu.org; Sat, 10 Apr 2010 12:36:11 -0400 Received: from sinclair.provo.novell.com ([137.65.248.137]:26992) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1O0dfE-0000eE-6c for qemu-devel@nongnu.org; Sat, 10 Apr 2010 12:36:09 -0400 Received: from INET-PRV-MTA by sinclair.provo.novell.com with Novell_GroupWise; Sat, 10 Apr 2010 10:36:07 -0600 Message-Id: <4BC054930200004800092ADD@sinclair.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 8.0.1 Date: Sat, 10 Apr 2010 10:36:03 -0600 From: "Bruce Rogers" To: Mime-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Novell Netware 6 SP3 Subject: [Qemu-devel] [PATCH] Write cmos hd data for ide drives using -device parm X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org When specifying ide devices using -device, the cmos information which the bios depends on is not written. This patch generalizes the cmos hd data setting for the existing code path and adds the ability to call that code on a per machine, per ide drive basis. This is important for older guests, such as Windows XP, and Windows Server 2003. I needed to add an id to the IDEBus structure since there wasn't a way to identify whether an ide bus was primary or secondary in the lower level code. Signed-off-by: Bruce Rogers Bruce hw/ide/internal.h | 1 hw/ide/piix.c | 2 + hw/ide/qdev.c | 9 ++++++- hw/pc.c | 68 ++++++++++++++++++++++++++++++++---------------------- sysemu.h | 1 vl.c | 6 ++++ 6 files changed, 59 insertions(+), 28 deletions(-) diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 027029e..b04232c 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -450,6 +450,7 @@ struct IDEBus { IDEState ifs[2]; uint8_t unit; uint8_t cmd; + uint8_t id; qemu_irq irq; }; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 295a93d..f62aadb 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -136,6 +136,8 @@ static int pci_piix_ide_initfn(PCIIDEState *d) ide_init_ioport(&d->bus[0], 0x1f0, 0x3f6); ide_init_ioport(&d->bus[1], 0x170, 0x376); + d->bus[0].id = 0; + d->bus[1].id = 1; ide_init2(&d->bus[0], NULL, NULL, isa_reserve_irq(14)); ide_init2(&d->bus[1], NULL, NULL, isa_reserve_irq(15)); return 0; diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index b18693d..632eccd 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -39,6 +39,7 @@ static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base) IDEDevice *dev = DO_UPCAST(IDEDevice, qdev, qdev); IDEDeviceInfo *info = DO_UPCAST(IDEDeviceInfo, qdev, base); IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus); + int i; if (!dev->conf.dinfo) { fprintf(stderr, "%s: no drive specified\n", qdev->info->name); @@ -65,7 +66,13 @@ static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base) default: goto err; } - return info->init(dev); + dev->dinfo->bus = bus->id; + dev->dinfo->unit = dev->unit; + i = info->init(dev); + if (i >= 0) { + machine_ide_finalize(dev->dinfo); + } + return i; err: return -1; diff --git a/hw/pc.c b/hw/pc.c index 69e597f..29f47d4 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -215,6 +215,44 @@ static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) rtc_set_memory(s, info_ofs + 8, sectors); } +static void set_cmos_hd_data(DriveInfo *dinfo) +{ + static int hd_type = 0; + static int hd_trans = 0; + RTCState *s = rtc_state; + int cylinders, heads, sectors, translation; + + if (dinfo->bus == 0) { + if (dinfo->unit == 0) { + hd_type |= 0xf0; + cmos_init_hd(0x19, 0x1b, dinfo->bdrv); + } else { + hd_type |= 0x0f; + cmos_init_hd(0x1a, 0x24, dinfo->bdrv); + } + rtc_set_memory(s, 0x12, hd_type); + } + /* NOTE: bdrv_get_geometry_hint() returns the physical + geometry. It is always such that: 1 <= sects <= 63, 1 + <= heads <= 16, 1 <= cylinders <= 16383. The BIOS + geometry can be different if a translation is done. */ + translation = bdrv_get_translation_hint(dinfo->bdrv); + if (translation == BIOS_ATA_TRANSLATION_AUTO) { + bdrv_get_geometry_hint(dinfo->bdrv, &cylinders, &heads, §ors); + if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { + /* No translation. */ + translation = 0; + } else { + /* LBA translation. */ + translation = 1; + } + } else { + translation--; + } + hd_trans |= translation << ((dinfo->bus * 4) + (dinfo->unit * 2)); + rtc_set_memory(s, 0x39, hd_trans); +} + /* convert boot_device letter to something recognizable by the bios */ static int boot_device2nibble(char boot_device) { @@ -338,37 +376,11 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, /* hard drives */ - rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0)); - if (hd_table[0]) - cmos_init_hd(0x19, 0x1b, hd_table[0]->bdrv); - if (hd_table[1]) - cmos_init_hd(0x1a, 0x24, hd_table[1]->bdrv); - - val = 0; for (i = 0; i < 4; i++) { if (hd_table[i]) { - int cylinders, heads, sectors, translation; - /* NOTE: bdrv_get_geometry_hint() returns the physical - geometry. It is always such that: 1 <= sects <= 63, 1 - <= heads <= 16, 1 <= cylinders <= 16383. The BIOS - geometry can be different if a translation is done. */ - translation = bdrv_get_translation_hint(hd_table[i]->bdrv); - if (translation == BIOS_ATA_TRANSLATION_AUTO) { - bdrv_get_geometry_hint(hd_table[i]->bdrv, &cylinders, &heads, §ors); - if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { - /* No translation. */ - translation = 0; - } else { - /* LBA translation. */ - translation = 1; - } - } else { - translation--; - } - val |= translation << (i * 2); + set_cmos_hd_data(hd_table[i]); } } - rtc_set_memory(s, 0x39, val); } void ioport_set_a20(int enable) @@ -820,6 +832,8 @@ static void pc_init1(ram_addr_t ram_size, DriveInfo *fd[MAX_FD]; void *fw_cfg; + machine_ide_finalize = set_cmos_hd_data; + if (ram_size >= 0xe0000000 ) { above_4g_mem_size = ram_size - 0xe0000000; below_4g_mem_size = 0xe0000000; diff --git a/sysemu.h b/sysemu.h index d0effa0..564d477 100644 --- a/sysemu.h +++ b/sysemu.h @@ -242,5 +242,6 @@ void usb_info(Monitor *mon); void rtc_change_mon_event(struct tm *tm); void register_devices(void); +extern void (*machine_ide_finalize)(DriveInfo *dinfo); #endif diff --git a/vl.c b/vl.c index ea79ac4..8ab3349 100644 --- a/vl.c +++ b/vl.c @@ -228,6 +228,7 @@ int ctrl_grab = 0; unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; int boot_menu; +void (*machine_ide_finalize)(DriveInfo *dinfo); int nb_numa_nodes; uint64_t node_mem[MAX_NODES]; @@ -275,6 +276,10 @@ static struct { { .driver = "vmware-svga", .flag = &default_vga }, }; +static void default_ide_finalize(DriveInfo *dinfo) +{ +} + static int default_driver_check(QemuOpts *opts, void *opaque) { const char *driver = qemu_opt_get(opts, "driver"); @@ -2624,6 +2629,7 @@ int main(int argc, char **argv, char **envp) module_call_init(MODULE_INIT_MACHINE); machine = find_default_machine(); + machine_ide_finalize = default_ide_finalize; cpu_model = NULL; initrd_filename = NULL; ram_size = 0;