diff options
-rw-r--r-- | hw/ide.h | 2 | ||||
-rw-r--r-- | hw/ide/qdev.c | 7 | ||||
-rw-r--r-- | hw/pc.c | 105 |
3 files changed, 77 insertions, 37 deletions
@@ -23,4 +23,6 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2, qemu_irq irq, int shift, DriveInfo *hd0, DriveInfo *hd1); +void ide_get_bs(BlockDriverState *bs[], BusState *qbus); + #endif /* HW_IDE_H */ diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 0b84a4f1d..a621d5edd 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -90,6 +90,13 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive) return DO_UPCAST(IDEDevice, qdev, dev); } +void ide_get_bs(BlockDriverState *bs[], BusState *qbus) +{ + IDEBus *bus = DO_UPCAST(IDEBus, qbus, qbus); + bs[0] = bus->master ? bus->master->dinfo->bdrv : NULL; + bs[1] = bus->slave ? bus->slave->dinfo->bdrv : NULL; +} + /* --------------------------------- */ typedef struct IDEDrive { @@ -24,6 +24,7 @@ #include "hw.h" #include "pc.h" #include "fdc.h" +#include "ide.h" #include "pci.h" #include "vmware_vga.h" #include "usb-uhci.h" @@ -251,15 +252,66 @@ static int pc_boot_set(void *opaque, const char *boot_device) return(0); } -/* hd_table must contain 4 block drivers */ +typedef struct pc_cmos_init_late_arg { + BusState *idebus0, *idebus1; +} pc_cmos_init_late_arg; + +static void pc_cmos_init_late(void *opaque) +{ + pc_cmos_init_late_arg *arg = opaque; + RTCState *s = rtc_state; + int val; + BlockDriverState *hd_table[4]; + int i; + + ide_get_bs(hd_table, arg->idebus0); + ide_get_bs(hd_table + 2, arg->idebus1); + + 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]); + if (hd_table[1]) + cmos_init_hd(0x1a, 0x24, hd_table[1]); + + 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]); + if (translation == BIOS_ATA_TRANSLATION_AUTO) { + bdrv_get_geometry_hint(hd_table[i], &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); + } + } + rtc_set_memory(s, 0x39, val); + + qemu_unregister_reset(pc_cmos_init_late, opaque); +} + static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, DriveInfo **hd_table) + const char *boot_device, + BusState *idebus0, BusState *idebus1) { RTCState *s = rtc_state; int nbds, bds[3] = { 0, }; int val; int fd0, fd1, nb; int i; + static pc_cmos_init_late_arg arg; /* various important CMOS locations needed by PC/Bochs bios */ @@ -342,37 +394,9 @@ 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); - } - } - rtc_set_memory(s, 0x39, val); + arg.idebus0 = idebus0; + arg.idebus1 = idebus1; + qemu_register_reset(pc_cmos_init_late, &arg); } void ioport_set_a20(int enable) @@ -1007,6 +1031,7 @@ static void pc_init1(ram_addr_t ram_size, qemu_irq *i8259; IsaIrqState *isa_irq_state; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BusState *idebus[MAX_IDE_BUS]; DriveInfo *fd[MAX_FD]; void *fw_cfg; @@ -1216,11 +1241,16 @@ static void pc_init1(ram_addr_t ram_size, } if (pci_enabled) { - pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1); + PCIDevice *dev; + dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1); + idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); } else { for(i = 0; i < MAX_IDE_BUS; i++) { - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], - hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); + ISADevice *dev; + dev = isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); + idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0"); } } @@ -1235,7 +1265,8 @@ static void pc_init1(ram_addr_t ram_size, } floppy_controller = fdctrl_init_isa(fd); - cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd); + cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + idebus[0], idebus[1]); if (pci_enabled && usb_enabled) { usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); |