gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  //go:build amd64
    16  // +build amd64
    17  
    18  package kvm
    19  
    20  import (
    21  	"fmt"
    22  	"unsafe"
    23  
    24  	"golang.org/x/sys/unix"
    25  	"gvisor.dev/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  	c.tid.Store(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  // setTSCOffset sets the TSC offset to zero.
    91  func (c *vCPU) setTSCOffset() error {
    92  	offset := uint64(0)
    93  	da := struct {
    94  		flags uint32
    95  		group uint32
    96  		attr  uint64
    97  		addr  unsafe.Pointer
    98  	}{
    99  		group: _KVM_VCPU_TSC_CTRL,
   100  		attr:  _KVM_VCPU_TSC_OFFSET,
   101  		addr:  unsafe.Pointer(&offset),
   102  	}
   103  	if _, _, errno := unix.RawSyscall(
   104  		unix.SYS_IOCTL,
   105  		uintptr(c.fd),
   106  		KVM_SET_DEVICE_ATTR,
   107  		uintptr(unsafe.Pointer(&da))); errno != 0 {
   108  		return fmt.Errorf("error setting tsc offset: %v", errno)
   109  	}
   110  	return nil
   111  }
   112  
   113  // setTSC sets the TSC value.
   114  func (c *vCPU) setTSC(value uint64) error {
   115  	const _MSR_IA32_TSC = 0x00000010
   116  	registers := modelControlRegisters{
   117  		nmsrs: 1,
   118  	}
   119  	registers.entries[0].index = _MSR_IA32_TSC
   120  	registers.entries[0].data = value
   121  	if _, _, errno := unix.RawSyscall(
   122  		unix.SYS_IOCTL,
   123  		uintptr(c.fd),
   124  		KVM_SET_MSRS,
   125  		uintptr(unsafe.Pointer(&registers))); errno != 0 {
   126  		return fmt.Errorf("error setting tsc: %v", errno)
   127  	}
   128  	return nil
   129  }
   130  
   131  // setUserRegisters sets user registers in the vCPU.
   132  //
   133  //go:nosplit
   134  func (c *vCPU) setUserRegisters(uregs *userRegs) unix.Errno {
   135  	if _, _, errno := unix.RawSyscall(
   136  		unix.SYS_IOCTL,
   137  		uintptr(c.fd),
   138  		KVM_SET_REGS,
   139  		uintptr(unsafe.Pointer(uregs))); errno != 0 {
   140  		return errno
   141  	}
   142  	return 0
   143  }
   144  
   145  // getUserRegisters reloads user registers in the vCPU.
   146  //
   147  // This is safe to call from a nosplit context.
   148  //
   149  //go:nosplit
   150  func (c *vCPU) getUserRegisters(uregs *userRegs) unix.Errno {
   151  	if _, _, errno := unix.RawSyscall( // escapes: no.
   152  		unix.SYS_IOCTL,
   153  		uintptr(c.fd),
   154  		KVM_GET_REGS,
   155  		uintptr(unsafe.Pointer(uregs))); errno != 0 {
   156  		return errno
   157  	}
   158  	return 0
   159  }
   160  
   161  // setSystemRegisters sets system registers.
   162  func (c *vCPU) setSystemRegisters(sregs *systemRegs) error {
   163  	if _, _, errno := unix.RawSyscall(
   164  		unix.SYS_IOCTL,
   165  		uintptr(c.fd),
   166  		KVM_SET_SREGS,
   167  		uintptr(unsafe.Pointer(sregs))); errno != 0 {
   168  		return fmt.Errorf("error setting system registers: %v", errno)
   169  	}
   170  	return nil
   171  }
   172  
   173  // getSystemRegisters sets system registers.
   174  //
   175  //go:nosplit
   176  func (c *vCPU) getSystemRegisters(sregs *systemRegs) unix.Errno {
   177  	if _, _, errno := unix.RawSyscall(
   178  		unix.SYS_IOCTL,
   179  		uintptr(c.fd),
   180  		KVM_GET_SREGS,
   181  		uintptr(unsafe.Pointer(sregs))); errno != 0 {
   182  		return errno
   183  	}
   184  	return 0
   185  }
   186  
   187  //go:nosplit
   188  func seccompMmapSyscall(context unsafe.Pointer) (uintptr, uintptr, unix.Errno) {
   189  	ctx := bluepillArchContext(context)
   190  
   191  	// MAP_DENYWRITE is deprecated and ignored by kernel. We use it only for seccomp filters.
   192  	addr, _, e := unix.RawSyscall6(uintptr(ctx.Rax), uintptr(ctx.Rdi), uintptr(ctx.Rsi),
   193  		uintptr(ctx.Rdx), uintptr(ctx.R10)|unix.MAP_DENYWRITE, uintptr(ctx.R8), uintptr(ctx.R9))
   194  	ctx.Rax = uint64(addr)
   195  
   196  	return addr, uintptr(ctx.Rsi), e
   197  }