Annotation of qemu/hw/esp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU ESP emulation
        !             3:  * 
        !             4:  * Copyright (c) 2005 Fabrice Bellard
        !             5:  * 
        !             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:
        !            12:  *
        !            13:  * The above copyright notice and this permission notice shall be included in
        !            14:  * all copies or substantial portions of the Software.
        !            15:  *
        !            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
        !            22:  * THE SOFTWARE.
        !            23:  */
        !            24: #include "vl.h"
        !            25: 
        !            26: /* debug ESP card */
        !            27: //#define DEBUG_ESP
        !            28: 
        !            29: #ifdef DEBUG_ESP
        !            30: #define DPRINTF(fmt, args...) \
        !            31: do { printf("ESP: " fmt , ##args); } while (0)
        !            32: #else
        !            33: #define DPRINTF(fmt, args...)
        !            34: #endif
        !            35: 
        !            36: #define ESPDMA_REGS 4
        !            37: #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
        !            38: #define ESP_MAXREG 0x3f
        !            39: 
        !            40: typedef struct ESPState {
        !            41:     BlockDriverState **bd;
        !            42:     uint8_t rregs[ESP_MAXREG];
        !            43:     uint8_t wregs[ESP_MAXREG];
        !            44:     int irq;
        !            45:     uint32_t espdmaregs[ESPDMA_REGS];
        !            46:     uint32_t ti_size;
        !            47:     int ti_dir;
        !            48:     uint8_t ti_buf[65536];
        !            49: } ESPState;
        !            50: 
        !            51: #define STAT_DO 0x00
        !            52: #define STAT_DI 0x01
        !            53: #define STAT_CD 0x02
        !            54: #define STAT_ST 0x03
        !            55: #define STAT_MI 0x06
        !            56: #define STAT_MO 0x07
        !            57: 
        !            58: #define STAT_TC 0x10
        !            59: #define STAT_IN 0x80
        !            60: 
        !            61: #define INTR_FC 0x08
        !            62: #define INTR_BS 0x10
        !            63: #define INTR_DC 0x20
        !            64: 
        !            65: #define SEQ_0 0x0
        !            66: #define SEQ_CD 0x4
        !            67: 
        !            68: static void handle_satn(ESPState *s)
        !            69: {
        !            70:     uint8_t buf[32];
        !            71:     uint32_t dmaptr, dmalen;
        !            72:     unsigned int i;
        !            73:     int64_t nb_sectors;
        !            74:     int target;
        !            75: 
        !            76:     dmaptr = iommu_translate(s->espdmaregs[1]);
        !            77:     dmalen = s->wregs[0] | (s->wregs[1] << 8);
        !            78:     DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen);
        !            79:     DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
        !            80:     cpu_physical_memory_read(dmaptr, buf, dmalen);
        !            81:     for (i = 0; i < dmalen; i++) {
        !            82:        DPRINTF("Command %2.2x\n", buf[i]);
        !            83:     }
        !            84:     s->ti_dir = 0;
        !            85:     s->ti_size = 0;
        !            86:     target = s->wregs[4] & 7;
        !            87: 
        !            88:     if (target > 4 || !s->bd[target]) { // No such drive
        !            89:        s->rregs[4] = STAT_IN;
        !            90:        s->rregs[5] = INTR_DC;
        !            91:        s->rregs[6] = SEQ_0;
        !            92:        s->espdmaregs[0] |= 1;
        !            93:        pic_set_irq(s->irq, 1);
        !            94:        return;
        !            95:     }
        !            96:     switch (buf[1]) {
        !            97:     case 0x0:
        !            98:        DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
        !            99:        break;
        !           100:     case 0x12:
        !           101:        DPRINTF("Inquiry (len %d)\n", buf[5]);
        !           102:        memset(s->ti_buf, 0, 36);
        !           103:        if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
        !           104:            s->ti_buf[0] = 5;
        !           105:            memcpy(&s->ti_buf[16], "QEMU CDROM     ", 16);
        !           106:        } else {
        !           107:            s->ti_buf[0] = 0;
        !           108:            memcpy(&s->ti_buf[16], "QEMU HARDDISK  ", 16);
        !           109:        }
        !           110:        memcpy(&s->ti_buf[8], "QEMU   ", 8);
        !           111:        s->ti_buf[2] = 1;
        !           112:        s->ti_buf[3] = 2;
        !           113:        s->ti_dir = 1;
        !           114:        s->ti_size = 36;
        !           115:        break;
        !           116:     case 0x1a:
        !           117:        DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
        !           118:        break;
        !           119:     case 0x25:
        !           120:        DPRINTF("Read Capacity (len %d)\n", buf[5]);
        !           121:        memset(s->ti_buf, 0, 8);
        !           122:        bdrv_get_geometry(s->bd[target], &nb_sectors);
        !           123:        s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
        !           124:        s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
        !           125:        s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
        !           126:        s->ti_buf[3] = nb_sectors & 0xff;
        !           127:        s->ti_buf[4] = 0;
        !           128:        s->ti_buf[5] = 0;
        !           129:        s->ti_buf[6] = 2;
        !           130:        s->ti_buf[7] = 0;
        !           131:        s->ti_dir = 1;
        !           132:        s->ti_size = 8;
        !           133:        break;
        !           134:     case 0x28:
        !           135:        {
        !           136:            int64_t offset, len;
        !           137: 
        !           138:            offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
        !           139:            len = (buf[8] << 8) | buf[9];
        !           140:            DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
        !           141:            bdrv_read(s->bd[target], offset, s->ti_buf, len);
        !           142:            s->ti_dir = 1;
        !           143:            s->ti_size = len * 512;
        !           144:            break;
        !           145:        }
        !           146:     case 0x2a:
        !           147:        {
        !           148:            int64_t offset, len;
        !           149: 
        !           150:            offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
        !           151:            len = (buf[8] << 8) | buf[9];
        !           152:            DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
        !           153:            bdrv_write(s->bd[target], offset, s->ti_buf, len);
        !           154:            s->ti_dir = 0;
        !           155:            s->ti_size = len * 512;
        !           156:            break;
        !           157:        }
        !           158:     default:
        !           159:        DPRINTF("Unknown command (%2.2x)\n", buf[1]);
        !           160:        break;
        !           161:     }
        !           162:     s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
        !           163:     s->rregs[5] = INTR_BS | INTR_FC;
        !           164:     s->rregs[6] = SEQ_CD;
        !           165:     s->espdmaregs[0] |= 1;
        !           166:     pic_set_irq(s->irq, 1);
        !           167: }
        !           168: 
        !           169: static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
        !           170: {
        !           171:     uint32_t dmaptr, dmalen;
        !           172: 
        !           173:     dmaptr = iommu_translate(s->espdmaregs[1]);
        !           174:     dmalen = s->wregs[0] | (s->wregs[1] << 8);
        !           175:     DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
        !           176:     cpu_physical_memory_write(dmaptr, buf, len);
        !           177:     s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
        !           178:     s->rregs[5] = INTR_BS | INTR_FC;
        !           179:     s->rregs[6] = SEQ_CD;
        !           180:     s->espdmaregs[0] |= 1;
        !           181:     pic_set_irq(s->irq, 1);
        !           182: 
        !           183: }
        !           184: static const uint8_t okbuf[] = {0, 0};
        !           185: 
        !           186: static void handle_ti(ESPState *s)
        !           187: {
        !           188:     uint32_t dmaptr, dmalen;
        !           189:     unsigned int i;
        !           190: 
        !           191:     dmaptr = iommu_translate(s->espdmaregs[1]);
        !           192:     dmalen = s->wregs[0] | (s->wregs[1] << 8);
        !           193:     DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen);
        !           194:     DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
        !           195:     for (i = 0; i < s->ti_size; i++) {
        !           196:        dmaptr = iommu_translate(s->espdmaregs[1] + i);
        !           197:        if (s->ti_dir)
        !           198:            cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
        !           199:        else
        !           200:            cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
        !           201:     }
        !           202:     s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
        !           203:     s->rregs[5] = INTR_BS;
        !           204:     s->rregs[6] = 0;
        !           205:     s->espdmaregs[0] |= 1;
        !           206:     pic_set_irq(s->irq, 1);
        !           207: }
        !           208: 
        !           209: static void esp_reset(void *opaque)
        !           210: {
        !           211:     ESPState *s = opaque;
        !           212:     memset(s->rregs, 0, ESP_MAXREG);
        !           213:     s->rregs[0x0e] = 0x4; // Indicate fas100a
        !           214:     memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
        !           215: }
        !           216: 
        !           217: static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
        !           218: {
        !           219:     ESPState *s = opaque;
        !           220:     uint32_t saddr;
        !           221: 
        !           222:     saddr = (addr & ESP_MAXREG) >> 2;
        !           223:     switch (saddr) {
        !           224:     default:
        !           225:        break;
        !           226:     }
        !           227:     DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
        !           228:     return s->rregs[saddr];
        !           229: }
        !           230: 
        !           231: static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
        !           232: {
        !           233:     ESPState *s = opaque;
        !           234:     uint32_t saddr;
        !           235: 
        !           236:     saddr = (addr & ESP_MAXREG) >> 2;
        !           237:     DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
        !           238:     switch (saddr) {
        !           239:     case 3:
        !           240:        // Command
        !           241:        switch(val & 0x7f) {
        !           242:        case 0:
        !           243:            DPRINTF("NOP (%2.2x)\n", val);
        !           244:            break;
        !           245:        case 1:
        !           246:            DPRINTF("Flush FIFO (%2.2x)\n", val);
        !           247:            s->rregs[6] = 0;
        !           248:            s->rregs[5] = INTR_FC;
        !           249:            break;
        !           250:        case 2:
        !           251:            DPRINTF("Chip reset (%2.2x)\n", val);
        !           252:            esp_reset(s);
        !           253:            break;
        !           254:        case 3:
        !           255:            DPRINTF("Bus reset (%2.2x)\n", val);
        !           256:            break;
        !           257:        case 0x10:
        !           258:            handle_ti(s);
        !           259:            break;
        !           260:        case 0x11:
        !           261:            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
        !           262:            dma_write(s, okbuf, 2);
        !           263:            break;
        !           264:        case 0x12:
        !           265:            DPRINTF("Message Accepted (%2.2x)\n", val);
        !           266:            dma_write(s, okbuf, 2);
        !           267:            s->rregs[5] = INTR_DC;
        !           268:            s->rregs[6] = 0;
        !           269:            break;
        !           270:        case 0x1a:
        !           271:            DPRINTF("Set ATN (%2.2x)\n", val);
        !           272:            break;
        !           273:        case 0x42:
        !           274:            handle_satn(s);
        !           275:            break;
        !           276:        case 0x43:
        !           277:            DPRINTF("Set ATN & stop (%2.2x)\n", val);
        !           278:            handle_satn(s);
        !           279:            break;
        !           280:        default:
        !           281:            DPRINTF("Unhandled command (%2.2x)\n", val);
        !           282:            break;
        !           283:        }
        !           284:        break;
        !           285:     case 4 ... 7:
        !           286:     case 9 ... 0xf:
        !           287:        break;
        !           288:     default:
        !           289:        break;
        !           290:     }
        !           291:     s->wregs[saddr] = val;
        !           292: }
        !           293: 
        !           294: static CPUReadMemoryFunc *esp_mem_read[3] = {
        !           295:     esp_mem_readb,
        !           296:     esp_mem_readb,
        !           297:     esp_mem_readb,
        !           298: };
        !           299: 
        !           300: static CPUWriteMemoryFunc *esp_mem_write[3] = {
        !           301:     esp_mem_writeb,
        !           302:     esp_mem_writeb,
        !           303:     esp_mem_writeb,
        !           304: };
        !           305: 
        !           306: static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
        !           307: {
        !           308:     ESPState *s = opaque;
        !           309:     uint32_t saddr;
        !           310: 
        !           311:     saddr = (addr & ESPDMA_MAXADDR) >> 2;
        !           312:     DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]);
        !           313:     return s->espdmaregs[saddr];
        !           314: }
        !           315: 
        !           316: static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
        !           317: {
        !           318:     ESPState *s = opaque;
        !           319:     uint32_t saddr;
        !           320: 
        !           321:     saddr = (addr & ESPDMA_MAXADDR) >> 2;
        !           322:     DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val);
        !           323:     switch (saddr) {
        !           324:     case 0:
        !           325:        if (!(val & 0x10))
        !           326:            pic_set_irq(s->irq, 0);
        !           327:        break;
        !           328:     default:
        !           329:        break;
        !           330:     }
        !           331:     s->espdmaregs[saddr] = val;
        !           332: }
        !           333: 
        !           334: static CPUReadMemoryFunc *espdma_mem_read[3] = {
        !           335:     espdma_mem_readl,
        !           336:     espdma_mem_readl,
        !           337:     espdma_mem_readl,
        !           338: };
        !           339: 
        !           340: static CPUWriteMemoryFunc *espdma_mem_write[3] = {
        !           341:     espdma_mem_writel,
        !           342:     espdma_mem_writel,
        !           343:     espdma_mem_writel,
        !           344: };
        !           345: 
        !           346: static void esp_save(QEMUFile *f, void *opaque)
        !           347: {
        !           348:     ESPState *s = opaque;
        !           349:     unsigned int i;
        !           350: 
        !           351:     qemu_put_buffer(f, s->rregs, ESP_MAXREG);
        !           352:     qemu_put_buffer(f, s->wregs, ESP_MAXREG);
        !           353:     qemu_put_be32s(f, &s->irq);
        !           354:     for (i = 0; i < ESPDMA_REGS; i++)
        !           355:        qemu_put_be32s(f, &s->espdmaregs[i]);
        !           356: }
        !           357: 
        !           358: static int esp_load(QEMUFile *f, void *opaque, int version_id)
        !           359: {
        !           360:     ESPState *s = opaque;
        !           361:     unsigned int i;
        !           362:     
        !           363:     if (version_id != 1)
        !           364:         return -EINVAL;
        !           365: 
        !           366:     qemu_get_buffer(f, s->rregs, ESP_MAXREG);
        !           367:     qemu_get_buffer(f, s->wregs, ESP_MAXREG);
        !           368:     qemu_get_be32s(f, &s->irq);
        !           369:     for (i = 0; i < ESPDMA_REGS; i++)
        !           370:        qemu_get_be32s(f, &s->espdmaregs[i]);
        !           371: 
        !           372:     return 0;
        !           373: }
        !           374: 
        !           375: void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
        !           376: {
        !           377:     ESPState *s;
        !           378:     int esp_io_memory, espdma_io_memory;
        !           379: 
        !           380:     s = qemu_mallocz(sizeof(ESPState));
        !           381:     if (!s)
        !           382:         return;
        !           383: 
        !           384:     s->bd = bd;
        !           385:     s->irq = irq;
        !           386: 
        !           387:     esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
        !           388:     cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
        !           389: 
        !           390:     espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
        !           391:     cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
        !           392: 
        !           393:     esp_reset(s);
        !           394: 
        !           395:     register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
        !           396:     qemu_register_reset(esp_reset, s);
        !           397: }
        !           398: 

unix.superglobalmegacorp.com