diff --git a/pkg/abi/nvgpu/classes.go b/pkg/abi/nvgpu/classes.go index b75fe111b..dbd9412ed 100644 --- a/pkg/abi/nvgpu/classes.go +++ b/pkg/abi/nvgpu/classes.go @@ -396,5 +396,4 @@ type NV00FD_ALLOCATION_PARAMETERS_V545 struct { // +marshal type NV_CONFIDENTIAL_COMPUTE_ALLOC_PARAMS struct { Handle Handle `nvproxy:"same"` - _ uint32 } diff --git a/pkg/abi/nvgpu/ctrl.go b/pkg/abi/nvgpu/ctrl.go index 98d2e72d4..3942c4197 100644 --- a/pkg/abi/nvgpu/ctrl.go +++ b/pkg/abi/nvgpu/ctrl.go @@ -72,6 +72,22 @@ const ( NV0000_CTRL_CMD_GPU_WAIT_ATTACH_ID = 0x290 ) +// NV0000_CTRL_GPU_GET_ID_INFO_PARAMS is the param type for NV0000_CTRL_CMD_GPU_GET_ID_INFO, +// from src/common/sdk/nvidia/inc/ctrl/ctrl0000/ctrl0000gpu.h. +// +// +marshal +type NV0000_CTRL_GPU_GET_ID_INFO_PARAMS struct { + GpuID uint32 `nvproxy:"same"` + GpuFlags uint32 + DeviceInstance uint32 + SubDeviceInstance uint32 + SzName P64 + SliStatus uint32 + BoardID uint32 + GpuInstance uint32 + NumaID int32 +} + // From src/common/sdk/nvidia/inc/ctrl/ctrl0000/ctrl0000syncgpuboost.h: const ( NV0000_CTRL_CMD_SYNC_GPU_BOOST_GROUP_INFO = 0xa04 @@ -85,8 +101,34 @@ const ( NV0000_CTRL_CMD_SYSTEM_GET_FABRIC_STATUS = 0x136 NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS_MATRIX = 0x13a NV0000_CTRL_CMD_SYSTEM_GET_FEATURES = 0x1f0 + NV0000_CTRL_SYSTEM_MAX_ATTACHED_GPUS = 32 + NV0000_CTRL_P2P_CAPS_INDEX_TABLE_SIZE = 9 ) +// NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS is the param type for NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS, +// from src/common/sdk/nvidia/inc/ctrl/ctrl0000/ctrl0000system.h. +// +// +marshal +type NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS struct { + GpuIDs [NV0000_CTRL_SYSTEM_MAX_ATTACHED_GPUS]uint32 `nvproxy:"same"` + GpuCount uint32 + P2PCaps uint32 + P2POptimalReadCEs uint32 + P2POptimalWriteCEs uint32 + P2PCapsStatus [NV0000_CTRL_P2P_CAPS_INDEX_TABLE_SIZE]uint8 + _ [7]byte + BusPeerIDs P64 +} + +// NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS_V550 is the updated version of +// NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS since 550.40.07. +// +// +marshal +type NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS_V550 struct { + NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS `nvproxy:"NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS"` + BusEgmPeerIDs P64 +} + // From src/common/sdk/nvidia/inc/ctrl/ctrl0000/ctrl0000unix.h: const ( NV0000_CTRL_CMD_OS_UNIX_EXPORT_OBJECT_TO_FD = 0x3d05 @@ -100,8 +142,8 @@ type NV0000_CTRL_OS_UNIX_GET_EXPORT_OBJECT_INFO_PARAMS struct { FD int32 `nvproxy:"same"` DeviceInstance uint32 MaxObjects uint16 - Pad [2]byte Metadata [NV0000_OS_UNIX_EXPORT_OBJECT_FD_BUFFER_SIZE]uint8 + Pad [2]byte } // GetFrontendFD implements HasFrontendFD.GetFrontendFD. @@ -120,8 +162,8 @@ type NV0000_CTRL_OS_UNIX_GET_EXPORT_OBJECT_INFO_PARAMS_V545 struct { DeviceInstance uint32 GpuInstanceID uint32 MaxObjects uint16 - Pad [2]byte Metadata [NV0000_OS_UNIX_EXPORT_OBJECT_FD_BUFFER_SIZE]uint8 + Pad [2]byte } // GetFrontendFD implements HasFrontendFD.GetFrontendFD. @@ -136,11 +178,8 @@ func (p *NV0000_CTRL_OS_UNIX_GET_EXPORT_OBJECT_INFO_PARAMS_V545) SetFrontendFD(f // +marshal type NV0000_CTRL_OS_UNIX_EXPORT_OBJECT struct { - Type uint32 // enum NV0000_CTRL_OS_UNIX_EXPORT_OBJECT_TYPE - // These fields are inside union `data`, in struct `rmObject`. - HDevice Handle - HParent Handle - HObject Handle + Type uint32 // enum NV0000_CTRL_OS_UNIX_EXPORT_OBJECT_TYPE + Data [12]byte // union } // +marshal diff --git a/pkg/abi/nvgpu/uvm.go b/pkg/abi/nvgpu/uvm.go index bba25bc9a..6c2ce44cf 100644 --- a/pkg/abi/nvgpu/uvm.go +++ b/pkg/abi/nvgpu/uvm.go @@ -161,8 +161,8 @@ type UVM_MAP_EXTERNAL_ALLOCATION_PARAMS struct { PerGPUAttributes [UVM_MAX_GPUS]UvmGpuMappingAttributes GPUAttributesCount uint64 RMCtrlFD int32 - HClient Handle - HMemory Handle + HClient uint32 // These are treated like NvHandle, but the driver uses NvU32. + HMemory uint32 // These are treated like NvHandle, but the driver uses NvU32. RMStatus uint32 } @@ -184,8 +184,8 @@ type UVM_MAP_EXTERNAL_ALLOCATION_PARAMS_V550 struct { PerGPUAttributes [UVM_MAX_GPUS_V2]UvmGpuMappingAttributes GPUAttributesCount uint64 RMCtrlFD int32 - HClient Handle - HMemory Handle + HClient uint32 // These are treated like NvHandle, but the driver uses NvU32. + HMemory uint32 // These are treated like NvHandle, but the driver uses NvU32. RMStatus uint32 } diff --git a/pkg/sentry/devices/nvproxy/frontend.go b/pkg/sentry/devices/nvproxy/frontend.go index 02ff5530b..fc2830c10 100644 --- a/pkg/sentry/devices/nvproxy/frontend.go +++ b/pkg/sentry/devices/nvproxy/frontend.go @@ -765,6 +765,27 @@ func ctrlSubdevFIFODisableChannels(fi *frontendIoctlState, ioctlParams *nvgpu.NV return n, nil } +func ctrlGpuGetIDInfo(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) { + var ctrlParams nvgpu.NV0000_CTRL_GPU_GET_ID_INFO_PARAMS + if ctrlParams.SizeBytes() != int(ioctlParams.ParamsSize) { + return 0, linuxerr.EINVAL + } + if _, err := ctrlParams.CopyIn(fi.t, addrFromP64(ioctlParams.Params)); err != nil { + return 0, err + } + + // szName is not used anywhere in the driver, so we explicitly set it to null. + // See src/nvidia/src/kernel/gpu_mgr/gpu_mgr.c::gpumgrGetGpuIdInfo(). + ctrlParams.SzName = 0 + + n, err := rmControlInvoke(fi, ioctlParams, &ctrlParams) + if err != nil { + return n, err + } + _, err = ctrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)) + return n, err +} + func rmAlloc(fi *frontendIoctlState) (uintptr, error) { var isNVOS64 bool switch fi.ioctlParamsSize { diff --git a/pkg/sentry/devices/nvproxy/frontend_unsafe.go b/pkg/sentry/devices/nvproxy/frontend_unsafe.go index 0d215c0bf..d4d4a174e 100644 --- a/pkg/sentry/devices/nvproxy/frontend_unsafe.go +++ b/pkg/sentry/devices/nvproxy/frontend_unsafe.go @@ -175,6 +175,96 @@ func ctrlDevFIFOGetChannelList(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54 return n, nil } +func ctrlClientSystemGetP2PCapsInitializeArray(origArr nvgpu.P64, gpuCount uint32) (nvgpu.P64, []uint32, bool) { + // The driver doesn't try and copy memory if the array is null. See + // src/nvidia/src/kernel/rmapi/embedded_param_copy.c::embeddedParamCopyIn(), + // case NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS. + if origArr == 0 { + return 0, nil, true + } + + // Params size is gpuCount * gpuCount * sizeof(NvU32). + numEntries := gpuCount * gpuCount + if numEntries*4 > nvgpu.RMAPI_PARAM_COPY_MAX_PARAMS_SIZE { + return 0, nil, false + } + + arr := make([]uint32, numEntries) + return p64FromPtr(unsafe.Pointer(&arr[0])), arr, true +} + +func ctrlClientSystemGetP2PCaps(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) { + var ctrlParams nvgpu.NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS + if ctrlParams.SizeBytes() != int(ioctlParams.ParamsSize) { + return 0, linuxerr.EINVAL + } + if _, err := ctrlParams.CopyIn(fi.t, addrFromP64(ioctlParams.Params)); err != nil { + return 0, err + } + + origBusPeerIDs := ctrlParams.BusPeerIDs + busPeerIDs, busPeerIDsBuf, ok := ctrlClientSystemGetP2PCapsInitializeArray(origBusPeerIDs, ctrlParams.GpuCount) + if !ok { + return 0, ctrlCmdFailWithStatus(fi, ioctlParams, nvgpu.NV_ERR_INVALID_ARGUMENT) + } + ctrlParams.BusPeerIDs = busPeerIDs + + n, err := rmControlInvoke(fi, ioctlParams, &ctrlParams) + ctrlParams.BusPeerIDs = origBusPeerIDs + if err != nil { + return n, err + } + + if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(origBusPeerIDs), busPeerIDsBuf); err != nil { + return n, err + } + + _, err = ctrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)) + return n, err +} + +func ctrlClientSystemGetP2PCapsV550(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) { + var ctrlParams nvgpu.NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS_V550 + if ctrlParams.SizeBytes() != int(ioctlParams.ParamsSize) { + return 0, linuxerr.EINVAL + } + if _, err := ctrlParams.CopyIn(fi.t, addrFromP64(ioctlParams.Params)); err != nil { + return 0, err + } + + origBusPeerIDs := ctrlParams.BusPeerIDs + busPeerIDs, busPeerIDsBuf, ok := ctrlClientSystemGetP2PCapsInitializeArray(origBusPeerIDs, ctrlParams.GpuCount) + if !ok { + return 0, ctrlCmdFailWithStatus(fi, ioctlParams, nvgpu.NV_ERR_INVALID_ARGUMENT) + } + ctrlParams.BusPeerIDs = busPeerIDs + + origBusEgmPeerIDs := ctrlParams.BusEgmPeerIDs + busEgmPeerIDs, busEgmPeerIDsBuf, ok := ctrlClientSystemGetP2PCapsInitializeArray(origBusEgmPeerIDs, ctrlParams.GpuCount) + if !ok { + return 0, ctrlCmdFailWithStatus(fi, ioctlParams, nvgpu.NV_ERR_INVALID_ARGUMENT) + } + ctrlParams.BusEgmPeerIDs = busEgmPeerIDs + + n, err := rmControlInvoke(fi, ioctlParams, &ctrlParams) + ctrlParams.BusPeerIDs = origBusPeerIDs + ctrlParams.BusEgmPeerIDs = origBusEgmPeerIDs + if err != nil { + return n, err + } + + // If origBufPeerIDS or origBusEgmPeerIDs is null, the corresponding buffer will be nil + // and CopyUint32SliceOut() will be a no-op. + if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(origBusPeerIDs), busPeerIDsBuf); err != nil { + return n, err + } + if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(origBusEgmPeerIDs), busEgmPeerIDsBuf); err != nil { + return n, err + } + _, err = ctrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)) + return n, err +} + func rmAllocInvoke[Params any](fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, allocParams *Params, isNVOS64 bool, addObjLocked func(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, rightsRequested nvgpu.RS_ACCESS_MASK, allocParams *Params)) (uintptr, error) { defer runtime.KeepAlive(allocParams) // since we convert to non-pointer-typed P64 diff --git a/pkg/sentry/devices/nvproxy/version.go b/pkg/sentry/devices/nvproxy/version.go index f28e0948b..30ec51e0d 100644 --- a/pkg/sentry/devices/nvproxy/version.go +++ b/pkg/sentry/devices/nvproxy/version.go @@ -225,7 +225,6 @@ func Init() { nvgpu.NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE: rmControlSimple, nvgpu.NV0000_CTRL_CMD_CLIENT_SET_INHERITED_SHARE_POLICY: rmControlSimple, nvgpu.NV0000_CTRL_CMD_GPU_GET_ATTACHED_IDS: rmControlSimple, - nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO: rmControlSimple, nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO_V2: rmControlSimple, nvgpu.NV0000_CTRL_CMD_GPU_GET_PROBED_IDS: rmControlSimple, nvgpu.NV0000_CTRL_CMD_GPU_ATTACH_IDS: rmControlSimple, @@ -234,7 +233,6 @@ func Init() { nvgpu.NV0000_CTRL_CMD_GPU_QUERY_DRAIN_STATE: rmControlSimple, nvgpu.NV0000_CTRL_CMD_GPU_GET_MEMOP_ENABLE: rmControlSimple, nvgpu.NV0000_CTRL_CMD_SYNC_GPU_BOOST_GROUP_INFO: rmControlSimple, - nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS: rmControlSimple, nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS_V2: rmControlSimple, nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_FABRIC_STATUS: rmControlSimple, nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS_MATRIX: rmControlSimple, @@ -315,7 +313,9 @@ func Init() { nvgpu.NVA06C_CTRL_CMD_PREEMPT: rmControlSimple, nvgpu.NVA06F_CTRL_CMD_GPFIFO_SCHEDULE: rmControlSimple, nvgpu.NVC56F_CTRL_CMD_GET_KMB: rmControlSimple, + nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO: ctrlGpuGetIDInfo, nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_BUILD_VERSION: ctrlClientSystemGetBuildVersion, + nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS: ctrlClientSystemGetP2PCaps, nvgpu.NV0000_CTRL_CMD_OS_UNIX_EXPORT_OBJECT_TO_FD: ctrlHasFrontendFD[nvgpu.NV0000_CTRL_OS_UNIX_EXPORT_OBJECT_TO_FD_PARAMS], nvgpu.NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_FROM_FD: ctrlHasFrontendFD[nvgpu.NV0000_CTRL_OS_UNIX_IMPORT_OBJECT_FROM_FD_PARAMS], nvgpu.NV0000_CTRL_CMD_OS_UNIX_GET_EXPORT_OBJECT_INFO: ctrlHasFrontendFD[nvgpu.NV0000_CTRL_OS_UNIX_GET_EXPORT_OBJECT_INFO_PARAMS], @@ -420,7 +420,6 @@ func Init() { nvgpu.NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE: simpleIoctl("NV0000_CTRL_CLIENT_GET_ADDR_SPACE_TYPE_PARAMS"), nvgpu.NV0000_CTRL_CMD_CLIENT_SET_INHERITED_SHARE_POLICY: simpleIoctl("NV0000_CTRL_CLIENT_SET_INHERITED_SHARE_POLICY_PARAMS"), nvgpu.NV0000_CTRL_CMD_GPU_GET_ATTACHED_IDS: simpleIoctl("NV0000_CTRL_GPU_GET_ATTACHED_IDS_PARAMS"), - nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO: simpleIoctl("NV0000_CTRL_GPU_GET_ID_INFO_PARAMS"), nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO_V2: simpleIoctl("NV0000_CTRL_GPU_GET_ID_INFO_V2_PARAMS"), nvgpu.NV0000_CTRL_CMD_GPU_GET_PROBED_IDS: simpleIoctl("NV0000_CTRL_GPU_GET_PROBED_IDS_PARAMS"), nvgpu.NV0000_CTRL_CMD_GPU_ATTACH_IDS: simpleIoctl("NV0000_CTRL_GPU_ATTACH_IDS_PARAMS"), @@ -429,7 +428,6 @@ func Init() { nvgpu.NV0000_CTRL_CMD_GPU_QUERY_DRAIN_STATE: simpleIoctl("NV0000_CTRL_GPU_QUERY_DRAIN_STATE_PARAMS"), nvgpu.NV0000_CTRL_CMD_GPU_GET_MEMOP_ENABLE: simpleIoctl("NV0000_CTRL_GPU_GET_MEMOP_ENABLE_PARAMS"), nvgpu.NV0000_CTRL_CMD_SYNC_GPU_BOOST_GROUP_INFO: simpleIoctl("NV0000_SYNC_GPU_BOOST_GROUP_INFO_PARAMS"), - nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS: simpleIoctl("NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS"), nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS_V2: simpleIoctl("NV0000_CTRL_SYSTEM_GET_P2P_CAPS_V2_PARAMS"), nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_FABRIC_STATUS: simpleIoctl("NV0000_CTRL_SYSTEM_GET_FABRIC_STATUS_PARAMS"), nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS_MATRIX: simpleIoctl("NV0000_CTRL_SYSTEM_GET_P2P_CAPS_MATRIX_PARAMS"), @@ -510,7 +508,9 @@ func Init() { nvgpu.NVA06C_CTRL_CMD_PREEMPT: simpleIoctl("NVA06C_CTRL_PREEMPT_PARAMS"), nvgpu.NVA06F_CTRL_CMD_GPFIFO_SCHEDULE: simpleIoctl("NVA06F_CTRL_GPFIFO_SCHEDULE_PARAMS"), nvgpu.NVC56F_CTRL_CMD_GET_KMB: simpleIoctl("NVC56F_CTRL_CMD_GET_KMB_PARAMS"), + nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO: getStructName(nvgpu.NV0000_CTRL_GPU_GET_ID_INFO_PARAMS{}), nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_BUILD_VERSION: getStructName(nvgpu.NV0000_CTRL_SYSTEM_GET_BUILD_VERSION_PARAMS{}), + nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS: getStructName(nvgpu.NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS{}), nvgpu.NV0000_CTRL_CMD_OS_UNIX_EXPORT_OBJECT_TO_FD: getStructName(nvgpu.NV0000_CTRL_OS_UNIX_EXPORT_OBJECT_TO_FD_PARAMS{}), nvgpu.NV0000_CTRL_CMD_OS_UNIX_IMPORT_OBJECT_FROM_FD: getStructName(nvgpu.NV0000_CTRL_OS_UNIX_IMPORT_OBJECT_FROM_FD_PARAMS{}), nvgpu.NV0000_CTRL_CMD_OS_UNIX_GET_EXPORT_OBJECT_INFO: getStructName(nvgpu.NV0000_CTRL_OS_UNIX_GET_EXPORT_OBJECT_INFO_PARAMS{}), @@ -616,6 +616,7 @@ func Init() { // NV2081_BINAPI forwards all control commands to the GSP in // src/nvidia/src/kernel/rmapi/binary_api.c:binapiControl_IMPL(). abi.controlCmd[(nvgpu.NV2081_BINAPI<<16)|0x0108] = rmControlSimple + abi.controlCmd[nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS] = ctrlClientSystemGetP2PCapsV550 abi.uvmIoctl[nvgpu.UVM_SET_PREFERRED_LOCATION] = uvmIoctlSimple[nvgpu.UVM_SET_PREFERRED_LOCATION_PARAMS_V550] prevNames := abi.getStructNames @@ -630,6 +631,7 @@ func Init() { // src/nvidia/src/kernel/rmapi/binary_api.c:binapiControl_IMPL(). // As such, there are no structs defined in the driver for this. names.controlNames[(nvgpu.NV2081_BINAPI<<16)|0x0108] = nil + names.controlNames[nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS] = getStructName(nvgpu.NV0000_CTRL_SYSTEM_GET_P2P_CAPS_PARAMS_V550{}) names.uvmNames[nvgpu.UVM_SET_PREFERRED_LOCATION] = getStructName(nvgpu.UVM_SET_PREFERRED_LOCATION_PARAMS_V550{}) return names