VirtualBox

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

Last change on this file since 35650 was 35368, checked in by vboxsync, 14 years ago

Main: source re-org.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/* $Id: BusAssignmentManager.cpp 35368 2010-12-30 13:38:23Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox bus slots assignment manager
6 */
7
8/*
9 * Copyright (C) 2010 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 {"ahci", 0, 13, 0, 1},
68 {"lsilogic", 0, 20, 0, 1},
69 {"buslogic", 0, 21, 0, 1},
70 {"lsilogicsas", 0, 22, 0, 1},
71
72 /* USB controllers */
73 {"usb-ohci", 0, 6, 0, 0},
74 {"usb-ehci", 0, 11, 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. */
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 /* VMWare assigns first NIC to slot 11 */
91 {"nic-vmware", 0, 11, 0, 1},
92
93 /* ISA/LPC controller */
94 {"lpc", 0, 31, 0, 0},
95
96 { NULL, -1, -1, -1, 0}
97};
98
99/* PIIX3 chipset rules */
100static const DeviceAssignmentRule aPiix3Rules[] =
101{
102 {"piix3ide", 0, 1, 1, 0},
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 { NULL, -1, -1, -1, 0}
203};
204
205/* Aliasing rules */
206static const DeviceAliasRule aDeviceAliases[] =
207{
208 {"e1000", "nic"},
209 {"pcnet", "nic"},
210 {"virtio-net", "nic"},
211 {"ahci", "storage"},
212 {"lsilogic", "storage"},
213 {"buslogic", "storage"},
214 {"lsilogicsas", "storage"}
215};
216
217struct BusAssignmentManager::State
218{
219 struct PciDeviceRecord
220 {
221 char szDevName[32];
222
223 PciDeviceRecord(const char* pszName)
224 {
225 RTStrCopy(szDevName, sizeof(szDevName), pszName);
226 }
227
228 bool operator<(const PciDeviceRecord &a) const
229 {
230 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) < 0;
231 }
232
233 bool operator==(const PciDeviceRecord &a) const
234 {
235 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
236 }
237 };
238
239 typedef std::map <PciBusAddress,PciDeviceRecord > PciMap;
240 typedef std::vector<PciBusAddress> PciAddrList;
241 typedef std::vector<const DeviceAssignmentRule*> PciRulesList;
242 typedef std::map <PciDeviceRecord,PciAddrList > ReversePciMap;
243
244 volatile int32_t cRefCnt;
245 ChipsetType_T mChipsetType;
246 PciMap mPciMap;
247 ReversePciMap mReversePciMap;
248
249 State()
250 : cRefCnt(1), mChipsetType(ChipsetType_Null)
251 {}
252 ~State()
253 {}
254
255 HRESULT init(ChipsetType_T chipsetType);
256
257 HRESULT record(const char* pszName, PciBusAddress& Address);
258 HRESULT autoAssign(const char* pszName, PciBusAddress& Address);
259 bool checkAvailable(PciBusAddress& Address);
260 bool findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address);
261
262 const char* findAlias(const char* pszName);
263 void addMatchingRules(const char* pszName, PciRulesList& aList);
264 void listAttachedPciDevices(ComSafeArrayOut(IPciDeviceAttachment*, aAttached));
265};
266
267HRESULT BusAssignmentManager::State::init(ChipsetType_T chipsetType)
268{
269 mChipsetType = chipsetType;
270 return S_OK;
271}
272
273HRESULT BusAssignmentManager::State::record(const char* pszName, PciBusAddress& Address)
274{
275 PciDeviceRecord devRec(pszName);
276
277 /* Remember address -> device mapping */
278 mPciMap.insert(PciMap::value_type(Address, devRec));
279
280 ReversePciMap::iterator it = mReversePciMap.find(devRec);
281 if (it == mReversePciMap.end())
282 {
283 mReversePciMap.insert(ReversePciMap::value_type(devRec, PciAddrList()));
284 it = mReversePciMap.find(devRec);
285 }
286
287 /* Remember device name -> addresses mapping */
288 it->second.push_back(Address);
289
290 return S_OK;
291}
292
293bool BusAssignmentManager::State::findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address)
294{
295 PciDeviceRecord devRec(pszDevName);
296
297 ReversePciMap::iterator it = mReversePciMap.find(devRec);
298 if (it == mReversePciMap.end())
299 return false;
300
301 if (iInstance >= (int)it->second.size())
302 return false;
303
304 Address = it->second[iInstance];
305 return true;
306}
307
308void BusAssignmentManager::State::addMatchingRules(const char* pszName, PciRulesList& aList)
309{
310 size_t iRuleset, iRule;
311 const DeviceAssignmentRule* aArrays[2] = {aGenericRules, NULL};
312
313 switch (mChipsetType)
314 {
315 case ChipsetType_PIIX3:
316 aArrays[1] = aPiix3Rules;
317 break;
318 case ChipsetType_ICH9:
319 aArrays[1] = aIch9Rules;
320 break;
321 default:
322 Assert(false);
323 break;
324 }
325
326 for (iRuleset = 0; iRuleset < RT_ELEMENTS(aArrays); iRuleset++)
327 {
328 if (aArrays[iRuleset] == NULL)
329 continue;
330
331 for (iRule = 0; aArrays[iRuleset][iRule].pszName != NULL; iRule++)
332 {
333 if (RTStrCmp(pszName, aArrays[iRuleset][iRule].pszName) == 0)
334 aList.push_back(&aArrays[iRuleset][iRule]);
335 }
336 }
337}
338
339const char* BusAssignmentManager::State::findAlias(const char* pszDev)
340{
341 for (size_t iAlias = 0; iAlias < RT_ELEMENTS(aDeviceAliases); iAlias++)
342 {
343 if (strcmp(pszDev, aDeviceAliases[iAlias].pszDevName) == 0)
344 return aDeviceAliases[iAlias].pszDevAlias;
345 }
346 return NULL;
347}
348
349static bool RuleComparator(const DeviceAssignmentRule* r1, const DeviceAssignmentRule* r2)
350{
351 return (r1->iPriority > r2->iPriority);
352}
353
354HRESULT BusAssignmentManager::State::autoAssign(const char* pszName, PciBusAddress& Address)
355{
356 PciRulesList matchingRules;
357
358 addMatchingRules(pszName, matchingRules);
359 const char* pszAlias = findAlias(pszName);
360 if (pszAlias)
361 addMatchingRules(pszAlias, matchingRules);
362
363 AssertMsg(matchingRules.size() > 0, ("No rule for %s(%s)\n", pszName, pszAlias));
364
365 stable_sort(matchingRules.begin(), matchingRules.end(), RuleComparator);
366
367 for (size_t iRule = 0; iRule < matchingRules.size(); iRule++)
368 {
369 const DeviceAssignmentRule* rule = matchingRules[iRule];
370
371 Address.iBus = rule->iBus;
372 Address.iDevice = rule->iDevice;
373 Address.iFn = rule->iFn;
374
375 if (checkAvailable(Address))
376 return S_OK;
377 }
378 AssertMsg(false, ("All possible candidate positions for %s exhausted\n", pszName));
379
380 return E_INVALIDARG;
381}
382
383bool BusAssignmentManager::State::checkAvailable(PciBusAddress& Address)
384{
385 PciMap::const_iterator it = mPciMap.find(Address);
386
387 return (it == mPciMap.end());
388}
389
390
391void BusAssignmentManager::State::listAttachedPciDevices(ComSafeArrayOut(IPciDeviceAttachment*, aAttached))
392{
393 com::SafeIfaceArray<IPciDeviceAttachment> result(mPciMap.size());
394
395 size_t iIndex = 0;
396 ComObjPtr<PciDeviceAttachment> dev;
397 for (PciMap::const_iterator it = mPciMap.begin(); it != mPciMap.end(); ++it)
398 {
399 dev.createObject();
400 com::Bstr devname(it->second.szDevName);
401 dev->init(NULL, devname, -1, it->first.asLong(), FALSE);
402 result.setElement(iIndex++, dev);
403 }
404
405 result.detachTo(ComSafeArrayOutArg(aAttached));
406}
407
408BusAssignmentManager::BusAssignmentManager()
409 : pState(NULL)
410{
411 pState = new State();
412 Assert(pState);
413}
414
415BusAssignmentManager::~BusAssignmentManager()
416{
417 if (pState)
418 {
419 delete pState;
420 pState = NULL;
421 }
422}
423
424BusAssignmentManager* BusAssignmentManager::createInstance(ChipsetType_T chipsetType)
425{
426 BusAssignmentManager* pInstance = new BusAssignmentManager();
427 pInstance->pState->init(chipsetType);
428 Assert(pInstance);
429 return pInstance;
430}
431
432void BusAssignmentManager::AddRef()
433{
434 ASMAtomicIncS32(&pState->cRefCnt);
435}
436void BusAssignmentManager::Release()
437{
438 if (ASMAtomicDecS32(&pState->cRefCnt) == 0)
439 delete this;
440}
441
442DECLINLINE(HRESULT) InsertConfigInteger(PCFGMNODE pCfg, const char* pszName, uint64_t u64)
443{
444 int vrc = CFGMR3InsertInteger(pCfg, pszName, u64);
445 if (RT_FAILURE(vrc))
446 return E_INVALIDARG;
447
448 return S_OK;
449}
450
451HRESULT BusAssignmentManager::assignPciDevice(const char* pszDevName, PCFGMNODE pCfg,
452 PciBusAddress& Address, bool fAddressRequired)
453{
454 HRESULT rc = S_OK;
455
456 if (!Address.valid())
457 rc = pState->autoAssign(pszDevName, Address);
458 else
459 {
460 bool fAvailable = pState->checkAvailable(Address);
461
462 if (!fAvailable)
463 {
464 if (fAddressRequired)
465 rc = E_ACCESSDENIED;
466 else
467 rc = pState->autoAssign(pszDevName, Address);
468 }
469 }
470
471 if (FAILED(rc))
472 return rc;
473
474 Assert(Address.valid() && pState->checkAvailable(Address));
475
476 rc = pState->record(pszDevName, Address);
477 if (FAILED(rc))
478 return rc;
479
480 rc = InsertConfigInteger(pCfg, "PCIBusNo", Address.iBus);
481 if (FAILED(rc))
482 return rc;
483 rc = InsertConfigInteger(pCfg, "PCIDeviceNo", Address.iDevice);
484 if (FAILED(rc))
485 return rc;
486 rc = InsertConfigInteger(pCfg, "PCIFunctionNo", Address.iFn);
487 if (FAILED(rc))
488 return rc;
489
490 return S_OK;
491}
492
493
494bool BusAssignmentManager::findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address)
495{
496 return pState->findPciAddress(pszDevName, iInstance, Address);
497}
498
499void BusAssignmentManager::listAttachedPciDevices(ComSafeArrayOut(IPciDeviceAttachment*, aAttached))
500{
501 pState->listAttachedPciDevices(ComSafeArrayOutArg(aAttached));
502}
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