github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/platform/kvm/bluepill_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 // +build amd64 16 17 package kvm 18 19 import ( 20 "golang.org/x/sys/unix" 21 "github.com/SagerNet/gvisor/pkg/ring0" 22 "github.com/SagerNet/gvisor/pkg/sentry/arch" 23 ) 24 25 var ( 26 // The action for bluepillSignal is changed by sigaction(). 27 bluepillSignal = unix.SIGSEGV 28 ) 29 30 // bluepillArchEnter is called during bluepillEnter. 31 // 32 //go:nosplit 33 func bluepillArchEnter(context *arch.SignalContext64) *vCPU { 34 c := vCPUPtr(uintptr(context.Rax)) 35 regs := c.CPU.Registers() 36 regs.R8 = context.R8 37 regs.R9 = context.R9 38 regs.R10 = context.R10 39 regs.R11 = context.R11 40 regs.R12 = context.R12 41 regs.R13 = context.R13 42 regs.R14 = context.R14 43 regs.R15 = context.R15 44 regs.Rdi = context.Rdi 45 regs.Rsi = context.Rsi 46 regs.Rbp = context.Rbp 47 regs.Rbx = context.Rbx 48 regs.Rdx = context.Rdx 49 regs.Rax = context.Rax 50 regs.Rcx = context.Rcx 51 regs.Rsp = context.Rsp 52 regs.Rip = context.Rip 53 regs.Eflags = context.Eflags 54 regs.Eflags &^= uint64(ring0.KernelFlagsClear) 55 regs.Eflags |= ring0.KernelFlagsSet 56 regs.Cs = uint64(ring0.Kcode) 57 regs.Ds = uint64(ring0.Udata) 58 regs.Es = uint64(ring0.Udata) 59 regs.Ss = uint64(ring0.Kdata) 60 return c 61 } 62 63 // KernelSyscall handles kernel syscalls. 64 // 65 // +checkescape:all 66 // 67 //go:nosplit 68 func (c *vCPU) KernelSyscall() { 69 regs := c.Registers() 70 if regs.Rax != ^uint64(0) { 71 regs.Rip -= 2 // Rewind. 72 } 73 // We only trigger a bluepill entry in the bluepill function, and can 74 // therefore be guaranteed that there is no floating point state to be 75 // loaded on resuming from halt. We only worry about saving on exit. 76 ring0.SaveFloatingPoint(c.floatingPointState.BytePointer()) // escapes: no. 77 ring0.Halt() 78 ring0.WriteFS(uintptr(regs.Fs_base)) // escapes: no, reload host segment. 79 } 80 81 // KernelException handles kernel exceptions. 82 // 83 // +checkescape:all 84 // 85 //go:nosplit 86 func (c *vCPU) KernelException(vector ring0.Vector) { 87 regs := c.Registers() 88 if vector == ring0.Vector(bounce) { 89 // These should not interrupt kernel execution; point the Rip 90 // to zero to ensure that we get a reasonable panic when we 91 // attempt to return and a full stack trace. 92 regs.Rip = 0 93 } 94 // See above. 95 ring0.SaveFloatingPoint(c.floatingPointState.BytePointer()) // escapes: no. 96 ring0.Halt() 97 ring0.WriteFS(uintptr(regs.Fs_base)) // escapes: no; reload host segment. 98 } 99 100 // bluepillArchExit is called during bluepillEnter. 101 // 102 //go:nosplit 103 func bluepillArchExit(c *vCPU, context *arch.SignalContext64) { 104 regs := c.CPU.Registers() 105 context.R8 = regs.R8 106 context.R9 = regs.R9 107 context.R10 = regs.R10 108 context.R11 = regs.R11 109 context.R12 = regs.R12 110 context.R13 = regs.R13 111 context.R14 = regs.R14 112 context.R15 = regs.R15 113 context.Rdi = regs.Rdi 114 context.Rsi = regs.Rsi 115 context.Rbp = regs.Rbp 116 context.Rbx = regs.Rbx 117 context.Rdx = regs.Rdx 118 context.Rax = regs.Rax 119 context.Rcx = regs.Rcx 120 context.Rsp = regs.Rsp 121 context.Rip = regs.Rip 122 context.Eflags = regs.Eflags 123 124 // Set the context pointer to the saved floating point state. This is 125 // where the guest data has been serialized, the kernel will restore 126 // from this new pointer value. 127 context.Fpstate = uint64(uintptrValue(c.floatingPointState.BytePointer())) 128 }