VirtualBox

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

Last change on this file since 47469 was 47223, checked in by vboxsync, 11 years ago

Main/ConsoleImpl2.cpp+BusAssignmentManager.cpp: fix long standing misunderstanding with the VMware NIC slot placement, was mixup between hex and dec, no behavior change

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

© 2023 Oracle
ContactPrivacy policyTerms of Use