VirtualBox

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

Last change on this file since 6290 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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