static int __dev_ata_data(ata_t *ata, io_insn_t *io) { ata_dev_t *disk = &ata->devices[0]; int rc; debug(DEV_ATA, "ata data\n"); if(ata->cmd != ATA_READ_SECTOR_CMD && ata->cmd != ATA_WRITE_SECTOR_CMD) return dev_io_proxify(io); rc = dev_io_proxify(io); if(rc == VM_DONE) { disk->lba++; disk->cnt--; } return rc; }
/* ** ATA Command/Register access dispatcher */ int dev_ata(ata_t *ata, io_insn_t *io) { if(!io->in) ata->last_out = io->port; if(io->port == ATA_STATUS_REG(ata->base)) { if(io->in) return __dev_ata_status(ata, io); else return dev_io_proxify_filter(io, __dev_ata_cmd_filter, ata); } if(io->port == ATA_ALT_STATUS_REG(ata->base)) { if(io->in) return __dev_ata_alt_status(ata, io); else goto __proxify; } if(io->port == ATA_DEVICE_REG(ata->base)) return __dev_ata_device(ata, io); if(io->port == ATA_DATA_REG(ata->base)) return __dev_ata_data(ata, io); if(io->port == ATA_SECT_CNT_REG(ata->base)) return dev_io_proxify_filter(io, __dev_ata_scnt_filter, ata); if(io->port == ATA_LBA_LOW_REG(ata->base) || io->port == ATA_LBA_MID_REG(ata->base) || io->port == ATA_LBA_HIGH_REG(ata->base)) return dev_io_proxify_filter(io, __dev_ata_lba_filter, ata); if(io->port == ATA_ERR_REG(ata->base)) { if(io->in) debug(DEV_ATA, "ata err\n"); else debug(DEV_ATA, "ata feat\n"); goto __proxify; } debug(DEV_ATA, "ata ???\n"); __proxify: return dev_io_proxify(io); }
int dev_access() { io_insn_t io; __io_init(&io); #ifdef CONFIG_HAS_NET if(io.port == PCI_CONFIG_ADDR || io.port == PCI_CONFIG_DATA) return dev_pci(&io); #endif if(io.port == PS2_SYS_CTRL_PORT_A) return dev_ps2(&info->vm.dev.ps2, &io); if(range(io.port, KBD_START_PORT, KBD_END_PORT)) return dev_kbd(&info->vm.dev.kbd, &io); if(range(io.port, COM1_START_PORT, COM1_END_PORT)) return dev_uart(&info->vm.dev.uart, &io); return dev_io_proxify(&io); }
static int __dev_ata_device(ata_t *ata, io_insn_t *io) { ata_dev_reg_t dev; int rc; io_size_t sz = {.available = sizeof(ata_dev_reg_t)}; if(io->in) return dev_io_proxify(io); else { /* check crazy io (should not happen) */ if((io->sz * io->cnt) > sizeof(ata_dev_reg_t)) { debug(DEV_ATA, "unsupported ata dev access\n"); return VM_FAIL; } rc = dev_io_insn(io, (void*)&dev.raw, &sz); if(rc != VM_DONE) return rc; ata->dev_head = dev; debug(DEV_ATA, "ata device [%s]\n", dev.dev ? "SLAVE":"MASTER"); return dev_io_native(io, &dev.raw); } } static int __fake_ata_status(ata_t *ata) { if(ata->last_out == ATA_CMD_REG(ata->base)) info->vm.cpu.gpr->rax.blow = 1; else if(ata->last_out == ATA_DEVICE_REG(ata->base)) info->vm.cpu.gpr->rax.blow = 0; else { debug(DEV_ATA, "can't fake status for previous out(0x%x)\n", ata->last_out); return VM_FAIL; } return VM_DONE; } static int __dev_ata_status(ata_t *ata, io_insn_t *io) { if(!__rmode() && __ata_guest_want_slave(ata)) { debug(DEV_ATA, "ata fake status\n"); return __fake_ata_status(ata); } debug(DEV_ATA, "ata status\n"); return dev_io_proxify(io); } static int __dev_ata_alt_status(ata_t *ata, io_insn_t *io) { if(!__rmode() && __ata_guest_want_slave(ata)) { debug(DEV_ATA, "ata fake ALT status\n"); return __fake_ata_status(ata); } debug(DEV_ATA, "ata ALT status\n"); return dev_io_proxify(io); } static int __dev_ata_lba_filter(void *device, void *arg) { ata_t *ata = (ata_t*)arg; ata_dev_t *disk = &ata->devices[0]; uint8_t lba = *(uint8_t*)device; uint8_t idx = ata->last_out - ATA_LBA_LOW_REG(ata->base); if(idx > 2) { debug(DEV_ATA, "unknown (internal) LBA index access (%d)\n", idx); return VM_FAIL; } disk->lba_r[idx] = lba; debug(DEV_ATA, "ata lba[%d] = 0x%x\n", idx, lba); return VM_DONE; }