VirtualBox

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

Last change on this file since 21205 was 12978, checked in by vboxsync, 16 years ago

PDM: PDM_DEVREG_FLAGS_DEFAULT_BITS convenience.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use