VirtualBox

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

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

Ich9: Remove the i82801 PCI-to-PCI bridge. It is completely unused and is not the Host-to-PCI bridge either

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 107.7 KB
Line 
1/* $Id: DevPciIch9.cpp 36288 2011-03-15 15:16:17Z 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 (rc != VINF_SUCCESS)
894 return rc;
895
896 rc = MsixInit(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp), pPciDev, pMsiReg);
897 if (rc != VINF_SUCCESS)
898 return rc;
899
900 return rc;
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 config space. */
961 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
962 uint32_t u32Value =
963 (((enmType & PCI_ADDRESS_SPACE_MEM_PREFETCH) != 0) ? (1 << 3) : 0)
964 | (((enmType & PCI_ADDRESS_SPACE_IO) != 0) ? 1 : 0);
965 PCIDevSetDWord(pPciDev, u32Address, u32Value);
966
967 return VINF_SUCCESS;
968}
969
970static DECLCALLBACK(void) ich9pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
971 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
972{
973 if (ppfnReadOld)
974 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
975 pPciDev->Int.s.pfnConfigRead = pfnRead;
976
977 if (ppfnWriteOld)
978 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
979 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
980}
981
982/**
983 * Saves a state of the PCI device.
984 *
985 * @returns VBox status code.
986 * @param pDevIns Device instance of the PCI Bus.
987 * @param pPciDev Pointer to PCI device.
988 * @param pSSM The handle to save the state to.
989 */
990static DECLCALLBACK(int) ich9pciGenericSaveExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
991{
992 Assert(!pciDevIsPassthrough(pPciDev));
993 return SSMR3PutMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
994}
995
996static int ich9pciR3CommonSaveExec(PICH9PCIBUS pBus, PSSMHANDLE pSSM)
997{
998 /*
999 * Iterate thru all the devices.
1000 */
1001 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
1002 {
1003 PPCIDEVICE pDev = pBus->apDevices[i];
1004 if (pDev)
1005 {
1006 /* Device position */
1007 SSMR3PutU32(pSSM, i);
1008 /* PCI config registers */
1009 SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
1010
1011 /* Device flags */
1012 int rc = SSMR3PutU32(pSSM, pDev->Int.s.fFlags);
1013 if (RT_FAILURE(rc))
1014 return rc;
1015
1016 /* IRQ pin state */
1017 rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
1018 if (RT_FAILURE(rc))
1019 return rc;
1020
1021 /* MSI info */
1022 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapOffset);
1023 if (RT_FAILURE(rc))
1024 return rc;
1025 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapSize);
1026 if (RT_FAILURE(rc))
1027 return rc;
1028
1029 /* MSI-X info */
1030 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapOffset);
1031 if (RT_FAILURE(rc))
1032 return rc;
1033 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapSize);
1034 if (RT_FAILURE(rc))
1035 return rc;
1036 /* Save MSI-X page state */
1037 if (pDev->Int.s.u8MsixCapOffset != 0)
1038 {
1039 Assert(pDev->Int.s.pMsixPageR3 != NULL);
1040 SSMR3PutMem(pSSM, pDev->Int.s.pMsixPageR3, 0x1000);
1041 if (RT_FAILURE(rc))
1042 return rc;
1043 }
1044 }
1045 }
1046 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1047}
1048
1049static DECLCALLBACK(int) ich9pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1050{
1051 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1052
1053 /*
1054 * Bus state data.
1055 */
1056 SSMR3PutU32(pSSM, pThis->uConfigReg);
1057
1058 /*
1059 * Save IRQ states.
1060 */
1061 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
1062 SSMR3PutU32(pSSM, pThis->uaPciApicIrqLevels[i]);
1063
1064 SSMR3PutU32(pSSM, ~0); /* separator */
1065
1066 return ich9pciR3CommonSaveExec(&pThis->aPciBus, pSSM);
1067}
1068
1069
1070static DECLCALLBACK(int) ich9pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1071{
1072 PICH9PCIBUS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1073 return ich9pciR3CommonSaveExec(pThis, pSSM);
1074}
1075
1076
1077static void ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, uint32_t u32Value, unsigned cb)
1078{
1079 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1080
1081 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u u32Value=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, u32Value, cb));
1082
1083 /* If the current bus is not the target bus search for the bus which contains the device. */
1084 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1085 {
1086 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1087 if (pBridgeDevice)
1088 {
1089 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
1090 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
1091 }
1092 }
1093 else
1094 {
1095 /* This is the target bus, pass the write to the device. */
1096 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1097 if (pPciDev)
1098 {
1099 Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1100 pPciDev->Int.s.pfnConfigWrite(pPciDev, u32Address, u32Value, cb);
1101 }
1102 }
1103}
1104
1105static uint32_t ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, unsigned cb)
1106{
1107 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1108 uint32_t u32Value;
1109
1110 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
1111
1112 /* If the current bus is not the target bus search for the bus which contains the device. */
1113 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1114 {
1115 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1116 if (pBridgeDevice)
1117 {
1118 AssertPtr( pBridgeDevice->Int.s.pfnBridgeConfigRead);
1119 u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
1120 }
1121 else
1122 ich9pciNoMem(&u32Value, 4);
1123 }
1124 else
1125 {
1126 /* This is the target bus, pass the read to the device. */
1127 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1128 if (pPciDev)
1129 {
1130 u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev, u32Address, cb);
1131 Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1132 }
1133 else
1134 ich9pciNoMem(&u32Value, 4);
1135 }
1136
1137 return u32Value;
1138}
1139
1140
1141/**
1142 * Common routine for restoring the config registers of a PCI device.
1143 *
1144 * @param pDev The PCI device.
1145 * @param pbSrcConfig The configuration register values to be loaded.
1146 * @param fIsBridge Whether this is a bridge device or not.
1147 */
1148static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
1149{
1150 /*
1151 * This table defines the fields for normal devices and bridge devices, and
1152 * the order in which they need to be restored.
1153 */
1154 static const struct PciField
1155 {
1156 uint8_t off;
1157 uint8_t cb;
1158 uint8_t fWritable;
1159 uint8_t fBridge;
1160 const char *pszName;
1161 } s_aFields[] =
1162 {
1163 /* off,cb,fW,fB, pszName */
1164 { VBOX_PCI_VENDOR_ID, 2, 0, 3, "VENDOR_ID" },
1165 { VBOX_PCI_DEVICE_ID, 2, 0, 3, "DEVICE_ID" },
1166 { VBOX_PCI_STATUS, 2, 1, 3, "STATUS" },
1167 { VBOX_PCI_REVISION_ID, 1, 0, 3, "REVISION_ID" },
1168 { VBOX_PCI_CLASS_PROG, 1, 0, 3, "CLASS_PROG" },
1169 { VBOX_PCI_CLASS_SUB, 1, 0, 3, "CLASS_SUB" },
1170 { VBOX_PCI_CLASS_BASE, 1, 0, 3, "CLASS_BASE" },
1171 { VBOX_PCI_CACHE_LINE_SIZE, 1, 1, 3, "CACHE_LINE_SIZE" },
1172 { VBOX_PCI_LATENCY_TIMER, 1, 1, 3, "LATENCY_TIMER" },
1173 { VBOX_PCI_HEADER_TYPE, 1, 0, 3, "HEADER_TYPE" },
1174 { VBOX_PCI_BIST, 1, 1, 3, "BIST" },
1175 { VBOX_PCI_BASE_ADDRESS_0, 4, 1, 3, "BASE_ADDRESS_0" },
1176 { VBOX_PCI_BASE_ADDRESS_1, 4, 1, 3, "BASE_ADDRESS_1" },
1177 { VBOX_PCI_BASE_ADDRESS_2, 4, 1, 1, "BASE_ADDRESS_2" },
1178 { VBOX_PCI_PRIMARY_BUS, 1, 1, 2, "PRIMARY_BUS" }, // fWritable = ??
1179 { VBOX_PCI_SECONDARY_BUS, 1, 1, 2, "SECONDARY_BUS" }, // fWritable = ??
1180 { VBOX_PCI_SUBORDINATE_BUS, 1, 1, 2, "SUBORDINATE_BUS" }, // fWritable = ??
1181 { VBOX_PCI_SEC_LATENCY_TIMER, 1, 1, 2, "SEC_LATENCY_TIMER" }, // fWritable = ??
1182 { VBOX_PCI_BASE_ADDRESS_3, 4, 1, 1, "BASE_ADDRESS_3" },
1183 { VBOX_PCI_IO_BASE, 1, 1, 2, "IO_BASE" }, // fWritable = ??
1184 { VBOX_PCI_IO_LIMIT, 1, 1, 2, "IO_LIMIT" }, // fWritable = ??
1185 { VBOX_PCI_SEC_STATUS, 2, 1, 2, "SEC_STATUS" }, // fWritable = ??
1186 { VBOX_PCI_BASE_ADDRESS_4, 4, 1, 1, "BASE_ADDRESS_4" },
1187 { VBOX_PCI_MEMORY_BASE, 2, 1, 2, "MEMORY_BASE" }, // fWritable = ??
1188 { VBOX_PCI_MEMORY_LIMIT, 2, 1, 2, "MEMORY_LIMIT" }, // fWritable = ??
1189 { VBOX_PCI_BASE_ADDRESS_5, 4, 1, 1, "BASE_ADDRESS_5" },
1190 { VBOX_PCI_PREF_MEMORY_BASE, 2, 1, 2, "PREF_MEMORY_BASE" }, // fWritable = ??
1191 { VBOX_PCI_PREF_MEMORY_LIMIT, 2, 1, 2, "PREF_MEMORY_LIMIT" }, // fWritable = ??
1192 { VBOX_PCI_CARDBUS_CIS, 4, 1, 1, "CARDBUS_CIS" }, // fWritable = ??
1193 { VBOX_PCI_PREF_BASE_UPPER32, 4, 1, 2, "PREF_BASE_UPPER32" }, // fWritable = ??
1194 { VBOX_PCI_SUBSYSTEM_VENDOR_ID, 2, 0, 1, "SUBSYSTEM_VENDOR_ID" },// fWritable = !?
1195 { VBOX_PCI_PREF_LIMIT_UPPER32, 4, 1, 2, "PREF_LIMIT_UPPER32" },// fWritable = ??
1196 { VBOX_PCI_SUBSYSTEM_ID, 2, 0, 1, "SUBSYSTEM_ID" }, // fWritable = !?
1197 { VBOX_PCI_ROM_ADDRESS, 4, 1, 1, "ROM_ADDRESS" }, // fWritable = ?!
1198 { VBOX_PCI_IO_BASE_UPPER16, 2, 1, 2, "IO_BASE_UPPER16" }, // fWritable = ?!
1199 { VBOX_PCI_IO_LIMIT_UPPER16, 2, 1, 2, "IO_LIMIT_UPPER16" }, // fWritable = ?!
1200 { VBOX_PCI_CAPABILITY_LIST, 4, 0, 3, "CAPABILITY_LIST" }, // fWritable = !? cb=!?
1201 { VBOX_PCI_RESERVED_38, 4, 1, 1, "RESERVED_38" }, // ???
1202 { VBOX_PCI_ROM_ADDRESS_BR, 4, 1, 2, "ROM_ADDRESS_BR" }, // fWritable = !? cb=!? fBridge=!?
1203 { VBOX_PCI_INTERRUPT_LINE, 1, 1, 3, "INTERRUPT_LINE" }, // fBridge=??
1204 { VBOX_PCI_INTERRUPT_PIN, 1, 0, 3, "INTERRUPT_PIN" }, // fBridge=??
1205 { VBOX_PCI_MIN_GNT, 1, 0, 1, "MIN_GNT" },
1206 { VBOX_PCI_BRIDGE_CONTROL, 2, 1, 2, "BRIDGE_CONTROL" }, // fWritable = !?
1207 { VBOX_PCI_MAX_LAT, 1, 0, 1, "MAX_LAT" },
1208 /* The COMMAND register must come last as it requires the *ADDRESS*
1209 registers to be restored before we pretent to change it from 0 to
1210 whatever value the guest assigned it. */
1211 { VBOX_PCI_COMMAND, 2, 1, 3, "COMMAND" },
1212 };
1213
1214#ifdef RT_STRICT
1215 /* Check that we've got full register coverage. */
1216 uint32_t bmDevice[0x40 / 32];
1217 uint32_t bmBridge[0x40 / 32];
1218 RT_ZERO(bmDevice);
1219 RT_ZERO(bmBridge);
1220 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1221 {
1222 uint8_t off = s_aFields[i].off;
1223 uint8_t cb = s_aFields[i].cb;
1224 uint8_t f = s_aFields[i].fBridge;
1225 while (cb-- > 0)
1226 {
1227 if (f & 1) AssertMsg(!ASMBitTest(bmDevice, off), ("%#x\n", off));
1228 if (f & 2) AssertMsg(!ASMBitTest(bmBridge, off), ("%#x\n", off));
1229 if (f & 1) ASMBitSet(bmDevice, off);
1230 if (f & 2) ASMBitSet(bmBridge, off);
1231 off++;
1232 }
1233 }
1234 for (uint32_t off = 0; off < 0x40; off++)
1235 {
1236 AssertMsg(ASMBitTest(bmDevice, off), ("%#x\n", off));
1237 AssertMsg(ASMBitTest(bmBridge, off), ("%#x\n", off));
1238 }
1239#endif
1240
1241 /*
1242 * Loop thru the fields covering the 64 bytes of standard registers.
1243 */
1244 uint8_t const fBridge = fIsBridge ? 2 : 1;
1245 Assert(!pciDevIsPassthrough(pDev));
1246 uint8_t *pbDstConfig = &pDev->config[0];
1247
1248 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1249 if (s_aFields[i].fBridge & fBridge)
1250 {
1251 uint8_t const off = s_aFields[i].off;
1252 uint8_t const cb = s_aFields[i].cb;
1253 uint32_t u32Src;
1254 uint32_t u32Dst;
1255 switch (cb)
1256 {
1257 case 1:
1258 u32Src = pbSrcConfig[off];
1259 u32Dst = pbDstConfig[off];
1260 break;
1261 case 2:
1262 u32Src = *(uint16_t const *)&pbSrcConfig[off];
1263 u32Dst = *(uint16_t const *)&pbDstConfig[off];
1264 break;
1265 case 4:
1266 u32Src = *(uint32_t const *)&pbSrcConfig[off];
1267 u32Dst = *(uint32_t const *)&pbDstConfig[off];
1268 break;
1269 default:
1270 AssertFailed();
1271 continue;
1272 }
1273
1274 if ( u32Src != u32Dst
1275 || off == VBOX_PCI_COMMAND)
1276 {
1277 if (u32Src != u32Dst)
1278 {
1279 if (!s_aFields[i].fWritable)
1280 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
1281 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1282 else
1283 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
1284 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1285 }
1286 if (off == VBOX_PCI_COMMAND)
1287 PCIDevSetCommand(pDev, 0); /* For remapping, see ich9pciR3CommonLoadExec. */
1288 pDev->Int.s.pfnConfigWrite(pDev, off, u32Src, cb);
1289 }
1290 }
1291
1292 /*
1293 * The device dependent registers.
1294 *
1295 * We will not use ConfigWrite here as we have no clue about the size
1296 * of the registers, so the device is responsible for correctly
1297 * restoring functionality governed by these registers.
1298 */
1299 for (uint32_t off = 0x40; off < sizeof(pDev->config); off++)
1300 if (pbDstConfig[off] != pbSrcConfig[off])
1301 {
1302 LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
1303 pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
1304 pbDstConfig[off] = pbSrcConfig[off];
1305 }
1306}
1307
1308/**
1309 * Common worker for ich9pciR3LoadExec and ich9pcibridgeR3LoadExec.
1310 *
1311 * @returns VBox status code.
1312 * @param pBus The bus which data is being loaded.
1313 * @param pSSM The saved state handle.
1314 * @param uVersion The data version.
1315 * @param uPass The pass.
1316 */
1317static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1318{
1319 uint32_t u32;
1320 uint32_t i;
1321 int rc;
1322
1323 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1324
1325 /*
1326 * Iterate thru all the devices and write 0 to the COMMAND register so
1327 * that all the memory is unmapped before we start restoring the saved
1328 * mapping locations.
1329 *
1330 * The register value is restored afterwards so we can do proper
1331 * LogRels in pciR3CommonRestoreConfig.
1332 */
1333 for (i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
1334 {
1335 PPCIDEVICE pDev = pBus->apDevices[i];
1336 if (pDev)
1337 {
1338 uint16_t u16 = PCIDevGetCommand(pDev);
1339 pDev->Int.s.pfnConfigWrite(pDev, VBOX_PCI_COMMAND, 0, 2);
1340 PCIDevSetCommand(pDev, u16);
1341 Assert(PCIDevGetCommand(pDev) == u16);
1342 }
1343 }
1344
1345 void* pvMsixPage = RTMemTmpAllocZ(0x1000);
1346 /*
1347 * Iterate all the devices.
1348 */
1349 for (i = 0;; i++)
1350 {
1351 PPCIDEVICE pDev;
1352 PCIDEVICE DevTmp;
1353
1354 /* index / terminator */
1355 rc = SSMR3GetU32(pSSM, &u32);
1356 if (RT_FAILURE(rc))
1357 return rc;
1358 if (u32 == (uint32_t)~0)
1359 break;
1360 if ( u32 >= RT_ELEMENTS(pBus->apDevices)
1361 || u32 < i)
1362 {
1363 AssertMsgFailed(("u32=%#x i=%#x\n", u32, i));
1364 goto out;
1365 }
1366
1367 /* skip forward to the device checking that no new devices are present. */
1368 for (; i < u32; i++)
1369 {
1370 pDev = pBus->apDevices[i];
1371 if (pDev)
1372 {
1373 LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pDev->name,
1374 PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev)));
1375 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1376 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1377 i, pDev->name, PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev));
1378 }
1379 }
1380
1381 /* get the data */
1382 DevTmp.Int.s.fFlags = 0;
1383 DevTmp.Int.s.u8MsiCapOffset = 0;
1384 DevTmp.Int.s.u8MsiCapSize = 0;
1385 DevTmp.Int.s.u8MsixCapOffset = 0;
1386 DevTmp.Int.s.u8MsixCapSize = 0;
1387 DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1388 SSMR3GetMem(pSSM, DevTmp.config, sizeof(DevTmp.config));
1389
1390 rc = SSMR3GetU32(pSSM, &DevTmp.Int.s.fFlags);
1391 if (RT_FAILURE(rc))
1392 goto out;
1393
1394 rc = SSMR3GetS32(pSSM, &DevTmp.Int.s.uIrqPinState);
1395 if (RT_FAILURE(rc))
1396 goto out;
1397
1398 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapOffset);
1399 if (RT_FAILURE(rc))
1400 goto out;
1401
1402 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapSize);
1403 if (RT_FAILURE(rc))
1404 goto out;
1405
1406 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapOffset);
1407 if (RT_FAILURE(rc))
1408 goto out;
1409
1410 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapSize);
1411 if (RT_FAILURE(rc))
1412 goto out;
1413
1414 /* Load MSI-X page state */
1415 if (DevTmp.Int.s.u8MsixCapOffset != 0)
1416 {
1417 Assert(pvMsixPage != NULL);
1418 SSMR3GetMem(pSSM, pvMsixPage, 0x1000);
1419 if (RT_FAILURE(rc))
1420 goto out;
1421 }
1422
1423 /* check that it's still around. */
1424 pDev = pBus->apDevices[i];
1425 if (!pDev)
1426 {
1427 LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
1428 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1429 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1430 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1431 i, PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp));
1432 continue;
1433 }
1434
1435 /* match the vendor id assuming that this will never be changed. */
1436 if ( PCIDevGetVendorId(&DevTmp) != PCIDevGetVendorId(pDev))
1437 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1438 i, pDev->name, PCIDevGetVendorId(&DevTmp), PCIDevGetVendorId(pDev));
1439
1440 /* commit the loaded device config. */
1441 Assert(!pciDevIsPassthrough(pDev));
1442 pciR3CommonRestoreConfig(pDev, &DevTmp.config[0], false ); /** @todo fix bridge fun! */
1443
1444 pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
1445 pDev->Int.s.u8MsiCapOffset = DevTmp.Int.s.u8MsiCapOffset;
1446 pDev->Int.s.u8MsiCapSize = DevTmp.Int.s.u8MsiCapSize;
1447 pDev->Int.s.u8MsixCapOffset = DevTmp.Int.s.u8MsixCapOffset;
1448 pDev->Int.s.u8MsixCapSize = DevTmp.Int.s.u8MsixCapSize;
1449 if (DevTmp.Int.s.u8MsixCapSize != 0)
1450 {
1451 Assert(pDev->Int.s.pMsixPageR3 != NULL);
1452 memcpy(pDev->Int.s.pMsixPageR3, pvMsixPage, 0x1000);
1453 }
1454 }
1455
1456 out:
1457 if (pvMsixPage)
1458 RTMemTmpFree(pvMsixPage);
1459
1460 return rc;
1461}
1462
1463/**
1464 * Loads a saved PCI device state.
1465 *
1466 * @returns VBox status code.
1467 * @param pDevIns Device instance of the PCI Bus.
1468 * @param pPciDev Pointer to PCI device.
1469 * @param pSSM The handle to the saved state.
1470 */
1471static DECLCALLBACK(int) ich9pciGenericLoadExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
1472{
1473 Assert(!pciDevIsPassthrough(pPciDev));
1474 return SSMR3GetMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
1475}
1476
1477static DECLCALLBACK(int) ich9pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1478{
1479 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1480 PICH9PCIBUS pBus = &pThis->aPciBus;
1481 uint32_t u32;
1482 int rc;
1483
1484 /* We ignore this version as there's no saved state with it anyway */
1485 if (uVersion == VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
1486 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1487 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1488 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1489
1490 /*
1491 * Bus state data.
1492 */
1493 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1494
1495 /*
1496 * Load IRQ states.
1497 */
1498 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
1499 SSMR3GetU32(pSSM, (uint32_t*)&pThis->uaPciApicIrqLevels[i]);
1500
1501 /* separator */
1502 rc = SSMR3GetU32(pSSM, &u32);
1503 if (RT_FAILURE(rc))
1504 return rc;
1505 if (u32 != (uint32_t)~0)
1506 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1507
1508 return ich9pciR3CommonLoadExec(pBus, pSSM, uVersion, uPass);
1509}
1510
1511static DECLCALLBACK(int) ich9pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1512{
1513 PICH9PCIBUS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1514 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1515 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1516 return ich9pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
1517}
1518
1519static uint32_t ich9pciConfigRead(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t len)
1520{
1521 /* Will only work in LSB case */
1522 uint32_t u32Val;
1523 PciAddress aPciAddr;
1524
1525 aPciAddr.iBus = uBus;
1526 aPciAddr.iDeviceFunc = uDevFn;
1527 aPciAddr.iRegister = addr;
1528
1529 /* cannot be rescheduled, as already in R3 */
1530 int rc = ich9pciDataReadAddr(pGlobals, &aPciAddr, len, &u32Val, VERR_INTERNAL_ERROR);
1531 AssertRC(rc);
1532 return u32Val;
1533}
1534
1535static void ich9pciConfigWrite(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val, uint32_t len)
1536{
1537 PciAddress aPciAddr;
1538
1539 aPciAddr.iBus = uBus;
1540 aPciAddr.iDeviceFunc = uDevFn;
1541 aPciAddr.iRegister = addr;
1542
1543 /* cannot be rescheduled, as already in R3 */
1544 int rc = ich9pciDataWriteAddr(pGlobals, &aPciAddr, val, len, VERR_INTERNAL_ERROR);
1545 AssertRC(rc);
1546}
1547
1548static void ich9pciSetRegionAddress(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int iRegion, uint64_t addr)
1549{
1550 uint32_t uReg = ich9pciGetRegionReg(iRegion);
1551
1552 /* Read memory type first. */
1553 uint8_t uResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, uReg, 1);
1554 /* Read command register. */
1555 uint16_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
1556
1557 Log(("Set region address: %02x:%02x.%d region %d address=%lld\n",
1558 uBus, uDevFn>>3, uDevFn&7, addr));
1559
1560 if ( iRegion == PCI_ROM_SLOT )
1561 uCmd |= PCI_COMMAND_MEMACCESS;
1562 else if ((uResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO)
1563 uCmd |= PCI_COMMAND_IOACCESS; /* Enable I/O space access. */
1564 else /* The region is MMIO. */
1565 uCmd |= PCI_COMMAND_MEMACCESS; /* Enable MMIO access. */
1566
1567 bool f64Bit = (uResourceType & PCI_ADDRESS_SPACE_BAR64) != 0;
1568
1569 /* Write address of the device. */
1570 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg, (uint32_t)addr, 4);
1571 if (f64Bit)
1572 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg + 4, (uint32_t)(addr >> 32), 4);
1573
1574 /* enable memory mappings */
1575 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
1576}
1577
1578
1579static void ich9pciBiosInitBridge(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
1580{
1581 Log(("BIOS init bridge: %02x::%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
1582
1583 /*
1584 * The I/O range for the bridge must be aligned to a 4KB boundary.
1585 * This does not change anything really as the access to the device is not going
1586 * through the bridge but we want to be compliant to the spec.
1587 */
1588 if ((pGlobals->uPciBiosIo % 4096) != 0)
1589 {
1590 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1591 Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosIo));
1592 }
1593 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->uPciBiosIo >> 8) & 0xf0, 1);
1594
1595 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
1596 if ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0)
1597 {
1598 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1599 Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosMmio));
1600 }
1601 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xffff0), 2);
1602
1603 /* Save values to compare later to. */
1604 uint32_t u32IoAddressBase = pGlobals->uPciBiosIo;
1605 uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
1606 uint8_t uBridgeBus = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_SECONDARY_BUS, 1);
1607
1608 /* Init devices behind the bridge and possibly other bridges as well. */
1609 for (int iDev = 0; iDev <= 255; iDev++)
1610 ich9pciBiosInitDevice(pGlobals, uBridgeBus, iDev);
1611
1612 /*
1613 * Set I/O limit register. If there is no device with I/O space behind the bridge
1614 * we set a lower value than in the base register.
1615 * The result with a real bridge is that no I/O transactions are passed to the secondary
1616 * interface. Again this doesn't really matter here but we want to be compliant to the spec.
1617 */
1618 if ((u32IoAddressBase != pGlobals->uPciBiosIo) && ((pGlobals->uPciBiosIo % 4096) != 0))
1619 {
1620 /* The upper boundary must be one byte less than a 4KB boundary. */
1621 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1622 }
1623
1624 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo >> 8) & 0xf0) - 1, 1);
1625
1626 /* Same with the MMIO limit register but with 1MB boundary here. */
1627 if ((u32MMIOAddressBase != pGlobals->uPciBiosMmio) && ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0))
1628 {
1629 /* The upper boundary must be one byte less than a 1MB boundary. */
1630 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1631 }
1632 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xfff0)) - 1, 2);
1633
1634 /*
1635 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
1636 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
1637 * the base register than in the limit register.
1638 */
1639 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0, 2);
1640 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0, 2);
1641 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00, 4);
1642 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00, 4);
1643}
1644
1645static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
1646{
1647 uint16_t uDevClass, uVendor, uDevice;
1648 uint8_t uCmd;
1649
1650 uDevClass = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_CLASS_DEVICE, 2);
1651 uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
1652 uDevice = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_DEVICE_ID, 2);
1653
1654 /* If device is present */
1655 if (uVendor == 0xffff)
1656 return;
1657
1658 Log(("BIOS init device: %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
1659
1660 switch (uDevClass)
1661 {
1662 case 0x0101:
1663 /* IDE controller */
1664 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x40, 0x8000, 2); /* enable IDE0 */
1665 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x42, 0x8000, 2); /* enable IDE1 */
1666 goto default_map;
1667 break;
1668 case 0x0300:
1669 /* VGA controller */
1670 if (uVendor != 0x80ee)
1671 goto default_map;
1672 /* VGA: map frame buffer to default Bochs VBE address */
1673 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, 0, 0xE0000000);
1674 /*
1675 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
1676 * only the framebuffer (i.e., a memory region) is explicitly registered via
1677 * ich9pciSetRegionAddress, so I/O decoding must be enabled manually.
1678 */
1679 uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 1);
1680 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND,
1681 /* Enable I/O space access. */
1682 uCmd | PCI_COMMAND_IOACCESS,
1683 1);
1684 break;
1685 case 0x0604:
1686 /* PCI-to-PCI bridge. */
1687 AssertMsg(pGlobals->uBus < 255, ("Too many bridges on the bus\n"));
1688 ich9pciBiosInitBridge(pGlobals, uBus, uDevFn);
1689 break;
1690 default:
1691 default_map:
1692 {
1693 /* default memory mappings */
1694 /*
1695 * We ignore ROM region here.
1696 */
1697 for (int iRegion = 0; iRegion < (PCI_NUM_REGIONS-1); iRegion++)
1698 {
1699 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
1700
1701 /* Calculate size - we write all 1s into the BAR, and then evaluate which bits
1702 are cleared. . */
1703 uint8_t u8ResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 1);
1704
1705 bool f64bit = (u8ResourceType & PCI_ADDRESS_SPACE_BAR64) != 0;
1706 bool fIsPio = ((u8ResourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS);
1707 uint64_t cbRegSize64 = 0;
1708
1709 if (f64bit)
1710 {
1711 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1712 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address+4, UINT32_C(0xffffffff), 4);
1713 cbRegSize64 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1714 cbRegSize64 |= ((uint64_t)ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address+4, 4) << 32);
1715 cbRegSize64 &= ~UINT64_C(0x0f);
1716 cbRegSize64 = (~cbRegSize64) + 1;
1717
1718 /* No 64-bit PIO regions possible. */
1719 Assert((u8ResourceType & PCI_COMMAND_IOACCESS) == 0);
1720 }
1721 else
1722 {
1723 uint32_t cbRegSize32;
1724 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1725 cbRegSize32 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1726
1727 /* Clear resource information depending on resource type. */
1728 if (fIsPio) /* PIO */
1729 cbRegSize32 &= ~UINT32_C(0x01);
1730 else /* MMIO */
1731 cbRegSize32 &= ~UINT32_C(0x0f);
1732
1733 /*
1734 * Invert all bits and add 1 to get size of the region.
1735 * (From PCI implementation note)
1736 */
1737 if (fIsPio && (cbRegSize32 & UINT32_C(0xffff0000)) == 0)
1738 cbRegSize32 = (~(cbRegSize32 | UINT32_C(0xffff0000))) + 1;
1739 else
1740 cbRegSize32 = (~cbRegSize32) + 1;
1741
1742 cbRegSize64 = cbRegSize32;
1743 }
1744 Assert(cbRegSize64 == (uint32_t)cbRegSize64);
1745 Log2(("%s: Size of region %u for device %d on bus %d is %lld\n", __FUNCTION__, iRegion, uDevFn, uBus, cbRegSize64));
1746
1747 if (cbRegSize64)
1748 {
1749 uint32_t cbRegSize32 = (uint32_t)cbRegSize64;
1750 uint32_t* paddr = fIsPio ? &pGlobals->uPciBiosIo : &pGlobals->uPciBiosMmio;
1751 *paddr = (*paddr + cbRegSize32 - 1) & ~(cbRegSize32 - 1);
1752 Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), iRegion, *paddr));
1753 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, *paddr);
1754 *paddr += cbRegSize32;
1755 Log2(("%s: New address is %#x\n", __FUNCTION__, *paddr));
1756
1757 if (f64bit)
1758 iRegion++; /* skip next region */
1759 }
1760 }
1761 break;
1762 }
1763 }
1764
1765 /* map the interrupt */
1766 uint32_t iPin = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_PIN, 1);
1767 if (iPin != 0)
1768 {
1769 iPin--;
1770
1771 if (uBus != 0)
1772 {
1773 /* Find bus this device attached to. */
1774 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1775 while (1)
1776 {
1777 PPCIDEVICE pBridge = ich9pciFindBridge(pBus, uBus);
1778 if (!pBridge)
1779 {
1780 Assert(false);
1781 break;
1782 }
1783 if (uBus == PCIDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS))
1784 {
1785 /* OK, found bus this device attached to. */
1786 break;
1787 }
1788 pBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1789 }
1790
1791 /* We need to go up to the host bus to see which irq pin this
1792 * device will use there. See logic in ich9pcibridgeSetIrq().
1793 */
1794 while (pBus->iBus != 0)
1795 {
1796 /* Get the pin the device would assert on the bridge. */
1797 iPin = ((pBus->aPciDev.devfn >> 3) + iPin) & 3;
1798 pBus = pBus->aPciDev.Int.s.pBusR3;
1799 };
1800 }
1801
1802 int iIrq = aPciIrqs[ich9pciSlotGetPirq(uBus, uDevFn, iPin)];
1803 Log(("Using pin %d and IRQ %d for device %02x:%02x.%d\n",
1804 iPin, iIrq, uBus, uDevFn>>3, uDevFn&7));
1805 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_LINE, iIrq, 1);
1806 }
1807}
1808
1809/* Initializes bridges registers used for routing. */
1810static void ich9pciInitBridgeTopology(PICH9PCIGLOBALS pGlobals, PICH9PCIBUS pBus)
1811{
1812 PPCIDEVICE pBridgeDev = &pBus->aPciDev;
1813
1814 /* Set only if we are not on the root bus, it has no primary bus attached. */
1815 if (pGlobals->uBus != 0)
1816 {
1817 PCIDevSetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS, pGlobals->uBus);
1818 PCIDevSetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS, pGlobals->uBus);
1819 }
1820
1821 pGlobals->uBus++;
1822 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
1823 {
1824 PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
1825 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
1826 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
1827 PICH9PCIBUS pChildBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1828 ich9pciInitBridgeTopology(pGlobals, pChildBus);
1829 }
1830 PCIDevSetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uBus);
1831 Log2(("ich9pciInitBridgeTopology: for bus %p: primary=%d secondary=%d subordinate=%d\n",
1832 pBus,
1833 PCIDevGetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS),
1834 PCIDevGetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS),
1835 PCIDevGetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS)
1836 ));
1837}
1838
1839
1840static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
1841{
1842 unsigned i;
1843 uint8_t elcr[2] = {0, 0};
1844 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1845 PVM pVM = PDMDevHlpGetVM(pDevIns);
1846 Assert(pVM);
1847
1848 /*
1849 * Set the start addresses.
1850 */
1851 pGlobals->uPciBiosIo = 0xd000;
1852 pGlobals->uPciBiosMmio = UINT32_C(0xf0000000);
1853 pGlobals->uBus = 0;
1854
1855 /*
1856 * Assign bridge topology, for further routing to work.
1857 */
1858 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1859 ich9pciInitBridgeTopology(pGlobals, pBus);
1860
1861 /*
1862 * Init the devices.
1863 */
1864 for (i = 0; i < 256; i++)
1865 {
1866 ich9pciBiosInitDevice(pGlobals, 0, i);
1867 }
1868
1869 return VINF_SUCCESS;
1870}
1871
1872static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len)
1873{
1874 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1875 {
1876 AssertMsgReturn(false, ("Read from extended registers falled back to generic code\n"), 0);
1877 }
1878
1879 AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
1880 0);
1881 if ( pciDevIsMsiCapable(aDev)
1882 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1883 && (u32Address < aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize)
1884 )
1885 {
1886 return MsiPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1887 }
1888
1889 if ( pciDevIsMsixCapable(aDev)
1890 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1891 && (u32Address < aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize)
1892 )
1893 {
1894 return MsixPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1895 }
1896
1897 AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
1898 0);
1899 switch (len)
1900 {
1901 case 1:
1902 return PCIDevGetByte(aDev, u32Address);
1903 case 2:
1904 return PCIDevGetWord(aDev, u32Address);
1905 case 4:
1906 return PCIDevGetDWord(aDev, u32Address);
1907 default:
1908 Assert(false);
1909 return 0;
1910 }
1911}
1912
1913DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset, uint8_t u8Val)
1914{
1915 PCIIORegion * pRegion = &aDev->Int.s.aIORegions[iRegion];
1916
1917 int iRegionSize = pRegion->size;
1918
1919 Log3(("ich9pciWriteBarByte: region=%d off=%d val=%x size=%d\n",
1920 iRegion, iOffset, u8Val, iRegionSize));
1921
1922 /* Region doesn't exist */
1923 if (iRegionSize == 0)
1924 return;
1925
1926 uint32_t uAddr = ich9pciGetRegionReg(iRegion) + iOffset;
1927 /* Region size must be power of two */
1928 Assert((iRegionSize & (iRegionSize - 1)) == 0);
1929 uint8_t uMask = (((uint32_t)iRegionSize - 1) >> (iOffset*8) ) & 0xff;
1930
1931 if (iOffset == 0)
1932 {
1933 uMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO) ?
1934 (1 << 2) - 1 /* 2 lowest bits for IO region */ :
1935 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
1936
1937 }
1938
1939 uint8_t u8Old = PCIDevGetByte(aDev, uAddr) & uMask;
1940 u8Val = (u8Old & uMask) | (u8Val & ~uMask);
1941
1942 Log3(("ich9pciWriteBarByte: was %x writing %x\n", u8Old, u8Val));
1943
1944 PCIDevSetByte(aDev, uAddr, u8Val);
1945}
1946
1947/**
1948 * See paragraph 7.5 of PCI Express specification (p. 349) for definition of
1949 * registers and their writability policy.
1950 */
1951static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Address,
1952 uint32_t val, unsigned len)
1953{
1954 Assert(len <= 4);
1955
1956 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1957 {
1958 AssertMsgReturnVoid(false, ("Write to extended registers falled back to generic code\n"));
1959 }
1960
1961 AssertMsgReturnVoid(u32Address + len <= 256, ("Write after end of PCI config space\n"));
1962
1963 if ( pciDevIsMsiCapable(aDev)
1964 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1965 && (u32Address < aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize)
1966 )
1967 {
1968 MsiPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1969 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1970 aDev, u32Address, val, len);
1971 return;
1972 }
1973
1974 if ( pciDevIsMsixCapable(aDev)
1975 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1976 && (u32Address < aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize)
1977 )
1978 {
1979 MsixPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1980 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1981 aDev, u32Address, val, len);
1982 return;
1983 }
1984
1985 uint32_t addr = u32Address;
1986 bool fUpdateMappings = false;
1987 bool fP2PBridge = false;
1988 bool fPassthrough = pciDevIsPassthrough(aDev);
1989 uint8_t u8HeaderType = ich9pciGetByte(aDev, VBOX_PCI_HEADER_TYPE);
1990
1991 for (uint32_t i = 0; i < len; i++)
1992 {
1993 bool fWritable = false;
1994 bool fRom = false;
1995 switch (u8HeaderType)
1996 {
1997 case 0x00: /* normal device */
1998 case 0x80: /* multi-function device */
1999 switch (addr)
2000 {
2001 /* Read-only registers */
2002 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
2003 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
2004 case VBOX_PCI_REVISION_ID:
2005 case VBOX_PCI_CLASS_PROG:
2006 case VBOX_PCI_CLASS_SUB:
2007 case VBOX_PCI_CLASS_BASE:
2008 case VBOX_PCI_HEADER_TYPE:
2009 case VBOX_PCI_SUBSYSTEM_VENDOR_ID: case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
2010 case VBOX_PCI_SUBSYSTEM_ID: case VBOX_PCI_SUBSYSTEM_ID+1:
2011 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS+1: case VBOX_PCI_ROM_ADDRESS+2: case VBOX_PCI_ROM_ADDRESS+3:
2012 case VBOX_PCI_CAPABILITY_LIST:
2013 case VBOX_PCI_INTERRUPT_PIN:
2014 fWritable = false;
2015 break;
2016 /* Others can be written */
2017 default:
2018 fWritable = true;
2019 break;
2020 }
2021 break;
2022 case 0x01: /* PCI-PCI bridge */
2023 fP2PBridge = true;
2024 switch (addr)
2025 {
2026 /* Read-only registers */
2027 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
2028 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
2029 case VBOX_PCI_REVISION_ID:
2030 case VBOX_PCI_CLASS_PROG:
2031 case VBOX_PCI_CLASS_SUB:
2032 case VBOX_PCI_CLASS_BASE:
2033 case VBOX_PCI_HEADER_TYPE:
2034 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:
2035 case VBOX_PCI_INTERRUPT_PIN:
2036 fWritable = false;
2037 break;
2038 default:
2039 fWritable = true;
2040 break;
2041 }
2042 break;
2043 default:
2044 AssertMsgFailed(("Unknown header type %x\n", PCIDevGetHeaderType(aDev)));
2045 fWritable = false;
2046 break;
2047 }
2048
2049 uint8_t u8Val = (uint8_t)val;
2050 switch (addr)
2051 {
2052 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
2053 fUpdateMappings = true;
2054 goto default_case;
2055 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
2056 /* don't change reserved bits (11-15) */
2057 u8Val &= UINT32_C(~0xf8);
2058 fUpdateMappings = true;
2059 goto default_case;
2060 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
2061 /* don't change read-only bits => actually all lower bits are read-only */
2062 u8Val &= UINT32_C(~0xff);
2063 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
2064 aDev->config[addr] &= ~u8Val;
2065 break;
2066 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
2067 /* don't change read-only bits */
2068 u8Val &= UINT32_C(~0x06);
2069 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
2070 aDev->config[addr] &= ~u8Val;
2071 break;
2072 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
2073 fRom = true;
2074 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:
2075 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:
2076 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:
2077 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:
2078 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:
2079 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:
2080 {
2081 /* We check that, as same PCI register numbers as BARs may mean different registers for bridges */
2082 if (fP2PBridge)
2083 goto default_case;
2084 else
2085 {
2086 int iRegion = fRom ? VBOX_PCI_ROM_SLOT : (addr - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2087 int iOffset = addr & 0x3;
2088 ich9pciWriteBarByte(aDev, iRegion, iOffset, u8Val);
2089 fUpdateMappings = true;
2090 }
2091 break;
2092 }
2093 default:
2094 default_case:
2095 if (fWritable)
2096 PCIDevSetByte(aDev, addr, u8Val);
2097 }
2098 addr++;
2099 val >>= 8;
2100 }
2101
2102 if (fUpdateMappings)
2103 /* if the command/base address register is modified, we must modify the mappings */
2104 ich9pciUpdateMappings(aDev);
2105}
2106
2107static bool assignPosition(PICH9PCIBUS pBus, PPCIDEVICE pPciDev, const char *pszName, int iDevFn, PciAddress* aPosition)
2108{
2109 aPosition->iBus = 0;
2110 aPosition->iDeviceFunc = iDevFn;
2111 aPosition->iRegister = 0; /* N/A */
2112
2113 /* Explicit slot request */
2114 if (iDevFn >=0 && iDevFn < (int)RT_ELEMENTS(pBus->apDevices))
2115 return true;
2116
2117 int iStartPos = 0;
2118
2119 /* Otherwise when assigning a slot, we need to make sure all its functions are available */
2120 for (int iPos = iStartPos; iPos < (int)RT_ELEMENTS(pBus->apDevices); iPos += 8)
2121 {
2122 if ( !pBus->apDevices[iPos]
2123 && !pBus->apDevices[iPos + 1]
2124 && !pBus->apDevices[iPos + 2]
2125 && !pBus->apDevices[iPos + 3]
2126 && !pBus->apDevices[iPos + 4]
2127 && !pBus->apDevices[iPos + 5]
2128 && !pBus->apDevices[iPos + 6]
2129 && !pBus->apDevices[iPos + 7])
2130 {
2131 pciDevClearRequestedDevfunc(pPciDev);
2132 aPosition->iDeviceFunc = iPos;
2133 return true;
2134 }
2135 }
2136
2137 return false;
2138}
2139
2140static bool hasHardAssignedDevsInSlot(PICH9PCIBUS pBus, int iSlot)
2141{
2142 PCIDevice** aSlot = &pBus->apDevices[iSlot << 3];
2143
2144 return (aSlot[0] && pciDevIsRequestedDevfunc(aSlot[0]))
2145 || (aSlot[1] && pciDevIsRequestedDevfunc(aSlot[1]))
2146 || (aSlot[2] && pciDevIsRequestedDevfunc(aSlot[2]))
2147 || (aSlot[3] && pciDevIsRequestedDevfunc(aSlot[3]))
2148 || (aSlot[4] && pciDevIsRequestedDevfunc(aSlot[4]))
2149 || (aSlot[5] && pciDevIsRequestedDevfunc(aSlot[5]))
2150 || (aSlot[6] && pciDevIsRequestedDevfunc(aSlot[6]))
2151 || (aSlot[7] && pciDevIsRequestedDevfunc(aSlot[7]))
2152 ;
2153}
2154
2155static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
2156{
2157 PciAddress aPosition = {0, 0, 0};
2158
2159 /*
2160 * Find device position
2161 */
2162 if (!assignPosition(pBus, pPciDev, pszName, iDev, &aPosition))
2163 {
2164 AssertMsgFailed(("Couldn't asssign position!\n"));
2165 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2166 }
2167
2168 AssertMsgReturn(aPosition.iBus == 0,
2169 ("Assigning behind the bridge not implemented yet\n"),
2170 VERR_PDM_TOO_PCI_MANY_DEVICES);
2171
2172
2173 iDev = aPosition.iDeviceFunc;
2174 /*
2175 * Check if we can really take this slot, possibly by relocating
2176 * its current habitant, if it wasn't hard assigned too.
2177 */
2178 if (pciDevIsRequestedDevfunc(pPciDev) &&
2179 pBus->apDevices[iDev] &&
2180 pciDevIsRequestedDevfunc(pBus->apDevices[iDev]))
2181 {
2182 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
2183 pszName, pBus->apDevices[iDev]->name, iDev));
2184 return VERR_INTERNAL_ERROR;
2185 }
2186
2187 if (pBus->apDevices[iDev])
2188 {
2189 /* if we got here, we shall (and usually can) relocate the device */
2190 bool assigned = assignPosition(pBus, pBus->apDevices[iDev], pBus->apDevices[iDev]->name, -1, &aPosition);
2191 AssertMsgReturn(aPosition.iBus == 0,
2192 ("Assigning behind the bridge not implemented yet\n"),
2193 VERR_PDM_TOO_PCI_MANY_DEVICES);
2194 int iRelDev = aPosition.iDeviceFunc;
2195 if (!assigned || iRelDev == iDev)
2196 {
2197 AssertMsgFailed(("Couldn't find free spot!\n"));
2198 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2199 }
2200 /* Copy device function by function to its new position */
2201 for (int i = 0; i < 8; i++)
2202 {
2203 if (!pBus->apDevices[iDev + i])
2204 continue;
2205 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->apDevices[iDev + i]->name, iDev + i, iRelDev + i));
2206 pBus->apDevices[iRelDev + i] = pBus->apDevices[iDev + i];
2207 pBus->apDevices[iRelDev + i]->devfn = iRelDev + i;
2208 pBus->apDevices[iDev + i] = NULL;
2209 }
2210 }
2211
2212 /*
2213 * Fill in device information.
2214 */
2215 pPciDev->devfn = iDev;
2216 pPciDev->name = pszName;
2217 pPciDev->Int.s.pBusR3 = pBus;
2218 pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2219 pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2220 pPciDev->Int.s.pfnConfigRead = ich9pciConfigReadDev;
2221 pPciDev->Int.s.pfnConfigWrite = ich9pciConfigWriteDev;
2222 pBus->apDevices[iDev] = pPciDev;
2223 if (pciDevIsPci2PciBridge(pPciDev))
2224 {
2225 AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
2226 AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
2227 ("device is a bridge but does not implement read/write functions\n"));
2228 Log2(("Setting bridge %d on bus %p\n", pBus->cBridges, pBus));
2229 pBus->papBridgesR3[pBus->cBridges] = pPciDev;
2230 pBus->cBridges++;
2231 }
2232
2233 Log(("PCI: Registered device %d function %d on bus %d (%#x) '%s'.\n",
2234 iDev >> 3, iDev & 7, pBus->iBus, 0x80000000 | (iDev << 8), pszName));
2235
2236 return VINF_SUCCESS;
2237}
2238
2239static void printIndent(PCDBGFINFOHLP pHlp, int iIndent)
2240{
2241 for (int i = 0; i < iIndent; i++)
2242 {
2243 pHlp->pfnPrintf(pHlp, " ");
2244 }
2245}
2246
2247static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRegisters)
2248{
2249 for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->apDevices); iDev++)
2250 {
2251 PPCIDEVICE pPciDev = pBus->apDevices[iDev];
2252 if (pPciDev != NULL)
2253 {
2254 printIndent(pHlp, iIndent);
2255
2256 /*
2257 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
2258 * as host driver handles real devices interrupts.
2259 */
2260 pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s%s: %04x-%04x%s%s",
2261 pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
2262 pPciDev->name,
2263 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
2264 ich9pciGetWord(pPciDev, VBOX_PCI_VENDOR_ID), ich9pciGetWord(pPciDev, VBOX_PCI_DEVICE_ID),
2265 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
2266 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
2267 );
2268 if (ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
2269 pHlp->pfnPrintf(pHlp, " IRQ%d", ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
2270
2271 pHlp->pfnPrintf(pHlp, "\n");
2272
2273 int iCmd = ich9pciGetWord(pPciDev, VBOX_PCI_COMMAND);
2274 if ((iCmd & (VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY)) != 0)
2275 {
2276 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2277 {
2278 PCIIORegion* pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2279 int32_t iRegionSize = pRegion->size;
2280
2281 if (iRegionSize == 0)
2282 continue;
2283
2284 uint32_t u32Addr = ich9pciGetDWord(pPciDev, ich9pciGetRegionReg(iRegion));
2285 const char * pszDesc;
2286 char szDescBuf[128];
2287
2288 bool f64Bit = (pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2289 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2290 {
2291 pszDesc = "IO";
2292 u32Addr &= ~0x3;
2293 }
2294 else
2295 {
2296 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
2297 f64Bit ? "64" : "32",
2298 (pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH) ? " PREFETCH" : "");
2299 pszDesc = szDescBuf;
2300 u32Addr &= ~0xf;
2301 }
2302
2303 printIndent(pHlp, iIndent + 2);
2304 pHlp->pfnPrintf(pHlp, " %s region #%d: %x..%x\n",
2305 pszDesc, iRegion, u32Addr, u32Addr+iRegionSize);
2306 if (f64Bit)
2307 iRegion++;
2308 }
2309 }
2310
2311 if (fRegisters)
2312 {
2313 printIndent(pHlp, iIndent + 2);
2314 pHlp->pfnPrintf(pHlp, " PCI registers:\n");
2315 for (int iReg = 0; iReg < 0x100; )
2316 {
2317 int iPerLine = 0x10;
2318 Assert (0x100 % iPerLine == 0);
2319 printIndent(pHlp, iIndent + 3);
2320
2321 while (iPerLine-- > 0)
2322 {
2323 pHlp->pfnPrintf(pHlp, "%02x ", ich9pciGetByte(pPciDev, iReg++));
2324 }
2325 pHlp->pfnPrintf(pHlp, "\n");
2326 }
2327 }
2328 }
2329 }
2330
2331 if (pBus->cBridges > 0)
2332 {
2333 printIndent(pHlp, iIndent);
2334 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
2335 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2336 {
2337 PICH9PCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PICH9PCIBUS);
2338 ich9pciBusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
2339 }
2340 }
2341}
2342
2343/**
2344 * Info handler, device version.
2345 *
2346 * @param pDevIns Device instance which registered the info.
2347 * @param pHlp Callback functions for doing output.
2348 * @param pszArgs Argument string. Optional and specific to the handler.
2349 */
2350static DECLCALLBACK(void) ich9pciInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2351{
2352 PICH9PCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
2353
2354 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2355 {
2356 ich9pciBusInfo(pBus, pHlp, 0, false);
2357 }
2358 else if (!strcmp(pszArgs, "verbose"))
2359 {
2360 ich9pciBusInfo(pBus, pHlp, 0, true);
2361 }
2362 else
2363 {
2364 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
2365 }
2366}
2367
2368
2369static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns,
2370 int iInstance,
2371 PCFGMNODE pCfg)
2372{
2373 Assert(iInstance == 0);
2374 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2375
2376 /*
2377 * Validate and read configuration.
2378 */
2379 if (!CFGMR3AreValuesValid(pCfg,
2380 "IOAPIC\0"
2381 "GCEnabled\0"
2382 "R0Enabled\0"
2383 "McfgBase\0"
2384 "McfgLength\0"
2385 ))
2386 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2387
2388 /* query whether we got an IOAPIC */
2389 bool fUseIoApic;
2390 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
2391 if (RT_FAILURE(rc))
2392 return PDMDEV_SET_ERROR(pDevIns, rc,
2393 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
2394
2395 /* check if RC code is enabled. */
2396 bool fGCEnabled;
2397 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2398 if (RT_FAILURE(rc))
2399 return PDMDEV_SET_ERROR(pDevIns, rc,
2400 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2401 /* check if R0 code is enabled. */
2402 bool fR0Enabled;
2403 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2404 if (RT_FAILURE(rc))
2405 return PDMDEV_SET_ERROR(pDevIns, rc,
2406 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2407
2408 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
2409
2410 /*
2411 * Init data.
2412 */
2413 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2414 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2415 /* Zero out everything */
2416 memset(pGlobals, 0, sizeof(*pGlobals));
2417 /* And fill values */
2418 if (!fUseIoApic)
2419 return PDMDEV_SET_ERROR(pDevIns, rc,
2420 N_("Must use IO-APIC with ICH9 chipset"));
2421 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pGlobals->u64PciConfigMMioAddress, 0);
2422 if (RT_FAILURE(rc))
2423 return PDMDEV_SET_ERROR(pDevIns, rc,
2424 N_("Configuration error: Failed to read \"McfgBase\""));
2425 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pGlobals->u64PciConfigMMioLength, 0);
2426 if (RT_FAILURE(rc))
2427 return PDMDEV_SET_ERROR(pDevIns, rc,
2428 N_("Configuration error: Failed to read \"McfgLength\""));
2429
2430 pGlobals->pDevInsR3 = pDevIns;
2431 pGlobals->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2432 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2433
2434 pGlobals->aPciBus.pDevInsR3 = pDevIns;
2435 pGlobals->aPciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2436 pGlobals->aPciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2437 pGlobals->aPciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
2438
2439 /*
2440 * Register bus
2441 */
2442 PDMPCIBUSREG PciBusReg;
2443 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2444 PciBusReg.pfnRegisterR3 = ich9pciRegister;
2445 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2446 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2447 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2448 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
2449 PciBusReg.pfnSaveExecR3 = ich9pciGenericSaveExec;
2450 PciBusReg.pfnLoadExecR3 = ich9pciGenericLoadExec;
2451 PciBusReg.pfnFakePCIBIOSR3 = ich9pciFakePCIBIOS;
2452 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pciSetIrq" : NULL;
2453 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pciSetIrq" : NULL;
2454 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2455 if (RT_FAILURE(rc))
2456 return PDMDEV_SET_ERROR(pDevIns, rc,
2457 N_("Failed to register ourselves as a PCI Bus"));
2458 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2459 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2460 N_("PCI helper version mismatch; got %#x expected %#x"),
2461 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2462
2463 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2464 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2465
2466 /*
2467 * Fill in PCI configs and add them to the bus.
2468 */
2469 /** @todo: Disabled for now because this causes error messages with Linux guests.
2470 * The guest loads the x38_edac device which tries to map a memory region
2471 * using an address given at place 0x48 - 0x4f in the PCi config space.
2472 * This fails. because we don't register such a region.
2473 */
2474#if 0
2475 /* Host bridge device */
2476 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2477 PCIDevSetDeviceId( &pBus->aPciDev, 0x29e0); /* Desktop */
2478 PCIDevSetRevisionId(&pBus->aPciDev, 0x01); /* rev. 01 */
2479 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* bridge */
2480 PCIDevSetClassSub( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2481 PCIDevSetClassProg( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2482 PCIDevSetHeaderType(&pBus->aPciDev, 0x00); /* bridge */
2483 PCIDevSetWord(&pBus->aPciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
2484
2485 pBus->aPciDev.pDevIns = pDevIns;
2486 /* We register Host<->PCI controller on the bus */
2487 ich9pciRegisterInternal(pBus, 0, &pBus->aPciDev, "dram");
2488#endif
2489
2490 /*
2491 * Register I/O ports and save state.
2492 */
2493 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL, NULL, "ICH9 (PCI)");
2494 if (RT_FAILURE(rc))
2495 return rc;
2496 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL, NULL, "ICH9 (PCI)");
2497 if (RT_FAILURE(rc))
2498 return rc;
2499 if (fGCEnabled)
2500 {
2501 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2502 if (RT_FAILURE(rc))
2503 return rc;
2504 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2505 if (RT_FAILURE(rc))
2506 return rc;
2507 }
2508 if (fR0Enabled)
2509 {
2510 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2511 if (RT_FAILURE(rc))
2512 return rc;
2513 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2514 if (RT_FAILURE(rc))
2515 return rc;
2516 }
2517
2518 if (pGlobals->u64PciConfigMMioAddress != 0)
2519 {
2520 rc = PDMDevHlpMMIORegister(pDevIns,
2521 pGlobals->u64PciConfigMMioAddress,
2522 pGlobals->u64PciConfigMMioLength,
2523 0,
2524 ich9pciMcfgMMIOWrite,
2525 ich9pciMcfgMMIORead,
2526 NULL /* fill */,
2527 "MCFG ranges");
2528 if (RT_FAILURE(rc))
2529 {
2530 AssertMsgRC(rc, ("Cannot register MCFG MMIO: %Rrc\n", rc));
2531 return rc;
2532 }
2533
2534 if (fGCEnabled)
2535 {
2536
2537 rc = PDMDevHlpMMIORegisterRC(pDevIns,
2538 pGlobals->u64PciConfigMMioAddress,
2539 pGlobals->u64PciConfigMMioLength,
2540 0,
2541 "ich9pciMcfgMMIOWrite",
2542 "ich9pciMcfgMMIORead",
2543 NULL /* fill */);
2544 if (RT_FAILURE(rc))
2545 {
2546 AssertMsgRC(rc, ("Cannot register MCFG MMIO (GC): %Rrc\n", rc));
2547 return rc;
2548 }
2549 }
2550
2551
2552 if (fR0Enabled)
2553 {
2554
2555 rc = PDMDevHlpMMIORegisterR0(pDevIns,
2556 pGlobals->u64PciConfigMMioAddress,
2557 pGlobals->u64PciConfigMMioLength,
2558 0,
2559 "ich9pciMcfgMMIOWrite",
2560 "ich9pciMcfgMMIORead",
2561 NULL /* fill */);
2562 if (RT_FAILURE(rc))
2563 {
2564 AssertMsgRC(rc, ("Cannot register MCFG MMIO (R0): %Rrc\n", rc));
2565 return rc;
2566 }
2567 }
2568 }
2569
2570 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2571 sizeof(*pBus) + 16*128, "pgm",
2572 NULL, NULL, NULL,
2573 NULL, ich9pciR3SaveExec, NULL,
2574 NULL, ich9pciR3LoadExec, NULL);
2575 if (RT_FAILURE(rc))
2576 return rc;
2577
2578
2579 /** @todo: other chipset devices shall be registered too */
2580
2581 PDMDevHlpDBGFInfoRegister(pDevIns, "pci", "Display PCI bus status. (no arguments)", ich9pciInfo);
2582
2583 return VINF_SUCCESS;
2584}
2585
2586static void ich9pciResetDevice(PPCIDEVICE pDev)
2587{
2588 PICH9PCIBUS pBus = pDev->Int.s.CTX_SUFF(pBus);
2589 int rc;
2590
2591 /* Clear regions */
2592 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2593 {
2594 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
2595 if (pRegion->size == 0)
2596 continue;
2597
2598 ich9pciUnmapRegion(pDev, iRegion);
2599 }
2600
2601 if (pciDevIsPassthrough(pDev))
2602 {
2603 // no reset handler - we can do what we need in PDM reset handler
2604 // @todo: is it correct?
2605 }
2606 else
2607 {
2608 PCIDevSetCommand(pDev,
2609 PCIDevGetCommand(pDev)
2610 &
2611 ~(VBOX_PCI_COMMAND_IO |
2612 VBOX_PCI_COMMAND_MEMORY |
2613 VBOX_PCI_COMMAND_MASTER));
2614
2615 /* Bridge device reset handlers processed later */
2616 if (!pciDevIsPci2PciBridge(pDev))
2617 {
2618 PCIDevSetByte(pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
2619 PCIDevSetInterruptLine(pDev, 0x0);
2620 }
2621 }
2622}
2623
2624
2625/**
2626 * @copydoc FNPDMDEVRESET
2627 */
2628static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
2629{
2630 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2631 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2632
2633 /* PCI-specific reset for each device. */
2634 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2635 {
2636 if (pBus->apDevices[i])
2637 ich9pciResetDevice(pBus->apDevices[i]);
2638 }
2639
2640 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2641 {
2642 if (pBus->papBridgesR3[iBridge])
2643 ich9pcibridgeReset(pBus->papBridgesR3[iBridge]->pDevIns);
2644 }
2645
2646 ich9pciFakePCIBIOS(pDevIns);
2647}
2648
2649static void ich9pciRelocateDevice(PPCIDEVICE pDev, RTGCINTPTR offDelta)
2650{
2651 if (pDev)
2652 {
2653 pDev->Int.s.pBusRC += offDelta;
2654 if (pDev->Int.s.pMsixPageRC)
2655 pDev->Int.s.pMsixPageRC += offDelta;
2656 }
2657}
2658
2659/**
2660 * @copydoc FNPDMDEVRELOCATE
2661 */
2662static DECLCALLBACK(void) ich9pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2663{
2664 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2665 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2666 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2667
2668 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2669 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2670
2671 /* Relocate RC pointers for the attached pci devices. */
2672 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2673 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2674
2675}
2676
2677/**
2678 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2679 */
2680static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
2681 int iInstance,
2682 PCFGMNODE pCfg)
2683{
2684 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2685
2686 /*
2687 * Validate and read configuration.
2688 */
2689 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
2690 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2691
2692 /* check if RC code is enabled. */
2693 bool fGCEnabled;
2694 int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2695 if (RT_FAILURE(rc))
2696 return PDMDEV_SET_ERROR(pDevIns, rc,
2697 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2698
2699 /* check if R0 code is enabled. */
2700 bool fR0Enabled;
2701 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2702 if (RT_FAILURE(rc))
2703 return PDMDEV_SET_ERROR(pDevIns, rc,
2704 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2705 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
2706
2707 /*
2708 * Init data and register the PCI bus.
2709 */
2710 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2711 pBus->pDevInsR3 = pDevIns;
2712 pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2713 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2714 pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->apDevices));
2715
2716 PDMPCIBUSREG PciBusReg;
2717 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2718 PciBusReg.pfnRegisterR3 = ich9pcibridgeRegister;
2719 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2720 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2721 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2722 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
2723 PciBusReg.pfnSaveExecR3 = ich9pciGenericSaveExec;
2724 PciBusReg.pfnLoadExecR3 = ich9pciGenericLoadExec;
2725 PciBusReg.pfnFakePCIBIOSR3 = NULL; /* Only needed for the first bus. */
2726 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pcibridgeSetIrq" : NULL;
2727 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pcibridgeSetIrq" : NULL;
2728 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2729 if (RT_FAILURE(rc))
2730 return PDMDEV_SET_ERROR(pDevIns, rc,
2731 N_("Failed to register ourselves as a PCI Bus"));
2732 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2733 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2734 N_("PCI helper version mismatch; got %#x expected %#x"),
2735 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2736
2737 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2738 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2739
2740 /*
2741 * Fill in PCI configs and add them to the bus.
2742 */
2743 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2744 PCIDevSetDeviceId( &pBus->aPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
2745 PCIDevSetRevisionId(&pBus->aPciDev, 0xf2);
2746 PCIDevSetClassSub( &pBus->aPciDev, 0x04); /* pci2pci */
2747 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* PCI_bridge */
2748 PCIDevSetClassProg( &pBus->aPciDev, 0x01); /* Supports subtractive decoding. */
2749 PCIDevSetHeaderType(&pBus->aPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
2750 PCIDevSetCommand( &pBus->aPciDev, 0x00);
2751 PCIDevSetStatus( &pBus->aPciDev, 0x20); /* 66MHz Capable. */
2752 PCIDevSetInterruptLine(&pBus->aPciDev, 0x00); /* This device does not assert interrupts. */
2753
2754 /*
2755 * This device does not generate interrupts. Interrupt delivery from
2756 * devices attached to the bus is unaffected.
2757 */
2758 PCIDevSetInterruptPin (&pBus->aPciDev, 0x00);
2759
2760 pBus->aPciDev.pDevIns = pDevIns;
2761
2762 /* Bridge-specific data */
2763 pciDevSetPci2PciBridge(&pBus->aPciDev);
2764 pBus->aPciDev.Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
2765 pBus->aPciDev.Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
2766
2767 /*
2768 * Register this PCI bridge. The called function will take care on which bus we will get registered.
2769 */
2770 rc = PDMDevHlpPCIRegister (pDevIns, &pBus->aPciDev);
2771 if (RT_FAILURE(rc))
2772 return rc;
2773
2774 /*
2775 * The iBus property doesn't really represent the bus number
2776 * because the guest and the BIOS can choose different bus numbers
2777 * for them.
2778 * The bus number is mainly for the setIrq function to indicate
2779 * when the host bus is reached which will have iBus = 0.
2780 * That's why the + 1.
2781 */
2782 pBus->iBus = iInstance + 1;
2783
2784 /*
2785 * Register SSM handlers. We use the same saved state version as for the host bridge
2786 * to make changes easier.
2787 */
2788 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2789 sizeof(*pBus) + 16*128,
2790 "pgm" /* before */,
2791 NULL, NULL, NULL,
2792 NULL, ich9pcibridgeR3SaveExec, NULL,
2793 NULL, ich9pcibridgeR3LoadExec, NULL);
2794 if (RT_FAILURE(rc))
2795 return rc;
2796
2797
2798 return VINF_SUCCESS;
2799}
2800
2801/**
2802 * @copydoc FNPDMDEVRESET
2803 */
2804static void ich9pcibridgeReset(PPDMDEVINS pDevIns)
2805{
2806 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2807
2808 /* Reset config space to default values. */
2809 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_PRIMARY_BUS, 0);
2810 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS, 0);
2811 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
2812
2813 /* PCI-specific reset for each device. */
2814 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2815 {
2816 if (pBus->apDevices[i])
2817 ich9pciResetDevice(pBus->apDevices[i]);
2818 }
2819}
2820
2821
2822/**
2823 * @copydoc FNPDMDEVRELOCATE
2824 */
2825static DECLCALLBACK(void) ich9pcibridgeRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2826{
2827 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2828 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2829
2830 /* Relocate RC pointers for the attached pci devices. */
2831 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2832 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2833}
2834
2835/**
2836 * The PCI bus device registration structure.
2837 */
2838const PDMDEVREG g_DevicePciIch9 =
2839{
2840 /* u32Version */
2841 PDM_DEVREG_VERSION,
2842 /* szName */
2843 "ich9pci",
2844 /* szRCMod */
2845 "VBoxDDGC.gc",
2846 /* szR0Mod */
2847 "VBoxDDR0.r0",
2848 /* pszDescription */
2849 "ICH9 PCI bridge",
2850 /* fFlags */
2851 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2852 /* fClass */
2853 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
2854 /* cMaxInstances */
2855 1,
2856 /* cbInstance */
2857 sizeof(ICH9PCIGLOBALS),
2858 /* pfnConstruct */
2859 ich9pciConstruct,
2860 /* pfnDestruct */
2861 NULL,
2862 /* pfnRelocate */
2863 ich9pciRelocate,
2864 /* pfnIOCtl */
2865 NULL,
2866 /* pfnPowerOn */
2867 NULL,
2868 /* pfnReset */
2869 ich9pciReset,
2870 /* pfnSuspend */
2871 NULL,
2872 /* pfnResume */
2873 NULL,
2874 /* pfnAttach */
2875 NULL,
2876 /* pfnDetach */
2877 NULL,
2878 /* pfnQueryInterface */
2879 NULL,
2880 /* pfnInitComplete */
2881 NULL,
2882 /* pfnPowerOff */
2883 NULL,
2884 /* pfnSoftReset */
2885 NULL,
2886 /* u32VersionEnd */
2887 PDM_DEVREG_VERSION
2888};
2889
2890/**
2891 * The device registration structure
2892 * for the PCI-to-PCI bridge.
2893 */
2894const PDMDEVREG g_DevicePciIch9Bridge =
2895{
2896 /* u32Version */
2897 PDM_DEVREG_VERSION,
2898 /* szName */
2899 "ich9pcibridge",
2900 /* szRCMod */
2901 "VBoxDDGC.gc",
2902 /* szR0Mod */
2903 "VBoxDDR0.r0",
2904 /* pszDescription */
2905 "ICH9 PCI to PCI bridge",
2906 /* fFlags */
2907 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2908 /* fClass */
2909 PDM_DEVREG_CLASS_BUS_PCI,
2910 /* cMaxInstances */
2911 ~0,
2912 /* cbInstance */
2913 sizeof(ICH9PCIBUS),
2914 /* pfnConstruct */
2915 ich9pcibridgeConstruct,
2916 /* pfnDestruct */
2917 NULL,
2918 /* pfnRelocate */
2919 ich9pcibridgeRelocate,
2920 /* pfnIOCtl */
2921 NULL,
2922 /* pfnPowerOn */
2923 NULL,
2924 /* pfnReset */
2925 NULL, /* Must be NULL, to make sure only bus driver handles reset */
2926 /* pfnSuspend */
2927 NULL,
2928 /* pfnResume */
2929 NULL,
2930 /* pfnAttach */
2931 NULL,
2932 /* pfnDetach */
2933 NULL,
2934 /* pfnQueryInterface */
2935 NULL,
2936 /* pfnInitComplete */
2937 NULL,
2938 /* pfnPowerOff */
2939 NULL,
2940 /* pfnSoftReset */
2941 NULL,
2942 /* u32VersionEnd */
2943 PDM_DEVREG_VERSION
2944};
2945
2946#endif /* IN_RING3 */
2947#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