1 #include "memory_utils.h" 2 3 4 5 /* Return page 'n' for the configured page size. */ 6 7 offset_t page(unsigned int n) 8 { 9 return PAGE_SIZE * n; 10 } 11 12 /* Return the order of 'size', where 2 ** order yields the size. */ 13 14 unsigned int page_order(offset_t size) 15 { 16 /* Count zeros from the left, stopping at the first set bit, using the width 17 of the size value (in bits, starting with the width in bytes) to 18 calculate the position of this bit and thus the order of the value. */ 19 20 return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(size); 21 } 22 23 /* Return 'value' rounded up to the nearest 'increment'. */ 24 25 offset_t round(offset_t value, offset_t increment) 26 { 27 return trunc(value + increment - 1, increment); 28 } 29 30 /* Return 'value' rounded up to the nearest multiple of 'increment'. */ 31 32 offset_t round_multiple(offset_t value, offset_t increment) 33 { 34 offset_t last = increment; 35 36 while (1) 37 { 38 if (value < increment) 39 return round(value, last); 40 41 last = increment; 42 increment *= 2; 43 } 44 } 45 46 /* Return 'value' rounded down (or truncated) to the nearest 'increment'. */ 47 48 offset_t trunc(offset_t value, offset_t increment) 49 { 50 return (value / increment) * increment; 51 } 52 53 /* Return 'value' rounded down (or truncated) to the nearest multiple of 54 'increment'. */ 55 56 offset_t trunc_multiple(offset_t value, offset_t increment) 57 { 58 offset_t last = increment; 59 60 while (1) 61 { 62 if (value < increment) 63 return trunc(value, last); 64 65 last = increment; 66 increment *= 2; 67 } 68 } 69 70 /* Find the maximum size aligned region within the region from 'start' to (but 71 not including) 'end', with the given initial 'increment'. */ 72 73 offset_t max_multiple(offset_t start, offset_t end, offset_t increment) 74 { 75 /* The largest possible aligned region is derived from the region size. */ 76 77 offset_t size = trunc_multiple(end - start, increment); 78 79 /* Apply the alignment to the start. */ 80 81 offset_t aligned = round(start, size); 82 83 /* If the region is aligned, return the size. */ 84 85 if (aligned == start) 86 return size; 87 88 /* If the region is not aligned to the current size, recalculate the aligned 89 size. */ 90 91 offset_t aligned_size; 92 93 do 94 { 95 aligned_size = trunc_multiple(end - aligned, increment); 96 size /= 2; 97 98 /* Determine whether a smaller alignment could yield a larger aligned 99 size. */ 100 101 if (aligned_size >= size) 102 return aligned_size; 103 104 aligned = round(start, size); 105 } 106 while (aligned > start); 107 108 return aligned_size; 109 } 110 111 // vim: tabstop=4 expandtab shiftwidth=4