diff --git a/MAINTAINERS b/MAINTAINERS index ade1100202..b76fb31861 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1577,7 +1577,7 @@ F: tests/qtest/ide-test.c F: tests/qtest/ahci-test.c F: tests/qtest/cdrom-test.c F: tests/qtest/libqos/ahci* -T: git https://github.com/jnsnow/qemu.git ide +T: git https://gitlab.com/jsnow/qemu.git ide IPMI M: Corey Minyard @@ -1595,7 +1595,7 @@ S: Supported F: hw/block/fdc.c F: include/hw/block/fdc.h F: tests/qtest/fdc-test.c -T: git https://github.com/jnsnow/qemu.git ide +T: git https://gitlab.com/jsnow/qemu.git ide OMAP M: Peter Maydell @@ -2169,7 +2169,7 @@ F: block/commit.c F: block/stream.c F: block/mirror.c F: qapi/job.json -T: git https://github.com/jnsnow/qemu.git jobs +T: git https://gitlab.com/jsnow/qemu.git jobs Block QAPI, monitor, command line M: Markus Armbruster diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index ee1d47ff75..680304a24c 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -250,7 +250,7 @@ static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr, } *ptr = dma_memory_map(as, addr, &len, DMA_DIRECTION_FROM_DEVICE); - if (len < wanted) { + if (len < wanted && *ptr) { dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len); *ptr = NULL; } diff --git a/hw/ide/core.c b/hw/ide/core.c index f76f7e5234..0e32abd779 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -367,7 +367,7 @@ fill_buffer: static void ide_set_signature(IDEState *s) { - s->select &= 0xf0; /* clear head */ + s->select &= ~(ATA_DEV_HS); /* clear head */ /* put signature */ s->nsector = 1; s->sector = 1; @@ -586,48 +586,54 @@ void ide_transfer_stop(IDEState *s) int64_t ide_get_sector(IDEState *s) { int64_t sector_num; - if (s->select & 0x40) { - /* lba */ - if (!s->lba48) { - sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | - (s->lcyl << 8) | s->sector; - } else { + if (s->select & (ATA_DEV_LBA)) { + if (s->lba48) { sector_num = ((int64_t)s->hob_hcyl << 40) | ((int64_t) s->hob_lcyl << 32) | ((int64_t) s->hob_sector << 24) | ((int64_t) s->hcyl << 16) | ((int64_t) s->lcyl << 8) | s->sector; + } else { + /* LBA28 */ + sector_num = ((s->select & (ATA_DEV_LBA_MSB)) << 24) | + (s->hcyl << 16) | (s->lcyl << 8) | s->sector; } } else { + /* CHS */ sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + - (s->select & 0x0f) * s->sectors + (s->sector - 1); + (s->select & (ATA_DEV_HS)) * s->sectors + (s->sector - 1); } + return sector_num; } void ide_set_sector(IDEState *s, int64_t sector_num) { unsigned int cyl, r; - if (s->select & 0x40) { - if (!s->lba48) { - s->select = (s->select & 0xf0) | (sector_num >> 24); - s->hcyl = (sector_num >> 16); - s->lcyl = (sector_num >> 8); - s->sector = (sector_num); - } else { + if (s->select & (ATA_DEV_LBA)) { + if (s->lba48) { s->sector = sector_num; s->lcyl = sector_num >> 8; s->hcyl = sector_num >> 16; s->hob_sector = sector_num >> 24; s->hob_lcyl = sector_num >> 32; s->hob_hcyl = sector_num >> 40; + } else { + /* LBA28 */ + s->select = (s->select & ~(ATA_DEV_LBA_MSB)) | + ((sector_num >> 24) & (ATA_DEV_LBA_MSB)); + s->hcyl = (sector_num >> 16); + s->lcyl = (sector_num >> 8); + s->sector = (sector_num); } } else { + /* CHS */ cyl = sector_num / (s->heads * s->sectors); r = sector_num % (s->heads * s->sectors); s->hcyl = cyl >> 8; s->lcyl = cyl; - s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f); + s->select = (s->select & ~(ATA_DEV_HS)) | + ((r / s->sectors) & (ATA_DEV_HS)); s->sector = (r % s->sectors) + 1; } } @@ -1215,8 +1221,7 @@ static void ide_cmd_lba48_transform(IDEState *s, int lba48) static void ide_clear_hob(IDEBus *bus) { /* any write clears HOB high bit of device control register */ - bus->ifs[0].select &= ~(1 << 7); - bus->ifs[1].select &= ~(1 << 7); + bus->cmd &= ~(IDE_CTRL_HOB); } /* IOport [W]rite [R]egisters */ @@ -1256,12 +1261,14 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) return; } + /* NOTE: Device0 and Device1 both receive incoming register writes. + * (They're on the same bus! They have to!) */ + switch (reg_num) { case 0: break; case ATA_IOPORT_WR_FEATURES: ide_clear_hob(bus); - /* NOTE: data is written to the two drives */ bus->ifs[0].hob_feature = bus->ifs[0].feature; bus->ifs[1].hob_feature = bus->ifs[1].feature; bus->ifs[0].feature = val; @@ -1296,15 +1303,16 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) bus->ifs[1].hcyl = val; break; case ATA_IOPORT_WR_DEVICE_HEAD: - /* FIXME: HOB readback uses bit 7 */ - bus->ifs[0].select = (val & ~0x10) | 0xa0; - bus->ifs[1].select = (val | 0x10) | 0xa0; + ide_clear_hob(bus); + bus->ifs[0].select = val | (ATA_DEV_ALWAYS_ON); + bus->ifs[1].select = val | (ATA_DEV_ALWAYS_ON); /* select drive */ - bus->unit = (val >> 4) & 1; + bus->unit = (val & (ATA_DEV_SELECT)) ? 1 : 0; break; default: case ATA_IOPORT_WR_COMMAND: - /* command */ + ide_clear_hob(bus); + qemu_irq_lower(bus->irq); ide_exec_cmd(bus, val); break; } @@ -1338,7 +1346,7 @@ static void ide_reset(IDEState *s) s->hob_lcyl = 0; s->hob_hcyl = 0; - s->select = 0xa0; + s->select = (ATA_DEV_ALWAYS_ON); s->status = READY_STAT | SEEK_STAT; s->lba48 = 0; @@ -2142,9 +2150,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr) int ret, hob; reg_num = addr & 7; - /* FIXME: HOB readback uses bit 7, but it's always set right now */ - //hob = s->select & (1 << 7); - hob = 0; + hob = bus->cmd & (IDE_CTRL_HOB); switch (reg_num) { case ATA_IOPORT_RR_DATA: ret = 0xff; @@ -2235,34 +2241,56 @@ uint32_t ide_status_read(void *opaque, uint32_t addr) return ret; } -void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val) +static void ide_perform_srst(IDEState *s) +{ + s->status |= BUSY_STAT; + + /* Halt PIO (Via register state); PIO BH remains scheduled. */ + ide_transfer_halt(s); + + /* Cancel DMA -- may drain block device and invoke callbacks */ + ide_cancel_dma_sync(s); + + /* Cancel PIO callback, reset registers/signature, etc */ + ide_reset(s); + + if (s->drive_kind == IDE_CD) { + /* ATAPI drives do not set READY or SEEK */ + s->status = 0x00; + } +} + +static void ide_bus_perform_srst(void *opaque) { IDEBus *bus = opaque; IDEState *s; int i; - trace_ide_cmd_write(addr, val, bus); + for (i = 0; i < 2; i++) { + s = &bus->ifs[i]; + ide_perform_srst(s); + } +} - /* common for both drives */ - if (!(bus->cmd & IDE_CMD_RESET) && - (val & IDE_CMD_RESET)) { - /* reset low to high */ - for(i = 0;i < 2; i++) { +void ide_ctrl_write(void *opaque, uint32_t addr, uint32_t val) +{ + IDEBus *bus = opaque; + IDEState *s; + int i; + + trace_ide_ctrl_write(addr, val, bus); + + /* Device0 and Device1 each have their own control register, + * but QEMU models it as just one register in the controller. */ + if ((bus->cmd & IDE_CTRL_RESET) && + !(val & IDE_CTRL_RESET)) { + /* SRST triggers on falling edge */ + for (i = 0; i < 2; i++) { s = &bus->ifs[i]; - s->status = BUSY_STAT | SEEK_STAT; - s->error = 0x01; - } - } else if ((bus->cmd & IDE_CMD_RESET) && - !(val & IDE_CMD_RESET)) { - /* high to low */ - for(i = 0;i < 2; i++) { - s = &bus->ifs[i]; - if (s->drive_kind == IDE_CD) - s->status = 0x00; /* NOTE: READY is _not_ set */ - else - s->status = READY_STAT | SEEK_STAT; - ide_set_signature(s); + s->status |= BUSY_STAT; } + aio_bh_schedule_oneshot(qemu_get_aio_context(), + ide_bus_perform_srst, bus); } bus->cmd = val; diff --git a/hw/ide/ioport.c b/hw/ide/ioport.c index ab1f4e5d9c..b613ff3bba 100644 --- a/hw/ide/ioport.c +++ b/hw/ide/ioport.c @@ -46,7 +46,7 @@ static const MemoryRegionPortio ide_portio_list[] = { }; static const MemoryRegionPortio ide_portio2_list[] = { - { 0, 1, 1, .read = ide_status_read, .write = ide_cmd_write }, + { 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write }, PORTIO_END_OF_LIST(), }; diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 62a599a075..b270a10163 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -329,7 +329,7 @@ static void pmac_ide_write(void *opaque, hwaddr addr, uint64_t val, case 0x8: case 0x16: if (size == 1) { - ide_cmd_write(&d->bus, 0, val); + ide_ctrl_write(&d->bus, 0, val); } break; case 0x20: diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 4bf6e3a8b7..36e2f4790a 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -98,16 +98,16 @@ static uint64_t mmio_ide_status_read(void *opaque, hwaddr addr, return ide_status_read(&s->bus, 0); } -static void mmio_ide_cmd_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) +static void mmio_ide_ctrl_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { MMIOState *s = opaque; - ide_cmd_write(&s->bus, 0, val); + ide_ctrl_write(&s->bus, 0, val); } static const MemoryRegionOps mmio_ide_cs_ops = { .read = mmio_ide_status_read, - .write = mmio_ide_cmd_write, + .write = mmio_ide_ctrl_write, .endianness = DEVICE_LITTLE_ENDIAN, }; diff --git a/hw/ide/pci.c b/hw/ide/pci.c index b50091b615..84ba733548 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -38,7 +38,7 @@ (IDE_RETRY_DMA | IDE_RETRY_PIO | \ IDE_RETRY_READ | IDE_RETRY_FLUSH) -static uint64_t pci_ide_cmd_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t pci_ide_status_read(void *opaque, hwaddr addr, unsigned size) { IDEBus *bus = opaque; @@ -48,20 +48,20 @@ static uint64_t pci_ide_cmd_read(void *opaque, hwaddr addr, unsigned size) return ide_status_read(bus, addr + 2); } -static void pci_ide_cmd_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) +static void pci_ide_ctrl_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) { IDEBus *bus = opaque; if (addr != 2 || size != 1) { return; } - ide_cmd_write(bus, addr + 2, data); + ide_ctrl_write(bus, addr + 2, data); } const MemoryRegionOps pci_ide_cmd_le_ops = { - .read = pci_ide_cmd_read, - .write = pci_ide_cmd_write, + .read = pci_ide_status_read, + .write = pci_ide_ctrl_write, .endianness = DEVICE_LITTLE_ENDIAN, }; diff --git a/hw/ide/trace-events b/hw/ide/trace-events index 2e4162629f..6e357685f9 100644 --- a/hw/ide/trace-events +++ b/hw/ide/trace-events @@ -5,7 +5,7 @@ ide_ioport_read(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p" ide_ioport_write(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p" ide_status_read(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Alt Status); val 0x%02"PRIx32"; bus %p; IDEState %p" -ide_cmd_write(uint32_t addr, uint32_t val, void *bus) "IDE PIO wr @ 0x%"PRIx32" (Device Control); val 0x%02"PRIx32"; bus %p" +ide_ctrl_write(uint32_t addr, uint32_t val, void *bus) "IDE PIO wr @ 0x%"PRIx32" (Device Control); val 0x%02"PRIx32"; bus %p" # Warning: verbose ide_data_readw(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p" ide_data_writew(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p" diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index 8a95ad8c4d..2d09162eeb 100644 --- a/include/hw/ide/internal.h +++ b/include/hw/ide/internal.h @@ -29,6 +29,17 @@ OBJECT_DECLARE_SIMPLE_TYPE(IDEBus, IDE_BUS) #define MAX_IDE_DEVS 2 +/* Device/Head ("select") Register */ +#define ATA_DEV_SELECT 0x10 +/* ATA1,3: Defined as '1'. + * ATA2: Reserved. + * ATA3-7: obsolete. */ +#define ATA_DEV_ALWAYS_ON 0xA0 +#define ATA_DEV_LBA 0x40 +#define ATA_DEV_LBA_MSB 0x0F /* LBA 24:27 */ +#define ATA_DEV_HS 0x0F /* HS 3:0 */ + + /* Bits of HD_STATUS */ #define ERR_STAT 0x01 #define INDEX_STAT 0x02 @@ -57,8 +68,10 @@ OBJECT_DECLARE_SIMPLE_TYPE(IDEBus, IDE_BUS) #define REL 0x04 #define TAG_MASK 0xf8 -#define IDE_CMD_RESET 0x04 -#define IDE_CMD_DISABLE_IRQ 0x02 +/* Bits of Device Control register */ +#define IDE_CTRL_HOB 0x80 +#define IDE_CTRL_RESET 0x04 +#define IDE_CTRL_DISABLE_IRQ 0x02 /* ACS-2 T13/2015-D Table B.2 Command codes */ #define WIN_NOP 0x00 @@ -559,7 +572,7 @@ static inline IDEState *idebus_active_if(IDEBus *bus) static inline void ide_set_irq(IDEBus *bus) { - if (!(bus->cmd & IDE_CMD_DISABLE_IRQ)) { + if (!(bus->cmd & IDE_CTRL_DISABLE_IRQ)) { qemu_irq_raise(bus->irq); } } @@ -598,7 +611,7 @@ void ide_atapi_io_error(IDEState *s, int ret); void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val); uint32_t ide_ioport_read(void *opaque, uint32_t addr1); uint32_t ide_status_read(void *opaque, uint32_t addr); -void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val); +void ide_ctrl_write(void *opaque, uint32_t addr, uint32_t val); void ide_data_writew(void *opaque, uint32_t addr, uint32_t val); uint32_t ide_data_readw(void *opaque, uint32_t addr); void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);