📄 esp.c
字号:
/* * QEMU ESP emulation * * Copyright (c) 2005-2006 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "vl.h"/* debug ESP card *///#define DEBUG_ESP#ifdef DEBUG_ESP#define DPRINTF(fmt, args...) \do { printf("ESP: " fmt , ##args); } while (0)#define pic_set_irq(irq, level) \do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)#else#define DPRINTF(fmt, args...)#endif#define ESPDMA_REGS 4#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)#define ESP_MAXREG 0x3f#define TI_BUFSZ 1024*1024 // XXX#define DMA_VER 0xa0000000#define DMA_INTR 1#define DMA_INTREN 0x10#define DMA_LOADED 0x04000000typedef struct ESPState ESPState;typedef int ESPDMAFunc(ESPState *s, target_phys_addr_t phys_addr, int transfer_size1);struct ESPState { BlockDriverState **bd; uint8_t rregs[ESP_MAXREG]; uint8_t wregs[ESP_MAXREG]; int irq; uint32_t espdmaregs[ESPDMA_REGS]; uint32_t ti_size; uint32_t ti_rptr, ti_wptr; int ti_dir; uint8_t ti_buf[TI_BUFSZ]; int dma; ESPDMAFunc *dma_cb; int64_t offset, len; int target;};#define STAT_DO 0x00#define STAT_DI 0x01#define STAT_CD 0x02#define STAT_ST 0x03#define STAT_MI 0x06#define STAT_MO 0x07#define STAT_TC 0x10#define STAT_IN 0x80#define INTR_FC 0x08#define INTR_BS 0x10#define INTR_DC 0x20#define INTR_RST 0x80#define SEQ_0 0x0#define SEQ_CD 0x4/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */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 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;}/* same toc as bochs. Return -1 if error or the toc length *//* XXX: check this */static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track){ uint8_t *q; int 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 */ 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(int nb_sectors, uint8_t *buf, int msf, int session_num){ uint8_t *q; int 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 */ 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 int esp_write_dma_cb(ESPState *s, target_phys_addr_t phys_addr, int transfer_size1){ DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", s->offset, s->len, s->ti_size, transfer_size1); bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len); s->offset = 0; s->len = 0; s->target = 0; return 0;}static void handle_satn(ESPState *s){ uint8_t buf[32]; uint32_t dmaptr, dmalen; unsigned int i; int64_t nb_sectors; int target; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; DPRINTF("Select with ATN len %d target %d\n", dmalen, target); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); cpu_physical_memory_read(dmaptr, buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); dmalen++; } for (i = 0; i < dmalen; i++) { DPRINTF("Command %2.2x\n", buf[i]); } s->ti_dir = 0; s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; if (target >= 4 || !s->bd[target]) { // No such drive s->rregs[4] = STAT_IN; s->rregs[5] = INTR_DC; s->rregs[6] = SEQ_0; s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); return; } switch (buf[1]) { case 0x0: DPRINTF("Test Unit Ready (len %d)\n", buf[5]); break; case 0x12: DPRINTF("Inquiry (len %d)\n", buf[5]); memset(s->ti_buf, 0, 36); if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { s->ti_buf[0] = 5; memcpy(&s->ti_buf[16], "QEMU CDROM ", 16); } else { s->ti_buf[0] = 0; memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16); } memcpy(&s->ti_buf[8], "QEMU ", 8); s->ti_buf[2] = 1; s->ti_buf[3] = 2; s->ti_buf[4] = 32; s->ti_dir = 1; s->ti_size = 36; break; case 0x1a: DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]); break; case 0x25: DPRINTF("Read Capacity (len %d)\n", buf[5]); memset(s->ti_buf, 0, 8); bdrv_get_geometry(s->bd[target], &nb_sectors); s->ti_buf[0] = (nb_sectors >> 24) & 0xff; s->ti_buf[1] = (nb_sectors >> 16) & 0xff; s->ti_buf[2] = (nb_sectors >> 8) & 0xff; s->ti_buf[3] = nb_sectors & 0xff; s->ti_buf[4] = 0; s->ti_buf[5] = 0; if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) s->ti_buf[6] = 8; // sector size 2048 else s->ti_buf[6] = 2; // sector size 512 s->ti_buf[7] = 0; s->ti_dir = 1; s->ti_size = 8; break; case 0x28: { int64_t offset, len; if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; len = ((buf[8] << 8) | buf[9]) * 4; s->ti_size = len * 2048; } else { offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; len = (buf[8] << 8) | buf[9]; s->ti_size = len * 512; } DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); if (s->ti_size > TI_BUFSZ) { DPRINTF("size too large %d\n", s->ti_size); } bdrv_read(s->bd[target], offset, s->ti_buf, len); // XXX error handling s->ti_dir = 1; break; } case 0x2a: { int64_t offset, len; if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; len = ((buf[8] << 8) | buf[9]) * 4; s->ti_size = len * 2048; } else { offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; len = (buf[8] << 8) | buf[9]; s->ti_size = len * 512; } DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); if (s->ti_size > TI_BUFSZ) { DPRINTF("size too large %d\n", s->ti_size); } s->dma_cb = esp_write_dma_cb; s->offset = offset; s->len = len; s->target = target; // XXX error handling s->ti_dir = 0; break; } case 0x43: { int start_track, format, msf, len; msf = buf[2] & 2; format = buf[3] & 0xf; start_track = buf[7]; bdrv_get_geometry(s->bd[target], &nb_sectors); DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -