VirtualBox

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

Last change on this file since 63165 was 61009, checked in by vboxsync, 9 years ago

Main: big settings cleanup and writing optimization. Moved constructors/equality/default checks into the .cpp file, and write only settings which aren't at the default value. Greatly reduces the effort needed to write everything out, especially when a lot of snapshots have to be dealt with. Move the storage controllers to the hardware settings, where they always belonged. No change to the XML file (yet). Lots of settings related cleanups in the API code.

  • 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 61009 2016-05-17 17:18:29Z 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 {"nvme", 1, 32, 0, 0},
170 {"nvme", 1, 33, 0, 0},
171 {"nvme", 1, 34, 0, 0},
172 {"nvme", 1, 35, 0, 0},
173 {"nvme", 1, 36, 0, 0},
174 {"nvme", 1, 37, 0, 0},
175 {"nvme", 1, 38, 0, 0},
176
177 /* NICs */
178 {"nic", 2, 0, 0, 0},
179 {"nic", 2, 1, 0, 0},
180 {"nic", 2, 2, 0, 0},
181 {"nic", 2, 3, 0, 0},
182 {"nic", 2, 4, 0, 0},
183 {"nic", 2, 5, 0, 0},
184 {"nic", 2, 6, 0, 0},
185 {"nic", 2, 7, 0, 0},
186 {"nic", 2, 8, 0, 0},
187 {"nic", 2, 9, 0, 0},
188 {"nic", 2, 10, 0, 0},
189 {"nic", 2, 11, 0, 0},
190 {"nic", 2, 12, 0, 0},
191 {"nic", 2, 13, 0, 0},
192 {"nic", 2, 14, 0, 0},
193 {"nic", 2, 15, 0, 0},
194 {"nic", 2, 16, 0, 0},
195 {"nic", 2, 17, 0, 0},
196 {"nic", 2, 18, 0, 0},
197 {"nic", 2, 19, 0, 0},
198 {"nic", 2, 20, 0, 0},
199 {"nic", 2, 21, 0, 0},
200 {"nic", 2, 26, 0, 0},
201 {"nic", 2, 27, 0, 0},
202 {"nic", 2, 28, 0, 0},
203 {"nic", 2, 29, 0, 0},
204 {"nic", 2, 30, 0, 0},
205 {"nic", 2, 31, 0, 0},
206
207 { NULL, -1, -1, -1, 0}
208};
209
210/* Aliasing rules */
211static const DeviceAliasRule aDeviceAliases[] =
212{
213 {"e1000", "nic"},
214 {"pcnet", "nic"},
215 {"virtio-net", "nic"},
216 {"ahci", "storage"},
217 {"lsilogic", "storage"},
218 {"buslogic", "storage"},
219 {"lsilogicsas", "storage"},
220 {"nvme", "storage"}
221};
222
223struct BusAssignmentManager::State
224{
225 struct PCIDeviceRecord
226 {
227 char szDevName[32];
228 PCIBusAddress HostAddress;
229
230 PCIDeviceRecord(const char* pszName, PCIBusAddress aHostAddress)
231 {
232 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
233 this->HostAddress = aHostAddress;
234 }
235
236 PCIDeviceRecord(const char* pszName)
237 {
238 RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
239 }
240
241 bool operator<(const PCIDeviceRecord &a) const
242 {
243 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) < 0;
244 }
245
246 bool operator==(const PCIDeviceRecord &a) const
247 {
248 return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
249 }
250 };
251
252 typedef std::map<PCIBusAddress,PCIDeviceRecord> PCIMap;
253 typedef std::vector<PCIBusAddress> PCIAddrList;
254 typedef std::vector<const DeviceAssignmentRule *> PCIRulesList;
255 typedef std::map<PCIDeviceRecord,PCIAddrList> ReversePCIMap;
256
257 volatile int32_t cRefCnt;
258 ChipsetType_T mChipsetType;
259 PCIMap mPCIMap;
260 ReversePCIMap mReversePCIMap;
261
262 State()
263 : cRefCnt(1), mChipsetType(ChipsetType_Null)
264 {}
265 ~State()
266 {}
267
268 HRESULT init(ChipsetType_T chipsetType);
269
270 HRESULT record(const char* pszName, PCIBusAddress& GuestAddress, PCIBusAddress HostAddress);
271 HRESULT autoAssign(const char* pszName, PCIBusAddress& Address);
272 bool checkAvailable(PCIBusAddress& Address);
273 bool findPCIAddress(const char* pszDevName, int iInstance, PCIBusAddress& Address);
274
275 const char* findAlias(const char* pszName);
276 void addMatchingRules(const char* pszName, PCIRulesList& aList);
277 void listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached);
278};
279
280HRESULT BusAssignmentManager::State::init(ChipsetType_T chipsetType)
281{
282 mChipsetType = chipsetType;
283 return S_OK;
284}
285
286HRESULT BusAssignmentManager::State::record(const char* pszName, PCIBusAddress& Address, PCIBusAddress HostAddress)
287{
288 PCIDeviceRecord devRec(pszName, HostAddress);
289
290 /* Remember address -> device mapping */
291 mPCIMap.insert(PCIMap::value_type(Address, devRec));
292
293 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
294 if (it == mReversePCIMap.end())
295 {
296 mReversePCIMap.insert(ReversePCIMap::value_type(devRec, PCIAddrList()));
297 it = mReversePCIMap.find(devRec);
298 }
299
300 /* Remember device name -> addresses mapping */
301 it->second.push_back(Address);
302
303 return S_OK;
304}
305
306bool BusAssignmentManager::State::findPCIAddress(const char* pszDevName, int iInstance, PCIBusAddress& Address)
307{
308 PCIDeviceRecord devRec(pszDevName);
309
310 ReversePCIMap::iterator it = mReversePCIMap.find(devRec);
311 if (it == mReversePCIMap.end())
312 return false;
313
314 if (iInstance >= (int)it->second.size())
315 return false;
316
317 Address = it->second[iInstance];
318 return true;
319}
320
321void BusAssignmentManager::State::addMatchingRules(const char* pszName, PCIRulesList& aList)
322{
323 size_t iRuleset, iRule;
324 const DeviceAssignmentRule* aArrays[2] = {aGenericRules, NULL};
325
326 switch (mChipsetType)
327 {
328 case ChipsetType_PIIX3:
329 aArrays[1] = aPiix3Rules;
330 break;
331 case ChipsetType_ICH9:
332 aArrays[1] = aIch9Rules;
333 break;
334 default:
335 Assert(false);
336 break;
337 }
338
339 for (iRuleset = 0; iRuleset < RT_ELEMENTS(aArrays); iRuleset++)
340 {
341 if (aArrays[iRuleset] == NULL)
342 continue;
343
344 for (iRule = 0; aArrays[iRuleset][iRule].pszName != NULL; iRule++)
345 {
346 if (RTStrCmp(pszName, aArrays[iRuleset][iRule].pszName) == 0)
347 aList.push_back(&aArrays[iRuleset][iRule]);
348 }
349 }
350}
351
352const char* BusAssignmentManager::State::findAlias(const char* pszDev)
353{
354 for (size_t iAlias = 0; iAlias < RT_ELEMENTS(aDeviceAliases); iAlias++)
355 {
356 if (strcmp(pszDev, aDeviceAliases[iAlias].pszDevName) == 0)
357 return aDeviceAliases[iAlias].pszDevAlias;
358 }
359 return NULL;
360}
361
362static bool RuleComparator(const DeviceAssignmentRule* r1, const DeviceAssignmentRule* r2)
363{
364 return (r1->iPriority > r2->iPriority);
365}
366
367HRESULT BusAssignmentManager::State::autoAssign(const char* pszName, PCIBusAddress& Address)
368{
369 PCIRulesList matchingRules;
370
371 addMatchingRules(pszName, matchingRules);
372 const char* pszAlias = findAlias(pszName);
373 if (pszAlias)
374 addMatchingRules(pszAlias, matchingRules);
375
376 AssertMsg(matchingRules.size() > 0, ("No rule for %s(%s)\n", pszName, pszAlias));
377
378 stable_sort(matchingRules.begin(), matchingRules.end(), RuleComparator);
379
380 for (size_t iRule = 0; iRule < matchingRules.size(); iRule++)
381 {
382 const DeviceAssignmentRule* rule = matchingRules[iRule];
383
384 Address.miBus = rule->iBus;
385 Address.miDevice = rule->iDevice;
386 Address.miFn = rule->iFn;
387
388 if (checkAvailable(Address))
389 return S_OK;
390 }
391 AssertMsgFailed(("All possible candidate positions for %s exhausted\n", pszName));
392
393 return E_INVALIDARG;
394}
395
396bool BusAssignmentManager::State::checkAvailable(PCIBusAddress& Address)
397{
398 PCIMap::const_iterator it = mPCIMap.find(Address);
399
400 return (it == mPCIMap.end());
401}
402
403void BusAssignmentManager::State::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
404{
405 aAttached.resize(mPCIMap.size());
406
407 size_t i = 0;
408 PCIDeviceInfo dev;
409 for (PCIMap::const_iterator it = mPCIMap.begin(); it != mPCIMap.end(); ++it, ++i)
410 {
411 dev.strDeviceName = it->second.szDevName;
412 dev.guestAddress = it->first;
413 dev.hostAddress = it->second.HostAddress;
414 aAttached[i] = dev;
415 }
416}
417
418BusAssignmentManager::BusAssignmentManager()
419 : pState(NULL)
420{
421 pState = new State();
422 Assert(pState);
423}
424
425BusAssignmentManager::~BusAssignmentManager()
426{
427 if (pState)
428 {
429 delete pState;
430 pState = NULL;
431 }
432}
433
434BusAssignmentManager* BusAssignmentManager::createInstance(ChipsetType_T chipsetType)
435{
436 BusAssignmentManager* pInstance = new BusAssignmentManager();
437 pInstance->pState->init(chipsetType);
438 Assert(pInstance);
439 return pInstance;
440}
441
442void BusAssignmentManager::AddRef()
443{
444 ASMAtomicIncS32(&pState->cRefCnt);
445}
446void BusAssignmentManager::Release()
447{
448 if (ASMAtomicDecS32(&pState->cRefCnt) == 0)
449 delete this;
450}
451
452DECLINLINE(HRESULT) InsertConfigInteger(PCFGMNODE pCfg, const char* pszName, uint64_t u64)
453{
454 int vrc = CFGMR3InsertInteger(pCfg, pszName, u64);
455 if (RT_FAILURE(vrc))
456 return E_INVALIDARG;
457
458 return S_OK;
459}
460
461HRESULT BusAssignmentManager::assignPCIDeviceImpl(const char* pszDevName,
462 PCFGMNODE pCfg,
463 PCIBusAddress& GuestAddress,
464 PCIBusAddress HostAddress,
465 bool fGuestAddressRequired)
466{
467 HRESULT rc = S_OK;
468
469 if (!GuestAddress.valid())
470 rc = pState->autoAssign(pszDevName, GuestAddress);
471 else
472 {
473 bool fAvailable = pState->checkAvailable(GuestAddress);
474
475 if (!fAvailable)
476 {
477 if (fGuestAddressRequired)
478 rc = E_ACCESSDENIED;
479 else
480 rc = pState->autoAssign(pszDevName, GuestAddress);
481 }
482 }
483
484 if (FAILED(rc))
485 return rc;
486
487 Assert(GuestAddress.valid() && pState->checkAvailable(GuestAddress));
488
489 rc = pState->record(pszDevName, GuestAddress, HostAddress);
490 if (FAILED(rc))
491 return rc;
492
493 rc = InsertConfigInteger(pCfg, "PCIBusNo", GuestAddress.miBus);
494 if (FAILED(rc))
495 return rc;
496 rc = InsertConfigInteger(pCfg, "PCIDeviceNo", GuestAddress.miDevice);
497 if (FAILED(rc))
498 return rc;
499 rc = InsertConfigInteger(pCfg, "PCIFunctionNo", GuestAddress.miFn);
500 if (FAILED(rc))
501 return rc;
502
503 return S_OK;
504}
505
506
507bool BusAssignmentManager::findPCIAddress(const char* pszDevName, int iInstance, PCIBusAddress& Address)
508{
509 return pState->findPCIAddress(pszDevName, iInstance, Address);
510}
511void BusAssignmentManager::listAttachedPCIDevices(std::vector<PCIDeviceInfo> &aAttached)
512{
513 pState->listAttachedPCIDevices(aAttached);
514}
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