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 }