VirtualBox

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

Last change on this file since 64093 was 63747, checked in by vboxsync, 8 years ago

Main/ConsoleImpl: Fix config for multiple NVMe controllers if ICH9 is used

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