📄 ide.c
字号:
ide_atapi_cmd_ok(s); } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } break; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: { int action, code; if (packet[0] == GPCMD_MODE_SENSE_10) max_len = ube16_to_cpu(packet + 7); else max_len = packet[4]; 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)) buf[6] |= 1 << 1; buf[15] = 0x00; cpu_to_ube16(&buf[16], 706); buf[18] = 0; buf[19] = 2; cpu_to_ube16(&buf[20], 512); cpu_to_ube16(&buf[22], 706); buf[24] = 0; buf[25] = 0; buf[26] = 0; buf[27] = 0; ide_atapi_cmd_reply(s, 28, max_len); break; default: goto error_cmd; } break; case 1: /* changeable values */ goto error_cmd; case 2: /* default values */ goto error_cmd; default: case 3: /* saved values */ ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_SAVING_PARAMETERS_NOT_SUPPORTED); break; } } break; case GPCMD_REQUEST_SENSE: max_len = packet[4]; memset(buf, 0, 18); buf[0] = 0x70 | (1 << 7); buf[2] = s->sense_key; buf[7] = 10; buf[12] = s->asc; ide_atapi_cmd_reply(s, 18, max_len); break; case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: if (bdrv_is_inserted(s->bs)) { bdrv_set_locked(s->bs, packet[4] & 1); ide_atapi_cmd_ok(s); } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } break; case GPCMD_READ_10: case GPCMD_READ_12: { int nb_sectors, lba; if (packet[0] == GPCMD_READ_10) nb_sectors = ube16_to_cpu(packet + 7); else nb_sectors = ube32_to_cpu(packet + 6); lba = ube32_to_cpu(packet + 2); if (nb_sectors == 0) { ide_atapi_cmd_ok(s); break; } ide_atapi_cmd_read(s, lba, nb_sectors, 2048); } break; case GPCMD_READ_CD: { int nb_sectors, lba, transfer_request; nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; lba = ube32_to_cpu(packet + 2); if (nb_sectors == 0) { ide_atapi_cmd_ok(s); break; } transfer_request = packet[9]; switch(transfer_request & 0xf8) { case 0x00: /* nothing */ ide_atapi_cmd_ok(s); break; case 0x10: /* normal read */ ide_atapi_cmd_read(s, lba, nb_sectors, 2048); break; case 0xf8: /* read all data */ ide_atapi_cmd_read(s, lba, nb_sectors, 2352); break; default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); break; } } break; case GPCMD_SEEK: { unsigned int lba; uint64_t total_sectors; bdrv_get_geometry(s->bs, &total_sectors); total_sectors >>= 2; if (total_sectors == 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } lba = ube32_to_cpu(packet + 2); if (lba >= total_sectors) { ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); break; } ide_atapi_cmd_ok(s); } break; case GPCMD_START_STOP_UNIT: { int start, eject; start = packet[4] & 1; eject = (packet[4] >> 1) & 1; if (eject && !start) { /* eject the disk */ bdrv_eject(s->bs, 1); } else if (eject && start) { /* close the tray */ bdrv_eject(s->bs, 0); } ide_atapi_cmd_ok(s); } break; case GPCMD_MECHANISM_STATUS: { max_len = ube16_to_cpu(packet + 8); cpu_to_ube16(buf, 0); /* no current LBA */ buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 1; cpu_to_ube16(buf + 6, 0); ide_atapi_cmd_reply(s, 8, max_len); } break; case GPCMD_READ_TOC_PMA_ATIP: { int format, msf, start_track, len; uint64_t total_sectors; bdrv_get_geometry(s->bs, &total_sectors); total_sectors >>= 2; if (total_sectors == 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } max_len = ube16_to_cpu(packet + 7); format = packet[9] >> 6; msf = (packet[1] >> 1) & 1; start_track = packet[6]; switch(format) { case 0: len = cdrom_read_toc(total_sectors, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); break; case 1: /* multi session : only a single session defined */ memset(buf, 0, 12); buf[1] = 0x0a; buf[2] = 0x01; buf[3] = 0x01; ide_atapi_cmd_reply(s, 12, max_len); break; case 2: len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); break; default: error_cmd: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); break; } } break; case GPCMD_READ_CDVD_CAPACITY: { uint64_t total_sectors; bdrv_get_geometry(s->bs, &total_sectors); total_sectors >>= 2; if (total_sectors == 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } /* NOTE: it is really the number of sectors minus 1 */ cpu_to_ube32(buf, total_sectors - 1); cpu_to_ube32(buf + 4, 2048); ide_atapi_cmd_reply(s, 8, 8); } break; case GPCMD_READ_DVD_STRUCTURE: { int media = packet[1]; int layer = packet[6]; int format = packet[2]; uint64_t total_sectors; if (media != 0 || layer != 0) { ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); } switch (format) { case 0: bdrv_get_geometry(s->bs, &total_sectors); total_sectors >>= 2; if (total_sectors == 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } memset(buf, 0, 2052); buf[4] = 1; // DVD-ROM, part version 1 buf[5] = 0xf; // 120mm disc, maximum rate unspecified buf[6] = 0; // one layer, embossed data buf[7] = 0; cpu_to_ube32(buf + 8, 0); cpu_to_ube32(buf + 12, total_sectors - 1); cpu_to_ube32(buf + 16, total_sectors - 1); cpu_to_be16wu((uint16_t *)buf, 2048 + 4); ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4); break; default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); break; } } break; case GPCMD_SET_SPEED: ide_atapi_cmd_ok(s); break; case GPCMD_INQUIRY: max_len = packet[4]; buf[0] = 0x05; /* CD-ROM */ buf[1] = 0x80; /* removable */ buf[2] = 0x00; /* ISO */ buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ buf[4] = 31; /* additional length */ buf[5] = 0; /* reserved */ buf[6] = 0; /* reserved */ buf[7] = 0; /* reserved */ padstr8(buf + 8, 8, "QEMU"); padstr8(buf + 16, 16, "QEMU DVD-ROM"); padstr8(buf + 32, 4, QEMU_VERSION); ide_atapi_cmd_reply(s, 36, max_len); break; case GPCMD_GET_CONFIGURATION: { uint32_t len; /* only feature 0 is supported */ if (packet[2] != 0 || packet[3] != 0) { ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); break; } /* XXX: could result in alignment problems in some architectures */ max_len = ube16_to_cpu(packet + 7); /* * XXX: avoid overflow for io_buffer if max_len is bigger than the * size of that buffer (dimensioned to max number of sectors * to transfer at once) * * Only a problem if the feature/profiles grow exponentially. */ if (max_len > 512) /* XXX: assume 1 sector */ max_len = 512; memset(buf, 0, max_len); /* * the number of sectors from the media tells us which profile * to use as current. 0 means there is no media * * XXX: fails to detect correctly DVDs with less data burned * than what a CD can hold */ if ((s -> nb_sectors)) { if ((s -> nb_sectors > CD_MAX_SECTORS)) cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); else cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); } len = 8; /* header completed */ if (max_len > len) { uint8_t index = 0; buf[10] = 0x02 | 0x01; /* persistent and current */ len += 4; /* header */ len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM); len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM); } cpu_to_ube32(buf, len - 4); /* data length */ ide_atapi_cmd_reply(s, len, max_len); break; } default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE); break; }}static void ide_cfata_metadata_inquiry(IDEState *s){ uint16_t *p; uint32_t spd; p = (uint16_t *) s->io_buffer; memset(p, 0, 0x200); spd = ((s->mdata_size - 1) >> 9) + 1; put_le16(p + 0, 0x0001); /* Data format revision */ put_le16(p + 1, 0x0000); /* Media property: silicon */ put_le16(p + 2, s->media_changed); /* Media status */ put_le16(p + 3, s->mdata_size & 0xffff); /* Capacity in bytes (low) */ put_le16(p + 4, s->mdata_size >> 16); /* Capacity in bytes (high) */ put_le16(p + 5, spd & 0xffff); /* Sectors per device (low) */ put_le16(p + 6, spd >> 16); /* Sectors per device (high) */}static void ide_cfata_metadata_read(IDEState *s){ uint16_t *p; if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) { s->status = ERR_STAT; s->error = ABRT_ERR; return; } p = (uint16_t *) s->io_buffer; memset(p,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -