1 | /* $Id: BusAssignmentManager.cpp 33690 2010-11-02 14:02:19Z 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 |
|
---|
28 | struct BusAssignmentManager::State
|
---|
29 | {
|
---|
30 | struct PciDeviceRecord
|
---|
31 | {
|
---|
32 | char szDevName[16];
|
---|
33 |
|
---|
34 | PciDeviceRecord(const char* pszName)
|
---|
35 | {
|
---|
36 | ::strncpy(szDevName, pszName, sizeof(szDevName));
|
---|
37 | }
|
---|
38 |
|
---|
39 | bool operator<(const PciDeviceRecord &a) const
|
---|
40 | {
|
---|
41 | return ::strcmp(szDevName, a.szDevName) < 0;
|
---|
42 | }
|
---|
43 |
|
---|
44 | bool operator==(const PciDeviceRecord &a) const
|
---|
45 | {
|
---|
46 | return ::strcmp(szDevName, a.szDevName) == 0;
|
---|
47 | }
|
---|
48 | };
|
---|
49 |
|
---|
50 | typedef std::map <PciBusAddress,PciDeviceRecord > PciMap;
|
---|
51 | typedef std::vector<PciBusAddress> PciAddrList;
|
---|
52 | typedef std::map <PciDeviceRecord,PciAddrList > ReversePciMap;
|
---|
53 |
|
---|
54 | volatile int32_t cRefCnt;
|
---|
55 | ChipsetType_T mChipsetType;
|
---|
56 | PciMap mPciMap;
|
---|
57 | ReversePciMap mReversePciMap;
|
---|
58 |
|
---|
59 | State()
|
---|
60 | : cRefCnt(1), mChipsetType(ChipsetType_Null)
|
---|
61 | {}
|
---|
62 | ~State()
|
---|
63 | {}
|
---|
64 |
|
---|
65 | HRESULT init(ChipsetType_T chipsetType);
|
---|
66 |
|
---|
67 | HRESULT record(const char* pszName, PciBusAddress& Address);
|
---|
68 | HRESULT autoAssign(const char* pszName, PciBusAddress& Address);
|
---|
69 | bool checkAvailable(PciBusAddress& Address);
|
---|
70 | bool findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address);
|
---|
71 | };
|
---|
72 |
|
---|
73 | HRESULT BusAssignmentManager::State::init(ChipsetType_T chipsetType)
|
---|
74 | {
|
---|
75 | mChipsetType = chipsetType;
|
---|
76 | return S_OK;
|
---|
77 | }
|
---|
78 |
|
---|
79 |
|
---|
80 | HRESULT BusAssignmentManager::State::record(const char* pszName, PciBusAddress& Address)
|
---|
81 | {
|
---|
82 | PciDeviceRecord devRec(pszName);
|
---|
83 |
|
---|
84 | /* Remember address -> device mapping */
|
---|
85 | mPciMap.insert(PciMap::value_type(Address, devRec));
|
---|
86 |
|
---|
87 | ReversePciMap::iterator it = mReversePciMap.find(devRec);
|
---|
88 | if (it == mReversePciMap.end())
|
---|
89 | {
|
---|
90 | mReversePciMap.insert(ReversePciMap::value_type(devRec, PciAddrList()));
|
---|
91 | it = mReversePciMap.find(devRec);
|
---|
92 | }
|
---|
93 |
|
---|
94 | /* Remember device name -> addresses mapping */
|
---|
95 | it->second.push_back(Address);
|
---|
96 |
|
---|
97 | return S_OK;
|
---|
98 | }
|
---|
99 |
|
---|
100 | bool BusAssignmentManager::State::findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address)
|
---|
101 | {
|
---|
102 | PciDeviceRecord devRec(pszDevName);
|
---|
103 |
|
---|
104 | ReversePciMap::iterator it = mReversePciMap.find(devRec);
|
---|
105 | if (it == mReversePciMap.end())
|
---|
106 | return false;
|
---|
107 |
|
---|
108 | if (iInstance >= (int)it->second.size())
|
---|
109 | return false;
|
---|
110 |
|
---|
111 | Address = it->second[iInstance];
|
---|
112 | return true;
|
---|
113 | }
|
---|
114 |
|
---|
115 | HRESULT BusAssignmentManager::State::autoAssign(const char* pszName, PciBusAddress& Address)
|
---|
116 | {
|
---|
117 | // unimplemented yet
|
---|
118 | Assert(false);
|
---|
119 | return S_OK;
|
---|
120 | }
|
---|
121 |
|
---|
122 | bool BusAssignmentManager::State::checkAvailable(PciBusAddress& Address)
|
---|
123 | {
|
---|
124 | PciMap::const_iterator it = mPciMap.find(Address);
|
---|
125 |
|
---|
126 | return (it == mPciMap.end());
|
---|
127 | }
|
---|
128 |
|
---|
129 | BusAssignmentManager::BusAssignmentManager()
|
---|
130 | : pState(NULL)
|
---|
131 | {
|
---|
132 | pState = new State();
|
---|
133 | Assert(pState);
|
---|
134 | }
|
---|
135 |
|
---|
136 | BusAssignmentManager::~BusAssignmentManager()
|
---|
137 | {
|
---|
138 | if (pState)
|
---|
139 | {
|
---|
140 | delete pState;
|
---|
141 | pState = NULL;
|
---|
142 | }
|
---|
143 | }
|
---|
144 |
|
---|
145 |
|
---|
146 | BusAssignmentManager* BusAssignmentManager::pInstance = NULL;
|
---|
147 |
|
---|
148 | BusAssignmentManager* BusAssignmentManager::getInstance(ChipsetType_T chipsetType)
|
---|
149 | {
|
---|
150 | if (pInstance == NULL)
|
---|
151 | {
|
---|
152 | pInstance = new BusAssignmentManager();
|
---|
153 | pInstance->pState->init(chipsetType);
|
---|
154 | Assert(pInstance);
|
---|
155 | return pInstance;
|
---|
156 | }
|
---|
157 |
|
---|
158 | pInstance->AddRef();
|
---|
159 | return pInstance;
|
---|
160 | }
|
---|
161 |
|
---|
162 | void BusAssignmentManager::AddRef()
|
---|
163 | {
|
---|
164 | ASMAtomicIncS32(&pState->cRefCnt);
|
---|
165 | }
|
---|
166 | void BusAssignmentManager::Release()
|
---|
167 | {
|
---|
168 | if (ASMAtomicDecS32(&pState->cRefCnt) == 1)
|
---|
169 | delete this;
|
---|
170 | }
|
---|
171 |
|
---|
172 | DECLINLINE(HRESULT) InsertConfigInteger(PCFGMNODE pCfg, const char* pszName, uint64_t u64)
|
---|
173 | {
|
---|
174 | int vrc = CFGMR3InsertInteger(pCfg, pszName, u64);
|
---|
175 | if (RT_FAILURE(vrc))
|
---|
176 | return E_INVALIDARG;
|
---|
177 |
|
---|
178 | return S_OK;
|
---|
179 | }
|
---|
180 |
|
---|
181 | HRESULT BusAssignmentManager::assignPciDevice(const char* pszDevName, PCFGMNODE pCfg,
|
---|
182 | PciBusAddress& Address, bool fAddressRequired)
|
---|
183 | {
|
---|
184 | HRESULT rc = S_OK;
|
---|
185 |
|
---|
186 | if (!Address.valid())
|
---|
187 | rc = pState->autoAssign(pszDevName, Address);
|
---|
188 | else
|
---|
189 | {
|
---|
190 | bool fAvailable = pState->checkAvailable(Address);
|
---|
191 |
|
---|
192 | if (!fAvailable)
|
---|
193 | {
|
---|
194 | if (fAddressRequired)
|
---|
195 | return E_ACCESSDENIED;
|
---|
196 | else
|
---|
197 | rc = pState->autoAssign(pszDevName, Address);
|
---|
198 | }
|
---|
199 | }
|
---|
200 |
|
---|
201 | if (FAILED(rc))
|
---|
202 | return rc;
|
---|
203 |
|
---|
204 | Assert(Address.valid());
|
---|
205 |
|
---|
206 | rc = pState->record(pszDevName, Address);
|
---|
207 | if (FAILED(rc))
|
---|
208 | return rc;
|
---|
209 |
|
---|
210 | rc = InsertConfigInteger(pCfg, "PCIBusNo", Address.iBus);
|
---|
211 | if (FAILED(rc))
|
---|
212 | return rc;
|
---|
213 | rc = InsertConfigInteger(pCfg, "PCIDeviceNo", Address.iDevice);
|
---|
214 | if (FAILED(rc))
|
---|
215 | return rc;
|
---|
216 | rc = InsertConfigInteger(pCfg, "PCIFunctionNo", Address.iFn);
|
---|
217 | if (FAILED(rc))
|
---|
218 | return rc;
|
---|
219 |
|
---|
220 | return S_OK;
|
---|
221 | }
|
---|
222 |
|
---|
223 |
|
---|
224 | bool BusAssignmentManager::findPciAddress(const char* pszDevName, int iInstance, PciBusAddress& Address)
|
---|
225 | {
|
---|
226 | return pState->findPciAddress(pszDevName, iInstance, Address);
|
---|
227 | }
|
---|