github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/devices/nvproxy/frontend_unsafe.go (about)

     1  // Copyright 2023 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  package nvproxy
    16  
    17  import (
    18  	"runtime"
    19  	"unsafe"
    20  
    21  	"golang.org/x/sys/unix"
    22  	"github.com/metacubex/gvisor/pkg/abi/nvgpu"
    23  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    24  	"github.com/metacubex/gvisor/pkg/marshal/primitive"
    25  )
    26  
    27  func frontendIoctlInvoke[Params any](fi *frontendIoctlState, sentryParams *Params) (uintptr, error) {
    28  	n, _, errno := unix.RawSyscall(unix.SYS_IOCTL, uintptr(fi.fd.hostFD), frontendIoctlCmd(fi.nr, fi.ioctlParamsSize), uintptr(unsafe.Pointer(sentryParams)))
    29  	if errno != 0 {
    30  		return n, errno
    31  	}
    32  	return n, nil
    33  }
    34  
    35  func frontendIoctlInvokePtr(fi *frontendIoctlState, sentryParams uintptr) (uintptr, error) {
    36  	n, _, errno := unix.RawSyscall(unix.SYS_IOCTL, uintptr(fi.fd.hostFD), frontendIoctlCmd(fi.nr, fi.ioctlParamsSize), sentryParams)
    37  	if errno != 0 {
    38  		return n, errno
    39  	}
    40  	return n, nil
    41  }
    42  
    43  func rmControlInvoke[Params any](fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters, ctrlParams *Params) (uintptr, error) {
    44  	defer runtime.KeepAlive(ctrlParams) // since we convert to non-pointer-typed P64
    45  	sentryIoctlParams := *ioctlParams
    46  	sentryIoctlParams.Params = p64FromPtr(unsafe.Pointer(ctrlParams))
    47  	n, err := frontendIoctlInvoke(fi, &sentryIoctlParams)
    48  	if err != nil {
    49  		return n, err
    50  	}
    51  	outIoctlParams := sentryIoctlParams
    52  	outIoctlParams.Params = ioctlParams.Params
    53  	if _, err := outIoctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil {
    54  		return n, err
    55  	}
    56  	return n, nil
    57  }
    58  
    59  func ctrlClientSystemGetBuildVersionInvoke(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters, ctrlParams *nvgpu.NV0000_CTRL_SYSTEM_GET_BUILD_VERSION_PARAMS, driverVersionBuf, versionBuf, titleBuf *byte) (uintptr, error) {
    60  	sentryCtrlParams := *ctrlParams
    61  	sentryCtrlParams.PDriverVersionBuffer = p64FromPtr(unsafe.Pointer(driverVersionBuf))
    62  	sentryCtrlParams.PVersionBuffer = p64FromPtr(unsafe.Pointer(versionBuf))
    63  	sentryCtrlParams.PTitleBuffer = p64FromPtr(unsafe.Pointer(titleBuf))
    64  	n, err := rmControlInvoke(fi, ioctlParams, &sentryCtrlParams)
    65  	if err != nil {
    66  		return n, err
    67  	}
    68  	outCtrlParams := sentryCtrlParams
    69  	outCtrlParams.PDriverVersionBuffer = ctrlParams.PDriverVersionBuffer
    70  	outCtrlParams.PVersionBuffer = ctrlParams.PVersionBuffer
    71  	outCtrlParams.PTitleBuffer = ctrlParams.PTitleBuffer
    72  	if _, err := outCtrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)); err != nil {
    73  		return n, err
    74  	}
    75  	return n, nil
    76  }
    77  
    78  func ctrlDevGpuGetClasslistInvoke(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters, ctrlParams *nvgpu.NV0080_CTRL_GPU_GET_CLASSLIST_PARAMS, classList []uint32) (uintptr, error) {
    79  	sentryCtrlParams := *ctrlParams
    80  	sentryCtrlParams.ClassList = p64FromPtr(unsafe.Pointer(&classList[0]))
    81  	n, err := rmControlInvoke(fi, ioctlParams, &sentryCtrlParams)
    82  	if err != nil {
    83  		return n, err
    84  	}
    85  	if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(ctrlParams.ClassList), classList); err != nil {
    86  		return 0, err
    87  	}
    88  	outCtrlParams := sentryCtrlParams
    89  	outCtrlParams.ClassList = ctrlParams.ClassList
    90  	if _, err := outCtrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)); err != nil {
    91  		return n, err
    92  	}
    93  	return n, nil
    94  }
    95  
    96  func ctrlDevFIFOGetChannelList(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) {
    97  	var ctrlParams nvgpu.NV0080_CTRL_FIFO_GET_CHANNELLIST_PARAMS
    98  	if ctrlParams.SizeBytes() != int(ioctlParams.ParamsSize) {
    99  		return 0, linuxerr.EINVAL
   100  	}
   101  	if _, err := ctrlParams.CopyIn(fi.t, addrFromP64(ioctlParams.Params)); err != nil {
   102  		return 0, err
   103  	}
   104  	if ctrlParams.NumChannels == 0 {
   105  		// Compare
   106  		// src/nvidia/src/kernel/gpu/fifo/kernel_fifo_ctrl.c:deviceCtrlCmdFifoGetChannelList_IMPL().
   107  		return 0, linuxerr.EINVAL
   108  	}
   109  	channelHandleList := make([]uint32, ctrlParams.NumChannels)
   110  	if _, err := primitive.CopyUint32SliceIn(fi.t, addrFromP64(ctrlParams.PChannelHandleList), channelHandleList); err != nil {
   111  		return 0, err
   112  	}
   113  	channelList := make([]uint32, ctrlParams.NumChannels)
   114  	if _, err := primitive.CopyUint32SliceIn(fi.t, addrFromP64(ctrlParams.PChannelList), channelList); err != nil {
   115  		return 0, err
   116  	}
   117  	sentryCtrlParams := ctrlParams
   118  	sentryCtrlParams.PChannelHandleList = p64FromPtr(unsafe.Pointer(&channelHandleList[0]))
   119  	sentryCtrlParams.PChannelList = p64FromPtr(unsafe.Pointer(&channelList[0]))
   120  
   121  	n, err := rmControlInvoke(fi, ioctlParams, &sentryCtrlParams)
   122  	if err != nil {
   123  		return n, err
   124  	}
   125  
   126  	if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(ctrlParams.PChannelHandleList), channelHandleList); err != nil {
   127  		return 0, err
   128  	}
   129  	if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(ctrlParams.PChannelList), channelList); err != nil {
   130  		return 0, err
   131  	}
   132  	outCtrlParams := sentryCtrlParams
   133  	outCtrlParams.PChannelHandleList = ctrlParams.PChannelHandleList
   134  	outCtrlParams.PChannelList = ctrlParams.PChannelList
   135  	if _, err := outCtrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)); err != nil {
   136  		return n, err
   137  	}
   138  
   139  	return n, nil
   140  }
   141  
   142  func ctrlSubdevGRGetInfo(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) {
   143  	var ctrlParams nvgpu.NV2080_CTRL_GR_GET_INFO_PARAMS
   144  	if ctrlParams.SizeBytes() != int(ioctlParams.ParamsSize) {
   145  		return 0, linuxerr.EINVAL
   146  	}
   147  	if _, err := ctrlParams.CopyIn(fi.t, addrFromP64(ioctlParams.Params)); err != nil {
   148  		return 0, err
   149  	}
   150  	if ctrlParams.GRInfoListSize == 0 {
   151  		// Compare
   152  		// src/nvidia/src/kernel/gpu/gr/kernel_graphics.c:_kgraphicsCtrlCmdGrGetInfoV2().
   153  		return 0, linuxerr.EINVAL
   154  	}
   155  	infoList := make([]byte, int(ctrlParams.GRInfoListSize)*(*nvgpu.NVXXXX_CTRL_XXX_INFO)(nil).SizeBytes())
   156  	if _, err := fi.t.CopyInBytes(addrFromP64(ctrlParams.GRInfoList), infoList); err != nil {
   157  		return 0, err
   158  	}
   159  	sentryCtrlParams := ctrlParams
   160  	sentryCtrlParams.GRInfoList = p64FromPtr(unsafe.Pointer(&infoList[0]))
   161  
   162  	n, err := rmControlInvoke(fi, ioctlParams, &sentryCtrlParams)
   163  	if err != nil {
   164  		return n, err
   165  	}
   166  
   167  	if _, err := fi.t.CopyOutBytes(addrFromP64(ctrlParams.GRInfoList), infoList); err != nil {
   168  		return n, err
   169  	}
   170  	outCtrlParams := sentryCtrlParams
   171  	outCtrlParams.GRInfoList = ctrlParams.GRInfoList
   172  	if _, err := outCtrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)); err != nil {
   173  		return n, err
   174  	}
   175  
   176  	return n, nil
   177  }
   178  
   179  func rmAllocInvoke[Params any](fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, allocParams *Params, isNVOS64 bool) (uintptr, error) {
   180  	defer runtime.KeepAlive(allocParams) // since we convert to non-pointer-typed P64
   181  
   182  	sentryIoctlParams := nvgpu.GetRmAllocParamObj(isNVOS64)
   183  	sentryIoctlParams.FromOS64(*ioctlParams)
   184  	sentryIoctlParams.SetPAllocParms(p64FromPtr(unsafe.Pointer(allocParams)))
   185  	var rightsRequested nvgpu.RS_ACCESS_MASK
   186  	if ioctlParams.PRightsRequested != 0 {
   187  		if _, err := rightsRequested.CopyIn(fi.t, addrFromP64(ioctlParams.PRightsRequested)); err != nil {
   188  			return 0, err
   189  		}
   190  		sentryIoctlParams.SetPRightsRequested(p64FromPtr(unsafe.Pointer(&rightsRequested)))
   191  	}
   192  	n, err := frontendIoctlInvokePtr(fi, sentryIoctlParams.GetPointer())
   193  	if err != nil {
   194  		return n, err
   195  	}
   196  	if ioctlParams.PRightsRequested != 0 {
   197  		if _, err := rightsRequested.CopyOut(fi.t, addrFromP64(ioctlParams.PRightsRequested)); err != nil {
   198  			return n, err
   199  		}
   200  	}
   201  	// Reuse sentryIoctlParams to write out params.
   202  	sentryIoctlParams.SetPAllocParms(ioctlParams.PAllocParms)
   203  	if ioctlParams.PRightsRequested != 0 {
   204  		sentryIoctlParams.SetPRightsRequested(ioctlParams.PRightsRequested)
   205  	}
   206  	if _, err := sentryIoctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil {
   207  		return n, err
   208  	}
   209  	return n, nil
   210  }
   211  
   212  func rmVidHeapControlAllocSize(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS32Parameters) (uintptr, error) {
   213  	allocSizeParams := (*nvgpu.NVOS32AllocSize)(unsafe.Pointer(&ioctlParams.Data))
   214  
   215  	sentryIoctlParams := *ioctlParams
   216  	sentryAllocSizeParams := (*nvgpu.NVOS32AllocSize)(unsafe.Pointer(&sentryIoctlParams.Data))
   217  	var addr uint64
   218  	if allocSizeParams.Address != 0 {
   219  		if _, err := primitive.CopyUint64In(fi.t, addrFromP64(allocSizeParams.Address), &addr); err != nil {
   220  			return 0, err
   221  		}
   222  		sentryAllocSizeParams.Address = p64FromPtr(unsafe.Pointer(&addr))
   223  	}
   224  
   225  	n, err := frontendIoctlInvoke(fi, &sentryIoctlParams)
   226  	if err != nil {
   227  		return n, err
   228  	}
   229  
   230  	outIoctlParams := sentryIoctlParams
   231  	outAllocSizeParams := (*nvgpu.NVOS32AllocSize)(unsafe.Pointer(&outIoctlParams.Data))
   232  	if allocSizeParams.Address != 0 {
   233  		if _, err := primitive.CopyUint64Out(fi.t, addrFromP64(allocSizeParams.Address), addr); err != nil {
   234  			return n, err
   235  		}
   236  		outAllocSizeParams.Address = allocSizeParams.Address
   237  	}
   238  	if _, err := outIoctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil {
   239  		return n, err
   240  	}
   241  
   242  	return n, nil
   243  }