VirtualBox

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

Last change on this file since 65314 was 64766, checked in by vboxsync, 8 years ago

src/VBox: Make the use of the iterator for RTListForEach()/RTListForEachSafe() more obvious. There is no need to initialize the iterator and we also must not depend on the iterator being NULL if the list was empty.

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