~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Main/src-client/BusAssignmentManager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
34
struct DeviceAssignmentRule
 
35
{
 
36
    const char* pszName;
 
37
    int         iBus;
 
38
    int         iDevice;
 
39
    int         iFn;
 
40
    int         iPriority;
 
41
};
 
42
 
 
43
struct 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 */
 
54
static 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 */
 
100
static 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 */
 
110
static 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 */
 
206
static 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
 
 
217
struct 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
 
 
267
HRESULT BusAssignmentManager::State::init(ChipsetType_T chipsetType)
 
268
{
 
269
    mChipsetType = chipsetType;
 
270
    return S_OK;
 
271
}
 
272
 
 
273
HRESULT 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
 
 
293
bool    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
 
 
308
void 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
 
 
339
const 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
 
 
349
static bool  RuleComparator(const DeviceAssignmentRule* r1, const DeviceAssignmentRule* r2)
 
350
{
 
351
    return (r1->iPriority > r2->iPriority);
 
352
}
 
353
 
 
354
HRESULT 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
 
 
383
bool BusAssignmentManager::State::checkAvailable(PciBusAddress& Address)
 
384
{
 
385
    PciMap::const_iterator it = mPciMap.find(Address);
 
386
 
 
387
    return (it == mPciMap.end());
 
388
}
 
389
 
 
390
 
 
391
void 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
 
 
408
BusAssignmentManager::BusAssignmentManager()
 
409
    : pState(NULL)
 
410
{
 
411
    pState = new State();
 
412
    Assert(pState);
 
413
}
 
414
 
 
415
BusAssignmentManager::~BusAssignmentManager()
 
416
{
 
417
    if (pState)
 
418
    {
 
419
        delete pState;
 
420
        pState = NULL;
 
421
    }
 
422
}
 
423
 
 
424
BusAssignmentManager* BusAssignmentManager::createInstance(ChipsetType_T chipsetType)
 
425
{
 
426
    BusAssignmentManager* pInstance = new BusAssignmentManager();
 
427
    pInstance->pState->init(chipsetType);
 
428
    Assert(pInstance);
 
429
    return pInstance;
 
430
}
 
431
 
 
432
void BusAssignmentManager::AddRef()
 
433
{
 
434
    ASMAtomicIncS32(&pState->cRefCnt);
 
435
}
 
436
void BusAssignmentManager::Release()
 
437
{
 
438
    if (ASMAtomicDecS32(&pState->cRefCnt) == 0)
 
439
        delete this;
 
440
}
 
441
 
 
442
DECLINLINE(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
 
 
451
HRESULT 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
 
 
494
bool BusAssignmentManager::findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address)
 
495
{
 
496
    return pState->findPciAddress(pszDevName, iInstance, Address);
 
497
}
 
498
 
 
499
void BusAssignmentManager::listAttachedPciDevices(ComSafeArrayOut(IPciDeviceAttachment*, aAttached))
 
500
{
 
501
    pState->listAttachedPciDevices(ComSafeArrayOutArg(aAttached));
 
502
}