VirtualBox

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

Last change on this file since 3670 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

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