github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/platform/kvm/machine_amd64_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 amd64
    16  
    17  package kvm
    18  
    19  import (
    20  	"fmt"
    21  	"sync/atomic"
    22  	"unsafe"
    23  
    24  	"golang.org/x/sys/unix"
    25  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    26  )
    27  
    28  // loadSegments copies the current segments.
    29  //
    30  // This may be called from within the signal context and throws on error.
    31  //
    32  //go:nosplit
    33  func (c *vCPU) loadSegments(tid uint64) {
    34  	if _, _, errno := unix.RawSyscall(
    35  		unix.SYS_ARCH_PRCTL,
    36  		linux.ARCH_GET_FS,
    37  		uintptr(unsafe.Pointer(&c.CPU.Registers().Fs_base)),
    38  		0); errno != 0 {
    39  		throw("getting FS segment")
    40  	}
    41  	if _, _, errno := unix.RawSyscall(
    42  		unix.SYS_ARCH_PRCTL,
    43  		linux.ARCH_GET_GS,
    44  		uintptr(unsafe.Pointer(&c.CPU.Registers().Gs_base)),
    45  		0); errno != 0 {
    46  		throw("getting GS segment")
    47  	}
    48  	atomic.StoreUint64(&c.tid, tid)
    49  }
    50  
    51  // setCPUID sets the CPUID to be used by the guest.
    52  func (c *vCPU) setCPUID() error {
    53  	if _, _, errno := unix.RawSyscall(
    54  		unix.SYS_IOCTL,
    55  		uintptr(c.fd),
    56  		_KVM_SET_CPUID2,
    57  		uintptr(unsafe.Pointer(&cpuidSupported))); errno != 0 {
    58  		return fmt.Errorf("error setting CPUID: %v", errno)
    59  	}
    60  	return nil
    61  }
    62  
    63  // getTSCFreq gets the TSC frequency.
    64  //
    65  // If mustSucceed is true, then this function panics on error.
    66  func (c *vCPU) getTSCFreq() (uintptr, error) {
    67  	rawFreq, _, errno := unix.RawSyscall(
    68  		unix.SYS_IOCTL,
    69  		uintptr(c.fd),
    70  		_KVM_GET_TSC_KHZ,
    71  		0 /* ignored */)
    72  	if errno != 0 {
    73  		return 0, errno
    74  	}
    75  	return rawFreq, nil
    76  }
    77  
    78  // setTSCFreq sets the TSC frequency.
    79  func (c *vCPU) setTSCFreq(freq uintptr) error {
    80  	if _, _, errno := unix.RawSyscall(
    81  		unix.SYS_IOCTL,
    82  		uintptr(c.fd),
    83  		_KVM_SET_TSC_KHZ,
    84  		freq /* khz */); errno != 0 {
    85  		return fmt.Errorf("error setting TSC frequency: %v", errno)
    86  	}
    87  	return nil
    88  }
    89  
    90  // setTSC sets the TSC value.
    91  func (c *vCPU) setTSC(value uint64) error {
    92  	const _MSR_IA32_TSC = 0x00000010
    93  	registers := modelControlRegisters{
    94  		nmsrs: 1,
    95  	}
    96  	registers.entries[0].index = _MSR_IA32_TSC
    97  	registers.entries[0].data = value
    98  	if _, _, errno := unix.RawSyscall(
    99  		unix.SYS_IOCTL,
   100  		uintptr(c.fd),
   101  		_KVM_SET_MSRS,
   102  		uintptr(unsafe.Pointer(&registers))); errno != 0 {
   103  		return fmt.Errorf("error setting tsc: %v", errno)
   104  	}
   105  	return nil
   106  }
   107  
   108  // setUserRegisters sets user registers in the vCPU.
   109  //
   110  //go:nosplit
   111  func (c *vCPU) setUserRegisters(uregs *userRegs) unix.Errno {
   112  	if _, _, errno := unix.RawSyscall(
   113  		unix.SYS_IOCTL,
   114  		uintptr(c.fd),
   115  		_KVM_SET_REGS,
   116  		uintptr(unsafe.Pointer(uregs))); errno != 0 {
   117  		return errno
   118  	}
   119  	return 0
   120  }
   121  
   122  // getUserRegisters reloads user registers in the vCPU.
   123  //
   124  // This is safe to call from a nosplit context.
   125  //
   126  //go:nosplit
   127  func (c *vCPU) getUserRegisters(uregs *userRegs) unix.Errno {
   128  	if _, _, errno := unix.RawSyscall( // escapes: no.
   129  		unix.SYS_IOCTL,
   130  		uintptr(c.fd),
   131  		_KVM_GET_REGS,
   132  		uintptr(unsafe.Pointer(uregs))); errno != 0 {
   133  		return errno
   134  	}
   135  	return 0
   136  }
   137  
   138  // setSystemRegisters sets system registers.
   139  func (c *vCPU) setSystemRegisters(sregs *systemRegs) error {
   140  	if _, _, errno := unix.RawSyscall(
   141  		unix.SYS_IOCTL,
   142  		uintptr(c.fd),
   143  		_KVM_SET_SREGS,
   144  		uintptr(unsafe.Pointer(sregs))); errno != 0 {
   145  		return fmt.Errorf("error setting system registers: %v", errno)
   146  	}
   147  	return nil
   148  }
   149  
   150  // getSystemRegisters sets system registers.
   151  //
   152  //go:nosplit
   153  func (c *vCPU) getSystemRegisters(sregs *systemRegs) unix.Errno {
   154  	if _, _, errno := unix.RawSyscall(
   155  		unix.SYS_IOCTL,
   156  		uintptr(c.fd),
   157  		_KVM_GET_SREGS,
   158  		uintptr(unsafe.Pointer(sregs))); errno != 0 {
   159  		return errno
   160  	}
   161  	return 0
   162  }