VirtualBox

source: vbox/trunk/src/VBox/Devices/Samples/DevPlayground.cpp@ 67579

Last change on this file since 67579 was 67579, checked in by vboxsync, 7 years ago

DevPlayground: make sure that the MMIO regions for the PCI functions have unique names, matching PGM assumptions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1/* $Id: DevPlayground.cpp 67579 2017-06-23 10:16:49Z vboxsync $ */
2/** @file
3 * DevPlayground - Device for making PDM/PCI/... experiments.
4 *
5 * This device uses big PCI BAR64 resources, which needs the ICH9 chipset.
6 * The device works without any PCI config (because the default setup with the
7 * ICH9 chipset doesn't have anything at bus=0, device=0, function=0.
8 *
9 * To enable this device for a particular VM:
10 * VBoxManage setextradata vmname VBoxInternal/PDM/Devices/playground/Path .../obj/VBoxSampleDevice/VBoxSampleDevice
11 * VBoxManage setextradata vmname VBoxInternal/Devices/playground/0/Config/Whatever1 0
12 */
13
14/*
15 * Copyright (C) 2009-2016 Oracle Corporation
16 *
17 * This file is part of VirtualBox Open Source Edition (OSE), as
18 * available from http://www.virtualbox.org. This file is free software;
19 * you can redistribute it and/or modify it under the terms of the GNU
20 * General Public License (GPL) as published by the Free Software
21 * Foundation, in version 2 as it comes in the "COPYING" file of the
22 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
23 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
24 */
25
26
27/*********************************************************************************************************************************
28* Header Files *
29*********************************************************************************************************************************/
30#define LOG_GROUP LOG_GROUP_MISC
31#include <VBox/vmm/pdmdev.h>
32#include <VBox/version.h>
33#include <VBox/err.h>
34#include <VBox/log.h>
35
36#include <iprt/assert.h>
37
38
39/*********************************************************************************************************************************
40* Structures and Typedefs *
41*********************************************************************************************************************************/
42/**
43 * Playground device per function (sub-device) data.
44 */
45typedef struct VBOXPLAYGROUNDDEVICEFUNCTION
46{
47 /** The PCI devices. */
48 PDMPCIDEV PciDev;
49 /** The function number. */
50 uint8_t iFun;
51 /** Device function name. */
52 char szName[31];
53} VBOXPLAYGROUNDDEVICEFUNCTION;
54/** Pointer to a PCI function of the playground device. */
55typedef VBOXPLAYGROUNDDEVICEFUNCTION *PVBOXPLAYGROUNDDEVICEFUNCTION;
56
57/**
58 * Playground device instance data.
59 */
60typedef struct VBOXPLAYGROUNDDEVICE
61{
62 /** PCI device functions. */
63 VBOXPLAYGROUNDDEVICEFUNCTION aPciFuns[8];
64} VBOXPLAYGROUNDDEVICE;
65/** Pointer to the instance data of a playground device instance. */
66typedef VBOXPLAYGROUNDDEVICE *PVBOXPLAYGROUNDDEVICE;
67
68
69/*********************************************************************************************************************************
70* Device Functions *
71*********************************************************************************************************************************/
72
73PDMBOTHCBDECL(int) devPlaygroundMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
74{
75 NOREF(pDevIns);
76 NOREF(pvUser);
77 NOREF(GCPhysAddr);
78 NOREF(pv);
79 NOREF(cb);
80 return VINF_SUCCESS;
81}
82
83
84PDMBOTHCBDECL(int) devPlaygroundMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
85{
86 NOREF(pDevIns);
87 NOREF(pvUser);
88 NOREF(GCPhysAddr);
89 NOREF(pv);
90 NOREF(cb);
91 return VINF_SUCCESS;
92}
93
94
95/**
96 * @callback_method_impl{FNPCIIOREGIONMAP}
97 */
98static DECLCALLBACK(int) devPlaygroundMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
99 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
100{
101 RT_NOREF(pPciDev, enmType, cb);
102
103 switch (iRegion)
104 {
105 case 0:
106 case 2:
107 Assert( enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64)
108 || enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR64));
109 if (GCPhysAddress == NIL_RTGCPHYS)
110 return VINF_SUCCESS; /* We ignore the unmap notification. */
111 return PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
112
113 default:
114 /* We should never get here */
115 AssertMsgFailedReturn(("Invalid PCI region param in map callback"), VERR_INTERNAL_ERROR);
116 }
117}
118
119
120/**
121 * @interface_method_impl{PDMDEVREG,pfnDestruct}
122 */
123static DECLCALLBACK(int) devPlaygroundDestruct(PPDMDEVINS pDevIns)
124{
125 /*
126 * Check the versions here as well since the destructor is *always* called.
127 */
128 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
129
130 return VINF_SUCCESS;
131}
132
133
134/**
135 * @interface_method_impl{PDMDEVREG,pfnConstruct}
136 */
137static DECLCALLBACK(int) devPlaygroundConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
138{
139 RT_NOREF(iInstance, pCfg);
140
141 /*
142 * Check that the device instance and device helper structures are compatible.
143 */
144 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
145
146 /*
147 * Initialize the instance data so that the destructor won't mess up.
148 */
149 PVBOXPLAYGROUNDDEVICE pThis = PDMINS_2_DATA(pDevIns, PVBOXPLAYGROUNDDEVICE);
150
151 /*
152 * Validate and read the configuration.
153 */
154 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Whatever1|Whatever2", "");
155
156 /*
157 * PCI device setup.
158 */
159 uint32_t iPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
160 for (uint32_t iPciFun = 0; iPciFun < RT_ELEMENTS(pThis->aPciFuns); iPciFun++)
161 {
162 PVBOXPLAYGROUNDDEVICEFUNCTION pFun = &pThis->aPciFuns[iPciFun];
163 RTStrPrintf(pFun->szName, sizeof(pThis->aPciFuns[iPciFun].PciDev), "playground%u", iPciFun);
164 pFun->iFun = iPciFun;
165
166 PCIDevSetVendorId( &pFun->PciDev, 0x80ee);
167 PCIDevSetDeviceId( &pFun->PciDev, 0xde4e);
168 PCIDevSetClassBase(&pFun->PciDev, 0x07); /* communications device */
169 PCIDevSetClassSub( &pFun->PciDev, 0x80); /* other communications device */
170 if (iPciFun == 0) /* only for the primary function */
171 PCIDevSetHeaderType(&pFun->PciDev, 0x80); /* normal, multifunction device */
172
173 int rc = PDMDevHlpPCIRegisterEx(pDevIns, &pFun->PciDev, iPciFun, 0 /*fFlags*/, iPciDevNo, iPciFun,
174 pThis->aPciFuns[iPciFun].szName);
175 AssertLogRelRCReturn(rc, rc);
176
177 /* First region. */
178 RTGCPHYS const cbFirst = iPciFun == 0 ? 8*_1G64 : iPciFun * _4K;
179 rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 0, cbFirst,
180 (PCIADDRESSSPACE)( PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64
181 | (iPciFun == 0 ? PCI_ADDRESS_SPACE_MEM_PREFETCH : 0)),
182 devPlaygroundMap);
183 AssertLogRelRCReturn(rc, rc);
184 char *pszRegionName = NULL;
185 RTStrAPrintf(&pszRegionName, "PG-F%d-BAR0", iPciFun);
186 Assert(pszRegionName);
187 rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 0, cbFirst,
188 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, pszRegionName,
189 NULL /*pvUser*/, devPlaygroundMMIOWrite, devPlaygroundMMIORead, NULL /*pfnFill*/,
190 NIL_RTR0PTR /*pvUserR0*/, NULL /*pszWriteR0*/, NULL /*pszReadR0*/, NULL /*pszFillR0*/,
191 NIL_RTRCPTR /*pvUserRC*/, NULL /*pszWriteRC*/, NULL /*pszReadRC*/, NULL /*pszFillRC*/);
192 AssertLogRelRCReturn(rc, rc);
193
194 /* Second region. */
195 RTGCPHYS const cbSecond = iPciFun == 0 ? 256*_1G64 : iPciFun * _32K;
196 rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 2, cbSecond,
197 (PCIADDRESSSPACE)( PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64
198 | (iPciFun == 0 ? PCI_ADDRESS_SPACE_MEM_PREFETCH : 0)),
199 devPlaygroundMap);
200 AssertLogRelRCReturn(rc, rc);
201 pszRegionName = NULL;
202 RTStrAPrintf(&pszRegionName, "PG-F%d-BAR2", iPciFun);
203 Assert(pszRegionName);
204 rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 2, cbSecond,
205 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, pszRegionName,
206 NULL /*pvUser*/, devPlaygroundMMIOWrite, devPlaygroundMMIORead, NULL /*pfnFill*/,
207 NIL_RTR0PTR /*pvUserR0*/, NULL /*pszWriteR0*/, NULL /*pszReadR0*/, NULL /*pszFillR0*/,
208 NIL_RTRCPTR /*pvUserRC*/, NULL /*pszWriteRC*/, NULL /*pszReadRC*/, NULL /*pszFillRC*/);
209 AssertLogRelRCReturn(rc, rc);
210
211 /* Subsequent function should use the same major as the previous one. */
212 iPciDevNo = PDMPCIDEVREG_DEV_NO_SAME_AS_PREV;
213 }
214
215 return VINF_SUCCESS;
216}
217
218RT_C_DECLS_BEGIN
219extern const PDMDEVREG g_DevicePlayground;
220RT_C_DECLS_END
221
222/**
223 * The device registration structure.
224 */
225const PDMDEVREG g_DevicePlayground =
226{
227 /* u32Version */
228 PDM_DEVREG_VERSION,
229 /* szName */
230 "playground",
231 /* szRCMod */
232 "",
233 /* szR0Mod */
234 "",
235 /* pszDescription */
236 "VBox Playground Device.",
237 /* fFlags */
238 PDM_DEVREG_FLAGS_DEFAULT_BITS,
239 /* fClass */
240 PDM_DEVREG_CLASS_MISC,
241 /* cMaxInstances */
242 1,
243 /* cbInstance */
244 sizeof(VBOXPLAYGROUNDDEVICE),
245 /* pfnConstruct */
246 devPlaygroundConstruct,
247 /* pfnDestruct */
248 devPlaygroundDestruct,
249 /* pfnRelocate */
250 NULL,
251 /* pfnMemSetup */
252 NULL,
253 /* pfnPowerOn */
254 NULL,
255 /* pfnReset */
256 NULL,
257 /* pfnSuspend */
258 NULL,
259 /* pfnResume */
260 NULL,
261 /* pfnAttach */
262 NULL,
263 /* pfnDetach */
264 NULL,
265 /* pfnQueryInterface */
266 NULL,
267 /* pfnInitComplete */
268 NULL,
269 /* pfnPowerOff */
270 NULL,
271 /* pfnSoftReset */
272 NULL,
273 /* u32VersionEnd */
274 PDM_DEVREG_VERSION
275};
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