VirtualBox

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

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

Main/BusAssignmentManager: comment about EFI assumptions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.0 KB
Line 
1/* $Id: BusAssignmentManager.cpp 68371 2017-08-10 13:52:23Z vboxsync $ */
2/** @file
3 * VirtualBox bus slots assignment manager
4 */
5
6/*
7 * Copyright (C) 2010-2016 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#define LOG_GROUP LOG_GROUP_MAIN
19#include "LoggingNew.h"
20
21#include "BusAssignmentManager.h"
22
23#include <iprt/asm.h>
24#include <iprt/string.h>
25
26#include <VBox/vmm/cfgm.h>
27#include <VBox/com/array.h>
28
29#include <map>
30#include <vector>
31#include <algorithm>
32
33struct DeviceAssignmentRule
34{
35 const char* pszName;
36 int iBus;
37 int iDevice;
38 int iFn;
39 int iPriority;
40};
41
42struct DeviceAliasRule
43{
44 const char* pszDevName;
45 const char* pszDevAlias;
46};
47
48/* Those rules define PCI slots assignment */
49/** @note
50 * The EFI takes assumptions about PCI slot assignments which are different
51 * from the following tables in certain cases, for example the IDE device
52 * is assumed to be 00:01.1! */
53
54/* Device Bus Device Function Priority */
55
56/* Generic rules */
57static const DeviceAssignmentRule aGenericRules[] =
58{
59 /* VGA controller */
60 {"vga", 0, 2, 0, 0},
61
62 /* VMM device */
63 {"VMMDev", 0, 4, 0, 0},
64
65 /* Audio controllers */
66 {"ichac97", 0, 5, 0, 0},
67 {"hda", 0, 5, 0, 0},
68
69 /* Storage controllers */
70 {"lsilogic", 0, 20, 0, 1},
71 {"buslogic", 0, 21, 0, 1},
72 {"lsilogicsas", 0, 22, 0, 1},
73 {"nvme", 0, 14, 0, 1},
74
75 /* USB controllers */
76 {"usb-ohci", 0, 6, 0, 0},
77 {"usb-ehci", 0, 11, 0, 0},
78 {"usb-xhci", 0, 12, 0, 0},
79
80 /* ACPI controller */
81 {"acpi", 0, 7, 0, 0},
82
83 /* Network controllers */
84 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
85 * next 4 get 16..19. In "VMWare compatibility" mode the IDs 3 and 17
86 * swap places, i.e. the first card goes to ID 17=0x11. */
87 {"nic", 0, 3, 0, 1},
88 {"nic", 0, 8, 0, 1},
89 {"nic", 0, 9, 0, 1},
90 {"nic", 0, 10, 0, 1},
91 {"nic", 0, 16, 0, 1},
92 {"nic", 0, 17, 0, 1},
93 {"nic", 0, 18, 0, 1},
94 {"nic", 0, 19, 0, 1},
95
96 /* ISA/LPC controller */
97 {"lpc", 0, 31, 0, 0},
98
99 { NULL, -1, -1, -1, 0}
100};
101
102/* PIIX3 chipset rules */
103static const DeviceAssignmentRule aPiix3Rules[] =
104{
105 {"piix3ide", 0, 1, 1, 0},
106 {"ahci", 0, 13, 0, 1},
107 {"pcibridge", 0, 24, 0, 0},
108 {"pcibridge", 0, 25, 0, 0},
109 { NULL, -1, -1, -1, 0}
110};
111
112
113/* ICH9 chipset rules */
114static const DeviceAssignmentRule aIch9Rules[] =
115{
116 /* Host Controller */
117 {"i82801", 0, 30, 0, 0},
118
119 /* Those are functions of LPC at 00:1e:00 */
120 /**
121 * Please note, that for devices being functions, like we do here, device 0
122 * must be multifunction, i.e. have header type 0x80. Our LPC device is.
123 * Alternative approach is to assign separate slot to each device.
124 */
125 {"piix3ide", 0, 31, 1, 2},
126 {"ahci", 0, 31, 2, 2},
127 {"smbus", 0, 31, 3, 2},
128 {"usb-ohci", 0, 31, 4, 2},
129 {"usb-ehci", 0, 31, 5, 2},
130 {"thermal", 0, 31, 6, 2},
131
132 /* to make sure rule never used before rules assigning devices on it */
133 {"ich9pcibridge", 0, 24, 0, 10},
134 {"ich9pcibridge", 0, 25, 0, 10},
135 {"ich9pcibridge", 1, 24, 0, 9},
136 {"ich9pcibridge", 1, 25, 0, 9},
137 {"ich9pcibridge", 2, 24, 0, 8},
138 {"ich9pcibridge", 2, 25, 0, 8},
139 {"ich9pcibridge", 3, 24, 0, 7},
140 {"ich9pcibridge", 3, 25, 0, 7},
141 {"ich9pcibridge", 4, 24, 0, 6},
142 {"ich9pcibridge", 4, 25, 0, 6},
143 {"ich9pcibridge", 5, 24, 0, 5},
144 {"ich9pcibridge", 5, 25, 0, 5},
145
146 /* Storage controllers */
147 {"ahci", 1, 0, 0, 0},
148 {"ahci", 1, 1, 0, 0},
149 {"ahci", 1, 2, 0, 0},
150 {"ahci", 1, 3, 0, 0},
151 {"ahci", 1, 4, 0, 0},
152 {"ahci", 1, 5, 0, 0},
153 {"ahci", 1, 6, 0, 0},
154 {"lsilogic", 1, 7, 0, 0},
155 {"lsilogic", 1, 8, 0, 0},
156 {"lsilogic", 1, 9, 0, 0},
157 {"lsilogic", 1, 10, 0, 0},
158 {"lsilogic", 1, 11, 0, 0},
159 {"lsilogic", 1, 12, 0, 0},
160 {"lsilogic", 1, 13, 0, 0},
161 {"buslogic", 1, 14, 0, 0},
162 {"buslogic", 1, 15, 0, 0},
163 {"buslogic", 1, 16, 0, 0},
164 {"buslogic", 1, 17, 0, 0},
165 {"buslogic", 1, 18, 0, 0},
166 {"buslogic", 1, 19, 0, 0},
167 {"buslogic", 1, 20, 0, 0},
168 {"lsilogicsas", 1, 21, 0, 0},
169 {"lsilogicsas", 1, 26, 0, 0},
170 {"lsilogicsas", 1, 27, 0, 0},
171 {"lsilogicsas", 1, 28, 0, 0},
172 {"lsilogicsas", 1, 29, 0, 0},
173 {"lsilogicsas", 1, 30, 0, 0},
174 {"lsilogicsas", 1, 31, 0, 0},
175
176 /* NICs */
177 {"nic", 2, 0, 0, 0},
178 {"nic", 2, 1, 0, 0},
179 {"nic", 2, 2, 0, 0},
180 {"nic", 2, 3, 0, 0},
181 {"nic", 2, 4, 0, 0},
182 {"nic", 2, 5, 0, 0},
183 {"nic", 2, 6, 0, 0},
184 {"nic", 2, 7, 0, 0},
185 {"nic", 2, 8, 0, 0},
186 {"nic", 2, 9, 0, 0},
187 {"nic", 2, 10, 0, 0},
188 {"nic", 2, 11, 0, 0},
189 {"nic", 2, 12, 0, 0},
190 {"nic", 2, 13, 0, 0},
191 {"nic", 2, 14, 0, 0},
192 {"nic", 2, 15, 0, 0},
193 {"nic", 2, 16, 0, 0},
194 {"nic", 2, 17, 0, 0},
195 {"nic", 2, 18, 0, 0},
196 {"nic", 2, 19, 0, 0},
197 {"nic", 2, 20, 0, 0},
198 {"nic", 2, 21, 0, 0},
199 {"nic", 2, 26, 0, 0},
200 {"nic", 2, 27, 0, 0},
201 {"nic", 2, 28, 0, 0},
202 {"nic", 2, 29, 0, 0},
203 {"nic", 2, 30, 0, 0},
204 {"nic", 2, 31, 0, 0},
205
206 /* Storage controller #2 (NVMe) */
207 {"nvme", 3, 0, 0, 0},
208 {"nvme", 3, 1, 0, 0},
209 {"nvme", 3, 2, 0, 0},
210 {"nvme", 3, 3, 0, 0},
211 {"nvme", 3, 4, 0, 0},
212 {"nvme", 3, 5, 0, 0},
213 {"nvme", 3, 6, 0, 0},
214
215 { NULL, -1, -1, -1, 0}
216};
217
218/* Aliasing rules */
219static const DeviceAliasRule aDeviceAliases[] =
220{
221 {"e1000", "nic"},
222 {"pcnet", "nic"},
223 {"virtio-net", "nic"},
224 {"ahci", "storage"},
225 {"lsilogic", "storage"},
226 {"buslogic", "storage"},
227 {"lsilogicsas", "storage"},
228 {"nvme", "storage"}
229};
230
231struct BusAssignmentManager::State
232{
233 struct PCIDeviceRecord
234 {
235 char szDevName[32];
236 PCIBusAddress HostAddress;
237
238 PCIDeviceRecord(const char* pszName, PCIBusAddress aHostAddress)
239 {
240 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
241 this->HostAddress = aHostAddress;
242 }
243
244 PCIDeviceRecord(const char* pszName)
245 {
246 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
247 }
248
249 bool operator<(const PCIDeviceRecord &a) const
250 {
251 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) < 0;
252 }
253
254 bool operator==(const PCIDeviceRecord &a) const
255 {
256 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
257 }
258 };
259
260 typedef std::map<PCIBusAddress,PCIDeviceRecord> PCIMap;
261 typedef std::vector<PCIBusAddress> PCIAddrList;
262 typedef std::vector<const DeviceAssignmentRule *> PCIRulesList;
263 typedef std::map<PCIDeviceRecord,PCIAddrList> ReversePCIMap;
264
265 volatile int32_t cRefCnt;
266 ChipsetType_T mChipsetType;
267 PCIMap mPCIMap;
268 ReversePCIMap mReversePCIMap;
269
270 State()
271 : cRefCnt(1), mChipsetType(ChipsetType_Null)
272 {}
273 ~State()
274 {}
275
276 HRESULT init(ChipsetType_T chipsetType);
277
278 HRESULT record(const char* pszName, PCIBusAddress& GuestAddress, PCIBusAddress HostAddress);
279 HRESULT autoAssign(const char* pszName, PCIBusAddress& Address);
280 bool checkAvailable(PCIBusAddress& Address);
281 bool findPCIAddress(const char* pszDevName, int iInstance, PCIBusAddress& Address);
282
283 const char* findAlias(const char* pszName);
284 void addMatchingRules(const char* pszName, PCIRulesList& aList);
285 void listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached);
286};
287
288HRESULT BusAssignmentManager::State::init(ChipsetType_T chipsetType)
289{
290 mChipsetType = chipsetType;
291 return S_OK;
292}
293
294HRESULT BusAssignmentManager::State::record(const char* pszName, PCIBusAddress& Address, PCIBusAddress HostAddress)
295{
296 PCIDeviceRecord devRec(pszName, HostAddress);
297
298 /* Remember address -> device mapping */
299 mPCIMap.insert(PCIMap::value_type(Address, devRec));
300
301 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
302 if (it == mReversePCIMap.end())
303 {
304 mReversePCIMap.insert(ReversePCIMap::value_type(devRec, PCIAddrList()));
305 it = mReversePCIMap.find(devRec);
306 }
307
308 /* Remember device name -> addresses mapping */
309 it->second.push_back(Address);
310
311 return S_OK;
312}
313
314bool BusAssignmentManager::State::findPCIAddress(const char* pszDevName, int iInstance, PCIBusAddress& Address)
315{
316 PCIDeviceRecord devRec(pszDevName);
317
318 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
319 if (it == mReversePCIMap.end())
320 return false;
321
322 if (iInstance >= (int)it->second.size())
323 return false;
324
325 Address = it->second[iInstance];
326 return true;
327}
328
329void BusAssignmentManager::State::addMatchingRules(const char* pszName, PCIRulesList& aList)
330{
331 size_t iRuleset, iRule;
332 const DeviceAssignmentRule* aArrays[2] = {aGenericRules, NULL};
333
334 switch (mChipsetType)
335 {
336 case ChipsetType_PIIX3:
337 aArrays[1] = aPiix3Rules;
338 break;
339 case ChipsetType_ICH9:
340 aArrays[1] = aIch9Rules;
341 break;
342 default:
343 Assert(false);
344 break;
345 }
346
347 for (iRuleset = 0; iRuleset < RT_ELEMENTS(aArrays); iRuleset++)
348 {
349 if (aArrays[iRuleset] == NULL)
350 continue;
351
352 for (iRule = 0; aArrays[iRuleset][iRule].pszName != NULL; iRule++)
353 {
354 if (RTStrCmp(pszName, aArrays[iRuleset][iRule].pszName) == 0)
355 aList.push_back(&aArrays[iRuleset][iRule]);
356 }
357 }
358}
359
360const char* BusAssignmentManager::State::findAlias(const char* pszDev)
361{
362 for (size_t iAlias = 0; iAlias < RT_ELEMENTS(aDeviceAliases); iAlias++)
363 {
364 if (strcmp(pszDev, aDeviceAliases[iAlias].pszDevName) == 0)
365 return aDeviceAliases[iAlias].pszDevAlias;
366 }
367 return NULL;
368}
369
370static bool RuleComparator(const DeviceAssignmentRule* r1, const DeviceAssignmentRule* r2)
371{
372 return (r1->iPriority > r2->iPriority);
373}
374
375HRESULT BusAssignmentManager::State::autoAssign(const char* pszName, PCIBusAddress& Address)
376{
377 PCIRulesList matchingRules;
378
379 addMatchingRules(pszName, matchingRules);
380 const char* pszAlias = findAlias(pszName);
381 if (pszAlias)
382 addMatchingRules(pszAlias, matchingRules);
383
384 AssertMsg(matchingRules.size() > 0, ("No rule for %s(%s)\n", pszName, pszAlias));
385
386 stable_sort(matchingRules.begin(), matchingRules.end(), RuleComparator);
387
388 for (size_t iRule = 0; iRule < matchingRules.size(); iRule++)
389 {
390 const DeviceAssignmentRule* rule = matchingRules[iRule];
391
392 Address.miBus = rule->iBus;
393 Address.miDevice = rule->iDevice;
394 Address.miFn = rule->iFn;
395
396 if (checkAvailable(Address))
397 return S_OK;
398 }
399 AssertMsgFailed(("All possible candidate positions for %s exhausted\n", pszName));
400
401 return E_INVALIDARG;
402}
403
404bool BusAssignmentManager::State::checkAvailable(PCIBusAddress& Address)
405{
406 PCIMap::const_iterator it = mPCIMap.find(Address);
407
408 return (it == mPCIMap.end());
409}
410
411void BusAssignmentManager::State::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
412{
413 aAttached.resize(mPCIMap.size());
414
415 size_t i = 0;
416 PCIDeviceInfo dev;
417 for (PCIMap::const_iterator it = mPCIMap.begin(); it != mPCIMap.end(); ++it, ++i)
418 {
419 dev.strDeviceName = it->second.szDevName;
420 dev.guestAddress = it->first;
421 dev.hostAddress = it->second.HostAddress;
422 aAttached[i] = dev;
423 }
424}
425
426BusAssignmentManager::BusAssignmentManager()
427 : pState(NULL)
428{
429 pState = new State();
430 Assert(pState);
431}
432
433BusAssignmentManager::~BusAssignmentManager()
434{
435 if (pState)
436 {
437 delete pState;
438 pState = NULL;
439 }
440}
441
442BusAssignmentManager* BusAssignmentManager::createInstance(ChipsetType_T chipsetType)
443{
444 BusAssignmentManager* pInstance = new BusAssignmentManager();
445 pInstance->pState->init(chipsetType);
446 Assert(pInstance);
447 return pInstance;
448}
449
450void BusAssignmentManager::AddRef()
451{
452 ASMAtomicIncS32(&pState->cRefCnt);
453}
454void BusAssignmentManager::Release()
455{
456 if (ASMAtomicDecS32(&pState->cRefCnt) == 0)
457 delete this;
458}
459
460DECLINLINE(HRESULT) InsertConfigInteger(PCFGMNODE pCfg, const char* pszName, uint64_t u64)
461{
462 int vrc = CFGMR3InsertInteger(pCfg, pszName, u64);
463 if (RT_FAILURE(vrc))
464 return E_INVALIDARG;
465
466 return S_OK;
467}
468
469HRESULT BusAssignmentManager::assignPCIDeviceImpl(const char* pszDevName,
470 PCFGMNODE pCfg,
471 PCIBusAddress& GuestAddress,
472 PCIBusAddress HostAddress,
473 bool fGuestAddressRequired)
474{
475 HRESULT rc = S_OK;
476
477 if (!GuestAddress.valid())
478 rc = pState->autoAssign(pszDevName, GuestAddress);
479 else
480 {
481 bool fAvailable = pState->checkAvailable(GuestAddress);
482
483 if (!fAvailable)
484 {
485 if (fGuestAddressRequired)
486 rc = E_ACCESSDENIED;
487 else
488 rc = pState->autoAssign(pszDevName, GuestAddress);
489 }
490 }
491
492 if (FAILED(rc))
493 return rc;
494
495 Assert(GuestAddress.valid() && pState->checkAvailable(GuestAddress));
496
497 rc = pState->record(pszDevName, GuestAddress, HostAddress);
498 if (FAILED(rc))
499 return rc;
500
501 rc = InsertConfigInteger(pCfg, "PCIBusNo", GuestAddress.miBus);
502 if (FAILED(rc))
503 return rc;
504 rc = InsertConfigInteger(pCfg, "PCIDeviceNo", GuestAddress.miDevice);
505 if (FAILED(rc))
506 return rc;
507 rc = InsertConfigInteger(pCfg, "PCIFunctionNo", GuestAddress.miFn);
508 if (FAILED(rc))
509 return rc;
510
511 return S_OK;
512}
513
514
515bool BusAssignmentManager::findPCIAddress(const char* pszDevName, int iInstance, PCIBusAddress& Address)
516{
517 return pState->findPCIAddress(pszDevName, iInstance, Address);
518}
519void BusAssignmentManager::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
520{
521 pState->listAttachedPCIDevices(aAttached);
522}
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