📄 ide.c
字号:
uint16_t *p; unsigned int oldsize; char buf[20]; if (s->identify_set) { memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); return; } memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; put_le16(p + 0, 0x0040); put_le16(p + 1, s->cylinders); put_le16(p + 3, s->heads); put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ put_le16(p + 5, 512); /* XXX: retired, remove ? */ put_le16(p + 6, s->sectors); snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ put_le16(p + 20, 3); /* XXX: retired, remove ? */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */#if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);#endif put_le16(p + 48, 1); /* dword I/O */ put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */ put_le16(p + 51, 0x200); /* PIO transfer cycle */ put_le16(p + 52, 0x200); /* DMA transfer cycle */ put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */ put_le16(p + 54, s->cylinders); put_le16(p + 55, s->heads); put_le16(p + 56, s->sectors); oldsize = s->cylinders * s->heads * s->sectors; put_le16(p + 57, oldsize); put_le16(p + 58, oldsize >> 16); if (s->mult_sectors) put_le16(p + 59, 0x100 | s->mult_sectors); put_le16(p + 60, s->nb_sectors); put_le16(p + 61, s->nb_sectors >> 16); put_le16(p + 63, 0x07); /* mdma0-2 supported */ put_le16(p + 65, 120); put_le16(p + 66, 120); put_le16(p + 67, 120); put_le16(p + 68, 120); put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ put_le16(p + 81, 0x16); /* conforms to ata5 */ put_le16(p + 82, (1 << 14)); /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); put_le16(p + 84, (1 << 14)); put_le16(p + 85, (1 << 14)); /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); put_le16(p + 87, (1 << 14)); put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ put_le16(p + 93, 1 | (1 << 14) | 0x2000); put_le16(p + 100, s->nb_sectors); put_le16(p + 101, s->nb_sectors >> 16); put_le16(p + 102, s->nb_sectors >> 32); put_le16(p + 103, s->nb_sectors >> 48); memcpy(s->identify_data, p, sizeof(s->identify_data)); s->identify_set = 1;}static void ide_atapi_identify(IDEState *s){ uint16_t *p; char buf[20]; if (s->identify_set) { memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); return; } memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; /* Removable CDROM, 50us response, 12 byte packets */ put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ put_le16(p + 20, 3); /* buffer type */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */#ifdef USE_DMA_CDROM put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */ put_le16(p + 63, 7); /* mdma0-2 supported */ put_le16(p + 64, 0x3f); /* PIO modes supported */#else put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ put_le16(p + 53, 3); /* words 64-70, 54-58 valid */ put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ put_le16(p + 64, 1); /* PIO modes */#endif put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ put_le16(p + 71, 30); /* in ns */ put_le16(p + 72, 30); /* in ns */ put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */#ifdef USE_DMA_CDROM put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */#endif memcpy(s->identify_data, p, sizeof(s->identify_data)); s->identify_set = 1;}static void ide_set_signature(IDEState *s){ s->select &= 0xf0; /* clear head */ /* put signature */ s->nsector = 1; s->sector = 1; if (s->is_cdrom) { s->lcyl = 0x14; s->hcyl = 0xeb; } else if (s->bs) { s->lcyl = 0; s->hcyl = 0; } else { s->lcyl = 0xff; s->hcyl = 0xff; }}static inline void ide_abort_command(IDEState *s){ s->status = READY_STAT | ERR_STAT; s->error = ABRT_ERR;}static inline void ide_set_irq(IDEState *s){ BMDMAState *bm = s->bmdma; if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { if (bm) { bm->status |= BM_STATUS_INT; } s->set_irq(s->irq_opaque, s->irq, 1); }}/* prepare data transfer and tell what to do after */static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, EndTransferFunc *end_transfer_func){ s->end_transfer_func = end_transfer_func; s->data_ptr = buf; s->data_end = buf + size; s->status |= DRQ_STAT;}static void ide_transfer_stop(IDEState *s){ s->end_transfer_func = ide_transfer_stop; s->data_ptr = s->io_buffer; s->data_end = s->io_buffer; s->status &= ~DRQ_STAT;}static 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 { 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 { sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + (s->select & 0x0f) * s->sectors + (s->sector - 1); } return sector_num;}static 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 { 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 { 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->sector = (r % s->sectors) + 1; }}static void ide_sector_read(IDEState *s){ int64_t sector_num; int ret, n; s->status = READY_STAT | SEEK_STAT; s->error = 0; /* not needed by IDE spec, but needed by Windows */ sector_num = ide_get_sector(s); n = s->nsector; if (n == 0) { /* no more sector to read from disk */ ide_transfer_stop(s); } else {#if defined(DEBUG_IDE) printf("read sector=%Ld\n", sector_num);#endif if (n > s->req_nb_sectors) n = s->req_nb_sectors; ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); ide_set_irq(s); ide_set_sector(s, sector_num + n); s->nsector -= n; }}/* return 0 if buffer completed */static int dma_buf_rw(BMDMAState *bm, int is_write){ IDEState *s = bm->ide_if; struct { uint32_t addr; uint32_t size; } prd; int l, len; for(;;) { l = s->io_buffer_size - s->io_buffer_index; if (l <= 0) break; if (bm->cur_prd_len == 0) { /* end of table (with a fail safe of one page) */ if (bm->cur_prd_last || (bm->cur_addr - bm->addr) >= 4096) return 0; cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8); bm->cur_addr += 8; prd.addr = le32_to_cpu(prd.addr); prd.size = le32_to_cpu(prd.size); len = prd.size & 0xfffe; if (len == 0) len = 0x10000; bm->cur_prd_len = len; bm->cur_prd_addr = prd.addr; bm->cur_prd_last = (prd.size & 0x80000000); } if (l > bm->cur_prd_len) l = bm->cur_prd_len; if (l > 0) { if (is_write) { cpu_physical_memory_write(bm->cur_prd_addr, s->io_buffer + s->io_buffer_index, l); } else { cpu_physical_memory_read(bm->cur_prd_addr, s->io_buffer + s->io_buffer_index, l); } bm->cur_prd_addr += l; bm->cur_prd_len -= l; s->io_buffer_index += l; } } return 1;}/* XXX: handle errors */static void ide_read_dma_cb(void *opaque, int ret){ BMDMAState *bm = opaque; IDEState *s = bm->ide_if; int n; int64_t sector_num; n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); if (n > 0) { sector_num += n; ide_set_sector(s, sector_num); s->nsector -= n; if (dma_buf_rw(bm, 1) == 0) goto eot; } /* end of transfer ? */ if (s->nsector == 0) { s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); eot: bm->status &= ~BM_STATUS_DMAING; bm->status |= BM_STATUS_INT; bm->dma_cb = NULL; bm->ide_if = NULL; bm->aiocb = NULL; return; } /* launch next transfer */ n = s->nsector; if (n > MAX_MULT_SECTORS) n = MAX_MULT_SECTORS; s->io_buffer_index = 0; s->io_buffer_size = n * 512;#ifdef DEBUG_AIO printf("aio_read: sector_num=%lld n=%d\n", sector_num, n);#endif bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, ide_read_dma_cb, bm);}static void ide_sector_read_dma(IDEState *s){ s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; s->io_buffer_index = 0; s->io_buffer_size = 0; ide_dma_start(s, ide_read_dma_cb);}static void ide_sector_write_timer_cb(void *opaque){ IDEState *s = opaque; ide_set_irq(s);}static void ide_sector_write(IDEState *s){ int64_t sector_num; int ret, n, n1; s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s);#if defined(DEBUG_IDE) printf("write sector=%Ld\n", sector_num);#endif n = s->nsector; if (n > s->req_nb_sectors) n = s->req_nb_sectors; ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); s->nsector -= n; if (s->nsector == 0) { /* no more sector to write */ ide_transfer_stop(s); } else { n1 = s->nsector; if (n1 > s->req_nb_sectors) n1 = s->req_nb_sectors; ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); } ide_set_sector(s, sector_num + n); #ifdef TARGET_I386 if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { /* It seems there is a bug in the Windows 2000 installer HDD IDE driver which fills the disk with empty logs when the IDE write IRQ comes too early. This hack tries to correct that at the expense of slower write performances. Use this option _only_ to install Windows 2000. You must disable it for normal use. */ qemu_mod_timer(s->sector_write_timer, qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); } else #endif { ide_set_irq(s); }}/* XXX: handle errors */static void ide_write_dma_cb(void *opaque, int ret){ BMDMAState *bm = opaque; IDEState *s = bm->ide_if; int n; int64_t sector_num; n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); if (n > 0) { sector_num += n; ide_set_sector(s, sector_num); s->nsector -= n; } /* end of transfer ? */ if (s->nsector == 0) { s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); eot: bm->status &= ~BM_STATUS_DMAING; bm->status |= BM_STATUS_INT; bm->dma_cb = NULL; bm->ide_if = NULL; bm->aiocb = NULL; return; } /* launch next transfer */ n = s->nsector; if (n > MAX_MULT_SECTORS) n = MAX_MULT_SECTORS; s->io_buffer_index = 0; s->io_buffer_size = n * 512;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -