github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/platform/kvm/bluepill_arm64.go (about) 1 // Copyright 2019 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 arm64 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.SIGILL 28 ) 29 30 // getTLS returns the value of TPIDR_EL0 register. 31 // 32 //go:nosplit 33 func getTLS() (value uint64) 34 35 // setTLS writes the TPIDR_EL0 value. 36 // 37 //go:nosplit 38 func setTLS(value uint64) 39 40 // bluepillArchEnter is called during bluepillEnter. 41 // 42 //go:nosplit 43 func bluepillArchEnter(context *arch.SignalContext64) (c *vCPU) { 44 c = vCPUPtr(uintptr(context.Regs[8])) 45 regs := c.CPU.Registers() 46 regs.Regs = context.Regs 47 regs.Sp = context.Sp 48 regs.Pc = context.Pc 49 regs.Pstate = context.Pstate 50 regs.Pstate &^= uint64(ring0.PsrFlagsClear) 51 regs.Pstate |= ring0.KernelFlagsSet 52 regs.TPIDR_EL0 = getTLS() 53 54 return 55 } 56 57 // bluepillArchExit is called during bluepillEnter. 58 // 59 //go:nosplit 60 func bluepillArchExit(c *vCPU, context *arch.SignalContext64) { 61 regs := c.CPU.Registers() 62 context.Regs = regs.Regs 63 context.Sp = regs.Sp 64 context.Pc = regs.Pc 65 context.Pstate = regs.Pstate 66 context.Pstate &^= uint64(ring0.PsrFlagsClear) 67 context.Pstate |= ring0.UserFlagsSet 68 setTLS(regs.TPIDR_EL0) 69 70 lazyVfp := c.GetLazyVFP() 71 if lazyVfp != 0 { 72 fpsimd := fpsimdPtr(c.floatingPointState.BytePointer()) 73 context.Fpsimd64.Fpsr = fpsimd.Fpsr 74 context.Fpsimd64.Fpcr = fpsimd.Fpcr 75 context.Fpsimd64.Vregs = fpsimd.Vregs 76 } 77 } 78 79 // KernelSyscall handles kernel syscalls. 80 // 81 // +checkescape:all 82 // 83 //go:nosplit 84 func (c *vCPU) KernelSyscall() { 85 regs := c.Registers() 86 if regs.Regs[8] != ^uint64(0) { 87 regs.Pc -= 4 // Rewind. 88 } 89 90 fpDisableTrap := ring0.CPACREL1() 91 if fpDisableTrap != 0 { 92 fpsimd := fpsimdPtr(c.floatingPointState.BytePointer()) 93 fpcr := ring0.GetFPCR() 94 fpsr := ring0.GetFPSR() 95 fpsimd.Fpcr = uint32(fpcr) 96 fpsimd.Fpsr = uint32(fpsr) 97 ring0.SaveVRegs(c.floatingPointState.BytePointer()) 98 } 99 100 ring0.Halt() 101 } 102 103 // KernelException handles kernel exceptions. 104 // 105 // +checkescape:all 106 // 107 //go:nosplit 108 func (c *vCPU) KernelException(vector ring0.Vector) { 109 regs := c.Registers() 110 if vector == ring0.Vector(bounce) { 111 regs.Pc = 0 112 } 113 114 fpDisableTrap := ring0.CPACREL1() 115 if fpDisableTrap != 0 { 116 fpsimd := fpsimdPtr(c.floatingPointState.BytePointer()) 117 fpcr := ring0.GetFPCR() 118 fpsr := ring0.GetFPSR() 119 fpsimd.Fpcr = uint32(fpcr) 120 fpsimd.Fpsr = uint32(fpsr) 121 ring0.SaveVRegs(c.floatingPointState.BytePointer()) 122 } 123 124 ring0.Halt() 125 }