VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/BusAssignmentManager.cpp@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.2 KB
RevLine 
[33687]1/* $Id: BusAssignmentManager.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VirtualBox bus slots assignment manager
4 */
5
6/*
[98103]7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
[33687]8 *
[96407]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
[33687]26 */
[67914]27
[93444]28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[67914]32#define LOG_GROUP LOG_GROUP_MAIN
33#include "LoggingNew.h"
34
[33687]35#include "BusAssignmentManager.h"
36
37#include <iprt/asm.h>
[34123]38#include <iprt/string.h>
[33687]39
[35346]40#include <VBox/vmm/cfgm.h>
[93444]41#include <VBox/vmm/vmmr3vtable.h>
[34331]42#include <VBox/com/array.h>
[33687]43
44#include <map>
[33690]45#include <vector>
[33722]46#include <algorithm>
[33687]47
[93444]48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
[33722]52struct DeviceAssignmentRule
53{
[70238]54 const char *pszName;
[33722]55 int iBus;
56 int iDevice;
57 int iFn;
58 int iPriority;
59};
60
61struct DeviceAliasRule
62{
[70238]63 const char *pszDevName;
64 const char *pszDevAlias;
[33722]65};
66
[93444]67
68/*********************************************************************************************************************************
69* Global Variables *
70*********************************************************************************************************************************/
[33722]71/* Those rules define PCI slots assignment */
[68371]72/** @note
73 * The EFI takes assumptions about PCI slot assignments which are different
74 * from the following tables in certain cases, for example the IDE device
75 * is assumed to be 00:01.1! */
[33722]76
[34014]77/* Device Bus Device Function Priority */
[34013]78
[33722]79/* Generic rules */
[85011]80static const DeviceAssignmentRule g_aGenericRules[] =
[33722]81{
82 /* VGA controller */
83 {"vga", 0, 2, 0, 0},
84
85 /* VMM device */
86 {"VMMDev", 0, 4, 0, 0},
87
88 /* Audio controllers */
89 {"ichac97", 0, 5, 0, 0},
90 {"hda", 0, 5, 0, 0},
91
92 /* Storage controllers */
[34013]93 {"buslogic", 0, 21, 0, 1},
94 {"lsilogicsas", 0, 22, 0, 1},
[57524]95 {"nvme", 0, 14, 0, 1},
[78509]96 {"virtio-scsi", 0, 15, 0, 1},
[33722]97
98 /* USB controllers */
99 {"usb-ohci", 0, 6, 0, 0},
100 {"usb-ehci", 0, 11, 0, 0},
[50721]101 {"usb-xhci", 0, 12, 0, 0},
[33722]102
103 /* ACPI controller */
[79674]104#if 0
105 // It really should be this for 440FX chipset (part of PIIX4 actually)
106 {"acpi", 0, 1, 3, 0},
107#else
[33722]108 {"acpi", 0, 7, 0, 0},
[79674]109#endif
[33722]110
111 /* Network controllers */
112 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
[47223]113 * next 4 get 16..19. In "VMWare compatibility" mode the IDs 3 and 17
114 * swap places, i.e. the first card goes to ID 17=0x11. */
[34013]115 {"nic", 0, 3, 0, 1},
116 {"nic", 0, 8, 0, 1},
117 {"nic", 0, 9, 0, 1},
118 {"nic", 0, 10, 0, 1},
119 {"nic", 0, 16, 0, 1},
120 {"nic", 0, 17, 0, 1},
121 {"nic", 0, 18, 0, 1},
122 {"nic", 0, 19, 0, 1},
[33722]123
124 /* ISA/LPC controller */
125 {"lpc", 0, 31, 0, 0},
126
127 { NULL, -1, -1, -1, 0}
128};
129
130/* PIIX3 chipset rules */
[85011]131static const DeviceAssignmentRule g_aPiix3Rules[] =
[33722]132{
133 {"piix3ide", 0, 1, 1, 0},
[42826]134 {"ahci", 0, 13, 0, 1},
[85007]135 {"lsilogic", 0, 20, 0, 1},
[33722]136 {"pcibridge", 0, 24, 0, 0},
137 {"pcibridge", 0, 25, 0, 0},
138 { NULL, -1, -1, -1, 0}
139};
140
141
142/* ICH9 chipset rules */
[85011]143static const DeviceAssignmentRule g_aIch9Rules[] =
[33722]144{
145 /* Host Controller */
146 {"i82801", 0, 30, 0, 0},
147
148 /* Those are functions of LPC at 00:1e:00 */
149 /**
150 * Please note, that for devices being functions, like we do here, device 0
151 * must be multifunction, i.e. have header type 0x80. Our LPC device is.
152 * Alternative approach is to assign separate slot to each device.
153 */
[34266]154 {"piix3ide", 0, 31, 1, 2},
155 {"ahci", 0, 31, 2, 2},
156 {"smbus", 0, 31, 3, 2},
157 {"usb-ohci", 0, 31, 4, 2},
158 {"usb-ehci", 0, 31, 5, 2},
159 {"thermal", 0, 31, 6, 2},
[33722]160
161 /* to make sure rule never used before rules assigning devices on it */
162 {"ich9pcibridge", 0, 24, 0, 10},
163 {"ich9pcibridge", 0, 25, 0, 10},
[70238]164 {"ich9pcibridge", 2, 24, 0, 9}, /* Bridges must be instantiated depth */
165 {"ich9pcibridge", 2, 25, 0, 9}, /* first (assumption in PDM and other */
166 {"ich9pcibridge", 4, 24, 0, 8}, /* places), so make sure that nested */
167 {"ich9pcibridge", 4, 25, 0, 8}, /* bridges are added to the last bridge */
168 {"ich9pcibridge", 6, 24, 0, 7}, /* only, avoiding the need to re-sort */
169 {"ich9pcibridge", 6, 25, 0, 7}, /* everything before starting the VM. */
170 {"ich9pcibridge", 8, 24, 0, 6},
171 {"ich9pcibridge", 8, 25, 0, 6},
172 {"ich9pcibridge", 10, 24, 0, 5},
173 {"ich9pcibridge", 10, 25, 0, 5},
[33907]174
175 /* Storage controllers */
176 {"ahci", 1, 0, 0, 0},
177 {"ahci", 1, 1, 0, 0},
178 {"ahci", 1, 2, 0, 0},
179 {"ahci", 1, 3, 0, 0},
180 {"ahci", 1, 4, 0, 0},
181 {"ahci", 1, 5, 0, 0},
182 {"ahci", 1, 6, 0, 0},
183 {"lsilogic", 1, 7, 0, 0},
184 {"lsilogic", 1, 8, 0, 0},
185 {"lsilogic", 1, 9, 0, 0},
186 {"lsilogic", 1, 10, 0, 0},
187 {"lsilogic", 1, 11, 0, 0},
188 {"lsilogic", 1, 12, 0, 0},
189 {"lsilogic", 1, 13, 0, 0},
190 {"buslogic", 1, 14, 0, 0},
191 {"buslogic", 1, 15, 0, 0},
192 {"buslogic", 1, 16, 0, 0},
193 {"buslogic", 1, 17, 0, 0},
194 {"buslogic", 1, 18, 0, 0},
195 {"buslogic", 1, 19, 0, 0},
196 {"buslogic", 1, 20, 0, 0},
197 {"lsilogicsas", 1, 21, 0, 0},
198 {"lsilogicsas", 1, 26, 0, 0},
199 {"lsilogicsas", 1, 27, 0, 0},
200 {"lsilogicsas", 1, 28, 0, 0},
201 {"lsilogicsas", 1, 29, 0, 0},
202 {"lsilogicsas", 1, 30, 0, 0},
203 {"lsilogicsas", 1, 31, 0, 0},
204
205 /* NICs */
206 {"nic", 2, 0, 0, 0},
207 {"nic", 2, 1, 0, 0},
208 {"nic", 2, 2, 0, 0},
209 {"nic", 2, 3, 0, 0},
210 {"nic", 2, 4, 0, 0},
211 {"nic", 2, 5, 0, 0},
212 {"nic", 2, 6, 0, 0},
213 {"nic", 2, 7, 0, 0},
214 {"nic", 2, 8, 0, 0},
215 {"nic", 2, 9, 0, 0},
216 {"nic", 2, 10, 0, 0},
217 {"nic", 2, 11, 0, 0},
218 {"nic", 2, 12, 0, 0},
219 {"nic", 2, 13, 0, 0},
220 {"nic", 2, 14, 0, 0},
221 {"nic", 2, 15, 0, 0},
222 {"nic", 2, 16, 0, 0},
223 {"nic", 2, 17, 0, 0},
224 {"nic", 2, 18, 0, 0},
225 {"nic", 2, 19, 0, 0},
226 {"nic", 2, 20, 0, 0},
227 {"nic", 2, 21, 0, 0},
228 {"nic", 2, 26, 0, 0},
229 {"nic", 2, 27, 0, 0},
230 {"nic", 2, 28, 0, 0},
231 {"nic", 2, 29, 0, 0},
232 {"nic", 2, 30, 0, 0},
233 {"nic", 2, 31, 0, 0},
234
[78509]235 /* Storage controller #2 (NVMe, virtio-scsi) */
[63747]236 {"nvme", 3, 0, 0, 0},
237 {"nvme", 3, 1, 0, 0},
238 {"nvme", 3, 2, 0, 0},
239 {"nvme", 3, 3, 0, 0},
240 {"nvme", 3, 4, 0, 0},
241 {"nvme", 3, 5, 0, 0},
242 {"nvme", 3, 6, 0, 0},
[78509]243 {"virtio-scsi", 3, 7, 0, 0},
244 {"virtio-scsi", 3, 8, 0, 0},
245 {"virtio-scsi", 3, 9, 0, 0},
246 {"virtio-scsi", 3, 10, 0, 0},
247 {"virtio-scsi", 3, 11, 0, 0},
248 {"virtio-scsi", 3, 12, 0, 0},
249 {"virtio-scsi", 3, 13, 0, 0},
[63747]250
[33722]251 { NULL, -1, -1, -1, 0}
252};
253
[85007]254
255#ifdef VBOX_WITH_IOMMU_AMD
256/*
257 * AMD IOMMU and LSI Logic controller rules.
258 *
259 * Since the PCI slot (BDF=00:20.0) of the LSI Logic controller
260 * conflicts with the SB I/O APIC, we assign the LSI Logic controller
261 * to device number 23 when the VM is configured for an AMD IOMMU.
262 */
[88333]263static const DeviceAssignmentRule g_aIch9IommuAmdRules[] =
[85007]264{
265 /* AMD IOMMU. */
[86733]266 {"iommu-amd", 0, 0, 0, 0},
[85007]267 /* AMD IOMMU: Reserved for southbridge I/O APIC. */
268 {"sb-ioapic", 0, 20, 0, 0},
269
270 /* Storage controller */
271 {"lsilogic", 0, 23, 0, 1},
272 { NULL, -1, -1, -1, 0}
273};
274#endif
275
[88333]276#ifdef VBOX_WITH_IOMMU_INTEL
277/*
278 * Intel IOMMU.
279 * The VT-d misc, address remapping, system management device is
[88484]280 * located at BDF 0:5:0 on real hardware but we use 0:1:0 since that
281 * slot isn't used for anything else.
282 *
283 * While we could place the I/O APIC anywhere, we keep it consistent
284 * with the AMD IOMMU and we assign the LSI Logic controller to
285 * device number 23 (and I/O APIC at device 20).
[88333]286 */
287static const DeviceAssignmentRule g_aIch9IommuIntelRules[] =
288{
289 /* Intel IOMMU. */
[88484]290 {"iommu-intel", 0, 1, 0, 0},
291 /* Intel IOMMU: Reserved for I/O APIC. */
292 {"sb-ioapic", 0, 20, 0, 0},
[88333]293
294 /* Storage controller */
[88484]295 {"lsilogic", 0, 23, 0, 1},
[88333]296 { NULL, -1, -1, -1, 0}
297};
298#endif
299
[85007]300/* LSI Logic Controller. */
[85011]301static const DeviceAssignmentRule g_aIch9LsiRules[] =
[85007]302{
303 /* Storage controller */
304 {"lsilogic", 0, 20, 0, 1},
305 { NULL, -1, -1, -1, 0}
306};
307
[33722]308/* Aliasing rules */
[85011]309static const DeviceAliasRule g_aDeviceAliases[] =
[33722]310{
[33907]311 {"e1000", "nic"},
312 {"pcnet", "nic"},
313 {"virtio-net", "nic"},
314 {"ahci", "storage"},
315 {"lsilogic", "storage"},
316 {"buslogic", "storage"},
[57524]317 {"lsilogicsas", "storage"},
[78509]318 {"nvme", "storage"},
319 {"virtio-scsi", "storage"}
[33722]320};
321
[93444]322
323
324/**
325 * Bus assignment manage state data.
326 * @internal
327 */
[33687]328struct BusAssignmentManager::State
329{
[42551]330 struct PCIDeviceRecord
[33687]331 {
[36107]332 char szDevName[32];
[42551]333 PCIBusAddress HostAddress;
[33688]334
[70238]335 PCIDeviceRecord(const char *pszName, PCIBusAddress aHostAddress)
[36107]336 {
337 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
338 this->HostAddress = aHostAddress;
339 }
340
[70238]341 PCIDeviceRecord(const char *pszName)
[33688]342 {
[36107]343 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
[33688]344 }
[33690]345
[42551]346 bool operator<(const PCIDeviceRecord &a) const
[33690]347 {
[34123]348 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) < 0;
[33690]349 }
350
[42551]351 bool operator==(const PCIDeviceRecord &a) const
[33690]352 {
[34123]353 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
[33690]354 }
[33687]355 };
356
[61009]357 typedef std::map<PCIBusAddress,PCIDeviceRecord> PCIMap;
[42551]358 typedef std::vector<PCIBusAddress> PCIAddrList;
[61009]359 typedef std::vector<const DeviceAssignmentRule *> PCIRulesList;
360 typedef std::map<PCIDeviceRecord,PCIAddrList> ReversePCIMap;
[33687]361
362 volatile int32_t cRefCnt;
363 ChipsetType_T mChipsetType;
[70238]364 const char * mpszBridgeName;
[87242]365 IommuType_T mIommuType;
[42551]366 PCIMap mPCIMap;
367 ReversePCIMap mReversePCIMap;
[93444]368 PCVMMR3VTABLE mpVMM;
[33687]369
370 State()
[93444]371 : cRefCnt(1), mChipsetType(ChipsetType_Null), mpszBridgeName("unknownbridge"), mpVMM(NULL)
[33687]372 {}
373 ~State()
374 {}
375
[93444]376 HRESULT init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType);
[33687]377
[70238]378 HRESULT record(const char *pszName, PCIBusAddress& GuestAddress, PCIBusAddress HostAddress);
379 HRESULT autoAssign(const char *pszName, PCIBusAddress& Address);
[42551]380 bool checkAvailable(PCIBusAddress& Address);
[70238]381 bool findPCIAddress(const char *pszDevName, int iInstance, PCIBusAddress& Address);
[33722]382
[70238]383 const char *findAlias(const char *pszName);
384 void addMatchingRules(const char *pszName, PCIRulesList& aList);
[61009]385 void listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached);
[33687]386};
387
[93444]388
389HRESULT BusAssignmentManager::State::init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType)
[33687]390{
[93444]391 mpVMM = pVMM;
392
[88333]393 if (iommuType != IommuType_None)
394 {
395#if defined(VBOX_WITH_IOMMU_AMD) && defined(VBOX_WITH_IOMMU_INTEL)
396 Assert(iommuType == IommuType_AMD || iommuType == IommuType_Intel);
397#elif defined(VBOX_WITH_IOMMU_AMD)
398 Assert(iommuType == IommuType_AMD);
399#elif defined(VBOX_WITH_IOMMU_INTEL)
400 Assert(iommuType == IommuType_Intel);
401#endif
402 }
[87242]403
[33687]404 mChipsetType = chipsetType;
[87242]405 mIommuType = iommuType;
[70238]406 switch (chipsetType)
407 {
408 case ChipsetType_PIIX3:
409 mpszBridgeName = "pcibridge";
410 break;
411 case ChipsetType_ICH9:
412 mpszBridgeName = "ich9pcibridge";
413 break;
414 default:
415 mpszBridgeName = "unknownbridge";
416 AssertFailed();
417 break;
418 }
[33687]419 return S_OK;
420}
421
[70238]422HRESULT BusAssignmentManager::State::record(const char *pszName, PCIBusAddress& Address, PCIBusAddress HostAddress)
[33688]423{
[42551]424 PCIDeviceRecord devRec(pszName, HostAddress);
[33690]425
426 /* Remember address -> device mapping */
[42551]427 mPCIMap.insert(PCIMap::value_type(Address, devRec));
[33690]428
[42551]429 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
430 if (it == mReversePCIMap.end())
[33690]431 {
[42551]432 mReversePCIMap.insert(ReversePCIMap::value_type(devRec, PCIAddrList()));
433 it = mReversePCIMap.find(devRec);
[33690]434 }
435
436 /* Remember device name -> addresses mapping */
437 it->second.push_back(Address);
438
[33688]439 return S_OK;
440}
441
[85007]442bool BusAssignmentManager::State::findPCIAddress(const char *pszDevName, int iInstance, PCIBusAddress& Address)
[33690]443{
[42551]444 PCIDeviceRecord devRec(pszDevName);
[33690]445
[42551]446 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
447 if (it == mReversePCIMap.end())
[33690]448 return false;
449
450 if (iInstance >= (int)it->second.size())
451 return false;
452
453 Address = it->second[iInstance];
454 return true;
455}
456
[70238]457void BusAssignmentManager::State::addMatchingRules(const char *pszName, PCIRulesList& aList)
[33722]458{
459 size_t iRuleset, iRule;
[85011]460 const DeviceAssignmentRule *aArrays[3] = {g_aGenericRules, NULL, NULL};
[33722]461
462 switch (mChipsetType)
463 {
464 case ChipsetType_PIIX3:
[85011]465 aArrays[1] = g_aPiix3Rules;
[33722]466 break;
467 case ChipsetType_ICH9:
[85007]468 {
[85011]469 aArrays[1] = g_aIch9Rules;
[85007]470#ifdef VBOX_WITH_IOMMU_AMD
[87242]471 if (mIommuType == IommuType_AMD)
[88333]472 aArrays[2] = g_aIch9IommuAmdRules;
[85007]473 else
474#endif
[88333]475#ifdef VBOX_WITH_IOMMU_INTEL
476 if (mIommuType == IommuType_Intel)
477 aArrays[2] = g_aIch9IommuIntelRules;
478 else
479#endif
[85007]480 {
[85011]481 aArrays[2] = g_aIch9LsiRules;
[85007]482 }
[33722]483 break;
[85007]484 }
[33722]485 default:
[70238]486 AssertFailed();
[33722]487 break;
488 }
489
490 for (iRuleset = 0; iRuleset < RT_ELEMENTS(aArrays); iRuleset++)
491 {
492 if (aArrays[iRuleset] == NULL)
493 continue;
494
495 for (iRule = 0; aArrays[iRuleset][iRule].pszName != NULL; iRule++)
496 {
[34123]497 if (RTStrCmp(pszName, aArrays[iRuleset][iRule].pszName) == 0)
[33722]498 aList.push_back(&aArrays[iRuleset][iRule]);
499 }
500 }
501}
502
[70238]503const char *BusAssignmentManager::State::findAlias(const char *pszDev)
[33722]504{
[85011]505 for (size_t iAlias = 0; iAlias < RT_ELEMENTS(g_aDeviceAliases); iAlias++)
[33722]506 {
[85011]507 if (strcmp(pszDev, g_aDeviceAliases[iAlias].pszDevName) == 0)
508 return g_aDeviceAliases[iAlias].pszDevAlias;
[33722]509 }
510 return NULL;
511}
512
[70238]513static bool RuleComparator(const DeviceAssignmentRule *r1, const DeviceAssignmentRule *r2)
[33722]514{
515 return (r1->iPriority > r2->iPriority);
516}
517
[70238]518HRESULT BusAssignmentManager::State::autoAssign(const char *pszName, PCIBusAddress& Address)
[33687]519{
[42551]520 PCIRulesList matchingRules;
[33722]521
[85007]522 addMatchingRules(pszName, matchingRules);
[70238]523 const char *pszAlias = findAlias(pszName);
[33722]524 if (pszAlias)
525 addMatchingRules(pszAlias, matchingRules);
526
527 AssertMsg(matchingRules.size() > 0, ("No rule for %s(%s)\n", pszName, pszAlias));
528
[34266]529 stable_sort(matchingRules.begin(), matchingRules.end(), RuleComparator);
[33722]530
531 for (size_t iRule = 0; iRule < matchingRules.size(); iRule++)
532 {
[70238]533 const DeviceAssignmentRule *rule = matchingRules[iRule];
[33722]534
[36630]535 Address.miBus = rule->iBus;
536 Address.miDevice = rule->iDevice;
537 Address.miFn = rule->iFn;
[33722]538
539 if (checkAvailable(Address))
540 return S_OK;
541 }
[70238]542 AssertLogRelMsgFailed(("BusAssignmentManager: All possible candidate positions for %s exhausted\n", pszName));
[33722]543
544 return E_INVALIDARG;
[33687]545}
546
[42551]547bool BusAssignmentManager::State::checkAvailable(PCIBusAddress& Address)
[33687]548{
[42551]549 PCIMap::const_iterator it = mPCIMap.find(Address);
[33688]550
[42551]551 return (it == mPCIMap.end());
[33687]552}
553
[61009]554void BusAssignmentManager::State::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
[34331]555{
[51612]556 aAttached.resize(mPCIMap.size());
[34331]557
[51612]558 size_t i = 0;
[61009]559 PCIDeviceInfo dev;
[51612]560 for (PCIMap::const_iterator it = mPCIMap.begin(); it != mPCIMap.end(); ++it, ++i)
[34331]561 {
[61009]562 dev.strDeviceName = it->second.szDevName;
563 dev.guestAddress = it->first;
564 dev.hostAddress = it->second.HostAddress;
565 aAttached[i] = dev;
[34331]566 }
567}
568
[33687]569BusAssignmentManager::BusAssignmentManager()
570 : pState(NULL)
571{
572 pState = new State();
573 Assert(pState);
574}
575
576BusAssignmentManager::~BusAssignmentManager()
577{
578 if (pState)
579 {
580 delete pState;
581 pState = NULL;
582 }
583}
584
[93444]585BusAssignmentManager *BusAssignmentManager::createInstance(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType)
[33687]586{
[70238]587 BusAssignmentManager *pInstance = new BusAssignmentManager();
[93444]588 pInstance->pState->init(pVMM, chipsetType, iommuType);
[34331]589 Assert(pInstance);
[33687]590 return pInstance;
591}
592
593void BusAssignmentManager::AddRef()
594{
595 ASMAtomicIncS32(&pState->cRefCnt);
596}
[93444]597
[33687]598void BusAssignmentManager::Release()
599{
[34044]600 if (ASMAtomicDecS32(&pState->cRefCnt) == 0)
[33687]601 delete this;
602}
603
[93444]604DECLINLINE(HRESULT) InsertConfigInteger(PCVMMR3VTABLE pVMM, PCFGMNODE pCfg, const char *pszName, uint64_t u64)
[33687]605{
[93444]606 int vrc = pVMM->pfnCFGMR3InsertInteger(pCfg, pszName, u64);
[33687]607 if (RT_FAILURE(vrc))
608 return E_INVALIDARG;
609
610 return S_OK;
611}
612
[93444]613DECLINLINE(HRESULT) InsertConfigNode(PCVMMR3VTABLE pVMM, PCFGMNODE pNode, const char *pcszName, PCFGMNODE *ppChild)
[70238]614{
[93444]615 int vrc = pVMM->pfnCFGMR3InsertNode(pNode, pcszName, ppChild);
[70238]616 if (RT_FAILURE(vrc))
617 return E_INVALIDARG;
618
619 return S_OK;
620}
621
622
623HRESULT BusAssignmentManager::assignPCIDeviceImpl(const char *pszDevName,
[36107]624 PCFGMNODE pCfg,
[42551]625 PCIBusAddress& GuestAddress,
626 PCIBusAddress HostAddress,
[36107]627 bool fGuestAddressRequired)
[33687]628{
[94920]629 HRESULT hrc = S_OK;
[33687]630
[36107]631 if (!GuestAddress.valid())
[94920]632 hrc = pState->autoAssign(pszDevName, GuestAddress);
[33687]633 else
634 {
[36107]635 bool fAvailable = pState->checkAvailable(GuestAddress);
[33687]636
637 if (!fAvailable)
638 {
[36107]639 if (fGuestAddressRequired)
[94920]640 hrc = E_ACCESSDENIED;
[33687]641 else
[94920]642 hrc = pState->autoAssign(pszDevName, GuestAddress);
[33687]643 }
644 }
645
[94920]646 if (FAILED(hrc))
647 return hrc;
[33687]648
[36107]649 Assert(GuestAddress.valid() && pState->checkAvailable(GuestAddress));
[33687]650
[94920]651 hrc = pState->record(pszDevName, GuestAddress, HostAddress);
652 if (FAILED(hrc))
653 return hrc;
[33688]654
[93444]655 PCVMMR3VTABLE const pVMM = pState->mpVMM;
[85007]656 if (pCfg)
657 {
[94920]658 hrc = InsertConfigInteger(pVMM, pCfg, "PCIBusNo", GuestAddress.miBus);
659 if (FAILED(hrc))
660 return hrc;
661 hrc = InsertConfigInteger(pVMM, pCfg, "PCIDeviceNo", GuestAddress.miDevice);
662 if (FAILED(hrc))
663 return hrc;
664 hrc = InsertConfigInteger(pVMM, pCfg, "PCIFunctionNo", GuestAddress.miFn);
665 if (FAILED(hrc))
666 return hrc;
[85007]667 }
[33687]668
[70238]669 /* Check if the bus is still unknown, i.e. the bridge to it is missing */
670 if ( GuestAddress.miBus > 0
671 && !hasPCIDevice(pState->mpszBridgeName, GuestAddress.miBus - 1))
672 {
[93444]673 PCFGMNODE pDevices = pVMM->pfnCFGMR3GetParent(pVMM->pfnCFGMR3GetParent(pCfg));
[70238]674 AssertLogRelMsgReturn(pDevices, ("BusAssignmentManager: cannot find base device configuration\n"), E_UNEXPECTED);
[93444]675 PCFGMNODE pBridges = pVMM->pfnCFGMR3GetChild(pDevices, "ich9pcibridge");
[70238]676 AssertLogRelMsgReturn(pBridges, ("BusAssignmentManager: cannot find bridge configuration base\n"), E_UNEXPECTED);
677
678 /* Device should be on a not yet existing bus, add it automatically */
679 for (int iBridge = 0; iBridge <= GuestAddress.miBus - 1; iBridge++)
680 {
681 if (!hasPCIDevice(pState->mpszBridgeName, iBridge))
682 {
683 PCIBusAddress BridgeGuestAddress;
[94920]684 hrc = pState->autoAssign(pState->mpszBridgeName, BridgeGuestAddress);
685 if (FAILED(hrc))
686 return hrc;
[70238]687 if (BridgeGuestAddress.miBus > iBridge)
688 AssertLogRelMsgFailedReturn(("BusAssignmentManager: cannot create bridge for bus %i because the possible parent bus positions are exhausted\n", iBridge + 1), E_UNEXPECTED);
689
690 PCFGMNODE pInst;
[93444]691 InsertConfigNode(pVMM, pBridges, Utf8StrFmt("%d", iBridge).c_str(), &pInst);
692 InsertConfigInteger(pVMM, pInst, "Trusted", 1);
[94920]693 hrc = assignPCIDevice(pState->mpszBridgeName, pInst);
694 if (FAILED(hrc))
695 return hrc;
[70238]696 }
697 }
698 }
699
[33687]700 return S_OK;
701}
[33690]702
703
[70238]704bool BusAssignmentManager::findPCIAddress(const char *pszDevName, int iInstance, PCIBusAddress& Address)
[33690]705{
[42551]706 return pState->findPCIAddress(pszDevName, iInstance, Address);
[33690]707}
[61009]708void BusAssignmentManager::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
[34331]709{
[51612]710 pState->listAttachedPCIDevices(aAttached);
[34331]711}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use