VirtualBox

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

Last change on this file since 108627 was 108627, checked in by vboxsync, 3 weeks ago

Main/src-client/BusAssignmentManager.cpp: clang build fixes, bugref:10391

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette