Commit 36b486bb74ca651d07968372cebd6e742114e144
1 parent
4ad06a29
hardware level IDE CD-ROM emulation - added second IDE interface for up to 4 IDE…
… disks emulation - added -boot command to enable CD boot git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@444 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
744 additions
and
71 deletions
vl.c
| ... | ... | @@ -63,6 +63,7 @@ |
| 63 | 63 | |
| 64 | 64 | /* debug IDE devices */ |
| 65 | 65 | //#define DEBUG_IDE |
| 66 | +//#define DEBUG_IDE_ATAPI | |
| 66 | 67 | |
| 67 | 68 | /* debug PIC */ |
| 68 | 69 | //#define DEBUG_PIC |
| ... | ... | @@ -85,7 +86,7 @@ |
| 85 | 86 | |
| 86 | 87 | #define GUI_REFRESH_INTERVAL 30 |
| 87 | 88 | |
| 88 | -#define MAX_DISKS 2 | |
| 89 | +#define MAX_DISKS 4 | |
| 89 | 90 | |
| 90 | 91 | /* from plex86 (BSD license) */ |
| 91 | 92 | struct __attribute__ ((packed)) linux_params { |
| ... | ... | @@ -216,6 +217,7 @@ static DisplayState display_state; |
| 216 | 217 | int nographic; |
| 217 | 218 | int term_inited; |
| 218 | 219 | int64_t ticks_per_sec; |
| 220 | +int boot_device = 'c'; | |
| 219 | 221 | |
| 220 | 222 | /***********************************************************/ |
| 221 | 223 | /* x86 io ports */ |
| ... | ... | @@ -533,8 +535,19 @@ void cmos_init(void) |
| 533 | 535 | cmos_data[0x34] = val; |
| 534 | 536 | cmos_data[0x35] = val >> 8; |
| 535 | 537 | |
| 536 | - cmos_data[0x3d] = 0x02; /* hard drive boot */ | |
| 537 | - | |
| 538 | + switch(boot_device) { | |
| 539 | + case 'a': | |
| 540 | + cmos_data[0x3d] = 0x01; /* floppy boot */ | |
| 541 | + break; | |
| 542 | + default: | |
| 543 | + case 'c': | |
| 544 | + cmos_data[0x3d] = 0x02; /* hard drive boot */ | |
| 545 | + break; | |
| 546 | + case 'd': | |
| 547 | + cmos_data[0x3d] = 0x03; /* CD-ROM boot */ | |
| 548 | + break; | |
| 549 | + } | |
| 550 | + | |
| 538 | 551 | register_ioport_write(0x70, 2, cmos_ioport_write, 1); |
| 539 | 552 | register_ioport_read(0x70, 2, cmos_ioport_read, 1); |
| 540 | 553 | } |
| ... | ... | @@ -1045,7 +1058,7 @@ static inline void pit_load_count(PITChannelState *s, int val) |
| 1045 | 1058 | s->count = val; |
| 1046 | 1059 | if (s == &pit_channels[0] && val <= pit_min_timer_count) { |
| 1047 | 1060 | fprintf(stderr, |
| 1048 | - "\nWARNING: vl: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.5.xx Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", | |
| 1061 | + "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.5.xx Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", | |
| 1049 | 1062 | PIT_FREQ / pit_min_timer_count); |
| 1050 | 1063 | } |
| 1051 | 1064 | } |
| ... | ... | @@ -2014,12 +2027,111 @@ void ne2000_init(void) |
| 2014 | 2027 | /* set to 1 set disable mult support */ |
| 2015 | 2028 | #define MAX_MULT_SECTORS 8 |
| 2016 | 2029 | |
| 2030 | +/* ATAPI defines */ | |
| 2031 | + | |
| 2032 | +#define ATAPI_PACKET_SIZE 12 | |
| 2033 | + | |
| 2034 | +/* The generic packet command opcodes for CD/DVD Logical Units, | |
| 2035 | + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ | |
| 2036 | +#define GPCMD_BLANK 0xa1 | |
| 2037 | +#define GPCMD_CLOSE_TRACK 0x5b | |
| 2038 | +#define GPCMD_FLUSH_CACHE 0x35 | |
| 2039 | +#define GPCMD_FORMAT_UNIT 0x04 | |
| 2040 | +#define GPCMD_GET_CONFIGURATION 0x46 | |
| 2041 | +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a | |
| 2042 | +#define GPCMD_GET_PERFORMANCE 0xac | |
| 2043 | +#define GPCMD_INQUIRY 0x12 | |
| 2044 | +#define GPCMD_LOAD_UNLOAD 0xa6 | |
| 2045 | +#define GPCMD_MECHANISM_STATUS 0xbd | |
| 2046 | +#define GPCMD_MODE_SELECT_10 0x55 | |
| 2047 | +#define GPCMD_MODE_SENSE_10 0x5a | |
| 2048 | +#define GPCMD_PAUSE_RESUME 0x4b | |
| 2049 | +#define GPCMD_PLAY_AUDIO_10 0x45 | |
| 2050 | +#define GPCMD_PLAY_AUDIO_MSF 0x47 | |
| 2051 | +#define GPCMD_PLAY_AUDIO_TI 0x48 | |
| 2052 | +#define GPCMD_PLAY_CD 0xbc | |
| 2053 | +#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e | |
| 2054 | +#define GPCMD_READ_10 0x28 | |
| 2055 | +#define GPCMD_READ_12 0xa8 | |
| 2056 | +#define GPCMD_READ_CDVD_CAPACITY 0x25 | |
| 2057 | +#define GPCMD_READ_CD 0xbe | |
| 2058 | +#define GPCMD_READ_CD_MSF 0xb9 | |
| 2059 | +#define GPCMD_READ_DISC_INFO 0x51 | |
| 2060 | +#define GPCMD_READ_DVD_STRUCTURE 0xad | |
| 2061 | +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 | |
| 2062 | +#define GPCMD_READ_HEADER 0x44 | |
| 2063 | +#define GPCMD_READ_TRACK_RZONE_INFO 0x52 | |
| 2064 | +#define GPCMD_READ_SUBCHANNEL 0x42 | |
| 2065 | +#define GPCMD_READ_TOC_PMA_ATIP 0x43 | |
| 2066 | +#define GPCMD_REPAIR_RZONE_TRACK 0x58 | |
| 2067 | +#define GPCMD_REPORT_KEY 0xa4 | |
| 2068 | +#define GPCMD_REQUEST_SENSE 0x03 | |
| 2069 | +#define GPCMD_RESERVE_RZONE_TRACK 0x53 | |
| 2070 | +#define GPCMD_SCAN 0xba | |
| 2071 | +#define GPCMD_SEEK 0x2b | |
| 2072 | +#define GPCMD_SEND_DVD_STRUCTURE 0xad | |
| 2073 | +#define GPCMD_SEND_EVENT 0xa2 | |
| 2074 | +#define GPCMD_SEND_KEY 0xa3 | |
| 2075 | +#define GPCMD_SEND_OPC 0x54 | |
| 2076 | +#define GPCMD_SET_READ_AHEAD 0xa7 | |
| 2077 | +#define GPCMD_SET_STREAMING 0xb6 | |
| 2078 | +#define GPCMD_START_STOP_UNIT 0x1b | |
| 2079 | +#define GPCMD_STOP_PLAY_SCAN 0x4e | |
| 2080 | +#define GPCMD_TEST_UNIT_READY 0x00 | |
| 2081 | +#define GPCMD_VERIFY_10 0x2f | |
| 2082 | +#define GPCMD_WRITE_10 0x2a | |
| 2083 | +#define GPCMD_WRITE_AND_VERIFY_10 0x2e | |
| 2084 | +/* This is listed as optional in ATAPI 2.6, but is (curiously) | |
| 2085 | + * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji | |
| 2086 | + * Table 377 as an MMC command for SCSi devices though... Most ATAPI | |
| 2087 | + * drives support it. */ | |
| 2088 | +#define GPCMD_SET_SPEED 0xbb | |
| 2089 | +/* This seems to be a SCSI specific CD-ROM opcode | |
| 2090 | + * to play data at track/index */ | |
| 2091 | +#define GPCMD_PLAYAUDIO_TI 0x48 | |
| 2092 | +/* | |
| 2093 | + * From MS Media Status Notification Support Specification. For | |
| 2094 | + * older drives only. | |
| 2095 | + */ | |
| 2096 | +#define GPCMD_GET_MEDIA_STATUS 0xda | |
| 2097 | + | |
| 2098 | +/* Mode page codes for mode sense/set */ | |
| 2099 | +#define GPMODE_R_W_ERROR_PAGE 0x01 | |
| 2100 | +#define GPMODE_WRITE_PARMS_PAGE 0x05 | |
| 2101 | +#define GPMODE_AUDIO_CTL_PAGE 0x0e | |
| 2102 | +#define GPMODE_POWER_PAGE 0x1a | |
| 2103 | +#define GPMODE_FAULT_FAIL_PAGE 0x1c | |
| 2104 | +#define GPMODE_TO_PROTECT_PAGE 0x1d | |
| 2105 | +#define GPMODE_CAPABILITIES_PAGE 0x2a | |
| 2106 | +#define GPMODE_ALL_PAGES 0x3f | |
| 2107 | +/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor | |
| 2108 | + * of MODE_SENSE_POWER_PAGE */ | |
| 2109 | +#define GPMODE_CDROM_PAGE 0x0d | |
| 2110 | + | |
| 2111 | +#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ | |
| 2112 | +#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ | |
| 2113 | +#define ATAPI_INT_REASON_REL 0x04 | |
| 2114 | +#define ATAPI_INT_REASON_TAG 0xf8 | |
| 2115 | + | |
| 2116 | +/* same constants as bochs */ | |
| 2117 | +#define ASC_LOGICAL_BLOCK_OOR 0x21 | |
| 2118 | +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 | |
| 2119 | +#define ASC_MEDIUM_NOT_PRESENT 0x3a | |
| 2120 | +#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 | |
| 2121 | + | |
| 2122 | +#define SENSE_NONE 0 | |
| 2123 | +#define SENSE_NOT_READY 2 | |
| 2124 | +#define SENSE_ILLEGAL_REQUEST 5 | |
| 2125 | +#define SENSE_UNIT_ATTENTION 6 | |
| 2126 | + | |
| 2017 | 2127 | struct IDEState; |
| 2018 | 2128 | |
| 2019 | 2129 | typedef void EndTransferFunc(struct IDEState *); |
| 2020 | 2130 | |
| 2021 | 2131 | typedef struct IDEState { |
| 2022 | 2132 | /* ide config */ |
| 2133 | + int is_cdrom; | |
| 2134 | + int cdrom_locked; | |
| 2023 | 2135 | int cylinders, heads, sectors; |
| 2024 | 2136 | int64_t nb_sectors; |
| 2025 | 2137 | int mult_sectors; |
| ... | ... | @@ -2038,6 +2150,14 @@ typedef struct IDEState { |
| 2038 | 2150 | /* depends on bit 4 in select, only meaningful for drive 0 */ |
| 2039 | 2151 | struct IDEState *cur_drive; |
| 2040 | 2152 | BlockDriverState *bs; |
| 2153 | + /* ATAPI specific */ | |
| 2154 | + uint8_t sense_key; | |
| 2155 | + uint8_t asc; | |
| 2156 | + int packet_transfer_size; | |
| 2157 | + int elementary_transfer_size; | |
| 2158 | + int io_buffer_index; | |
| 2159 | + int lba; | |
| 2160 | + /* transfer handling */ | |
| 2041 | 2161 | int req_nb_sectors; /* number of sectors per interrupt */ |
| 2042 | 2162 | EndTransferFunc *end_transfer_func; |
| 2043 | 2163 | uint8_t *data_ptr; |
| ... | ... | @@ -2046,6 +2166,12 @@ typedef struct IDEState { |
| 2046 | 2166 | } IDEState; |
| 2047 | 2167 | |
| 2048 | 2168 | IDEState ide_state[MAX_DISKS]; |
| 2169 | +IDEState *ide_table[0x400 >> 3]; | |
| 2170 | + | |
| 2171 | +static inline IDEState *get_ide_interface(uint32_t addr) | |
| 2172 | +{ | |
| 2173 | + return ide_table[addr >> 3]; | |
| 2174 | +} | |
| 2049 | 2175 | |
| 2050 | 2176 | static void padstr(char *str, const char *src, int len) |
| 2051 | 2177 | { |
| ... | ... | @@ -2073,10 +2199,12 @@ static void ide_identify(IDEState *s) |
| 2073 | 2199 | stw_raw(p + 4, 512 * s->sectors); /* sectors */ |
| 2074 | 2200 | stw_raw(p + 5, 512); /* sector size */ |
| 2075 | 2201 | stw_raw(p + 6, s->sectors); |
| 2202 | + padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ | |
| 2076 | 2203 | stw_raw(p + 20, 3); /* buffer type */ |
| 2077 | 2204 | stw_raw(p + 21, 512); /* cache size in sectors */ |
| 2078 | 2205 | stw_raw(p + 22, 4); /* ecc bytes */ |
| 2079 | - padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); | |
| 2206 | + padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ | |
| 2207 | + padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ | |
| 2080 | 2208 | #if MAX_MULT_SECTORS > 1 |
| 2081 | 2209 | stw_raw(p + 47, MAX_MULT_SECTORS); |
| 2082 | 2210 | #endif |
| ... | ... | @@ -2103,6 +2231,59 @@ static void ide_identify(IDEState *s) |
| 2103 | 2231 | stw_raw(p + 87, (1 << 14)); |
| 2104 | 2232 | } |
| 2105 | 2233 | |
| 2234 | +static void ide_atapi_identify(IDEState *s) | |
| 2235 | +{ | |
| 2236 | + uint16_t *p; | |
| 2237 | + | |
| 2238 | + memset(s->io_buffer, 0, 512); | |
| 2239 | + p = (uint16_t *)s->io_buffer; | |
| 2240 | + /* Removable CDROM, 50us response, 12 byte packets */ | |
| 2241 | + stw_raw(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); | |
| 2242 | + stw_raw(p + 1, s->cylinders); | |
| 2243 | + stw_raw(p + 3, s->heads); | |
| 2244 | + stw_raw(p + 4, 512 * s->sectors); /* sectors */ | |
| 2245 | + stw_raw(p + 5, 512); /* sector size */ | |
| 2246 | + stw_raw(p + 6, s->sectors); | |
| 2247 | + padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ | |
| 2248 | + stw_raw(p + 20, 3); /* buffer type */ | |
| 2249 | + stw_raw(p + 21, 512); /* cache size in sectors */ | |
| 2250 | + stw_raw(p + 22, 4); /* ecc bytes */ | |
| 2251 | + padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ | |
| 2252 | + padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ | |
| 2253 | + stw_raw(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ | |
| 2254 | + stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ | |
| 2255 | + stw_raw(p + 53, 3); /* words 64-70, 54-58 valid */ | |
| 2256 | + stw_raw(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ | |
| 2257 | + stw_raw(p + 64, 1); /* PIO modes */ | |
| 2258 | + stw_raw(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ | |
| 2259 | + stw_raw(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ | |
| 2260 | + stw_raw(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ | |
| 2261 | + stw_raw(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ | |
| 2262 | + | |
| 2263 | + stw_raw(p + 71, 30); /* in ns */ | |
| 2264 | + stw_raw(p + 72, 30); /* in ns */ | |
| 2265 | + | |
| 2266 | + stw_raw(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ | |
| 2267 | +} | |
| 2268 | + | |
| 2269 | +static void ide_set_signature(IDEState *s) | |
| 2270 | +{ | |
| 2271 | + s->select &= 0xf0; /* clear head */ | |
| 2272 | + /* put signature */ | |
| 2273 | + s->nsector = 1; | |
| 2274 | + s->sector = 1; | |
| 2275 | + if (s->is_cdrom) { | |
| 2276 | + s->lcyl = 0x14; | |
| 2277 | + s->hcyl = 0xeb; | |
| 2278 | + } else if (s->bs) { | |
| 2279 | + s->lcyl = 0; | |
| 2280 | + s->hcyl = 0; | |
| 2281 | + } else { | |
| 2282 | + s->lcyl = 0xff; | |
| 2283 | + s->hcyl = 0xff; | |
| 2284 | + } | |
| 2285 | +} | |
| 2286 | + | |
| 2106 | 2287 | static inline void ide_abort_command(IDEState *s) |
| 2107 | 2288 | { |
| 2108 | 2289 | s->status = READY_STAT | ERR_STAT; |
| ... | ... | @@ -2111,18 +2292,18 @@ static inline void ide_abort_command(IDEState *s) |
| 2111 | 2292 | |
| 2112 | 2293 | static inline void ide_set_irq(IDEState *s) |
| 2113 | 2294 | { |
| 2114 | - if (!(ide_state[0].cmd & IDE_CMD_DISABLE_IRQ)) { | |
| 2295 | + if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { | |
| 2115 | 2296 | pic_set_irq(s->irq, 1); |
| 2116 | 2297 | } |
| 2117 | 2298 | } |
| 2118 | 2299 | |
| 2119 | 2300 | /* prepare data transfer and tell what to do after */ |
| 2120 | -static void ide_transfer_start(IDEState *s, int size, | |
| 2301 | +static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, | |
| 2121 | 2302 | EndTransferFunc *end_transfer_func) |
| 2122 | 2303 | { |
| 2123 | 2304 | s->end_transfer_func = end_transfer_func; |
| 2124 | - s->data_ptr = s->io_buffer; | |
| 2125 | - s->data_end = s->io_buffer + size; | |
| 2305 | + s->data_ptr = buf; | |
| 2306 | + s->data_end = buf + size; | |
| 2126 | 2307 | s->status |= DRQ_STAT; |
| 2127 | 2308 | } |
| 2128 | 2309 | |
| ... | ... | @@ -2185,7 +2366,7 @@ static void ide_sector_read(IDEState *s) |
| 2185 | 2366 | if (n > s->req_nb_sectors) |
| 2186 | 2367 | n = s->req_nb_sectors; |
| 2187 | 2368 | ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); |
| 2188 | - ide_transfer_start(s, 512 * n, ide_sector_read); | |
| 2369 | + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); | |
| 2189 | 2370 | ide_set_irq(s); |
| 2190 | 2371 | ide_set_sector(s, sector_num + n); |
| 2191 | 2372 | s->nsector -= n; |
| ... | ... | @@ -2214,21 +2395,457 @@ static void ide_sector_write(IDEState *s) |
| 2214 | 2395 | n1 = s->nsector; |
| 2215 | 2396 | if (n1 > s->req_nb_sectors) |
| 2216 | 2397 | n1 = s->req_nb_sectors; |
| 2217 | - ide_transfer_start(s, 512 * n1, ide_sector_write); | |
| 2398 | + ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); | |
| 2218 | 2399 | } |
| 2219 | 2400 | ide_set_sector(s, sector_num + n); |
| 2220 | 2401 | ide_set_irq(s); |
| 2221 | 2402 | } |
| 2222 | 2403 | |
| 2404 | +static void ide_atapi_cmd_ok(IDEState *s) | |
| 2405 | +{ | |
| 2406 | + s->error = 0; | |
| 2407 | + s->status = READY_STAT; | |
| 2408 | + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; | |
| 2409 | + ide_set_irq(s); | |
| 2410 | +} | |
| 2411 | + | |
| 2412 | +static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) | |
| 2413 | +{ | |
| 2414 | +#ifdef DEBUG_IDE_ATAPI | |
| 2415 | + printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); | |
| 2416 | +#endif | |
| 2417 | + s->error = sense_key << 4; | |
| 2418 | + s->status = READY_STAT | ERR_STAT; | |
| 2419 | + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; | |
| 2420 | + s->sense_key = sense_key; | |
| 2421 | + s->asc = asc; | |
| 2422 | + ide_set_irq(s); | |
| 2423 | +} | |
| 2424 | + | |
| 2425 | +static inline void cpu_to_ube16(uint8_t *buf, int val) | |
| 2426 | +{ | |
| 2427 | + buf[0] = val >> 8; | |
| 2428 | + buf[1] = val; | |
| 2429 | +} | |
| 2430 | + | |
| 2431 | +static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) | |
| 2432 | +{ | |
| 2433 | + buf[0] = val >> 24; | |
| 2434 | + buf[1] = val >> 16; | |
| 2435 | + buf[2] = val >> 8; | |
| 2436 | + buf[3] = val; | |
| 2437 | +} | |
| 2438 | + | |
| 2439 | +static inline int ube16_to_cpu(const uint8_t *buf) | |
| 2440 | +{ | |
| 2441 | + return (buf[0] << 8) | buf[1]; | |
| 2442 | +} | |
| 2443 | + | |
| 2444 | +static inline int ube32_to_cpu(const uint8_t *buf) | |
| 2445 | +{ | |
| 2446 | + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | |
| 2447 | +} | |
| 2448 | + | |
| 2449 | +/* The whole ATAPI transfer logic is handled in this function */ | |
| 2450 | +static void ide_atapi_cmd_reply_end(IDEState *s) | |
| 2451 | +{ | |
| 2452 | + int byte_count_limit, size; | |
| 2453 | +#ifdef DEBUG_IDE_ATAPI | |
| 2454 | + printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", | |
| 2455 | + s->packet_transfer_size, | |
| 2456 | + s->elementary_transfer_size, | |
| 2457 | + s->io_buffer_index); | |
| 2458 | +#endif | |
| 2459 | + if (s->packet_transfer_size <= 0) { | |
| 2460 | + /* end of transfer */ | |
| 2461 | + ide_transfer_stop(s); | |
| 2462 | + s->status = READY_STAT; | |
| 2463 | + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; | |
| 2464 | + ide_set_irq(s); | |
| 2465 | +#ifdef DEBUG_IDE_ATAPI | |
| 2466 | + printf("status=0x%x\n", s->status); | |
| 2467 | +#endif | |
| 2468 | + } else { | |
| 2469 | + /* see if a new sector must be read */ | |
| 2470 | + if (s->lba != -1 && s->io_buffer_index >= 2048) { | |
| 2471 | + bdrv_read(s->bs, (int64_t)s->lba << 2, s->io_buffer, 4); | |
| 2472 | + s->lba++; | |
| 2473 | + s->io_buffer_index = 0; | |
| 2474 | + } | |
| 2475 | + if (s->elementary_transfer_size > 0) { | |
| 2476 | + /* there are some data left to transmit in this elementary | |
| 2477 | + transfer */ | |
| 2478 | + size = 2048 - s->io_buffer_index; | |
| 2479 | + if (size > s->elementary_transfer_size) | |
| 2480 | + size = s->elementary_transfer_size; | |
| 2481 | + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, | |
| 2482 | + size, ide_atapi_cmd_reply_end); | |
| 2483 | + s->packet_transfer_size -= size; | |
| 2484 | + s->elementary_transfer_size -= size; | |
| 2485 | + s->io_buffer_index += size; | |
| 2486 | + } else { | |
| 2487 | + /* a new transfer is needed */ | |
| 2488 | + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; | |
| 2489 | + byte_count_limit = s->lcyl | (s->hcyl << 8); | |
| 2490 | +#ifdef DEBUG_IDE_ATAPI | |
| 2491 | + printf("byte_count_limit=%d\n", byte_count_limit); | |
| 2492 | +#endif | |
| 2493 | + if (byte_count_limit == 0xffff) | |
| 2494 | + byte_count_limit--; | |
| 2495 | + size = s->packet_transfer_size; | |
| 2496 | + if (size > byte_count_limit) { | |
| 2497 | + /* byte count limit must be even if this case */ | |
| 2498 | + if (byte_count_limit & 1) | |
| 2499 | + byte_count_limit--; | |
| 2500 | + size = byte_count_limit; | |
| 2501 | + } else { | |
| 2502 | + s->lcyl = size; | |
| 2503 | + s->hcyl = size >> 8; | |
| 2504 | + } | |
| 2505 | + s->elementary_transfer_size = size; | |
| 2506 | + /* we cannot transmit more than one sector at a time */ | |
| 2507 | + if (s->lba != -1) { | |
| 2508 | + if (size > (2048 - s->io_buffer_index)) | |
| 2509 | + size = (2048 - s->io_buffer_index); | |
| 2510 | + } | |
| 2511 | + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, | |
| 2512 | + size, ide_atapi_cmd_reply_end); | |
| 2513 | + s->packet_transfer_size -= size; | |
| 2514 | + s->elementary_transfer_size -= size; | |
| 2515 | + s->io_buffer_index += size; | |
| 2516 | + ide_set_irq(s); | |
| 2517 | +#ifdef DEBUG_IDE_ATAPI | |
| 2518 | + printf("status=0x%x\n", s->status); | |
| 2519 | +#endif | |
| 2520 | + } | |
| 2521 | + } | |
| 2522 | +} | |
| 2523 | + | |
| 2524 | +/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ | |
| 2525 | +static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) | |
| 2526 | +{ | |
| 2527 | + if (size > max_size) | |
| 2528 | + size = max_size; | |
| 2529 | + s->lba = -1; /* no sector read */ | |
| 2530 | + s->packet_transfer_size = size; | |
| 2531 | + s->elementary_transfer_size = 0; | |
| 2532 | + s->io_buffer_index = 0; | |
| 2533 | + | |
| 2534 | + s->status = READY_STAT; | |
| 2535 | + ide_atapi_cmd_reply_end(s); | |
| 2536 | +} | |
| 2537 | + | |
| 2538 | +/* start a CD-CDROM read command */ | |
| 2539 | +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors) | |
| 2540 | +{ | |
| 2541 | +#ifdef DEBUG_IDE_ATAPI | |
| 2542 | + printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); | |
| 2543 | +#endif | |
| 2544 | + s->lba = lba; | |
| 2545 | + s->packet_transfer_size = nb_sectors * 2048; | |
| 2546 | + s->elementary_transfer_size = 0; | |
| 2547 | + s->io_buffer_index = 2048; | |
| 2548 | + | |
| 2549 | + s->status = READY_STAT; | |
| 2550 | + ide_atapi_cmd_reply_end(s); | |
| 2551 | +} | |
| 2552 | + | |
| 2553 | +/* same toc as bochs. Return -1 if error or the toc length */ | |
| 2554 | +static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) | |
| 2555 | +{ | |
| 2556 | + uint8_t *q; | |
| 2557 | + int nb_sectors, len; | |
| 2558 | + | |
| 2559 | + if (start_track > 1 && start_track != 0xaa) | |
| 2560 | + return -1; | |
| 2561 | + q = buf + 2; | |
| 2562 | + *q++ = 1; | |
| 2563 | + *q++ = 1; | |
| 2564 | + if (start_track <= 1) { | |
| 2565 | + *q++ = 0; /* reserved */ | |
| 2566 | + *q++ = 0x14; /* ADR, control */ | |
| 2567 | + *q++ = 1; /* track number */ | |
| 2568 | + *q++ = 0; /* reserved */ | |
| 2569 | + if (msf) { | |
| 2570 | + *q++ = 0; /* reserved */ | |
| 2571 | + *q++ = 0; /* minute */ | |
| 2572 | + *q++ = 2; /* second */ | |
| 2573 | + *q++ = 0; /* frame */ | |
| 2574 | + } else { | |
| 2575 | + /* sector 0 */ | |
| 2576 | + cpu_to_ube32(q, 0); | |
| 2577 | + q += 4; | |
| 2578 | + } | |
| 2579 | + } | |
| 2580 | + /* lead out track */ | |
| 2581 | + *q++ = 0; /* reserved */ | |
| 2582 | + *q++ = 0x16; /* ADR, control */ | |
| 2583 | + *q++ = 0xaa; /* track number */ | |
| 2584 | + *q++ = 0; /* reserved */ | |
| 2585 | + nb_sectors = s->nb_sectors >> 2; | |
| 2586 | + if (msf) { | |
| 2587 | + *q++ = 0; /* reserved */ | |
| 2588 | + *q++ = ((nb_sectors + 150) / 75) / 60; | |
| 2589 | + *q++ = ((nb_sectors + 150) / 75) % 60; | |
| 2590 | + *q++ = (nb_sectors + 150) % 75; | |
| 2591 | + } else { | |
| 2592 | + cpu_to_ube32(q, nb_sectors); | |
| 2593 | + q += 4; | |
| 2594 | + } | |
| 2595 | + len = q - buf; | |
| 2596 | + cpu_to_ube16(buf, len - 2); | |
| 2597 | + return len; | |
| 2598 | +} | |
| 2599 | + | |
| 2600 | +static void ide_atapi_cmd(IDEState *s) | |
| 2601 | +{ | |
| 2602 | + const uint8_t *packet; | |
| 2603 | + uint8_t *buf; | |
| 2604 | + int max_len; | |
| 2605 | + | |
| 2606 | + packet = s->io_buffer; | |
| 2607 | + buf = s->io_buffer; | |
| 2608 | +#ifdef DEBUG_IDE_ATAPI | |
| 2609 | + { | |
| 2610 | + int i; | |
| 2611 | + printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); | |
| 2612 | + for(i = 0; i < ATAPI_PACKET_SIZE; i++) { | |
| 2613 | + printf(" %02x", packet[i]); | |
| 2614 | + } | |
| 2615 | + printf("\n"); | |
| 2616 | + } | |
| 2617 | +#endif | |
| 2618 | + switch(s->io_buffer[0]) { | |
| 2619 | + case GPCMD_TEST_UNIT_READY: | |
| 2620 | + if (s->bs) { | |
| 2621 | + ide_atapi_cmd_ok(s); | |
| 2622 | + } else { | |
| 2623 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
| 2624 | + ASC_MEDIUM_NOT_PRESENT); | |
| 2625 | + } | |
| 2626 | + break; | |
| 2627 | + case GPCMD_MODE_SENSE_10: | |
| 2628 | + { | |
| 2629 | + int action, code; | |
| 2630 | + max_len = ube16_to_cpu(packet + 7); | |
| 2631 | + action = packet[2] >> 6; | |
| 2632 | + code = packet[2] & 0x3f; | |
| 2633 | + switch(action) { | |
| 2634 | + case 0: /* current values */ | |
| 2635 | + switch(code) { | |
| 2636 | + case 0x01: /* error recovery */ | |
| 2637 | + cpu_to_ube16(&buf[0], 16 + 6); | |
| 2638 | + buf[2] = 0x70; | |
| 2639 | + buf[3] = 0; | |
| 2640 | + buf[4] = 0; | |
| 2641 | + buf[5] = 0; | |
| 2642 | + buf[6] = 0; | |
| 2643 | + buf[7] = 0; | |
| 2644 | + | |
| 2645 | + buf[8] = 0x01; | |
| 2646 | + buf[9] = 0x06; | |
| 2647 | + buf[10] = 0x00; | |
| 2648 | + buf[11] = 0x05; | |
| 2649 | + buf[12] = 0x00; | |
| 2650 | + buf[13] = 0x00; | |
| 2651 | + buf[14] = 0x00; | |
| 2652 | + buf[15] = 0x00; | |
| 2653 | + ide_atapi_cmd_reply(s, 16, max_len); | |
| 2654 | + break; | |
| 2655 | + case 0x2a: | |
| 2656 | + cpu_to_ube16(&buf[0], 28 + 6); | |
| 2657 | + buf[2] = 0x70; | |
| 2658 | + buf[3] = 0; | |
| 2659 | + buf[4] = 0; | |
| 2660 | + buf[5] = 0; | |
| 2661 | + buf[6] = 0; | |
| 2662 | + buf[7] = 0; | |
| 2663 | + | |
| 2664 | + buf[8] = 0x2a; | |
| 2665 | + buf[9] = 0x12; | |
| 2666 | + buf[10] = 0x00; | |
| 2667 | + buf[11] = 0x00; | |
| 2668 | + | |
| 2669 | + buf[12] = 0x70; | |
| 2670 | + buf[13] = 3 << 5; | |
| 2671 | + buf[14] = (1 << 0) | (1 << 3) | (1 << 5); | |
| 2672 | + if (s->cdrom_locked) | |
| 2673 | + buf[6] |= 1 << 1; | |
| 2674 | + buf[15] = 0x00; | |
| 2675 | + cpu_to_ube16(&buf[16], 706); | |
| 2676 | + buf[18] = 0; | |
| 2677 | + buf[19] = 2; | |
| 2678 | + cpu_to_ube16(&buf[20], 512); | |
| 2679 | + cpu_to_ube16(&buf[22], 706); | |
| 2680 | + buf[24] = 0; | |
| 2681 | + buf[25] = 0; | |
| 2682 | + buf[26] = 0; | |
| 2683 | + buf[27] = 0; | |
| 2684 | + ide_atapi_cmd_reply(s, 28, max_len); | |
| 2685 | + break; | |
| 2686 | + default: | |
| 2687 | + goto error_cmd; | |
| 2688 | + } | |
| 2689 | + break; | |
| 2690 | + case 1: /* changeable values */ | |
| 2691 | + goto error_cmd; | |
| 2692 | + case 2: /* default values */ | |
| 2693 | + goto error_cmd; | |
| 2694 | + default: | |
| 2695 | + case 3: /* saved values */ | |
| 2696 | + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
| 2697 | + ASC_SAVING_PARAMETERS_NOT_SUPPORTED); | |
| 2698 | + break; | |
| 2699 | + } | |
| 2700 | + } | |
| 2701 | + break; | |
| 2702 | + case GPCMD_REQUEST_SENSE: | |
| 2703 | + max_len = packet[4]; | |
| 2704 | + memset(buf, 0, 18); | |
| 2705 | + buf[0] = 0x70 | (1 << 7); | |
| 2706 | + buf[2] = s->sense_key; | |
| 2707 | + buf[7] = 10; | |
| 2708 | + buf[12] = s->asc; | |
| 2709 | + ide_atapi_cmd_reply(s, 18, max_len); | |
| 2710 | + break; | |
| 2711 | + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: | |
| 2712 | + if (s->bs) { | |
| 2713 | + s->cdrom_locked = packet[4] & 1; | |
| 2714 | + ide_atapi_cmd_ok(s); | |
| 2715 | + } else { | |
| 2716 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
| 2717 | + ASC_MEDIUM_NOT_PRESENT); | |
| 2718 | + } | |
| 2719 | + break; | |
| 2720 | + case GPCMD_READ_10: | |
| 2721 | + case GPCMD_READ_12: | |
| 2722 | + { | |
| 2723 | + int nb_sectors, lba; | |
| 2724 | + | |
| 2725 | + if (!s->bs) { | |
| 2726 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
| 2727 | + ASC_MEDIUM_NOT_PRESENT); | |
| 2728 | + break; | |
| 2729 | + } | |
| 2730 | + if (packet[0] == GPCMD_READ_10) | |
| 2731 | + nb_sectors = ube16_to_cpu(packet + 7); | |
| 2732 | + else | |
| 2733 | + nb_sectors = ube32_to_cpu(packet + 6); | |
| 2734 | + lba = ube32_to_cpu(packet + 2); | |
| 2735 | + if (nb_sectors == 0) { | |
| 2736 | + ide_atapi_cmd_ok(s); | |
| 2737 | + break; | |
| 2738 | + } | |
| 2739 | + if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { | |
| 2740 | + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
| 2741 | + ASC_LOGICAL_BLOCK_OOR); | |
| 2742 | + break; | |
| 2743 | + } | |
| 2744 | + ide_atapi_cmd_read(s, lba, nb_sectors); | |
| 2745 | + } | |
| 2746 | + break; | |
| 2747 | + case GPCMD_SEEK: | |
| 2748 | + { | |
| 2749 | + int lba; | |
| 2750 | + if (!s->bs) { | |
| 2751 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
| 2752 | + ASC_MEDIUM_NOT_PRESENT); | |
| 2753 | + break; | |
| 2754 | + } | |
| 2755 | + lba = ube32_to_cpu(packet + 2); | |
| 2756 | + if (((int64_t)lba << 2) > s->nb_sectors) { | |
| 2757 | + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
| 2758 | + ASC_LOGICAL_BLOCK_OOR); | |
| 2759 | + break; | |
| 2760 | + } | |
| 2761 | + ide_atapi_cmd_ok(s); | |
| 2762 | + } | |
| 2763 | + break; | |
| 2764 | + case GPCMD_START_STOP_UNIT: | |
| 2765 | + { | |
| 2766 | + int start, eject; | |
| 2767 | + start = packet[4] & 1; | |
| 2768 | + eject = (packet[4] >> 1) & 1; | |
| 2769 | + | |
| 2770 | + /* XXX: currently none implemented */ | |
| 2771 | + ide_atapi_cmd_ok(s); | |
| 2772 | + } | |
| 2773 | + break; | |
| 2774 | + case GPCMD_MECHANISM_STATUS: | |
| 2775 | + { | |
| 2776 | + max_len = ube16_to_cpu(packet + 8); | |
| 2777 | + cpu_to_ube16(buf, 0); | |
| 2778 | + /* no current LBA */ | |
| 2779 | + buf[2] = 0; | |
| 2780 | + buf[3] = 0; | |
| 2781 | + buf[4] = 0; | |
| 2782 | + buf[5] = 1; | |
| 2783 | + cpu_to_ube16(buf + 6, 0); | |
| 2784 | + ide_atapi_cmd_reply(s, 8, max_len); | |
| 2785 | + } | |
| 2786 | + break; | |
| 2787 | + case GPCMD_READ_TOC_PMA_ATIP: | |
| 2788 | + { | |
| 2789 | + int format, msf, start_track, len; | |
| 2790 | + | |
| 2791 | + if (!s->bs) { | |
| 2792 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
| 2793 | + ASC_MEDIUM_NOT_PRESENT); | |
| 2794 | + break; | |
| 2795 | + } | |
| 2796 | + max_len = ube16_to_cpu(packet + 7); | |
| 2797 | + format = packet[9] >> 6; | |
| 2798 | + msf = (packet[1] >> 1) & 1; | |
| 2799 | + start_track = packet[6]; | |
| 2800 | + switch(format) { | |
| 2801 | + case 0: | |
| 2802 | + len = cdrom_read_toc(s, buf, msf, start_track); | |
| 2803 | + if (len < 0) | |
| 2804 | + goto error_cmd; | |
| 2805 | + ide_atapi_cmd_reply(s, len, max_len); | |
| 2806 | + break; | |
| 2807 | + case 1: | |
| 2808 | + /* multi session : only a single session defined */ | |
| 2809 | + memset(buf, 0, 12); | |
| 2810 | + buf[1] = 0x0a; | |
| 2811 | + buf[2] = 0x01; | |
| 2812 | + buf[3] = 0x01; | |
| 2813 | + ide_atapi_cmd_reply(s, 12, max_len); | |
| 2814 | + break; | |
| 2815 | + default: | |
| 2816 | + goto error_cmd; | |
| 2817 | + } | |
| 2818 | + } | |
| 2819 | + break; | |
| 2820 | + case GPCMD_READ_CDVD_CAPACITY: | |
| 2821 | + if (!s->bs) { | |
| 2822 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
| 2823 | + ASC_MEDIUM_NOT_PRESENT); | |
| 2824 | + break; | |
| 2825 | + } | |
| 2826 | + /* NOTE: it is really the number of sectors minus 1 */ | |
| 2827 | + cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); | |
| 2828 | + cpu_to_ube32(buf + 4, 2048); | |
| 2829 | + ide_atapi_cmd_reply(s, 8, 8); | |
| 2830 | + break; | |
| 2831 | + default: | |
| 2832 | + error_cmd: | |
| 2833 | + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
| 2834 | + ASC_INV_FIELD_IN_CMD_PACKET); | |
| 2835 | + break; | |
| 2836 | + } | |
| 2837 | +} | |
| 2838 | + | |
| 2223 | 2839 | void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2224 | 2840 | { |
| 2225 | - IDEState *s = ide_state[0].cur_drive; | |
| 2841 | + IDEState *ide_if = get_ide_interface(addr); | |
| 2842 | + IDEState *s = ide_if->cur_drive; | |
| 2226 | 2843 | int unit, n; |
| 2227 | 2844 | |
| 2228 | - addr &= 7; | |
| 2229 | 2845 | #ifdef DEBUG_IDE |
| 2230 | 2846 | printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); |
| 2231 | 2847 | #endif |
| 2848 | + addr &= 7; | |
| 2232 | 2849 | switch(addr) { |
| 2233 | 2850 | case 0: |
| 2234 | 2851 | break; |
| ... | ... | @@ -2252,8 +2869,8 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2252 | 2869 | case 6: |
| 2253 | 2870 | /* select drive */ |
| 2254 | 2871 | unit = (val >> 4) & 1; |
| 2255 | - s = &ide_state[unit]; | |
| 2256 | - ide_state[0].cur_drive = s; | |
| 2872 | + s = ide_if + unit; | |
| 2873 | + ide_if->cur_drive = s; | |
| 2257 | 2874 | s->select = val; |
| 2258 | 2875 | break; |
| 2259 | 2876 | default: |
| ... | ... | @@ -2263,13 +2880,15 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2263 | 2880 | printf("ide: CMD=%02x\n", val); |
| 2264 | 2881 | #endif |
| 2265 | 2882 | switch(val) { |
| 2266 | - case WIN_PIDENTIFY: | |
| 2267 | 2883 | case WIN_IDENTIFY: |
| 2268 | - if (s->bs) { | |
| 2884 | + if (s->bs && !s->is_cdrom) { | |
| 2269 | 2885 | ide_identify(s); |
| 2270 | 2886 | s->status = READY_STAT; |
| 2271 | - ide_transfer_start(s, 512, ide_transfer_stop); | |
| 2887 | + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); | |
| 2272 | 2888 | } else { |
| 2889 | + if (s->is_cdrom) { | |
| 2890 | + ide_set_signature(s); | |
| 2891 | + } | |
| 2273 | 2892 | ide_abort_command(s); |
| 2274 | 2893 | } |
| 2275 | 2894 | ide_set_irq(s); |
| ... | ... | @@ -2299,7 +2918,7 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2299 | 2918 | case WIN_WRITE_ONCE: |
| 2300 | 2919 | s->status = SEEK_STAT; |
| 2301 | 2920 | s->req_nb_sectors = 1; |
| 2302 | - ide_transfer_start(s, 512, ide_sector_write); | |
| 2921 | + ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); | |
| 2303 | 2922 | break; |
| 2304 | 2923 | case WIN_MULTREAD: |
| 2305 | 2924 | if (!s->mult_sectors) |
| ... | ... | @@ -2315,13 +2934,42 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2315 | 2934 | n = s->nsector; |
| 2316 | 2935 | if (n > s->req_nb_sectors) |
| 2317 | 2936 | n = s->req_nb_sectors; |
| 2318 | - ide_transfer_start(s, 512 * n, ide_sector_write); | |
| 2937 | + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); | |
| 2319 | 2938 | break; |
| 2320 | 2939 | case WIN_READ_NATIVE_MAX: |
| 2321 | 2940 | ide_set_sector(s, s->nb_sectors - 1); |
| 2322 | 2941 | s->status = READY_STAT; |
| 2323 | 2942 | ide_set_irq(s); |
| 2324 | 2943 | break; |
| 2944 | + | |
| 2945 | + /* ATAPI commands */ | |
| 2946 | + case WIN_PIDENTIFY: | |
| 2947 | + if (s->is_cdrom) { | |
| 2948 | + ide_atapi_identify(s); | |
| 2949 | + s->status = READY_STAT; | |
| 2950 | + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); | |
| 2951 | + } else { | |
| 2952 | + ide_abort_command(s); | |
| 2953 | + } | |
| 2954 | + ide_set_irq(s); | |
| 2955 | + break; | |
| 2956 | + case WIN_SRST: | |
| 2957 | + if (!s->is_cdrom) | |
| 2958 | + goto abort_cmd; | |
| 2959 | + ide_set_signature(s); | |
| 2960 | + s->status = READY_STAT; | |
| 2961 | + s->error = 0x01; | |
| 2962 | + break; | |
| 2963 | + case WIN_PACKETCMD: | |
| 2964 | + if (!s->is_cdrom) | |
| 2965 | + goto abort_cmd; | |
| 2966 | + /* DMA or overlapping commands not supported */ | |
| 2967 | + if ((s->feature & 0x03) != 0) | |
| 2968 | + goto abort_cmd; | |
| 2969 | + s->nsector = 1; | |
| 2970 | + ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, | |
| 2971 | + ide_atapi_cmd); | |
| 2972 | + break; | |
| 2325 | 2973 | default: |
| 2326 | 2974 | abort_cmd: |
| 2327 | 2975 | ide_abort_command(s); |
| ... | ... | @@ -2331,12 +2979,13 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2331 | 2979 | } |
| 2332 | 2980 | } |
| 2333 | 2981 | |
| 2334 | -uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr) | |
| 2982 | +uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr1) | |
| 2335 | 2983 | { |
| 2336 | - IDEState *s = ide_state[0].cur_drive; | |
| 2984 | + IDEState *s = get_ide_interface(addr1)->cur_drive; | |
| 2985 | + uint32_t addr; | |
| 2337 | 2986 | int ret; |
| 2338 | 2987 | |
| 2339 | - addr &= 7; | |
| 2988 | + addr = addr1 & 7; | |
| 2340 | 2989 | switch(addr) { |
| 2341 | 2990 | case 0: |
| 2342 | 2991 | ret = 0xff; |
| ... | ... | @@ -2366,66 +3015,57 @@ uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr) |
| 2366 | 3015 | break; |
| 2367 | 3016 | } |
| 2368 | 3017 | #ifdef DEBUG_IDE |
| 2369 | - printf("ide: read addr=0x%x val=%02x\n", addr, ret); | |
| 3018 | + printf("ide: read addr=0x%x val=%02x\n", addr1, ret); | |
| 2370 | 3019 | #endif |
| 2371 | 3020 | return ret; |
| 2372 | 3021 | } |
| 2373 | 3022 | |
| 2374 | 3023 | uint32_t ide_status_read(CPUX86State *env, uint32_t addr) |
| 2375 | 3024 | { |
| 2376 | - IDEState *s = ide_state[0].cur_drive; | |
| 3025 | + IDEState *s = get_ide_interface(addr)->cur_drive; | |
| 2377 | 3026 | int ret; |
| 2378 | 3027 | ret = s->status; |
| 2379 | 3028 | #ifdef DEBUG_IDE |
| 2380 | - printf("ide: read status val=%02x\n", ret); | |
| 3029 | + printf("ide: read status addr=0x%x val=%02x\n", addr, ret); | |
| 2381 | 3030 | #endif |
| 2382 | 3031 | return ret; |
| 2383 | 3032 | } |
| 2384 | 3033 | |
| 2385 | 3034 | void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2386 | 3035 | { |
| 3036 | + IDEState *ide_if = get_ide_interface(addr); | |
| 2387 | 3037 | IDEState *s; |
| 2388 | 3038 | int i; |
| 2389 | 3039 | |
| 2390 | 3040 | #ifdef DEBUG_IDE |
| 2391 | - printf("ide: write control val=%02x\n", val); | |
| 3041 | + printf("ide: write control addr=0x%x val=%02x\n", addr, val); | |
| 2392 | 3042 | #endif |
| 2393 | 3043 | /* common for both drives */ |
| 2394 | - if (!(ide_state[0].cmd & IDE_CMD_RESET) && | |
| 3044 | + if (!(ide_if[0].cmd & IDE_CMD_RESET) && | |
| 2395 | 3045 | (val & IDE_CMD_RESET)) { |
| 2396 | 3046 | /* reset low to high */ |
| 2397 | 3047 | for(i = 0;i < 2; i++) { |
| 2398 | - s = &ide_state[i]; | |
| 3048 | + s = &ide_if[i]; | |
| 2399 | 3049 | s->status = BUSY_STAT | SEEK_STAT; |
| 2400 | 3050 | s->error = 0x01; |
| 2401 | 3051 | } |
| 2402 | - } else if ((ide_state[0].cmd & IDE_CMD_RESET) && | |
| 3052 | + } else if ((ide_if[0].cmd & IDE_CMD_RESET) && | |
| 2403 | 3053 | !(val & IDE_CMD_RESET)) { |
| 2404 | 3054 | /* high to low */ |
| 2405 | 3055 | for(i = 0;i < 2; i++) { |
| 2406 | - s = &ide_state[i]; | |
| 3056 | + s = &ide_if[i]; | |
| 2407 | 3057 | s->status = READY_STAT; |
| 2408 | - /* set hard disk drive ID */ | |
| 2409 | - s->select &= 0xf0; /* clear head */ | |
| 2410 | - s->nsector = 1; | |
| 2411 | - s->sector = 1; | |
| 2412 | - if (s->nb_sectors == 0) { | |
| 2413 | - /* no disk present */ | |
| 2414 | - s->lcyl = 0x12; | |
| 2415 | - s->hcyl = 0x34; | |
| 2416 | - } else { | |
| 2417 | - s->lcyl = 0; | |
| 2418 | - s->hcyl = 0; | |
| 2419 | - } | |
| 3058 | + ide_set_signature(s); | |
| 2420 | 3059 | } |
| 2421 | 3060 | } |
| 2422 | 3061 | |
| 2423 | - ide_state[0].cmd = val; | |
| 3062 | + ide_if[0].cmd = val; | |
| 3063 | + ide_if[1].cmd = val; | |
| 2424 | 3064 | } |
| 2425 | 3065 | |
| 2426 | 3066 | void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2427 | 3067 | { |
| 2428 | - IDEState *s = ide_state[0].cur_drive; | |
| 3068 | + IDEState *s = get_ide_interface(addr)->cur_drive; | |
| 2429 | 3069 | uint8_t *p; |
| 2430 | 3070 | |
| 2431 | 3071 | p = s->data_ptr; |
| ... | ... | @@ -2438,10 +3078,9 @@ void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2438 | 3078 | |
| 2439 | 3079 | uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) |
| 2440 | 3080 | { |
| 2441 | - IDEState *s = ide_state[0].cur_drive; | |
| 3081 | + IDEState *s = get_ide_interface(addr)->cur_drive; | |
| 2442 | 3082 | uint8_t *p; |
| 2443 | 3083 | int ret; |
| 2444 | - | |
| 2445 | 3084 | p = s->data_ptr; |
| 2446 | 3085 | ret = tswap16(*(uint16_t *)p); |
| 2447 | 3086 | p += 2; |
| ... | ... | @@ -2453,7 +3092,7 @@ uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) |
| 2453 | 3092 | |
| 2454 | 3093 | void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2455 | 3094 | { |
| 2456 | - IDEState *s = ide_state[0].cur_drive; | |
| 3095 | + IDEState *s = get_ide_interface(addr)->cur_drive; | |
| 2457 | 3096 | uint8_t *p; |
| 2458 | 3097 | |
| 2459 | 3098 | p = s->data_ptr; |
| ... | ... | @@ -2466,7 +3105,7 @@ void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2466 | 3105 | |
| 2467 | 3106 | uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) |
| 2468 | 3107 | { |
| 2469 | - IDEState *s = ide_state[0].cur_drive; | |
| 3108 | + IDEState *s = get_ide_interface(addr)->cur_drive; | |
| 2470 | 3109 | uint8_t *p; |
| 2471 | 3110 | int ret; |
| 2472 | 3111 | |
| ... | ... | @@ -2482,9 +3121,10 @@ uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) |
| 2482 | 3121 | void ide_reset(IDEState *s) |
| 2483 | 3122 | { |
| 2484 | 3123 | s->mult_sectors = MAX_MULT_SECTORS; |
| 2485 | - s->status = READY_STAT; | |
| 2486 | 3124 | s->cur_drive = s; |
| 2487 | 3125 | s->select = 0xa0; |
| 3126 | + s->status = READY_STAT; | |
| 3127 | + ide_set_signature(s); | |
| 2488 | 3128 | } |
| 2489 | 3129 | |
| 2490 | 3130 | struct partition { |
| ... | ... | @@ -2536,8 +3176,11 @@ void ide_guess_geometry(IDEState *s) |
| 2536 | 3176 | void ide_init(void) |
| 2537 | 3177 | { |
| 2538 | 3178 | IDEState *s; |
| 2539 | - int i, cylinders; | |
| 3179 | + int i, cylinders, iobase, iobase2; | |
| 2540 | 3180 | int64_t nb_sectors; |
| 3181 | + static const int ide_iobase[2] = { 0x1f0, 0x170 }; | |
| 3182 | + static const int ide_iobase2[2] = { 0x3f6, 0x376 }; | |
| 3183 | + static const int ide_irq[2] = { 14, 15 }; | |
| 2541 | 3184 | |
| 2542 | 3185 | for(i = 0; i < MAX_DISKS; i++) { |
| 2543 | 3186 | s = &ide_state[i]; |
| ... | ... | @@ -2558,19 +3201,26 @@ void ide_init(void) |
| 2558 | 3201 | s->sectors = 63; |
| 2559 | 3202 | } |
| 2560 | 3203 | } |
| 2561 | - s->irq = 14; | |
| 3204 | + s->irq = ide_irq[i >> 1]; | |
| 2562 | 3205 | ide_reset(s); |
| 2563 | 3206 | } |
| 2564 | - register_ioport_write(0x1f0, 8, ide_ioport_write, 1); | |
| 2565 | - register_ioport_read(0x1f0, 8, ide_ioport_read, 1); | |
| 2566 | - register_ioport_read(0x3f6, 1, ide_status_read, 1); | |
| 2567 | - register_ioport_write(0x3f6, 1, ide_cmd_write, 1); | |
| 2568 | - | |
| 2569 | - /* data ports */ | |
| 2570 | - register_ioport_write(0x1f0, 2, ide_data_writew, 2); | |
| 2571 | - register_ioport_read(0x1f0, 2, ide_data_readw, 2); | |
| 2572 | - register_ioport_write(0x1f0, 4, ide_data_writel, 4); | |
| 2573 | - register_ioport_read(0x1f0, 4, ide_data_readl, 4); | |
| 3207 | + for(i = 0; i < (MAX_DISKS / 2); i++) { | |
| 3208 | + iobase = ide_iobase[i]; | |
| 3209 | + iobase2 = ide_iobase2[i]; | |
| 3210 | + ide_table[iobase >> 3] = &ide_state[2 * i]; | |
| 3211 | + if (ide_iobase2[i]) | |
| 3212 | + ide_table[iobase2 >> 3] = &ide_state[2 * i]; | |
| 3213 | + register_ioport_write(iobase, 8, ide_ioport_write, 1); | |
| 3214 | + register_ioport_read(iobase, 8, ide_ioport_read, 1); | |
| 3215 | + register_ioport_read(iobase2, 1, ide_status_read, 1); | |
| 3216 | + register_ioport_write(iobase2, 1, ide_cmd_write, 1); | |
| 3217 | + | |
| 3218 | + /* data ports */ | |
| 3219 | + register_ioport_write(iobase, 2, ide_data_writew, 2); | |
| 3220 | + register_ioport_read(iobase, 2, ide_data_readw, 2); | |
| 3221 | + register_ioport_write(iobase, 4, ide_data_writel, 4); | |
| 3222 | + register_ioport_read(iobase, 4, ide_data_readl, 4); | |
| 3223 | + } | |
| 2574 | 3224 | } |
| 2575 | 3225 | |
| 2576 | 3226 | /***********************************************************/ |
| ... | ... | @@ -2811,7 +3461,7 @@ void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2811 | 3461 | cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); |
| 2812 | 3462 | break; |
| 2813 | 3463 | default: |
| 2814 | - fprintf(stderr, "vl: unsupported keyboard cmd=0x%02x\n", val); | |
| 3464 | + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); | |
| 2815 | 3465 | break; |
| 2816 | 3466 | } |
| 2817 | 3467 | } |
| ... | ... | @@ -3458,8 +4108,10 @@ void help(void) |
| 3458 | 4108 | "'disk_image' is a raw hard image image for IDE hard disk 0\n" |
| 3459 | 4109 | "\n" |
| 3460 | 4110 | "Standard options:\n" |
| 3461 | - "-hda file use 'file' as IDE hard disk 0 image\n" | |
| 3462 | - "-hdb file use 'file' as IDE hard disk 1 image\n" | |
| 4111 | + "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" | |
| 4112 | + "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" | |
| 4113 | + "-cdrom file use 'file' as IDE cdrom 2 image\n" | |
| 4114 | + "-boot [c|d] boot on hard disk or CD-ROM\n" | |
| 3463 | 4115 | "-snapshot write to temporary files instead of disk image files\n" |
| 3464 | 4116 | "-m megs set virtual RAM size to megs MB\n" |
| 3465 | 4117 | "-n script set network init script [default=%s]\n" |
| ... | ... | @@ -3506,6 +4158,10 @@ struct option long_options[] = { |
| 3506 | 4158 | { "kernel", 1, NULL, 0, }, |
| 3507 | 4159 | { "append", 1, NULL, 0, }, |
| 3508 | 4160 | { "tun-fd", 1, NULL, 0, }, |
| 4161 | + { "hdc", 1, NULL, 0, }, | |
| 4162 | + { "hdd", 1, NULL, 0, }, | |
| 4163 | + { "cdrom", 1, NULL, 0, }, | |
| 4164 | + { "boot", 1, NULL, 0, }, | |
| 3509 | 4165 | { NULL, 0, NULL, 0 }, |
| 3510 | 4166 | }; |
| 3511 | 4167 | |
| ... | ... | @@ -3601,6 +4257,23 @@ int main(int argc, char **argv) |
| 3601 | 4257 | case 8: |
| 3602 | 4258 | net_fd = atoi(optarg); |
| 3603 | 4259 | break; |
| 4260 | + case 9: | |
| 4261 | + hd_filename[2] = optarg; | |
| 4262 | + break; | |
| 4263 | + case 10: | |
| 4264 | + hd_filename[3] = optarg; | |
| 4265 | + break; | |
| 4266 | + case 11: | |
| 4267 | + hd_filename[2] = optarg; | |
| 4268 | + ide_state[2].is_cdrom = 1; | |
| 4269 | + break; | |
| 4270 | + case 12: | |
| 4271 | + boot_device = optarg[0]; | |
| 4272 | + if (boot_device != 'c' && boot_device != 'd') { | |
| 4273 | + fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device); | |
| 4274 | + exit(1); | |
| 4275 | + } | |
| 4276 | + break; | |
| 3604 | 4277 | } |
| 3605 | 4278 | break; |
| 3606 | 4279 | case 'h': |
| ... | ... | @@ -3611,7 +4284,7 @@ int main(int argc, char **argv) |
| 3611 | 4284 | if (phys_ram_size <= 0) |
| 3612 | 4285 | help(); |
| 3613 | 4286 | if (phys_ram_size > PHYS_RAM_MAX_SIZE) { |
| 3614 | - fprintf(stderr, "vl: at most %d MB RAM can be simulated\n", | |
| 4287 | + fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", | |
| 3615 | 4288 | PHYS_RAM_MAX_SIZE / (1024 * 1024)); |
| 3616 | 4289 | exit(1); |
| 3617 | 4290 | } |
| ... | ... | @@ -3640,7 +4313,7 @@ int main(int argc, char **argv) |
| 3640 | 4313 | |
| 3641 | 4314 | linux_boot = (kernel_filename != NULL); |
| 3642 | 4315 | |
| 3643 | - if (!linux_boot && hd_filename[0] == '\0') | |
| 4316 | + if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0') | |
| 3644 | 4317 | help(); |
| 3645 | 4318 | |
| 3646 | 4319 | /* init debug */ |
| ... | ... | @@ -3698,7 +4371,7 @@ int main(int argc, char **argv) |
| 3698 | 4371 | if (hd_filename[i]) { |
| 3699 | 4372 | bs_table[i] = bdrv_open(hd_filename[i], snapshot); |
| 3700 | 4373 | if (!bs_table[i]) { |
| 3701 | - fprintf(stderr, "vl: could not open hard disk image '%s\n", | |
| 4374 | + fprintf(stderr, "qemu: could not open hard disk image '%s\n", | |
| 3702 | 4375 | hd_filename[i]); |
| 3703 | 4376 | exit(1); |
| 3704 | 4377 | } |
| ... | ... | @@ -3719,7 +4392,7 @@ int main(int argc, char **argv) |
| 3719 | 4392 | /* now we can load the kernel */ |
| 3720 | 4393 | ret = load_kernel(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); |
| 3721 | 4394 | if (ret < 0) { |
| 3722 | - fprintf(stderr, "vl: could not load kernel '%s'\n", | |
| 4395 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
| 3723 | 4396 | kernel_filename); |
| 3724 | 4397 | exit(1); |
| 3725 | 4398 | } |
| ... | ... | @@ -3729,7 +4402,7 @@ int main(int argc, char **argv) |
| 3729 | 4402 | if (initrd_filename) { |
| 3730 | 4403 | initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); |
| 3731 | 4404 | if (initrd_size < 0) { |
| 3732 | - fprintf(stderr, "vl: could not load initial ram disk '%s'\n", | |
| 4405 | + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | |
| 3733 | 4406 | initrd_filename); |
| 3734 | 4407 | exit(1); |
| 3735 | 4408 | } |
| ... | ... | @@ -3788,7 +4461,7 @@ int main(int argc, char **argv) |
| 3788 | 4461 | snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); |
| 3789 | 4462 | ret = load_image(buf, phys_ram_base + 0x000f0000); |
| 3790 | 4463 | if (ret != 0x10000) { |
| 3791 | - fprintf(stderr, "vl: could not load PC bios '%s'\n", buf); | |
| 4464 | + fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); | |
| 3792 | 4465 | exit(1); |
| 3793 | 4466 | } |
| 3794 | 4467 | ... | ... |