Add driver versioning support in nvproxy.

This adds utilities to make it easier to add versioning support in nvproxy.
This way we can have different handling of ioctls based on driver versions.

The largest downside of this solution is the usage of maps instead of switch
statements. Switch statements are *way* faster than map accesses. The rationale
is that most of the latency bound work happens on the GPU for GPU workloads. So
micro-optimizations like using switch statements should not be visible.

Co-authored-by: Jamie Liu <jamieliu@google.com>
PiperOrigin-RevId: 570889581
This commit is contained in:
Ayush Ranjan
2023-10-04 20:33:43 -07:00
committed by gVisor bot
co-authored by Jamie Liu
parent d493e93763
commit cce5b85235
7 changed files with 332 additions and 201 deletions
+8 -1
View File
@@ -1,4 +1,4 @@
load("//tools:defs.bzl", "go_library")
load("//tools:defs.bzl", "go_library", "go_test")
load("//pkg/sync/locking:locking.bzl", "declare_mutex")
package(default_applicable_licenses = ["//:license"])
@@ -25,6 +25,7 @@ go_library(
"uvm.go",
"uvm_mmap.go",
"uvm_unsafe.go",
"version.go",
],
visibility = ["//pkg/sentry:internal"],
deps = [
@@ -53,3 +54,9 @@ go_library(
"@org_golang_x_sys//unix:go_default_library",
],
)
go_test(
name = "nvproxy_test",
srcs = ["nvproxy_test.go"],
library = ":nvproxy",
)
+17 -153
View File
@@ -167,44 +167,12 @@ func (fd *frontendFD) Ioctl(ctx context.Context, uio usermem.IO, sysno uintptr,
// - Add symbol and parameter type definitions to //pkg/abi/nvgpu.
// - Add filter to seccomp_filters.go.
// - Add handling below.
switch nr {
case
nvgpu.NV_ESC_CARD_INFO, // nv_ioctl_card_info_t
nvgpu.NV_ESC_CHECK_VERSION_STR, // nv_rm_api_version_t
nvgpu.NV_ESC_SYS_PARAMS, // nv_ioctl_sys_params_t
nvgpu.NV_ESC_RM_DUP_OBJECT, // NVOS55_PARAMETERS
nvgpu.NV_ESC_RM_SHARE, // NVOS57_PARAMETERS
nvgpu.NV_ESC_RM_UNMAP_MEMORY, // NVOS34_PARAMETERS
nvgpu.NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO: // NVOS56_PARAMETERS
return frontendIoctlSimple(&fi)
case nvgpu.NV_ESC_REGISTER_FD:
return frontendRegisterFD(&fi)
case nvgpu.NV_ESC_ALLOC_OS_EVENT:
return rmAllocOSEvent(&fi)
case nvgpu.NV_ESC_FREE_OS_EVENT:
return rmFreeOSEvent(&fi)
case nvgpu.NV_ESC_NUMA_INFO:
// The CPU topology seen by the host driver differs from the CPU
// topology presented by the sentry to the application, so reject this
// ioctl; doing so is non-fatal.
ctx.Debugf("nvproxy: ignoring NV_ESC_NUMA_INFO")
return 0, linuxerr.EINVAL
case nvgpu.NV_ESC_RM_ALLOC_MEMORY:
return rmAllocMemory(&fi)
case nvgpu.NV_ESC_RM_FREE:
return rmFree(&fi)
case nvgpu.NV_ESC_RM_CONTROL:
return rmControl(&fi)
case nvgpu.NV_ESC_RM_ALLOC:
return rmAlloc(&fi)
case nvgpu.NV_ESC_RM_VID_HEAP_CONTROL:
return rmVidHeapControl(&fi)
case nvgpu.NV_ESC_RM_MAP_MEMORY:
return rmMapMemory(&fi)
default:
handler := fd.nvp.abi.frontendIoctl[nr]
if handler == nil {
ctx.Warningf("nvproxy: unknown frontend ioctl %d == %#x (argSize=%d, cmd=%#x)", nr, nr, argSize, cmd)
return 0, linuxerr.EINVAL
}
return handler(&fi)
}
func frontendIoctlCmd(nr, argSize uint32) uintptr {
@@ -243,6 +211,14 @@ func frontendIoctlSimple(fi *frontendIoctlState) (uintptr, error) {
return n, nil
}
func rmNumaInfo(fi *frontendIoctlState) (uintptr, error) {
// The CPU topology seen by the host driver differs from the CPU
// topology presented by the sentry to the application, so reject this
// ioctl; doing so is non-fatal.
log.Debugf("nvproxy: ignoring NV_ESC_NUMA_INFO")
return 0, linuxerr.EINVAL
}
func frontendRegisterFD(fi *frontendIoctlState) (uintptr, error) {
var ioctlParams nvgpu.IoctlRegisterFD
if fi.ioctlParamsSize != nvgpu.SizeofIoctlRegisterFD {
@@ -532,95 +508,12 @@ func rmControl(fi *frontendIoctlState) (uintptr, error) {
// - Add symbol definition to //pkg/abi/nvgpu. Parameter type definition is
// only required for non-simple commands.
// - Add handling below.
switch ioctlParams.Cmd {
case
nvgpu.NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE,
nvgpu.NV0000_CTRL_CMD_CLIENT_SET_INHERITED_SHARE_POLICY,
nvgpu.NV0000_CTRL_CMD_GPU_GET_ATTACHED_IDS,
nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO,
nvgpu.NV0000_CTRL_CMD_GPU_GET_ID_INFO_V2,
nvgpu.NV0000_CTRL_CMD_GPU_GET_PROBED_IDS,
nvgpu.NV0000_CTRL_CMD_GPU_ATTACH_IDS,
nvgpu.NV0000_CTRL_CMD_GPU_DETACH_IDS,
nvgpu.NV0000_CTRL_CMD_GPU_GET_PCI_INFO,
nvgpu.NV0000_CTRL_CMD_GPU_QUERY_DRAIN_STATE,
nvgpu.NV0000_CTRL_CMD_GPU_GET_MEMOP_ENABLE,
nvgpu.NV0000_CTRL_CMD_SYNC_GPU_BOOST_GROUP_INFO,
nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS,
nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_FABRIC_STATUS,
nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS_MATRIX,
nvgpu.NV0080_CTRL_CMD_FB_GET_CAPS_V2,
nvgpu.NV0080_CTRL_CMD_GPU_GET_NUM_SUBDEVICES,
nvgpu.NV0080_CTRL_CMD_GPU_QUERY_SW_STATE_PERSISTENCE,
nvgpu.NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE,
0x80028b, // unknown, paramsSize == 1
nvgpu.NV0080_CTRL_CMD_GPU_GET_CLASSLIST_V2,
nvgpu.NV0080_CTRL_CMD_HOST_GET_CAPS_V2,
nvgpu.NV2080_CTRL_CMD_BUS_GET_PCI_INFO,
nvgpu.NV2080_CTRL_CMD_BUS_GET_PCI_BAR_INFO,
nvgpu.NV2080_CTRL_CMD_BUS_GET_INFO_V2,
nvgpu.NV2080_CTRL_CMD_BUS_GET_PCIE_SUPPORTED_GPU_ATOMICS,
nvgpu.NV2080_CTRL_CMD_CE_GET_ALL_CAPS,
nvgpu.NV2080_CTRL_CMD_FB_GET_INFO_V2,
nvgpu.NV2080_CTRL_CMD_GPU_GET_INFO_V2,
nvgpu.NV2080_CTRL_CMD_GPU_GET_NAME_STRING,
nvgpu.NV2080_CTRL_CMD_GPU_GET_SHORT_NAME_STRING,
nvgpu.NV2080_CTRL_CMD_GPU_GET_SIMULATION_INFO,
nvgpu.NV2080_CTRL_CMD_GPU_QUERY_ECC_STATUS,
nvgpu.NV2080_CTRL_CMD_GPU_QUERY_COMPUTE_MODE_RULES,
nvgpu.NV2080_CTRL_CMD_GPU_ACQUIRE_COMPUTE_MODE_RESERVATION,
nvgpu.NV2080_CTRL_CMD_GPU_RELEASE_COMPUTE_MODE_RESERVATION,
nvgpu.NV2080_CTRL_CMD_GPU_GET_GID_INFO,
nvgpu.NV2080_CTRL_CMD_GPU_GET_ENGINES_V2,
nvgpu.NV2080_CTRL_CMD_GPU_GET_ACTIVE_PARTITION_IDS,
nvgpu.NV2080_CTRL_CMD_GPU_GET_COMPUTE_POLICY_CONFIG,
nvgpu.NV2080_CTRL_CMD_GET_GPU_FABRIC_PROBE_INFO,
nvgpu.NV2080_CTRL_CMD_GR_SET_CTXSW_PREEMPTION_MODE,
nvgpu.NV2080_CTRL_CMD_GR_GET_CTX_BUFFER_SIZE,
nvgpu.NV2080_CTRL_CMD_GR_GET_GLOBAL_SM_ORDER,
nvgpu.NV2080_CTRL_CMD_GR_GET_CAPS_V2,
nvgpu.NV2080_CTRL_CMD_GR_GET_GPC_MASK,
nvgpu.NV2080_CTRL_CMD_GR_GET_TPC_MASK,
nvgpu.NV2080_CTRL_CMD_GSP_GET_FEATURES,
nvgpu.NV2080_CTRL_CMD_MC_GET_ARCH_INFO,
nvgpu.NV2080_CTRL_CMD_MC_SERVICE_INTERRUPTS,
nvgpu.NV2080_CTRL_CMD_NVLINK_GET_NVLINK_STATUS,
nvgpu.NV2080_CTRL_CMD_PERF_BOOST,
nvgpu.NV2080_CTRL_CMD_RC_GET_WATCHDOG_INFO,
nvgpu.NV2080_CTRL_CMD_RC_RELEASE_WATCHDOG_REQUESTS,
nvgpu.NV2080_CTRL_CMD_RC_SOFT_DISABLE_WATCHDOG,
nvgpu.NV2080_CTRL_CMD_TIMER_GET_GPU_CPU_TIME_CORRELATION_INFO,
nvgpu.NV503C_CTRL_CMD_REGISTER_VA_SPACE,
nvgpu.NV503C_CTRL_CMD_REGISTER_VIDMEM,
nvgpu.NV503C_CTRL_CMD_UNREGISTER_VIDMEM,
nvgpu.NV83DE_CTRL_CMD_DEBUG_SET_EXCEPTION_MASK,
nvgpu.NV83DE_CTRL_CMD_DEBUG_READ_ALL_SM_ERROR_STATES,
nvgpu.NV83DE_CTRL_CMD_DEBUG_CLEAR_ALL_SM_ERROR_STATES,
nvgpu.NV906F_CTRL_CMD_RESET_CHANNEL,
nvgpu.NV90E6_CTRL_CMD_MASTER_GET_VIRTUAL_FUNCTION_ERROR_CONT_INTR_MASK,
nvgpu.NVC36F_CTRL_GET_CLASS_ENGINEID,
nvgpu.NVC36F_CTRL_CMD_GPFIFO_GET_WORK_SUBMIT_TOKEN,
nvgpu.NVA06C_CTRL_CMD_GPFIFO_SCHEDULE,
nvgpu.NVA06C_CTRL_CMD_SET_TIMESLICE,
nvgpu.NVA06C_CTRL_CMD_PREEMPT:
return rmControlSimple(fi, &ioctlParams)
case nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_BUILD_VERSION:
return ctrlClientSystemGetBuildVersion(fi, &ioctlParams)
case nvgpu.NV0080_CTRL_CMD_FIFO_GET_CHANNELLIST:
return ctrlDevFIFOGetChannelList(fi, &ioctlParams)
case nvgpu.NV2080_CTRL_CMD_FIFO_DISABLE_CHANNELS:
return ctrlSubdevFIFODisableChannels(fi, &ioctlParams)
case nvgpu.NV2080_CTRL_CMD_GR_GET_INFO:
return ctrlSubdevGRGetInfo(fi, &ioctlParams)
default:
handler := fi.fd.nvp.abi.controlCmd[ioctlParams.Cmd]
if handler == nil {
fi.ctx.Warningf("nvproxy: unknown control command %#x (paramsSize=%d)", ioctlParams.Cmd, ioctlParams.ParamsSize)
return 0, linuxerr.EINVAL
}
return handler(fi, &ioctlParams)
}
func rmControlSimple(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) {
@@ -752,41 +645,12 @@ func rmAlloc(fi *frontendIoctlState) (uintptr, error) {
// the class whose constructor interprets it ("Internal Class").
// - Add symbol and parameter type definitions to //pkg/abi/nvgpu.
// - Add handling below.
switch ioctlParams.HClass {
case nvgpu.NV01_ROOT, nvgpu.NV01_ROOT_NON_PRIV, nvgpu.NV01_ROOT_CLIENT:
return rmAllocSimple[nvgpu.Handle](fi, &ioctlParams, isNVOS64)
case nvgpu.NV01_EVENT_OS_EVENT:
return rmAllocEventOSEvent(fi, &ioctlParams, isNVOS64)
case nvgpu.NV01_DEVICE_0:
return rmAllocSimple[nvgpu.NV0080_ALLOC_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.NV20_SUBDEVICE_0:
return rmAllocSimple[nvgpu.NV2080_ALLOC_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.NV50_THIRD_PARTY_P2P:
return rmAllocSimple[nvgpu.NV503C_ALLOC_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.GT200_DEBUGGER:
return rmAllocSimple[nvgpu.NV83DE_ALLOC_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.FERMI_CONTEXT_SHARE_A:
return rmAllocSimple[nvgpu.NV_CTXSHARE_ALLOCATION_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.FERMI_VASPACE_A:
return rmAllocSimple[nvgpu.NV_VASPACE_ALLOCATION_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.KEPLER_CHANNEL_GROUP_A:
return rmAllocSimple[nvgpu.NV_CHANNEL_GROUP_ALLOCATION_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.TURING_CHANNEL_GPFIFO_A, nvgpu.AMPERE_CHANNEL_GPFIFO_A:
return rmAllocSimple[nvgpu.NV_CHANNEL_ALLOC_PARAMS](fi, &ioctlParams, isNVOS64)
case nvgpu.TURING_DMA_COPY_A, nvgpu.AMPERE_DMA_COPY_A, nvgpu.AMPERE_DMA_COPY_B, nvgpu.HOPPER_DMA_COPY_A:
return rmAllocSimple[nvgpu.NVB0B5_ALLOCATION_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.TURING_COMPUTE_A, nvgpu.AMPERE_COMPUTE_A, nvgpu.AMPERE_COMPUTE_B, nvgpu.ADA_COMPUTE_A, nvgpu.HOPPER_COMPUTE_A:
return rmAllocSimple[nvgpu.NV_GR_ALLOCATION_PARAMETERS](fi, &ioctlParams, isNVOS64)
case nvgpu.HOPPER_USERMODE_A:
return rmAllocSimple[nvgpu.NV_HOPPER_USERMODE_A_PARAMS](fi, &ioctlParams, isNVOS64)
case nvgpu.GF100_SUBDEVICE_MASTER, nvgpu.TURING_USERMODE_A:
return rmAllocNoParams(fi, &ioctlParams, isNVOS64)
case nvgpu.NV_MEMORY_FABRIC:
return rmAllocSimple[nvgpu.NV00F8_ALLOCATION_PARAMETERS](fi, &ioctlParams, isNVOS64)
default:
handler := fi.fd.nvp.abi.allocationClass[ioctlParams.HClass]
if handler == nil {
fi.ctx.Warningf("nvproxy: unknown allocation class %#08x", ioctlParams.HClass)
return 0, linuxerr.EINVAL
}
return handler(fi, &ioctlParams, isNVOS64)
}
// Unlike frontendIoctlSimple and rmControlSimple, rmAllocSimple requires the
+11 -10
View File
@@ -35,22 +35,22 @@ import (
func Register(vfsObj *vfs.VirtualFilesystem, uvmDevMajor uint32) error {
// The kernel driver's interface is unstable, so only allow versions of the
// driver that are known to be supported.
version, err := hostDriverVersion()
versionStr, err := hostDriverVersion()
if err != nil {
return fmt.Errorf("failed to get Nvidia driver version: %w", err)
}
switch version {
case
"525.60.13",
"525.105.17",
"525.125.06":
log.Infof("Nvidia driver version: %s", version)
default:
return fmt.Errorf("unsupported Nvidia driver version: %s", version)
version, err := driverVersionFrom(versionStr)
if err != nil {
return fmt.Errorf("failed to parse Nvidia driver version %s: %w", versionStr, err)
}
abiCons, ok := abis[version]
if !ok {
return fmt.Errorf("unsupported Nvidia driver version: %s", versionStr)
}
log.Infof("Nvidia driver version: %s", versionStr)
nvp := &nvproxy{
objsLive: make(map[nvgpu.Handle]*object),
abi: abiCons(),
}
for minor := uint32(0); minor <= nvgpu.NV_CONTROL_DEVICE_MINOR; minor++ {
if err := vfsObj.RegisterDevice(vfs.CharDevice, nvgpu.NV_MAJOR_DEVICE_NUMBER, minor, &frontendDevice{
@@ -95,6 +95,7 @@ func CreateIndexDevtmpfsFile(ctx context.Context, dev *devtmpfs.Accessor, minor
type nvproxy struct {
objsMu objsMutex `state:"nosave"`
objsLive map[nvgpu.Handle]*object
abi *driverABI
}
// object tracks an object allocated through the driver.
@@ -0,0 +1,27 @@
// Copyright 2023 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nvproxy
import (
"testing"
)
func TestInit(t *testing.T) {
// Test that initializing all driverABI works (does not panic or anything).
Init()
for _, cons := range abis {
cons()
}
}
+7 -37
View File
@@ -131,46 +131,12 @@ func (fd *uvmFD) Ioctl(ctx context.Context, uio usermem.IO, sysno uintptr, args
cmd: cmd,
ioctlParamsAddr: argPtr,
}
switch cmd {
case nvgpu.UVM_INITIALIZE:
return uvmInitialize(&ui)
case nvgpu.UVM_DEINITIALIZE:
return uvmIoctlInvoke[byte](&ui, nil)
case nvgpu.UVM_CREATE_RANGE_GROUP:
return uvmIoctlSimple[nvgpu.UVM_CREATE_RANGE_GROUP_PARAMS](&ui)
case nvgpu.UVM_DESTROY_RANGE_GROUP:
return uvmIoctlSimple[nvgpu.UVM_DESTROY_RANGE_GROUP_PARAMS](&ui)
case nvgpu.UVM_REGISTER_GPU_VASPACE:
return uvmIoctlHasRMCtrlFD[nvgpu.UVM_REGISTER_GPU_VASPACE_PARAMS](&ui)
case nvgpu.UVM_UNREGISTER_GPU_VASPACE:
return uvmIoctlSimple[nvgpu.UVM_UNREGISTER_GPU_VASPACE_PARAMS](&ui)
case nvgpu.UVM_REGISTER_CHANNEL:
return uvmIoctlHasRMCtrlFD[nvgpu.UVM_REGISTER_CHANNEL_PARAMS](&ui)
case nvgpu.UVM_UNREGISTER_CHANNEL:
return uvmIoctlSimple[nvgpu.UVM_UNREGISTER_CHANNEL_PARAMS](&ui)
case nvgpu.UVM_MAP_EXTERNAL_ALLOCATION:
return uvmIoctlHasRMCtrlFD[nvgpu.UVM_MAP_EXTERNAL_ALLOCATION_PARAMS](&ui)
case nvgpu.UVM_FREE:
return uvmIoctlSimple[nvgpu.UVM_FREE_PARAMS](&ui)
case nvgpu.UVM_REGISTER_GPU:
return uvmIoctlHasRMCtrlFD[nvgpu.UVM_REGISTER_GPU_PARAMS](&ui)
case nvgpu.UVM_UNREGISTER_GPU:
return uvmIoctlSimple[nvgpu.UVM_UNREGISTER_GPU_PARAMS](&ui)
case nvgpu.UVM_PAGEABLE_MEM_ACCESS:
return uvmIoctlSimple[nvgpu.UVM_PAGEABLE_MEM_ACCESS_PARAMS](&ui)
case nvgpu.UVM_MAP_DYNAMIC_PARALLELISM_REGION:
return uvmIoctlSimple[nvgpu.UVM_MAP_DYNAMIC_PARALLELISM_REGION_PARAMS](&ui)
case nvgpu.UVM_ALLOC_SEMAPHORE_POOL:
return uvmIoctlSimple[nvgpu.UVM_ALLOC_SEMAPHORE_POOL_PARAMS](&ui)
case nvgpu.UVM_VALIDATE_VA_RANGE:
return uvmIoctlSimple[nvgpu.UVM_VALIDATE_VA_RANGE_PARAMS](&ui)
case nvgpu.UVM_CREATE_EXTERNAL_RANGE:
return uvmIoctlSimple[nvgpu.UVM_CREATE_EXTERNAL_RANGE_PARAMS](&ui)
default:
handler := fd.nvp.abi.uvmIoctl[cmd]
if handler == nil {
ctx.Warningf("nvproxy: unknown uvm ioctl %d", cmd)
return 0, linuxerr.EINVAL
}
return handler(&ui)
}
// uvmIoctlState holds the state of a call to uvmFD.Ioctl().
@@ -182,6 +148,10 @@ type uvmIoctlState struct {
ioctlParamsAddr hostarch.Addr
}
func uvmIoctlNoParams(ui *uvmIoctlState) (uintptr, error) {
return uvmIoctlInvoke[byte](ui, nil)
}
func uvmIoctlSimple[Params any, PParams marshalPtr[Params]](ui *uvmIoctlState) (uintptr, error) {
var ioctlParams Params
if _, err := (PParams)(&ioctlParams).CopyIn(ui.t, ui.ioctlParamsAddr); err != nil {
+257
View File
@@ -0,0 +1,257 @@
// Copyright 2023 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nvproxy
import (
"fmt"
"strconv"
"strings"
"gvisor.dev/gvisor/pkg/abi/nvgpu"
"gvisor.dev/gvisor/pkg/sync"
)
type driverVersion struct {
major int
minor int
patch int
}
func driverVersionFrom(version string) (driverVersion, error) {
parts := strings.Split(version, ".")
if len(parts) != 3 {
return driverVersion{}, fmt.Errorf("invalid format of version string %q", version)
}
var (
res driverVersion
err error
)
res.major, err = strconv.Atoi(parts[0])
if err != nil {
return driverVersion{}, fmt.Errorf("invalid format for major version %q: %v", version, err)
}
res.minor, err = strconv.Atoi(parts[1])
if err != nil {
return driverVersion{}, fmt.Errorf("invalid format for minor version %q: %v", version, err)
}
res.patch, err = strconv.Atoi(parts[2])
if err != nil {
return driverVersion{}, fmt.Errorf("invalid format for patch version %q: %v", version, err)
}
return res, nil
}
func (v driverVersion) String() string {
return fmt.Sprintf("%02d.%02d.%02d", v.major, v.minor, v.patch)
}
type frontendIoctlHandler func(fi *frontendIoctlState) (uintptr, error)
type controlCmdHandler func(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error)
type allocationClassHandler func(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, isNVOS64 bool) (uintptr, error)
type uvmIoctlHandler func(ui *uvmIoctlState) (uintptr, error)
// A driverABIFunc constructs and returns a driverABI.
// This indirection exists to avoid memory usage from unused driver ABIs.
type driverABIFunc func() *driverABI
// driverABI defines the Nvidia kernel driver ABI proxied at a given version.
//
// The Nvidia driver's ioctl interface branches widely at various places in the
// kernel driver. As for now, versioning is only supported for the following
// points of branching:
// 1. frontend device ioctls (based on IOC_NR(cmd)).
// 2. uvm device ioctls (based on cmd).
// 3. control commands within NV_ESC_RM_CONTROL in frontend device (based on
// NVOS54_PARAMETERS.Cmd). Note that commands that have RM_GSS_LEGACY_MASK
// set are not versioned.
// 4. allocation classes within NV_ESC_RM_ALLOC in frontend device (based on
// NVOS64_PARAMETERS.HClass).
type driverABI struct {
frontendIoctl map[uint32]frontendIoctlHandler
uvmIoctl map[uint32]uvmIoctlHandler
controlCmd map[uint32]controlCmdHandler
allocationClass map[uint32]allocationClassHandler
}
// abis is a global map containing all supported Nvidia driver ABIs. This is
// initialized on Init() and is immutable henceforth.
var abis map[driverVersion]driverABIFunc
var abisOnce sync.Once
func addDriverABI(major, minor, patch int, cons driverABIFunc) driverABIFunc {
if abis == nil {
abis = make(map[driverVersion]driverABIFunc)
}
abis[driverVersion{major, minor, patch}] = cons
return cons
}
// Init initializes abis global map.
func Init() {
abisOnce.Do(func() {
v525_60_13 := addDriverABI(525, 60, 13, func() *driverABI {
// 525.60.13 is the earliest driver version supported by nvproxy. Since
// there is no parent to inherit from, the driverABI needs to be constructed
// with the entirety of the nvproxy functionality at this version.
return &driverABI{
frontendIoctl: map[uint32]frontendIoctlHandler{
nvgpu.NV_ESC_CARD_INFO: frontendIoctlSimple, // nv_ioctl_card_info_t
nvgpu.NV_ESC_CHECK_VERSION_STR: frontendIoctlSimple, // nv_rm_api_version_t
nvgpu.NV_ESC_SYS_PARAMS: frontendIoctlSimple, // nv_ioctl_sys_params_t
nvgpu.NV_ESC_RM_DUP_OBJECT: frontendIoctlSimple, // NVOS55_PARAMETERS
nvgpu.NV_ESC_RM_SHARE: frontendIoctlSimple, // NVOS57_PARAMETERS
nvgpu.NV_ESC_RM_UNMAP_MEMORY: frontendIoctlSimple, // NVOS34_PARAMETERS
nvgpu.NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO: frontendIoctlSimple, // NVOS56_PARAMETERS
nvgpu.NV_ESC_REGISTER_FD: frontendRegisterFD,
nvgpu.NV_ESC_ALLOC_OS_EVENT: rmAllocOSEvent,
nvgpu.NV_ESC_FREE_OS_EVENT: rmFreeOSEvent,
nvgpu.NV_ESC_NUMA_INFO: rmNumaInfo,
nvgpu.NV_ESC_RM_ALLOC_MEMORY: rmAllocMemory,
nvgpu.NV_ESC_RM_FREE: rmFree,
nvgpu.NV_ESC_RM_CONTROL: rmControl,
nvgpu.NV_ESC_RM_ALLOC: rmAlloc,
nvgpu.NV_ESC_RM_VID_HEAP_CONTROL: rmVidHeapControl,
nvgpu.NV_ESC_RM_MAP_MEMORY: rmMapMemory,
},
uvmIoctl: map[uint32]uvmIoctlHandler{
nvgpu.UVM_INITIALIZE: uvmInitialize,
nvgpu.UVM_DEINITIALIZE: uvmIoctlNoParams,
nvgpu.UVM_CREATE_RANGE_GROUP: uvmIoctlSimple[nvgpu.UVM_CREATE_RANGE_GROUP_PARAMS],
nvgpu.UVM_DESTROY_RANGE_GROUP: uvmIoctlSimple[nvgpu.UVM_DESTROY_RANGE_GROUP_PARAMS],
nvgpu.UVM_REGISTER_GPU_VASPACE: uvmIoctlHasRMCtrlFD[nvgpu.UVM_REGISTER_GPU_VASPACE_PARAMS],
nvgpu.UVM_UNREGISTER_GPU_VASPACE: uvmIoctlSimple[nvgpu.UVM_UNREGISTER_GPU_VASPACE_PARAMS],
nvgpu.UVM_REGISTER_CHANNEL: uvmIoctlHasRMCtrlFD[nvgpu.UVM_REGISTER_CHANNEL_PARAMS],
nvgpu.UVM_UNREGISTER_CHANNEL: uvmIoctlSimple[nvgpu.UVM_UNREGISTER_CHANNEL_PARAMS],
nvgpu.UVM_MAP_EXTERNAL_ALLOCATION: uvmIoctlHasRMCtrlFD[nvgpu.UVM_MAP_EXTERNAL_ALLOCATION_PARAMS],
nvgpu.UVM_FREE: uvmIoctlSimple[nvgpu.UVM_FREE_PARAMS],
nvgpu.UVM_REGISTER_GPU: uvmIoctlHasRMCtrlFD[nvgpu.UVM_REGISTER_GPU_PARAMS],
nvgpu.UVM_UNREGISTER_GPU: uvmIoctlSimple[nvgpu.UVM_UNREGISTER_GPU_PARAMS],
nvgpu.UVM_PAGEABLE_MEM_ACCESS: uvmIoctlSimple[nvgpu.UVM_PAGEABLE_MEM_ACCESS_PARAMS],
nvgpu.UVM_MAP_DYNAMIC_PARALLELISM_REGION: uvmIoctlSimple[nvgpu.UVM_MAP_DYNAMIC_PARALLELISM_REGION_PARAMS],
nvgpu.UVM_ALLOC_SEMAPHORE_POOL: uvmIoctlSimple[nvgpu.UVM_ALLOC_SEMAPHORE_POOL_PARAMS],
nvgpu.UVM_VALIDATE_VA_RANGE: uvmIoctlSimple[nvgpu.UVM_VALIDATE_VA_RANGE_PARAMS],
nvgpu.UVM_CREATE_EXTERNAL_RANGE: uvmIoctlSimple[nvgpu.UVM_CREATE_EXTERNAL_RANGE_PARAMS],
},
controlCmd: map[uint32]controlCmdHandler{
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,
nvgpu.NV0000_CTRL_CMD_GPU_DETACH_IDS: rmControlSimple,
nvgpu.NV0000_CTRL_CMD_GPU_GET_PCI_INFO: rmControlSimple,
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_FABRIC_STATUS: rmControlSimple,
nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_P2P_CAPS_MATRIX: rmControlSimple,
nvgpu.NV0080_CTRL_CMD_FB_GET_CAPS_V2: rmControlSimple,
nvgpu.NV0080_CTRL_CMD_GPU_GET_NUM_SUBDEVICES: rmControlSimple,
nvgpu.NV0080_CTRL_CMD_GPU_QUERY_SW_STATE_PERSISTENCE: rmControlSimple,
nvgpu.NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE: rmControlSimple,
0x80028b: rmControlSimple, // unknown, paramsSize == 1
nvgpu.NV0080_CTRL_CMD_GPU_GET_CLASSLIST_V2: rmControlSimple,
nvgpu.NV0080_CTRL_CMD_HOST_GET_CAPS_V2: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_BUS_GET_PCI_INFO: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_BUS_GET_PCI_BAR_INFO: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_BUS_GET_INFO_V2: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_BUS_GET_PCIE_SUPPORTED_GPU_ATOMICS: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_CE_GET_ALL_CAPS: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_FB_GET_INFO_V2: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_INFO_V2: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_NAME_STRING: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_SHORT_NAME_STRING: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_SIMULATION_INFO: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_QUERY_ECC_STATUS: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_QUERY_COMPUTE_MODE_RULES: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_ACQUIRE_COMPUTE_MODE_RESERVATION: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_RELEASE_COMPUTE_MODE_RESERVATION: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_GID_INFO: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_ENGINES_V2: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_ACTIVE_PARTITION_IDS: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GPU_GET_COMPUTE_POLICY_CONFIG: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GET_GPU_FABRIC_PROBE_INFO: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GR_SET_CTXSW_PREEMPTION_MODE: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GR_GET_CTX_BUFFER_SIZE: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GR_GET_GLOBAL_SM_ORDER: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GR_GET_CAPS_V2: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GR_GET_GPC_MASK: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GR_GET_TPC_MASK: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_GSP_GET_FEATURES: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_MC_GET_ARCH_INFO: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_MC_SERVICE_INTERRUPTS: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_NVLINK_GET_NVLINK_STATUS: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_PERF_BOOST: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_RC_GET_WATCHDOG_INFO: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_RC_RELEASE_WATCHDOG_REQUESTS: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_RC_SOFT_DISABLE_WATCHDOG: rmControlSimple,
nvgpu.NV2080_CTRL_CMD_TIMER_GET_GPU_CPU_TIME_CORRELATION_INFO: rmControlSimple,
nvgpu.NV503C_CTRL_CMD_REGISTER_VA_SPACE: rmControlSimple,
nvgpu.NV503C_CTRL_CMD_REGISTER_VIDMEM: rmControlSimple,
nvgpu.NV503C_CTRL_CMD_UNREGISTER_VIDMEM: rmControlSimple,
nvgpu.NV83DE_CTRL_CMD_DEBUG_SET_EXCEPTION_MASK: rmControlSimple,
nvgpu.NV83DE_CTRL_CMD_DEBUG_READ_ALL_SM_ERROR_STATES: rmControlSimple,
nvgpu.NV83DE_CTRL_CMD_DEBUG_CLEAR_ALL_SM_ERROR_STATES: rmControlSimple,
nvgpu.NV906F_CTRL_CMD_RESET_CHANNEL: rmControlSimple,
nvgpu.NV90E6_CTRL_CMD_MASTER_GET_VIRTUAL_FUNCTION_ERROR_CONT_INTR_MASK: rmControlSimple,
nvgpu.NVC36F_CTRL_GET_CLASS_ENGINEID: rmControlSimple,
nvgpu.NVC36F_CTRL_CMD_GPFIFO_GET_WORK_SUBMIT_TOKEN: rmControlSimple,
nvgpu.NVA06C_CTRL_CMD_GPFIFO_SCHEDULE: rmControlSimple,
nvgpu.NVA06C_CTRL_CMD_SET_TIMESLICE: rmControlSimple,
nvgpu.NVA06C_CTRL_CMD_PREEMPT: rmControlSimple,
nvgpu.NV0000_CTRL_CMD_SYSTEM_GET_BUILD_VERSION: ctrlClientSystemGetBuildVersion,
nvgpu.NV0080_CTRL_CMD_FIFO_GET_CHANNELLIST: ctrlDevFIFOGetChannelList,
nvgpu.NV2080_CTRL_CMD_FIFO_DISABLE_CHANNELS: ctrlSubdevFIFODisableChannels,
nvgpu.NV2080_CTRL_CMD_GR_GET_INFO: ctrlSubdevGRGetInfo,
},
allocationClass: map[uint32]allocationClassHandler{
nvgpu.NV01_ROOT: rmAllocSimple[nvgpu.Handle],
nvgpu.NV01_ROOT_NON_PRIV: rmAllocSimple[nvgpu.Handle],
nvgpu.NV01_ROOT_CLIENT: rmAllocSimple[nvgpu.Handle],
nvgpu.NV01_EVENT_OS_EVENT: rmAllocEventOSEvent,
nvgpu.NV01_DEVICE_0: rmAllocSimple[nvgpu.NV0080_ALLOC_PARAMETERS],
nvgpu.NV20_SUBDEVICE_0: rmAllocSimple[nvgpu.NV2080_ALLOC_PARAMETERS],
nvgpu.NV50_THIRD_PARTY_P2P: rmAllocSimple[nvgpu.NV503C_ALLOC_PARAMETERS],
nvgpu.GT200_DEBUGGER: rmAllocSimple[nvgpu.NV83DE_ALLOC_PARAMETERS],
nvgpu.FERMI_CONTEXT_SHARE_A: rmAllocSimple[nvgpu.NV_CTXSHARE_ALLOCATION_PARAMETERS],
nvgpu.FERMI_VASPACE_A: rmAllocSimple[nvgpu.NV_VASPACE_ALLOCATION_PARAMETERS],
nvgpu.KEPLER_CHANNEL_GROUP_A: rmAllocSimple[nvgpu.NV_CHANNEL_GROUP_ALLOCATION_PARAMETERS],
nvgpu.TURING_CHANNEL_GPFIFO_A: rmAllocSimple[nvgpu.NV_CHANNEL_ALLOC_PARAMS],
nvgpu.AMPERE_CHANNEL_GPFIFO_A: rmAllocSimple[nvgpu.NV_CHANNEL_ALLOC_PARAMS],
nvgpu.TURING_DMA_COPY_A: rmAllocSimple[nvgpu.NVB0B5_ALLOCATION_PARAMETERS],
nvgpu.AMPERE_DMA_COPY_A: rmAllocSimple[nvgpu.NVB0B5_ALLOCATION_PARAMETERS],
nvgpu.AMPERE_DMA_COPY_B: rmAllocSimple[nvgpu.NVB0B5_ALLOCATION_PARAMETERS],
nvgpu.HOPPER_DMA_COPY_A: rmAllocSimple[nvgpu.NVB0B5_ALLOCATION_PARAMETERS],
nvgpu.TURING_COMPUTE_A: rmAllocSimple[nvgpu.NV_GR_ALLOCATION_PARAMETERS],
nvgpu.AMPERE_COMPUTE_A: rmAllocSimple[nvgpu.NV_GR_ALLOCATION_PARAMETERS],
nvgpu.AMPERE_COMPUTE_B: rmAllocSimple[nvgpu.NV_GR_ALLOCATION_PARAMETERS],
nvgpu.ADA_COMPUTE_A: rmAllocSimple[nvgpu.NV_GR_ALLOCATION_PARAMETERS],
nvgpu.HOPPER_COMPUTE_A: rmAllocSimple[nvgpu.NV_GR_ALLOCATION_PARAMETERS],
nvgpu.HOPPER_USERMODE_A: rmAllocSimple[nvgpu.NV_HOPPER_USERMODE_A_PARAMS],
nvgpu.GF100_SUBDEVICE_MASTER: rmAllocNoParams,
nvgpu.TURING_USERMODE_A: rmAllocNoParams,
nvgpu.NV_MEMORY_FABRIC: rmAllocSimple[nvgpu.NV00F8_ALLOCATION_PARAMETERS],
},
}
})
v525_105_17 := addDriverABI(525, 105, 17, v525_60_13)
_ = addDriverABI(525, 125, 06, v525_105_17)
})
}
+5
View File
@@ -38,6 +38,7 @@ import (
"gvisor.dev/gvisor/pkg/rand"
"gvisor.dev/gvisor/pkg/refs"
"gvisor.dev/gvisor/pkg/sentry/control"
"gvisor.dev/gvisor/pkg/sentry/devices/nvproxy"
"gvisor.dev/gvisor/pkg/sentry/fdimport"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/host"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs"
@@ -304,6 +305,10 @@ func New(args Args) (*Loader, error) {
return nil, fmt.Errorf("setting up memory usage: %w", err)
}
if args.Conf.NVProxy {
nvproxy.Init()
}
kernel.IOUringEnabled = args.Conf.IOUring
info := containerInfo{