VirtualBox

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

Last change on this file since 101473 was 101473, checked in by vboxsync, 7 months ago

Main/BusAssignmentManager: Preliminary support for the VirtualBox Armv8 virtual platform, bugref:10528

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.3 KB
Line 
1/* $Id: BusAssignmentManager.cpp 101473 2023-10-17 11:54:45Z vboxsync $ */
2/** @file
3 * VirtualBox bus slots assignment manager
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
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_MAIN
33#include "LoggingNew.h"
34
35#include "BusAssignmentManager.h"
36
37#include <iprt/asm.h>
38#include <iprt/string.h>
39
40#include <VBox/vmm/cfgm.h>
41#include <VBox/vmm/vmmr3vtable.h>
42#include <VBox/com/array.h>
43
44#include <map>
45#include <vector>
46#include <algorithm>
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52struct DeviceAssignmentRule
53{
54 const char *pszName;
55 int iBus;
56 int iDevice;
57 int iFn;
58 int iPriority;
59};
60
61struct DeviceAliasRule
62{
63 const char *pszDevName;
64 const char *pszDevAlias;
65};
66
67
68/*********************************************************************************************************************************
69* Global Variables *
70*********************************************************************************************************************************/
71/* Those rules define PCI slots assignment */
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! */
76
77/* Device Bus Device Function Priority */
78
79/* Generic rules */
80static const DeviceAssignmentRule g_aGenericRules[] =
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 */
93 {"buslogic", 0, 21, 0, 1},
94 {"lsilogicsas", 0, 22, 0, 1},
95 {"nvme", 0, 14, 0, 1},
96 {"virtio-scsi", 0, 15, 0, 1},
97
98 /* USB controllers */
99 {"usb-ohci", 0, 6, 0, 0},
100 {"usb-ehci", 0, 11, 0, 0},
101 {"usb-xhci", 0, 12, 0, 0},
102
103 /* ACPI controller */
104#if 0
105 // It really should be this for 440FX chipset (part of PIIX4 actually)
106 {"acpi", 0, 1, 3, 0},
107#else
108 {"acpi", 0, 7, 0, 0},
109#endif
110
111 /* Network controllers */
112 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
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. */
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},
123
124 /* ISA/LPC controller */
125 {"lpc", 0, 31, 0, 0},
126
127 { NULL, -1, -1, -1, 0}
128};
129
130/* PIIX3 chipset rules */
131static const DeviceAssignmentRule g_aPiix3Rules[] =
132{
133 {"piix3ide", 0, 1, 1, 0},
134 {"ahci", 0, 13, 0, 1},
135 {"lsilogic", 0, 20, 0, 1},
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 */
143static const DeviceAssignmentRule g_aIch9Rules[] =
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 */
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},
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},
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},
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
235 /* Storage controller #2 (NVMe, virtio-scsi) */
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},
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},
250
251 { NULL, -1, -1, -1, 0}
252};
253
254
255/* Virtual Armv8 platform chipset rules */
256static const DeviceAssignmentRule g_aArmv8Rules[] =
257{
258 /* VGA controller */
259 {"vga", 0, 0, 0, 0},
260
261 /* VMM device */
262 {"VMMDev", 0, 1, 0, 0},
263
264 /* Audio controllers */
265 {"ichac97", 0, 2, 0, 0},
266 {"hda", 0, 2, 0, 0},
267
268 /* Storage controllers */
269 {"virtio-scsi", 0, 3, 0, 1},
270 {"nvme", 0, 4, 0, 1},
271 {"ahci", 0, 16, 0, 1},
272 {"lsilogicsas", 0, 17, 0, 1},
273
274 /* USB controllers */
275 {"usb-ehci", 0, 5, 0, 0},
276 {"usb-xhci", 0, 6, 0, 0},
277 {"usb-ohci", 0, 7, 0, 0},
278
279 /* Network controllers */
280 {"nic", 0, 8, 0, 1},
281 {"nic", 0, 9, 0, 1},
282 {"nic", 0, 10, 0, 1},
283 {"nic", 0, 11, 0, 1},
284 {"nic", 0, 12, 0, 1},
285 {"nic", 0, 13, 0, 1},
286 {"nic", 0, 14, 0, 1},
287 {"nic", 0, 15, 0, 1},
288
289 { NULL, -1, -1, -1, 0}
290};
291
292
293#ifdef VBOX_WITH_IOMMU_AMD
294/*
295 * AMD IOMMU and LSI Logic controller rules.
296 *
297 * Since the PCI slot (BDF=00:20.0) of the LSI Logic controller
298 * conflicts with the SB I/O APIC, we assign the LSI Logic controller
299 * to device number 23 when the VM is configured for an AMD IOMMU.
300 */
301static const DeviceAssignmentRule g_aIch9IommuAmdRules[] =
302{
303 /* AMD IOMMU. */
304 {"iommu-amd", 0, 0, 0, 0},
305 /* AMD IOMMU: Reserved for southbridge I/O APIC. */
306 {"sb-ioapic", 0, 20, 0, 0},
307
308 /* Storage controller */
309 {"lsilogic", 0, 23, 0, 1},
310 { NULL, -1, -1, -1, 0}
311};
312#endif
313
314#ifdef VBOX_WITH_IOMMU_INTEL
315/*
316 * Intel IOMMU.
317 * The VT-d misc, address remapping, system management device is
318 * located at BDF 0:5:0 on real hardware but we use 0:1:0 since that
319 * slot isn't used for anything else.
320 *
321 * While we could place the I/O APIC anywhere, we keep it consistent
322 * with the AMD IOMMU and we assign the LSI Logic controller to
323 * device number 23 (and I/O APIC at device 20).
324 */
325static const DeviceAssignmentRule g_aIch9IommuIntelRules[] =
326{
327 /* Intel IOMMU. */
328 {"iommu-intel", 0, 1, 0, 0},
329 /* Intel IOMMU: Reserved for I/O APIC. */
330 {"sb-ioapic", 0, 20, 0, 0},
331
332 /* Storage controller */
333 {"lsilogic", 0, 23, 0, 1},
334 { NULL, -1, -1, -1, 0}
335};
336#endif
337
338/* LSI Logic Controller. */
339static const DeviceAssignmentRule g_aIch9LsiRules[] =
340{
341 /* Storage controller */
342 {"lsilogic", 0, 20, 0, 1},
343 { NULL, -1, -1, -1, 0}
344};
345
346/* Aliasing rules */
347static const DeviceAliasRule g_aDeviceAliases[] =
348{
349 {"e1000", "nic"},
350 {"pcnet", "nic"},
351 {"virtio-net", "nic"},
352 {"ahci", "storage"},
353 {"lsilogic", "storage"},
354 {"buslogic", "storage"},
355 {"lsilogicsas", "storage"},
356 {"nvme", "storage"},
357 {"virtio-scsi", "storage"}
358};
359
360
361
362/**
363 * Bus assignment manage state data.
364 * @internal
365 */
366struct BusAssignmentManager::State
367{
368 struct PCIDeviceRecord
369 {
370 char szDevName[32];
371 PCIBusAddress HostAddress;
372
373 PCIDeviceRecord(const char *pszName, PCIBusAddress aHostAddress)
374 {
375 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
376 this->HostAddress = aHostAddress;
377 }
378
379 PCIDeviceRecord(const char *pszName)
380 {
381 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
382 }
383
384 bool operator<(const PCIDeviceRecord &a) const
385 {
386 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) < 0;
387 }
388
389 bool operator==(const PCIDeviceRecord &a) const
390 {
391 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
392 }
393 };
394
395 typedef std::map<PCIBusAddress,PCIDeviceRecord> PCIMap;
396 typedef std::vector<PCIBusAddress> PCIAddrList;
397 typedef std::vector<const DeviceAssignmentRule *> PCIRulesList;
398 typedef std::map<PCIDeviceRecord,PCIAddrList> ReversePCIMap;
399
400 volatile int32_t cRefCnt;
401 ChipsetType_T mChipsetType;
402 const char * mpszBridgeName;
403 IommuType_T mIommuType;
404 PCIMap mPCIMap;
405 ReversePCIMap mReversePCIMap;
406 PCVMMR3VTABLE mpVMM;
407
408 State()
409 : cRefCnt(1), mChipsetType(ChipsetType_Null), mpszBridgeName("unknownbridge"), mpVMM(NULL)
410 {}
411 ~State()
412 {}
413
414 HRESULT init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType);
415
416 HRESULT record(const char *pszName, PCIBusAddress& GuestAddress, PCIBusAddress HostAddress);
417 HRESULT autoAssign(const char *pszName, PCIBusAddress& Address);
418 bool checkAvailable(PCIBusAddress& Address);
419 bool findPCIAddress(const char *pszDevName, int iInstance, PCIBusAddress& Address);
420
421 const char *findAlias(const char *pszName);
422 void addMatchingRules(const char *pszName, PCIRulesList& aList);
423 void listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached);
424};
425
426
427HRESULT BusAssignmentManager::State::init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType)
428{
429 mpVMM = pVMM;
430
431 if (iommuType != IommuType_None)
432 {
433#if defined(VBOX_WITH_IOMMU_AMD) && defined(VBOX_WITH_IOMMU_INTEL)
434 Assert(iommuType == IommuType_AMD || iommuType == IommuType_Intel);
435#elif defined(VBOX_WITH_IOMMU_AMD)
436 Assert(iommuType == IommuType_AMD);
437#elif defined(VBOX_WITH_IOMMU_INTEL)
438 Assert(iommuType == IommuType_Intel);
439#endif
440 }
441
442 mChipsetType = chipsetType;
443 mIommuType = iommuType;
444 switch (chipsetType)
445 {
446 case ChipsetType_PIIX3:
447 mpszBridgeName = "pcibridge";
448 break;
449 case ChipsetType_ICH9:
450 case ChipsetType_ARMv8Virtual:
451 mpszBridgeName = "ich9pcibridge";
452 break;
453 default:
454 mpszBridgeName = "unknownbridge";
455 AssertFailed();
456 break;
457 }
458 return S_OK;
459}
460
461HRESULT BusAssignmentManager::State::record(const char *pszName, PCIBusAddress& Address, PCIBusAddress HostAddress)
462{
463 PCIDeviceRecord devRec(pszName, HostAddress);
464
465 /* Remember address -> device mapping */
466 mPCIMap.insert(PCIMap::value_type(Address, devRec));
467
468 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
469 if (it == mReversePCIMap.end())
470 {
471 mReversePCIMap.insert(ReversePCIMap::value_type(devRec, PCIAddrList()));
472 it = mReversePCIMap.find(devRec);
473 }
474
475 /* Remember device name -> addresses mapping */
476 it->second.push_back(Address);
477
478 return S_OK;
479}
480
481bool BusAssignmentManager::State::findPCIAddress(const char *pszDevName, int iInstance, PCIBusAddress& Address)
482{
483 PCIDeviceRecord devRec(pszDevName);
484
485 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
486 if (it == mReversePCIMap.end())
487 return false;
488
489 if (iInstance >= (int)it->second.size())
490 return false;
491
492 Address = it->second[iInstance];
493 return true;
494}
495
496void BusAssignmentManager::State::addMatchingRules(const char *pszName, PCIRulesList& aList)
497{
498 size_t iRuleset, iRule;
499 const DeviceAssignmentRule *aArrays[3] = {g_aGenericRules, NULL, NULL};
500
501 switch (mChipsetType)
502 {
503 case ChipsetType_PIIX3:
504 aArrays[1] = g_aPiix3Rules;
505 break;
506 case ChipsetType_ICH9:
507 {
508 aArrays[1] = g_aIch9Rules;
509#ifdef VBOX_WITH_IOMMU_AMD
510 if (mIommuType == IommuType_AMD)
511 aArrays[2] = g_aIch9IommuAmdRules;
512 else
513#endif
514#ifdef VBOX_WITH_IOMMU_INTEL
515 if (mIommuType == IommuType_Intel)
516 aArrays[2] = g_aIch9IommuIntelRules;
517 else
518#endif
519 {
520 aArrays[2] = g_aIch9LsiRules;
521 }
522 break;
523 }
524 case ChipsetType_ARMv8Virtual:
525 aArrays[0] = g_aArmv8Rules;
526 break;
527 default:
528 AssertFailed();
529 break;
530 }
531
532 for (iRuleset = 0; iRuleset < RT_ELEMENTS(aArrays); iRuleset++)
533 {
534 if (aArrays[iRuleset] == NULL)
535 continue;
536
537 for (iRule = 0; aArrays[iRuleset][iRule].pszName != NULL; iRule++)
538 {
539 if (RTStrCmp(pszName, aArrays[iRuleset][iRule].pszName) == 0)
540 aList.push_back(&aArrays[iRuleset][iRule]);
541 }
542 }
543}
544
545const char *BusAssignmentManager::State::findAlias(const char *pszDev)
546{
547 for (size_t iAlias = 0; iAlias < RT_ELEMENTS(g_aDeviceAliases); iAlias++)
548 {
549 if (strcmp(pszDev, g_aDeviceAliases[iAlias].pszDevName) == 0)
550 return g_aDeviceAliases[iAlias].pszDevAlias;
551 }
552 return NULL;
553}
554
555static bool RuleComparator(const DeviceAssignmentRule *r1, const DeviceAssignmentRule *r2)
556{
557 return (r1->iPriority > r2->iPriority);
558}
559
560HRESULT BusAssignmentManager::State::autoAssign(const char *pszName, PCIBusAddress& Address)
561{
562 PCIRulesList matchingRules;
563
564 addMatchingRules(pszName, matchingRules);
565 const char *pszAlias = findAlias(pszName);
566 if (pszAlias)
567 addMatchingRules(pszAlias, matchingRules);
568
569 AssertMsg(matchingRules.size() > 0, ("No rule for %s(%s)\n", pszName, pszAlias));
570
571 stable_sort(matchingRules.begin(), matchingRules.end(), RuleComparator);
572
573 for (size_t iRule = 0; iRule < matchingRules.size(); iRule++)
574 {
575 const DeviceAssignmentRule *rule = matchingRules[iRule];
576
577 Address.miBus = rule->iBus;
578 Address.miDevice = rule->iDevice;
579 Address.miFn = rule->iFn;
580
581 if (checkAvailable(Address))
582 return S_OK;
583 }
584 AssertLogRelMsgFailed(("BusAssignmentManager: All possible candidate positions for %s exhausted\n", pszName));
585
586 return E_INVALIDARG;
587}
588
589bool BusAssignmentManager::State::checkAvailable(PCIBusAddress& Address)
590{
591 PCIMap::const_iterator it = mPCIMap.find(Address);
592
593 return (it == mPCIMap.end());
594}
595
596void BusAssignmentManager::State::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
597{
598 aAttached.resize(mPCIMap.size());
599
600 size_t i = 0;
601 PCIDeviceInfo dev;
602 for (PCIMap::const_iterator it = mPCIMap.begin(); it != mPCIMap.end(); ++it, ++i)
603 {
604 dev.strDeviceName = it->second.szDevName;
605 dev.guestAddress = it->first;
606 dev.hostAddress = it->second.HostAddress;
607 aAttached[i] = dev;
608 }
609}
610
611BusAssignmentManager::BusAssignmentManager()
612 : pState(NULL)
613{
614 pState = new State();
615 Assert(pState);
616}
617
618BusAssignmentManager::~BusAssignmentManager()
619{
620 if (pState)
621 {
622 delete pState;
623 pState = NULL;
624 }
625}
626
627BusAssignmentManager *BusAssignmentManager::createInstance(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType)
628{
629 BusAssignmentManager *pInstance = new BusAssignmentManager();
630 pInstance->pState->init(pVMM, chipsetType, iommuType);
631 Assert(pInstance);
632 return pInstance;
633}
634
635void BusAssignmentManager::AddRef()
636{
637 ASMAtomicIncS32(&pState->cRefCnt);
638}
639
640void BusAssignmentManager::Release()
641{
642 if (ASMAtomicDecS32(&pState->cRefCnt) == 0)
643 delete this;
644}
645
646DECLINLINE(HRESULT) InsertConfigInteger(PCVMMR3VTABLE pVMM, PCFGMNODE pCfg, const char *pszName, uint64_t u64)
647{
648 int vrc = pVMM->pfnCFGMR3InsertInteger(pCfg, pszName, u64);
649 if (RT_FAILURE(vrc))
650 return E_INVALIDARG;
651
652 return S_OK;
653}
654
655DECLINLINE(HRESULT) InsertConfigNode(PCVMMR3VTABLE pVMM, PCFGMNODE pNode, const char *pcszName, PCFGMNODE *ppChild)
656{
657 int vrc = pVMM->pfnCFGMR3InsertNode(pNode, pcszName, ppChild);
658 if (RT_FAILURE(vrc))
659 return E_INVALIDARG;
660
661 return S_OK;
662}
663
664
665HRESULT BusAssignmentManager::assignPCIDeviceImpl(const char *pszDevName,
666 PCFGMNODE pCfg,
667 PCIBusAddress& GuestAddress,
668 PCIBusAddress HostAddress,
669 bool fGuestAddressRequired)
670{
671 HRESULT hrc = S_OK;
672
673 if (!GuestAddress.valid())
674 hrc = pState->autoAssign(pszDevName, GuestAddress);
675 else
676 {
677 bool fAvailable = pState->checkAvailable(GuestAddress);
678
679 if (!fAvailable)
680 {
681 if (fGuestAddressRequired)
682 hrc = E_ACCESSDENIED;
683 else
684 hrc = pState->autoAssign(pszDevName, GuestAddress);
685 }
686 }
687
688 if (FAILED(hrc))
689 return hrc;
690
691 Assert(GuestAddress.valid() && pState->checkAvailable(GuestAddress));
692
693 hrc = pState->record(pszDevName, GuestAddress, HostAddress);
694 if (FAILED(hrc))
695 return hrc;
696
697 PCVMMR3VTABLE const pVMM = pState->mpVMM;
698 if (pCfg)
699 {
700 hrc = InsertConfigInteger(pVMM, pCfg, "PCIBusNo", GuestAddress.miBus);
701 if (FAILED(hrc))
702 return hrc;
703 hrc = InsertConfigInteger(pVMM, pCfg, "PCIDeviceNo", GuestAddress.miDevice);
704 if (FAILED(hrc))
705 return hrc;
706 hrc = InsertConfigInteger(pVMM, pCfg, "PCIFunctionNo", GuestAddress.miFn);
707 if (FAILED(hrc))
708 return hrc;
709 }
710
711 /* Check if the bus is still unknown, i.e. the bridge to it is missing */
712 if ( GuestAddress.miBus > 0
713 && !hasPCIDevice(pState->mpszBridgeName, GuestAddress.miBus - 1))
714 {
715 PCFGMNODE pDevices = pVMM->pfnCFGMR3GetParent(pVMM->pfnCFGMR3GetParent(pCfg));
716 AssertLogRelMsgReturn(pDevices, ("BusAssignmentManager: cannot find base device configuration\n"), E_UNEXPECTED);
717 PCFGMNODE pBridges = pVMM->pfnCFGMR3GetChild(pDevices, "ich9pcibridge");
718 AssertLogRelMsgReturn(pBridges, ("BusAssignmentManager: cannot find bridge configuration base\n"), E_UNEXPECTED);
719
720 /* Device should be on a not yet existing bus, add it automatically */
721 for (int iBridge = 0; iBridge <= GuestAddress.miBus - 1; iBridge++)
722 {
723 if (!hasPCIDevice(pState->mpszBridgeName, iBridge))
724 {
725 PCIBusAddress BridgeGuestAddress;
726 hrc = pState->autoAssign(pState->mpszBridgeName, BridgeGuestAddress);
727 if (FAILED(hrc))
728 return hrc;
729 if (BridgeGuestAddress.miBus > iBridge)
730 AssertLogRelMsgFailedReturn(("BusAssignmentManager: cannot create bridge for bus %i because the possible parent bus positions are exhausted\n", iBridge + 1), E_UNEXPECTED);
731
732 PCFGMNODE pInst;
733 InsertConfigNode(pVMM, pBridges, Utf8StrFmt("%d", iBridge).c_str(), &pInst);
734 InsertConfigInteger(pVMM, pInst, "Trusted", 1);
735 hrc = assignPCIDevice(pState->mpszBridgeName, pInst);
736 if (FAILED(hrc))
737 return hrc;
738 }
739 }
740 }
741
742 return S_OK;
743}
744
745
746bool BusAssignmentManager::findPCIAddress(const char *pszDevName, int iInstance, PCIBusAddress& Address)
747{
748 return pState->findPCIAddress(pszDevName, iInstance, Address);
749}
750void BusAssignmentManager::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
751{
752 pState->listAttachedPCIDevices(aAttached);
753}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use