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