1 #include "memory_utils.h" 2 3 4 5 /* Return page 'n' for the configured page size. */ 6 7 length_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(length_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 length_t round(length_t value, length_t increment) 26 { 27 return trunc(value + increment - 1, increment); 28 } 29 30 offset_t round_offset(offset_t value, length_t increment) 31 { 32 return trunc_offset(value + increment - 1, increment); 33 } 34 35 /* Return 'value' rounded up to the nearest multiple of 'increment'. */ 36 37 length_t round_multiple(length_t value, length_t increment) 38 { 39 length_t last = increment; 40 41 while (1) 42 { 43 if (value < increment) 44 return round(value, last); 45 46 last = increment; 47 increment *= 2; 48 } 49 } 50 51 /* Return 'value' rounded down (or truncated) to the nearest 'increment'. */ 52 53 length_t trunc(length_t value, length_t increment) 54 { 55 return (value / increment) * increment; 56 } 57 58 offset_t trunc_offset(offset_t value, length_t increment) 59 { 60 return (value / increment) * increment; 61 } 62 63 /* Return 'value' rounded down (or truncated) to the nearest multiple of 64 'increment'. */ 65 66 length_t trunc_multiple(length_t value, length_t increment) 67 { 68 length_t last = increment; 69 70 while (1) 71 { 72 if (value < increment) 73 return trunc(value, last); 74 75 last = increment; 76 increment *= 2; 77 } 78 } 79 80 /* Find the maximum size aligned region within the region from 'start' to (but 81 not including) 'end', with the given initial 'increment'. */ 82 83 length_t max_multiple(length_t start, length_t end, length_t increment) 84 { 85 /* The largest possible aligned region is derived from the region size. */ 86 87 length_t size = trunc_multiple(end - start, increment); 88 89 /* Apply the alignment to the start. */ 90 91 length_t aligned = round(start, size); 92 93 /* If the region is aligned, return the size. */ 94 95 if (aligned == start) 96 return size; 97 98 /* If the region is not aligned to the current size, recalculate the aligned 99 size. */ 100 101 length_t aligned_size; 102 103 do 104 { 105 aligned_size = trunc_multiple(end - aligned, increment); 106 size /= 2; 107 108 /* Determine whether a smaller alignment could yield a larger aligned 109 size. */ 110 111 if (aligned_size >= size) 112 return aligned_size; 113 114 aligned = round(start, size); 115 } 116 while (aligned > start); 117 118 return aligned_size; 119 } 120 121 // vim: tabstop=4 expandtab shiftwidth=4