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  }