Annotation of qemu/hw/dma.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * QEMU DMA emulation
                      3:  *
                      4:  * Copyright (c) 2003-2004 Vassili Karpov (malc)
                      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: /* #define DEBUG_DMA */
                     27: 
                     28: #define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
                     29: #ifdef DEBUG_DMA
                     30: #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
                     31: #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
                     32: #define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
                     33: #else
                     34: #define lwarn(...)
                     35: #define linfo(...)
                     36: #define ldebug(...)
                     37: #endif
                     38: 
                     39: #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
                     40: 
                     41: struct dma_regs {
                     42:     int now[2];
                     43:     uint16_t base[2];
                     44:     uint8_t mode;
                     45:     uint8_t page;
                     46:     uint8_t pageh;
                     47:     uint8_t dack;
                     48:     uint8_t eop;
                     49:     DMA_transfer_handler transfer_handler;
                     50:     void *opaque;
                     51: };
                     52: 
                     53: #define ADDR 0
                     54: #define COUNT 1
                     55: 
                     56: static struct dma_cont {
                     57:     uint8_t status;
                     58:     uint8_t command;
                     59:     uint8_t mask;
                     60:     uint8_t flip_flop;
                     61:     int dshift;
                     62:     struct dma_regs regs[4];
                     63: } dma_controllers[2];
                     64: 
                     65: enum {
                     66:     CMD_MEMORY_TO_MEMORY = 0x01,
                     67:     CMD_FIXED_ADDRESS    = 0x02,
                     68:     CMD_BLOCK_CONTROLLER = 0x04,
                     69:     CMD_COMPRESSED_TIME  = 0x08,
                     70:     CMD_CYCLIC_PRIORITY  = 0x10,
                     71:     CMD_EXTENDED_WRITE   = 0x20,
                     72:     CMD_LOW_DREQ         = 0x40,
                     73:     CMD_LOW_DACK         = 0x80,
                     74:     CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
                     75:     | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
                     76:     | CMD_LOW_DREQ | CMD_LOW_DACK
                     77: 
                     78: };
                     79: 
                     80: static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
                     81: 
                     82: static void write_page (void *opaque, uint32_t nport, uint32_t data)
                     83: {
                     84:     struct dma_cont *d = opaque;
                     85:     int ichan;
                     86: 
                     87:     ichan = channels[nport & 7];
                     88:     if (-1 == ichan) {
                     89:         dolog ("invalid channel %#x %#x\n", nport, data);
                     90:         return;
                     91:     }
                     92:     d->regs[ichan].page = data;
                     93: }
                     94: 
                     95: static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
                     96: {
                     97:     struct dma_cont *d = opaque;
                     98:     int ichan;
                     99: 
                    100:     ichan = channels[nport & 7];
                    101:     if (-1 == ichan) {
                    102:         dolog ("invalid channel %#x %#x\n", nport, data);
                    103:         return;
                    104:     }
                    105:     d->regs[ichan].pageh = data;
                    106: }
                    107: 
                    108: static uint32_t read_page (void *opaque, uint32_t nport)
                    109: {
                    110:     struct dma_cont *d = opaque;
                    111:     int ichan;
                    112: 
                    113:     ichan = channels[nport & 7];
                    114:     if (-1 == ichan) {
                    115:         dolog ("invalid channel read %#x\n", nport);
                    116:         return 0;
                    117:     }
                    118:     return d->regs[ichan].page;
                    119: }
                    120: 
                    121: static uint32_t read_pageh (void *opaque, uint32_t nport)
                    122: {
                    123:     struct dma_cont *d = opaque;
                    124:     int ichan;
                    125: 
                    126:     ichan = channels[nport & 7];
                    127:     if (-1 == ichan) {
                    128:         dolog ("invalid channel read %#x\n", nport);
                    129:         return 0;
                    130:     }
                    131:     return d->regs[ichan].pageh;
                    132: }
                    133: 
                    134: static inline void init_chan (struct dma_cont *d, int ichan)
                    135: {
                    136:     struct dma_regs *r;
                    137: 
                    138:     r = d->regs + ichan;
                    139:     r->now[ADDR] = r->base[ADDR] << d->dshift;
                    140:     r->now[COUNT] = 0;
                    141: }
                    142: 
                    143: static inline int getff (struct dma_cont *d)
                    144: {
                    145:     int ff;
                    146: 
                    147:     ff = d->flip_flop;
                    148:     d->flip_flop = !ff;
                    149:     return ff;
                    150: }
                    151: 
                    152: static uint32_t read_chan (void *opaque, uint32_t nport)
                    153: {
                    154:     struct dma_cont *d = opaque;
                    155:     int ichan, nreg, iport, ff, val, dir;
                    156:     struct dma_regs *r;
                    157: 
                    158:     iport = (nport >> d->dshift) & 0x0f;
                    159:     ichan = iport >> 1;
                    160:     nreg = iport & 1;
                    161:     r = d->regs + ichan;
                    162: 
                    163:     dir = ((r->mode >> 5) & 1) ? -1 : 1;
                    164:     ff = getff (d);
                    165:     if (nreg)
                    166:         val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
                    167:     else
                    168:         val = r->now[ADDR] + r->now[COUNT] * dir;
                    169: 
                    170:     ldebug ("read_chan %#x -> %d\n", iport, val);
                    171:     return (val >> (d->dshift + (ff << 3))) & 0xff;
                    172: }
                    173: 
                    174: static void write_chan (void *opaque, uint32_t nport, uint32_t data)
                    175: {
                    176:     struct dma_cont *d = opaque;
                    177:     int iport, ichan, nreg;
                    178:     struct dma_regs *r;
                    179: 
                    180:     iport = (nport >> d->dshift) & 0x0f;
                    181:     ichan = iport >> 1;
                    182:     nreg = iport & 1;
                    183:     r = d->regs + ichan;
                    184:     if (getff (d)) {
                    185:         r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
                    186:         init_chan (d, ichan);
                    187:     } else {
                    188:         r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
                    189:     }
                    190: }
                    191: 
                    192: static void write_cont (void *opaque, uint32_t nport, uint32_t data)
                    193: {
                    194:     struct dma_cont *d = opaque;
                    195:     int iport, ichan = 0;
                    196: 
                    197:     iport = (nport >> d->dshift) & 0x0f;
                    198:     switch (iport) {
                    199:     case 0x08:                  /* command */
                    200:         if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
                    201:             dolog ("command %#x not supported\n", data);
                    202:             return;
                    203:         }
                    204:         d->command = data;
                    205:         break;
                    206: 
                    207:     case 0x09:
                    208:         ichan = data & 3;
                    209:         if (data & 4) {
                    210:             d->status |= 1 << (ichan + 4);
                    211:         }
                    212:         else {
                    213:             d->status &= ~(1 << (ichan + 4));
                    214:         }
                    215:         d->status &= ~(1 << ichan);
                    216:         break;
                    217: 
                    218:     case 0x0a:                  /* single mask */
                    219:         if (data & 4)
                    220:             d->mask |= 1 << (data & 3);
                    221:         else
                    222:             d->mask &= ~(1 << (data & 3));
                    223:         break;
                    224: 
                    225:     case 0x0b:                  /* mode */
                    226:         {
                    227:             ichan = data & 3;
                    228: #ifdef DEBUG_DMA
                    229:             {
                    230:                 int op, ai, dir, opmode;
                    231:                 op = (data >> 2) & 3;
                    232:                 ai = (data >> 4) & 1;
                    233:                 dir = (data >> 5) & 1;
                    234:                 opmode = (data >> 6) & 3;
                    235: 
                    236:                 linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
                    237:                        ichan, op, ai, dir, opmode);
                    238:             }
                    239: #endif
                    240:             d->regs[ichan].mode = data;
                    241:             break;
                    242:         }
                    243: 
                    244:     case 0x0c:                  /* clear flip flop */
                    245:         d->flip_flop = 0;
                    246:         break;
                    247: 
                    248:     case 0x0d:                  /* reset */
                    249:         d->flip_flop = 0;
                    250:         d->mask = ~0;
                    251:         d->status = 0;
                    252:         d->command = 0;
                    253:         break;
                    254: 
                    255:     case 0x0e:                  /* clear mask for all channels */
                    256:         d->mask = 0;
                    257:         break;
                    258: 
                    259:     case 0x0f:                  /* write mask for all channels */
                    260:         d->mask = data;
                    261:         break;
                    262: 
                    263:     default:
                    264:         dolog ("unknown iport %#x\n", iport);
                    265:         break;
                    266:     }
                    267: 
                    268: #ifdef DEBUG_DMA
                    269:     if (0xc != iport) {
                    270:         linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
                    271:                nport, ichan, data);
                    272:     }
                    273: #endif
                    274: }
                    275: 
                    276: static uint32_t read_cont (void *opaque, uint32_t nport)
                    277: {
                    278:     struct dma_cont *d = opaque;
                    279:     int iport, val;
                    280: 
                    281:     iport = (nport >> d->dshift) & 0x0f;
                    282:     switch (iport) {
                    283:     case 0x08:                  /* status */
                    284:         val = d->status;
                    285:         d->status &= 0xf0;
                    286:         break;
                    287:     case 0x0f:                  /* mask */
                    288:         val = d->mask;
                    289:         break;
                    290:     default:
                    291:         val = 0;
                    292:         break;
                    293:     }
                    294: 
                    295:     ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
                    296:     return val;
                    297: }
                    298: 
                    299: int DMA_get_channel_mode (int nchan)
                    300: {
                    301:     return dma_controllers[nchan > 3].regs[nchan & 3].mode;
                    302: }
                    303: 
                    304: void DMA_hold_DREQ (int nchan)
                    305: {
                    306:     int ncont, ichan;
                    307: 
                    308:     ncont = nchan > 3;
                    309:     ichan = nchan & 3;
                    310:     linfo ("held cont=%d chan=%d\n", ncont, ichan);
                    311:     dma_controllers[ncont].status |= 1 << (ichan + 4);
                    312: }
                    313: 
                    314: void DMA_release_DREQ (int nchan)
                    315: {
                    316:     int ncont, ichan;
                    317: 
                    318:     ncont = nchan > 3;
                    319:     ichan = nchan & 3;
                    320:     linfo ("released cont=%d chan=%d\n", ncont, ichan);
                    321:     dma_controllers[ncont].status &= ~(1 << (ichan + 4));
                    322: }
                    323: 
                    324: static void channel_run (int ncont, int ichan)
                    325: {
                    326:     int n;
                    327:     struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
                    328: #ifdef DEBUG_DMA
                    329:     int dir, opmode;
                    330: 
                    331:     dir = (r->mode >> 5) & 1;
                    332:     opmode = (r->mode >> 6) & 3;
                    333: 
                    334:     if (dir) {
                    335:         dolog ("DMA in address decrement mode\n");
                    336:     }
                    337:     if (opmode != 1) {
                    338:         dolog ("DMA not in single mode select %#x\n", opmode);
                    339:     }
                    340: #endif
                    341: 
                    342:     r = dma_controllers[ncont].regs + ichan;
                    343:     n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
                    344:                              r->now[COUNT], (r->base[COUNT] + 1) << ncont);
                    345:     r->now[COUNT] = n;
                    346:     ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
                    347: }
                    348: 
                    349: void DMA_run (void)
                    350: {
                    351:     struct dma_cont *d;
                    352:     int icont, ichan;
                    353: 
                    354:     d = dma_controllers;
                    355: 
                    356:     for (icont = 0; icont < 2; icont++, d++) {
                    357:         for (ichan = 0; ichan < 4; ichan++) {
                    358:             int mask;
                    359: 
                    360:             mask = 1 << ichan;
                    361: 
                    362:             if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
                    363:                 channel_run (icont, ichan);
                    364:         }
                    365:     }
                    366: }
                    367: 
                    368: void DMA_register_channel (int nchan,
                    369:                            DMA_transfer_handler transfer_handler,
                    370:                            void *opaque)
                    371: {
                    372:     struct dma_regs *r;
                    373:     int ichan, ncont;
                    374: 
                    375:     ncont = nchan > 3;
                    376:     ichan = nchan & 3;
                    377: 
                    378:     r = dma_controllers[ncont].regs + ichan;
                    379:     r->transfer_handler = transfer_handler;
                    380:     r->opaque = opaque;
                    381: }
                    382: 
                    383: int DMA_read_memory (int nchan, void *buf, int pos, int len)
                    384: {
                    385:     struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
                    386:     target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
                    387: 
                    388:     if (r->mode & 0x20) {
                    389:         int i;
                    390:         uint8_t *p = buf;
                    391: 
                    392:         cpu_physical_memory_read (addr - pos - len, buf, len);
                    393:         /* What about 16bit transfers? */
                    394:         for (i = 0; i < len >> 1; i++) {
                    395:             uint8_t b = p[len - i - 1];
                    396:             p[i] = b;
                    397:         }
                    398:     }
                    399:     else
                    400:         cpu_physical_memory_read (addr + pos, buf, len);
                    401: 
                    402:     return len;
                    403: }
                    404: 
                    405: int DMA_write_memory (int nchan, void *buf, int pos, int len)
                    406: {
                    407:     struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
                    408:     target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
                    409: 
                    410:     if (r->mode & 0x20) {
                    411:         int i;
                    412:         uint8_t *p = buf;
                    413: 
                    414:         cpu_physical_memory_write (addr - pos - len, buf, len);
                    415:         /* What about 16bit transfers? */
                    416:         for (i = 0; i < len; i++) {
                    417:             uint8_t b = p[len - i - 1];
                    418:             p[i] = b;
                    419:         }
                    420:     }
                    421:     else
                    422:         cpu_physical_memory_write (addr + pos, buf, len);
                    423: 
                    424:     return len;
                    425: }
                    426: 
                    427: /* request the emulator to transfer a new DMA memory block ASAP */
                    428: void DMA_schedule(int nchan)
                    429: {
1.1.1.2 ! root      430:     CPUState *env = cpu_single_env;
        !           431:     if (env)
        !           432:         cpu_interrupt(env, CPU_INTERRUPT_EXIT);
1.1       root      433: }
                    434: 
                    435: static void dma_reset(void *opaque)
                    436: {
                    437:     struct dma_cont *d = opaque;
                    438:     write_cont (d, (0x0d << d->dshift), 0);
                    439: }
                    440: 
                    441: /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
                    442: static void dma_init2(struct dma_cont *d, int base, int dshift,
                    443:                       int page_base, int pageh_base)
                    444: {
                    445:     const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
                    446:     int i;
                    447: 
                    448:     d->dshift = dshift;
                    449:     for (i = 0; i < 8; i++) {
                    450:         register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
                    451:         register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
                    452:     }
                    453:     for (i = 0; i < LENOFA (page_port_list); i++) {
                    454:         register_ioport_write (page_base + page_port_list[i], 1, 1,
                    455:                                write_page, d);
                    456:         register_ioport_read (page_base + page_port_list[i], 1, 1,
                    457:                               read_page, d);
                    458:         if (pageh_base >= 0) {
                    459:             register_ioport_write (pageh_base + page_port_list[i], 1, 1,
                    460:                                    write_pageh, d);
                    461:             register_ioport_read (pageh_base + page_port_list[i], 1, 1,
                    462:                                   read_pageh, d);
                    463:         }
                    464:     }
                    465:     for (i = 0; i < 8; i++) {
                    466:         register_ioport_write (base + ((i + 8) << dshift), 1, 1,
                    467:                                write_cont, d);
                    468:         register_ioport_read (base + ((i + 8) << dshift), 1, 1,
                    469:                               read_cont, d);
                    470:     }
                    471:     qemu_register_reset(dma_reset, d);
                    472:     dma_reset(d);
                    473: }
                    474: 
                    475: static void dma_save (QEMUFile *f, void *opaque)
                    476: {
                    477:     struct dma_cont *d = opaque;
                    478:     int i;
                    479: 
                    480:     /* qemu_put_8s (f, &d->status); */
                    481:     qemu_put_8s (f, &d->command);
                    482:     qemu_put_8s (f, &d->mask);
                    483:     qemu_put_8s (f, &d->flip_flop);
                    484:     qemu_put_be32s (f, &d->dshift);
                    485: 
                    486:     for (i = 0; i < 4; ++i) {
                    487:         struct dma_regs *r = &d->regs[i];
                    488:         qemu_put_be32s (f, &r->now[0]);
                    489:         qemu_put_be32s (f, &r->now[1]);
                    490:         qemu_put_be16s (f, &r->base[0]);
                    491:         qemu_put_be16s (f, &r->base[1]);
                    492:         qemu_put_8s (f, &r->mode);
                    493:         qemu_put_8s (f, &r->page);
                    494:         qemu_put_8s (f, &r->pageh);
                    495:         qemu_put_8s (f, &r->dack);
                    496:         qemu_put_8s (f, &r->eop);
                    497:     }
                    498: }
                    499: 
                    500: static int dma_load (QEMUFile *f, void *opaque, int version_id)
                    501: {
                    502:     struct dma_cont *d = opaque;
                    503:     int i;
                    504: 
                    505:     if (version_id != 1)
                    506:         return -EINVAL;
                    507: 
                    508:     /* qemu_get_8s (f, &d->status); */
                    509:     qemu_get_8s (f, &d->command);
                    510:     qemu_get_8s (f, &d->mask);
                    511:     qemu_get_8s (f, &d->flip_flop);
                    512:     qemu_get_be32s (f, &d->dshift);
                    513: 
                    514:     for (i = 0; i < 4; ++i) {
                    515:         struct dma_regs *r = &d->regs[i];
                    516:         qemu_get_be32s (f, &r->now[0]);
                    517:         qemu_get_be32s (f, &r->now[1]);
                    518:         qemu_get_be16s (f, &r->base[0]);
                    519:         qemu_get_be16s (f, &r->base[1]);
                    520:         qemu_get_8s (f, &r->mode);
                    521:         qemu_get_8s (f, &r->page);
                    522:         qemu_get_8s (f, &r->pageh);
                    523:         qemu_get_8s (f, &r->dack);
                    524:         qemu_get_8s (f, &r->eop);
                    525:     }
                    526:     return 0;
                    527: }
                    528: 
                    529: void DMA_init (int high_page_enable)
                    530: {
                    531:     dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
                    532:               high_page_enable ? 0x480 : -1);
                    533:     dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
                    534:               high_page_enable ? 0x488 : -1);
                    535:     register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
                    536:     register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
                    537: }

unix.superglobalmegacorp.com