inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/hostarch/addr.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hostarch 16 17 import ( 18 "fmt" 19 ) 20 21 // Addr represents a generic virtual address. 22 // 23 // +stateify savable 24 type Addr uintptr 25 26 // AddLength adds the given length to start and returns the result. ok is true 27 // iff adding the length did not overflow the range of Addr. 28 // 29 // Note: This function is usually used to get the end of an address range 30 // defined by its start address and length. Since the resulting end is 31 // exclusive, end == 0 is technically valid, and corresponds to a range that 32 // extends to the end of the address space, but ok will be false. This isn't 33 // expected to ever come up in practice. 34 func (v Addr) AddLength(length uint64) (end Addr, ok bool) { 35 end = v + Addr(length) 36 // The second half of the following check is needed in case uintptr is 37 // smaller than 64 bits. 38 ok = end >= v && length <= uint64(^Addr(0)) 39 return 40 } 41 42 // RoundDown returns the address rounded down to the nearest page boundary. 43 func (v Addr) RoundDown() Addr { 44 return v & ^Addr(PageSize-1) 45 } 46 47 // RoundUp returns the address rounded up to the nearest page boundary. ok is 48 // true iff rounding up did not wrap around. 49 func (v Addr) RoundUp() (addr Addr, ok bool) { 50 addr = Addr(v + PageSize - 1).RoundDown() 51 ok = addr >= v 52 return 53 } 54 55 // MustRoundUp is equivalent to RoundUp, but panics if rounding up wraps 56 // around. 57 func (v Addr) MustRoundUp() Addr { 58 addr, ok := v.RoundUp() 59 if !ok { 60 panic(fmt.Sprintf("hostarch.Addr(%d).RoundUp() wraps", v)) 61 } 62 return addr 63 } 64 65 // HugeRoundDown returns the address rounded down to the nearest huge page 66 // boundary. 67 func (v Addr) HugeRoundDown() Addr { 68 return v & ^Addr(HugePageSize-1) 69 } 70 71 // HugeRoundUp returns the address rounded up to the nearest huge page boundary. 72 // ok is true iff rounding up did not wrap around. 73 func (v Addr) HugeRoundUp() (addr Addr, ok bool) { 74 addr = Addr(v + HugePageSize - 1).HugeRoundDown() 75 ok = addr >= v 76 return 77 } 78 79 // PageOffset returns the offset of v into the current page. 80 func (v Addr) PageOffset() uint64 { 81 return uint64(v & Addr(PageSize-1)) 82 } 83 84 // IsPageAligned returns true if v.PageOffset() == 0. 85 func (v Addr) IsPageAligned() bool { 86 return v.PageOffset() == 0 87 } 88 89 // AddrRange is a range of Addrs. 90 // 91 // type AddrRange <generated by go_generics> 92 93 // ToRange returns [v, v+length). 94 func (v Addr) ToRange(length uint64) (AddrRange, bool) { 95 end, ok := v.AddLength(length) 96 return AddrRange{v, end}, ok 97 } 98 99 // IsPageAligned returns true if ar.Start.IsPageAligned() and 100 // ar.End.IsPageAligned(). 101 func (ar AddrRange) IsPageAligned() bool { 102 return ar.Start.IsPageAligned() && ar.End.IsPageAligned() 103 } 104 105 // String implements fmt.Stringer.String. 106 func (ar AddrRange) String() string { 107 return fmt.Sprintf("[%#x, %#x)", ar.Start, ar.End) 108 } 109 110 // PageRoundDown/Up are equivalent to Addr.RoundDown/Up, but without the 111 // potentially truncating conversion from uint64 to Addr. This is necessary 112 // because there is no way to define generic "PageRoundDown/Up" functions in Go. 113 114 // PageRoundDown returns x rounded down to the nearest page boundary. 115 func PageRoundDown(x uint64) uint64 { 116 return x &^ (PageSize - 1) 117 } 118 119 // PageRoundUp returns x rounded up to the nearest page boundary. 120 // ok is true iff rounding up did not wrap around. 121 func PageRoundUp(x uint64) (addr uint64, ok bool) { 122 addr = PageRoundDown(x + PageSize - 1) 123 ok = addr >= x 124 return 125 }