VirtualBox

source: vbox/trunk/src/VBox/GuestHost/HGSMI/HGSMIMemAlloc.cpp@ 67914

Last change on this file since 67914 was 66506, checked in by vboxsync, 8 years ago

bugref:8524: Additions/linux: play nicely with distribution-installed Additions
Based on a patch series by Hans de Goede/Red Hat with minor adjustments by Oracle.
Graphics: Add VBoxVideoIPRT.h header
Add a VBoxVideoIPRT.h header, this adds 2 versions of this file:
1) Generic include/VBox/Graphics/VBoxVideoIPRT.h which includes all the header

files needed by files shared with the linux drm driver

2) src/VBox/Additions/linux/drm/VBoxVideoIPRT.h, which replaces the generic

gfx-common.h when building the linux drm driver


The purpose of this is to eventually redefines various iprt and HGSMI bits
in the linux drm driver version to use more linux kernel infrastructure.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.5 KB
Line 
1/* $Id: HGSMIMemAlloc.cpp 66506 2017-04-11 09:59:29Z vboxsync $ */
2/** @file
3 * VBox Host Guest Shared Memory Interface (HGSMI) - Memory allocator.
4 */
5
6/*
7 * Copyright (C) 2014-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * Memory allocator
20 * ----------------
21 *
22 * Area [0; AreaSize) contains only the data, control structures are separate.
23 * Block sizes are power of 2: 32B, ..., 1MB
24 * Area size can be anything and will be divided initially to largest possible free blocks.
25 *
26 * The entire area is described by a list of 32 bit block descriptors:
27 * * bits 0..3 - order, which is log2 size of the block - 5: 2^(0+5) ... 2^(15+5) == 32B .. 1MB
28 * * bit 4 - 1 for free blocks.
29 * * bits 5..31 - block offset.
30 *
31 * 31 ... 5 | 4 | 3 ... 0
32 * offset F order
33 *
34 * There is a sorted collection of all block descriptors
35 * (key is the block offset, bits 0...4 do not interfere with sorting).
36 * Also there are lists of free blocks for each size for fast allocation.
37 *
38 *
39 * Implementation
40 * --------------
41 *
42 * The blocks collection is a sorted linear list.
43 *
44 * Initially the entire area consists of one or more largest blocks followed by smaller blocks:
45 * * 100B area - 64B block with descriptor: 0x00000011
46 * 32B block with descriptor: 0x00000030
47 * 4B unused
48 * * 64K area - one 64K block with descriptor: 0x0000001C
49 * * 512K area - one 512K block with descriptor: 0x0000001F
50 *
51 * When allocating a new block:
52 * * larger free blocks are splitted when there are no smaller free blocks;
53 * * smaller free blocks are merged if they can build a requested larger block.
54 */
55#include <HGSMIMemAlloc.h>
56#include <HGSMI.h>
57
58#include <VBoxVideoIPRT.h>
59
60/*
61 * We do not want assertions in Linux kernel code to reduce symbol dependencies.
62 */
63#if defined(IN_RING0) && defined(RT_OS_LINUX)
64# define HGSMI_ASSERT_RETURN(a, b) if (!(a)) return (b)
65# define HGSMI_ASSERT_FAILED() do {} while (0)
66# define HGSMI_ASSERT(expr) do {} while (0)
67#else
68# define HGSMI_ASSERT_RETURN(a, b) AssertReturn(a, b)
69# define HGSMI_ASSERT_FAILED() AssertFailed()
70# define HGSMI_ASSERT(expr) Assert(expr)
71#endif /* !IN_RING0 && RT_OS_LINUX */
72
73DECLINLINE(HGSMIOFFSET) hgsmiMADescriptor(HGSMIOFFSET off, bool fFree, HGSMIOFFSET order)
74{
75 return (off & HGSMI_MA_DESC_OFFSET_MASK) |
76 (fFree? HGSMI_MA_DESC_FREE_MASK: 0) |
77 (order & HGSMI_MA_DESC_ORDER_MASK);
78}
79
80static void hgsmiMABlockFree(HGSMIMADATA *pMA, HGSMIMABLOCK *pBlock)
81{
82 pMA->env.pfnFree(pMA->env.pvEnv, pBlock);
83}
84
85static int hgsmiMABlockAlloc(HGSMIMADATA *pMA, HGSMIMABLOCK **ppBlock)
86{
87 int rc = VINF_SUCCESS;
88
89 HGSMIMABLOCK *pBlock = (HGSMIMABLOCK *)pMA->env.pfnAlloc(pMA->env.pvEnv, sizeof(HGSMIMABLOCK));
90 if (pBlock)
91 {
92 RT_ZERO(pBlock->nodeBlock);
93 *ppBlock = pBlock;
94 }
95 else
96 {
97 rc = VERR_NO_MEMORY;
98 }
99
100 return rc;
101}
102
103/* Divide entire area to free blocks. */
104static int hgsmiMAFormat(HGSMIMADATA *pMA)
105{
106 int rc = VINF_SUCCESS;
107
108 /* Initial value, it will be updated in the loop below. */
109 pMA->cbMaxBlock = HGSMI_MA_BLOCK_SIZE_MIN;
110 pMA->cBlocks = 0;
111
112 HGSMISIZE cbBlock = HGSMI_MA_BLOCK_SIZE_MAX;
113 HGSMISIZE cbRemaining = pMA->area.cbArea;
114 HGSMIOFFSET off = 0;
115
116 while (cbBlock >= HGSMI_MA_BLOCK_SIZE_MIN)
117 {
118 /* Build a list of free memory blocks with u32BlockSize. */
119 uint32_t cBlocks = cbRemaining / cbBlock;
120 if (cBlocks > 0)
121 {
122 if (pMA->cbMaxBlock < cbBlock)
123 {
124 pMA->cbMaxBlock = cbBlock;
125 }
126
127 HGSMIOFFSET order = HGSMIMASize2Order(cbBlock);
128
129 uint32_t i;
130 for (i = 0; i < cBlocks; ++i)
131 {
132 /* A new free block. */
133 HGSMIMABLOCK *pBlock;
134 rc = hgsmiMABlockAlloc(pMA, &pBlock);
135 if (RT_FAILURE(rc))
136 {
137 break;
138 }
139
140 pBlock->descriptor = hgsmiMADescriptor(off, true, order);
141 RTListAppend(&pMA->listBlocks, &pBlock->nodeBlock);
142 ++pMA->cBlocks;
143
144 off += cbBlock;
145 cbRemaining -= cbBlock;
146 }
147 }
148
149 if (RT_FAILURE(rc))
150 {
151 break;
152 }
153
154 cbBlock /= 2;
155 }
156
157 return rc;
158}
159
160static int hgsmiMARebuildFreeLists(HGSMIMADATA *pMA)
161{
162 int rc = VINF_SUCCESS;
163
164 HGSMIMABLOCK *pIter;
165 RTListForEach(&pMA->listBlocks, pIter, HGSMIMABLOCK, nodeBlock)
166 {
167 if (HGSMI_MA_DESC_IS_FREE(pIter->descriptor))
168 {
169 HGSMIOFFSET order = HGSMI_MA_DESC_ORDER(pIter->descriptor);
170 RTListAppend(&pMA->aListFreeBlocks[order], &pIter->nodeFree);
171 }
172 }
173
174 return rc;
175}
176
177static int hgsmiMARestore(HGSMIMADATA *pMA, HGSMIOFFSET *paDescriptors, uint32_t cDescriptors, HGSMISIZE cbMaxBlock)
178{
179 int rc = VINF_SUCCESS;
180
181 pMA->cbMaxBlock = cbMaxBlock;
182 pMA->cBlocks = 0;
183
184 HGSMISIZE cbRemaining = pMA->area.cbArea;
185 HGSMIOFFSET off = 0;
186
187 uint32_t i;
188 for (i = 0; i < cDescriptors; ++i)
189 {
190 /* Verify the descriptor. */
191 HGSMISIZE cbBlock = HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(paDescriptors[i]));
192 if ( off != HGSMI_MA_DESC_OFFSET(paDescriptors[i])
193 || cbBlock > cbRemaining
194 || cbBlock > pMA->cbMaxBlock)
195 {
196 rc = VERR_INVALID_PARAMETER;
197 break;
198 }
199
200 /* A new free block. */
201 HGSMIMABLOCK *pBlock;
202 rc = hgsmiMABlockAlloc(pMA, &pBlock);
203 if (RT_FAILURE(rc))
204 {
205 break;
206 }
207
208 pBlock->descriptor = paDescriptors[i];
209 RTListAppend(&pMA->listBlocks, &pBlock->nodeBlock);
210 ++pMA->cBlocks;
211
212 off += cbBlock;
213 cbRemaining -= cbBlock;
214 }
215
216 return rc;
217}
218
219static HGSMIMABLOCK *hgsmiMAGetFreeBlock(HGSMIMADATA *pMA, HGSMIOFFSET order)
220{
221 HGSMIMABLOCK *pBlock = NULL;
222
223 HGSMIOFFSET i;
224 for (i = order; i < RT_ELEMENTS(pMA->aListFreeBlocks); ++i)
225 {
226 pBlock = RTListGetFirst(&pMA->aListFreeBlocks[i], HGSMIMABLOCK, nodeFree);
227 if (pBlock)
228 {
229 break;
230 }
231 }
232
233 if (pBlock)
234 {
235 HGSMI_ASSERT_RETURN(HGSMI_MA_DESC_IS_FREE(pBlock->descriptor), NULL);
236
237 /* Where the block starts. */
238 HGSMIOFFSET off = HGSMI_MA_DESC_OFFSET(pBlock->descriptor);
239
240 /* 'i' is the order of the block. */
241 while (i != order)
242 {
243 /* A larger block was found and need to be split to 2 smaller blocks. */
244 HGSMIMABLOCK *pBlock2;
245 int rc = hgsmiMABlockAlloc(pMA, &pBlock2);
246 if (RT_FAILURE(rc))
247 {
248 pBlock = NULL;
249 break;
250 }
251
252 /* Create 2 blocks with descreased order. */
253 --i;
254
255 /* Remove from the free list. */
256 RTListNodeRemove(&pBlock->nodeFree);
257
258 pBlock->descriptor = hgsmiMADescriptor(off, true, i);
259 pBlock2->descriptor = hgsmiMADescriptor(off + HGSMIMAOrder2Size(i), true, i);
260
261 /* Update list of all blocks by inserting pBlock2 after pBlock. */
262 RTListNodeInsertAfter(&pBlock->nodeBlock, &pBlock2->nodeBlock);
263 ++pMA->cBlocks;
264
265 /* Update the free list. */
266 RTListAppend(&pMA->aListFreeBlocks[i], &pBlock->nodeFree);
267 RTListAppend(&pMA->aListFreeBlocks[i], &pBlock2->nodeFree);
268 }
269 }
270
271 return pBlock;
272}
273
274static void hgsmiMAReformatFreeBlocks(HGSMIMADATA *pMA, HGSMIOFFSET maxId,
275 HGSMIMABLOCK *pStart, HGSMIMABLOCK *pEnd, HGSMISIZE cbBlocks)
276{
277 int rc = VINF_SUCCESS;
278
279 /*
280 * Blocks starting from pStart until pEnd will be replaced with
281 * another set of blocks.
282 *
283 * The new set will include the block with the required order.
284 * Since the required order is larger than any existing block,
285 * it will replace at least two existing blocks.
286 * The new set will also have minimal possible number of blocks.
287 * Therefore the new set will have at least one block less.
288 * Blocks will be updated in place and remaining blocks will be
289 * deallocated.
290 */
291
292 HGSMISIZE u32BlockSize = HGSMIMAOrder2Size(maxId);
293 HGSMISIZE cbRemaining = cbBlocks;
294 HGSMIOFFSET off = HGSMI_MA_DESC_OFFSET(pStart->descriptor);
295 HGSMIMABLOCK *pBlock = pStart;
296
297 while (u32BlockSize >= HGSMI_MA_BLOCK_SIZE_MIN && cbRemaining)
298 {
299 /* Build a list of free memory blocks with u32BlockSize. */
300 uint32_t cBlocks = cbRemaining / u32BlockSize;
301 if (cBlocks > 0)
302 {
303 HGSMIOFFSET order = HGSMIMASize2Order(u32BlockSize);
304
305 uint32_t i;
306 for (i = 0; i < cBlocks; ++i)
307 {
308 if (pBlock == pEnd)
309 {
310 /* Should never happen because the new set of blocks is supposed to be smaller. */
311 HGSMI_ASSERT_FAILED();
312 rc = VERR_OUT_OF_RESOURCES;
313 break;
314 }
315
316 /* Remove from the free list. */
317 RTListNodeRemove(&pBlock->nodeFree);
318
319 pBlock->descriptor = hgsmiMADescriptor(off, true, order);
320
321 RTListAppend(&pMA->aListFreeBlocks[order], &pBlock->nodeFree);
322
323 off += u32BlockSize;
324 cbRemaining -= u32BlockSize;
325
326 pBlock = RTListGetNext(&pMA->listBlocks, pBlock, HGSMIMABLOCK, nodeBlock);
327 }
328 }
329
330 if (RT_FAILURE(rc))
331 {
332 break;
333 }
334
335 u32BlockSize /= 2;
336 }
337
338 HGSMI_ASSERT(cbRemaining == 0);
339
340 if (RT_SUCCESS(rc))
341 {
342 /* Remove remaining free blocks from pBlock until pEnd */
343 for (;;)
344 {
345 bool fEnd = (pBlock == pEnd);
346 HGSMIMABLOCK *pNext = RTListGetNext(&pMA->listBlocks, pBlock, HGSMIMABLOCK, nodeBlock);
347
348 RTListNodeRemove(&pBlock->nodeFree);
349 RTListNodeRemove(&pBlock->nodeBlock);
350 --pMA->cBlocks;
351
352 hgsmiMABlockFree(pMA, pBlock);
353
354 if (fEnd)
355 {
356 break;
357 }
358
359 pBlock = pNext;
360 }
361 }
362}
363
364static void hgsmiMAQueryFreeRange(HGSMIMADATA *pMA, HGSMIMABLOCK *pBlock, HGSMISIZE cbRequired,
365 HGSMIMABLOCK **ppStart, HGSMIMABLOCK **ppEnd, HGSMISIZE *pcbBlocks)
366{
367 HGSMI_ASSERT(HGSMI_MA_DESC_IS_FREE(pBlock->descriptor));
368
369 *pcbBlocks = HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(pBlock->descriptor));
370 *ppStart = pBlock;
371 *ppEnd = pBlock;
372
373 HGSMIMABLOCK *p;
374 for (;;)
375 {
376 p = RTListGetNext(&pMA->listBlocks, *ppEnd, HGSMIMABLOCK, nodeBlock);
377 if (!p || !HGSMI_MA_DESC_IS_FREE(p->descriptor))
378 {
379 break;
380 }
381 *pcbBlocks += HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(p->descriptor));
382 *ppEnd = p;
383
384 if (cbRequired && *pcbBlocks >= cbRequired)
385 {
386 return;
387 }
388 }
389 for (;;)
390 {
391 p = RTListGetPrev(&pMA->listBlocks, *ppStart, HGSMIMABLOCK, nodeBlock);
392 if (!p || !HGSMI_MA_DESC_IS_FREE(p->descriptor))
393 {
394 break;
395 }
396 *pcbBlocks += HGSMIMAOrder2Size(HGSMI_MA_DESC_ORDER(p->descriptor));
397 *ppStart = p;
398
399 if (cbRequired && *pcbBlocks >= cbRequired)
400 {
401 return;
402 }
403 }
404}
405
406static void hgsmiMAMergeFreeBlocks(HGSMIMADATA *pMA, HGSMIOFFSET order)
407{
408 /* Try to create a free block with the order from smaller free blocks. */
409 if (order == 0)
410 {
411 /* No smaller blocks. */
412 return;
413 }
414
415 HGSMISIZE cbRequired = HGSMIMAOrder2Size(order);
416
417 /* Scan all free lists of smaller blocks.
418 *
419 * Get the sequence of free blocks before and after each free block.
420 * If possible, re-split the sequence to get the required block and other free block(s).
421 * If not possible, try the next free block.
422 *
423 * Free blocks are scanned from i to 0 orders.
424 */
425 HGSMIOFFSET i = order - 1;
426 for (;;)
427 {
428 HGSMIMABLOCK *pIter;
429 RTListForEach(&pMA->aListFreeBlocks[i], pIter, HGSMIMABLOCK, nodeFree)
430 {
431 HGSMI_ASSERT(HGSMI_MA_DESC_ORDER(pIter->descriptor) == i);
432
433 HGSMISIZE cbBlocks;
434 HGSMIMABLOCK *pFreeStart;
435 HGSMIMABLOCK *pFreeEnd;
436 hgsmiMAQueryFreeRange(pMA, pIter, cbRequired, &pFreeStart, &pFreeEnd, &cbBlocks);
437
438 HGSMI_ASSERT((cbBlocks / HGSMI_MA_BLOCK_SIZE_MIN) * HGSMI_MA_BLOCK_SIZE_MIN == cbBlocks);
439
440 /* Verify whether cbBlocks is enough for the requested block. */
441 if (cbBlocks >= cbRequired)
442 {
443 /* Build new free blocks starting from the requested. */
444 hgsmiMAReformatFreeBlocks(pMA, order, pFreeStart, pFreeEnd, cbBlocks);
445 i = 0; /* Leave the loop. */
446 break;
447 }
448 }
449
450 if (i == 0)
451 {
452 break;
453 }
454
455 --i;
456 }
457}
458
459static HGSMIOFFSET hgsmiMAAlloc(HGSMIMADATA *pMA, HGSMISIZE cb)
460{
461 if (cb > pMA->cbMaxBlock)
462 {
463 return HGSMIOFFSET_VOID;
464 }
465
466 if (cb < HGSMI_MA_BLOCK_SIZE_MIN)
467 {
468 cb = HGSMI_MA_BLOCK_SIZE_MIN;
469 }
470
471 HGSMIOFFSET order = HGSMIPopCnt32(cb - 1) - HGSMI_MA_DESC_ORDER_BASE;
472
473 HGSMI_ASSERT_RETURN(HGSMIMAOrder2Size(order) >= cb, HGSMIOFFSET_VOID);
474 HGSMI_ASSERT_RETURN(order < RT_ELEMENTS(pMA->aListFreeBlocks), HGSMIOFFSET_VOID);
475
476 HGSMIMABLOCK *pBlock = hgsmiMAGetFreeBlock(pMA, order);
477 if (RT_UNLIKELY(pBlock == NULL))
478 {
479 /* No free block with large enough size. Merge smaller free blocks and try again. */
480 hgsmiMAMergeFreeBlocks(pMA, order);
481 pBlock = hgsmiMAGetFreeBlock(pMA, order);
482 }
483
484 if (RT_LIKELY(pBlock != NULL))
485 {
486 RTListNodeRemove(&pBlock->nodeFree);
487 pBlock->descriptor &= ~HGSMI_MA_DESC_FREE_MASK;
488 return HGSMI_MA_DESC_OFFSET(pBlock->descriptor);
489 }
490
491 return HGSMIOFFSET_VOID;
492}
493
494static void hgsmiMAFree(HGSMIMADATA *pMA, HGSMIOFFSET off)
495{
496 if (off == HGSMIOFFSET_VOID)
497 {
498 return;
499 }
500
501 /* Find the block corresponding to the offset. */
502 HGSMI_ASSERT((off / HGSMI_MA_BLOCK_SIZE_MIN) * HGSMI_MA_BLOCK_SIZE_MIN == off);
503
504 HGSMIMABLOCK *pBlock = HGSMIMASearchOffset(pMA, off);
505 if (pBlock)
506 {
507 if (HGSMI_MA_DESC_OFFSET(pBlock->descriptor) == off)
508 {
509 /* Found the right block, mark it as free. */
510 pBlock->descriptor |= HGSMI_MA_DESC_FREE_MASK;
511 RTListAppend(&pMA->aListFreeBlocks[HGSMI_MA_DESC_ORDER(pBlock->descriptor)], &pBlock->nodeFree);
512 return;
513 }
514 }
515
516 HGSMI_ASSERT_FAILED();
517}
518
519int HGSMIMAInit(HGSMIMADATA *pMA, const HGSMIAREA *pArea,
520 HGSMIOFFSET *paDescriptors, uint32_t cDescriptors, HGSMISIZE cbMaxBlock,
521 const HGSMIENV *pEnv)
522{
523 HGSMI_ASSERT_RETURN(pArea->cbArea < UINT32_C(0x80000000), VERR_INVALID_PARAMETER);
524 HGSMI_ASSERT_RETURN(pArea->cbArea >= HGSMI_MA_BLOCK_SIZE_MIN, VERR_INVALID_PARAMETER);
525
526 RT_ZERO(*pMA);
527
528 HGSMISIZE cb = (pArea->cbArea / HGSMI_MA_BLOCK_SIZE_MIN) * HGSMI_MA_BLOCK_SIZE_MIN;
529
530 int rc = HGSMIAreaInitialize(&pMA->area, pArea->pu8Base, cb, 0);
531 if (RT_SUCCESS(rc))
532 {
533 pMA->env = *pEnv;
534
535 uint32_t i;
536 for (i = 0; i < RT_ELEMENTS(pMA->aListFreeBlocks); ++i)
537 {
538 RTListInit(&pMA->aListFreeBlocks[i]);
539 }
540 RTListInit(&pMA->listBlocks);
541
542 if (cDescriptors)
543 {
544 rc = hgsmiMARestore(pMA, paDescriptors, cDescriptors, cbMaxBlock);
545 }
546 else
547 {
548 rc = hgsmiMAFormat(pMA);
549 }
550
551 if (RT_SUCCESS(rc))
552 {
553 rc = hgsmiMARebuildFreeLists(pMA);
554 }
555 }
556
557 return rc;
558}
559
560void HGSMIMAUninit(HGSMIMADATA *pMA)
561{
562 HGSMIMABLOCK *pIter;
563 HGSMIMABLOCK *pNext;
564 RTListForEachSafe(&pMA->listBlocks, pIter, pNext, HGSMIMABLOCK, nodeBlock)
565 {
566 RTListNodeRemove(&pIter->nodeBlock);
567 hgsmiMABlockFree(pMA, pIter);
568 }
569
570 RT_ZERO(*pMA);
571}
572
573HGSMIOFFSET HGSMIMAPointerToOffset(const HGSMIMADATA *pMA, const void *pv)
574{
575 if (HGSMIAreaContainsPointer(&pMA->area, pv))
576 {
577 return HGSMIPointerToOffset(&pMA->area, pv);
578 }
579
580 HGSMI_ASSERT_FAILED();
581 return HGSMIOFFSET_VOID;
582}
583
584void *HGSMIMAOffsetToPointer(const HGSMIMADATA *pMA, HGSMIOFFSET off)
585{
586 if (HGSMIAreaContainsOffset(&pMA->area, off))
587 {
588 return HGSMIOffsetToPointer(&pMA->area, off);
589 }
590
591 HGSMI_ASSERT_FAILED();
592 return NULL;
593}
594
595void *HGSMIMAAlloc(HGSMIMADATA *pMA, HGSMISIZE cb)
596{
597 HGSMIOFFSET off = hgsmiMAAlloc(pMA, cb);
598 return HGSMIMAOffsetToPointer(pMA, off);
599}
600
601void HGSMIMAFree(HGSMIMADATA *pMA, void *pv)
602{
603 HGSMIOFFSET off = HGSMIMAPointerToOffset(pMA, pv);
604 if (off != HGSMIOFFSET_VOID)
605 {
606 hgsmiMAFree(pMA, off);
607 }
608 else
609 {
610 HGSMI_ASSERT_FAILED();
611 }
612}
613
614HGSMIMABLOCK *HGSMIMASearchOffset(HGSMIMADATA *pMA, HGSMIOFFSET off)
615{
616 /* Binary search in the block list for the offset. */
617 HGSMIMABLOCK *pStart = RTListGetFirst(&pMA->listBlocks, HGSMIMABLOCK, nodeBlock);
618 HGSMIMABLOCK *pEnd = RTListGetLast(&pMA->listBlocks, HGSMIMABLOCK, nodeBlock);
619 HGSMIMABLOCK *pMiddle;
620
621 uint32_t iStart = 0;
622 uint32_t iEnd = pMA->cBlocks;
623 uint32_t iMiddle;
624
625 for (;;)
626 {
627 pMiddle = pStart;
628 iMiddle = iStart + (iEnd - iStart) / 2;
629 if (iMiddle == iStart)
630 {
631 break;
632 }
633
634 /* Find the block with the iMiddle index. Never go further than pEnd. */
635 uint32_t i;
636 for (i = iStart; i < iMiddle && pMiddle != pEnd; ++i)
637 {
638 pMiddle = RTListNodeGetNext(&pMiddle->nodeBlock, HGSMIMABLOCK, nodeBlock);
639 }
640
641 HGSMIOFFSET offMiddle = HGSMI_MA_DESC_OFFSET(pMiddle->descriptor);
642 if (offMiddle > off)
643 {
644 pEnd = pMiddle;
645 iEnd = iMiddle;
646 }
647 else
648 {
649 pStart = pMiddle;
650 iStart = iMiddle;
651 }
652 }
653
654 return pMiddle;
655}
656
657
658/*
659 * Helper.
660 */
661
662uint32_t HGSMIPopCnt32(uint32_t u32)
663{
664 uint32_t c = 0;
665 if (u32 > 0xFFFF) { c += 16; u32 >>= 16; }
666 if (u32 > 0xFF) { c += 8; u32 >>= 8; }
667 if (u32 > 0xF) { c += 4; u32 >>= 4; }
668 if (u32 > 0x3) { c += 2; u32 >>= 2; }
669 if (u32 > 0x1) { c += 1; u32 >>= 1; }
670 return c + u32;
671}
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