github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/ring0/pagetables/pagetables_x86.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 // +build 386 amd64 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 // pcid is the value assigned by PCIDs.Assign. 28 // 29 // Note that zero is a valid PCID. 30 pcid uint16 31 } 32 33 // CR3 returns the CR3 value for these tables. 34 // 35 // This may be called in interrupt contexts. A PCID of zero always implies a 36 // flush and should be passed when PCIDs are not enabled. See pcids_x86.go for 37 // more information. 38 // 39 //go:nosplit 40 func (p *PageTables) CR3(noFlush bool, pcid uint16) uint64 { 41 // Bit 63 is set to avoid flushing the PCID (per SDM 4.10.4.1). 42 const noFlushBit uint64 = 0x8000000000000000 43 if noFlush && pcid != 0 { 44 return noFlushBit | uint64(p.rootPhysical) | uint64(pcid) 45 } 46 return uint64(p.rootPhysical) | uint64(pcid) 47 } 48 49 // Bits in page table entries. 50 const ( 51 present = 0x001 52 writable = 0x002 53 user = 0x004 54 writeThrough = 0x008 55 cacheDisable = 0x010 56 accessed = 0x020 57 dirty = 0x040 58 super = 0x080 59 global = 0x100 60 optionMask = executeDisable | 0xfff 61 ) 62 63 // MapOpts are x86 options. 64 type MapOpts struct { 65 // AccessType defines permissions. 66 AccessType hostarch.AccessType 67 68 // Global indicates the page is globally accessible. 69 Global bool 70 71 // User indicates the page is a user page. 72 User bool 73 } 74 75 // PTE is a page table entry. 76 type PTE uintptr 77 78 // Clear clears this PTE, including super page information. 79 // 80 //go:nosplit 81 func (p *PTE) Clear() { 82 atomic.StoreUintptr((*uintptr)(p), 0) 83 } 84 85 // Valid returns true iff this entry is valid. 86 // 87 //go:nosplit 88 func (p *PTE) Valid() bool { 89 return atomic.LoadUintptr((*uintptr)(p))&present != 0 90 } 91 92 // Opts returns the PTE options. 93 // 94 // These are all options except Valid and Super. 95 // 96 //go:nosplit 97 func (p *PTE) Opts() MapOpts { 98 v := atomic.LoadUintptr((*uintptr)(p)) 99 return MapOpts{ 100 AccessType: hostarch.AccessType{ 101 Read: v&present != 0, 102 Write: v&writable != 0, 103 Execute: v&executeDisable == 0, 104 }, 105 Global: v&global != 0, 106 User: v&user != 0, 107 } 108 } 109 110 // SetSuper sets this page as a super page. 111 // 112 // The page must not be valid or a panic will result. 113 // 114 //go:nosplit 115 func (p *PTE) SetSuper() { 116 if p.Valid() { 117 // This is not allowed. 118 panic("SetSuper called on valid page!") 119 } 120 atomic.StoreUintptr((*uintptr)(p), super) 121 } 122 123 // IsSuper returns true iff this page is a super page. 124 // 125 //go:nosplit 126 func (p *PTE) IsSuper() bool { 127 return atomic.LoadUintptr((*uintptr)(p))&super != 0 128 } 129 130 // Set sets this PTE value. 131 // 132 // This does not change the super page property. 133 // 134 //go:nosplit 135 func (p *PTE) Set(addr uintptr, opts MapOpts) { 136 if !opts.AccessType.Any() { 137 p.Clear() 138 return 139 } 140 v := (addr &^ optionMask) 141 if opts.AccessType.Any() { 142 v |= present | accessed 143 } 144 if opts.User { 145 v |= user 146 } 147 if opts.Global { 148 v |= global 149 } 150 if !opts.AccessType.Execute { 151 v |= executeDisable 152 } 153 if opts.AccessType.Write { 154 v |= writable | dirty 155 } 156 if p.IsSuper() { 157 // Note that this is inherited from the previous instance. Set 158 // does not change the value of Super. See above. 159 v |= super 160 } 161 atomic.StoreUintptr((*uintptr)(p), v) 162 } 163 164 // setPageTable sets this PTE value and forces the write bit and super bit to 165 // be cleared. This is used explicitly for breaking super pages. 166 // 167 //go:nosplit 168 func (p *PTE) setPageTable(pt *PageTables, ptes *PTEs) { 169 addr := pt.Allocator.PhysicalFor(ptes) 170 if addr&^optionMask != addr { 171 // This should never happen. 172 panic("unaligned physical address!") 173 } 174 v := addr | present | user | writable | accessed | dirty 175 atomic.StoreUintptr((*uintptr)(p), v) 176 } 177 178 // Address extracts the address. This should only be used if Valid returns true. 179 // 180 //go:nosplit 181 func (p *PTE) Address() uintptr { 182 return atomic.LoadUintptr((*uintptr)(p)) &^ optionMask 183 }