github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/platform/kvm/kvm_amd64.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 amd64 16 // +build amd64 17 18 package kvm 19 20 import ( 21 "github.com/nicocha30/gvisor-ligolo/pkg/cpuid" 22 "github.com/nicocha30/gvisor-ligolo/pkg/ring0" 23 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch/fpu" 24 ) 25 26 // userRegs represents KVM user registers. 27 // 28 // This mirrors kvm_regs. 29 type userRegs struct { 30 RAX uint64 31 RBX uint64 32 RCX uint64 33 RDX uint64 34 RSI uint64 35 RDI uint64 36 RSP uint64 37 RBP uint64 38 R8 uint64 39 R9 uint64 40 R10 uint64 41 R11 uint64 42 R12 uint64 43 R13 uint64 44 R14 uint64 45 R15 uint64 46 RIP uint64 47 RFLAGS uint64 48 } 49 50 // systemRegs represents KVM system registers. 51 // 52 // This mirrors kvm_sregs. 53 type systemRegs struct { 54 CS segment 55 DS segment 56 ES segment 57 FS segment 58 GS segment 59 SS segment 60 TR segment 61 LDT segment 62 GDT descriptor 63 IDT descriptor 64 CR0 uint64 65 CR2 uint64 66 CR3 uint64 67 CR4 uint64 68 CR8 uint64 69 EFER uint64 70 apicBase uint64 71 interruptBitmap [(_KVM_NR_INTERRUPTS + 63) / 64]uint64 72 } 73 74 // segment is the expanded form of a segment register. 75 // 76 // This mirrors kvm_segment. 77 type segment struct { 78 base uint64 79 limit uint32 80 selector uint16 81 typ uint8 82 present uint8 83 DPL uint8 84 DB uint8 85 S uint8 86 L uint8 87 G uint8 88 AVL uint8 89 unusable uint8 90 _ uint8 91 } 92 93 // Clear clears the segment and marks it unusable. 94 func (s *segment) Clear() { 95 *s = segment{unusable: 1} 96 } 97 98 // selector is a segment selector. 99 type selector uint16 100 101 // tobool is a simple helper. 102 func tobool(x ring0.SegmentDescriptorFlags) uint8 { 103 if x != 0 { 104 return 1 105 } 106 return 0 107 } 108 109 // Load loads the segment described by d into the segment s. 110 // 111 // The argument sel is recorded as the segment selector index. 112 func (s *segment) Load(d *ring0.SegmentDescriptor, sel ring0.Selector) { 113 flag := d.Flags() 114 if flag&ring0.SegmentDescriptorPresent == 0 { 115 s.Clear() 116 return 117 } 118 s.base = uint64(d.Base()) 119 s.limit = d.Limit() 120 s.typ = uint8((flag>>8)&0xF) | 1 121 s.S = tobool(flag & ring0.SegmentDescriptorSystem) 122 s.DPL = uint8(d.DPL()) 123 s.present = tobool(flag & ring0.SegmentDescriptorPresent) 124 s.AVL = tobool(flag & ring0.SegmentDescriptorAVL) 125 s.L = tobool(flag & ring0.SegmentDescriptorLong) 126 s.DB = tobool(flag & ring0.SegmentDescriptorDB) 127 s.G = tobool(flag & ring0.SegmentDescriptorG) 128 if s.L != 0 { 129 s.limit = 0xffffffff 130 } 131 s.unusable = 0 132 s.selector = uint16(sel) 133 } 134 135 // descriptor describes a region of physical memory. 136 // 137 // It corresponds to the pseudo-descriptor used in the x86 LGDT and LIDT 138 // instructions, and mirrors kvm_dtable. 139 type descriptor struct { 140 base uint64 141 limit uint16 142 _ [3]uint16 143 } 144 145 // modelControlRegister is an MSR entry. 146 // 147 // This mirrors kvm_msr_entry. 148 type modelControlRegister struct { 149 index uint32 150 _ uint32 151 data uint64 152 } 153 154 // modelControlRegisers is a collection of MSRs. 155 // 156 // This mirrors kvm_msrs. 157 type modelControlRegisters struct { 158 nmsrs uint32 159 _ uint32 160 entries [16]modelControlRegister 161 } 162 163 // cpuidEntry is a single CPUID entry. 164 // 165 // This mirrors kvm_cpuid_entry2. 166 type cpuidEntry struct { 167 function uint32 168 index uint32 169 flags uint32 170 eax uint32 171 ebx uint32 172 ecx uint32 173 edx uint32 174 _ [3]uint32 175 } 176 177 // cpuidEntries is a collection of CPUID entries. 178 // 179 // This mirrors kvm_cpuid2. 180 type cpuidEntries struct { 181 nr uint32 182 _ uint32 183 entries [_KVM_NR_CPUID_ENTRIES]cpuidEntry 184 } 185 186 // Query implements cpuid.Function.Query. 187 func (c *cpuidEntries) Query(in cpuid.In) (out cpuid.Out) { 188 for i := 0; i < int(c.nr); i++ { 189 if c.entries[i].function == in.Eax && c.entries[i].index == in.Ecx { 190 out.Eax = c.entries[i].eax 191 out.Ebx = c.entries[i].ebx 192 out.Ecx = c.entries[i].ecx 193 out.Edx = c.entries[i].edx 194 return 195 } 196 } 197 return 198 } 199 200 // Set implements cpuid.ChangeableSet.Set. 201 func (c *cpuidEntries) Set(in cpuid.In, out cpuid.Out) { 202 i := 0 203 for ; i < int(c.nr); i++ { 204 if c.entries[i].function == in.Eax && c.entries[i].index == in.Ecx { 205 break 206 } 207 } 208 if i == _KVM_NR_CPUID_ENTRIES { 209 panic("exceeded KVM_NR_CPUID_ENTRIES") 210 } 211 212 c.entries[i].eax = out.Eax 213 c.entries[i].ebx = out.Ebx 214 c.entries[i].ecx = out.Ecx 215 c.entries[i].edx = out.Edx 216 if i == int(c.nr) { 217 c.nr++ 218 } 219 } 220 221 // updateGlobalOnce does global initialization. It has to be called only once. 222 func updateGlobalOnce(fd int) error { 223 fpu.InitHostState() 224 bitsForScaling = getBitsForScaling() 225 if err := updateSystemValues(int(fd)); err != nil { 226 return err 227 } 228 fs := cpuid.FeatureSet{ 229 Function: &cpuidSupported, 230 } 231 // Calculate whether guestPCID is supported. 232 hasGuestPCID = fs.HasFeature(cpuid.X86FeaturePCID) 233 // Create a static feature set from the KVM entries. Then, we 234 // explicitly set OSXSAVE, since this does not come in the feature 235 // entries, but can be provided when the relevant CR4 bit is set. 236 s := &cpuidSupported 237 cpuid.X86FeatureOSXSAVE.Set(s) 238 // Explicitly disable nested virtualization. Since we don't provide 239 // any virtualization APIs, there is no need to enable this feature. 240 cpuid.X86FeatureVMX.Unset(s) 241 cpuid.X86FeatureSVM.Unset(s) 242 ring0.Init(cpuid.FeatureSet{ 243 Function: s, 244 }) 245 physicalInit() 246 return nil 247 }