github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/platform/kvm/machine_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 go1.12 16 // +build !go1.18 17 18 // Check go:linkname function signatures when updating Go version. 19 20 package kvm 21 22 import ( 23 "fmt" 24 "math" 25 "sync/atomic" 26 "unsafe" 27 28 "golang.org/x/sys/unix" 29 "github.com/SagerNet/gvisor/pkg/abi/linux" 30 ) 31 32 //go:linkname entersyscall runtime.entersyscall 33 func entersyscall() 34 35 //go:linkname exitsyscall runtime.exitsyscall 36 func exitsyscall() 37 38 // setMemoryRegion initializes a region. 39 // 40 // This may be called from bluepillHandler, and therefore returns an errno 41 // directly (instead of wrapping in an error) to avoid allocations. 42 // 43 //go:nosplit 44 func (m *machine) setMemoryRegion(slot int, physical, length, virtual uintptr, flags uint32) unix.Errno { 45 userRegion := userMemoryRegion{ 46 slot: uint32(slot), 47 flags: uint32(flags), 48 guestPhysAddr: uint64(physical), 49 memorySize: uint64(length), 50 userspaceAddr: uint64(virtual), 51 } 52 53 // Set the region. 54 _, _, errno := unix.RawSyscall( 55 unix.SYS_IOCTL, 56 uintptr(m.fd), 57 _KVM_SET_USER_MEMORY_REGION, 58 uintptr(unsafe.Pointer(&userRegion))) 59 return errno 60 } 61 62 // mapRunData maps the vCPU run data. 63 func mapRunData(fd int) (*runData, error) { 64 r, _, errno := unix.RawSyscall6( 65 unix.SYS_MMAP, 66 0, 67 uintptr(runDataSize), 68 unix.PROT_READ|unix.PROT_WRITE, 69 unix.MAP_SHARED, 70 uintptr(fd), 71 0) 72 if errno != 0 { 73 return nil, fmt.Errorf("error mapping runData: %v", errno) 74 } 75 return (*runData)(unsafe.Pointer(r)), nil 76 } 77 78 // unmapRunData unmaps the vCPU run data. 79 func unmapRunData(r *runData) error { 80 if _, _, errno := unix.RawSyscall( 81 unix.SYS_MUNMAP, 82 uintptr(unsafe.Pointer(r)), 83 uintptr(runDataSize), 84 0); errno != 0 { 85 return fmt.Errorf("error unmapping runData: %v", errno) 86 } 87 return nil 88 } 89 90 // atomicAddressSpace is an atomic address space pointer. 91 type atomicAddressSpace struct { 92 pointer unsafe.Pointer 93 } 94 95 // set sets the address space value. 96 // 97 //go:nosplit 98 func (a *atomicAddressSpace) set(as *addressSpace) { 99 atomic.StorePointer(&a.pointer, unsafe.Pointer(as)) 100 } 101 102 // get gets the address space value. 103 // 104 // Note that this should be considered best-effort, and may have changed by the 105 // time this function returns. 106 // 107 //go:nosplit 108 func (a *atomicAddressSpace) get() *addressSpace { 109 return (*addressSpace)(atomic.LoadPointer(&a.pointer)) 110 } 111 112 // notify notifies that the vCPU has transitioned modes. 113 // 114 // This may be called by a signal handler and therefore throws on error. 115 // 116 //go:nosplit 117 func (c *vCPU) notify() { 118 _, _, errno := unix.RawSyscall6( // escapes: no. 119 unix.SYS_FUTEX, 120 uintptr(unsafe.Pointer(&c.state)), 121 linux.FUTEX_WAKE|linux.FUTEX_PRIVATE_FLAG, 122 math.MaxInt32, // Number of waiters. 123 0, 0, 0) 124 if errno != 0 { 125 throw("futex wake error") 126 } 127 } 128 129 // waitUntilNot waits for the vCPU to transition modes. 130 // 131 // The state should have been previously set to vCPUWaiter after performing an 132 // appropriate action to cause a transition (e.g. interrupt injection). 133 // 134 // This panics on error. 135 func (c *vCPU) waitUntilNot(state uint32) { 136 _, _, errno := unix.Syscall6( 137 unix.SYS_FUTEX, 138 uintptr(unsafe.Pointer(&c.state)), 139 linux.FUTEX_WAIT|linux.FUTEX_PRIVATE_FLAG, 140 uintptr(state), 141 0, 0, 0) 142 if errno != 0 && errno != unix.EINTR && errno != unix.EAGAIN { 143 panic("futex wait error") 144 } 145 } 146 147 // setSignalMask sets the vCPU signal mask. 148 // 149 // This must be called prior to running the vCPU. 150 func (c *vCPU) setSignalMask() error { 151 // The layout of this structure implies that it will not necessarily be 152 // the same layout chosen by the Go compiler. It gets fudged here. 153 var data struct { 154 length uint32 155 mask1 uint32 156 mask2 uint32 157 _ uint32 158 } 159 data.length = 8 // Fixed sigset size. 160 data.mask1 = ^uint32(bounceSignalMask & 0xffffffff) 161 data.mask2 = ^uint32(bounceSignalMask >> 32) 162 if _, _, errno := unix.RawSyscall( 163 unix.SYS_IOCTL, 164 uintptr(c.fd), 165 _KVM_SET_SIGNAL_MASK, 166 uintptr(unsafe.Pointer(&data))); errno != 0 { 167 return fmt.Errorf("error setting signal mask: %v", errno) 168 } 169 170 return nil 171 }