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