VirtualBox

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

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

src-client: Define LOG_GROUP according to interface or similar.

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