gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/hostarch/sizes_util.go (about) 1 // Copyright 2022 The gVisor Authors. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package hostarch 7 8 // Masks often used when working with alignment in constant expressions. 9 const ( 10 PageMask = PageSize - 1 11 HugePageMask = HugePageSize - 1 12 CacheLineMask = CacheLineSize - 1 13 ) 14 15 type bytecount interface { 16 ~uint | ~uint16 | ~uint32 | ~uint64 | ~uintptr 17 } 18 19 type hugebytecount interface { 20 ~uint | ~uint32 | ~uint64 | ~uintptr 21 } 22 23 // PageRoundDown returns x rounded down to the nearest multiple of PageSize. 24 func PageRoundDown[T bytecount](x T) T { 25 return x &^ PageMask 26 } 27 28 // PageRoundUp returns x rounded up to the nearest multiple of PageSize. ok is 29 // true iff rounding up does not overflow the range of T. 30 func PageRoundUp[T bytecount](x T) (val T, ok bool) { 31 val = PageRoundDown(x + PageMask) 32 ok = val >= x 33 return 34 } 35 36 // MustPageRoundUp is equivalent to PageRoundUp, but panics if rounding up 37 // overflows. 38 func MustPageRoundUp[T bytecount](x T) T { 39 val, ok := PageRoundUp(x) 40 if !ok { 41 panic("PageRoundUp overflows") 42 } 43 return val 44 } 45 46 // PageOffset returns the offset of x into its containing page. 47 func PageOffset[T bytecount](x T) T { 48 return x & PageMask 49 } 50 51 // IsPageAligned returns true if x is a multiple of PageSize. 52 func IsPageAligned[T bytecount](x T) bool { 53 return PageOffset(x) == 0 54 } 55 56 // ToPagesRoundUp returns (the number of pages equal to x bytes rounded up, 57 // true). If rounding x up to a multiple of PageSize overflows the range of T, 58 // ToPagesRoundUp returns (unspecified, false). 59 func ToPagesRoundUp[T bytecount](x T) (T, bool) { 60 y := x + PageMask 61 if y < x { 62 return x, false 63 } 64 return y / PageSize, true 65 } 66 67 // HugePageRoundDown returns x rounded down to the nearest multiple of 68 // HugePageSize. 69 func HugePageRoundDown[T hugebytecount](x T) T { 70 return x &^ HugePageMask 71 } 72 73 // HugePageRoundUp returns x rounded up to the nearest multiple of 74 // HugePageSize. ok is true iff rounding up does not overflow the range of T. 75 func HugePageRoundUp[T hugebytecount](x T) (val T, ok bool) { 76 val = HugePageRoundDown(x + HugePageMask) 77 ok = val >= x 78 return 79 } 80 81 // MustHugePageRoundUp is equivalent to HugePageRoundUp, but panics if rounding 82 // up overflows. 83 func MustHugePageRoundUp[T hugebytecount](x T) T { 84 val, ok := HugePageRoundUp(x) 85 if !ok { 86 panic("HugePageRoundUp overflows") 87 } 88 return val 89 } 90 91 // HugePageOffset returns the offset of x into its containing page. 92 func HugePageOffset[T hugebytecount](x T) T { 93 return x & HugePageMask 94 } 95 96 // IsHugePageAligned returns true if x is a multiple of HugePageSize. 97 func IsHugePageAligned[T hugebytecount](x T) bool { 98 return HugePageOffset(x) == 0 99 } 100 101 // CacheLineRoundDown returns the offset rounded down to the nearest multiple 102 // of CacheLineSize. 103 func CacheLineRoundDown[T bytecount](x T) T { 104 return x &^ CacheLineMask 105 } 106 107 // CacheLineRoundUp returns the offset rounded up to the nearest multiple of 108 // CacheLineSize. ok is true iff rounding up does not overflow the range of T. 109 func CacheLineRoundUp[T bytecount](x T) (val T, ok bool) { 110 val = CacheLineRoundDown(x + CacheLineMask) 111 ok = val >= x 112 return 113 }