?? ide.c
字號(hào):
typedef struct PCIIDEState { PCIDevice dev; IDEState ide_if[4]; BMDMAState bmdma[2]; int type; /* see IDE_TYPE_xxx */} PCIIDEState;static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);static void padstr(char *str, const char *src, int len){ int i, v; for(i = 0; i < len; i++) { if (*src) v = *src++; else v = ' '; str[i^1] = v; }}static void padstr8(uint8_t *buf, int buf_size, const char *src){ int i; for(i = 0; i < buf_size; i++) { if (*src) buf[i] = *src++; else buf[i] = ' '; }}static void put_le16(uint16_t *p, unsigned int v){ *p = cpu_to_le16(v);}static void ide_identify(IDEState *s){ 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((char *)(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((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((char *)(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((char *)(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((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((char *)(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_cfata_identify(IDEState *s){ uint16_t *p; uint32_t cur_sec; char buf[20]; p = (uint16_t *) s->identify_data; if (s->identify_set) goto fill_buffer; memset(p, 0, sizeof(s->identify_data)); cur_sec = s->cylinders * s->heads * s->sectors; put_le16(p + 0, 0x848a); /* CF Storage Card signature */ put_le16(p + 1, s->cylinders); /* Default cylinders */ put_le16(p + 3, s->heads); /* Default heads */ put_le16(p + 6, s->sectors); /* Default sectors per track */ put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ put_le16(p + 8, s->nb_sectors); /* Sectors per card */ snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); padstr((char *)(p + 10), buf, 20); /* Serial number in ASCII */ put_le16(p + 22, 0x0004); /* ECC bytes */ padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */ padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */#if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);#else put_le16(p + 47, 0x0000);#endif put_le16(p + 49, 0x0f00); /* Capabilities */ put_le16(p + 51, 0x0002); /* PIO cycle timing mode */ put_le16(p + 52, 0x0001); /* DMA cycle timing mode */ put_le16(p + 53, 0x0003); /* Translation params valid */ put_le16(p + 54, s->cylinders); /* Current cylinders */ put_le16(p + 55, s->heads); /* Current heads */ put_le16(p + 56, s->sectors); /* Current sectors */ put_le16(p + 57, cur_sec); /* Current capacity */ put_le16(p + 58, cur_sec >> 16); /* Current capacity */ if (s->mult_sectors) /* Multiple sector setting */ put_le16(p + 59, 0x100 | s->mult_sectors); put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */ put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */ put_le16(p + 63, 0x0203); /* Multiword DMA capability */ put_le16(p + 64, 0x0001); /* Flow Control PIO support */ put_le16(p + 65, 0x0096); /* Min. Multiword DMA cycle */ put_le16(p + 66, 0x0096); /* Rec. Multiword DMA cycle */ put_le16(p + 68, 0x00b4); /* Min. PIO cycle time */ put_le16(p + 82, 0x400c); /* Command Set supported */ put_le16(p + 83, 0x7068); /* Command Set supported */ put_le16(p + 84, 0x4000); /* Features supported */ put_le16(p + 85, 0x000c); /* Command Set enabled */ put_le16(p + 86, 0x7044); /* Command Set enabled */ put_le16(p + 87, 0x4000); /* Features enabled */ put_le16(p + 91, 0x4060); /* Current APM level */ put_le16(p + 129, 0x0002); /* Current features option */ put_le16(p + 130, 0x0005); /* Reassigned sectors */ put_le16(p + 131, 0x0001); /* Initial power mode */ put_le16(p + 132, 0x0000); /* User signature */ put_le16(p + 160, 0x8100); /* Power requirement */ put_le16(p + 161, 0x8001); /* CF command set */ s->identify_set = 1;fill_buffer: memcpy(s->io_buffer, p, sizeof(s->identify_data));}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; } qemu_irq_raise(s->irq); }}/* 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; if (!(s->status & ERR_STAT)) 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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -