VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/DevPciIch9.cpp@ 36678

Last change on this file since 36678 was 36678, checked in by vboxsync, 14 years ago

PCI: cleanups, R3 mapping work

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 107.6 KB
Line 
1/* $Id: DevPciIch9.cpp 36678 2011-04-15 09:24:13Z vboxsync $ */
2/** @file
3 * DevPCI - ICH9 southbridge PCI bus emulation device.
4 */
5
6/*
7 * Copyright (C) 2010-2011 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/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_PCI
22/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
23#define PCI_INCLUDE_PRIVATE
24#define PCIBus ICH9PCIBus
25#include <VBox/pci.h>
26#include <VBox/msi.h>
27#include <VBox/vmm/pdmdev.h>
28#include <iprt/asm.h>
29#include <iprt/assert.h>
30#include <iprt/string.h>
31#ifdef IN_RING3
32#include <iprt/alloc.h>
33#endif
34
35#include "VBoxDD.h"
36
37#include "MsiCommon.h"
38
39
40/*******************************************************************************
41* Structures and Typedefs *
42*******************************************************************************/
43/**
44 * PCI Bus instance.
45 */
46typedef struct ICH9PCIBus
47{
48 /** Bus number. */
49 int32_t iBus;
50 /** Number of bridges attached to the bus. */
51 uint32_t cBridges;
52
53 /** Array of PCI devices. We assume 32 slots, each with 8 functions. */
54 R3PTRTYPE(PPCIDEVICE) apDevices[256];
55 /** Array of bridges attached to the bus. */
56 R3PTRTYPE(PPCIDEVICE *) papBridgesR3;
57
58 /** R3 pointer to the device instance. */
59 PPDMDEVINSR3 pDevInsR3;
60 /** Pointer to the PCI R3 helpers. */
61 PCPDMPCIHLPR3 pPciHlpR3;
62
63 /** R0 pointer to the device instance. */
64 PPDMDEVINSR0 pDevInsR0;
65 /** Pointer to the PCI R0 helpers. */
66 PCPDMPCIHLPR0 pPciHlpR0;
67
68 /** RC pointer to the device instance. */
69 PPDMDEVINSRC pDevInsRC;
70 /** Pointer to the PCI RC helpers. */
71 PCPDMPCIHLPRC pPciHlpRC;
72
73 /** The PCI device for the PCI bridge. */
74 PCIDEVICE aPciDev;
75
76} ICH9PCIBUS, *PICH9PCIBUS;
77
78
79/** @def PCI_APIC_IRQ_PINS
80 * Number of pins for interrupts if the APIC is used.
81 */
82#define PCI_APIC_IRQ_PINS 8
83
84/**
85 * PCI Globals - This is the host-to-pci bridge and the root bus.
86 */
87typedef struct
88{
89 /** R3 pointer to the device instance. */
90 PPDMDEVINSR3 pDevInsR3;
91 /** R0 pointer to the device instance. */
92 PPDMDEVINSR0 pDevInsR0;
93 /** RC pointer to the device instance. */
94 PPDMDEVINSRC pDevInsRC;
95
96#if HC_ARCH_BITS == 64
97 uint32_t Alignment0;
98#endif
99
100 /** Config register. */
101 uint32_t uConfigReg;
102
103 /** I/O APIC irq levels */
104 volatile uint32_t uaPciApicIrqLevels[PCI_APIC_IRQ_PINS];
105
106#if 1 /* Will be moved into the BIOS soon. */
107 /** The next I/O port address which the PCI BIOS will use. */
108 uint32_t uPciBiosIo;
109 /** The next MMIO address which the PCI BIOS will use. */
110 uint32_t uPciBiosMmio;
111 /** Actual bus number. */
112 uint8_t uBus;
113#endif
114 /* Physical address of PCI config space MMIO region */
115 uint64_t u64PciConfigMMioAddress;
116 /* Length of PCI config space MMIO region */
117 uint64_t u64PciConfigMMioLength;
118
119 /** PCI bus which is attached to the host-to-PCI bridge. */
120 ICH9PCIBUS aPciBus;
121} ICH9PCIGLOBALS, *PICH9PCIGLOBALS;
122
123
124typedef struct
125{
126 uint8_t iBus;
127 uint8_t iDeviceFunc;
128 uint16_t iRegister;
129} PciAddress;
130
131#ifndef VBOX_DEVICE_STRUCT_TESTCASE
132
133/*******************************************************************************
134* Defined Constants And Macros *
135*******************************************************************************/
136
137/** @def VBOX_ICH9PCI_SAVED_STATE_VERSION
138 * Saved state version of the ICH9 PCI bus device.
139 */
140#define VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI 1
141#define VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI 2
142#define VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI
143
144/** Converts a bus instance pointer to a device instance pointer. */
145#define PCIBUS_2_DEVINS(pPciBus) ((pPciBus)->CTX_SUFF(pDevIns))
146/** Converts a device instance pointer to a ICH9PCIGLOBALS pointer. */
147#define DEVINS_2_PCIGLOBALS(pDevIns) ((PICH9PCIGLOBALS)(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS)))
148/** Converts a device instance pointer to a PCIBUS pointer. */
149#define DEVINS_2_PCIBUS(pDevIns) ((PICH9PCIBUS)(&PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS)->aPciBus))
150/** Converts a pointer to a PCI root bus instance to a PCIGLOBALS pointer. */
151#define PCIROOTBUS_2_PCIGLOBALS(pPciBus) ( (PICH9PCIGLOBALS)((uintptr_t)(pPciBus) - RT_OFFSETOF(ICH9PCIGLOBALS, aPciBus)) )
152
153/** @def PCI_LOCK
154 * Acquires the PDM lock. This is a NOP if locking is disabled. */
155/** @def PCI_UNLOCK
156 * Releases the PDM lock. This is a NOP if locking is disabled. */
157#define PCI_LOCK(pDevIns, rc) \
158 do { \
159 int rc2 = DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnLock((pDevIns), rc); \
160 if (rc2 != VINF_SUCCESS) \
161 return rc2; \
162 } while (0)
163#define PCI_UNLOCK(pDevIns) \
164 DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
165
166RT_C_DECLS_BEGIN
167
168PDMBOTHCBDECL(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel);
169PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel);
170PDMBOTHCBDECL(int) ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
171PDMBOTHCBDECL(int) ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
172PDMBOTHCBDECL(int) ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
173PDMBOTHCBDECL(int) ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
174PDMBOTHCBDECL(int) ich9pciMcfgMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
175PDMBOTHCBDECL(int) ich9pciMcfgMMIORead (PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
176
177RT_C_DECLS_END
178
179/* Prototypes */
180static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel);
181#ifdef IN_RING3
182static void ich9pcibridgeReset(PPDMDEVINS pDevIns);
183static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName);
184static void ich9pciUpdateMappings(PCIDevice *pDev);
185static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len);
186DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus);
187static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn);
188#endif
189
190// See 7.2.2. PCI Express Enhanced Configuration Mechanism for details of address
191// mapping, we take n=6 approach
192DECLINLINE(void) ich9pciPhysToPciAddr(PICH9PCIGLOBALS pGlobals, RTGCPHYS GCPhysAddr, PciAddress* pPciAddr)
193{
194 pPciAddr->iBus = (GCPhysAddr >> 20) & ((1<<6) - 1);
195 pPciAddr->iDeviceFunc = (GCPhysAddr >> 12) & ((1<<(5+3)) - 1); // 5 bits - device, 3 bits - function
196 pPciAddr->iRegister = (GCPhysAddr >> 0) & ((1<<(6+4+2)) - 1); // 6 bits - register, 4 bits - extended register, 2 bits -Byte Enable
197}
198
199DECLINLINE(void) ich9pciStateToPciAddr(PICH9PCIGLOBALS pGlobals, RTGCPHYS addr, PciAddress* pPciAddr)
200{
201 pPciAddr->iBus = (pGlobals->uConfigReg >> 16) & 0xff;
202 pPciAddr->iDeviceFunc = (pGlobals->uConfigReg >> 8) & 0xff;
203 pPciAddr->iRegister = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
204}
205
206PDMBOTHCBDECL(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel)
207{
208 ich9pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS), pPciDev->devfn, pPciDev, iIrq, iLevel);
209}
210
211PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel)
212{
213 /*
214 * The PCI-to-PCI bridge specification defines how the interrupt pins
215 * are routed from the secondary to the primary bus (see chapter 9).
216 * iIrq gives the interrupt pin the pci device asserted.
217 * We change iIrq here according to the spec and call the SetIrq function
218 * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
219 */
220 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
221 PPCIDEVICE pPciDevBus = pPciDev;
222 int iIrqPinBridge = iIrq;
223 uint8_t uDevFnBridge = 0;
224
225 /* Walk the chain until we reach the host bus. */
226 do
227 {
228 uDevFnBridge = pBus->aPciDev.devfn;
229 iIrqPinBridge = ((pPciDevBus->devfn >> 3) + iIrqPinBridge) & 3;
230
231 /* Get the parent. */
232 pBus = pBus->aPciDev.Int.s.CTX_SUFF(pBus);
233 pPciDevBus = &pBus->aPciDev;
234 } while (pBus->iBus != 0);
235
236 AssertMsgReturnVoid(pBus->iBus == 0, ("This is not the host pci bus iBus=%d\n", pBus->iBus));
237 ich9pciSetIrqInternal(PCIROOTBUS_2_PCIGLOBALS(pBus), uDevFnBridge, pPciDev, iIrqPinBridge, iLevel);
238}
239
240/**
241 * Port I/O Handler for PCI address OUT operations.
242 *
243 * @returns VBox status code.
244 *
245 * @param pDevIns The device instance.
246 * @param pvUser User argument - ignored.
247 * @param uPort Port number used for the OUT operation.
248 * @param u32 The value to output.
249 * @param cb The value size in bytes.
250 */
251PDMBOTHCBDECL(int) ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
252{
253 LogFlow(("ich9pciIOPortAddressWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
254 NOREF(pvUser);
255 if (cb == 4)
256 {
257 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
258
259 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
260 pThis->uConfigReg = u32 & ~3; /* Bits 0-1 are reserved and we silently clear them */
261 PCI_UNLOCK(pDevIns);
262 }
263
264 return VINF_SUCCESS;
265}
266
267/**
268 * Port I/O Handler for PCI address IN operations.
269 *
270 * @returns VBox status code.
271 *
272 * @param pDevIns The device instance.
273 * @param pvUser User argument - ignored.
274 * @param uPort Port number used for the IN operation.
275 * @param pu32 Where to store the result.
276 * @param cb Number of bytes read.
277 */
278PDMBOTHCBDECL(int) ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
279{
280 NOREF(pvUser);
281 if (cb == 4)
282 {
283 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
284 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
285 *pu32 = pThis->uConfigReg;
286 PCI_UNLOCK(pDevIns);
287 LogFlow(("ich9pciIOPortAddressRead: Port=%#x cb=%d -> %#x\n", Port, cb, *pu32));
288 return VINF_SUCCESS;
289 }
290
291 Log(("ich9pciIOPortAddressRead: Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
292
293 return VERR_IOM_IOPORT_UNUSED;
294}
295
296static int ich9pciDataWriteAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pAddr,
297 uint32_t val, int cb, int rcReschedule)
298{
299 int rc = VINF_SUCCESS;
300
301 if (pAddr->iRegister > 0xff)
302 {
303 LogRel(("PCI: attempt to write extended register: %x (%d) <- val\n", pAddr->iRegister, cb, val));
304 goto out;
305 }
306
307 if (pAddr->iBus != 0)
308 {
309 if (pGlobals->aPciBus.cBridges)
310 {
311#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
312 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pAddr->iBus);
313 if (pBridgeDevice)
314 {
315 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
316 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, pAddr->iBus, pAddr->iDeviceFunc, pAddr->iRegister, val, cb);
317 }
318 else
319 {
320 // do nothing, bridge not found
321 }
322#else
323 rc = rcReschedule;
324 goto out;
325#endif
326 }
327 }
328 else
329 {
330 if (pGlobals->aPciBus.apDevices[pAddr->iDeviceFunc])
331 {
332#ifdef IN_RING3
333 R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[pAddr->iDeviceFunc];
334 aDev->Int.s.pfnConfigWrite(aDev, pAddr->iRegister, val, cb);
335#else
336 rc = rcReschedule;
337 goto out;
338#endif
339 }
340 }
341
342 out:
343 Log2(("ich9pciDataWriteAddr: %02x:%02x:%02x reg %x(%d) %x %Rrc\n",
344 pAddr->iBus, pAddr->iDeviceFunc >> 3, pAddr->iDeviceFunc & 0x7, pAddr->iRegister,
345 cb, val, rc));
346
347 return rc;
348}
349
350static int ich9pciDataWrite(PICH9PCIGLOBALS pGlobals, uint32_t addr, uint32_t val, int len)
351{
352 PciAddress aPciAddr;
353
354 LogFlow(("ich9pciDataWrite: config=%08x val=%08x len=%d\n", pGlobals->uConfigReg, val, len));
355
356 if (!(pGlobals->uConfigReg & (1 << 31)))
357 return VINF_SUCCESS;
358
359 if ((pGlobals->uConfigReg & 0x3) != 0)
360 return VINF_SUCCESS;
361
362 /* Compute destination device */
363 ich9pciStateToPciAddr(pGlobals, addr, &aPciAddr);
364
365 return ich9pciDataWriteAddr(pGlobals, &aPciAddr, val, len, VINF_IOM_HC_IOPORT_WRITE);
366}
367
368static void ich9pciNoMem(void* ptr, int cb)
369{
370 for (int i = 0; i < cb; i++)
371 ((uint8_t*)ptr)[i] = 0xff;
372}
373
374/**
375 * Port I/O Handler for PCI data OUT operations.
376 *
377 * @returns VBox status code.
378 *
379 * @param pDevIns The device instance.
380 * @param pvUser User argument - ignored.
381 * @param uPort Port number used for the OUT operation.
382 * @param u32 The value to output.
383 * @param cb The value size in bytes.
384 */
385PDMBOTHCBDECL(int) ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
386{
387 LogFlow(("ich9pciIOPortDataWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
388 NOREF(pvUser);
389 int rc = VINF_SUCCESS;
390 if (!(Port % cb))
391 {
392 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
393 rc = ich9pciDataWrite(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS), Port, u32, cb);
394 PCI_UNLOCK(pDevIns);
395 }
396 else
397 AssertMsgFailed(("Unaligned write to port %#x u32=%#x cb=%d\n", Port, u32, cb));
398 return rc;
399}
400
401static int ich9pciDataReadAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pPciAddr, int cb,
402 uint32_t *pu32, int rcReschedule)
403{
404 int rc = VINF_SUCCESS;
405
406 if (pPciAddr->iRegister > 0xff)
407 {
408 LogRel(("PCI: attempt to read extended register: %x\n", pPciAddr->iRegister));
409 ich9pciNoMem(pu32, cb);
410 goto out;
411 }
412
413
414 if (pPciAddr->iBus != 0)
415 {
416 if (pGlobals->aPciBus.cBridges)
417 {
418#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
419 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pPciAddr->iBus);
420 if (pBridgeDevice)
421 {
422 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
423 *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, pPciAddr->iBus, pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb);
424 }
425 else
426 ich9pciNoMem(pu32, cb);
427#else
428 rc = rcReschedule;
429 goto out;
430#endif
431 } else
432 ich9pciNoMem(pu32, cb);
433 }
434 else
435 {
436 if (pGlobals->aPciBus.apDevices[pPciAddr->iDeviceFunc])
437 {
438#ifdef IN_RING3
439 R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[pPciAddr->iDeviceFunc];
440 *pu32 = aDev->Int.s.pfnConfigRead(aDev, pPciAddr->iRegister, cb);
441#else
442 rc = rcReschedule;
443 goto out;
444#endif
445 }
446 else
447 ich9pciNoMem(pu32, cb);
448 }
449
450 out:
451 Log3(("ich9pciDataReadAddr: %02x:%02x:%02x reg %x(%d) gave %x %Rrc\n",
452 pPciAddr->iBus, pPciAddr->iDeviceFunc >> 3, pPciAddr->iDeviceFunc & 0x7, pPciAddr->iRegister,
453 cb, *pu32, rc));
454
455 return rc;
456}
457
458static int ich9pciDataRead(PICH9PCIGLOBALS pGlobals, uint32_t addr, int cb, uint32_t *pu32)
459{
460 PciAddress aPciAddr;
461
462 LogFlow(("ich9pciDataRead: config=%x cb=%d\n", pGlobals->uConfigReg, cb));
463
464 *pu32 = 0xffffffff;
465
466 if (!(pGlobals->uConfigReg & (1 << 31)))
467 return VINF_SUCCESS;
468
469 if ((pGlobals->uConfigReg & 0x3) != 0)
470 return VINF_SUCCESS;
471
472 /* Compute destination device */
473 ich9pciStateToPciAddr(pGlobals, addr, &aPciAddr);
474
475 return ich9pciDataReadAddr(pGlobals, &aPciAddr, cb, pu32, VINF_IOM_HC_IOPORT_READ);
476}
477
478/**
479 * Port I/O Handler for PCI data IN operations.
480 *
481 * @returns VBox status code.
482 *
483 * @param pDevIns The device instance.
484 * @param pvUser User argument - ignored.
485 * @param uPort Port number used for the IN operation.
486 * @param pu32 Where to store the result.
487 * @param cb Number of bytes read.
488 */
489PDMBOTHCBDECL(int) ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
490{
491 NOREF(pvUser);
492 if (!(Port % cb))
493 {
494 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
495 int rc = ich9pciDataRead(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS), Port, cb, pu32);
496 PCI_UNLOCK(pDevIns);
497 LogFlow(("ich9pciIOPortDataRead: Port=%#x cb=%#x -> %#x (%Rrc)\n", Port, cb, *pu32, rc));
498 return rc;
499 }
500 AssertMsgFailed(("Unaligned read from port %#x cb=%d\n", Port, cb));
501 return VERR_IOM_IOPORT_UNUSED;
502}
503
504/* Compute mapping of PCI slot and IRQ number to APIC interrupt line */
505DECLINLINE(int) ich9pciSlot2ApicIrq(uint8_t uSlot, int irq_num)
506{
507 return (irq_num + uSlot) & 7;
508}
509
510/* return the global irq number corresponding to a given device irq
511 pin. We could also use the bus number to have a more precise
512 mapping. This is the implementation note described in the PCI spec chapter 2.2.6 */
513DECLINLINE(int) ich9pciSlotGetPirq(uint8_t uBus, uint8_t uDevFn, int iIrqNum)
514{
515 int iSlotAddend = (uDevFn >> 3) - 1;
516 return (iIrqNum + iSlotAddend) & 3;
517}
518
519/* irqs corresponding to PCI irqs A-D, must match pci_irq_list in rombios.c */
520static const uint8_t aPciIrqs[4] = { 11, 10, 9, 5 };
521
522/* Add one more level up request on APIC input line */
523DECLINLINE(void) ich9pciApicLevelUp(PICH9PCIGLOBALS pGlobals, int irq_num)
524{
525 ASMAtomicIncU32(&pGlobals->uaPciApicIrqLevels[irq_num]);
526}
527
528/* Remove one level up request on APIC input line */
529DECLINLINE(void) ich9pciApicLevelDown(PICH9PCIGLOBALS pGlobals, int irq_num)
530{
531 ASMAtomicDecU32(&pGlobals->uaPciApicIrqLevels[irq_num]);
532}
533
534static void ich9pciApicSetIrq(PICH9PCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int irq_num1, int iLevel, int iForcedIrq)
535{
536 /* This is only allowed to be called with a pointer to the root bus. */
537 AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
538
539 if (iForcedIrq == -1)
540 {
541 int apic_irq, apic_level;
542 PICH9PCIGLOBALS pGlobals = PCIROOTBUS_2_PCIGLOBALS(pBus);
543 int irq_num = ich9pciSlot2ApicIrq(uDevFn >> 3, irq_num1);
544
545 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
546 ich9pciApicLevelUp(pGlobals, irq_num);
547 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
548 ich9pciApicLevelDown(pGlobals, irq_num);
549
550 apic_irq = irq_num + 0x10;
551 apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
552 Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d\n",
553 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
554 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level);
555
556 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
557 {
558 /*
559 * we raised it few lines above, as PDM_IRQ_LEVEL_FLIP_FLOP has
560 * PDM_IRQ_LEVEL_HIGH bit set
561 */
562 ich9pciApicLevelDown(pGlobals, irq_num);
563 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
564 apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
565 Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d (flop)\n",
566 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
567 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level);
568 }
569 } else {
570 Log3(("ich9pciApicSetIrq: (forced) %s: irq_num1=%d level=%d acpi_irq=%d\n",
571 R3STRING(pPciDev->name), irq_num1, iLevel, iForcedIrq));
572 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), iForcedIrq, iLevel);
573 }
574}
575
576static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel)
577{
578
579 if (PCIDevIsIntxDisabled(pPciDev))
580 {
581 if (MsiIsEnabled(pPciDev))
582 {
583 PPDMDEVINS pDevIns = pGlobals->aPciBus.CTX_SUFF(pDevIns);
584 MsiNotify(pDevIns, pGlobals->aPciBus.CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel);
585 }
586
587 if (MsixIsEnabled(pPciDev))
588 {
589 PPDMDEVINS pDevIns = pGlobals->aPciBus.CTX_SUFF(pDevIns);
590 MsixNotify(pDevIns, pGlobals->aPciBus.CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel);
591 }
592 return;
593 }
594
595 PICH9PCIBUS pBus = &pGlobals->aPciBus;
596 const bool fIsAcpiDevice = PCIDevGetDeviceId(pPciDev) == 0x7113;
597
598 /* Check if the state changed. */
599 if (pPciDev->Int.s.uIrqPinState != iLevel)
600 {
601 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
602
603 /* Send interrupt to I/O APIC only now. */
604 if (fIsAcpiDevice)
605 /*
606 * ACPI needs special treatment since SCI is hardwired and
607 * should not be affected by PCI IRQ routing tables at the
608 * same time SCI IRQ is shared in PCI sense hence this
609 * kludge (i.e. we fetch the hardwired value from ACPIs
610 * PCI device configuration space).
611 */
612 ich9pciApicSetIrq(pBus, uDevFn, pPciDev, -1, iLevel, PCIDevGetInterruptLine(pPciDev));
613 else
614 ich9pciApicSetIrq(pBus, uDevFn, pPciDev, iIrq, iLevel, -1);
615 }
616}
617
618PDMBOTHCBDECL(int) ich9pciMcfgMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
619{
620 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
621 PciAddress aDest;
622 uint32_t u32 = 0;
623
624 Log2(("ich9pciMcfgMMIOWrite: %RGp(%d) \n", GCPhysAddr, cb));
625
626 PCI_LOCK(pDevIns, VINF_IOM_HC_MMIO_WRITE);
627
628 ich9pciPhysToPciAddr(pGlobals, GCPhysAddr, &aDest);
629
630 switch (cb)
631 {
632 case 1:
633 u32 = *(uint8_t*)pv;
634 break;
635 case 2:
636 u32 = *(uint16_t*)pv;
637 break;
638 case 4:
639 u32 = *(uint32_t*)pv;
640 break;
641 default:
642 Assert(false);
643 break;
644 }
645 int rc = ich9pciDataWriteAddr(pGlobals, &aDest, u32, cb, VINF_IOM_HC_MMIO_WRITE);
646 PCI_UNLOCK(pDevIns);
647
648 return rc;
649}
650
651PDMBOTHCBDECL(int) ich9pciMcfgMMIORead (PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
652{
653 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
654 PciAddress aDest;
655 uint32_t rv;
656
657 LogFlow(("ich9pciMcfgMMIORead: %RGp(%d) \n", GCPhysAddr, cb));
658
659 PCI_LOCK(pDevIns, VINF_IOM_HC_MMIO_READ);
660
661 ich9pciPhysToPciAddr(pGlobals, GCPhysAddr, &aDest);
662
663 int rc = ich9pciDataReadAddr(pGlobals, &aDest, cb, &rv, VINF_IOM_HC_MMIO_READ);
664
665 if (RT_SUCCESS(rc))
666 {
667 switch (cb)
668 {
669 case 1:
670 *(uint8_t*)pv = (uint8_t)rv;
671 break;
672 case 2:
673 *(uint16_t*)pv = (uint16_t)rv;
674 break;
675 case 4:
676 *(uint32_t*)pv = (uint32_t)rv;
677 break;
678 default:
679 Assert(false);
680 break;
681 }
682 }
683 PCI_UNLOCK(pDevIns);
684
685 return rc;
686}
687
688#ifdef IN_RING3
689
690DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus)
691{
692 /* Search for a fitting bridge. */
693 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
694 {
695 /*
696 * Examine secondary and subordinate bus number.
697 * If the target bus is in the range we pass the request on to the bridge.
698 */
699 PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
700 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
701 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
702 uint32_t uSecondary = PCIDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
703 uint32_t uSubordinate = PCIDevGetByte(pBridge, VBOX_PCI_SUBORDINATE_BUS);
704 Log3(("ich9pciFindBridge on bus %p, bridge %d: %d in %d..%d\n", pBus, iBridge, iBus, uSecondary, uSubordinate));
705 if (iBus >= uSecondary && iBus <= uSubordinate)
706 return pBridge;
707 }
708
709 /* Nothing found. */
710 return NULL;
711}
712
713static uint32_t ich9pciGetCfg(PCIDevice* aDev, int32_t iRegister, int cb)
714{
715 return aDev->Int.s.pfnConfigRead(aDev, iRegister, cb);
716}
717
718static uint8_t ich9pciGetByte(PCIDevice* aDev, int32_t iRegister)
719{
720 return (uint8_t)ich9pciGetCfg(aDev, iRegister, 1);
721}
722
723static uint16_t ich9pciGetWord(PCIDevice* aDev, int32_t iRegister)
724{
725 return (uint16_t)ich9pciGetCfg(aDev, iRegister, 2);
726}
727
728static uint32_t ich9pciGetDWord(PCIDevice* aDev, int32_t iRegister)
729{
730 return (uint32_t)ich9pciGetCfg(aDev, iRegister, 4);
731}
732
733DECLINLINE(uint32_t) ich9pciGetRegionReg(int iRegion)
734{
735 return (iRegion == VBOX_PCI_ROM_SLOT) ?
736 VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4);
737}
738
739#define INVALID_PCI_ADDRESS ~0U
740
741static int ich9pciUnmapRegion(PPCIDEVICE pDev, int iRegion)
742{
743 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
744 int rc = VINF_SUCCESS;
745 PICH9PCIBUS pBus = pDev->Int.s.CTX_SUFF(pBus);
746
747 Assert (pRegion->size != 0);
748
749 if (pRegion->addr != INVALID_PCI_ADDRESS)
750 {
751 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
752 {
753 /* Port IO */
754 rc = PDMDevHlpIOPortDeregister(pDev->pDevIns, pRegion->addr, pRegion->size);
755 AssertRC(rc);
756 }
757 else
758 {
759 RTGCPHYS GCPhysBase = pRegion->addr;
760 if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, pDev->pDevIns, GCPhysBase))
761 {
762 /* unmap it. */
763 rc = pRegion->map_func(pDev, iRegion, NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
764 AssertRC(rc);
765 rc = PDMDevHlpMMIO2Unmap(pDev->pDevIns, iRegion, GCPhysBase);
766 }
767 else
768 rc = PDMDevHlpMMIODeregister(pDev->pDevIns, GCPhysBase, pRegion->size);
769 }
770
771 pRegion->addr = INVALID_PCI_ADDRESS;
772 }
773
774 return rc;
775}
776
777static void ich9pciUpdateMappings(PCIDevice* pDev)
778{
779 PICH9PCIBUS pBus = pDev->Int.s.CTX_SUFF(pBus);
780 uint64_t uLast, uNew;
781
782 int iCmd = ich9pciGetWord(pDev, VBOX_PCI_COMMAND);
783 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
784 {
785 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
786 uint32_t uConfigReg = ich9pciGetRegionReg(iRegion);
787 int64_t iRegionSize = pRegion->size;
788 int rc;
789
790 if (iRegionSize == 0)
791 continue;
792
793 bool f64Bit = (pRegion->type & PCI_ADDRESS_SPACE_BAR64) != 0;
794
795 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
796 {
797 /* port IO region */
798 if (iCmd & PCI_COMMAND_IOACCESS)
799 {
800 /* IO access allowed */
801 uNew = ich9pciGetDWord(pDev, uConfigReg);
802 uNew &= ~(iRegionSize - 1);
803 uLast = uNew + iRegionSize - 1;
804 /* only 64K ioports on PC */
805 if (uLast <= uNew || uNew == 0 || uLast >= 0x10000)
806 uNew = INVALID_PCI_ADDRESS;
807 } else
808 uNew = INVALID_PCI_ADDRESS;
809 }
810 else
811 {
812 /* MMIO region */
813 if (iCmd & PCI_COMMAND_MEMACCESS)
814 {
815 uNew = ich9pciGetDWord(pDev, uConfigReg);
816
817 if (f64Bit)
818 {
819 uNew |= ((uint64_t)ich9pciGetDWord(pDev, uConfigReg+4)) << 32;
820 if (uNew > UINT64_C(0x0000010000000000))
821 {
822 /* Workaround for REM being unhapping with mapping very lange 64-bit addresses */
823 Log(("Ignoring too 64-bit BAR: %llx\n", uNew));
824 uNew = INVALID_PCI_ADDRESS;
825 }
826 }
827
828 /* the ROM slot has a specific enable bit */
829 if (iRegion == PCI_ROM_SLOT && !(uNew & 1))
830 uNew = INVALID_PCI_ADDRESS;
831 else
832 {
833 uNew &= ~(iRegionSize - 1);
834 uLast = uNew + iRegionSize - 1;
835 /* NOTE: we do not support wrapping */
836 /* XXX: as we cannot support really dynamic
837 mappings, we handle specific values as invalid
838 mappings. */
839 if (uLast <= uNew || uNew == 0 || uLast == INVALID_PCI_ADDRESS)
840 uNew = INVALID_PCI_ADDRESS;
841 }
842 } else
843 uNew = INVALID_PCI_ADDRESS;
844 }
845 /* now do the real mapping */
846 if (uNew != pRegion->addr)
847 {
848 if (pRegion->addr != INVALID_PCI_ADDRESS)
849 ich9pciUnmapRegion(pDev, iRegion);
850
851 pRegion->addr = uNew;
852 if (pRegion->addr != INVALID_PCI_ADDRESS)
853 {
854
855 /* finally, map the region */
856 rc = pRegion->map_func(pDev, iRegion,
857 pRegion->addr, pRegion->size,
858 (PCIADDRESSSPACE)(pRegion->type));
859 AssertRC(rc);
860 }
861 }
862 }
863}
864
865static DECLCALLBACK(int) ich9pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
866{
867 PICH9PCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
868
869 /*
870 * Check input.
871 */
872 if ( !pszName
873 || !pPciDev
874 || iDev >= (int)RT_ELEMENTS(pBus->apDevices)
875 )
876 {
877 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
878 return VERR_INVALID_PARAMETER;
879 }
880
881 /*
882 * Register the device.
883 */
884 return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
885}
886
887
888static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg)
889{
890 int rc;
891
892 rc = MsiInit(pPciDev, pMsiReg);
893 if (RT_FAILURE(rc))
894 return rc;
895
896 rc = MsixInit(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp), pPciDev, pMsiReg);
897 if (RT_FAILURE(rc))
898 return rc;
899
900 return VINF_SUCCESS;
901}
902
903
904static DECLCALLBACK(int) ich9pcibridgeRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
905{
906
907 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
908
909 /*
910 * Check input.
911 */
912 if ( !pszName
913 || !pPciDev
914 || iDev >= (int)RT_ELEMENTS(pBus->apDevices))
915 {
916 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
917 return VERR_INVALID_PARAMETER;
918 }
919
920 /*
921 * Register the device.
922 */
923 return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
924}
925
926static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
927{
928 /*
929 * Validate.
930 */
931 AssertMsgReturn( enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR32)
932 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR32)
933 || enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64)
934 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR64)
935 || enmType == PCI_ADDRESS_SPACE_IO
936 ,
937 ("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType),
938 VERR_INVALID_PARAMETER);
939 AssertMsgReturn((unsigned)iRegion < PCI_NUM_REGIONS,
940 ("Invalid iRegion=%d PCI_NUM_REGIONS=%d\n", iRegion, PCI_NUM_REGIONS),
941 VERR_INVALID_PARAMETER);
942 int iLastSet = ASMBitLastSetU32(cbRegion);
943 AssertMsgReturn( iLastSet != 0
944 && RT_BIT_32(iLastSet - 1) == cbRegion,
945 ("Invalid cbRegion=%#x iLastSet=%#x (not a power of 2 or 0)\n", cbRegion, iLastSet),
946 VERR_INVALID_PARAMETER);
947
948 Log(("ich9pciIORegionRegister: %s region %d size %d type %x\n",
949 pPciDev->name, iRegion, cbRegion, enmType));
950
951 /*
952 * Register the I/O region.
953 */
954 PPCIIOREGION pRegion = &pPciDev->Int.s.aIORegions[iRegion];
955 pRegion->addr = INVALID_PCI_ADDRESS;
956 pRegion->size = cbRegion;
957 pRegion->type = enmType;
958 pRegion->map_func = pfnCallback;
959
960 /* Set type in the PCI config space. */
961 uint32_t u32Value = ((uint32_t)enmType) & (PCI_ADDRESS_SPACE_IO | PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_MEM_PREFETCH);
962 PCIDevSetDWord(pPciDev, ich9pciGetRegionReg(iRegion), u32Value);
963
964 return VINF_SUCCESS;
965}
966
967static DECLCALLBACK(void) ich9pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
968 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
969{
970 if (ppfnReadOld)
971 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
972 pPciDev->Int.s.pfnConfigRead = pfnRead;
973
974 if (ppfnWriteOld)
975 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
976 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
977}
978
979/**
980 * Saves a state of the PCI device.
981 *
982 * @returns VBox status code.
983 * @param pDevIns Device instance of the PCI Bus.
984 * @param pPciDev Pointer to PCI device.
985 * @param pSSM The handle to save the state to.
986 */
987static DECLCALLBACK(int) ich9pciGenericSaveExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
988{
989 Assert(!pciDevIsPassthrough(pPciDev));
990 return SSMR3PutMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
991}
992
993static int ich9pciR3CommonSaveExec(PICH9PCIBUS pBus, PSSMHANDLE pSSM)
994{
995 /*
996 * Iterate thru all the devices.
997 */
998 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
999 {
1000 PPCIDEVICE pDev = pBus->apDevices[i];
1001 if (pDev)
1002 {
1003 /* Device position */
1004 SSMR3PutU32(pSSM, i);
1005 /* PCI config registers */
1006 SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
1007
1008 /* Device flags */
1009 int rc = SSMR3PutU32(pSSM, pDev->Int.s.fFlags);
1010 if (RT_FAILURE(rc))
1011 return rc;
1012
1013 /* IRQ pin state */
1014 rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
1015 if (RT_FAILURE(rc))
1016 return rc;
1017
1018 /* MSI info */
1019 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapOffset);
1020 if (RT_FAILURE(rc))
1021 return rc;
1022 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapSize);
1023 if (RT_FAILURE(rc))
1024 return rc;
1025
1026 /* MSI-X info */
1027 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapOffset);
1028 if (RT_FAILURE(rc))
1029 return rc;
1030 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapSize);
1031 if (RT_FAILURE(rc))
1032 return rc;
1033 /* Save MSI-X page state */
1034 if (pDev->Int.s.u8MsixCapOffset != 0)
1035 {
1036 Assert(pDev->Int.s.pMsixPageR3 != NULL);
1037 SSMR3PutMem(pSSM, pDev->Int.s.pMsixPageR3, 0x1000);
1038 if (RT_FAILURE(rc))
1039 return rc;
1040 }
1041 }
1042 }
1043 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1044}
1045
1046static DECLCALLBACK(int) ich9pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1047{
1048 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1049
1050 /*
1051 * Bus state data.
1052 */
1053 SSMR3PutU32(pSSM, pThis->uConfigReg);
1054
1055 /*
1056 * Save IRQ states.
1057 */
1058 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
1059 SSMR3PutU32(pSSM, pThis->uaPciApicIrqLevels[i]);
1060
1061 SSMR3PutU32(pSSM, ~0); /* separator */
1062
1063 return ich9pciR3CommonSaveExec(&pThis->aPciBus, pSSM);
1064}
1065
1066
1067static DECLCALLBACK(int) ich9pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1068{
1069 PICH9PCIBUS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1070 return ich9pciR3CommonSaveExec(pThis, pSSM);
1071}
1072
1073
1074static void ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, uint32_t u32Value, unsigned cb)
1075{
1076 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1077
1078 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u u32Value=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, u32Value, cb));
1079
1080 /* If the current bus is not the target bus search for the bus which contains the device. */
1081 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1082 {
1083 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1084 if (pBridgeDevice)
1085 {
1086 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
1087 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
1088 }
1089 }
1090 else
1091 {
1092 /* This is the target bus, pass the write to the device. */
1093 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1094 if (pPciDev)
1095 {
1096 Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1097 pPciDev->Int.s.pfnConfigWrite(pPciDev, u32Address, u32Value, cb);
1098 }
1099 }
1100}
1101
1102static uint32_t ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, unsigned cb)
1103{
1104 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1105 uint32_t u32Value;
1106
1107 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
1108
1109 /* If the current bus is not the target bus search for the bus which contains the device. */
1110 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1111 {
1112 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1113 if (pBridgeDevice)
1114 {
1115 AssertPtr( pBridgeDevice->Int.s.pfnBridgeConfigRead);
1116 u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
1117 }
1118 else
1119 ich9pciNoMem(&u32Value, 4);
1120 }
1121 else
1122 {
1123 /* This is the target bus, pass the read to the device. */
1124 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1125 if (pPciDev)
1126 {
1127 u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev, u32Address, cb);
1128 Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1129 }
1130 else
1131 ich9pciNoMem(&u32Value, 4);
1132 }
1133
1134 return u32Value;
1135}
1136
1137
1138/**
1139 * Common routine for restoring the config registers of a PCI device.
1140 *
1141 * @param pDev The PCI device.
1142 * @param pbSrcConfig The configuration register values to be loaded.
1143 * @param fIsBridge Whether this is a bridge device or not.
1144 */
1145static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
1146{
1147 /*
1148 * This table defines the fields for normal devices and bridge devices, and
1149 * the order in which they need to be restored.
1150 */
1151 static const struct PciField
1152 {
1153 uint8_t off;
1154 uint8_t cb;
1155 uint8_t fWritable;
1156 uint8_t fBridge;
1157 const char *pszName;
1158 } s_aFields[] =
1159 {
1160 /* off,cb,fW,fB, pszName */
1161 { VBOX_PCI_VENDOR_ID, 2, 0, 3, "VENDOR_ID" },
1162 { VBOX_PCI_DEVICE_ID, 2, 0, 3, "DEVICE_ID" },
1163 { VBOX_PCI_STATUS, 2, 1, 3, "STATUS" },
1164 { VBOX_PCI_REVISION_ID, 1, 0, 3, "REVISION_ID" },
1165 { VBOX_PCI_CLASS_PROG, 1, 0, 3, "CLASS_PROG" },
1166 { VBOX_PCI_CLASS_SUB, 1, 0, 3, "CLASS_SUB" },
1167 { VBOX_PCI_CLASS_BASE, 1, 0, 3, "CLASS_BASE" },
1168 { VBOX_PCI_CACHE_LINE_SIZE, 1, 1, 3, "CACHE_LINE_SIZE" },
1169 { VBOX_PCI_LATENCY_TIMER, 1, 1, 3, "LATENCY_TIMER" },
1170 { VBOX_PCI_HEADER_TYPE, 1, 0, 3, "HEADER_TYPE" },
1171 { VBOX_PCI_BIST, 1, 1, 3, "BIST" },
1172 { VBOX_PCI_BASE_ADDRESS_0, 4, 1, 3, "BASE_ADDRESS_0" },
1173 { VBOX_PCI_BASE_ADDRESS_1, 4, 1, 3, "BASE_ADDRESS_1" },
1174 { VBOX_PCI_BASE_ADDRESS_2, 4, 1, 1, "BASE_ADDRESS_2" },
1175 { VBOX_PCI_PRIMARY_BUS, 1, 1, 2, "PRIMARY_BUS" }, // fWritable = ??
1176 { VBOX_PCI_SECONDARY_BUS, 1, 1, 2, "SECONDARY_BUS" }, // fWritable = ??
1177 { VBOX_PCI_SUBORDINATE_BUS, 1, 1, 2, "SUBORDINATE_BUS" }, // fWritable = ??
1178 { VBOX_PCI_SEC_LATENCY_TIMER, 1, 1, 2, "SEC_LATENCY_TIMER" }, // fWritable = ??
1179 { VBOX_PCI_BASE_ADDRESS_3, 4, 1, 1, "BASE_ADDRESS_3" },
1180 { VBOX_PCI_IO_BASE, 1, 1, 2, "IO_BASE" }, // fWritable = ??
1181 { VBOX_PCI_IO_LIMIT, 1, 1, 2, "IO_LIMIT" }, // fWritable = ??
1182 { VBOX_PCI_SEC_STATUS, 2, 1, 2, "SEC_STATUS" }, // fWritable = ??
1183 { VBOX_PCI_BASE_ADDRESS_4, 4, 1, 1, "BASE_ADDRESS_4" },
1184 { VBOX_PCI_MEMORY_BASE, 2, 1, 2, "MEMORY_BASE" }, // fWritable = ??
1185 { VBOX_PCI_MEMORY_LIMIT, 2, 1, 2, "MEMORY_LIMIT" }, // fWritable = ??
1186 { VBOX_PCI_BASE_ADDRESS_5, 4, 1, 1, "BASE_ADDRESS_5" },
1187 { VBOX_PCI_PREF_MEMORY_BASE, 2, 1, 2, "PREF_MEMORY_BASE" }, // fWritable = ??
1188 { VBOX_PCI_PREF_MEMORY_LIMIT, 2, 1, 2, "PREF_MEMORY_LIMIT" }, // fWritable = ??
1189 { VBOX_PCI_CARDBUS_CIS, 4, 1, 1, "CARDBUS_CIS" }, // fWritable = ??
1190 { VBOX_PCI_PREF_BASE_UPPER32, 4, 1, 2, "PREF_BASE_UPPER32" }, // fWritable = ??
1191 { VBOX_PCI_SUBSYSTEM_VENDOR_ID, 2, 0, 1, "SUBSYSTEM_VENDOR_ID" },// fWritable = !?
1192 { VBOX_PCI_PREF_LIMIT_UPPER32, 4, 1, 2, "PREF_LIMIT_UPPER32" },// fWritable = ??
1193 { VBOX_PCI_SUBSYSTEM_ID, 2, 0, 1, "SUBSYSTEM_ID" }, // fWritable = !?
1194 { VBOX_PCI_ROM_ADDRESS, 4, 1, 1, "ROM_ADDRESS" }, // fWritable = ?!
1195 { VBOX_PCI_IO_BASE_UPPER16, 2, 1, 2, "IO_BASE_UPPER16" }, // fWritable = ?!
1196 { VBOX_PCI_IO_LIMIT_UPPER16, 2, 1, 2, "IO_LIMIT_UPPER16" }, // fWritable = ?!
1197 { VBOX_PCI_CAPABILITY_LIST, 4, 0, 3, "CAPABILITY_LIST" }, // fWritable = !? cb=!?
1198 { VBOX_PCI_RESERVED_38, 4, 1, 1, "RESERVED_38" }, // ???
1199 { VBOX_PCI_ROM_ADDRESS_BR, 4, 1, 2, "ROM_ADDRESS_BR" }, // fWritable = !? cb=!? fBridge=!?
1200 { VBOX_PCI_INTERRUPT_LINE, 1, 1, 3, "INTERRUPT_LINE" }, // fBridge=??
1201 { VBOX_PCI_INTERRUPT_PIN, 1, 0, 3, "INTERRUPT_PIN" }, // fBridge=??
1202 { VBOX_PCI_MIN_GNT, 1, 0, 1, "MIN_GNT" },
1203 { VBOX_PCI_BRIDGE_CONTROL, 2, 1, 2, "BRIDGE_CONTROL" }, // fWritable = !?
1204 { VBOX_PCI_MAX_LAT, 1, 0, 1, "MAX_LAT" },
1205 /* The COMMAND register must come last as it requires the *ADDRESS*
1206 registers to be restored before we pretent to change it from 0 to
1207 whatever value the guest assigned it. */
1208 { VBOX_PCI_COMMAND, 2, 1, 3, "COMMAND" },
1209 };
1210
1211#ifdef RT_STRICT
1212 /* Check that we've got full register coverage. */
1213 uint32_t bmDevice[0x40 / 32];
1214 uint32_t bmBridge[0x40 / 32];
1215 RT_ZERO(bmDevice);
1216 RT_ZERO(bmBridge);
1217 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1218 {
1219 uint8_t off = s_aFields[i].off;
1220 uint8_t cb = s_aFields[i].cb;
1221 uint8_t f = s_aFields[i].fBridge;
1222 while (cb-- > 0)
1223 {
1224 if (f & 1) AssertMsg(!ASMBitTest(bmDevice, off), ("%#x\n", off));
1225 if (f & 2) AssertMsg(!ASMBitTest(bmBridge, off), ("%#x\n", off));
1226 if (f & 1) ASMBitSet(bmDevice, off);
1227 if (f & 2) ASMBitSet(bmBridge, off);
1228 off++;
1229 }
1230 }
1231 for (uint32_t off = 0; off < 0x40; off++)
1232 {
1233 AssertMsg(ASMBitTest(bmDevice, off), ("%#x\n", off));
1234 AssertMsg(ASMBitTest(bmBridge, off), ("%#x\n", off));
1235 }
1236#endif
1237
1238 /*
1239 * Loop thru the fields covering the 64 bytes of standard registers.
1240 */
1241 uint8_t const fBridge = fIsBridge ? 2 : 1;
1242 Assert(!pciDevIsPassthrough(pDev));
1243 uint8_t *pbDstConfig = &pDev->config[0];
1244
1245 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1246 if (s_aFields[i].fBridge & fBridge)
1247 {
1248 uint8_t const off = s_aFields[i].off;
1249 uint8_t const cb = s_aFields[i].cb;
1250 uint32_t u32Src;
1251 uint32_t u32Dst;
1252 switch (cb)
1253 {
1254 case 1:
1255 u32Src = pbSrcConfig[off];
1256 u32Dst = pbDstConfig[off];
1257 break;
1258 case 2:
1259 u32Src = *(uint16_t const *)&pbSrcConfig[off];
1260 u32Dst = *(uint16_t const *)&pbDstConfig[off];
1261 break;
1262 case 4:
1263 u32Src = *(uint32_t const *)&pbSrcConfig[off];
1264 u32Dst = *(uint32_t const *)&pbDstConfig[off];
1265 break;
1266 default:
1267 AssertFailed();
1268 continue;
1269 }
1270
1271 if ( u32Src != u32Dst
1272 || off == VBOX_PCI_COMMAND)
1273 {
1274 if (u32Src != u32Dst)
1275 {
1276 if (!s_aFields[i].fWritable)
1277 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
1278 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1279 else
1280 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
1281 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1282 }
1283 if (off == VBOX_PCI_COMMAND)
1284 PCIDevSetCommand(pDev, 0); /* For remapping, see ich9pciR3CommonLoadExec. */
1285 pDev->Int.s.pfnConfigWrite(pDev, off, u32Src, cb);
1286 }
1287 }
1288
1289 /*
1290 * The device dependent registers.
1291 *
1292 * We will not use ConfigWrite here as we have no clue about the size
1293 * of the registers, so the device is responsible for correctly
1294 * restoring functionality governed by these registers.
1295 */
1296 for (uint32_t off = 0x40; off < sizeof(pDev->config); off++)
1297 if (pbDstConfig[off] != pbSrcConfig[off])
1298 {
1299 LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
1300 pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
1301 pbDstConfig[off] = pbSrcConfig[off];
1302 }
1303}
1304
1305/**
1306 * Common worker for ich9pciR3LoadExec and ich9pcibridgeR3LoadExec.
1307 *
1308 * @returns VBox status code.
1309 * @param pBus The bus which data is being loaded.
1310 * @param pSSM The saved state handle.
1311 * @param uVersion The data version.
1312 * @param uPass The pass.
1313 */
1314static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1315{
1316 uint32_t u32;
1317 uint32_t i;
1318 int rc;
1319
1320 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1321
1322 /*
1323 * Iterate thru all the devices and write 0 to the COMMAND register so
1324 * that all the memory is unmapped before we start restoring the saved
1325 * mapping locations.
1326 *
1327 * The register value is restored afterwards so we can do proper
1328 * LogRels in pciR3CommonRestoreConfig.
1329 */
1330 for (i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
1331 {
1332 PPCIDEVICE pDev = pBus->apDevices[i];
1333 if (pDev)
1334 {
1335 uint16_t u16 = PCIDevGetCommand(pDev);
1336 pDev->Int.s.pfnConfigWrite(pDev, VBOX_PCI_COMMAND, 0, 2);
1337 PCIDevSetCommand(pDev, u16);
1338 Assert(PCIDevGetCommand(pDev) == u16);
1339 }
1340 }
1341
1342 void* pvMsixPage = RTMemTmpAllocZ(0x1000);
1343 /*
1344 * Iterate all the devices.
1345 */
1346 for (i = 0;; i++)
1347 {
1348 PPCIDEVICE pDev;
1349 PCIDEVICE DevTmp;
1350
1351 /* index / terminator */
1352 rc = SSMR3GetU32(pSSM, &u32);
1353 if (RT_FAILURE(rc))
1354 return rc;
1355 if (u32 == (uint32_t)~0)
1356 break;
1357 if ( u32 >= RT_ELEMENTS(pBus->apDevices)
1358 || u32 < i)
1359 {
1360 AssertMsgFailed(("u32=%#x i=%#x\n", u32, i));
1361 goto out;
1362 }
1363
1364 /* skip forward to the device checking that no new devices are present. */
1365 for (; i < u32; i++)
1366 {
1367 pDev = pBus->apDevices[i];
1368 if (pDev)
1369 {
1370 LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pDev->name,
1371 PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev)));
1372 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1373 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1374 i, pDev->name, PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev));
1375 }
1376 }
1377
1378 /* get the data */
1379 DevTmp.Int.s.fFlags = 0;
1380 DevTmp.Int.s.u8MsiCapOffset = 0;
1381 DevTmp.Int.s.u8MsiCapSize = 0;
1382 DevTmp.Int.s.u8MsixCapOffset = 0;
1383 DevTmp.Int.s.u8MsixCapSize = 0;
1384 DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1385 SSMR3GetMem(pSSM, DevTmp.config, sizeof(DevTmp.config));
1386
1387 rc = SSMR3GetU32(pSSM, &DevTmp.Int.s.fFlags);
1388 if (RT_FAILURE(rc))
1389 goto out;
1390
1391 rc = SSMR3GetS32(pSSM, &DevTmp.Int.s.uIrqPinState);
1392 if (RT_FAILURE(rc))
1393 goto out;
1394
1395 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapOffset);
1396 if (RT_FAILURE(rc))
1397 goto out;
1398
1399 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapSize);
1400 if (RT_FAILURE(rc))
1401 goto out;
1402
1403 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapOffset);
1404 if (RT_FAILURE(rc))
1405 goto out;
1406
1407 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapSize);
1408 if (RT_FAILURE(rc))
1409 goto out;
1410
1411 /* Load MSI-X page state */
1412 if (DevTmp.Int.s.u8MsixCapOffset != 0)
1413 {
1414 Assert(pvMsixPage != NULL);
1415 SSMR3GetMem(pSSM, pvMsixPage, 0x1000);
1416 if (RT_FAILURE(rc))
1417 goto out;
1418 }
1419
1420 /* check that it's still around. */
1421 pDev = pBus->apDevices[i];
1422 if (!pDev)
1423 {
1424 LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
1425 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1426 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1427 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1428 i, PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp));
1429 continue;
1430 }
1431
1432 /* match the vendor id assuming that this will never be changed. */
1433 if ( PCIDevGetVendorId(&DevTmp) != PCIDevGetVendorId(pDev))
1434 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1435 i, pDev->name, PCIDevGetVendorId(&DevTmp), PCIDevGetVendorId(pDev));
1436
1437 /* commit the loaded device config. */
1438 Assert(!pciDevIsPassthrough(pDev));
1439 pciR3CommonRestoreConfig(pDev, &DevTmp.config[0], false ); /** @todo fix bridge fun! */
1440
1441 pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
1442 pDev->Int.s.u8MsiCapOffset = DevTmp.Int.s.u8MsiCapOffset;
1443 pDev->Int.s.u8MsiCapSize = DevTmp.Int.s.u8MsiCapSize;
1444 pDev->Int.s.u8MsixCapOffset = DevTmp.Int.s.u8MsixCapOffset;
1445 pDev->Int.s.u8MsixCapSize = DevTmp.Int.s.u8MsixCapSize;
1446 if (DevTmp.Int.s.u8MsixCapSize != 0)
1447 {
1448 Assert(pDev->Int.s.pMsixPageR3 != NULL);
1449 memcpy(pDev->Int.s.pMsixPageR3, pvMsixPage, 0x1000);
1450 }
1451 }
1452
1453 out:
1454 if (pvMsixPage)
1455 RTMemTmpFree(pvMsixPage);
1456
1457 return rc;
1458}
1459
1460/**
1461 * Loads a saved PCI device state.
1462 *
1463 * @returns VBox status code.
1464 * @param pDevIns Device instance of the PCI Bus.
1465 * @param pPciDev Pointer to PCI device.
1466 * @param pSSM The handle to the saved state.
1467 */
1468static DECLCALLBACK(int) ich9pciGenericLoadExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
1469{
1470 Assert(!pciDevIsPassthrough(pPciDev));
1471 return SSMR3GetMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
1472}
1473
1474static DECLCALLBACK(int) ich9pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1475{
1476 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1477 PICH9PCIBUS pBus = &pThis->aPciBus;
1478 uint32_t u32;
1479 int rc;
1480
1481 /* We ignore this version as there's no saved state with it anyway */
1482 if (uVersion == VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
1483 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1484 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1485 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1486
1487 /*
1488 * Bus state data.
1489 */
1490 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1491
1492 /*
1493 * Load IRQ states.
1494 */
1495 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
1496 SSMR3GetU32(pSSM, (uint32_t*)&pThis->uaPciApicIrqLevels[i]);
1497
1498 /* separator */
1499 rc = SSMR3GetU32(pSSM, &u32);
1500 if (RT_FAILURE(rc))
1501 return rc;
1502 if (u32 != (uint32_t)~0)
1503 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1504
1505 return ich9pciR3CommonLoadExec(pBus, pSSM, uVersion, uPass);
1506}
1507
1508static DECLCALLBACK(int) ich9pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1509{
1510 PICH9PCIBUS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1511 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1512 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1513 return ich9pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
1514}
1515
1516static uint32_t ich9pciConfigRead(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t len)
1517{
1518 /* Will only work in LSB case */
1519 uint32_t u32Val;
1520 PciAddress aPciAddr;
1521
1522 aPciAddr.iBus = uBus;
1523 aPciAddr.iDeviceFunc = uDevFn;
1524 aPciAddr.iRegister = addr;
1525
1526 /* cannot be rescheduled, as already in R3 */
1527 int rc = ich9pciDataReadAddr(pGlobals, &aPciAddr, len, &u32Val, VERR_INTERNAL_ERROR);
1528 AssertRC(rc);
1529 return u32Val;
1530}
1531
1532static void ich9pciConfigWrite(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val, uint32_t len)
1533{
1534 PciAddress aPciAddr;
1535
1536 aPciAddr.iBus = uBus;
1537 aPciAddr.iDeviceFunc = uDevFn;
1538 aPciAddr.iRegister = addr;
1539
1540 /* cannot be rescheduled, as already in R3 */
1541 int rc = ich9pciDataWriteAddr(pGlobals, &aPciAddr, val, len, VERR_INTERNAL_ERROR);
1542 AssertRC(rc);
1543}
1544
1545static void ich9pciSetRegionAddress(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int iRegion, uint64_t addr)
1546{
1547 uint32_t uReg = ich9pciGetRegionReg(iRegion);
1548
1549 /* Read memory type first. */
1550 uint8_t uResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, uReg, 1);
1551 /* Read command register. */
1552 uint16_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
1553
1554 Log(("Set region address: %02x:%02x.%d region %d address=%lld\n",
1555 uBus, uDevFn>>3, uDevFn&7, addr));
1556
1557 if ( iRegion == PCI_ROM_SLOT )
1558 uCmd |= PCI_COMMAND_MEMACCESS;
1559 else if ((uResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO)
1560 uCmd |= PCI_COMMAND_IOACCESS; /* Enable I/O space access. */
1561 else /* The region is MMIO. */
1562 uCmd |= PCI_COMMAND_MEMACCESS; /* Enable MMIO access. */
1563
1564 bool f64Bit = (uResourceType & PCI_ADDRESS_SPACE_BAR64) != 0;
1565
1566 /* Write address of the device. */
1567 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg, (uint32_t)addr, 4);
1568 if (f64Bit)
1569 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg + 4, (uint32_t)(addr >> 32), 4);
1570
1571 /* enable memory mappings */
1572 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
1573}
1574
1575
1576static void ich9pciBiosInitBridge(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
1577{
1578 Log(("BIOS init bridge: %02x::%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
1579
1580 /*
1581 * The I/O range for the bridge must be aligned to a 4KB boundary.
1582 * This does not change anything really as the access to the device is not going
1583 * through the bridge but we want to be compliant to the spec.
1584 */
1585 if ((pGlobals->uPciBiosIo % 4096) != 0)
1586 {
1587 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1588 Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosIo));
1589 }
1590 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->uPciBiosIo >> 8) & 0xf0, 1);
1591
1592 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
1593 if ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0)
1594 {
1595 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1596 Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosMmio));
1597 }
1598 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xffff0), 2);
1599
1600 /* Save values to compare later to. */
1601 uint32_t u32IoAddressBase = pGlobals->uPciBiosIo;
1602 uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
1603 uint8_t uBridgeBus = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_SECONDARY_BUS, 1);
1604
1605 /* Init devices behind the bridge and possibly other bridges as well. */
1606 for (int iDev = 0; iDev <= 255; iDev++)
1607 ich9pciBiosInitDevice(pGlobals, uBridgeBus, iDev);
1608
1609 /*
1610 * Set I/O limit register. If there is no device with I/O space behind the bridge
1611 * we set a lower value than in the base register.
1612 * The result with a real bridge is that no I/O transactions are passed to the secondary
1613 * interface. Again this doesn't really matter here but we want to be compliant to the spec.
1614 */
1615 if ((u32IoAddressBase != pGlobals->uPciBiosIo) && ((pGlobals->uPciBiosIo % 4096) != 0))
1616 {
1617 /* The upper boundary must be one byte less than a 4KB boundary. */
1618 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1619 }
1620
1621 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo >> 8) & 0xf0) - 1, 1);
1622
1623 /* Same with the MMIO limit register but with 1MB boundary here. */
1624 if ((u32MMIOAddressBase != pGlobals->uPciBiosMmio) && ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0))
1625 {
1626 /* The upper boundary must be one byte less than a 1MB boundary. */
1627 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1628 }
1629 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xfff0)) - 1, 2);
1630
1631 /*
1632 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
1633 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
1634 * the base register than in the limit register.
1635 */
1636 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0, 2);
1637 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0, 2);
1638 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00, 4);
1639 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00, 4);
1640}
1641
1642static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
1643{
1644 uint16_t uDevClass, uVendor, uDevice;
1645 uint8_t uCmd;
1646
1647 uDevClass = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_CLASS_DEVICE, 2);
1648 uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
1649 uDevice = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_DEVICE_ID, 2);
1650
1651 /* If device is present */
1652 if (uVendor == 0xffff)
1653 return;
1654
1655 Log(("BIOS init device: %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
1656
1657 switch (uDevClass)
1658 {
1659 case 0x0101:
1660 /* IDE controller */
1661 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x40, 0x8000, 2); /* enable IDE0 */
1662 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x42, 0x8000, 2); /* enable IDE1 */
1663 goto default_map;
1664 break;
1665 case 0x0300:
1666 /* VGA controller */
1667 if (uVendor != 0x80ee)
1668 goto default_map;
1669 /* VGA: map frame buffer to default Bochs VBE address */
1670 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, 0, 0xE0000000);
1671 /*
1672 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
1673 * only the framebuffer (i.e., a memory region) is explicitly registered via
1674 * ich9pciSetRegionAddress, so I/O decoding must be enabled manually.
1675 */
1676 uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 1);
1677 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND,
1678 /* Enable I/O space access. */
1679 uCmd | PCI_COMMAND_IOACCESS,
1680 1);
1681 break;
1682 case 0x0604:
1683 /* PCI-to-PCI bridge. */
1684 AssertMsg(pGlobals->uBus < 255, ("Too many bridges on the bus\n"));
1685 ich9pciBiosInitBridge(pGlobals, uBus, uDevFn);
1686 break;
1687 default:
1688 default_map:
1689 {
1690 /* default memory mappings */
1691 /*
1692 * We ignore ROM region here.
1693 */
1694 for (int iRegion = 0; iRegion < (PCI_NUM_REGIONS-1); iRegion++)
1695 {
1696 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
1697
1698 /* Calculate size - we write all 1s into the BAR, and then evaluate which bits
1699 are cleared. . */
1700 uint8_t u8ResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 1);
1701
1702 bool f64bit = (u8ResourceType & PCI_ADDRESS_SPACE_BAR64) != 0;
1703 bool fIsPio = ((u8ResourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS);
1704 uint64_t cbRegSize64 = 0;
1705
1706 if (f64bit)
1707 {
1708 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1709 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address+4, UINT32_C(0xffffffff), 4);
1710 cbRegSize64 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1711 cbRegSize64 |= ((uint64_t)ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address+4, 4) << 32);
1712 cbRegSize64 &= ~UINT64_C(0x0f);
1713 cbRegSize64 = (~cbRegSize64) + 1;
1714
1715 /* No 64-bit PIO regions possible. */
1716 Assert((u8ResourceType & PCI_COMMAND_IOACCESS) == 0);
1717 }
1718 else
1719 {
1720 uint32_t cbRegSize32;
1721 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1722 cbRegSize32 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1723
1724 /* Clear resource information depending on resource type. */
1725 if (fIsPio) /* PIO */
1726 cbRegSize32 &= ~UINT32_C(0x01);
1727 else /* MMIO */
1728 cbRegSize32 &= ~UINT32_C(0x0f);
1729
1730 /*
1731 * Invert all bits and add 1 to get size of the region.
1732 * (From PCI implementation note)
1733 */
1734 if (fIsPio && (cbRegSize32 & UINT32_C(0xffff0000)) == 0)
1735 cbRegSize32 = (~(cbRegSize32 | UINT32_C(0xffff0000))) + 1;
1736 else
1737 cbRegSize32 = (~cbRegSize32) + 1;
1738
1739 cbRegSize64 = cbRegSize32;
1740 }
1741 Assert(cbRegSize64 == (uint32_t)cbRegSize64);
1742 Log2(("%s: Size of region %u for device %d on bus %d is %lld\n", __FUNCTION__, iRegion, uDevFn, uBus, cbRegSize64));
1743
1744 if (cbRegSize64)
1745 {
1746 uint32_t cbRegSize32 = (uint32_t)cbRegSize64;
1747 uint32_t* paddr = fIsPio ? &pGlobals->uPciBiosIo : &pGlobals->uPciBiosMmio;
1748 *paddr = (*paddr + cbRegSize32 - 1) & ~(cbRegSize32 - 1);
1749 Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), iRegion, *paddr));
1750 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, *paddr);
1751 *paddr += cbRegSize32;
1752 Log2(("%s: New address is %#x\n", __FUNCTION__, *paddr));
1753
1754 if (f64bit)
1755 iRegion++; /* skip next region */
1756 }
1757 }
1758 break;
1759 }
1760 }
1761
1762 /* map the interrupt */
1763 uint32_t iPin = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_PIN, 1);
1764 if (iPin != 0)
1765 {
1766 iPin--;
1767
1768 if (uBus != 0)
1769 {
1770 /* Find bus this device attached to. */
1771 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1772 while (1)
1773 {
1774 PPCIDEVICE pBridge = ich9pciFindBridge(pBus, uBus);
1775 if (!pBridge)
1776 {
1777 Assert(false);
1778 break;
1779 }
1780 if (uBus == PCIDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS))
1781 {
1782 /* OK, found bus this device attached to. */
1783 break;
1784 }
1785 pBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1786 }
1787
1788 /* We need to go up to the host bus to see which irq pin this
1789 * device will use there. See logic in ich9pcibridgeSetIrq().
1790 */
1791 while (pBus->iBus != 0)
1792 {
1793 /* Get the pin the device would assert on the bridge. */
1794 iPin = ((pBus->aPciDev.devfn >> 3) + iPin) & 3;
1795 pBus = pBus->aPciDev.Int.s.pBusR3;
1796 };
1797 }
1798
1799 int iIrq = aPciIrqs[ich9pciSlotGetPirq(uBus, uDevFn, iPin)];
1800 Log(("Using pin %d and IRQ %d for device %02x:%02x.%d\n",
1801 iPin, iIrq, uBus, uDevFn>>3, uDevFn&7));
1802 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_LINE, iIrq, 1);
1803 }
1804}
1805
1806/* Initializes bridges registers used for routing. */
1807static void ich9pciInitBridgeTopology(PICH9PCIGLOBALS pGlobals, PICH9PCIBUS pBus)
1808{
1809 PPCIDEVICE pBridgeDev = &pBus->aPciDev;
1810
1811 /* Set only if we are not on the root bus, it has no primary bus attached. */
1812 if (pGlobals->uBus != 0)
1813 {
1814 PCIDevSetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS, pGlobals->uBus);
1815 PCIDevSetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS, pGlobals->uBus);
1816 }
1817
1818 pGlobals->uBus++;
1819 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
1820 {
1821 PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
1822 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
1823 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
1824 PICH9PCIBUS pChildBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1825 ich9pciInitBridgeTopology(pGlobals, pChildBus);
1826 }
1827 PCIDevSetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uBus);
1828 Log2(("ich9pciInitBridgeTopology: for bus %p: primary=%d secondary=%d subordinate=%d\n",
1829 pBus,
1830 PCIDevGetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS),
1831 PCIDevGetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS),
1832 PCIDevGetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS)
1833 ));
1834}
1835
1836
1837static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
1838{
1839 unsigned i;
1840 uint8_t elcr[2] = {0, 0};
1841 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1842 PVM pVM = PDMDevHlpGetVM(pDevIns);
1843 Assert(pVM);
1844
1845 /*
1846 * Set the start addresses.
1847 */
1848 pGlobals->uPciBiosIo = 0xd000;
1849 pGlobals->uPciBiosMmio = UINT32_C(0xf0000000);
1850 pGlobals->uBus = 0;
1851
1852 /*
1853 * Assign bridge topology, for further routing to work.
1854 */
1855 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1856 ich9pciInitBridgeTopology(pGlobals, pBus);
1857
1858 /*
1859 * Init the devices.
1860 */
1861 for (i = 0; i < 256; i++)
1862 {
1863 ich9pciBiosInitDevice(pGlobals, 0, i);
1864 }
1865
1866 return VINF_SUCCESS;
1867}
1868
1869static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len)
1870{
1871 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1872 {
1873 AssertMsgReturn(false, ("Read from extended registers fallen back to generic code\n"), 0);
1874 }
1875
1876 AssertMsgReturn(u32Address + len <= 256, ("Read after the end of PCI config space\n"),
1877 0);
1878 if ( pciDevIsMsiCapable(aDev)
1879 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1880 && (u32Address < aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize)
1881 )
1882 {
1883 return MsiPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1884 }
1885
1886 if ( pciDevIsMsixCapable(aDev)
1887 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1888 && (u32Address < aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize)
1889 )
1890 {
1891 return MsixPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1892 }
1893
1894 AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
1895 0);
1896 switch (len)
1897 {
1898 case 1:
1899 return PCIDevGetByte(aDev, u32Address);
1900 case 2:
1901 return PCIDevGetWord(aDev, u32Address);
1902 case 4:
1903 return PCIDevGetDWord(aDev, u32Address);
1904 default:
1905 Assert(false);
1906 return 0;
1907 }
1908}
1909
1910DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset, uint8_t u8Val)
1911{
1912 PCIIORegion * pRegion = &aDev->Int.s.aIORegions[iRegion];
1913
1914 int iRegionSize = pRegion->size;
1915
1916 Log3(("ich9pciWriteBarByte: region=%d off=%d val=%x size=%d\n",
1917 iRegion, iOffset, u8Val, iRegionSize));
1918
1919 /* Region doesn't exist */
1920 if (iRegionSize == 0)
1921 return;
1922
1923 uint32_t uAddr = ich9pciGetRegionReg(iRegion) + iOffset;
1924 /* Region size must be power of two */
1925 Assert((iRegionSize & (iRegionSize - 1)) == 0);
1926 uint8_t uMask = (((uint32_t)iRegionSize - 1) >> (iOffset*8) ) & 0xff;
1927
1928 if (iOffset == 0)
1929 {
1930 uMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO) ?
1931 (1 << 2) - 1 /* 2 lowest bits for IO region */ :
1932 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
1933
1934 }
1935
1936 uint8_t u8Old = PCIDevGetByte(aDev, uAddr) & uMask;
1937 u8Val = (u8Old & uMask) | (u8Val & ~uMask);
1938
1939 Log3(("ich9pciWriteBarByte: was %x writing %x\n", u8Old, u8Val));
1940
1941 PCIDevSetByte(aDev, uAddr, u8Val);
1942}
1943
1944/**
1945 * See paragraph 7.5 of PCI Express specification (p. 349) for definition of
1946 * registers and their writability policy.
1947 */
1948static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Address,
1949 uint32_t val, unsigned len)
1950{
1951 Assert(len <= 4);
1952
1953 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1954 {
1955 AssertMsgReturnVoid(false, ("Write to extended registers fallen back to generic code\n"));
1956 }
1957
1958 AssertMsgReturnVoid(u32Address + len <= 256, ("Write after end of PCI config space\n"));
1959
1960 if ( pciDevIsMsiCapable(aDev)
1961 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1962 && (u32Address < aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize)
1963 )
1964 {
1965 MsiPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1966 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1967 aDev, u32Address, val, len);
1968 return;
1969 }
1970
1971 if ( pciDevIsMsixCapable(aDev)
1972 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1973 && (u32Address < aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize)
1974 )
1975 {
1976 MsixPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1977 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1978 aDev, u32Address, val, len);
1979 return;
1980 }
1981
1982 uint32_t addr = u32Address;
1983 bool fUpdateMappings = false;
1984 bool fP2PBridge = false;
1985 bool fPassthrough = pciDevIsPassthrough(aDev);
1986 uint8_t u8HeaderType = ich9pciGetByte(aDev, VBOX_PCI_HEADER_TYPE);
1987
1988 for (uint32_t i = 0; i < len; i++)
1989 {
1990 bool fWritable = false;
1991 bool fRom = false;
1992 switch (u8HeaderType)
1993 {
1994 case 0x00: /* normal device */
1995 case 0x80: /* multi-function device */
1996 switch (addr)
1997 {
1998 /* Read-only registers */
1999 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
2000 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
2001 case VBOX_PCI_REVISION_ID:
2002 case VBOX_PCI_CLASS_PROG:
2003 case VBOX_PCI_CLASS_SUB:
2004 case VBOX_PCI_CLASS_BASE:
2005 case VBOX_PCI_HEADER_TYPE:
2006 case VBOX_PCI_SUBSYSTEM_VENDOR_ID: case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
2007 case VBOX_PCI_SUBSYSTEM_ID: case VBOX_PCI_SUBSYSTEM_ID+1:
2008 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS+1: case VBOX_PCI_ROM_ADDRESS+2: case VBOX_PCI_ROM_ADDRESS+3:
2009 case VBOX_PCI_CAPABILITY_LIST:
2010 case VBOX_PCI_INTERRUPT_PIN:
2011 fWritable = false;
2012 break;
2013 /* Others can be written */
2014 default:
2015 fWritable = true;
2016 break;
2017 }
2018 break;
2019 case 0x01: /* PCI-PCI bridge */
2020 fP2PBridge = true;
2021 switch (addr)
2022 {
2023 /* Read-only registers */
2024 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
2025 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
2026 case VBOX_PCI_REVISION_ID:
2027 case VBOX_PCI_CLASS_PROG:
2028 case VBOX_PCI_CLASS_SUB:
2029 case VBOX_PCI_CLASS_BASE:
2030 case VBOX_PCI_HEADER_TYPE:
2031 case VBOX_PCI_ROM_ADDRESS_BR: case VBOX_PCI_ROM_ADDRESS_BR+1: case VBOX_PCI_ROM_ADDRESS_BR+2: case VBOX_PCI_ROM_ADDRESS_BR+3:
2032 case VBOX_PCI_INTERRUPT_PIN:
2033 fWritable = false;
2034 break;
2035 default:
2036 fWritable = true;
2037 break;
2038 }
2039 break;
2040 default:
2041 AssertMsgFailed(("Unknown header type %x\n", PCIDevGetHeaderType(aDev)));
2042 fWritable = false;
2043 break;
2044 }
2045
2046 uint8_t u8Val = (uint8_t)val;
2047 switch (addr)
2048 {
2049 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
2050 fUpdateMappings = true;
2051 goto default_case;
2052 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
2053 /* don't change reserved bits (11-15) */
2054 u8Val &= UINT32_C(~0xf8);
2055 fUpdateMappings = true;
2056 goto default_case;
2057 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
2058 /* don't change read-only bits => actually all lower bits are read-only */
2059 u8Val &= UINT32_C(~0xff);
2060 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
2061 aDev->config[addr] &= ~u8Val;
2062 break;
2063 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
2064 /* don't change read-only bits */
2065 u8Val &= UINT32_C(~0x06);
2066 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
2067 aDev->config[addr] &= ~u8Val;
2068 break;
2069 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
2070 fRom = true;
2071 case VBOX_PCI_BASE_ADDRESS_0: case VBOX_PCI_BASE_ADDRESS_0+1: case VBOX_PCI_BASE_ADDRESS_0+2: case VBOX_PCI_BASE_ADDRESS_0+3:
2072 case VBOX_PCI_BASE_ADDRESS_1: case VBOX_PCI_BASE_ADDRESS_1+1: case VBOX_PCI_BASE_ADDRESS_1+2: case VBOX_PCI_BASE_ADDRESS_1+3:
2073 case VBOX_PCI_BASE_ADDRESS_2: case VBOX_PCI_BASE_ADDRESS_2+1: case VBOX_PCI_BASE_ADDRESS_2+2: case VBOX_PCI_BASE_ADDRESS_2+3:
2074 case VBOX_PCI_BASE_ADDRESS_3: case VBOX_PCI_BASE_ADDRESS_3+1: case VBOX_PCI_BASE_ADDRESS_3+2: case VBOX_PCI_BASE_ADDRESS_3+3:
2075 case VBOX_PCI_BASE_ADDRESS_4: case VBOX_PCI_BASE_ADDRESS_4+1: case VBOX_PCI_BASE_ADDRESS_4+2: case VBOX_PCI_BASE_ADDRESS_4+3:
2076 case VBOX_PCI_BASE_ADDRESS_5: case VBOX_PCI_BASE_ADDRESS_5+1: case VBOX_PCI_BASE_ADDRESS_5+2: case VBOX_PCI_BASE_ADDRESS_5+3:
2077 {
2078 /* We check that, as same PCI register numbers as BARs may mean different registers for bridges */
2079 if (fP2PBridge)
2080 goto default_case;
2081 else
2082 {
2083 int iRegion = fRom ? VBOX_PCI_ROM_SLOT : (addr - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2084 int iOffset = addr & 0x3;
2085 ich9pciWriteBarByte(aDev, iRegion, iOffset, u8Val);
2086 fUpdateMappings = true;
2087 }
2088 break;
2089 }
2090 default:
2091 default_case:
2092 if (fWritable)
2093 PCIDevSetByte(aDev, addr, u8Val);
2094 }
2095 addr++;
2096 val >>= 8;
2097 }
2098
2099 if (fUpdateMappings)
2100 /* if the command/base address register is modified, we must modify the mappings */
2101 ich9pciUpdateMappings(aDev);
2102}
2103
2104static bool assignPosition(PICH9PCIBUS pBus, PPCIDEVICE pPciDev, const char *pszName, int iDevFn, PciAddress* aPosition)
2105{
2106 aPosition->iBus = 0;
2107 aPosition->iDeviceFunc = iDevFn;
2108 aPosition->iRegister = 0; /* N/A */
2109
2110 /* Explicit slot request */
2111 if (iDevFn >=0 && iDevFn < (int)RT_ELEMENTS(pBus->apDevices))
2112 return true;
2113
2114 int iStartPos = 0;
2115
2116 /* Otherwise when assigning a slot, we need to make sure all its functions are available */
2117 for (int iPos = iStartPos; iPos < (int)RT_ELEMENTS(pBus->apDevices); iPos += 8)
2118 {
2119 if ( !pBus->apDevices[iPos]
2120 && !pBus->apDevices[iPos + 1]
2121 && !pBus->apDevices[iPos + 2]
2122 && !pBus->apDevices[iPos + 3]
2123 && !pBus->apDevices[iPos + 4]
2124 && !pBus->apDevices[iPos + 5]
2125 && !pBus->apDevices[iPos + 6]
2126 && !pBus->apDevices[iPos + 7])
2127 {
2128 pciDevClearRequestedDevfunc(pPciDev);
2129 aPosition->iDeviceFunc = iPos;
2130 return true;
2131 }
2132 }
2133
2134 return false;
2135}
2136
2137static bool hasHardAssignedDevsInSlot(PICH9PCIBUS pBus, int iSlot)
2138{
2139 PCIDevice** aSlot = &pBus->apDevices[iSlot << 3];
2140
2141 return (aSlot[0] && pciDevIsRequestedDevfunc(aSlot[0]))
2142 || (aSlot[1] && pciDevIsRequestedDevfunc(aSlot[1]))
2143 || (aSlot[2] && pciDevIsRequestedDevfunc(aSlot[2]))
2144 || (aSlot[3] && pciDevIsRequestedDevfunc(aSlot[3]))
2145 || (aSlot[4] && pciDevIsRequestedDevfunc(aSlot[4]))
2146 || (aSlot[5] && pciDevIsRequestedDevfunc(aSlot[5]))
2147 || (aSlot[6] && pciDevIsRequestedDevfunc(aSlot[6]))
2148 || (aSlot[7] && pciDevIsRequestedDevfunc(aSlot[7]))
2149 ;
2150}
2151
2152static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
2153{
2154 PciAddress aPosition = {0, 0, 0};
2155
2156 /*
2157 * Find device position
2158 */
2159 if (!assignPosition(pBus, pPciDev, pszName, iDev, &aPosition))
2160 {
2161 AssertMsgFailed(("Couldn't asssign position!\n"));
2162 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2163 }
2164
2165 AssertMsgReturn(aPosition.iBus == 0,
2166 ("Assigning behind the bridge not implemented yet\n"),
2167 VERR_PDM_TOO_PCI_MANY_DEVICES);
2168
2169
2170 iDev = aPosition.iDeviceFunc;
2171 /*
2172 * Check if we can really take this slot, possibly by relocating
2173 * its current habitant, if it wasn't hard assigned too.
2174 */
2175 if (pciDevIsRequestedDevfunc(pPciDev) &&
2176 pBus->apDevices[iDev] &&
2177 pciDevIsRequestedDevfunc(pBus->apDevices[iDev]))
2178 {
2179 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
2180 pszName, pBus->apDevices[iDev]->name, iDev));
2181 return VERR_INTERNAL_ERROR;
2182 }
2183
2184 if (pBus->apDevices[iDev])
2185 {
2186 /* if we got here, we shall (and usually can) relocate the device */
2187 bool assigned = assignPosition(pBus, pBus->apDevices[iDev], pBus->apDevices[iDev]->name, -1, &aPosition);
2188 AssertMsgReturn(aPosition.iBus == 0,
2189 ("Assigning behind the bridge not implemented yet\n"),
2190 VERR_PDM_TOO_PCI_MANY_DEVICES);
2191 int iRelDev = aPosition.iDeviceFunc;
2192 if (!assigned || iRelDev == iDev)
2193 {
2194 AssertMsgFailed(("Couldn't find free spot!\n"));
2195 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2196 }
2197 /* Copy device function by function to its new position */
2198 for (int i = 0; i < 8; i++)
2199 {
2200 if (!pBus->apDevices[iDev + i])
2201 continue;
2202 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->apDevices[iDev + i]->name, iDev + i, iRelDev + i));
2203 pBus->apDevices[iRelDev + i] = pBus->apDevices[iDev + i];
2204 pBus->apDevices[iRelDev + i]->devfn = iRelDev + i;
2205 pBus->apDevices[iDev + i] = NULL;
2206 }
2207 }
2208
2209 /*
2210 * Fill in device information.
2211 */
2212 pPciDev->devfn = iDev;
2213 pPciDev->name = pszName;
2214 pPciDev->Int.s.pBusR3 = pBus;
2215 pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2216 pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2217 pPciDev->Int.s.pfnConfigRead = ich9pciConfigReadDev;
2218 pPciDev->Int.s.pfnConfigWrite = ich9pciConfigWriteDev;
2219 pBus->apDevices[iDev] = pPciDev;
2220 if (pciDevIsPci2PciBridge(pPciDev))
2221 {
2222 AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
2223 AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
2224 ("device is a bridge but does not implement read/write functions\n"));
2225 Log2(("Setting bridge %d on bus %p\n", pBus->cBridges, pBus));
2226 pBus->papBridgesR3[pBus->cBridges] = pPciDev;
2227 pBus->cBridges++;
2228 }
2229
2230 Log(("PCI: Registered device %d function %d on bus %d (%#x) '%s'.\n",
2231 iDev >> 3, iDev & 7, pBus->iBus, 0x80000000 | (iDev << 8), pszName));
2232
2233 return VINF_SUCCESS;
2234}
2235
2236static void printIndent(PCDBGFINFOHLP pHlp, int iIndent)
2237{
2238 for (int i = 0; i < iIndent; i++)
2239 {
2240 pHlp->pfnPrintf(pHlp, " ");
2241 }
2242}
2243
2244static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRegisters)
2245{
2246 for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->apDevices); iDev++)
2247 {
2248 PPCIDEVICE pPciDev = pBus->apDevices[iDev];
2249 if (pPciDev != NULL)
2250 {
2251 printIndent(pHlp, iIndent);
2252
2253 /*
2254 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
2255 * as host driver handles real devices interrupts.
2256 */
2257 pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s%s: %04x-%04x%s%s",
2258 pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
2259 pPciDev->name,
2260 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
2261 ich9pciGetWord(pPciDev, VBOX_PCI_VENDOR_ID), ich9pciGetWord(pPciDev, VBOX_PCI_DEVICE_ID),
2262 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
2263 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
2264 );
2265 if (ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
2266 pHlp->pfnPrintf(pHlp, " IRQ%d", ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
2267
2268 pHlp->pfnPrintf(pHlp, "\n");
2269
2270 int iCmd = ich9pciGetWord(pPciDev, VBOX_PCI_COMMAND);
2271 if ((iCmd & (VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY)) != 0)
2272 {
2273 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2274 {
2275 PCIIORegion* pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2276 int32_t iRegionSize = pRegion->size;
2277
2278 if (iRegionSize == 0)
2279 continue;
2280
2281 uint32_t u32Addr = ich9pciGetDWord(pPciDev, ich9pciGetRegionReg(iRegion));
2282 const char * pszDesc;
2283 char szDescBuf[128];
2284
2285 bool f64Bit = (pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2286 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2287 {
2288 pszDesc = "IO";
2289 u32Addr &= ~0x3;
2290 }
2291 else
2292 {
2293 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
2294 f64Bit ? "64" : "32",
2295 (pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH) ? " PREFETCH" : "");
2296 pszDesc = szDescBuf;
2297 u32Addr &= ~0xf;
2298 }
2299
2300 printIndent(pHlp, iIndent + 2);
2301 pHlp->pfnPrintf(pHlp, " %s region #%d: %x..%x\n",
2302 pszDesc, iRegion, u32Addr, u32Addr+iRegionSize);
2303 if (f64Bit)
2304 iRegion++;
2305 }
2306 }
2307
2308 if (fRegisters)
2309 {
2310 printIndent(pHlp, iIndent + 2);
2311 pHlp->pfnPrintf(pHlp, " PCI registers:\n");
2312 for (int iReg = 0; iReg < 0x100; )
2313 {
2314 int iPerLine = 0x10;
2315 Assert (0x100 % iPerLine == 0);
2316 printIndent(pHlp, iIndent + 3);
2317
2318 while (iPerLine-- > 0)
2319 {
2320 pHlp->pfnPrintf(pHlp, "%02x ", ich9pciGetByte(pPciDev, iReg++));
2321 }
2322 pHlp->pfnPrintf(pHlp, "\n");
2323 }
2324 }
2325 }
2326 }
2327
2328 if (pBus->cBridges > 0)
2329 {
2330 printIndent(pHlp, iIndent);
2331 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
2332 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2333 {
2334 PICH9PCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PICH9PCIBUS);
2335 ich9pciBusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
2336 }
2337 }
2338}
2339
2340/**
2341 * Info handler, device version.
2342 *
2343 * @param pDevIns Device instance which registered the info.
2344 * @param pHlp Callback functions for doing output.
2345 * @param pszArgs Argument string. Optional and specific to the handler.
2346 */
2347static DECLCALLBACK(void) ich9pciInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2348{
2349 PICH9PCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
2350
2351 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2352 {
2353 ich9pciBusInfo(pBus, pHlp, 0, false);
2354 }
2355 else if (!strcmp(pszArgs, "verbose"))
2356 {
2357 ich9pciBusInfo(pBus, pHlp, 0, true);
2358 }
2359 else
2360 {
2361 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
2362 }
2363}
2364
2365
2366static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns,
2367 int iInstance,
2368 PCFGMNODE pCfg)
2369{
2370 Assert(iInstance == 0);
2371 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2372
2373 /*
2374 * Validate and read configuration.
2375 */
2376 if (!CFGMR3AreValuesValid(pCfg,
2377 "IOAPIC\0"
2378 "GCEnabled\0"
2379 "R0Enabled\0"
2380 "McfgBase\0"
2381 "McfgLength\0"
2382 ))
2383 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2384
2385 /* query whether we got an IOAPIC */
2386 bool fUseIoApic;
2387 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
2388 if (RT_FAILURE(rc))
2389 return PDMDEV_SET_ERROR(pDevIns, rc,
2390 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
2391
2392 /* check if RC code is enabled. */
2393 bool fGCEnabled;
2394 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2395 if (RT_FAILURE(rc))
2396 return PDMDEV_SET_ERROR(pDevIns, rc,
2397 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2398 /* check if R0 code is enabled. */
2399 bool fR0Enabled;
2400 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2401 if (RT_FAILURE(rc))
2402 return PDMDEV_SET_ERROR(pDevIns, rc,
2403 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2404
2405 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
2406
2407 /*
2408 * Init data.
2409 */
2410 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2411 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2412 /* Zero out everything */
2413 memset(pGlobals, 0, sizeof(*pGlobals));
2414 /* And fill values */
2415 if (!fUseIoApic)
2416 return PDMDEV_SET_ERROR(pDevIns, rc,
2417 N_("Must use IO-APIC with ICH9 chipset"));
2418 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pGlobals->u64PciConfigMMioAddress, 0);
2419 if (RT_FAILURE(rc))
2420 return PDMDEV_SET_ERROR(pDevIns, rc,
2421 N_("Configuration error: Failed to read \"McfgBase\""));
2422 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pGlobals->u64PciConfigMMioLength, 0);
2423 if (RT_FAILURE(rc))
2424 return PDMDEV_SET_ERROR(pDevIns, rc,
2425 N_("Configuration error: Failed to read \"McfgLength\""));
2426
2427 pGlobals->pDevInsR3 = pDevIns;
2428 pGlobals->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2429 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2430
2431 pGlobals->aPciBus.pDevInsR3 = pDevIns;
2432 pGlobals->aPciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2433 pGlobals->aPciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2434 pGlobals->aPciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
2435
2436 /*
2437 * Register bus
2438 */
2439 PDMPCIBUSREG PciBusReg;
2440 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2441 PciBusReg.pfnRegisterR3 = ich9pciRegister;
2442 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2443 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2444 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2445 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
2446 PciBusReg.pfnSaveExecR3 = ich9pciGenericSaveExec;
2447 PciBusReg.pfnLoadExecR3 = ich9pciGenericLoadExec;
2448 PciBusReg.pfnFakePCIBIOSR3 = ich9pciFakePCIBIOS;
2449 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pciSetIrq" : NULL;
2450 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pciSetIrq" : NULL;
2451 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2452 if (RT_FAILURE(rc))
2453 return PDMDEV_SET_ERROR(pDevIns, rc,
2454 N_("Failed to register ourselves as a PCI Bus"));
2455 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2456 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2457 N_("PCI helper version mismatch; got %#x expected %#x"),
2458 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2459
2460 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2461 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2462
2463 /*
2464 * Fill in PCI configs and add them to the bus.
2465 */
2466 /** @todo: Disabled for now because this causes error messages with Linux guests.
2467 * The guest loads the x38_edac device which tries to map a memory region
2468 * using an address given at place 0x48 - 0x4f in the PCi config space.
2469 * This fails. because we don't register such a region.
2470 */
2471#if 0
2472 /* Host bridge device */
2473 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2474 PCIDevSetDeviceId( &pBus->aPciDev, 0x29e0); /* Desktop */
2475 PCIDevSetRevisionId(&pBus->aPciDev, 0x01); /* rev. 01 */
2476 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* bridge */
2477 PCIDevSetClassSub( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2478 PCIDevSetClassProg( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2479 PCIDevSetHeaderType(&pBus->aPciDev, 0x00); /* bridge */
2480 PCIDevSetWord(&pBus->aPciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
2481
2482 pBus->aPciDev.pDevIns = pDevIns;
2483 /* We register Host<->PCI controller on the bus */
2484 ich9pciRegisterInternal(pBus, 0, &pBus->aPciDev, "dram");
2485#endif
2486
2487 /*
2488 * Register I/O ports and save state.
2489 */
2490 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL, NULL, "ICH9 (PCI)");
2491 if (RT_FAILURE(rc))
2492 return rc;
2493 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL, NULL, "ICH9 (PCI)");
2494 if (RT_FAILURE(rc))
2495 return rc;
2496 if (fGCEnabled)
2497 {
2498 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2499 if (RT_FAILURE(rc))
2500 return rc;
2501 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2502 if (RT_FAILURE(rc))
2503 return rc;
2504 }
2505 if (fR0Enabled)
2506 {
2507 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2508 if (RT_FAILURE(rc))
2509 return rc;
2510 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2511 if (RT_FAILURE(rc))
2512 return rc;
2513 }
2514
2515 if (pGlobals->u64PciConfigMMioAddress != 0)
2516 {
2517 rc = PDMDevHlpMMIORegister(pDevIns,
2518 pGlobals->u64PciConfigMMioAddress,
2519 pGlobals->u64PciConfigMMioLength,
2520 0,
2521 ich9pciMcfgMMIOWrite,
2522 ich9pciMcfgMMIORead,
2523 NULL /* fill */,
2524 "MCFG ranges");
2525 if (RT_FAILURE(rc))
2526 {
2527 AssertMsgRC(rc, ("Cannot register MCFG MMIO: %Rrc\n", rc));
2528 return rc;
2529 }
2530
2531 if (fGCEnabled)
2532 {
2533
2534 rc = PDMDevHlpMMIORegisterRC(pDevIns,
2535 pGlobals->u64PciConfigMMioAddress,
2536 pGlobals->u64PciConfigMMioLength,
2537 0,
2538 "ich9pciMcfgMMIOWrite",
2539 "ich9pciMcfgMMIORead",
2540 NULL /* fill */);
2541 if (RT_FAILURE(rc))
2542 {
2543 AssertMsgRC(rc, ("Cannot register MCFG MMIO (GC): %Rrc\n", rc));
2544 return rc;
2545 }
2546 }
2547
2548
2549 if (fR0Enabled)
2550 {
2551
2552 rc = PDMDevHlpMMIORegisterR0(pDevIns,
2553 pGlobals->u64PciConfigMMioAddress,
2554 pGlobals->u64PciConfigMMioLength,
2555 0,
2556 "ich9pciMcfgMMIOWrite",
2557 "ich9pciMcfgMMIORead",
2558 NULL /* fill */);
2559 if (RT_FAILURE(rc))
2560 {
2561 AssertMsgRC(rc, ("Cannot register MCFG MMIO (R0): %Rrc\n", rc));
2562 return rc;
2563 }
2564 }
2565 }
2566
2567 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2568 sizeof(*pBus) + 16*128, "pgm",
2569 NULL, NULL, NULL,
2570 NULL, ich9pciR3SaveExec, NULL,
2571 NULL, ich9pciR3LoadExec, NULL);
2572 if (RT_FAILURE(rc))
2573 return rc;
2574
2575
2576 /** @todo: other chipset devices shall be registered too */
2577
2578 PDMDevHlpDBGFInfoRegister(pDevIns, "pci", "Display PCI bus status. (no arguments)", ich9pciInfo);
2579
2580 return VINF_SUCCESS;
2581}
2582
2583static void ich9pciResetDevice(PPCIDEVICE pDev)
2584{
2585 PICH9PCIBUS pBus = pDev->Int.s.CTX_SUFF(pBus);
2586 int rc;
2587
2588 /* Clear regions */
2589 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2590 {
2591 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
2592 if (pRegion->size == 0)
2593 continue;
2594
2595 ich9pciUnmapRegion(pDev, iRegion);
2596 }
2597
2598 if (pciDevIsPassthrough(pDev))
2599 {
2600 // no reset handler - we can do what we need in PDM reset handler
2601 // @todo: is it correct?
2602 }
2603 else
2604 {
2605 PCIDevSetCommand(pDev,
2606 PCIDevGetCommand(pDev)
2607 &
2608 ~(VBOX_PCI_COMMAND_IO |
2609 VBOX_PCI_COMMAND_MEMORY |
2610 VBOX_PCI_COMMAND_MASTER));
2611
2612 /* Bridge device reset handlers processed later */
2613 if (!pciDevIsPci2PciBridge(pDev))
2614 {
2615 PCIDevSetByte(pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
2616 PCIDevSetInterruptLine(pDev, 0x0);
2617 }
2618 }
2619}
2620
2621
2622/**
2623 * @copydoc FNPDMDEVRESET
2624 */
2625static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
2626{
2627 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2628 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2629
2630 /* PCI-specific reset for each device. */
2631 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2632 {
2633 if (pBus->apDevices[i])
2634 ich9pciResetDevice(pBus->apDevices[i]);
2635 }
2636
2637 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2638 {
2639 if (pBus->papBridgesR3[iBridge])
2640 ich9pcibridgeReset(pBus->papBridgesR3[iBridge]->pDevIns);
2641 }
2642
2643 ich9pciFakePCIBIOS(pDevIns);
2644}
2645
2646static void ich9pciRelocateDevice(PPCIDEVICE pDev, RTGCINTPTR offDelta)
2647{
2648 if (pDev)
2649 {
2650 pDev->Int.s.pBusRC += offDelta;
2651 if (pDev->Int.s.pMsixPageRC)
2652 pDev->Int.s.pMsixPageRC += offDelta;
2653 }
2654}
2655
2656/**
2657 * @copydoc FNPDMDEVRELOCATE
2658 */
2659static DECLCALLBACK(void) ich9pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2660{
2661 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2662 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2663 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2664
2665 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2666 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2667
2668 /* Relocate RC pointers for the attached pci devices. */
2669 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2670 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2671
2672}
2673
2674/**
2675 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2676 */
2677static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
2678 int iInstance,
2679 PCFGMNODE pCfg)
2680{
2681 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2682
2683 /*
2684 * Validate and read configuration.
2685 */
2686 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
2687 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2688
2689 /* check if RC code is enabled. */
2690 bool fGCEnabled;
2691 int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2692 if (RT_FAILURE(rc))
2693 return PDMDEV_SET_ERROR(pDevIns, rc,
2694 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2695
2696 /* check if R0 code is enabled. */
2697 bool fR0Enabled;
2698 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2699 if (RT_FAILURE(rc))
2700 return PDMDEV_SET_ERROR(pDevIns, rc,
2701 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2702 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
2703
2704 /*
2705 * Init data and register the PCI bus.
2706 */
2707 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2708 pBus->pDevInsR3 = pDevIns;
2709 pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2710 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2711 pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->apDevices));
2712
2713 PDMPCIBUSREG PciBusReg;
2714 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2715 PciBusReg.pfnRegisterR3 = ich9pcibridgeRegister;
2716 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2717 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2718 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2719 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
2720 PciBusReg.pfnSaveExecR3 = ich9pciGenericSaveExec;
2721 PciBusReg.pfnLoadExecR3 = ich9pciGenericLoadExec;
2722 PciBusReg.pfnFakePCIBIOSR3 = NULL; /* Only needed for the first bus. */
2723 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pcibridgeSetIrq" : NULL;
2724 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pcibridgeSetIrq" : NULL;
2725 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2726 if (RT_FAILURE(rc))
2727 return PDMDEV_SET_ERROR(pDevIns, rc,
2728 N_("Failed to register ourselves as a PCI Bus"));
2729 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2730 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2731 N_("PCI helper version mismatch; got %#x expected %#x"),
2732 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2733
2734 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2735 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2736
2737 /*
2738 * Fill in PCI configs and add them to the bus.
2739 */
2740 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2741 PCIDevSetDeviceId( &pBus->aPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
2742 PCIDevSetRevisionId(&pBus->aPciDev, 0xf2);
2743 PCIDevSetClassSub( &pBus->aPciDev, 0x04); /* pci2pci */
2744 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* PCI_bridge */
2745 PCIDevSetClassProg( &pBus->aPciDev, 0x01); /* Supports subtractive decoding. */
2746 PCIDevSetHeaderType(&pBus->aPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
2747 PCIDevSetCommand( &pBus->aPciDev, 0x00);
2748 PCIDevSetStatus( &pBus->aPciDev, 0x20); /* 66MHz Capable. */
2749 PCIDevSetInterruptLine(&pBus->aPciDev, 0x00); /* This device does not assert interrupts. */
2750
2751 /*
2752 * This device does not generate interrupts. Interrupt delivery from
2753 * devices attached to the bus is unaffected.
2754 */
2755 PCIDevSetInterruptPin (&pBus->aPciDev, 0x00);
2756
2757 pBus->aPciDev.pDevIns = pDevIns;
2758
2759 /* Bridge-specific data */
2760 pciDevSetPci2PciBridge(&pBus->aPciDev);
2761 pBus->aPciDev.Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
2762 pBus->aPciDev.Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
2763
2764 /*
2765 * Register this PCI bridge. The called function will take care on which bus we will get registered.
2766 */
2767 rc = PDMDevHlpPCIRegister (pDevIns, &pBus->aPciDev);
2768 if (RT_FAILURE(rc))
2769 return rc;
2770
2771 /*
2772 * The iBus property doesn't really represent the bus number
2773 * because the guest and the BIOS can choose different bus numbers
2774 * for them.
2775 * The bus number is mainly for the setIrq function to indicate
2776 * when the host bus is reached which will have iBus = 0.
2777 * That's why the + 1.
2778 */
2779 pBus->iBus = iInstance + 1;
2780
2781 /*
2782 * Register SSM handlers. We use the same saved state version as for the host bridge
2783 * to make changes easier.
2784 */
2785 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2786 sizeof(*pBus) + 16*128,
2787 "pgm" /* before */,
2788 NULL, NULL, NULL,
2789 NULL, ich9pcibridgeR3SaveExec, NULL,
2790 NULL, ich9pcibridgeR3LoadExec, NULL);
2791 if (RT_FAILURE(rc))
2792 return rc;
2793
2794
2795 return VINF_SUCCESS;
2796}
2797
2798/**
2799 * @copydoc FNPDMDEVRESET
2800 */
2801static void ich9pcibridgeReset(PPDMDEVINS pDevIns)
2802{
2803 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2804
2805 /* Reset config space to default values. */
2806 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_PRIMARY_BUS, 0);
2807 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS, 0);
2808 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
2809
2810 /* PCI-specific reset for each device. */
2811 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2812 {
2813 if (pBus->apDevices[i])
2814 ich9pciResetDevice(pBus->apDevices[i]);
2815 }
2816}
2817
2818
2819/**
2820 * @copydoc FNPDMDEVRELOCATE
2821 */
2822static DECLCALLBACK(void) ich9pcibridgeRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2823{
2824 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2825 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2826
2827 /* Relocate RC pointers for the attached pci devices. */
2828 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2829 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2830}
2831
2832/**
2833 * The PCI bus device registration structure.
2834 */
2835const PDMDEVREG g_DevicePciIch9 =
2836{
2837 /* u32Version */
2838 PDM_DEVREG_VERSION,
2839 /* szName */
2840 "ich9pci",
2841 /* szRCMod */
2842 "VBoxDDGC.gc",
2843 /* szR0Mod */
2844 "VBoxDDR0.r0",
2845 /* pszDescription */
2846 "ICH9 PCI bridge",
2847 /* fFlags */
2848 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2849 /* fClass */
2850 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
2851 /* cMaxInstances */
2852 1,
2853 /* cbInstance */
2854 sizeof(ICH9PCIGLOBALS),
2855 /* pfnConstruct */
2856 ich9pciConstruct,
2857 /* pfnDestruct */
2858 NULL,
2859 /* pfnRelocate */
2860 ich9pciRelocate,
2861 /* pfnIOCtl */
2862 NULL,
2863 /* pfnPowerOn */
2864 NULL,
2865 /* pfnReset */
2866 ich9pciReset,
2867 /* pfnSuspend */
2868 NULL,
2869 /* pfnResume */
2870 NULL,
2871 /* pfnAttach */
2872 NULL,
2873 /* pfnDetach */
2874 NULL,
2875 /* pfnQueryInterface */
2876 NULL,
2877 /* pfnInitComplete */
2878 NULL,
2879 /* pfnPowerOff */
2880 NULL,
2881 /* pfnSoftReset */
2882 NULL,
2883 /* u32VersionEnd */
2884 PDM_DEVREG_VERSION
2885};
2886
2887/**
2888 * The device registration structure
2889 * for the PCI-to-PCI bridge.
2890 */
2891const PDMDEVREG g_DevicePciIch9Bridge =
2892{
2893 /* u32Version */
2894 PDM_DEVREG_VERSION,
2895 /* szName */
2896 "ich9pcibridge",
2897 /* szRCMod */
2898 "VBoxDDGC.gc",
2899 /* szR0Mod */
2900 "VBoxDDR0.r0",
2901 /* pszDescription */
2902 "ICH9 PCI to PCI bridge",
2903 /* fFlags */
2904 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2905 /* fClass */
2906 PDM_DEVREG_CLASS_BUS_PCI,
2907 /* cMaxInstances */
2908 ~0,
2909 /* cbInstance */
2910 sizeof(ICH9PCIBUS),
2911 /* pfnConstruct */
2912 ich9pcibridgeConstruct,
2913 /* pfnDestruct */
2914 NULL,
2915 /* pfnRelocate */
2916 ich9pcibridgeRelocate,
2917 /* pfnIOCtl */
2918 NULL,
2919 /* pfnPowerOn */
2920 NULL,
2921 /* pfnReset */
2922 NULL, /* Must be NULL, to make sure only bus driver handles reset */
2923 /* pfnSuspend */
2924 NULL,
2925 /* pfnResume */
2926 NULL,
2927 /* pfnAttach */
2928 NULL,
2929 /* pfnDetach */
2930 NULL,
2931 /* pfnQueryInterface */
2932 NULL,
2933 /* pfnInitComplete */
2934 NULL,
2935 /* pfnPowerOff */
2936 NULL,
2937 /* pfnSoftReset */
2938 NULL,
2939 /* u32VersionEnd */
2940 PDM_DEVREG_VERSION
2941};
2942
2943#endif /* IN_RING3 */
2944#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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