github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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  }