github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/ring0/pagetables/pagetables_aarch64.go (about) 1 // Copyright 2019 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 // +build arm64 16 17 package pagetables 18 19 import ( 20 "sync/atomic" 21 22 "github.com/SagerNet/gvisor/pkg/hostarch" 23 ) 24 25 // archPageTables is architecture-specific data. 26 type archPageTables struct { 27 // root is the pagetable root for kernel space. 28 root *PTEs 29 30 // rootPhysical is the cached physical address of the root. 31 // 32 // This is saved only to prevent constant translation. 33 rootPhysical uintptr 34 35 asid uint16 36 } 37 38 // TTBR0_EL1 returns the translation table base register 0. 39 // 40 //go:nosplit 41 func (p *PageTables) TTBR0_EL1(noFlush bool, asid uint16) uint64 { 42 return uint64(p.rootPhysical) | (uint64(asid)&ttbrASIDMask)<<ttbrASIDOffset 43 } 44 45 // TTBR1_EL1 returns the translation table base register 1. 46 // 47 //go:nosplit 48 func (p *PageTables) TTBR1_EL1(noFlush bool, asid uint16) uint64 { 49 return uint64(p.archPageTables.rootPhysical) | (uint64(asid)&ttbrASIDMask)<<ttbrASIDOffset 50 } 51 52 // Bits in page table entries. 53 const ( 54 typeTable = 0x3 << 0 55 typeSect = 0x1 << 0 56 typePage = 0x3 << 0 57 pteValid = 0x1 << 0 58 pteTableBit = 0x1 << 1 59 pteTypeMask = 0x3 << 0 60 present = pteValid | pteTableBit 61 user = 0x1 << 6 /* AP[1] */ 62 readOnly = 0x1 << 7 /* AP[2] */ 63 accessed = 0x1 << 10 64 dbm = 0x1 << 51 65 writable = dbm 66 cont = 0x1 << 52 67 pxn = 0x1 << 53 68 xn = 0x1 << 54 69 dirty = 0x1 << 55 70 nG = 0x1 << 11 71 shared = 0x3 << 8 72 ) 73 74 const ( 75 mtDevicenGnRE = 0x1 << 2 76 mtNormal = 0x4 << 2 77 ) 78 79 const ( 80 executeDisable = xn 81 optionMask = 0xfff | 0xffff<<48 82 protDefault = accessed | shared 83 ) 84 85 // MapOpts are x86 options. 86 type MapOpts struct { 87 // AccessType defines permissions. 88 AccessType hostarch.AccessType 89 90 // Global indicates the page is globally accessible. 91 Global bool 92 93 // User indicates the page is a user page. 94 User bool 95 } 96 97 // PTE is a page table entry. 98 type PTE uintptr 99 100 // Clear clears this PTE, including sect page information. 101 // 102 //go:nosplit 103 func (p *PTE) Clear() { 104 atomic.StoreUintptr((*uintptr)(p), 0) 105 } 106 107 // Valid returns true iff this entry is valid. 108 // 109 //go:nosplit 110 func (p *PTE) Valid() bool { 111 return atomic.LoadUintptr((*uintptr)(p))&present != 0 112 } 113 114 // Opts returns the PTE options. 115 // 116 // These are all options except Valid and Sect. 117 // 118 //go:nosplit 119 func (p *PTE) Opts() MapOpts { 120 v := atomic.LoadUintptr((*uintptr)(p)) 121 122 return MapOpts{ 123 AccessType: hostarch.AccessType{ 124 Read: true, 125 Write: v&readOnly == 0, 126 Execute: v&xn == 0, 127 }, 128 Global: v&nG == 0, 129 User: v&user != 0, 130 } 131 } 132 133 // SetSect sets this page as a sect page. 134 // 135 // The page must not be valid or a panic will result. 136 // 137 //go:nosplit 138 func (p *PTE) SetSect() { 139 if p.Valid() { 140 // This is not allowed. 141 panic("SetSect called on valid page!") 142 } 143 atomic.StoreUintptr((*uintptr)(p), typeSect) 144 } 145 146 // IsSect returns true iff this page is a sect page. 147 // 148 //go:nosplit 149 func (p *PTE) IsSect() bool { 150 return atomic.LoadUintptr((*uintptr)(p))&pteTypeMask == typeSect 151 } 152 153 // Set sets this PTE value. 154 // 155 // This does not change the sect page property. 156 // 157 //go:nosplit 158 func (p *PTE) Set(addr uintptr, opts MapOpts) { 159 v := (addr &^ optionMask) | nG | readOnly | protDefault 160 if p.IsSect() { 161 // Note that this is inherited from the previous instance. Set 162 // does not change the value of Sect. See above. 163 v |= typeSect 164 } else { 165 v |= typePage 166 } 167 if !opts.AccessType.Any() { 168 // Leave as non-valid if no access is available. 169 v &^= pteValid 170 } 171 172 if opts.Global { 173 v = v &^ nG 174 } 175 176 if opts.AccessType.Execute { 177 v = v &^ executeDisable 178 } else { 179 v |= executeDisable 180 } 181 if opts.AccessType.Write { 182 v = v &^ readOnly 183 } 184 185 if opts.User { 186 v |= user 187 v |= mtNormal 188 } else { 189 v = v &^ user 190 v |= mtNormal 191 } 192 atomic.StoreUintptr((*uintptr)(p), v) 193 } 194 195 // setPageTable sets this PTE value and forces the write bit and sect bit to 196 // be cleared. This is used explicitly for breaking sect pages. 197 // 198 //go:nosplit 199 func (p *PTE) setPageTable(pt *PageTables, ptes *PTEs) { 200 addr := pt.Allocator.PhysicalFor(ptes) 201 if addr&^optionMask != addr { 202 // This should never happen. 203 panic("unaligned physical address!") 204 } 205 v := addr | typeTable | protDefault | mtNormal 206 atomic.StoreUintptr((*uintptr)(p), v) 207 } 208 209 // Address extracts the address. This should only be used if Valid returns true. 210 // 211 //go:nosplit 212 func (p *PTE) Address() uintptr { 213 return atomic.LoadUintptr((*uintptr)(p)) &^ optionMask 214 }