1
/* $Id: BusAssignmentManager.cpp 35368 2010-12-30 13:38:23Z vboxsync $ */
5
* VirtualBox bus slots assignment manager
9
* Copyright (C) 2010 Oracle Corporation
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.
19
#include "BusAssignmentManager.h"
22
#include <iprt/string.h>
24
#include <VBox/vmm/cfgm.h>
25
#include <VBox/com/array.h>
28
#include "PciDeviceAttachmentImpl.h"
34
struct DeviceAssignmentRule
43
struct DeviceAliasRule
45
const char* pszDevName;
46
const char* pszDevAlias;
49
/* Those rules define PCI slots assignment */
51
/* Device Bus Device Function Priority */
54
static const DeviceAssignmentRule aGenericRules[] =
60
{"VMMDev", 0, 4, 0, 0},
62
/* Audio controllers */
63
{"ichac97", 0, 5, 0, 0},
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},
73
{"usb-ohci", 0, 6, 0, 0},
74
{"usb-ehci", 0, 11, 0, 0},
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. */
90
/* VMWare assigns first NIC to slot 11 */
91
{"nic-vmware", 0, 11, 0, 1},
93
/* ISA/LPC controller */
96
{ NULL, -1, -1, -1, 0}
99
/* PIIX3 chipset rules */
100
static const DeviceAssignmentRule aPiix3Rules[] =
102
{"piix3ide", 0, 1, 1, 0},
103
{"pcibridge", 0, 24, 0, 0},
104
{"pcibridge", 0, 25, 0, 0},
105
{ NULL, -1, -1, -1, 0}
109
/* ICH9 chipset rules */
110
static const DeviceAssignmentRule aIch9Rules[] =
112
/* Host Controller */
113
{"i82801", 0, 30, 0, 0},
115
/* Those are functions of LPC at 00:1e:00 */
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.
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},
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},
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},
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},
202
{ NULL, -1, -1, -1, 0}
206
static const DeviceAliasRule aDeviceAliases[] =
210
{"virtio-net", "nic"},
212
{"lsilogic", "storage"},
213
{"buslogic", "storage"},
214
{"lsilogicsas", "storage"}
217
struct BusAssignmentManager::State
219
struct PciDeviceRecord
223
PciDeviceRecord(const char* pszName)
225
RTStrCopy(szDevName, sizeof(szDevName), pszName);
228
bool operator<(const PciDeviceRecord &a) const
230
return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) < 0;
233
bool operator==(const PciDeviceRecord &a) const
235
return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
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;
244
volatile int32_t cRefCnt;
245
ChipsetType_T mChipsetType;
247
ReversePciMap mReversePciMap;
250
: cRefCnt(1), mChipsetType(ChipsetType_Null)
255
HRESULT init(ChipsetType_T chipsetType);
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);
262
const char* findAlias(const char* pszName);
263
void addMatchingRules(const char* pszName, PciRulesList& aList);
264
void listAttachedPciDevices(ComSafeArrayOut(IPciDeviceAttachment*, aAttached));
267
HRESULT BusAssignmentManager::State::init(ChipsetType_T chipsetType)
269
mChipsetType = chipsetType;
273
HRESULT BusAssignmentManager::State::record(const char* pszName, PciBusAddress& Address)
275
PciDeviceRecord devRec(pszName);
277
/* Remember address -> device mapping */
278
mPciMap.insert(PciMap::value_type(Address, devRec));
280
ReversePciMap::iterator it = mReversePciMap.find(devRec);
281
if (it == mReversePciMap.end())
283
mReversePciMap.insert(ReversePciMap::value_type(devRec, PciAddrList()));
284
it = mReversePciMap.find(devRec);
287
/* Remember device name -> addresses mapping */
288
it->second.push_back(Address);
293
bool BusAssignmentManager::State::findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address)
295
PciDeviceRecord devRec(pszDevName);
297
ReversePciMap::iterator it = mReversePciMap.find(devRec);
298
if (it == mReversePciMap.end())
301
if (iInstance >= (int)it->second.size())
304
Address = it->second[iInstance];
308
void BusAssignmentManager::State::addMatchingRules(const char* pszName, PciRulesList& aList)
310
size_t iRuleset, iRule;
311
const DeviceAssignmentRule* aArrays[2] = {aGenericRules, NULL};
313
switch (mChipsetType)
315
case ChipsetType_PIIX3:
316
aArrays[1] = aPiix3Rules;
318
case ChipsetType_ICH9:
319
aArrays[1] = aIch9Rules;
326
for (iRuleset = 0; iRuleset < RT_ELEMENTS(aArrays); iRuleset++)
328
if (aArrays[iRuleset] == NULL)
331
for (iRule = 0; aArrays[iRuleset][iRule].pszName != NULL; iRule++)
333
if (RTStrCmp(pszName, aArrays[iRuleset][iRule].pszName) == 0)
334
aList.push_back(&aArrays[iRuleset][iRule]);
339
const char* BusAssignmentManager::State::findAlias(const char* pszDev)
341
for (size_t iAlias = 0; iAlias < RT_ELEMENTS(aDeviceAliases); iAlias++)
343
if (strcmp(pszDev, aDeviceAliases[iAlias].pszDevName) == 0)
344
return aDeviceAliases[iAlias].pszDevAlias;
349
static bool RuleComparator(const DeviceAssignmentRule* r1, const DeviceAssignmentRule* r2)
351
return (r1->iPriority > r2->iPriority);
354
HRESULT BusAssignmentManager::State::autoAssign(const char* pszName, PciBusAddress& Address)
356
PciRulesList matchingRules;
358
addMatchingRules(pszName, matchingRules);
359
const char* pszAlias = findAlias(pszName);
361
addMatchingRules(pszAlias, matchingRules);
363
AssertMsg(matchingRules.size() > 0, ("No rule for %s(%s)\n", pszName, pszAlias));
365
stable_sort(matchingRules.begin(), matchingRules.end(), RuleComparator);
367
for (size_t iRule = 0; iRule < matchingRules.size(); iRule++)
369
const DeviceAssignmentRule* rule = matchingRules[iRule];
371
Address.iBus = rule->iBus;
372
Address.iDevice = rule->iDevice;
373
Address.iFn = rule->iFn;
375
if (checkAvailable(Address))
378
AssertMsg(false, ("All possible candidate positions for %s exhausted\n", pszName));
383
bool BusAssignmentManager::State::checkAvailable(PciBusAddress& Address)
385
PciMap::const_iterator it = mPciMap.find(Address);
387
return (it == mPciMap.end());
391
void BusAssignmentManager::State::listAttachedPciDevices(ComSafeArrayOut(IPciDeviceAttachment*, aAttached))
393
com::SafeIfaceArray<IPciDeviceAttachment> result(mPciMap.size());
396
ComObjPtr<PciDeviceAttachment> dev;
397
for (PciMap::const_iterator it = mPciMap.begin(); it != mPciMap.end(); ++it)
400
com::Bstr devname(it->second.szDevName);
401
dev->init(NULL, devname, -1, it->first.asLong(), FALSE);
402
result.setElement(iIndex++, dev);
405
result.detachTo(ComSafeArrayOutArg(aAttached));
408
BusAssignmentManager::BusAssignmentManager()
411
pState = new State();
415
BusAssignmentManager::~BusAssignmentManager()
424
BusAssignmentManager* BusAssignmentManager::createInstance(ChipsetType_T chipsetType)
426
BusAssignmentManager* pInstance = new BusAssignmentManager();
427
pInstance->pState->init(chipsetType);
432
void BusAssignmentManager::AddRef()
434
ASMAtomicIncS32(&pState->cRefCnt);
436
void BusAssignmentManager::Release()
438
if (ASMAtomicDecS32(&pState->cRefCnt) == 0)
442
DECLINLINE(HRESULT) InsertConfigInteger(PCFGMNODE pCfg, const char* pszName, uint64_t u64)
444
int vrc = CFGMR3InsertInteger(pCfg, pszName, u64);
451
HRESULT BusAssignmentManager::assignPciDevice(const char* pszDevName, PCFGMNODE pCfg,
452
PciBusAddress& Address, bool fAddressRequired)
456
if (!Address.valid())
457
rc = pState->autoAssign(pszDevName, Address);
460
bool fAvailable = pState->checkAvailable(Address);
464
if (fAddressRequired)
467
rc = pState->autoAssign(pszDevName, Address);
474
Assert(Address.valid() && pState->checkAvailable(Address));
476
rc = pState->record(pszDevName, Address);
480
rc = InsertConfigInteger(pCfg, "PCIBusNo", Address.iBus);
483
rc = InsertConfigInteger(pCfg, "PCIDeviceNo", Address.iDevice);
486
rc = InsertConfigInteger(pCfg, "PCIFunctionNo", Address.iFn);
494
bool BusAssignmentManager::findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address)
496
return pState->findPciAddress(pszDevName, iInstance, Address);
499
void BusAssignmentManager::listAttachedPciDevices(ComSafeArrayOut(IPciDeviceAttachment*, aAttached))
501
pState->listAttachedPciDevices(ComSafeArrayOutArg(aAttached));