VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/DevPciInternal.h@ 105381

Last change on this file since 105381 was 101479, checked in by vboxsync, 13 months ago

Devices/Bus: Add PCI bridge support to the generic PCI ECAM bus (the PCI config space is the same as the ICH9 bridge as of now), bugref:10445 bugref:10528

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: DevPciInternal.h 101479 2023-10-17 14:38:54Z vboxsync $ */
2/** @file
3 * DevPCI - Common Internal Header.
4 */
5
6/*
7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#ifndef VBOX_INCLUDED_SRC_Bus_DevPciInternal_h
29#define VBOX_INCLUDED_SRC_Bus_DevPciInternal_h
30#ifndef RT_WITHOUT_PRAGMA_ONCE
31# pragma once
32#endif
33
34#ifndef PDMPCIDEV_INCLUDE_PRIVATE
35# define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
36#endif
37#include <VBox/vmm/pdmdev.h>
38
39#include "PciInline.h"
40
41
42/**
43 * Supported PCI bus types.
44 */
45typedef enum DEVPCIBUSTYPE
46{
47 /** The usual invalid type. */
48 DEVPCIBUSTYPE_INVALID = 0,
49 /** PIIX3 PCI bus type. */
50 DEVPCIBUSTYPE_PIIX3,
51 /** ICH9 PCI bus type. */
52 DEVPCIBUSTYPE_ICH9,
53 /** Generic ECAM PCI bus type. */
54 DEVPCIBUSTYPE_GENERIC_ECAM,
55 /** 32bit blowup. */
56 DEVPCIBUSTYPE_32BIT_HACK = 0x7fffffff
57} DEVPCIBUSTYPE;
58
59
60/**
61 * PCI bus shared instance data (common to both PCI buses).
62 *
63 * The PCI device for the bus is always the first one (PDMDEVINSR3::apPciDevs[0]).
64 */
65typedef struct DEVPCIBUS
66{
67 /** Bus number. */
68 uint32_t iBus;
69 /** Number of bridges attached to the bus. */
70 uint32_t cBridges;
71 /** Start device number - always zero (only for DevPCI source compat). */
72 uint32_t iDevSearch;
73 /** PCI Bus type. */
74 DEVPCIBUSTYPE enmType;
75 /** Set if this is a pure bridge, i.e. not part of DEVPCIGLOBALS struct. */
76 uint32_t fPureBridge : 1;
77 /** Reserved for future config flags. */
78 uint32_t uReservedConfigFlags : 31;
79
80 /** Array of bridges attached to the bus. */
81 R3PTRTYPE(PPDMPCIDEV *) papBridgesR3;
82 /** Cache line align apDevices. */
83 uint32_t au32Alignment1[HC_ARCH_BITS == 32 ? 2 + 8 : 8];
84 /** Array of PCI devices. We assume 32 slots, each with 8 functions. */
85 R3PTRTYPE(PPDMPCIDEV) apDevices[256];
86} DEVPCIBUS;
87/** Pointer to PCI bus shared instance data. */
88typedef DEVPCIBUS *PDEVPCIBUS;
89AssertCompileMemberAlignment(DEVPCIBUS, apDevices, 64);
90
91
92/**
93 * PCI bus ring-3 instance data (common to both PCI buses).
94 */
95typedef struct DEVPCIBUSR3
96{
97 /** R3 pointer to the device instance. */
98 PPDMDEVINSR3 pDevInsR3;
99 /** Pointer to the PCI R3 helpers. */
100 PCPDMPCIHLPR3 pPciHlpR3;
101} DEVPCIBUSR3;
102/** Pointer to PCI bus ring-3 instance data. */
103typedef DEVPCIBUSR3 *PDEVPCIBUSR3;
104
105/**
106 * PCI bus ring-0 instance data (common to both PCI buses).
107 */
108typedef struct DEVPCIBUSR0
109{
110 /** R0 pointer to the device instance. */
111 PPDMDEVINSR0 pDevInsR0;
112 /** Pointer to the PCI R0 helpers. */
113 PCPDMPCIHLPR0 pPciHlpR0;
114} DEVPCIBUSR0;
115/** Pointer to PCI bus ring-0 instance data. */
116typedef DEVPCIBUSR0 *PDEVPCIBUSR0;
117
118/**
119 * PCI bus raw-mode instance data (common to both PCI buses).
120 */
121typedef struct DEVPCIBUSRC
122{
123 /** R0 pointer to the device instance. */
124 PPDMDEVINSRC pDevInsRC;
125 /** Pointer to the PCI raw-mode helpers. */
126 PCPDMPCIHLPRC pPciHlpRC;
127} DEVPCIBUSRC;
128/** Pointer to PCI bus raw-mode instance data. */
129typedef DEVPCIBUSRC *PDEVPCIBUSRC;
130
131/** DEVPCIBUSR3, DEVPCIBUSR0 or DEVPCIBUSRC depending on context. */
132typedef CTX_SUFF(DEVPCIBUS) DEVPCIBUSCC;
133/** PDEVPCIBUSR3, PDEVPCIBUSR0 or PDEVPCIBUSRC depending on context. */
134typedef CTX_SUFF(PDEVPCIBUS) PDEVPCIBUSCC;
135
136
137/** @def DEVPCI_APIC_IRQ_PINS
138 * Number of pins for interrupts if the APIC is used.
139 */
140#define DEVPCI_APIC_IRQ_PINS 8
141/** @def DEVPCI_LEGACY_IRQ_PINS
142 * Number of pins for interrupts (PIRQ#0...PIRQ#3).
143 * @remarks Labling this "legacy" might be a bit off...
144 */
145#define DEVPCI_LEGACY_IRQ_PINS 4
146
147
148/**
149 * PCI Globals - This is the host-to-pci bridge and the root bus, shared data.
150 *
151 * @note Only used by the root bus, not the bridges.
152 */
153typedef struct DEVPCIROOT
154{
155 /** PCI bus which is attached to the host-to-PCI bridge.
156 * @note This must come first so we can share more code with the bridges! */
157 DEVPCIBUS PciBus;
158
159 /** I/O APIC usage flag (always true of ICH9, see constructor). */
160 bool fUseIoApic;
161 /** Reserved for future config flags. */
162 bool afFutureFlags[3+4+8];
163 /** Physical address of PCI config space MMIO region. */
164 uint64_t u64PciConfigMMioAddress;
165 /** Length of PCI config space MMIO region. */
166 uint64_t u64PciConfigMMioLength;
167 /** Physical address of PCI PIO emulation MMIO region. */
168 RTGCPHYS GCPhysMmioPioEmuBase;
169 /** Length of PCI PIO emulation MMIO region. */
170 RTGCPHYS GCPhysMmioPioEmuSize;
171
172
173 /** I/O APIC irq levels */
174 volatile uint32_t auPciApicIrqLevels[DEVPCI_APIC_IRQ_PINS];
175 /** Value latched in Configuration Address Port (0CF8h) */
176 uint32_t uConfigReg;
177 /** Alignment padding. */
178 uint32_t u32Alignment1;
179 /** PCI bus dependent data. */
180 union
181 {
182 /** Members only used by the PIIX3 code variant.
183 * (The PCI device for the PCI-to-ISA bridge is PDMDEVINSR3::apPciDevs[1].) */
184 struct
185 {
186 /** ACPI IRQ level */
187 uint32_t iAcpiIrqLevel;
188 /** ACPI PIC IRQ */
189 int32_t iAcpiIrq;
190 /** Irq levels for the four PCI Irqs.
191 * These count how many devices asserted the IRQ line. If greater 0 an IRQ
192 * is sent to the guest. If it drops to 0 the IRQ is deasserted.
193 * @remarks Labling this "legacy" might be a bit off...
194 */
195 volatile uint32_t auPciLegacyIrqLevels[DEVPCI_LEGACY_IRQ_PINS];
196 } Piix3;
197 /** Members only used by the generic ECAM variant. */
198 struct
199 {
200 /** The interrupt config for INT#A ... INT#D. */
201 uint32_t auPciIrqNr[DEVPCI_LEGACY_IRQ_PINS];
202 /** Irq levels for the four PCI Irqs.
203 * These count how many devices asserted the IRQ line. If greater 0 an IRQ
204 * is sent to the guest. If it drops to 0 the IRQ is deasserted.
205 */
206 volatile uint32_t auPciIrqLevels[DEVPCI_LEGACY_IRQ_PINS];
207 } GenericEcam;
208 } u;
209
210 /** The address I/O port handle. */
211 IOMIOPORTHANDLE hIoPortAddress;
212 /** The data I/O port handle. */
213 IOMIOPORTHANDLE hIoPortData;
214 /** The magic I/O port handle. */
215 IOMIOPORTHANDLE hIoPortMagic;
216 /** The MCFG MMIO region. */
217 IOMMMIOHANDLE hMmioMcfg;
218 /** The PIO emulation MMIO region. */
219 IOMMMIOHANDLE hMmioPioEmu;
220
221#if 1 /* Will be moved into the BIOS "soon". */
222 /** Current bus number - obsolete (still used by DevPCI, but merge will fix that). */
223 uint8_t uPciBiosBus;
224 uint8_t abAlignment2[7];
225 /** The next I/O port address which the PCI BIOS will use. */
226 uint32_t uPciBiosIo;
227 /** The next MMIO address which the PCI BIOS will use. */
228 uint32_t uPciBiosMmio;
229 /** The next 64-bit MMIO address which the PCI BIOS will use. */
230 uint64_t uPciBiosMmio64;
231#endif
232
233} DEVPCIROOT;
234/** Pointer to PCI device globals. */
235typedef DEVPCIROOT *PDEVPCIROOT;
236/** Converts a PCI bus device instance pointer to a DEVPCIBUS pointer. */
237#define DEVINS_2_DEVPCIBUS(pDevIns) (&PDMINS_2_DATA(pDevIns, PDEVPCIROOT)->PciBus)
238/** Converts a pointer to a PCI bus instance to a DEVPCIROOT pointer. */
239#define DEVPCIBUS_2_DEVPCIROOT(pPciBus) RT_FROM_MEMBER(pPciBus, DEVPCIROOT, PciBus)
240
241
242/** @def PCI_LOCK_RET
243 * Acquires the PDM lock. This is a NOP if locking is disabled. */
244#define PCI_LOCK_RET(pDevIns, rcBusy) \
245 do { \
246 int const rcLock = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC)->CTX_SUFF(pPciHlp)->pfnLock((pDevIns), rcBusy); \
247 if (rcLock == VINF_SUCCESS) \
248 { /* likely */ } \
249 else \
250 return rcLock; \
251 } while (0)
252/** @def PCI_UNLOCK
253 * Releases the PDM lock. This is a NOP if locking is disabled. */
254#define PCI_UNLOCK(pDevIns) \
255 PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
256
257
258DECLHIDDEN(PPDMDEVINS) devpcibridgeCommonSetIrqRootWalk(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq,
259 PDEVPCIBUS *ppBus, uint8_t *puDevFnBridge, int *piIrqPinBridge);
260
261DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciCommonMcfgMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb);
262DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciCommonMcfgMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb);
263
264
265#ifdef IN_RING3
266
267# ifndef VBOX_DEVICE_STRUCT_TESTCASE
268DECLCALLBACK(void) devpciR3InfoPci(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs);
269DECLCALLBACK(void) devpciR3InfoPciIrq(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs);
270DECLCALLBACK(int) devpciR3CommonRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
271 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName);
272DECLCALLBACK(int) devpcibridgeR3CommonRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
273 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName);
274DECLCALLBACK(int) devpciR3CommonIORegionRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
275 RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags,
276 uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap);
277DECLCALLBACK(void) devpciR3CommonInterceptConfigAccesses(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
278 PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite);
279DECLCALLBACK(VBOXSTRICTRC) devpciR3CommonConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
280 uint32_t uAddress, unsigned cb, uint32_t *pu32Value);
281DECLHIDDEN(VBOXSTRICTRC) devpciR3CommonConfigReadWorker(PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb, uint32_t *pu32Value);
282DECLCALLBACK(VBOXSTRICTRC) devpciR3CommonConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
283 uint32_t uAddress, unsigned cb, uint32_t u32Value);
284DECLHIDDEN(VBOXSTRICTRC) devpciR3CommonConfigWriteWorker(PPDMDEVINS pDevIns, PDEVPCIBUSCC pBusCC,
285 PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb, uint32_t u32Value);
286void devpciR3CommonRestoreConfig(PPDMDEVINS pDevIns, PPDMPCIDEV pDev, uint8_t const *pbSrcConfig);
287int devpciR3CommonRestoreRegions(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PPDMPCIDEV pPciDev, PPCIIOREGION paIoRegions, bool fNewState);
288void devpciR3ResetDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pDev);
289void devpciR3BiosInitSetRegionAddress(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, int iRegion, uint64_t addr);
290uint32_t devpciR3GetCfg(PPDMPCIDEV pPciDev, int32_t iRegister, int cb);
291void devpciR3SetCfg(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_t iRegister, uint32_t u32, int cb);
292DECLHIDDEN(void) devpciR3CommonResetBridge(PPDMDEVINS pDevIns);
293DECL_HIDDEN_CALLBACK(int) devpciR3CommonSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
294DECL_HIDDEN_CALLBACK(int) devpciR3CommonLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
295
296DECL_HIDDEN_CALLBACK(int) devpciR3BridgeCommonSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
297DECL_HIDDEN_CALLBACK(int) devpciR3BridgeCommonLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
298
299DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciR3BridgeCommonConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
300 uint32_t u32Address, unsigned cb, uint32_t u32Value);
301DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciR3BridgeCommonConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
302 uint32_t u32Address, unsigned cb, uint32_t *pu32Value);
303
304DECLHIDDEN(uint8_t) devpciR3BridgeCommonGetExpressPortTypeFromString(const char *pszExpressPortType);
305
306
307DECLINLINE(uint8_t) devpciR3GetByte(PPDMPCIDEV pPciDev, int32_t iRegister)
308{
309 return (uint8_t)devpciR3GetCfg(pPciDev, iRegister, 1);
310}
311
312DECLINLINE(uint16_t) devpciR3GetWord(PPDMPCIDEV pPciDev, int32_t iRegister)
313{
314 return (uint16_t)devpciR3GetCfg(pPciDev, iRegister, 2);
315}
316
317DECLINLINE(uint32_t) devpciR3GetDWord(PPDMPCIDEV pPciDev, int32_t iRegister)
318{
319 return (uint32_t)devpciR3GetCfg(pPciDev, iRegister, 4);
320}
321
322DECLINLINE(void) devpciR3SetByte(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_t iRegister, uint8_t u8)
323{
324 devpciR3SetCfg(pDevIns, pPciDev, iRegister, u8, 1);
325}
326
327DECLINLINE(void) devpciR3SetWord(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_t iRegister, uint16_t u16)
328{
329 devpciR3SetCfg(pDevIns, pPciDev, iRegister, u16, 2);
330}
331
332DECLINLINE(void) devpciR3SetDWord(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_t iRegister, uint32_t u32)
333{
334 devpciR3SetCfg(pDevIns, pPciDev, iRegister, u32, 4);
335}
336
337
338DECLINLINE(PPDMPCIDEV) devpciR3FindBridge(PDEVPCIBUS pBus, uint8_t uBus)
339{
340 /* Search for a fitting bridge. */
341 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
342 {
343 /*
344 * Examine secondary and subordinate bus number.
345 * If the target bus is in the range we pass the request on to the bridge.
346 */
347 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
348 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
349 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
350 /* safe, only needs to go to the config space array */
351 uint32_t uSecondary = PDMPciDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
352 /* safe, only needs to go to the config space array */
353 uint32_t uSubordinate = PDMPciDevGetByte(pBridge, VBOX_PCI_SUBORDINATE_BUS);
354 Log3Func(("bus %p, bridge %d: %d in %d..%d\n", pBus, iBridge, uBus, uSecondary, uSubordinate));
355 if (uBus >= uSecondary && uBus <= uSubordinate)
356 return pBridge;
357 }
358
359 /* Nothing found. */
360 return NULL;
361}
362# endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
363
364#endif /* IN_RING3 */
365
366#endif /* !VBOX_INCLUDED_SRC_Bus_DevPciInternal_h */
367
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