VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevDMA.cpp@ 26169

Last change on this file since 26169 was 26169, checked in by vboxsync, 15 years ago

PDM: s/pDevHlp\(|R0|R3|RC\)/pHlp\1/g - PDMDEVINS.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 25.6 KB
Line 
1/* $Id: DevDMA.cpp 26169 2010-02-02 20:19:15Z vboxsync $ */
2/** @file
3 * DevDMA - DMA Controller Device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 * --------------------------------------------------------------------
21 *
22 * This code is based on:
23 *
24 * QEMU DMA emulation
25 *
26 * Copyright (c) 2003 Vassili Karpov (malc)
27 *
28 * Permission is hereby granted, free of charge, to any person obtaining a copy
29 * of this software and associated documentation files (the "Software"), to deal
30 * in the Software without restriction, including without limitation the rights
31 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 * copies of the Software, and to permit persons to whom the Software is
33 * furnished to do so, subject to the following conditions:
34 *
35 * The above copyright notice and this permission notice shall be included in
36 * all copies or substantial portions of the Software.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 * THE SOFTWARE.
45 */
46
47#ifdef VBOX
48
49/*******************************************************************************
50* Header Files *
51*******************************************************************************/
52#include <VBox/pdmdev.h>
53#include <VBox/err.h>
54
55#define LOG_GROUP LOG_GROUP_DEFAULT ///@todo LOG_GROUP_DEV_DMA
56#include <VBox/log.h>
57#include <iprt/assert.h>
58#include <iprt/string.h>
59
60#include <stdio.h>
61#include <stdlib.h>
62
63#include "../Builtins.h"
64#include "../vl_vbox.h"
65typedef PFNDMATRANSFERHANDLER DMA_transfer_handler;
66
67#else /* !VBOX */
68#include "vl.h"
69#endif
70
71/* #define DEBUG_DMA */
72
73#ifndef VBOX
74#ifndef __WIN32__
75#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
76#ifdef DEBUG_DMA
77#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
78#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
79#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
80#else
81#define lwarn(...)
82#define linfo(...)
83#define ldebug(...)
84#endif
85#else
86#define dolog()
87#define lwarn()
88#define linfo()
89#define ldebug()
90#endif
91#else /* VBOX */
92
93# ifdef LOG_ENABLED
94# define DEBUG_DMA
95 static void DMA_DPRINTF (const char *fmt, ...)
96 {
97 if (LogIsEnabled ()) {
98 va_list args;
99 va_start (args, fmt);
100 RTLogLogger (NULL, NULL, "dma: %N", fmt, &args); /* %N - nested va_list * type formatting call. */
101 va_end (args);
102 }
103 }
104# else
105 DECLINLINE(void) DMA_DPRINTF(const char *pszFmt, ...) {}
106# endif
107
108# define dolog DMA_DPRINTF
109# define lwarn DMA_DPRINTF
110# define linfo DMA_DPRINTF
111# define ldebug DMA_DPRINTF
112
113#endif /* VBOX */
114
115#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
116
117struct dma_regs {
118 unsigned int now[2];
119 uint16_t base[2];
120 uint8_t mode;
121 uint8_t page;
122 uint8_t pageh;
123 uint8_t dack;
124 uint8_t eop;
125 DMA_transfer_handler transfer_handler;
126 void *opaque;
127};
128
129#define ADDR 0
130#define COUNT 1
131
132struct dma_cont {
133 uint8_t status;
134 uint8_t command;
135 uint8_t mask;
136 uint8_t flip_flop;
137 unsigned int dshift;
138 struct dma_regs regs[4];
139};
140
141typedef struct {
142 PPDMDEVINS pDevIns;
143 PCPDMDMACHLP pHlp;
144 struct dma_cont dma_controllers[2];
145} DMAState;
146
147enum {
148 CMD_MEMORY_TO_MEMORY = 0x01,
149 CMD_FIXED_ADDRESS = 0x02,
150 CMD_BLOCK_CONTROLLER = 0x04,
151 CMD_COMPRESSED_TIME = 0x08,
152 CMD_CYCLIC_PRIORITY = 0x10,
153 CMD_EXTENDED_WRITE = 0x20,
154 CMD_LOW_DREQ = 0x40,
155 CMD_LOW_DACK = 0x80,
156 CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
157 | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
158 | CMD_LOW_DREQ | CMD_LOW_DACK
159
160};
161
162static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
163
164static void write_page (void *opaque, uint32_t nport, uint32_t data)
165{
166 struct dma_cont *d = (struct dma_cont*)opaque;
167 int ichan;
168
169 ichan = channels[nport & 7];
170 if (-1 == ichan) {
171 dolog ("invalid channel %#x %#x\n", nport, data);
172 return;
173 }
174 d->regs[ichan].page = data;
175}
176
177static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
178{
179 struct dma_cont *d = (struct dma_cont*)opaque;
180 int ichan;
181
182 ichan = channels[nport & 7];
183 if (-1 == ichan) {
184 dolog ("invalid channel %#x %#x\n", nport, data);
185 return;
186 }
187 d->regs[ichan].pageh = data;
188}
189
190static uint32_t read_page (void *opaque, uint32_t nport)
191{
192 struct dma_cont *d = (struct dma_cont*)opaque;
193 int ichan;
194
195 ichan = channels[nport & 7];
196 if (-1 == ichan) {
197 dolog ("invalid channel read %#x\n", nport);
198 return 0;
199 }
200 return d->regs[ichan].page;
201}
202
203static uint32_t read_pageh (void *opaque, uint32_t nport)
204{
205 struct dma_cont *d = (struct dma_cont*)opaque;
206 int ichan;
207
208 ichan = channels[nport & 7];
209 if (-1 == ichan) {
210 dolog ("invalid channel read %#x\n", nport);
211 return 0;
212 }
213 return d->regs[ichan].pageh;
214}
215
216static inline void init_chan (struct dma_cont *d, int ichan)
217{
218 struct dma_regs *r;
219
220 r = d->regs + ichan;
221 r->now[ADDR] = r->base[ADDR] << d->dshift;
222 r->now[COUNT] = 0;
223}
224
225static inline int getff (struct dma_cont *d)
226{
227 int ff;
228
229 ff = d->flip_flop;
230 d->flip_flop = !ff;
231 return ff;
232}
233
234static uint32_t read_chan (void *opaque, uint32_t nport)
235{
236 struct dma_cont *d = (struct dma_cont*)opaque;
237 int ichan, nreg, iport, ff, val, dir;
238 struct dma_regs *r;
239
240 iport = (nport >> d->dshift) & 0x0f;
241 ichan = iport >> 1;
242 nreg = iport & 1;
243 r = d->regs + ichan;
244
245 dir = ((r->mode >> 5) & 1) ? -1 : 1;
246 ff = getff (d);
247 if (nreg)
248 val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
249 else
250 val = r->now[ADDR] + r->now[COUNT] * dir;
251
252 ldebug ("read_chan %#x -> %d\n", iport, val);
253 return (val >> (d->dshift + (ff << 3))) & 0xff;
254}
255
256static void write_chan (void *opaque, uint32_t nport, uint32_t data)
257{
258 struct dma_cont *d = (struct dma_cont*)opaque;
259 int iport, ichan, nreg;
260 struct dma_regs *r;
261
262 iport = (nport >> d->dshift) & 0x0f;
263 ichan = iport >> 1;
264 nreg = iport & 1;
265 r = d->regs + ichan;
266 if (getff (d)) {
267 r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
268 init_chan (d, ichan);
269 } else {
270 r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
271 }
272}
273
274static void write_cont (void *opaque, uint32_t nport, uint32_t data)
275{
276 struct dma_cont *d = (struct dma_cont*)opaque;
277 int iport, ichan = 0;
278
279 iport = (nport >> d->dshift) & 0x0f;
280 switch (iport) {
281 case 0x08: /* command */
282 if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
283 dolog ("command %#x not supported\n", data);
284 return;
285 }
286 d->command = data;
287 break;
288
289 case 0x09:
290 ichan = data & 3;
291 if (data & 4) {
292 d->status |= 1 << (ichan + 4);
293 }
294 else {
295 d->status &= ~(1 << (ichan + 4));
296 }
297 d->status &= ~(1 << ichan);
298 break;
299
300 case 0x0a: /* single mask */
301 if (data & 4)
302 d->mask |= 1 << (data & 3);
303 else
304 d->mask &= ~(1 << (data & 3));
305 break;
306
307 case 0x0b: /* mode */
308 {
309 ichan = data & 3;
310#ifdef DEBUG_DMA
311 {
312 int op, ai, dir, opmode;
313 op = (data >> 2) & 3;
314 ai = (data >> 4) & 1;
315 dir = (data >> 5) & 1;
316 opmode = (data >> 6) & 3;
317
318 linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
319 ichan, op, ai, dir, opmode);
320 }
321#endif
322 d->regs[ichan].mode = data;
323 break;
324 }
325
326 case 0x0c: /* clear flip flop */
327 d->flip_flop = 0;
328 break;
329
330 case 0x0d: /* reset */
331 d->flip_flop = 0;
332 d->mask = ~0;
333 d->status = 0;
334 d->command = 0;
335 break;
336
337 case 0x0e: /* clear mask for all channels */
338 d->mask = 0;
339 break;
340
341 case 0x0f: /* write mask for all channels */
342 d->mask = data;
343 break;
344
345 default:
346 dolog ("unknown iport %#x\n", iport);
347 break;
348 }
349
350#ifdef DEBUG_DMA
351 if (0xc != iport) {
352 linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
353 nport, ichan, data);
354 }
355#endif
356}
357
358static uint32_t read_cont (void *opaque, uint32_t nport)
359{
360 struct dma_cont *d = (struct dma_cont*)opaque;
361 int iport, val;
362
363 iport = (nport >> d->dshift) & 0x0f;
364 switch (iport) {
365 case 0x08: /* status */
366 val = d->status;
367 d->status &= 0xf0;
368 break;
369 case 0x0f: /* mask */
370 val = d->mask;
371 break;
372 default:
373 val = 0;
374 break;
375 }
376
377 ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
378 return val;
379}
380
381static uint8_t DMA_get_channel_mode (DMAState *s, int nchan)
382{
383 return s->dma_controllers[nchan > 3].regs[nchan & 3].mode;
384}
385
386static void DMA_hold_DREQ (DMAState *s, int nchan)
387{
388 int ncont, ichan;
389
390 ncont = nchan > 3;
391 ichan = nchan & 3;
392 linfo ("held cont=%d chan=%d\n", ncont, ichan);
393 s->dma_controllers[ncont].status |= 1 << (ichan + 4);
394}
395
396static void DMA_release_DREQ (DMAState *s, int nchan)
397{
398 int ncont, ichan;
399
400 ncont = nchan > 3;
401 ichan = nchan & 3;
402 linfo ("released cont=%d chan=%d\n", ncont, ichan);
403 s->dma_controllers[ncont].status &= ~(1 << (ichan + 4));
404}
405
406static void channel_run (DMAState *s, int ncont, int ichan)
407{
408 int n;
409 struct dma_regs *r = &s->dma_controllers[ncont].regs[ichan];
410#ifdef DEBUG_DMA
411 int dir, opmode;
412
413 dir = (r->mode >> 5) & 1;
414 opmode = (r->mode >> 6) & 3;
415
416 if (dir) {
417 dolog ("DMA in address decrement mode\n");
418 }
419 if (opmode != 1) {
420 dolog ("DMA not in single mode select %#x\n", opmode);
421 }
422#endif
423
424 r = s->dma_controllers[ncont].regs + ichan;
425 n = r->transfer_handler (s->pDevIns, r->opaque, ichan + (ncont << 2),
426 r->now[COUNT], (r->base[COUNT] + 1) << ncont);
427 r->now[COUNT] = n;
428 ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
429}
430
431static void DMA_run (DMAState *s)
432{
433 struct dma_cont *d;
434 int icont, ichan;
435
436 d = s->dma_controllers;
437
438 for (icont = 0; icont < 2; icont++, d++) {
439 for (ichan = 0; ichan < 4; ichan++) {
440 int mask;
441
442 mask = 1 << ichan;
443
444 if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
445 channel_run (s, icont, ichan);
446 }
447 }
448}
449
450static void DMA_register_channel (DMAState *s, unsigned nchan,
451 DMA_transfer_handler transfer_handler,
452 void *opaque)
453{
454 struct dma_regs *r;
455 int ichan, ncont;
456 LogFlow (("DMA_register_channel: s=%p nchan=%d transfer_handler=%p opaque=%p\n",
457 s, nchan, transfer_handler, opaque));
458
459 ncont = nchan > 3;
460 ichan = nchan & 3;
461
462 r = s->dma_controllers[ncont].regs + ichan;
463 r->transfer_handler = transfer_handler;
464 r->opaque = opaque;
465}
466
467static uint32_t DMA_read_memory (DMAState *s,
468 unsigned nchan,
469 void *buf,
470 uint32_t pos,
471 uint32_t len)
472{
473 struct dma_regs *r = &s->dma_controllers[nchan > 3].regs[nchan & 3];
474 uint32_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
475
476 if (r->mode & 0x20) {
477 unsigned i;
478 uint8_t *p = (uint8_t*)buf;
479
480#ifdef VBOX
481 PDMDevHlpPhysRead (s->pDevIns, addr - pos - len, buf, len);
482#else
483 cpu_physical_memory_read (addr - pos - len, buf, len);
484#endif
485 /* What about 16bit transfers? */
486 for (i = 0; i < len >> 1; i++) {
487 uint8_t b = p[len - i - 1];
488 p[i] = b;
489 }
490 }
491 else
492#ifdef VBOX
493 PDMDevHlpPhysRead (s->pDevIns, addr + pos, buf, len);
494#else
495 cpu_physical_memory_read (addr + pos, buf, len);
496#endif
497 return len;
498}
499
500static uint32_t DMA_write_memory (DMAState *s,
501 unsigned nchan,
502 const void *buf,
503 uint32_t pos,
504 uint32_t len)
505{
506 struct dma_regs *r = &s->dma_controllers[nchan > 3].regs[nchan & 3];
507 uint32_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
508
509 if (r->mode & 0x20) {
510 unsigned i;
511 uint8_t *p = (uint8_t *) buf;
512
513#ifdef VBOX
514 PDMDevHlpPhysWrite (s->pDevIns, addr - pos - len, buf, len);
515#else
516 cpu_physical_memory_write (addr - pos - len, buf, len);
517#endif
518 /* What about 16bit transfers? */
519 for (i = 0; i < len; i++) {
520 uint8_t b = p[len - i - 1];
521 p[i] = b;
522 }
523 }
524 else
525#ifdef VBOX
526 PDMDevHlpPhysWrite (s->pDevIns, addr + pos, buf, len);
527#else
528 cpu_physical_memory_write (addr + pos, buf, len);
529#endif
530
531 return len;
532}
533
534
535#ifndef VBOX
536/* request the emulator to transfer a new DMA memory block ASAP */
537void DMA_schedule(int nchan)
538{
539 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
540}
541#endif
542
543static void dma_reset(void *opaque)
544{
545 struct dma_cont *d = (struct dma_cont*)opaque;
546 write_cont (d, (0x0d << d->dshift), 0);
547}
548
549#ifdef VBOX
550#define IO_READ_PROTO(n) \
551static DECLCALLBACK(int) io_read_##n (PPDMDEVINS pDevIns, \
552 void *pvUser, \
553 RTIOPORT Port, \
554 uint32_t *pu32, \
555 unsigned cb)
556
557
558#define IO_WRITE_PROTO(n) \
559static DECLCALLBACK(int) io_write_##n (PPDMDEVINS pDevIns, \
560 void *pvUser, \
561 RTIOPORT Port, \
562 uint32_t u32, \
563 unsigned cb)
564
565IO_WRITE_PROTO (chan)
566{
567 if (cb == 1) {
568 write_chan (pvUser, Port, u32);
569 }
570#ifdef PARANOID
571 else {
572 Log (("Unknown write to %#x of size %d, value %#x\n",
573 Port, cb, u32));
574 }
575#endif
576 return VINF_SUCCESS;
577}
578
579IO_WRITE_PROTO (page)
580{
581 if (cb == 1) {
582 write_page (pvUser, Port, u32);
583 }
584#ifdef PARANOID
585 else {
586 Log (("Unknown write to %#x of size %d, value %#x\n",
587 Port, cb, u32));
588 }
589#endif
590 return VINF_SUCCESS;
591}
592
593IO_WRITE_PROTO (pageh)
594{
595 if (cb == 1) {
596 write_pageh (pvUser, Port, u32);
597 }
598#ifdef PARANOID
599 else {
600 Log (("Unknown write to %#x of size %d, value %#x\n",
601 Port, cb, u32));
602 }
603#endif
604 return VINF_SUCCESS;
605}
606
607IO_WRITE_PROTO (cont)
608{
609 if (cb == 1) {
610 write_cont (pvUser, Port, u32);
611 }
612#ifdef PARANOID
613 else {
614 Log (("Unknown write to %#x of size %d, value %#x\n",
615 Port, cb, u32));
616 }
617#endif
618 return VINF_SUCCESS;
619}
620
621IO_READ_PROTO (chan)
622{
623 if (cb == 1) {
624 *pu32 = read_chan (pvUser, Port);
625 return VINF_SUCCESS;
626 }
627 else {
628 return VERR_IOM_IOPORT_UNUSED;
629 }
630}
631
632IO_READ_PROTO (page)
633{
634 if (cb == 1) {
635 *pu32 = read_page (pvUser, Port);
636 return VINF_SUCCESS;
637 }
638 else {
639 return VERR_IOM_IOPORT_UNUSED;
640 }
641}
642
643IO_READ_PROTO (pageh)
644{
645 if (cb == 1) {
646 *pu32 = read_pageh (pvUser, Port);
647 return VINF_SUCCESS;
648 }
649 else {
650 return VERR_IOM_IOPORT_UNUSED;
651 }
652}
653
654IO_READ_PROTO (cont)
655{
656 if (cb == 1) {
657 *pu32 = read_cont (pvUser, Port);
658 return VINF_SUCCESS;
659 }
660 else {
661 return VERR_IOM_IOPORT_UNUSED;
662 }
663}
664#endif
665
666/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
667static void dma_init2(DMAState *s, struct dma_cont *d, int base, int dshift,
668 int page_base, int pageh_base)
669{
670 const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
671 int i;
672
673 d->dshift = dshift;
674 for (i = 0; i < 8; i++) {
675#ifdef VBOX
676 PDMDevHlpIOPortRegister (s->pDevIns, base + (i << dshift), 1, d,
677 io_write_chan, io_read_chan, NULL, NULL, "DMA");
678#else
679 register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
680 register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
681#endif
682 }
683 for (i = 0; i < LENOFA (page_port_list); i++) {
684#ifdef VBOX
685 PDMDevHlpIOPortRegister (s->pDevIns, page_base + page_port_list[i], 1, d,
686 io_write_page, io_read_page, NULL, NULL, "DMA Page");
687#else
688 register_ioport_write (page_base + page_port_list[i], 1, 1,
689 write_page, d);
690 register_ioport_read (page_base + page_port_list[i], 1, 1,
691 read_page, d);
692#endif
693 if (pageh_base >= 0) {
694#ifdef VBOX
695 PDMDevHlpIOPortRegister (s->pDevIns, pageh_base + page_port_list[i], 1, d,
696 io_write_pageh, io_read_pageh, NULL, NULL, "DMA Page High");
697#else
698 register_ioport_write (pageh_base + page_port_list[i], 1, 1,
699 write_pageh, d);
700 register_ioport_read (pageh_base + page_port_list[i], 1, 1,
701 read_pageh, d);
702#endif
703 }
704 }
705 for (i = 0; i < 8; i++) {
706#ifdef VBOX
707 PDMDevHlpIOPortRegister (s->pDevIns, base + ((i + 8) << dshift), 1, d,
708 io_write_cont, io_read_cont, NULL, NULL, "DMA cont");
709#else
710 register_ioport_write (base + ((i + 8) << dshift), 1, 1,
711 write_cont, d);
712 register_ioport_read (base + ((i + 8) << dshift), 1, 1,
713 read_cont, d);
714#endif
715 }
716#ifndef VBOX
717 qemu_register_reset(dma_reset, d);
718#endif
719 dma_reset(d);
720}
721
722static void dma_save (QEMUFile *f, void *opaque)
723{
724 struct dma_cont *d = (struct dma_cont*)opaque;
725 int i;
726
727 /* qemu_put_8s (f, &d->status); */
728 qemu_put_8s (f, &d->command);
729 qemu_put_8s (f, &d->mask);
730 qemu_put_8s (f, &d->flip_flop);
731 qemu_put_be32s (f, &d->dshift);
732
733 for (i = 0; i < 4; ++i) {
734 struct dma_regs *r = &d->regs[i];
735 qemu_put_be32s (f, &r->now[0]);
736 qemu_put_be32s (f, &r->now[1]);
737 qemu_put_be16s (f, &r->base[0]);
738 qemu_put_be16s (f, &r->base[1]);
739 qemu_put_8s (f, &r->mode);
740 qemu_put_8s (f, &r->page);
741 qemu_put_8s (f, &r->pageh);
742 qemu_put_8s (f, &r->dack);
743 qemu_put_8s (f, &r->eop);
744 }
745}
746
747static int dma_load (QEMUFile *f, void *opaque, int version_id)
748{
749 struct dma_cont *d = (struct dma_cont*)opaque;
750 int i;
751
752 if (version_id != 1)
753#ifdef VBOX
754 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
755#else
756 return -EINVAL;
757#endif
758
759 /* qemu_get_8s (f, &d->status); */
760 qemu_get_8s (f, &d->command);
761 qemu_get_8s (f, &d->mask);
762 qemu_get_8s (f, &d->flip_flop);
763 qemu_get_be32s (f, &d->dshift);
764
765 for (i = 0; i < 4; ++i) {
766 struct dma_regs *r = &d->regs[i];
767 qemu_get_be32s (f, &r->now[0]);
768 qemu_get_be32s (f, &r->now[1]);
769 qemu_get_be16s (f, &r->base[0]);
770 qemu_get_be16s (f, &r->base[1]);
771 qemu_get_8s (f, &r->mode);
772 qemu_get_8s (f, &r->page);
773 qemu_get_8s (f, &r->pageh);
774 qemu_get_8s (f, &r->dack);
775 qemu_get_8s (f, &r->eop);
776 }
777 return 0;
778}
779
780#ifndef VBOX
781void DMA_init (int high_page_enable)
782{
783 dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
784 high_page_enable ? 0x480 : -1);
785 dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
786 high_page_enable ? 0x488 : -1);
787 register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
788 register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
789}
790#endif
791
792#ifdef VBOX
793static bool run_wrapper (PPDMDEVINS pDevIns)
794{
795 DMA_run (PDMINS_2_DATA (pDevIns, DMAState *));
796 return 0;
797}
798
799static void register_channel_wrapper (PPDMDEVINS pDevIns,
800 unsigned nchan,
801 PFNDMATRANSFERHANDLER f,
802 void *opaque)
803{
804 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
805 DMA_register_channel (s, nchan, f, opaque);
806}
807
808static uint32_t rd_mem_wrapper (PPDMDEVINS pDevIns,
809 unsigned nchan,
810 void *buf,
811 uint32_t pos,
812 uint32_t len)
813{
814 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
815 return DMA_read_memory (s, nchan, buf, pos, len);
816}
817
818static uint32_t wr_mem_wrapper (PPDMDEVINS pDevIns,
819 unsigned nchan,
820 const void *buf,
821 uint32_t pos,
822 uint32_t len)
823{
824 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
825 return DMA_write_memory (s, nchan, buf, pos, len);
826}
827
828static void set_DREQ_wrapper (PPDMDEVINS pDevIns,
829 unsigned nchan,
830 unsigned level)
831{
832 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
833 if (level) {
834 DMA_hold_DREQ (s, nchan);
835 }
836 else {
837 DMA_release_DREQ (s, nchan);
838 }
839}
840
841static uint8_t get_mode_wrapper (PPDMDEVINS pDevIns, unsigned nchan)
842{
843 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
844 return DMA_get_channel_mode (s, nchan);
845}
846
847static void dmaReset (PPDMDEVINS pDevIns)
848{
849 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
850 dma_reset (&s->dma_controllers[0]);
851 dma_reset (&s->dma_controllers[1]);
852}
853
854static DECLCALLBACK(int) dmaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
855{
856 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
857 dma_save (pSSMHandle, &s->dma_controllers[0]);
858 dma_save (pSSMHandle, &s->dma_controllers[1]);
859 return VINF_SUCCESS;
860}
861
862static DECLCALLBACK(int) dmaLoadExec (PPDMDEVINS pDevIns,
863 PSSMHANDLE pSSMHandle,
864 uint32_t uVersion,
865 uint32_t uPass)
866{
867 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
868
869 AssertMsgReturn (uVersion == 1, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
870 Assert (uPass == SSM_PASS_FINAL); NOREF(uPass);
871
872 dma_load (pSSMHandle, &s->dma_controllers[0], uVersion);
873 return dma_load (pSSMHandle, &s->dma_controllers[1], uVersion);
874}
875
876/**
877 * @interface_method_impl{PDMDEVREG,pfnConstruct}
878 */
879static DECLCALLBACK(int) dmaConstruct(PPDMDEVINS pDevIns,
880 int iInstance,
881 PCFGMNODE pCfgHandle)
882{
883 DMAState *s = PDMINS_2_DATA (pDevIns, DMAState *);
884 bool high_page_enable = 0;
885 PDMDMACREG reg;
886 int rc;
887
888 s->pDevIns = pDevIns;
889
890 /*
891 * Validate configuration.
892 */
893 if (!CFGMR3AreValuesValid(pCfgHandle, "\0")) /* "HighPageEnable\0")) */
894 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
895
896#if 0
897 rc = CFGMR3QueryBool (pCfgHandle, "HighPageEnable", &high_page_enable);
898 if (RT_FAILURE (rc)) {
899 return rc;
900 }
901#endif
902
903 dma_init2(s, &s->dma_controllers[0], 0x00, 0, 0x80,
904 high_page_enable ? 0x480 : -1);
905 dma_init2(s, &s->dma_controllers[1], 0xc0, 1, 0x88,
906 high_page_enable ? 0x488 : -1);
907
908 reg.u32Version = PDM_DMACREG_VERSION;
909 reg.pfnRun = run_wrapper;
910 reg.pfnRegister = register_channel_wrapper;
911 reg.pfnReadMemory = rd_mem_wrapper;
912 reg.pfnWriteMemory = wr_mem_wrapper;
913 reg.pfnSetDREQ = set_DREQ_wrapper;
914 reg.pfnGetChannelMode = get_mode_wrapper;
915
916 rc = PDMDevHlpDMACRegister (pDevIns, &reg, &s->pHlp);
917 if (RT_FAILURE (rc)) {
918 return rc;
919 }
920
921 rc = PDMDevHlpSSMRegister (pDevIns, 1 /*uVersion*/, sizeof (*s), dmaSaveExec, dmaLoadExec);
922 if (RT_FAILURE(rc))
923 return rc;
924
925 return VINF_SUCCESS;
926}
927
928/**
929 * The device registration structure.
930 */
931const PDMDEVREG g_DeviceDMA =
932{
933 /* u32Version */
934 PDM_DEVREG_VERSION,
935 /* szName */
936 "8237A",
937 /* szRCMod */
938 "",
939 /* szR0Mod */
940 "",
941 /* pszDescription */
942 "DMA Controller Device",
943 /* fFlags */
944 PDM_DEVREG_FLAGS_DEFAULT_BITS,
945 /* fClass */
946 PDM_DEVREG_CLASS_DMA,
947 /* cMaxInstances */
948 1,
949 /* cbInstance */
950 sizeof(DMAState),
951 /* pfnConstruct */
952 dmaConstruct,
953 /* pfnDestruct */
954 NULL,
955 /* pfnRelocate */
956 NULL,
957 /* pfnIOCtl */
958 NULL,
959 /* pfnPowerOn */
960 NULL,
961 /* pfnReset */
962 dmaReset,
963 /* pfnSuspend */
964 NULL,
965 /* pfnResume */
966 NULL,
967 /* pfnAttach */
968 NULL,
969 /* pfnDetach */
970 NULL,
971 /* pfnQueryInterface. */
972 NULL,
973 /* pfnInitComplete */
974 NULL,
975 /* pfnPowerOff */
976 NULL,
977 /* pfnSoftReset */
978 NULL,
979 /* u32VersionEnd */
980 PDM_DEVREG_VERSION
981};
982#endif /* VBOX */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette