VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ResourceAssignmentManager.cpp@ 107462

Last change on this file since 107462 was 107462, checked in by vboxsync, 3 months ago

Main/src-client/ResourceAssignmentManager.cpp: Missing field initialisers, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.9 KB
Line 
1/* $Id: ResourceAssignmentManager.cpp 107462 2025-01-07 11:12:21Z vboxsync $ */
2/** @file
3 * VirtualBox bus slots assignment manager
4 */
5
6/*
7 * Copyright (C) 2010-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_MAIN
33#include "LoggingNew.h"
34
35#include "ResourceAssignmentManager.h"
36
37#include <VBox/com/array.h>
38
39#include <iprt/asm.h>
40#include <iprt/mem.h>
41#include <iprt/string.h>
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47/**
48 * Address space range type.
49 */
50typedef enum RESOURCEREGIONTYPE
51{
52 /** Free region. */
53 kResourceRegionType_Free = 0,
54 /** RAM. */
55 kResourceRegionType_Ram,
56 /** ROM. */
57 kResourceRegionType_Rom,
58 /** MMIO. */
59 kResourceRegionType_Mmio,
60 /** 32bit hack. */
61 kResourceRegionType_32Bit_Hack = 0x7fffffff
62} RESOURCEREGIONTYPE;
63
64
65/**
66 * Address space range descriptor.
67 */
68typedef struct RESOURCEREGION
69{
70 /** Region name. */
71 char szName[32];
72 /** Physical start address of the region. */
73 RTGCPHYS GCPhysStart;
74 /** Physical end address of the region. */
75 RTGCPHYS GCPhysEnd;
76 /** Region type. */
77 RESOURCEREGIONTYPE enmType;
78 /** Padding. */
79 uint32_t u32Pad;
80} RESOURCEREGION;
81AssertCompileSize(RESOURCEREGION, 56);
82/** Pointer to a resource region. */
83typedef RESOURCEREGION *PRESOURCEREGION;
84/** Pointer to a const resource region. */
85typedef const RESOURCEREGION *PCRESOURCEREGION;
86
87
88/*********************************************************************************************************************************
89* Global Variables *
90*********************************************************************************************************************************/
91
92
93/**
94 * Resource assignment manage state data.
95 * @internal
96 */
97struct ResourceAssignmentManager::State
98{
99 ChipsetType_T mChipsetType;
100 IommuType_T mIommuType;
101
102 /** Pointer to the array of regions (sorted by address, not overlapping, adjacent). */
103 PRESOURCEREGION m_paRegions;
104 /** Number of used regions. */
105 uint32_t m_cRegions;
106 /** Number of regions the allocated array can hold. */
107 uint32_t m_cRegionsMax;
108
109 uint32_t mcInterrupts;
110 uint32_t miInterrupt;
111
112 State()
113 : mChipsetType(ChipsetType_Null)
114 , mIommuType(IommuType_None)
115 , m_paRegions(NULL)
116 , m_cRegions(0)
117 , m_cRegionsMax(0)
118 , mcInterrupts(0)
119 , miInterrupt(0)
120 {}
121 ~State()
122 {}
123
124 HRESULT init(ChipsetType_T chipsetType, IommuType_T iommuType, uint32_t cInterrupts);
125
126 HRESULT ensureAdditionalRegions(uint32_t cRegions);
127 void setRegion(PRESOURCEREGION pRegion, const char *pszName, RESOURCEREGIONTYPE enmType,
128 RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
129 HRESULT addAddrRange(const char *pszName, RESOURCEREGIONTYPE enmType, RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
130 HRESULT findNextFreeAddrRange(RTGCPHYS cbRegion, RTGCPHYS cbAlignment, RTGCPHYS GCPhysMin, RTGCPHYS GCPhysMax, RTGCPHYS GCPhysHint,
131 PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion);
132
133 void dumpToReleaseLog(void);
134};
135
136
137HRESULT ResourceAssignmentManager::State::init(ChipsetType_T chipsetType, IommuType_T iommuType,
138 uint32_t cInterrupts)
139{
140 Assert(chipsetType == ChipsetType_ARMv8Virtual);
141 Assert(iommuType == IommuType_None); /* For now no IOMMU support on ARMv8. */
142
143 mChipsetType = chipsetType;
144 mIommuType = iommuType;
145 mcInterrupts = cInterrupts;
146 miInterrupt = 0;
147
148 m_paRegions = (PRESOURCEREGION)RTMemRealloc(m_paRegions, 32 * sizeof(*m_paRegions));
149 if (!m_paRegions)
150 return E_OUTOFMEMORY;
151
152 m_paRegions[m_cRegions].enmType = kResourceRegionType_Free;
153 m_paRegions[m_cRegions].GCPhysStart = 0;
154 m_paRegions[m_cRegions].GCPhysEnd = UINT64_MAX;
155 strcpy(&m_paRegions[m_cRegions].szName[0], "Free");
156 m_cRegions++;
157
158 return S_OK;
159}
160
161
162HRESULT ResourceAssignmentManager::State::ensureAdditionalRegions(uint32_t cRegions)
163{
164 if (m_cRegions + cRegions == m_cRegionsMax)
165 {
166 uint32_t const cRegionsNew = m_cRegionsMax + 32;
167 PRESOURCEREGION paDescsNew = (PRESOURCEREGION)RTMemRealloc(m_paRegions, cRegionsNew * sizeof(*paDescsNew));
168 if (!paDescsNew)
169 return E_OUTOFMEMORY;
170
171 m_paRegions = paDescsNew;
172 m_cRegionsMax = cRegionsNew;
173 }
174
175 return S_OK;
176}
177
178
179void ResourceAssignmentManager::State::setRegion(PRESOURCEREGION pRegion, const char *pszName, RESOURCEREGIONTYPE enmType,
180 RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd)
181{
182 strncpy(&pRegion->szName[0], pszName, sizeof(pRegion->szName));
183 pRegion->szName[sizeof(pRegion->szName) - 1] = '\0';
184 pRegion->enmType = enmType;
185 pRegion->GCPhysStart = GCPhysStart;
186 pRegion->GCPhysEnd = GCPhysEnd;
187}
188
189
190HRESULT ResourceAssignmentManager::State::addAddrRange(const char *pszName, RESOURCEREGIONTYPE enmType,
191 RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
192{
193 RTGCPHYS GCPhysEnd = GCPhysStart + cbRegion - 1;
194
195 /* Find the right spot in the array where to insert the range, it must not overlap with an existing used range. */
196 uint32_t iRegion = 0;
197 while ( iRegion < m_cRegions
198 && GCPhysStart > m_paRegions[iRegion].GCPhysEnd)
199 iRegion++;
200
201 Assert( iRegion == m_cRegions - 1
202 || m_paRegions[iRegion].enmType != m_paRegions[iRegion + 1].enmType);
203
204 /* Check that there is sufficient free space. */
205 if ( (m_paRegions[iRegion].enmType != kResourceRegionType_Free)
206 || GCPhysEnd > m_paRegions[iRegion].GCPhysEnd)
207 return E_INVALIDARG;
208
209 Assert(m_paRegions[iRegion].enmType == kResourceRegionType_Free);
210
211 /* Requested region fits exactly into the free region. */
212 if ( GCPhysStart == m_paRegions[iRegion].GCPhysStart
213 && GCPhysEnd == m_paRegions[iRegion].GCPhysEnd)
214 {
215 setRegion(&m_paRegions[iRegion], pszName, enmType, GCPhysStart, GCPhysEnd);
216 return S_OK;
217 }
218
219 HRESULT hrc = ensureAdditionalRegions(2 /*cRegions*/); /* Need two additional region descriptors max. */
220 if (FAILED(hrc))
221 return hrc;
222
223 /* Need to split the region into two or three depending on where the requested region lies. */
224 if (GCPhysStart == m_paRegions[iRegion].GCPhysStart)
225 {
226 /* At the start, move the free regions and everything at the end. */
227 memmove(&m_paRegions[iRegion + 1], &m_paRegions[iRegion], (m_cRegions - iRegion) * sizeof(*m_paRegions));
228 setRegion(&m_paRegions[iRegion], pszName, enmType, GCPhysStart, GCPhysEnd);
229
230 /* Adjust the free region. */
231 m_paRegions[iRegion + 1].GCPhysStart = GCPhysStart + cbRegion;
232 m_cRegions++;
233 }
234 else if (GCPhysStart + cbRegion - 1 == m_paRegions[iRegion].GCPhysEnd)
235 {
236 /* At the end of the region, move the remaining regions and adjust ranges. */
237 if (iRegion < m_cRegions)
238 memmove(&m_paRegions[iRegion + 2], &m_paRegions[iRegion + 1], (m_cRegions - iRegion) * sizeof(*m_paRegions));
239 setRegion(&m_paRegions[iRegion + 1], pszName, enmType, GCPhysStart, GCPhysEnd);
240 m_paRegions[iRegion].GCPhysEnd = GCPhysStart - 1;
241 m_cRegions++;
242 }
243 else
244 {
245 /* Somewhere in the middle, split into three regions. */
246 if (iRegion < m_cRegions)
247 memmove(&m_paRegions[iRegion + 3], &m_paRegions[iRegion + 1], (m_cRegions - iRegion) * sizeof(*m_paRegions));
248 setRegion(&m_paRegions[iRegion + 1], pszName, enmType, GCPhysStart, GCPhysEnd);
249 setRegion(&m_paRegions[iRegion + 2], "Free", kResourceRegionType_Free, GCPhysStart + cbRegion, m_paRegions[iRegion].GCPhysEnd);
250 m_paRegions[iRegion].GCPhysEnd = GCPhysStart - 1;
251 m_cRegions += 2;
252 }
253
254 return S_OK;
255}
256
257
258HRESULT ResourceAssignmentManager::State::findNextFreeAddrRange(RTGCPHYS cbRegion, RTGCPHYS cbAlignment, RTGCPHYS GCPhysMin, RTGCPHYS GCPhysMax,
259 RTGCPHYS GCPhysHint, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
260{
261 AssertReturn(GCPhysMax >= cbRegion, E_FAIL);
262 GCPhysMax -= cbRegion;
263
264 uint32_t iRegion = 0;
265 if (GCPhysHint)
266 {
267 /* Look for free address range downwards from the hint first. */
268 iRegion = m_cRegions - 1;
269 while (iRegion)
270 {
271 PCRESOURCEREGION pRegion = &m_paRegions[iRegion];
272
273 /* Region must be free and satisfy the alignment++ requirements. */
274 RTGCPHYS GCPhysStartAligned = RT_ALIGN_T(pRegion->GCPhysEnd - cbRegion + 1, cbAlignment, RTGCPHYS);
275 if ( pRegion->enmType == kResourceRegionType_Free
276 && GCPhysHint >= pRegion->GCPhysEnd
277 && GCPhysMin <= pRegion->GCPhysStart
278 && GCPhysMax >= pRegion->GCPhysEnd
279 && GCPhysStartAligned >= pRegion->GCPhysStart
280 && pRegion->GCPhysEnd - GCPhysStartAligned + 1 >= cbRegion)
281 {
282 *pGCPhysStart = GCPhysStartAligned;
283 *pcbRegion = cbRegion;
284 return S_OK;
285 }
286
287 iRegion--;
288 }
289 }
290
291 while ( iRegion < m_cRegions
292 && GCPhysMin > m_paRegions[iRegion].GCPhysStart)
293 iRegion++;
294
295 /* Find a free region which satisfies or requirements. */
296 while ( iRegion < m_cRegions
297 && GCPhysMax >= m_paRegions[iRegion].GCPhysStart)
298 {
299 PCRESOURCEREGION pRegion = &m_paRegions[iRegion];
300
301 /* Region must be free and satisfy the alignment++ requirements. */
302 RTGCPHYS GCPhysStartAligned = RT_ALIGN_T(pRegion->GCPhysStart, cbAlignment, RTGCPHYS);
303 if ( pRegion->enmType == kResourceRegionType_Free
304 && GCPhysStartAligned >= pRegion->GCPhysStart
305 && pRegion->GCPhysEnd - GCPhysStartAligned + 1 >= cbRegion)
306 {
307 *pGCPhysStart = pRegion->GCPhysStart;
308 *pcbRegion = cbRegion;
309 return S_OK;
310 }
311
312 iRegion++;
313 }
314
315 return E_OUTOFMEMORY;
316}
317
318
319static const char *resourceManagerRegionType2Str(RESOURCEREGIONTYPE enmType)
320{
321 switch (enmType)
322 {
323 case kResourceRegionType_Free: return "FREE";
324 case kResourceRegionType_Ram: return "RAM ";
325 case kResourceRegionType_Rom: return "ROM ";
326 case kResourceRegionType_Mmio: return "MMIO";
327 default: AssertFailed(); return "UNKNOWN";
328 }
329}
330
331
332void ResourceAssignmentManager::State::dumpToReleaseLog(void)
333{
334 LogRel(("Memory Regions:\n"));
335 for (uint32_t iRegion = 0; iRegion < m_cRegions; iRegion++)
336 {
337 LogRel((" %RGp - %RGp (%zu) %s %s\n",
338 m_paRegions[iRegion].GCPhysStart,
339 m_paRegions[iRegion].GCPhysEnd,
340 m_paRegions[iRegion].GCPhysEnd - m_paRegions[iRegion].GCPhysStart + 1,
341 resourceManagerRegionType2Str(m_paRegions[iRegion].enmType),
342 m_paRegions[iRegion].szName));
343 }
344}
345
346
347ResourceAssignmentManager::ResourceAssignmentManager()
348 : m_pState(NULL),
349 m_GCPhysMmioHint(RTGCPHYS_MAX)
350{
351 m_pState = new State();
352 Assert(m_pState);
353}
354
355
356ResourceAssignmentManager::~ResourceAssignmentManager()
357{
358 if (m_pState)
359 {
360 delete m_pState;
361 m_pState = NULL;
362 }
363}
364
365
366ResourceAssignmentManager *ResourceAssignmentManager::createInstance(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType,
367 uint32_t cInterrupts, RTGCPHYS GCPhysMmioHint)
368{
369 RT_NOREF(pVMM);
370
371 ResourceAssignmentManager *pInstance = new ResourceAssignmentManager();
372
373 pInstance->m_GCPhysMmioHint = GCPhysMmioHint;
374 pInstance->m_pState->init(chipsetType, iommuType, cInterrupts);
375 Assert(pInstance);
376 return pInstance;
377}
378
379
380HRESULT ResourceAssignmentManager::assignFixedRomRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
381{
382 return m_pState->addAddrRange(pszName, kResourceRegionType_Rom, GCPhysStart, cbRegion);
383}
384
385
386HRESULT ResourceAssignmentManager::assignFixedRamRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
387{
388 return m_pState->addAddrRange(pszName, kResourceRegionType_Ram, GCPhysStart, cbRegion);
389}
390
391
392HRESULT ResourceAssignmentManager::assignFixedMmioRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
393{
394 return m_pState->addAddrRange(pszName, kResourceRegionType_Mmio, GCPhysStart, cbRegion);
395}
396
397
398HRESULT ResourceAssignmentManager::assignMmioRegionAligned(const char *pszName, RTGCPHYS cbRegion, RTGCPHYS cbAlignment, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion,
399 bool fOnly32Bit)
400{
401 RTGCPHYS GCPhysRegionStart;
402 RTGCPHYS cbRegionFinal;
403 HRESULT hrc = m_pState->findNextFreeAddrRange(cbRegion, cbAlignment, 0 /*GCPhysMin*/, fOnly32Bit ? _4G : RTGCPHYS_MAX,
404 m_GCPhysMmioHint, &GCPhysRegionStart, &cbRegionFinal);
405 if (SUCCEEDED(hrc))
406 {
407 *pGCPhysStart = GCPhysRegionStart;
408 *pcbRegion = cbRegionFinal;
409 return assignFixedMmioRegion(pszName, GCPhysRegionStart, cbRegion);
410 }
411
412 return hrc;
413}
414
415
416HRESULT ResourceAssignmentManager::assignMmioRegion(const char *pszName, RTGCPHYS cbRegion, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
417{
418 return assignMmioRegionAligned(pszName, cbRegion, _4K, pGCPhysStart, pcbRegion, false /*fOnly32Bit*/);
419}
420
421
422HRESULT ResourceAssignmentManager::assignMmio32Region(const char *pszName, RTGCPHYS cbRegion, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
423{
424 return assignMmioRegionAligned(pszName, cbRegion, _4K, pGCPhysStart, pcbRegion, true /*fOnly32Bit*/);
425}
426
427
428HRESULT ResourceAssignmentManager::assignMmio64Region(const char *pszName, RTGCPHYS cbRegion, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
429{
430 RTGCPHYS GCPhysRegionStart;
431 RTGCPHYS cbRegionFinal;
432 HRESULT hrc = m_pState->findNextFreeAddrRange(cbRegion, _4K, _4G /*GCPhysMin*/, RTGCPHYS_MAX,
433 m_GCPhysMmioHint, &GCPhysRegionStart, &cbRegionFinal);
434 if (SUCCEEDED(hrc))
435 {
436 *pGCPhysStart = GCPhysRegionStart;
437 *pcbRegion = cbRegionFinal;
438 return assignFixedMmioRegion(pszName, GCPhysRegionStart, cbRegion);
439 }
440
441 return hrc;
442}
443
444
445HRESULT ResourceAssignmentManager::assignInterrupts(const char *pszName, uint32_t cInterrupts, uint32_t *piInterruptFirst)
446{
447 if (m_pState->miInterrupt + cInterrupts > m_pState->mcInterrupts)
448 {
449 AssertLogRelMsgFailed(("ResourceAssignmentManager: Interrupt count for %s exceeds number of available interrupts\n", pszName));
450 return E_INVALIDARG;
451 }
452
453 *piInterruptFirst = m_pState->miInterrupt;
454 m_pState->miInterrupt += cInterrupts;
455 return S_OK;
456}
457
458HRESULT ResourceAssignmentManager::queryMmioRegion(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
459{
460 /*
461 * This ASSUMES that there are adjacent MMIO regions above 4GiB which can be combined into one single region
462 * (adjacent and no ROM/RAM regions inbetween).
463 */
464 *pGCPhysMmioStart = 0;
465 *pcbMmio = 0;
466
467 /* Look for the start. */
468 for (uint32_t i = 0; i < m_pState->m_cRegions; i++)
469 {
470 PCRESOURCEREGION pRegion = &m_pState->m_paRegions[i];
471
472 if ( pRegion->GCPhysStart >= _4G
473 && pRegion->enmType == kResourceRegionType_Mmio)
474 {
475 RTGCPHYS cbMmio = pRegion->GCPhysEnd - pRegion->GCPhysStart + 1;
476
477 *pGCPhysMmioStart = pRegion->GCPhysStart;
478
479 /* Add up any remaining MMIO regions adjacent to this one. */
480 for (uint32_t j = i; j < m_pState->m_cRegions; j++)
481 {
482 pRegion = &m_pState->m_paRegions[i];
483 if ( pRegion->enmType == kResourceRegionType_Mmio
484 && pRegion->GCPhysStart == *pGCPhysMmioStart + cbMmio)
485 cbMmio += pRegion->GCPhysEnd - pRegion->GCPhysStart + 1;
486 else
487 break;
488 }
489
490 *pcbMmio = cbMmio;
491 return S_OK;
492 }
493 }
494
495 return S_OK;
496}
497
498
499HRESULT ResourceAssignmentManager::queryMmio32Region(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
500{
501 RT_NOREF(pGCPhysMmioStart, pcbMmio);
502 return S_OK;
503}
504
505
506HRESULT ResourceAssignmentManager::assignSingleInterrupt(const char *pszName, uint32_t *piInterrupt)
507{
508 return assignInterrupts(pszName, 1, piInterrupt);
509}
510
511
512void ResourceAssignmentManager::dumpMemoryRegionsToReleaseLog(void)
513{
514 m_pState->dumpToReleaseLog();
515}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette