VirtualBox

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

Last change on this file since 94173 was 93444, checked in by vboxsync, 3 years ago

VMM,Main,HostServices: Use a function table for accessing the VBoxVMM.dll/so/dylib functionality, and load it dynamically when the Console object is initialized. Also converted a few drivers in Main to use device helpers to get config values and such. bugref:10074

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