VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevPIC.cpp@ 85194

Last change on this file since 85194 was 84334, checked in by vboxsync, 5 years ago

Devices/{DevPIC,DevPIT-i8254}: Doxygen

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 38.2 KB
Line 
1/* $Id: DevPIC.cpp 84334 2020-05-18 15:47:26Z vboxsync $ */
2/** @file
3 * DevPIC - Intel 8259 Programmable Interrupt Controller (PIC) Device.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
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 8259 interrupt controller emulation
21 *
22 * Copyright (c) 2003-2004 Fabrice Bellard
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
44
45/*********************************************************************************************************************************
46* Header Files *
47*********************************************************************************************************************************/
48#define LOG_GROUP LOG_GROUP_DEV_PIC
49#include <VBox/vmm/pdmdev.h>
50#include <VBox/log.h>
51#include <iprt/assert.h>
52#include <iprt/string.h>
53
54#include "VBoxDD.h"
55
56
57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
60/** @def PIC_LOCK
61 * Acquires the PDM lock. This is a NOP if locking is disabled. */
62/** @def PIC_UNLOCK
63 * Releases the PDM lock. This is a NOP if locking is disabled. */
64#define PIC_LOCK(a_pDevIns, a_pThisCC, rc) \
65 do { \
66 int rc2 = (a_pThisCC)->pPicHlp->pfnLock((a_pDevIns), rc); \
67 if (rc2 != VINF_SUCCESS) \
68 return rc2; \
69 } while (0)
70#define PIC_UNLOCK(a_pDevIns, a_pThisCC) \
71 (a_pThisCC)->pPicHlp->pfnUnlock((a_pDevIns))
72
73
74/*********************************************************************************************************************************
75* Structures and Typedefs *
76*********************************************************************************************************************************/
77/**
78 * The instance data of one (1) PIC.
79 */
80typedef struct PICSTATE
81{
82 uint8_t last_irr; /**< edge detection */
83 uint8_t irr; /**< interrupt request register */
84 uint8_t imr; /**< interrupt mask register */
85 uint8_t isr; /**< interrupt service register */
86 uint8_t priority_add; /**< highest irq priority */
87 uint8_t irq_base;
88 uint8_t read_reg_select;
89 uint8_t poll;
90 uint8_t special_mask;
91 uint8_t init_state;
92 uint8_t auto_eoi;
93 uint8_t rotate_on_auto_eoi;
94 uint8_t special_fully_nested_mode;
95 uint8_t init4; /**< true if 4 byte init */
96 uint8_t elcr; /**< PIIX edge/trigger selection*/
97 uint8_t elcr_mask;
98 /** The IRQ tags and source IDs for each (tracing purposes). */
99 uint32_t auTags[8];
100 /** The PIC index (0 or 1). */
101 uint8_t idxPic;
102 uint8_t abAlignment0[7]; /**< Alignment padding. */
103 /** The two I/O ports at 0x20 or 0xa0. */
104 IOMIOPORTHANDLE hIoPorts0;
105 /** The ELCR I/O port at 0x4d0 or 0x4d1. */
106 IOMIOPORTHANDLE hIoPorts1;
107} PICSTATE;
108AssertCompileMemberAlignment(PICSTATE, hIoPorts0, 8);
109/** Pointer to the state of one PIC. */
110typedef PICSTATE *PPICSTATE;
111
112
113/**
114 * The shared PIC device instance data.
115 */
116typedef struct DEVPIC
117{
118 /** The two interrupt controllers. */
119 PICSTATE aPics[2];
120 /** Number of release log entries. Used to prevent flooding. */
121 uint32_t cRelLogEntries;
122 uint32_t u32Padding;
123#ifdef VBOX_WITH_STATISTICS
124 STAMCOUNTER StatSetIrqRZ;
125 STAMCOUNTER StatSetIrqR3;
126 STAMCOUNTER StatClearedActiveIRQ2;
127 STAMCOUNTER StatClearedActiveMasterIRQ;
128 STAMCOUNTER StatClearedActiveSlaveIRQ;
129#endif
130} DEVPIC;
131/** Pointer to the shared PIC instance data. */
132typedef DEVPIC *PDEVPIC;
133
134
135/**
136 * The PIC device instance data for ring-3.
137 */
138typedef struct DEVPICR3
139{
140 /** Pointer to the PIC ring-3 helpers. */
141 R3PTRTYPE(PCPDMPICHLP) pPicHlp;
142} DEVPICR3;
143/** Pointer to the ring-3 PIC instance data. */
144typedef DEVPICR3 *PDEVPICR3;
145
146
147/**
148 * The PIC device instance data for ring-0.
149 */
150typedef struct DEVPICR0
151{
152 /** Pointer to the PIC ring-0 helpers. */
153 R0PTRTYPE(PCPDMPICHLP) pPicHlp;
154} DEVPICR0;
155/** Pointer to the ring-0 PIC instance data. */
156typedef DEVPICR0 *PDEVPICR0;
157
158
159/**
160 * The PIC device instance data for raw-mode.
161 */
162typedef struct DEVPICRC
163{
164 /** Pointer to the PIC raw-mode helpers. */
165 RCPTRTYPE(PCPDMPICHLP) pPicHlp;
166} DEVPICRC;
167/** Pointer to the raw-mode PIC instance data. */
168typedef DEVPICRC *PDEVPICRC;
169
170
171/** The PIC instance data for the current context. */
172typedef CTX_SUFF(DEVPIC) DEVPICCC;
173/** Pointer to the PIC instance data for the current context. */
174typedef CTX_SUFF(PDEVPIC) PDEVPICCC;
175
176
177
178#ifndef VBOX_DEVICE_STRUCT_TESTCASE /* The rest of the file! */
179
180#ifdef LOG_ENABLED
181DECLINLINE(void) DumpPICState(PPICSTATE pPic, const char *pszFn)
182{
183 Log2(("%s: pic%d: elcr=%x last_irr=%x irr=%x imr=%x isr=%x irq_base=%x\n",
184 pszFn, pPic->idxPic, pPic->elcr, pPic->last_irr, pPic->irr, pPic->imr, pPic->isr, pPic->irq_base));
185}
186#else
187# define DumpPICState(pThis, szFn) do { } while (0)
188#endif
189
190/* set irq level. If an edge is detected, then the IRR is set to 1 */
191DECLINLINE(void) pic_set_irq1(PPICSTATE pPic, int irq, int level, uint32_t uTagSrc)
192{
193 Log(("pic_set_irq1: irq=%d level=%d\n", irq, level));
194 int mask = 1 << irq;
195 if (pPic->elcr & mask)
196 {
197 /* level triggered */
198 if (level)
199 {
200 Log2(("pic_set_irq1(ls) irr=%d irrnew=%d\n", pPic->irr, pPic->irr | mask));
201 pPic->irr |= mask;
202 pPic->last_irr |= mask;
203 }
204 else
205 {
206 Log2(("pic_set_irq1(lc) irr=%d irrnew=%d\n", pPic->irr, pPic->irr & ~mask));
207 pPic->irr &= ~mask;
208 pPic->last_irr &= ~mask;
209 }
210 }
211 else
212 {
213 /* edge triggered */
214 if (level)
215 {
216 if ((pPic->last_irr & mask) == 0)
217 {
218 Log2(("pic_set_irq1 irr=%x last_irr=%x\n", pPic->irr | mask, pPic->last_irr));
219 pPic->irr |= mask;
220 }
221 pPic->last_irr |= mask;
222 }
223 else
224 {
225 pPic->irr &= ~mask;
226 pPic->last_irr &= ~mask;
227 }
228 }
229
230 /* Save the tag. */
231 if (level)
232 {
233 if (!pPic->auTags[irq])
234 pPic->auTags[irq] = uTagSrc;
235 else
236 pPic->auTags[irq] |= RT_BIT_32(31);
237 }
238
239 DumpPICState(pPic, "pic_set_irq1");
240}
241
242/* return the highest priority found in mask (highest = smallest
243 number). Return 8 if no irq */
244DECLINLINE(int) get_priority(PPICSTATE pPic, int mask)
245{
246 int priority;
247 if (mask == 0)
248 return 8;
249 priority = 0;
250 while ((mask & (1 << ((priority + pPic->priority_add) & 7))) == 0)
251 priority++;
252 return priority;
253}
254
255/* return the pic wanted interrupt. return -1 if none */
256static int pic_get_irq(PPICSTATE pPic)
257{
258 int mask, cur_priority, priority;
259 Log(("pic_get_irq%d: mask=%x\n", pPic->idxPic, pPic->irr & ~pPic->imr));
260 DumpPICState(pPic, "pic_get_irq");
261
262 mask = pPic->irr & ~pPic->imr;
263 priority = get_priority(pPic, mask);
264 Log(("pic_get_irq: priority=%x\n", priority));
265 if (priority == 8)
266 return -1;
267 /* compute current priority. If special fully nested mode on the
268 master, the IRQ coming from the slave is not taken into account
269 for the priority computation. */
270 mask = pPic->isr;
271 if (pPic->special_mask)
272 mask &= ~pPic->imr;
273 if (pPic->special_fully_nested_mode && pPic->idxPic == 0)
274 mask &= ~(1 << 2);
275 cur_priority = get_priority(pPic, mask);
276 Log(("pic_get_irq%d: cur_priority=%x pending=%d\n", pPic->idxPic,
277 cur_priority, (priority == 8) ? -1 : (priority + pPic->priority_add) & 7));
278 if (priority < cur_priority)
279 {
280 /* higher priority found: an irq should be generated */
281 return (priority + pPic->priority_add) & 7;
282 }
283 return -1;
284}
285
286/* raise irq to CPU if necessary. must be called every time the active
287 irq may change */
288static int pic_update_irq(PPDMDEVINS pDevIns, PDEVPIC pThis, PDEVPICCC pThisCC)
289{
290 int irq2, irq;
291
292 /* first look at slave pic */
293 irq2 = pic_get_irq(&pThis->aPics[1]);
294 Log(("pic_update_irq irq2=%d\n", irq2));
295 if (irq2 >= 0)
296 {
297 /* if irq request by slave pic, signal master PIC */
298 pic_set_irq1(&pThis->aPics[0], 2, 1, pThis->aPics[1].auTags[irq2]);
299 }
300 else
301 {
302 /* If not, clear the IR on the master PIC. */
303 pic_set_irq1(&pThis->aPics[0], 2, 0, 0 /*uTagSrc*/);
304 }
305 /* look at requested irq */
306 irq = pic_get_irq(&pThis->aPics[0]);
307 if (irq >= 0)
308 {
309 /* If irq 2 is pending on the master pic, then there must be one pending on the slave pic too! Otherwise we'll get
310 * spurious slave interrupts in picGetInterrupt.
311 */
312 if (irq != 2 || irq2 != -1)
313 {
314 for (int i = 0; i < 2; i++)
315 Log(("pic%d: imr=%x irr=%x padd=%d\n", i, pThis->aPics[i].imr, pThis->aPics[i].irr, pThis->aPics[i].priority_add));
316 Log(("pic: cpu_interrupt\n"));
317 pThisCC->pPicHlp->pfnSetInterruptFF(pDevIns);
318 }
319 else
320 {
321 STAM_COUNTER_INC(&pThis->StatClearedActiveIRQ2);
322 Log(("pic_update_irq: irq 2 is active, but no interrupt is pending on the slave pic!!\n"));
323 /* Clear it here, so lower priority interrupts can still be dispatched. */
324
325 /* if this was the only pending irq, then we must clear the interrupt ff flag */
326 pThisCC->pPicHlp->pfnClearInterruptFF(pDevIns);
327
328 /** @todo Is this correct? */
329 pThis->aPics[0].irr &= ~(1 << 2);
330
331 /* Call ourselves again just in case other interrupts are pending */
332 return pic_update_irq(pDevIns, pThis, pThisCC);
333 }
334 }
335 else
336 {
337 Log(("pic_update_irq: no interrupt is pending!!\n"));
338
339 /* we must clear the interrupt ff flag */
340 pThisCC->pPicHlp->pfnClearInterruptFF(pDevIns);
341 }
342 return VINF_SUCCESS;
343}
344
345/**
346 * Set the an IRQ.
347 *
348 * @param pDevIns Device instance of the PICs.
349 * @param iIrq IRQ number to set.
350 * @param iLevel IRQ level.
351 * @param uTagSrc The IRQ tag and source ID (for tracing).
352 */
353static DECLCALLBACK(void) picSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
354{
355 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
356 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
357 AssertMsgReturnVoid(iIrq < 16, ("iIrq=%d\n", iIrq));
358
359 Log(("picSetIrq %d %d\n", iIrq, iLevel));
360 DumpPICState(&pThis->aPics[0], "picSetIrq");
361 DumpPICState(&pThis->aPics[1], "picSetIrq");
362 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatSetIrq));
363 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
364 {
365 /* A flip-flop lowers the IRQ line and immediately raises it, so
366 * that a rising edge is guaranteed to occur. Note that the IRQ
367 * line must be held high for a while to avoid spurious interrupts.
368 */
369 pic_set_irq1(&RT_SAFE_SUBSCRIPT(pThis->aPics, iIrq >> 3), iIrq & 7, 0, uTagSrc);
370 pic_update_irq(pDevIns, pThis, pThisCC);
371 }
372 pic_set_irq1(&RT_SAFE_SUBSCRIPT(pThis->aPics, iIrq >> 3), iIrq & 7, iLevel & PDM_IRQ_LEVEL_HIGH, uTagSrc);
373 pic_update_irq(pDevIns, pThis, pThisCC);
374}
375
376
377/* acknowledge interrupt 'irq' */
378DECLINLINE(void) pic_intack(PPICSTATE pPic, int irq)
379{
380 if (pPic->auto_eoi)
381 {
382 if (pPic->rotate_on_auto_eoi)
383 pPic->priority_add = (irq + 1) & 7;
384 }
385 else
386 pPic->isr |= (1 << irq);
387
388 /* We don't clear a level sensitive interrupt here */
389 if (!(pPic->elcr & (1 << irq)))
390 {
391 Log2(("pic_intack: irr=%x irrnew=%x\n", pPic->irr, pPic->irr & ~(1 << irq)));
392 pPic->irr &= ~(1 << irq);
393 }
394}
395
396
397/**
398 * Get a pending interrupt.
399 *
400 * @returns Pending interrupt number.
401 * @param pDevIns Device instance of the PICs.
402 * @param puTagSrc Where to return the IRQ tag and source ID.
403 */
404static DECLCALLBACK(int) picGetInterrupt(PPDMDEVINS pDevIns, uint32_t *puTagSrc)
405{
406 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
407 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
408 int irq;
409 int irq2;
410 int intno;
411
412 /* read the irq from the PIC */
413 DumpPICState(&pThis->aPics[0], "picGetInterrupt");
414 DumpPICState(&pThis->aPics[1], "picGetInterrupt");
415
416 irq = pic_get_irq(&pThis->aPics[0]);
417 if (irq >= 0)
418 {
419 pic_intack(&pThis->aPics[0], irq);
420 if (irq == 2)
421 {
422 irq2 = pic_get_irq(&pThis->aPics[1]);
423 if (irq2 >= 0)
424 pic_intack(&pThis->aPics[1], irq2);
425 else
426 {
427 /* Interrupt went away or is now masked. */
428 Log(("picGetInterrupt: spurious IRQ on slave controller, converted to IRQ15\n"));
429 irq2 = 7;
430 }
431 intno = pThis->aPics[1].irq_base + irq2;
432 *puTagSrc = pThis->aPics[0].auTags[irq2];
433 pThis->aPics[0].auTags[irq2] = 0;
434 Log2(("picGetInterrupt1: %x base=%x irq=%x uTagSrc=%#x\n", intno, pThis->aPics[1].irq_base, irq2, *puTagSrc));
435 irq = irq2 + 8;
436 }
437 else
438 {
439 intno = pThis->aPics[0].irq_base + irq;
440 *puTagSrc = pThis->aPics[0].auTags[irq];
441 pThis->aPics[0].auTags[irq] = 0;
442 Log2(("picGetInterrupt0: %x base=%x irq=%x uTagSrc=%#x\n", intno, pThis->aPics[0].irq_base, irq, *puTagSrc));
443 }
444 }
445 else
446 {
447 /* Interrupt went away or is now masked. */
448 Log(("picGetInterrupt: spurious IRQ on master controller, converted to IRQ7\n"));
449 irq = 7;
450 intno = pThis->aPics[0].irq_base + irq;
451 *puTagSrc = 0;
452 }
453 pic_update_irq(pDevIns, pThis, pThisCC);
454
455 Log(("picGetInterrupt: 0x%02x pending 0:%d 1:%d\n", intno, pic_get_irq(&pThis->aPics[0]), pic_get_irq(&pThis->aPics[1])));
456
457 return intno;
458}
459
460static void pic_reset(PPICSTATE pPic)
461{
462 pPic->last_irr = 0;
463 pPic->irr = 0;
464 pPic->imr = 0;
465 pPic->isr = 0;
466 pPic->priority_add = 0;
467 pPic->irq_base = 0;
468 pPic->read_reg_select = 0;
469 pPic->poll = 0;
470 pPic->special_mask = 0;
471 pPic->init_state = 0;
472 pPic->auto_eoi = 0;
473 pPic->rotate_on_auto_eoi = 0;
474 pPic->special_fully_nested_mode = 0;
475 pPic->init4 = 0;
476 //pPic->elcr - not cleared;
477 //pPic->elcr_mask - not cleared;
478 RT_ZERO(pPic->auTags);
479}
480
481
482static VBOXSTRICTRC pic_ioport_write(PPDMDEVINS pDevIns, PDEVPIC pThis, PDEVPICCC pThisCC, PPICSTATE pPic,
483 uint32_t addr, uint32_t val)
484{
485 VBOXSTRICTRC rc = VINF_SUCCESS;
486 int irq;
487
488 Log(("pic_write/%zu: addr=0x%02x val=0x%02x\n", pPic - pThis->aPics, addr, val));
489 addr &= 1;
490 if (addr == 0)
491 {
492 if (val & 0x10)
493 {
494 /* init */
495 pic_reset(pPic);
496 /* deassert a pending interrupt */
497 pThisCC->pPicHlp->pfnClearInterruptFF(pDevIns);
498
499 pPic->init_state = 1;
500 pPic->init4 = val & 1;
501 if (val & 0x02)
502 AssertReleaseMsgFailed(("single mode not supported"));
503 if (val & 0x08)
504 if (pThis->cRelLogEntries++ < 64)
505 LogRel(("pic_write: Level sensitive IRQ setting ignored.\n"));
506 }
507 else if (val & 0x08)
508 {
509 if (val & 0x04)
510 pPic->poll = 1;
511 if (val & 0x02)
512 pPic->read_reg_select = val & 1;
513 if (val & 0x40)
514 pPic->special_mask = (val >> 5) & 1;
515 }
516 else
517 {
518 int cmd = val >> 5;
519 switch (cmd)
520 {
521 case 0:
522 case 4:
523 pPic->rotate_on_auto_eoi = cmd >> 2;
524 break;
525 case 1: /* end of interrupt */
526 case 5:
527 {
528 int priority = get_priority(pPic, pPic->isr);
529 if (priority != 8) {
530 irq = (priority + pPic->priority_add) & 7;
531 Log(("pic_write: EOI prio=%d irq=%d\n", priority, irq));
532 pPic->isr &= ~(1 << irq);
533 if (cmd == 5)
534 pPic->priority_add = (irq + 1) & 7;
535 rc = pic_update_irq(pDevIns, pThis, pThisCC);
536 Assert(rc == VINF_SUCCESS);
537 DumpPICState(pPic, "eoi");
538 }
539 break;
540 }
541 case 3:
542 {
543 irq = val & 7;
544 Log(("pic_write: EOI2 for irq %d\n", irq));
545 pPic->isr &= ~(1 << irq);
546 rc = pic_update_irq(pDevIns, pThis, pThisCC);
547 Assert(rc == VINF_SUCCESS);
548 DumpPICState(pPic, "eoi2");
549 break;
550 }
551 case 6:
552 {
553 pPic->priority_add = (val + 1) & 7;
554 Log(("pic_write: lowest priority %d (highest %d)\n", val & 7, pPic->priority_add));
555 rc = pic_update_irq(pDevIns, pThis, pThisCC);
556 Assert(rc == VINF_SUCCESS);
557 break;
558 }
559 case 7:
560 {
561 irq = val & 7;
562 Log(("pic_write: EOI3 for irq %d\n", irq));
563 pPic->isr &= ~(1 << irq);
564 pPic->priority_add = (irq + 1) & 7;
565 rc = pic_update_irq(pDevIns, pThis, pThisCC);
566 Assert(rc == VINF_SUCCESS);
567 DumpPICState(pPic, "eoi3");
568 break;
569 }
570 default:
571 /* no operation */
572 break;
573 }
574 }
575 }
576 else
577 {
578 switch (pPic->init_state)
579 {
580 case 0:
581 /* normal mode */
582 pPic->imr = val;
583 rc = pic_update_irq(pDevIns, pThis, pThisCC);
584 Assert(rc == VINF_SUCCESS);
585 break;
586 case 1:
587 pPic->irq_base = val & 0xf8;
588 pPic->init_state = 2;
589 Log(("pic_write: set irq base to %x\n", pPic->irq_base));
590 break;
591 case 2:
592 if (pPic->init4)
593 pPic->init_state = 3;
594 else
595 pPic->init_state = 0;
596 break;
597 case 3:
598 pPic->special_fully_nested_mode = (val >> 4) & 1;
599 pPic->auto_eoi = (val >> 1) & 1;
600 pPic->init_state = 0;
601 Log(("pic_write: special_fully_nested_mode=%d auto_eoi=%d\n", pPic->special_fully_nested_mode, pPic->auto_eoi));
602 break;
603 }
604 }
605 return rc;
606}
607
608
609static uint32_t pic_poll_read(PPDMDEVINS pDevIns, PDEVPIC pThis, PDEVPICCC pThisCC, PPICSTATE pPic, uint32_t addr1)
610{
611 int ret = pic_get_irq(pPic);
612 if (ret >= 0)
613 {
614 if (addr1 >> 7)
615 {
616 Log2(("pic_poll_read: clear slave irq (isr)\n"));
617 pThis->aPics[0].isr &= ~(1 << 2);
618 pThis->aPics[0].irr &= ~(1 << 2);
619 }
620 Log2(("pic_poll_read: clear irq %d (isr)\n", ret));
621 pPic->irr &= ~(1 << ret);
622 pPic->isr &= ~(1 << ret);
623 if (addr1 >> 7 || ret != 2)
624 pic_update_irq(pDevIns, pThis, pThisCC);
625 }
626 else
627 {
628 ret = 0;
629 pic_update_irq(pDevIns, pThis, pThisCC);
630 }
631
632 return ret;
633}
634
635
636static uint32_t pic_ioport_read(PPDMDEVINS pDevIns, PDEVPIC pThis, PDEVPICCC pThisCC, PPICSTATE pPic, uint32_t addr1, int *pRC)
637{
638 unsigned int addr;
639 int ret;
640
641 *pRC = VINF_SUCCESS;
642
643 addr = addr1;
644 addr &= 1;
645 if (pPic->poll)
646 {
647 ret = pic_poll_read(pDevIns, pThis, pThisCC, pPic, addr1);
648 pPic->poll = 0;
649 }
650 else
651 {
652 if (addr == 0)
653 {
654 if (pPic->read_reg_select)
655 ret = pPic->isr;
656 else
657 ret = pPic->irr;
658 }
659 else
660 ret = pPic->imr;
661 }
662 Log(("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret));
663 return ret;
664}
665
666
667
668/* -=-=-=-=-=- I/O ports -=-=-=-=-=- */
669
670/**
671 * @callback_method_impl{FNIOMIOPORTNEWIN}
672 */
673static DECLCALLBACK(VBOXSTRICTRC) picIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
674{
675 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
676 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
677 uint32_t iPic = (uint32_t)(uintptr_t)pvUser;
678
679 Assert(iPic == 0 || iPic == 1);
680 if (cb == 1)
681 {
682 int rc;
683 PIC_LOCK(pDevIns, pThisCC, VINF_IOM_R3_IOPORT_READ);
684 *pu32 = pic_ioport_read(pDevIns, pThis, pThisCC, &RT_SAFE_SUBSCRIPT(pThis->aPics, iPic), offPort, &rc);
685 PIC_UNLOCK(pDevIns, pThisCC);
686 return rc;
687 }
688 return VERR_IOM_IOPORT_UNUSED;
689}
690
691
692/**
693 * @callback_method_impl{FNIOMIOPORTNEWOUT}
694 */
695static DECLCALLBACK(VBOXSTRICTRC) picIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
696{
697 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
698 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
699 uint32_t iPic = (uint32_t)(uintptr_t)pvUser;
700
701 Assert(iPic == 0 || iPic == 1);
702
703 if (cb == 1)
704 {
705 VBOXSTRICTRC rc;
706 PIC_LOCK(pDevIns, pThisCC, VINF_IOM_R3_IOPORT_WRITE);
707 rc = pic_ioport_write(pDevIns, pThis, pThisCC, &RT_SAFE_SUBSCRIPT(pThis->aPics, iPic), offPort, u32);
708 PIC_UNLOCK(pDevIns, pThisCC);
709 return rc;
710 }
711 return VINF_SUCCESS;
712}
713
714
715/**
716 * @callback_method_impl{FNIOMIOPORTNEWIN, ELCR}
717 */
718static DECLCALLBACK(VBOXSTRICTRC) picIOPortElcrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
719{
720 if (cb == 1)
721 {
722 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
723 PPICSTATE pPic = (PPICSTATE)pvUser;
724 PIC_LOCK(pDevIns, pThisCC, VINF_IOM_R3_IOPORT_READ);
725 *pu32 = pPic->elcr;
726 PIC_UNLOCK(pDevIns, pThisCC);
727 return VINF_SUCCESS;
728 }
729 RT_NOREF(offPort);
730 return VERR_IOM_IOPORT_UNUSED;
731}
732
733
734/**
735 * @callback_method_impl{FNIOMIOPORTNEWOUT, ELCR}
736 */
737static DECLCALLBACK(VBOXSTRICTRC) picIOPortElcrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
738{
739 if (cb == 1)
740 {
741 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
742 PPICSTATE pPic = (PPICSTATE)pvUser;
743 PIC_LOCK(pDevIns, pThisCC, VINF_IOM_R3_IOPORT_WRITE);
744 pPic->elcr = u32 & pPic->elcr_mask;
745 PIC_UNLOCK(pDevIns, pThisCC);
746 }
747 RT_NOREF(offPort);
748 return VINF_SUCCESS;
749}
750
751
752#ifdef IN_RING3
753
754/**
755 * @callback_method_impl{FNDBGFHANDLERDEV}
756 */
757static DECLCALLBACK(void) picR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
758{
759 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
760 NOREF(pszArgs);
761
762 /*
763 * Show info.
764 */
765 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
766 {
767 PPICSTATE pPic = &pThis->aPics[i];
768
769 pHlp->pfnPrintf(pHlp, "PIC%d:\n", i);
770 pHlp->pfnPrintf(pHlp, " IMR :%02x ISR :%02x IRR :%02x LIRR:%02x\n",
771 pPic->imr, pPic->isr, pPic->irr, pPic->last_irr);
772 pHlp->pfnPrintf(pHlp, " Base:%02x PriAdd:%02x RegSel:%02x\n",
773 pPic->irq_base, pPic->priority_add, pPic->read_reg_select);
774 pHlp->pfnPrintf(pHlp, " Poll:%02x SpMask:%02x IState:%02x\n",
775 pPic->poll, pPic->special_mask, pPic->init_state);
776 pHlp->pfnPrintf(pHlp, " AEOI:%02x Rotate:%02x FNest :%02x Ini4:%02x\n",
777 pPic->auto_eoi, pPic->rotate_on_auto_eoi,
778 pPic->special_fully_nested_mode, pPic->init4);
779 pHlp->pfnPrintf(pHlp, " ELCR:%02x ELMask:%02x\n", pPic->elcr, pPic->elcr_mask);
780 }
781}
782
783
784/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
785
786/**
787 * @callback_method_impl{FNSSMDEVSAVEEXEC}
788 */
789static DECLCALLBACK(int) picR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
790{
791 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
792 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
793
794 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
795 {
796 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].last_irr);
797 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].irr);
798 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].imr);
799 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].isr);
800 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].priority_add);
801 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].irq_base);
802 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].read_reg_select);
803 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].poll);
804 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].special_mask);
805 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].init_state);
806 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].auto_eoi);
807 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].rotate_on_auto_eoi);
808 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].special_fully_nested_mode);
809 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].init4);
810 pHlp->pfnSSMPutU8(pSSM, pThis->aPics[i].elcr);
811 }
812 return VINF_SUCCESS;
813}
814
815
816/**
817 * @callback_method_impl{FNSSMDEVLOADEXEC}
818 */
819static DECLCALLBACK(int) picR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
820{
821 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
822 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
823
824 if (uVersion != 1)
825 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
826 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
827
828 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
829 {
830 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].last_irr);
831 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].irr);
832 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].imr);
833 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].isr);
834 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].priority_add);
835 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].irq_base);
836 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].read_reg_select);
837 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].poll);
838 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].special_mask);
839 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].init_state);
840 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].auto_eoi);
841 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].rotate_on_auto_eoi);
842 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].special_fully_nested_mode);
843 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].init4);
844 pHlp->pfnSSMGetU8(pSSM, &pThis->aPics[i].elcr);
845 }
846
847 /* Note! PDM will restore the VMCPU_FF_INTERRUPT_PIC state. */
848 return VINF_SUCCESS;
849}
850
851
852/* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */
853
854/**
855 * @interface_method_impl{PDMDEVREG,pfnReset}
856 */
857static DECLCALLBACK(void) picR3Reset(PPDMDEVINS pDevIns)
858{
859 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
860 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
861 unsigned i;
862 LogFlow(("picR3Reset:\n"));
863 pThisCC->pPicHlp->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
864
865 for (i = 0; i < RT_ELEMENTS(pThis->aPics); i++)
866 pic_reset(&pThis->aPics[i]);
867
868 PIC_UNLOCK(pDevIns, pThisCC);
869}
870
871
872/**
873 * @interface_method_impl{PDMDEVREG,pfnRelocate}
874 */
875static DECLCALLBACK(void) picR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
876{
877 PDEVPICRC pThisRC = PDMINS_2_DATA_RC(pDevIns, PDEVPICRC);
878 pThisRC->pPicHlp += offDelta;
879}
880
881
882/**
883 * @interface_method_impl{PDMDEVREG,pfnConstruct}
884 */
885static DECLCALLBACK(int) picR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
886{
887 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
888 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
889 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
890 int rc;
891 RT_NOREF(iInstance, pCfg);
892
893 Assert(iInstance == 0);
894
895 /*
896 * Validate and read configuration.
897 */
898 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "", "");
899 Log(("DevPIC: fRCEnabled=%RTbool fR0Enabled=%RTbool\n", pDevIns->fRCEnabled, pDevIns->fR0Enabled));
900
901 /*
902 * Init the data.
903 */
904 Assert(RT_ELEMENTS(pThis->aPics) == 2);
905 pThis->aPics[0].elcr_mask = 0xf8;
906 pThis->aPics[1].elcr_mask = 0xde;
907 pThis->aPics[0].idxPic = 0;
908 pThis->aPics[1].idxPic = 1;
909 pThis->cRelLogEntries = 0;
910
911 /*
912 * Register us as the PIC with PDM.
913 */
914 PDMPICREG PicReg;
915 PicReg.u32Version = PDM_PICREG_VERSION;
916 PicReg.pfnSetIrq = picSetIrq;
917 PicReg.pfnGetInterrupt = picGetInterrupt;
918 PicReg.u32TheEnd = PDM_PICREG_VERSION;
919 rc = PDMDevHlpPICRegister(pDevIns, &PicReg, &pThisCC->pPicHlp);
920 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpPICRegister -> %Rrc\n", rc), rc);
921 AssertReturn(pThisCC->pPicHlp->u32Version == PDM_PICHLP_VERSION, VERR_VERSION_MISMATCH);
922 AssertReturn(pThisCC->pPicHlp->u32TheEnd == PDM_PICHLP_VERSION, VERR_VERSION_MISMATCH);
923
924 /*
925 * Since the PIC helper interface provides access to the PDM lock,
926 * we need no device level critical section.
927 */
928 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
929 AssertRCReturn(rc, rc);
930
931 /*
932 * Register I/O ports and save state.
933 */
934 rc = PDMDevHlpIoPortCreateUAndMap(pDevIns, 0x20 /*uPort*/, 2 /*cPorts*/, picIOPortWrite, picIOPortRead, (void *)0,
935 "i8259 PIC #0", NULL /*paExtDesc*/, &pThis->aPics[0].hIoPorts0);
936 AssertRCReturn(rc, rc);
937 rc = PDMDevHlpIoPortCreateUAndMap(pDevIns, 0xa0 /*uPort*/, 2 /*cPorts*/, picIOPortWrite, picIOPortRead, (void *)1,
938 "i8259 PIC #1", NULL /*paExtDesc*/, &pThis->aPics[1].hIoPorts0);
939 AssertRCReturn(rc, rc);
940
941
942 rc = PDMDevHlpIoPortCreateUAndMap(pDevIns, 0x4d0 /*uPort*/, 1 /*cPorts*/, picIOPortElcrWrite, picIOPortElcrRead,
943 &pThis->aPics[0], "i8259 PIC #0 - elcr", NULL /*paExtDesc*/, &pThis->aPics[0].hIoPorts1);
944 AssertRCReturn(rc, rc);
945 rc = PDMDevHlpIoPortCreateUAndMap(pDevIns, 0x4d1 /*uPort*/, 1 /*cPorts*/, picIOPortElcrWrite, picIOPortElcrRead,
946 &pThis->aPics[1], "i8259 PIC #1 - elcr", NULL /*paExtDesc*/, &pThis->aPics[1].hIoPorts1);
947 AssertRCReturn(rc, rc);
948
949 /*
950 * Saved state.
951 */
952 rc = PDMDevHlpSSMRegister(pDevIns, 1 /* uVersion */, sizeof(*pThis), picR3SaveExec, picR3LoadExec);
953 AssertRCReturn(rc, rc);
954
955 /*
956 * Register the info item.
957 */
958 PDMDevHlpDBGFInfoRegister(pDevIns, "pic", "PIC info.", picR3Info);
959
960 /*
961 * Initialize the device state.
962 */
963 picR3Reset(pDevIns);
964
965# ifdef VBOX_WITH_STATISTICS
966 /*
967 * Statistics.
968 */
969 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqRZ, STAMTYPE_COUNTER, "SetIrqRZ", STAMUNIT_OCCURENCES, "Number of PIC SetIrq calls in ring-0/raw-mode.");
970 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqR3, STAMTYPE_COUNTER, "SetIrqR3", STAMUNIT_OCCURENCES, "Number of PIC SetIrq calls in ring-3.");
971
972 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveIRQ2, STAMTYPE_COUNTER, "Masked/ActiveIRQ2", STAMUNIT_OCCURENCES, "Number of cleared irq 2.");
973 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveMasterIRQ, STAMTYPE_COUNTER, "Masked/ActiveMaster", STAMUNIT_OCCURENCES, "Number of cleared master irqs.");
974 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatClearedActiveSlaveIRQ, STAMTYPE_COUNTER, "Masked/ActiveSlave", STAMUNIT_OCCURENCES, "Number of cleared slave irqs.");
975# endif
976
977 return VINF_SUCCESS;
978}
979
980#else /* !IN_RING3 */
981
982/**
983 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
984 */
985static DECLCALLBACK(int) picRZConstruct(PPDMDEVINS pDevIns)
986{
987 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
988 PDEVPIC pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPIC);
989 PDEVPICCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVPICCC);
990
991 /* NOP the critsect: */
992 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
993 AssertRCReturn(rc, rc);
994
995 /* Set up the PIC callbacks: */
996 PDMPICREG PicReg;
997 PicReg.u32Version = PDM_PICREG_VERSION;
998 PicReg.pfnSetIrq = picSetIrq;
999 PicReg.pfnGetInterrupt = picGetInterrupt;
1000 PicReg.u32TheEnd = PDM_PICREG_VERSION;
1001 rc = PDMDevHlpPICSetUpContext(pDevIns, &PicReg, &pThisCC->pPicHlp);
1002 AssertLogRelMsgRCReturn(rc, ("PDMDevHlpPICSetUpContext -> %Rrc\n", rc), rc);
1003 AssertPtrReturn(pThisCC->pPicHlp, VERR_INTERNAL_ERROR_3);
1004 AssertReturn(pThisCC->pPicHlp->u32Version == PDM_PICHLP_VERSION, VERR_VERSION_MISMATCH);
1005 AssertReturn(pThisCC->pPicHlp->u32TheEnd == PDM_PICHLP_VERSION, VERR_VERSION_MISMATCH);
1006
1007 /* I/O port callbacks: */
1008 Assert(RT_ELEMENTS(pThis->aPics) == 2);
1009 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->aPics[0].hIoPorts0, picIOPortWrite, picIOPortRead, (void *)0);
1010 AssertRCReturn(rc, rc);
1011 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->aPics[1].hIoPorts0, picIOPortWrite, picIOPortRead, (void *)1);
1012 AssertRCReturn(rc, rc);
1013
1014 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->aPics[0].hIoPorts1, picIOPortElcrWrite, picIOPortElcrRead, &pThis->aPics[0]);
1015 AssertRCReturn(rc, rc);
1016 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->aPics[1].hIoPorts1, picIOPortElcrWrite, picIOPortElcrRead, &pThis->aPics[1]);
1017 AssertRCReturn(rc, rc);
1018
1019 return VINF_SUCCESS;
1020}
1021
1022#endif /* !IN_RING3 */
1023
1024/**
1025 * The device registration structure.
1026 */
1027const PDMDEVREG g_DeviceI8259 =
1028{
1029 /* .u32Version = */ PDM_DEVREG_VERSION,
1030 /* .uReserved0 = */ 0,
1031 /* .szName = */ "i8259",
1032 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
1033 | PDM_DEVREG_FLAGS_REQUIRE_R0 | PDM_DEVREG_FLAGS_REQUIRE_RC,
1034 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
1035 /* .cMaxInstances = */ 1,
1036 /* .uSharedVersion = */ 42,
1037 /* .cbInstanceShared = */ sizeof(DEVPIC),
1038 /* .cbInstanceCC = */ sizeof(DEVPICCC),
1039 /* .cbInstanceRC = */ sizeof(DEVPICRC),
1040 /* .cMaxPciDevices = */ 0,
1041 /* .cMaxMsixVectors = */ 0,
1042 /* .pszDescription = */ "Intel 8259 Programmable Interrupt Controller (PIC) Device.",
1043#if defined(IN_RING3)
1044 /* .pszRCMod = */ "VBoxDDRC.rc",
1045 /* .pszR0Mod = */ "VBoxDDR0.r0",
1046 /* .pfnConstruct = */ picR3Construct,
1047 /* .pfnDestruct = */ NULL,
1048 /* .pfnRelocate = */ picR3Relocate,
1049 /* .pfnMemSetup = */ NULL,
1050 /* .pfnPowerOn = */ NULL,
1051 /* .pfnReset = */ picR3Reset,
1052 /* .pfnSuspend = */ NULL,
1053 /* .pfnResume = */ NULL,
1054 /* .pfnAttach = */ NULL,
1055 /* .pfnDetach = */ NULL,
1056 /* .pfnQueryInterface = */ NULL,
1057 /* .pfnInitComplete = */ NULL,
1058 /* .pfnPowerOff = */ NULL,
1059 /* .pfnSoftReset = */ NULL,
1060 /* .pfnReserved0 = */ NULL,
1061 /* .pfnReserved1 = */ NULL,
1062 /* .pfnReserved2 = */ NULL,
1063 /* .pfnReserved3 = */ NULL,
1064 /* .pfnReserved4 = */ NULL,
1065 /* .pfnReserved5 = */ NULL,
1066 /* .pfnReserved6 = */ NULL,
1067 /* .pfnReserved7 = */ NULL,
1068#elif defined(IN_RING0)
1069 /* .pfnEarlyConstruct = */ NULL,
1070 /* .pfnConstruct = */ picRZConstruct,
1071 /* .pfnDestruct = */ NULL,
1072 /* .pfnFinalDestruct = */ NULL,
1073 /* .pfnRequest = */ NULL,
1074 /* .pfnReserved0 = */ NULL,
1075 /* .pfnReserved1 = */ NULL,
1076 /* .pfnReserved2 = */ NULL,
1077 /* .pfnReserved3 = */ NULL,
1078 /* .pfnReserved4 = */ NULL,
1079 /* .pfnReserved5 = */ NULL,
1080 /* .pfnReserved6 = */ NULL,
1081 /* .pfnReserved7 = */ NULL,
1082#elif defined(IN_RC)
1083 /* .pfnConstruct = */ picRZConstruct,
1084 /* .pfnReserved0 = */ NULL,
1085 /* .pfnReserved1 = */ NULL,
1086 /* .pfnReserved2 = */ NULL,
1087 /* .pfnReserved3 = */ NULL,
1088 /* .pfnReserved4 = */ NULL,
1089 /* .pfnReserved5 = */ NULL,
1090 /* .pfnReserved6 = */ NULL,
1091 /* .pfnReserved7 = */ NULL,
1092#else
1093# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1094#endif
1095 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1096};
1097
1098#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1099
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