VirtualBox

source: vbox/trunk/src/VBox/Main/BusAssignmentManager.cpp@ 33907

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

Main: more PCI assignment rules

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