📄 ide.c
字号:
static inline void cpu_to_ube16(uint8_t *buf, int val){ buf[0] = val >> 8; buf[1] = val;}static inline void cpu_to_ube32(uint8_t *buf, unsigned int val){ buf[0] = val >> 24; buf[1] = val >> 16; buf[2] = val >> 8; buf[3] = val;}static inline int ube16_to_cpu(const uint8_t *buf){ return (buf[0] << 8) | buf[1];}static inline int ube32_to_cpu(const uint8_t *buf){ return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];}static void lba_to_msf(uint8_t *buf, int lba){ lba += 150; buf[0] = (lba / 75) / 60; buf[1] = (lba / 75) % 60; buf[2] = lba % 75;}static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, int sector_size){ switch(sector_size) { case 2048: bdrv_read(bs, (int64_t)lba << 2, buf, 4); break; case 2352: /* sync bytes */ buf[0] = 0x00; memset(buf + 1, 0xff, 10); buf[11] = 0x00; buf += 12; /* MSF */ lba_to_msf(buf, lba); buf[3] = 0x01; /* mode 1 data */ buf += 4; /* data */ bdrv_read(bs, (int64_t)lba << 2, buf, 4); buf += 2048; /* ECC */ memset(buf, 0, 288); break; default: break; }}/* The whole ATAPI transfer logic is handled in this function */static void ide_atapi_cmd_reply_end(IDEState *s){ int byte_count_limit, size;#ifdef DEBUG_IDE_ATAPI printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", s->packet_transfer_size, s->elementary_transfer_size, s->io_buffer_index);#endif if (s->packet_transfer_size <= 0) { /* end of transfer */ ide_transfer_stop(s); s->status = READY_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s);#ifdef DEBUG_IDE_ATAPI printf("status=0x%x\n", s->status);#endif } else { /* see if a new sector must be read */ if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); s->lba++; s->io_buffer_index = 0; } if (s->elementary_transfer_size > 0) { /* there are some data left to transmit in this elementary transfer */ size = s->cd_sector_size - s->io_buffer_index; if (size > s->elementary_transfer_size) size = s->elementary_transfer_size; ide_transfer_start(s, s->io_buffer + s->io_buffer_index, size, ide_atapi_cmd_reply_end); s->packet_transfer_size -= size; s->elementary_transfer_size -= size; s->io_buffer_index += size; } else { /* a new transfer is needed */ s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; byte_count_limit = s->lcyl | (s->hcyl << 8);#ifdef DEBUG_IDE_ATAPI printf("byte_count_limit=%d\n", byte_count_limit);#endif if (byte_count_limit == 0xffff) byte_count_limit--; size = s->packet_transfer_size; if (size > byte_count_limit) { /* byte count limit must be even if this case */ if (byte_count_limit & 1) byte_count_limit--; size = byte_count_limit; } s->lcyl = size; s->hcyl = size >> 8; s->elementary_transfer_size = size; /* we cannot transmit more than one sector at a time */ if (s->lba != -1) { if (size > (s->cd_sector_size - s->io_buffer_index)) size = (s->cd_sector_size - s->io_buffer_index); } ide_transfer_start(s, s->io_buffer + s->io_buffer_index, size, ide_atapi_cmd_reply_end); s->packet_transfer_size -= size; s->elementary_transfer_size -= size; s->io_buffer_index += size; ide_set_irq(s);#ifdef DEBUG_IDE_ATAPI printf("status=0x%x\n", s->status);#endif } }}/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size){ if (size > max_size) size = max_size; s->lba = -1; /* no sector read */ s->packet_transfer_size = size; s->elementary_transfer_size = 0; s->io_buffer_index = 0; s->status = READY_STAT; ide_atapi_cmd_reply_end(s);}/* start a CD-CDROM read command */static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, int sector_size){ s->lba = lba; s->packet_transfer_size = nb_sectors * sector_size; s->elementary_transfer_size = 0; s->io_buffer_index = sector_size; s->cd_sector_size = sector_size; s->status = READY_STAT; ide_atapi_cmd_reply_end(s);}/* ATAPI DMA support */static int ide_atapi_cmd_read_dma_cb(IDEState *s, target_phys_addr_t phys_addr, int transfer_size1){ int len, transfer_size; transfer_size = transfer_size1; while (transfer_size > 0) {#ifdef DEBUG_IDE_ATAPI printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr);#endif if (s->packet_transfer_size <= 0) break; len = s->cd_sector_size - s->io_buffer_index; if (len <= 0) { /* transfert next data */ cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); s->lba++; s->io_buffer_index = 0; len = s->cd_sector_size; } if (len > transfer_size) len = transfer_size; cpu_physical_memory_write(phys_addr, s->io_buffer + s->io_buffer_index, len); s->packet_transfer_size -= len; s->io_buffer_index += len; transfer_size -= len; phys_addr += len; } if (s->packet_transfer_size <= 0) { s->status = READY_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s);#ifdef DEBUG_IDE_ATAPI printf("dma status=0x%x\n", s->status);#endif return 0; } return transfer_size1 - transfer_size;}/* start a CD-CDROM read command with DMA *//* XXX: test if DMA is available */static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, int sector_size){ s->lba = lba; s->packet_transfer_size = nb_sectors * sector_size; s->io_buffer_index = sector_size; s->cd_sector_size = sector_size; s->status = READY_STAT | DRQ_STAT; ide_dma_start(s, ide_atapi_cmd_read_dma_cb);}static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, int sector_size){#ifdef DEBUG_IDE_ATAPI printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors);#endif if (s->atapi_dma) { ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); } else { ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); }}/* same toc as bochs. Return -1 if error or the toc length *//* XXX: check this */static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track){ uint8_t *q; int nb_sectors, len; if (start_track > 1 && start_track != 0xaa) return -1; q = buf + 2; *q++ = 1; /* first session */ *q++ = 1; /* last session */ if (start_track <= 1) { *q++ = 0; /* reserved */ *q++ = 0x14; /* ADR, control */ *q++ = 1; /* track number */ *q++ = 0; /* reserved */ if (msf) { *q++ = 0; /* reserved */ lba_to_msf(q, 0); q += 3; } else { /* sector 0 */ cpu_to_ube32(q, 0); q += 4; } } /* lead out track */ *q++ = 0; /* reserved */ *q++ = 0x16; /* ADR, control */ *q++ = 0xaa; /* track number */ *q++ = 0; /* reserved */ nb_sectors = s->nb_sectors >> 2; if (msf) { *q++ = 0; /* reserved */ lba_to_msf(q, nb_sectors); q += 3; } else { cpu_to_ube32(q, nb_sectors); q += 4; } len = q - buf; cpu_to_ube16(buf, len - 2); return len;}/* mostly same info as PearPc */static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, int session_num){ uint8_t *q; int nb_sectors, len; q = buf + 2; *q++ = 1; /* first session */ *q++ = 1; /* last session */ *q++ = 1; /* session number */ *q++ = 0x14; /* data track */ *q++ = 0; /* track number */ *q++ = 0xa0; /* lead-in */ *q++ = 0; /* min */ *q++ = 0; /* sec */ *q++ = 0; /* frame */ *q++ = 0; *q++ = 1; /* first track */ *q++ = 0x00; /* disk type */ *q++ = 0x00; *q++ = 1; /* session number */ *q++ = 0x14; /* data track */ *q++ = 0; /* track number */ *q++ = 0xa1; *q++ = 0; /* min */ *q++ = 0; /* sec */ *q++ = 0; /* frame */ *q++ = 0; *q++ = 1; /* last track */ *q++ = 0x00; *q++ = 0x00; *q++ = 1; /* session number */ *q++ = 0x14; /* data track */ *q++ = 0; /* track number */ *q++ = 0xa2; /* lead-out */ *q++ = 0; /* min */ *q++ = 0; /* sec */ *q++ = 0; /* frame */ nb_sectors = s->nb_sectors >> 2; if (msf) { *q++ = 0; /* reserved */ lba_to_msf(q, nb_sectors); q += 3; } else { cpu_to_ube32(q, nb_sectors); q += 4; } *q++ = 1; /* session number */ *q++ = 0x14; /* ADR, control */ *q++ = 0; /* track number */ *q++ = 1; /* point */ *q++ = 0; /* min */ *q++ = 0; /* sec */ *q++ = 0; /* frame */ if (msf) { *q++ = 0; lba_to_msf(q, 0); q += 3; } else { *q++ = 0; *q++ = 0; *q++ = 0; *q++ = 0; } len = q - buf; cpu_to_ube16(buf, len - 2); return len;}static void ide_atapi_cmd(IDEState *s){ const uint8_t *packet; uint8_t *buf; int max_len; packet = s->io_buffer; buf = s->io_buffer;#ifdef DEBUG_IDE_ATAPI { int i; printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); for(i = 0; i < ATAPI_PACKET_SIZE; i++) { printf(" %02x", packet[i]); } printf("\n"); }#endif switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: if (bdrv_is_inserted(s->bs)) { ide_atapi_cmd_ok(s); } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } break; case GPCMD_MODE_SENSE_10: { int action, code; max_len = ube16_to_cpu(packet + 7); action = packet[2] >> 6; code = packet[2] & 0x3f; switch(action) { case 0: /* current values */ switch(code) { case 0x01: /* error recovery */ cpu_to_ube16(&buf[0], 16 + 6); buf[2] = 0x70; buf[3] = 0; buf[4] = 0; buf[5] = 0; buf[6] = 0; buf[7] = 0; buf[8] = 0x01; buf[9] = 0x06; buf[10] = 0x00; buf[11] = 0x05; buf[12] = 0x00; buf[13] = 0x00; buf[14] = 0x00; buf[15] = 0x00; ide_atapi_cmd_reply(s, 16, max_len); break; case 0x2a: cpu_to_ube16(&buf[0], 28 + 6); buf[2] = 0x70; buf[3] = 0; buf[4] = 0; buf[5] = 0; buf[6] = 0; buf[7] = 0; buf[8] = 0x2a; buf[9] = 0x12; buf[10] = 0x00; buf[11] = 0x00; buf[12] = 0x70; buf[13] = 3 << 5; buf[14] = (1 << 0) | (1 << 3) | (1 << 5); if (bdrv_is_locked(s->bs))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -