4 * Copyright (c) 2005-2006 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 #define DPRINTF(fmt, args...) \
31 do { printf("ESP: " fmt , ##args); } while (0)
32 #define pic_set_irq(irq, level) \
33 do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
35 #define DPRINTF(fmt, args...)
39 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
40 #define ESP_MAXREG 0x3f
41 #define TI_BUFSZ 1024*1024 // XXX
42 #define DMA_VER 0xa0000000
44 #define DMA_INTREN 0x10
45 #define DMA_LOADED 0x04000000
46 typedef struct ESPState ESPState
;
48 typedef int ESPDMAFunc(ESPState
*s
,
49 target_phys_addr_t phys_addr
,
53 BlockDriverState
**bd
;
54 uint8_t rregs
[ESP_MAXREG
];
55 uint8_t wregs
[ESP_MAXREG
];
57 uint32_t espdmaregs
[ESPDMA_REGS
];
59 uint32_t ti_rptr
, ti_wptr
;
61 uint8_t ti_buf
[TI_BUFSZ
];
86 /* XXX: stolen from ide.c, move to common ATAPI/SCSI library */
87 static void lba_to_msf(uint8_t *buf
, int lba
)
90 buf
[0] = (lba
/ 75) / 60;
91 buf
[1] = (lba
/ 75) % 60;
95 static inline void cpu_to_ube16(uint8_t *buf
, int val
)
101 static inline void cpu_to_ube32(uint8_t *buf
, unsigned int val
)
109 /* same toc as bochs. Return -1 if error or the toc length */
110 /* XXX: check this */
111 static int cdrom_read_toc(int nb_sectors
, uint8_t *buf
, int msf
, int start_track
)
116 if (start_track
> 1 && start_track
!= 0xaa)
119 *q
++ = 1; /* first session */
120 *q
++ = 1; /* last session */
121 if (start_track
<= 1) {
122 *q
++ = 0; /* reserved */
123 *q
++ = 0x14; /* ADR, control */
124 *q
++ = 1; /* track number */
125 *q
++ = 0; /* reserved */
127 *q
++ = 0; /* reserved */
137 *q
++ = 0; /* reserved */
138 *q
++ = 0x16; /* ADR, control */
139 *q
++ = 0xaa; /* track number */
140 *q
++ = 0; /* reserved */
142 *q
++ = 0; /* reserved */
143 lba_to_msf(q
, nb_sectors
);
146 cpu_to_ube32(q
, nb_sectors
);
150 cpu_to_ube16(buf
, len
- 2);
154 /* mostly same info as PearPc */
155 static int cdrom_read_toc_raw(int nb_sectors
, uint8_t *buf
, int msf
,
162 *q
++ = 1; /* first session */
163 *q
++ = 1; /* last session */
165 *q
++ = 1; /* session number */
166 *q
++ = 0x14; /* data track */
167 *q
++ = 0; /* track number */
168 *q
++ = 0xa0; /* lead-in */
171 *q
++ = 0; /* frame */
173 *q
++ = 1; /* first track */
174 *q
++ = 0x00; /* disk type */
177 *q
++ = 1; /* session number */
178 *q
++ = 0x14; /* data track */
179 *q
++ = 0; /* track number */
183 *q
++ = 0; /* frame */
185 *q
++ = 1; /* last track */
189 *q
++ = 1; /* session number */
190 *q
++ = 0x14; /* data track */
191 *q
++ = 0; /* track number */
192 *q
++ = 0xa2; /* lead-out */
195 *q
++ = 0; /* frame */
197 *q
++ = 0; /* reserved */
198 lba_to_msf(q
, nb_sectors
);
201 cpu_to_ube32(q
, nb_sectors
);
205 *q
++ = 1; /* session number */
206 *q
++ = 0x14; /* ADR, control */
207 *q
++ = 0; /* track number */
208 *q
++ = 1; /* point */
211 *q
++ = 0; /* frame */
224 cpu_to_ube16(buf
, len
- 2);
228 static int esp_write_dma_cb(ESPState
*s
,
229 target_phys_addr_t phys_addr
,
233 if (bdrv_get_type_hint(s
->bd
[s
->target
]) == BDRV_TYPE_CDROM
) {
234 len
= transfer_size1
/2048;
236 len
= transfer_size1
/512;
238 DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n",
239 s
->offset
, s
->len
, s
->ti_size
, transfer_size1
);
241 bdrv_write(s
->bd
[s
->target
], s
->offset
, s
->ti_buf
+s
->ti_rptr
, len
);
246 static void handle_satn(ESPState
*s
)
249 uint32_t dmaptr
, dmalen
;
254 dmalen
= s
->wregs
[0] | (s
->wregs
[1] << 8);
255 target
= s
->wregs
[4] & 7;
256 DPRINTF("Select with ATN len %d target %d\n", dmalen
, target
);
258 dmaptr
= iommu_translate(s
->espdmaregs
[1]);
259 DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s
->espdmaregs
[0] & 0x100? 'w': 'r', dmaptr
);
260 cpu_physical_memory_read(dmaptr
, buf
, dmalen
);
263 memcpy(&buf
[1], s
->ti_buf
, dmalen
);
266 for (i
= 0; i
< dmalen
; i
++) {
267 DPRINTF("Command %2.2x\n", buf
[i
]);
274 if (target
>= 4 || !s
->bd
[target
]) { // No such drive
275 s
->rregs
[4] = STAT_IN
;
276 s
->rregs
[5] = INTR_DC
;
278 s
->espdmaregs
[0] |= DMA_INTR
;
279 pic_set_irq(s
->irq
, 1);
284 DPRINTF("Test Unit Ready (len %d)\n", buf
[5]);
287 DPRINTF("Inquiry (len %d)\n", buf
[5]);
288 memset(s
->ti_buf
, 0, 36);
289 if (bdrv_get_type_hint(s
->bd
[target
]) == BDRV_TYPE_CDROM
) {
291 memcpy(&s
->ti_buf
[16], "QEMU CDROM ", 16);
294 memcpy(&s
->ti_buf
[16], "QEMU HARDDISK ", 16);
296 memcpy(&s
->ti_buf
[8], "QEMU ", 8);
304 DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf
[3], buf
[5]);
307 DPRINTF("Read Capacity (len %d)\n", buf
[5]);
308 memset(s
->ti_buf
, 0, 8);
309 bdrv_get_geometry(s
->bd
[target
], &nb_sectors
);
310 s
->ti_buf
[0] = (nb_sectors
>> 24) & 0xff;
311 s
->ti_buf
[1] = (nb_sectors
>> 16) & 0xff;
312 s
->ti_buf
[2] = (nb_sectors
>> 8) & 0xff;
313 s
->ti_buf
[3] = nb_sectors
& 0xff;
316 if (bdrv_get_type_hint(s
->bd
[target
]) == BDRV_TYPE_CDROM
)
317 s
->ti_buf
[6] = 8; // sector size 2048
319 s
->ti_buf
[6] = 2; // sector size 512
328 if (bdrv_get_type_hint(s
->bd
[target
]) == BDRV_TYPE_CDROM
) {
329 offset
= ((buf
[3] << 24) | (buf
[4] << 16) | (buf
[5] << 8) | buf
[6]) * 4;
330 len
= ((buf
[8] << 8) | buf
[9]) * 4;
331 s
->ti_size
= len
* 2048;
333 offset
= (buf
[3] << 24) | (buf
[4] << 16) | (buf
[5] << 8) | buf
[6];
334 len
= (buf
[8] << 8) | buf
[9];
335 s
->ti_size
= len
* 512;
337 DPRINTF("Read (10) (offset %lld len %lld)\n", offset
, len
);
338 if (s
->ti_size
> TI_BUFSZ
) {
339 DPRINTF("size too large %d\n", s
->ti_size
);
341 bdrv_read(s
->bd
[target
], offset
, s
->ti_buf
, len
);
342 // XXX error handling
351 if (bdrv_get_type_hint(s
->bd
[target
]) == BDRV_TYPE_CDROM
) {
352 offset
= ((buf
[3] << 24) | (buf
[4] << 16) | (buf
[5] << 8) | buf
[6]) * 4;
353 len
= ((buf
[8] << 8) | buf
[9]) * 4;
354 s
->ti_size
= len
* 2048;
356 offset
= (buf
[3] << 24) | (buf
[4] << 16) | (buf
[5] << 8) | buf
[6];
357 len
= (buf
[8] << 8) | buf
[9];
358 s
->ti_size
= len
* 512;
360 DPRINTF("Write (10) (offset %lld len %lld)\n", offset
, len
);
361 if (s
->ti_size
> TI_BUFSZ
) {
362 DPRINTF("size too large %d\n", s
->ti_size
);
364 s
->dma_cb
= esp_write_dma_cb
;
369 // XXX error handling
375 int start_track
, format
, msf
, len
;
378 format
= buf
[3] & 0xf;
379 start_track
= buf
[7];
380 bdrv_get_geometry(s
->bd
[target
], &nb_sectors
);
381 DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track
, format
, msf
>> 1);
384 len
= cdrom_read_toc(nb_sectors
, buf
, msf
, start_track
);
390 /* multi session : only a single session defined */
398 len
= cdrom_read_toc_raw(nb_sectors
, buf
, msf
, start_track
);
405 DPRINTF("Read TOC error\n");
406 // XXX error handling
413 DPRINTF("Unknown SCSI command (%2.2x)\n", buf
[1]);
416 s
->rregs
[4] = STAT_IN
| STAT_TC
| STAT_DI
;
417 s
->rregs
[5] = INTR_BS
| INTR_FC
;
418 s
->rregs
[6] = SEQ_CD
;
419 s
->espdmaregs
[0] |= DMA_INTR
;
420 pic_set_irq(s
->irq
, 1);
423 static void dma_write(ESPState
*s
, const uint8_t *buf
, uint32_t len
)
427 DPRINTF("Transfer status len %d\n", len
);
429 dmaptr
= iommu_translate(s
->espdmaregs
[1]);
430 DPRINTF("DMA Direction: %c\n", s
->espdmaregs
[0] & 0x100? 'w': 'r');
431 cpu_physical_memory_write(dmaptr
, buf
, len
);
432 s
->rregs
[4] = STAT_IN
| STAT_TC
| STAT_ST
;
433 s
->rregs
[5] = INTR_BS
| INTR_FC
;
434 s
->rregs
[6] = SEQ_CD
;
436 memcpy(s
->ti_buf
, buf
, len
);
442 s
->espdmaregs
[0] |= DMA_INTR
;
443 pic_set_irq(s
->irq
, 1);
447 static const uint8_t okbuf
[] = {0, 0};
449 static void handle_ti(ESPState
*s
)
451 uint32_t dmaptr
, dmalen
, minlen
, len
, from
, to
;
454 dmalen
= s
->wregs
[0] | (s
->wregs
[1] << 8);
459 minlen
= (dmalen
< s
->ti_size
) ? dmalen
: s
->ti_size
;
460 DPRINTF("Transfer Information len %d\n", minlen
);
462 dmaptr
= iommu_translate(s
->espdmaregs
[1]);
463 DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x %d %d\n", s
->espdmaregs
[0] & 0x100? 'w': 'r', dmaptr
, s
->ti_size
, s
->ti_rptr
, s
->ti_dir
);
464 from
= s
->espdmaregs
[1];
466 for (i
= 0; i
< minlen
; i
+= len
, from
+= len
) {
467 dmaptr
= iommu_translate(s
->espdmaregs
[1] + i
);
468 if ((from
& TARGET_PAGE_MASK
) != (to
& TARGET_PAGE_MASK
)) {
469 len
= TARGET_PAGE_SIZE
- (from
& ~TARGET_PAGE_MASK
);
473 DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr
, s
->espdmaregs
[1] + i
, len
, from
, to
);
475 cpu_physical_memory_write(dmaptr
, &s
->ti_buf
[s
->ti_rptr
+ i
], len
);
477 cpu_physical_memory_read(dmaptr
, &s
->ti_buf
[s
->ti_rptr
+ i
], len
);
480 s
->dma_cb(s
, s
->espdmaregs
[1], minlen
);
482 if (minlen
< s
->ti_size
) {
483 s
->rregs
[4] = STAT_IN
| STAT_TC
| (s
->ti_dir
? STAT_DO
: STAT_DI
);
484 s
->ti_size
-= minlen
;
485 s
->ti_rptr
+= minlen
;
487 s
->rregs
[4] = STAT_IN
| STAT_TC
| STAT_ST
;
494 s
->rregs
[5] = INTR_BS
;
497 s
->espdmaregs
[0] |= DMA_INTR
;
502 s
->rregs
[7] = minlen
;
504 pic_set_irq(s
->irq
, 1);
507 static void esp_reset(void *opaque
)
509 ESPState
*s
= opaque
;
510 memset(s
->rregs
, 0, ESP_MAXREG
);
511 memset(s
->wregs
, 0, ESP_MAXREG
);
512 s
->rregs
[0x0e] = 0x4; // Indicate fas100a
513 memset(s
->espdmaregs
, 0, ESPDMA_REGS
* 4);
522 static uint32_t esp_mem_readb(void *opaque
, target_phys_addr_t addr
)
524 ESPState
*s
= opaque
;
527 saddr
= (addr
& ESP_MAXREG
) >> 2;
528 DPRINTF("read reg[%d]: 0x%2.2x\n", saddr
, s
->rregs
[saddr
]);
532 if (s
->ti_size
> 0) {
534 s
->rregs
[saddr
] = s
->ti_buf
[s
->ti_rptr
++];
535 pic_set_irq(s
->irq
, 1);
537 if (s
->ti_size
== 0) {
544 // Clear status bits except TC
545 s
->rregs
[4] &= STAT_TC
;
546 pic_set_irq(s
->irq
, 0);
547 s
->espdmaregs
[0] &= ~DMA_INTR
;
552 return s
->rregs
[saddr
];
555 static void esp_mem_writeb(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
557 ESPState
*s
= opaque
;
560 saddr
= (addr
& ESP_MAXREG
) >> 2;
561 DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr
, s
->wregs
[saddr
], val
);
565 s
->rregs
[saddr
] = val
;
570 s
->ti_buf
[s
->ti_wptr
++] = val
& 0xff;
573 s
->rregs
[saddr
] = val
;
582 DPRINTF("NOP (%2.2x)\n", val
);
585 DPRINTF("Flush FIFO (%2.2x)\n", val
);
587 s
->rregs
[5] = INTR_FC
;
591 DPRINTF("Chip reset (%2.2x)\n", val
);
595 DPRINTF("Bus reset (%2.2x)\n", val
);
596 s
->rregs
[5] = INTR_RST
;
597 if (!(s
->wregs
[8] & 0x40)) {
598 s
->espdmaregs
[0] |= DMA_INTR
;
599 pic_set_irq(s
->irq
, 1);
606 DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val
);
607 dma_write(s
, okbuf
, 2);
610 DPRINTF("Message Accepted (%2.2x)\n", val
);
611 dma_write(s
, okbuf
, 2);
612 s
->rregs
[5] = INTR_DC
;
616 DPRINTF("Set ATN (%2.2x)\n", val
);
622 DPRINTF("Set ATN & stop (%2.2x)\n", val
);
626 DPRINTF("Unhandled ESP command (%2.2x)\n", val
);
633 s
->rregs
[saddr
] = val
;
638 s
->rregs
[saddr
] = val
& 0x15;
641 s
->rregs
[saddr
] = val
;
646 s
->wregs
[saddr
] = val
;
649 static CPUReadMemoryFunc
*esp_mem_read
[3] = {
655 static CPUWriteMemoryFunc
*esp_mem_write
[3] = {
661 static uint32_t espdma_mem_readl(void *opaque
, target_phys_addr_t addr
)
663 ESPState
*s
= opaque
;
666 saddr
= (addr
& ESPDMA_MAXADDR
) >> 2;
667 DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr
, s
->espdmaregs
[saddr
]);
669 return s
->espdmaregs
[saddr
];
672 static void espdma_mem_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
674 ESPState
*s
= opaque
;
677 saddr
= (addr
& ESPDMA_MAXADDR
) >> 2;
678 DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr
, s
->espdmaregs
[saddr
], val
);
681 if (!(val
& DMA_INTREN
))
682 pic_set_irq(s
->irq
, 0);
685 } else if (val
& 0x40) {
693 s
->espdmaregs
[0] |= DMA_LOADED
;
698 s
->espdmaregs
[saddr
] = val
;
701 static CPUReadMemoryFunc
*espdma_mem_read
[3] = {
707 static CPUWriteMemoryFunc
*espdma_mem_write
[3] = {
713 static void esp_save(QEMUFile
*f
, void *opaque
)
715 ESPState
*s
= opaque
;
718 qemu_put_buffer(f
, s
->rregs
, ESP_MAXREG
);
719 qemu_put_buffer(f
, s
->wregs
, ESP_MAXREG
);
720 qemu_put_be32s(f
, &s
->irq
);
721 for (i
= 0; i
< ESPDMA_REGS
; i
++)
722 qemu_put_be32s(f
, &s
->espdmaregs
[i
]);
723 qemu_put_be32s(f
, &s
->ti_size
);
724 qemu_put_be32s(f
, &s
->ti_rptr
);
725 qemu_put_be32s(f
, &s
->ti_wptr
);
726 qemu_put_be32s(f
, &s
->ti_dir
);
727 qemu_put_buffer(f
, s
->ti_buf
, TI_BUFSZ
);
728 qemu_put_be32s(f
, &s
->dma
);
731 static int esp_load(QEMUFile
*f
, void *opaque
, int version_id
)
733 ESPState
*s
= opaque
;
739 qemu_get_buffer(f
, s
->rregs
, ESP_MAXREG
);
740 qemu_get_buffer(f
, s
->wregs
, ESP_MAXREG
);
741 qemu_get_be32s(f
, &s
->irq
);
742 for (i
= 0; i
< ESPDMA_REGS
; i
++)
743 qemu_get_be32s(f
, &s
->espdmaregs
[i
]);
744 qemu_get_be32s(f
, &s
->ti_size
);
745 qemu_get_be32s(f
, &s
->ti_rptr
);
746 qemu_get_be32s(f
, &s
->ti_wptr
);
747 qemu_get_be32s(f
, &s
->ti_dir
);
748 qemu_get_buffer(f
, s
->ti_buf
, TI_BUFSZ
);
749 qemu_get_be32s(f
, &s
->dma
);
754 void esp_init(BlockDriverState
**bd
, int irq
, uint32_t espaddr
, uint32_t espdaddr
)
757 int esp_io_memory
, espdma_io_memory
;
759 s
= qemu_mallocz(sizeof(ESPState
));
766 esp_io_memory
= cpu_register_io_memory(0, esp_mem_read
, esp_mem_write
, s
);
767 cpu_register_physical_memory(espaddr
, ESP_MAXREG
*4, esp_io_memory
);
769 espdma_io_memory
= cpu_register_io_memory(0, espdma_mem_read
, espdma_mem_write
, s
);
770 cpu_register_physical_memory(espdaddr
, 16, espdma_io_memory
);
774 register_savevm("esp", espaddr
, 1, esp_save
, esp_load
, s
);
775 qemu_register_reset(esp_reset
, s
);