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  }