github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/platform/kvm/machine_amd64_unsafe.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 amd64 16 17 package kvm 18 19 import ( 20 "fmt" 21 "sync/atomic" 22 "unsafe" 23 24 "golang.org/x/sys/unix" 25 "github.com/SagerNet/gvisor/pkg/abi/linux" 26 ) 27 28 // loadSegments copies the current segments. 29 // 30 // This may be called from within the signal context and throws on error. 31 // 32 //go:nosplit 33 func (c *vCPU) loadSegments(tid uint64) { 34 if _, _, errno := unix.RawSyscall( 35 unix.SYS_ARCH_PRCTL, 36 linux.ARCH_GET_FS, 37 uintptr(unsafe.Pointer(&c.CPU.Registers().Fs_base)), 38 0); errno != 0 { 39 throw("getting FS segment") 40 } 41 if _, _, errno := unix.RawSyscall( 42 unix.SYS_ARCH_PRCTL, 43 linux.ARCH_GET_GS, 44 uintptr(unsafe.Pointer(&c.CPU.Registers().Gs_base)), 45 0); errno != 0 { 46 throw("getting GS segment") 47 } 48 atomic.StoreUint64(&c.tid, tid) 49 } 50 51 // setCPUID sets the CPUID to be used by the guest. 52 func (c *vCPU) setCPUID() error { 53 if _, _, errno := unix.RawSyscall( 54 unix.SYS_IOCTL, 55 uintptr(c.fd), 56 _KVM_SET_CPUID2, 57 uintptr(unsafe.Pointer(&cpuidSupported))); errno != 0 { 58 return fmt.Errorf("error setting CPUID: %v", errno) 59 } 60 return nil 61 } 62 63 // getTSCFreq gets the TSC frequency. 64 // 65 // If mustSucceed is true, then this function panics on error. 66 func (c *vCPU) getTSCFreq() (uintptr, error) { 67 rawFreq, _, errno := unix.RawSyscall( 68 unix.SYS_IOCTL, 69 uintptr(c.fd), 70 _KVM_GET_TSC_KHZ, 71 0 /* ignored */) 72 if errno != 0 { 73 return 0, errno 74 } 75 return rawFreq, nil 76 } 77 78 // setTSCFreq sets the TSC frequency. 79 func (c *vCPU) setTSCFreq(freq uintptr) error { 80 if _, _, errno := unix.RawSyscall( 81 unix.SYS_IOCTL, 82 uintptr(c.fd), 83 _KVM_SET_TSC_KHZ, 84 freq /* khz */); errno != 0 { 85 return fmt.Errorf("error setting TSC frequency: %v", errno) 86 } 87 return nil 88 } 89 90 // setTSC sets the TSC value. 91 func (c *vCPU) setTSC(value uint64) error { 92 const _MSR_IA32_TSC = 0x00000010 93 registers := modelControlRegisters{ 94 nmsrs: 1, 95 } 96 registers.entries[0].index = _MSR_IA32_TSC 97 registers.entries[0].data = value 98 if _, _, errno := unix.RawSyscall( 99 unix.SYS_IOCTL, 100 uintptr(c.fd), 101 _KVM_SET_MSRS, 102 uintptr(unsafe.Pointer(®isters))); errno != 0 { 103 return fmt.Errorf("error setting tsc: %v", errno) 104 } 105 return nil 106 } 107 108 // setUserRegisters sets user registers in the vCPU. 109 // 110 //go:nosplit 111 func (c *vCPU) setUserRegisters(uregs *userRegs) unix.Errno { 112 if _, _, errno := unix.RawSyscall( 113 unix.SYS_IOCTL, 114 uintptr(c.fd), 115 _KVM_SET_REGS, 116 uintptr(unsafe.Pointer(uregs))); errno != 0 { 117 return errno 118 } 119 return 0 120 } 121 122 // getUserRegisters reloads user registers in the vCPU. 123 // 124 // This is safe to call from a nosplit context. 125 // 126 //go:nosplit 127 func (c *vCPU) getUserRegisters(uregs *userRegs) unix.Errno { 128 if _, _, errno := unix.RawSyscall( // escapes: no. 129 unix.SYS_IOCTL, 130 uintptr(c.fd), 131 _KVM_GET_REGS, 132 uintptr(unsafe.Pointer(uregs))); errno != 0 { 133 return errno 134 } 135 return 0 136 } 137 138 // setSystemRegisters sets system registers. 139 func (c *vCPU) setSystemRegisters(sregs *systemRegs) error { 140 if _, _, errno := unix.RawSyscall( 141 unix.SYS_IOCTL, 142 uintptr(c.fd), 143 _KVM_SET_SREGS, 144 uintptr(unsafe.Pointer(sregs))); errno != 0 { 145 return fmt.Errorf("error setting system registers: %v", errno) 146 } 147 return nil 148 } 149 150 // getSystemRegisters sets system registers. 151 // 152 //go:nosplit 153 func (c *vCPU) getSystemRegisters(sregs *systemRegs) unix.Errno { 154 if _, _, errno := unix.RawSyscall( 155 unix.SYS_IOCTL, 156 uintptr(c.fd), 157 _KVM_GET_SREGS, 158 uintptr(unsafe.Pointer(sregs))); errno != 0 { 159 return errno 160 } 161 return 0 162 }