From 72abe3c92766ab447beb41d6a9b56d095fe2abc4 Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Wed, 7 Dec 2022 12:16:25 +0000 Subject: [PATCH] nvidia: refactor everything out of the main class and use official naming and structs where possible --- src/ioctl.rs | 2 +- src/lib.rs | 495 +++++++++---------------------------- src/nvidia/ctrl0000vgpu.rs | 44 ++++ src/nvidia/ctrl0080gpu.rs | 11 + src/nvidia/ctrl2080bus.rs | 13 + src/nvidia/ctrl2080gpu.rs | 7 + src/nvidia/ctrl9096.rs | 3 + src/nvidia/ctrla081.rs | 153 ++++++++++++ src/nvidia/ctrla082.rs | 108 ++++++++ src/nvidia/error.rs | 141 +++++++++++ src/nvidia/ioctl.rs | 4 + src/nvidia/mod.rs | 11 + src/nvidia/nvos.rs | 40 +++ src/nvidia/nvtypes.rs | 1 + src/utils.rs | 19 ++ src/uuid.rs | 25 ++ 16 files changed, 703 insertions(+), 374 deletions(-) create mode 100644 src/nvidia/ctrl0000vgpu.rs create mode 100644 src/nvidia/ctrl0080gpu.rs create mode 100644 src/nvidia/ctrl2080bus.rs create mode 100644 src/nvidia/ctrl2080gpu.rs create mode 100644 src/nvidia/ctrl9096.rs create mode 100644 src/nvidia/ctrla081.rs create mode 100644 src/nvidia/ctrla082.rs create mode 100644 src/nvidia/error.rs create mode 100644 src/nvidia/ioctl.rs create mode 100644 src/nvidia/mod.rs create mode 100644 src/nvidia/nvos.rs create mode 100644 src/nvidia/nvtypes.rs create mode 100644 src/utils.rs create mode 100644 src/uuid.rs diff --git a/src/ioctl.rs b/src/ioctl.rs index 057a943..8ef6f34 100644 --- a/src/ioctl.rs +++ b/src/ioctl.rs @@ -19,6 +19,6 @@ pub const fn _IOC(a: c_ulong, b: c_ulong, c: c_ulong, d: c_ulong) -> c_ulong { #[allow(non_snake_case)] #[inline] -pub const fn _IOCWR(b: c_ulong, c: c_ulong) -> c_ulong { +pub const fn _IOWR(b: c_ulong, c: c_ulong) -> c_ulong { _IOC(_IOC_READ | _IOC_WRITE, b, c, mem::size_of::() as c_ulong) } diff --git a/src/lib.rs b/src/lib.rs index 264fa2a..c0839c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,6 @@ use std::borrow::Cow; use std::cmp; use std::collections::HashMap; use std::env; -use std::fmt; use std::fs; use std::io::{ErrorKind, Write}; use std::mem; @@ -33,11 +32,37 @@ mod format; mod human_number; mod ioctl; mod log; +mod nvidia; +mod utils; +mod uuid; use crate::config::Config; -use crate::format::{CStrFormat, HexFormat, HexFormatSlice, StraightFormat, WideCharFormat}; -use crate::ioctl::_IOCWR; +use crate::format::WideCharFormat; use crate::log::{error, info}; +use crate::nvidia::ctrl0000vgpu::{ + Nv0000CtrlVgpuGetStartDataParams, NV0000_CTRL_CMD_VGPU_GET_START_DATA, +}; +use crate::nvidia::ctrl0080gpu::{ + Nv0080CtrlGpuGetVirtualizationModeParams, NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE, + NV0080_CTRL_GPU_VIRTUALIZATION_MODE_HOST, +}; +use crate::nvidia::ctrl2080bus::{Nv2080CtrlBusGetPciInfoParams, NV2080_CTRL_CMD_BUS_GET_PCI_INFO}; +use crate::nvidia::ctrl2080gpu::NV2080_CTRL_CMD_GPU_GET_INFOROM_OBJECT_VERSION; +use crate::nvidia::ctrl9096::NV9096_CTRL_CMD_GET_ZBC_CLEAR_TABLE; +use crate::nvidia::ctrla081::{ + NvA081CtrlCmdVgpuConfigGetMigrationCapParams, NvA081CtrlVgpuConfigGetVgpuTypeInfoParams, + NvA081CtrlVgpuInfo, NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP, + NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO, +}; +use crate::nvidia::ctrla082::{ + NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams, + NVA082_CTRL_CMD_HOST_VGPU_DEVICE_GET_VGPU_TYPE_INFO, +}; +use crate::nvidia::error::{ + NV_ERR_BUSY_RETRY, NV_ERR_NOT_SUPPORTED, NV_ERR_OBJECT_NOT_FOUND, NV_OK, +}; +use crate::nvidia::nvos::{Nvos54Parameters, NV_ESC_RM_CONTROL}; +use crate::uuid::Uuid; static LAST_MDEV_UUID: Mutex> = parking_lot::const_mutex(None); @@ -65,187 +90,6 @@ static CONFIG: Config = { const DEFAULT_CONFIG_PATH: &str = "/etc/vgpu_unlock/config.toml"; const DEFAULT_PROFILE_OVERRIDE_CONFIG_PATH: &str = "/etc/vgpu_unlock/profile_override.toml"; -/// Pulled from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/kernel-open/common/inc/nv-ioctl-numbers.h -const NV_IOCTL_MAGIC: c_ulong = b'F' as _; - -/// Value of the "request" argument used by `nvidia-vgpud` and `nvidia-vgpu-mgr` when calling -/// ioctl to read the PCI device ID, type, and many other things from the driver. -/// -/// Pulled from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/src/nvidia/arch/nvalloc/unix/include/nv_escape.h -/// and [`nvidia_ioctl`](https://github.com/NVIDIA/open-gpu-kernel-modules/blob/98553501593ef05bddcc438689ed1136f732d40a/kernel-open/nvidia/nv.c) -/// and [`__NV_IOWR`](https://github.com/NVIDIA/open-gpu-kernel-modules/blob/98553501593ef05bddcc438689ed1136f732d40a/kernel-open/common/inc/nv.h) -/// showing that `_IOCWR` is used to derive the I/O control request codes. -const NV_ESC_RM_CONTROL: c_ulong = _IOCWR::(NV_IOCTL_MAGIC, 0x2a); - -/// `result` is a pointer to `VgpuStart`. -const OP_READ_START_CALL: u32 = 0xc01; - -/// `result` is a pointer to `uint32_t`. -const NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE: u32 = 0x800289; - -/// `result` is a pointer to `uint32_t[4]`, the second element (index 1) is the device ID, the -/// forth element (index 3) is the subsystem ID. -/// -/// Pulled from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/src/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080bus.h -const NV2080_CTRL_CMD_BUS_GET_PCI_INFO: u32 = 0x20801801; - -/// `result` is a pointer to `VgpuConfig`. -const OP_READ_VGPU_CFG: u32 = 0xa0820102; - -/// `result` is a pointer to `VgpuConfig`. -/// -/// This RM control command is used starting in vGPU version 15.0 (525.60.12). -const OP_READ_VGPU_CFG2: u32 = 0xA0810103; - -/// `result` is a pointer to `bool`. -const OP_READ_VGPU_MIGRATION_CAP: u32 = 0xa0810112; - -/// `nvidia-vgpu-mgr` expects this value for a vGPU capable GPU. -/// -/// Pulled from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/src/common/sdk/nvidia/inc/ctrl/ctrl0080/ctrl0080gpu.h -const NV0080_CTRL_GPU_VIRTUALIZATION_MODE_HOST: u32 = 3; - -/// When ioctl returns success (retval >= 0) but sets the status value of the arg structure to 3 -/// then `nvidia-vgpud` will sleep for a bit (first 0.1s then 1s then 10s) then issue the same -/// ioctl call again until the status differs from 3. It will attempt this for up to 24h before -/// giving up. -/// -/// See https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/kernel-open/common/inc/nvstatuscodes.h -const NV_OK: u32 = 0x0; -const NV_ERR_BUSY_RETRY: u32 = 0x3; -const NV_ERR_NOT_SUPPORTED: u32 = 0x56; -const NV_ERR_OBJECT_NOT_FOUND: u32 = 0x57; - -/// When issuing ioctl with `NV_ESC_RM_CONTROL` then the `argp` argument is a pointer to a -/// `NVOS54_PARAMETERS` structure like this. -/// -/// See [`NVOS54_PARAMETERS`](https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/src/common/sdk/nvidia/inc/nvos.h) -//#[derive(Debug)] -#[repr(C)] -struct Nvos54Parameters { - /// Initialized prior to call. - h_client: u32, - /// Initialized prior to call. - h_object: u32, - /// Operation type, see comment below. - cmd: u32, - /// Pointer initialized prior to call. - /// Pointee initialized to 0 prior to call. - /// Pointee is written by ioctl call. - params: *mut c_void, - /// Size in bytes of the object referenced in `params`. - params_size: u32, - /// Written by ioctl call. See comment below. - status: u32, -} - -#[derive(Clone, Copy)] -#[repr(C)] -struct Uuid(u32, u16, u16, [u8; 8]); - -impl fmt::Display for Uuid { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", - self.0, - self.1, - self.2, - self.3[0], - self.3[1], - self.3[2], - self.3[3], - self.3[4], - self.3[5], - self.3[6], - self.3[7] - ) - } -} - -#[repr(C)] -struct VgpuStart { - uuid: Uuid, - config_params: [u8; 1024], - qemu_pid: u32, - unknown_414: [u8; 12], -} - -#[repr(C)] -struct VgpuConfig { - vgpu_type: u32, - vgpu_name: [u8; 32], - vgpu_class: [u8; 32], - vgpu_signature: [u8; 128], - features: [u8; 128], - max_instances: u32, - num_heads: u32, - max_resolution_x: u32, - max_resolution_y: u32, - max_pixels: u32, - frl_config: u32, - cuda_enabled: u32, - ecc_supported: u32, - mig_instance_size: u32, - multi_vgpu_supported: u32, - vdev_id: u64, - pdev_id: u64, - fb_length: u64, - mappable_video_size: u64, - fb_reservation: u64, - encoder_capacity: u32, - bar1_length: u64, - frl_enable: u32, - adapter_name: [u8; 64], - adapter_name_unicode: [u16; 64], - short_gpu_name_string: [u8; 64], - licensed_product_name: [u8; 128], - vgpu_extra_params: [u8; 1024], - unknown_end: [u8; 8], -} - -#[repr(C)] -struct VgpuConfig2 { - vgpu_type: u32, - vgpu_name: [u8; 32], - vgpu_class: [u8; 32], - vgpu_signature: [u8; 128], - features: [u8; 128], - max_instances: u32, - num_heads: u32, - max_resolution_x: u32, - max_resolution_y: u32, - max_pixels: u32, - frl_config: u32, - cuda_enabled: u32, - ecc_supported: u32, - mig_instance_size: u32, - multi_vgpu_supported: u32, - vdev_id: u64, - pdev_id: u64, - profile_size: u64, - fb_length: u64, - unknown: u64, - fb_reservation: u64, - mappable_video_size: u64, - encoder_capacity: u32, - bar1_length: u64, - frl_enable: u32, - adapter_name: [u8; 64], - adapter_name_unicode: [u16; 64], - short_gpu_name_string: [u8; 64], - licensed_product_name: [u8; 128], - vgpu_extra_params: [u8; 1024], - unknown_end: [u8; 0xc1c], -} - -#[derive(Debug)] -#[repr(C)] -struct LoadVgpuConfig2 { - vgpu_type: u32, - config: VgpuConfig2, -} - trait VgpuConfigLike { fn vgpu_type(&mut self) -> &mut u32; fn vgpu_name(&mut self) -> &mut [u8; 32]; @@ -279,14 +123,26 @@ trait VgpuConfigLike { } macro_rules! impl_trait_fn { - ($name:ident, $t:ty) => { - fn $name(&mut self) -> &mut $t { - &mut self.$name + ($field:ident, $t:ty) => { + fn $field(&mut self) -> &mut $t { + &mut self.$field + } + }; + ($source_field:ident => $target_field:ident, $t:ty) => { + fn $target_field(&mut self) -> &mut $t { + &mut self.$source_field + } + }; +} +macro_rules! impl_trait_fn_aligned { + ($field:ident, $t:ty) => { + fn $field(&mut self) -> &mut $t { + &mut self.$field.0 } }; } -impl VgpuConfigLike for VgpuConfig { +impl VgpuConfigLike for NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams { impl_trait_fn!(vgpu_type, u32); impl_trait_fn!(vgpu_name, [u8; 32]); impl_trait_fn!(vgpu_class, [u8; 32]); @@ -322,13 +178,13 @@ impl VgpuConfigLike for VgpuConfig { impl_trait_fn!(vgpu_extra_params, [u8; 1024]); } -impl VgpuConfigLike for VgpuConfig2 { +impl VgpuConfigLike for NvA081CtrlVgpuInfo { impl_trait_fn!(vgpu_type, u32); impl_trait_fn!(vgpu_name, [u8; 32]); impl_trait_fn!(vgpu_class, [u8; 32]); impl_trait_fn!(vgpu_signature, [u8; 128]); - impl_trait_fn!(features, [u8; 128]); - impl_trait_fn!(max_instances, u32); + impl_trait_fn!(license => features, [u8; 128]); + impl_trait_fn!(max_instance => max_instances, u32); impl_trait_fn!(num_heads, u32); impl_trait_fn!(max_resolution_x, u32); impl_trait_fn!(max_resolution_y, u32); @@ -336,20 +192,20 @@ impl VgpuConfigLike for VgpuConfig2 { impl_trait_fn!(frl_config, u32); impl_trait_fn!(cuda_enabled, u32); impl_trait_fn!(ecc_supported, u32); - impl_trait_fn!(mig_instance_size, u32); + impl_trait_fn!(gpu_instance_size => mig_instance_size, u32); impl_trait_fn!(multi_vgpu_supported, u32); - impl_trait_fn!(vdev_id, u64); - impl_trait_fn!(pdev_id, u64); + impl_trait_fn_aligned!(vdev_id, u64); + impl_trait_fn_aligned!(pdev_id, u64); fn profile_size(&mut self) -> Option<&mut u64> { - Some(&mut self.profile_size) + Some(&mut self.profile_size.0) } - impl_trait_fn!(fb_length, u64); - impl_trait_fn!(mappable_video_size, u64); - impl_trait_fn!(fb_reservation, u64); + impl_trait_fn_aligned!(fb_length, u64); + impl_trait_fn_aligned!(mappable_video_size, u64); + impl_trait_fn_aligned!(fb_reservation, u64); impl_trait_fn!(encoder_capacity, u32); - impl_trait_fn!(bar1_length, u64); + impl_trait_fn_aligned!(bar1_length, u64); impl_trait_fn!(frl_enable, u32); impl_trait_fn!(adapter_name, [u8; 64]); impl_trait_fn!(adapter_name_unicode, [u16; 64]); @@ -398,125 +254,6 @@ struct VgpuProfileOverride<'a> { license_type: Option<&'a str>, } -impl fmt::Debug for VgpuStart { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("VgpuStart") - .field("uuid", &format_args!("{{{}}}", self.uuid)) - .field("config_params", &CStrFormat(&self.config_params)) - .field("qemu_pid", &self.qemu_pid) - .field("unknown_414", &StraightFormat(&self.unknown_414)) - .finish() - } -} - -impl fmt::Debug for VgpuConfig { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let vgpu_signature = self.vgpu_signature[..] - .split(|&x| x == 0) - .next() - .unwrap_or(&[]); - let vgpu_extra_params = self.vgpu_extra_params[..] - .split(|&x| x == 0) - .next() - .unwrap_or(&[]); - - f.debug_struct("VgpuConfig") - .field("vgpu_type", &self.vgpu_type) - .field("vgpu_name", &CStrFormat(&self.vgpu_name)) - .field("vgpu_class", &CStrFormat(&self.vgpu_class)) - .field("vgpu_signature", &HexFormatSlice(vgpu_signature)) - .field("features", &CStrFormat(&self.features)) - .field("max_instances", &self.max_instances) - .field("num_heads", &self.num_heads) - .field("max_resolution_x", &self.max_resolution_x) - .field("max_resolution_y", &self.max_resolution_y) - .field("max_pixels", &self.max_pixels) - .field("frl_config", &self.frl_config) - .field("cuda_enabled", &self.cuda_enabled) - .field("ecc_supported", &self.ecc_supported) - .field("mig_instance_size", &self.mig_instance_size) - .field("multi_vgpu_supported", &self.multi_vgpu_supported) - .field("vdev_id", &HexFormat(self.vdev_id)) - .field("pdev_id", &HexFormat(self.pdev_id)) - .field("fb_length", &HexFormat(self.fb_length)) - .field("mappable_video_size", &HexFormat(self.mappable_video_size)) - .field("fb_reservation", &HexFormat(self.fb_reservation)) - .field("encoder_capacity", &HexFormat(self.encoder_capacity)) - .field("bar1_length", &HexFormat(self.bar1_length)) - .field("frl_enable", &self.frl_enable) - .field("adapter_name", &CStrFormat(&self.adapter_name)) - .field( - "adapter_name_unicode", - &WideCharFormat(&self.adapter_name_unicode), - ) - .field( - "short_gpu_name_string", - &CStrFormat(&self.short_gpu_name_string), - ) - .field( - "licensed_product_name", - &CStrFormat(&self.licensed_product_name), - ) - .field("vgpu_extra_params", &HexFormatSlice(vgpu_extra_params)) - .finish() - } -} - -impl fmt::Debug for VgpuConfig2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let vgpu_signature = self.vgpu_signature[..] - .split(|&x| x == 0) - .next() - .unwrap_or(&[]); - let vgpu_extra_params = self.vgpu_extra_params[..] - .split(|&x| x == 0) - .next() - .unwrap_or(&[]); - - f.debug_struct("VgpuConfig2") - .field("vgpu_type", &self.vgpu_type) - .field("vgpu_name", &CStrFormat(&self.vgpu_name)) - .field("vgpu_class", &CStrFormat(&self.vgpu_class)) - .field("vgpu_signature", &HexFormatSlice(vgpu_signature)) - .field("features", &CStrFormat(&self.features)) - .field("max_instances", &self.max_instances) - .field("num_heads", &self.num_heads) - .field("max_resolution_x", &self.max_resolution_x) - .field("max_resolution_y", &self.max_resolution_y) - .field("max_pixels", &self.max_pixels) - .field("frl_config", &self.frl_config) - .field("cuda_enabled", &self.cuda_enabled) - .field("ecc_supported", &self.ecc_supported) - .field("mig_instance_size", &self.mig_instance_size) - .field("multi_vgpu_supported", &self.multi_vgpu_supported) - .field("vdev_id", &HexFormat(self.vdev_id)) - .field("pdev_id", &HexFormat(self.pdev_id)) - .field("profile_size", &HexFormat(self.profile_size)) - .field("fb_length", &HexFormat(self.fb_length)) - .field("unknown", &HexFormat(self.unknown)) - .field("fb_reservation", &HexFormat(self.fb_reservation)) - .field("mappable_video_size", &HexFormat(self.mappable_video_size)) - .field("encoder_capacity", &HexFormat(self.encoder_capacity)) - .field("bar1_length", &HexFormat(self.bar1_length)) - .field("frl_enable", &self.frl_enable) - .field("adapter_name", &CStrFormat(&self.adapter_name)) - .field( - "adapter_name_unicode", - &WideCharFormat(&self.adapter_name_unicode), - ) - .field( - "short_gpu_name_string", - &CStrFormat(&self.short_gpu_name_string), - ) - .field( - "licensed_product_name", - &CStrFormat(&self.licensed_product_name), - ) - .field("vgpu_extra_params", &CStrFormat(vgpu_extra_params)) - .finish() - } -} - fn check_size(name: &str, actual_size: usize, expected_size: usize) -> bool { if actual_size != expected_size { error!( @@ -565,7 +302,7 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - // Safety: NVIDIA's driver itself uses `sizeof` when calculating the ioctl number and so does // this hook so the structure passed in should be of the correct size. - let io_data = &mut *(argp as *mut Nvos54Parameters); + let io_data: &mut Nvos54Parameters = &mut *argp.cast(); if io_data.status == NV_ERR_BUSY_RETRY { // Driver will try again. @@ -593,19 +330,20 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - match io_data.cmd { NV2080_CTRL_CMD_BUS_GET_PCI_INFO - if check_size!(NV2080_CTRL_CMD_BUS_GET_PCI_INFO, size: 16) && CONFIG.unlock => + if check_size!( + NV2080_CTRL_CMD_BUS_GET_PCI_INFO, + Nv2080CtrlBusGetPciInfoParams + ) && CONFIG.unlock => { - // Lookup address of the device and subsystem IDs. - let devid_ptr: *mut u32 = io_data.params.add(0).cast(); - let subsysid_ptr: *mut u32 = io_data.params.add(4).cast(); + let params: &mut Nv2080CtrlBusGetPciInfoParams = &mut *io_data.params.cast(); - let orig_devid = *devid_ptr; - let orig_subsysid = *subsysid_ptr; + let orig_device_id = params.pci_device_id; + let orig_sub_system_id = params.pci_sub_system_id; - let actual_devid = (orig_devid & 0xffff0000) >> 16; - let actual_subsysid = (orig_subsysid & 0xffff0000) >> 16; + let actual_device_id = (orig_device_id & 0xffff0000) >> 16; + let actual_sub_system_id = (orig_sub_system_id & 0xffff0000) >> 16; - let (spoofed_devid, spoofed_subsysid) = match actual_devid { + let (spoofed_devid, spoofed_subsysid) = match actual_device_id { // Maxwell 0x1340..=0x13bd | 0x174d..=0x179c => { // Tesla M10 @@ -614,12 +352,12 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - // Maxwell 2.0 0x13c0..=0x1436 | 0x1617..=0x1667 | 0x17c2..=0x17fd => { // Tesla M60 - (0x13f2, actual_subsysid) + (0x13f2, actual_sub_system_id) } // Pascal 0x15f0 | 0x15f1 | 0x1b00..=0x1d56 | 0x1725..=0x172f => { // Tesla P40 - (0x1b38, actual_subsysid) + (0x1b38, actual_sub_system_id) } // GV100 Volta // @@ -627,7 +365,7 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - // 0x1dba = Quadro GV100 32GB 0x1d81 | 0x1dba => { // Tesla V100 32GB PCIE - (0x1db6, actual_subsysid) + (0x1db6, actual_sub_system_id) } // Turing 0x1e02..=0x1ff9 | 0x2182..=0x21d1 => { @@ -637,58 +375,82 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - // Ampere 0x2200..=0x2600 => { // RTX A6000 - (0x2230, actual_subsysid) + (0x2230, actual_sub_system_id) } - _ => (actual_devid, actual_subsysid), + _ => (actual_device_id, actual_sub_system_id), }; - *devid_ptr = (orig_devid & 0xffff) | (spoofed_devid << 16); - *subsysid_ptr = (orig_subsysid & 0xffff) | (spoofed_subsysid << 16); + params.pci_device_id = (orig_device_id & 0xffff) | (spoofed_devid << 16); + params.pci_sub_system_id = (orig_sub_system_id & 0xffff) | (spoofed_subsysid << 16); } NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE - if check_size!(NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE, u32) && CONFIG.unlock => + if check_size!( + NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE, + Nv0080CtrlGpuGetVirtualizationModeParams + ) && CONFIG.unlock => { - let dev_type_ptr: *mut u32 = io_data.params.cast(); + let params: &mut Nv0080CtrlGpuGetVirtualizationModeParams = &mut *io_data.params.cast(); // Set device type to vGPU capable. - *dev_type_ptr = NV0080_CTRL_GPU_VIRTUALIZATION_MODE_HOST; + params.virtualization_mode = NV0080_CTRL_GPU_VIRTUALIZATION_MODE_HOST; } - OP_READ_VGPU_MIGRATION_CAP - if check_size!(OP_READ_VGPU_MIGRATION_CAP, u8) && CONFIG.unlock_migration => + NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP + if check_size!( + NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP, + NvA081CtrlCmdVgpuConfigGetMigrationCapParams + ) && CONFIG.unlock_migration => { - let migration_enabled: *mut u8 = io_data.params.cast(); + let params: &mut NvA081CtrlCmdVgpuConfigGetMigrationCapParams = + &mut *io_data.params.cast(); - *migration_enabled = 1; + params.migration_cap = 1; } _ => {} } if io_data.status == NV_OK { match io_data.cmd { - OP_READ_VGPU_CFG if check_size!(OP_READ_VGPU_CFG, VgpuConfig) => { - let config = &mut *(io_data.params as *mut VgpuConfig); + NV0000_CTRL_CMD_VGPU_GET_START_DATA + if check_size!( + NV0000_CTRL_CMD_VGPU_GET_START_DATA, + Nv0000CtrlVgpuGetStartDataParams + ) => + { + let config: &Nv0000CtrlVgpuGetStartDataParams = &*io_data.params.cast(); info!("{:#?}", config); - if !handle_profile_override(config) { + *LAST_MDEV_UUID.lock() = Some(config.mdev_uuid); + } + NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO + if check_size!( + NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO, + NvA081CtrlVgpuConfigGetVgpuTypeInfoParams + ) => + { + let params: &mut NvA081CtrlVgpuConfigGetVgpuTypeInfoParams = + &mut *io_data.params.cast(); + info!("{:#?}", params); + + if !handle_profile_override(&mut params.vgpu_type_info) { error!("Failed to apply profile override"); return -1; } } - OP_READ_VGPU_CFG2 if check_size!(OP_READ_VGPU_CFG2, LoadVgpuConfig2) => { - let config = &mut *io_data.params.cast::(); - info!("{:#?}", config); + NVA082_CTRL_CMD_HOST_VGPU_DEVICE_GET_VGPU_TYPE_INFO + if check_size!( + NVA082_CTRL_CMD_HOST_VGPU_DEVICE_GET_VGPU_TYPE_INFO, + NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams + ) => + { + let params: &mut NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams = + &mut *io_data.params.cast(); + info!("{:#?}", params); - if !handle_profile_override(&mut config.config) { + if !handle_profile_override(params) { error!("Failed to apply profile override"); return -1; } } - OP_READ_START_CALL if check_size!(OP_READ_START_CALL, VgpuStart) => { - let config = &*(io_data.params as *const VgpuStart); - info!("{:#?}", config); - - *LAST_MDEV_UUID.lock() = Some(config.uuid); - } _ => {} } } @@ -697,15 +459,17 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - // Things seems to work fine even if some operations that fail result in failed assertions. // So here we change the status value for these cases to cleanup the logs for // `nvidia-vgpu-mgr`. - if io_data.cmd == 0xa0820104 || io_data.cmd == 0x90960103 { + if io_data.cmd == 0xa0820104 || io_data.cmd == NV9096_CTRL_CMD_GET_ZBC_CLEAR_TABLE { io_data.status = NV_OK; } else { - error!("cmd: 0x{:x} failed.", io_data.cmd); + error!("cmd: {:#x} failed.", io_data.cmd); } } // Workaround for some Maxwell cards not supporting reading inforom. - if io_data.cmd == 0x2080014b && io_data.status == NV_ERR_NOT_SUPPORTED { + if io_data.cmd == NV2080_CTRL_CMD_GPU_GET_INFOROM_OBJECT_VERSION + && io_data.status == NV_ERR_NOT_SUPPORTED + { io_data.status = NV_ERR_OBJECT_NOT_FOUND; } @@ -995,18 +759,3 @@ fn apply_profile_override( true } - -#[cfg(test)] -mod test { - use std::mem; - - use super::{LoadVgpuConfig2, VgpuConfig, VgpuConfig2, VgpuStart}; - - #[test] - fn verify_sizes() { - assert_eq!(mem::size_of::(), 0x420); - assert_eq!(mem::size_of::(), 0x738); - assert_eq!(mem::size_of::(), 0x1358); - assert_eq!(mem::size_of::(), 0x1360); - } -} diff --git a/src/nvidia/ctrl0000vgpu.rs b/src/nvidia/ctrl0000vgpu.rs new file mode 100644 index 0000000..4389bda --- /dev/null +++ b/src/nvidia/ctrl0000vgpu.rs @@ -0,0 +1,44 @@ +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/758b4ee8189c5198504cb1c3c5bc29027a9118a3/src/common/sdk/nvidia/inc/ctrl/ctrl0000/ctrl0000vgpu.h +use std::fmt; + +use crate::format::{CStrFormat, HexFormat}; +use crate::uuid::Uuid; + +pub const NV0000_CTRL_CMD_VGPU_GET_START_DATA: u32 = 0xc01; + +/// See `NV0000_CTRL_VGPU_GET_START_DATA_PARAMS` +#[repr(C)] +pub struct Nv0000CtrlVgpuGetStartDataParams { + // [u8; VM_UUID_SIZE] + pub mdev_uuid: Uuid, + pub config_params: [u8; 1024], + pub qemu_pid: u32, + pub gpu_pci_id: u32, + pub vgpu_id: u16, + pub gpu_pci_bdf: u32, +} + +impl fmt::Debug for Nv0000CtrlVgpuGetStartDataParams { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Nv0000CtrlVgpuGetStartDataParams") + .field("mdev_uuid", &format_args!("{{{}}}", self.mdev_uuid)) + .field("config_params", &CStrFormat(&self.config_params)) + .field("qemu_pid", &self.qemu_pid) + .field("gpu_pci_id", &HexFormat(&self.gpu_pci_id)) + .field("vgpu_id", &self.vgpu_id) + .field("gpu_pci_bdf", &self.gpu_pci_bdf) + .finish() + } +} + +#[cfg(test)] +mod test { + use std::mem; + + use super::Nv0000CtrlVgpuGetStartDataParams; + + #[test] + fn verify_sizes() { + assert_eq!(mem::size_of::(), 0x420); + } +} diff --git a/src/nvidia/ctrl0080gpu.rs b/src/nvidia/ctrl0080gpu.rs new file mode 100644 index 0000000..df16f15 --- /dev/null +++ b/src/nvidia/ctrl0080gpu.rs @@ -0,0 +1,11 @@ +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/758b4ee8189c5198504cb1c3c5bc29027a9118a3/src/common/sdk/nvidia/inc/ctrl/ctrl0080/ctrl0080gpu.h + +pub const NV0080_CTRL_CMD_GPU_GET_VIRTUALIZATION_MODE: u32 = 0x800289; + +/// `nvidia-vgpu-mgr` expects this value for a vGPU capable GPU. +pub const NV0080_CTRL_GPU_VIRTUALIZATION_MODE_HOST: u32 = 0x00000003; + +/// See `NV0080_CTRL_GPU_GET_VIRTUALIZATION_MODE_PARAMS` +pub struct Nv0080CtrlGpuGetVirtualizationModeParams { + pub virtualization_mode: u32, +} diff --git a/src/nvidia/ctrl2080bus.rs b/src/nvidia/ctrl2080bus.rs new file mode 100644 index 0000000..a478607 --- /dev/null +++ b/src/nvidia/ctrl2080bus.rs @@ -0,0 +1,13 @@ +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/5f40a5aee5ef9c92085836bf5b5a9056174f07f1/src/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080bus.h + +pub const NV2080_CTRL_CMD_BUS_GET_PCI_INFO: u32 = 0x20801801; + +/// See `NV2080_CTRL_BUS_GET_PCI_INFO_PARAMS` +//#[derive(Debug)] +#[repr(C)] +pub struct Nv2080CtrlBusGetPciInfoParams { + pub pci_device_id: u32, + pub pci_sub_system_id: u32, + pub pci_revision_id: u32, + pub pci_ext_device_id: u32, +} diff --git a/src/nvidia/ctrl2080gpu.rs b/src/nvidia/ctrl2080gpu.rs new file mode 100644 index 0000000..1025893 --- /dev/null +++ b/src/nvidia/ctrl2080gpu.rs @@ -0,0 +1,7 @@ +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/5f40a5aee5ef9c92085836bf5b5a9056174f07f1/src/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080gpu.h + +pub const NV_GRID_LICENSE_INFO_MAX_LENGTH: usize = 128; + +pub const NV2080_GPU_MAX_NAME_STRING_LENGTH: usize = 0x0000040; + +pub const NV2080_CTRL_CMD_GPU_GET_INFOROM_OBJECT_VERSION: u32 = 0x2080014b; diff --git a/src/nvidia/ctrl9096.rs b/src/nvidia/ctrl9096.rs new file mode 100644 index 0000000..6fb6b20 --- /dev/null +++ b/src/nvidia/ctrl9096.rs @@ -0,0 +1,3 @@ +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/90eb10774f1c53d2364eacf9fa8f0c7a92b1b824/src/common/sdk/nvidia/inc/ctrl/ctrl9096.h + +pub const NV9096_CTRL_CMD_GET_ZBC_CLEAR_TABLE: u32 = 0x90960103; diff --git a/src/nvidia/ctrla081.rs b/src/nvidia/ctrla081.rs new file mode 100644 index 0000000..759df10 --- /dev/null +++ b/src/nvidia/ctrla081.rs @@ -0,0 +1,153 @@ +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/758b4ee8189c5198504cb1c3c5bc29027a9118a3/src/common/sdk/nvidia/inc/ctrl/ctrla081.h +use std::fmt; + +use super::ctrl2080gpu::{NV2080_GPU_MAX_NAME_STRING_LENGTH, NV_GRID_LICENSE_INFO_MAX_LENGTH}; +use crate::format::{CStrFormat, HexFormat, HexFormatSlice, WideCharFormat}; +use crate::utils::AlignedU64; + +pub const NVA081_VGPU_STRING_BUFFER_SIZE: usize = 32; +pub const NVA081_VGPU_SIGNATURE_SIZE: usize = 128; + +pub const NVA081_EXTRA_PARAMETERS_SIZE: usize = 1024; + +/// See `NVA081_CTRL_VGPU_CONFIG_INFO` +// Set `align(8)` for `NVA081_CTRL_VGPU_CONFIG_GET_VGPU_TYPE_INFO_PARAMS` +#[repr(C, align(8))] +pub struct NvA081CtrlVgpuInfo { + pub vgpu_type: u32, + pub vgpu_name: [u8; NVA081_VGPU_STRING_BUFFER_SIZE], + pub vgpu_class: [u8; NVA081_VGPU_STRING_BUFFER_SIZE], + pub vgpu_signature: [u8; NVA081_VGPU_SIGNATURE_SIZE], + pub license: [u8; NV_GRID_LICENSE_INFO_MAX_LENGTH], + pub max_instance: u32, + pub num_heads: u32, + pub max_resolution_x: u32, + pub max_resolution_y: u32, + pub max_pixels: u32, + pub frl_config: u32, + pub cuda_enabled: u32, + pub ecc_supported: u32, + pub gpu_instance_size: u32, + pub multi_vgpu_supported: u32, + pub vdev_id: AlignedU64, + pub pdev_id: AlignedU64, + pub profile_size: AlignedU64, + pub fb_length: AlignedU64, + pub gsp_heap_size: AlignedU64, + pub fb_reservation: AlignedU64, + pub mappable_video_size: AlignedU64, + pub encoder_capacity: u32, + pub bar1_length: AlignedU64, + pub frl_enable: u32, + pub adapter_name: [u8; NV2080_GPU_MAX_NAME_STRING_LENGTH], + pub adapter_name_unicode: [u16; NV2080_GPU_MAX_NAME_STRING_LENGTH], + pub short_gpu_name_string: [u8; NV2080_GPU_MAX_NAME_STRING_LENGTH], + pub licensed_product_name: [u8; NV_GRID_LICENSE_INFO_MAX_LENGTH], + pub vgpu_extra_params: [u8; NVA081_EXTRA_PARAMETERS_SIZE], + pub ftrace_enable: u32, + pub gpu_direct_supported: u32, + pub nvlink_p2p_supported: u32, + pub multi_vgpu_exclusive: u32, + pub exclusive_type: u32, + pub exclusive_size: u32, + pub gpu_instance_profile_id: u32, + unknown_end: [u8; 0xc00], +} + +pub const NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO: u32 = 0xa0810103; + +/// This RM control command is used starting in vGPU version 15.0 (525.60.12). +/// +/// See `NVA081_CTRL_VGPU_CONFIG_GET_VGPU_TYPE_INFO_PARAMS` +#[derive(Debug)] +#[repr(C)] +pub struct NvA081CtrlVgpuConfigGetVgpuTypeInfoParams { + pub vgpu_type: u32, + pub vgpu_type_info: NvA081CtrlVgpuInfo, +} + +pub const NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP: u32 = 0xa0810112; + +/// See `NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP_PARAMS` +#[repr(C)] +pub struct NvA081CtrlCmdVgpuConfigGetMigrationCapParams { + pub migration_cap: u8, +} + +impl fmt::Debug for NvA081CtrlVgpuInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let vgpu_signature = self.vgpu_signature[..] + .split(|&x| x == 0) + .next() + .unwrap_or(&[]); + let vgpu_extra_params = self.vgpu_extra_params[..] + .split(|&x| x == 0) + .next() + .unwrap_or(&[]); + + f.debug_struct("NvA081CtrlVgpuInfo") + .field("vgpu_type", &self.vgpu_type) + .field("vgpu_name", &CStrFormat(&self.vgpu_name)) + .field("vgpu_class", &CStrFormat(&self.vgpu_class)) + .field("vgpu_signature", &HexFormatSlice(vgpu_signature)) + .field("license", &CStrFormat(&self.license)) + .field("max_instance", &self.max_instance) + .field("num_heads", &self.num_heads) + .field("max_resolution_x", &self.max_resolution_x) + .field("max_resolution_y", &self.max_resolution_y) + .field("max_pixels", &self.max_pixels) + .field("frl_config", &self.frl_config) + .field("cuda_enabled", &self.cuda_enabled) + .field("ecc_supported", &self.ecc_supported) + .field("gpu_instance_size", &self.gpu_instance_size) + .field("multi_vgpu_supported", &self.multi_vgpu_supported) + .field("vdev_id", &HexFormat(self.vdev_id)) + .field("pdev_id", &HexFormat(self.pdev_id)) + .field("profile_size", &HexFormat(self.profile_size)) + .field("fb_length", &HexFormat(self.fb_length)) + .field("gsp_heap_size", &HexFormat(self.gsp_heap_size)) + .field("fb_reservation", &HexFormat(self.fb_reservation)) + .field("mappable_video_size", &HexFormat(self.mappable_video_size)) + .field("encoder_capacity", &HexFormat(self.encoder_capacity)) + .field("bar1_length", &HexFormat(self.bar1_length)) + .field("frl_enable", &self.frl_enable) + .field("adapter_name", &CStrFormat(&self.adapter_name)) + .field( + "adapter_name_unicode", + &WideCharFormat(&self.adapter_name_unicode), + ) + .field( + "short_gpu_name_string", + &CStrFormat(&self.short_gpu_name_string), + ) + .field( + "licensed_product_name", + &CStrFormat(&self.licensed_product_name), + ) + .field("vgpu_extra_params", &CStrFormat(vgpu_extra_params)) + .field("ftrace_enable", &self.ftrace_enable) + .field("gpu_direct_supported", &self.gpu_direct_supported) + .field("nvlink_p2p_supported", &self.nvlink_p2p_supported) + .field("multi_vgpu_exclusive", &self.multi_vgpu_exclusive) + .field("exclusive_type", &self.exclusive_type) + .field("exclusive_size", &self.exclusive_size) + .field("gpu_instance_profile_id", &self.gpu_instance_profile_id) + .finish() + } +} + +#[cfg(test)] +mod test { + use std::mem; + + use super::{NvA081CtrlVgpuConfigGetVgpuTypeInfoParams, NvA081CtrlVgpuInfo}; + + #[test] + fn verify_sizes() { + assert_eq!(mem::size_of::(), 0x1358); + assert_eq!( + mem::size_of::(), + 0x1360 + ); + } +} diff --git a/src/nvidia/ctrla082.rs b/src/nvidia/ctrla082.rs new file mode 100644 index 0000000..68cca64 --- /dev/null +++ b/src/nvidia/ctrla082.rs @@ -0,0 +1,108 @@ +use std::fmt; + +use crate::format::{CStrFormat, HexFormat, HexFormatSlice, WideCharFormat}; + +/// Inferred based on `NVA082_CTRL_CMD_HOST_VGPU_DEVICE_GET_VGPU_TYPE_INFO_PARAMS` +pub const NVA082_CTRL_CMD_HOST_VGPU_DEVICE_GET_VGPU_TYPE_INFO: u32 = 0xa0820102; + +/// Pulled from a comment in [`NVA081_CTRL_VGPU_INFO`](https://github.com/NVIDIA/open-gpu-kernel-modules/blob/758b4ee8189c5198504cb1c3c5bc29027a9118a3/src/common/sdk/nvidia/inc/ctrl/ctrla081.h#L82) +#[repr(C)] +pub struct NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams { + pub vgpu_type: u32, + pub vgpu_name: [u8; 32], + pub vgpu_class: [u8; 32], + pub vgpu_signature: [u8; 128], + pub features: [u8; 128], + pub max_instances: u32, + pub num_heads: u32, + pub max_resolution_x: u32, + pub max_resolution_y: u32, + pub max_pixels: u32, + pub frl_config: u32, + pub cuda_enabled: u32, + pub ecc_supported: u32, + pub mig_instance_size: u32, + pub multi_vgpu_supported: u32, + pub vdev_id: u64, + pub pdev_id: u64, + pub fb_length: u64, + pub mappable_video_size: u64, + pub fb_reservation: u64, + pub encoder_capacity: u32, + pub bar1_length: u64, + pub frl_enable: u32, + pub adapter_name: [u8; 64], + pub adapter_name_unicode: [u16; 64], + pub short_gpu_name_string: [u8; 64], + pub licensed_product_name: [u8; 128], + pub vgpu_extra_params: [u8; 1024], + unknown_end: [u8; 8], +} + +impl fmt::Debug for NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let vgpu_signature = self.vgpu_signature[..] + .split(|&x| x == 0) + .next() + .unwrap_or(&[]); + let vgpu_extra_params = self.vgpu_extra_params[..] + .split(|&x| x == 0) + .next() + .unwrap_or(&[]); + + f.debug_struct("NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams") + .field("vgpu_type", &self.vgpu_type) + .field("vgpu_name", &CStrFormat(&self.vgpu_name)) + .field("vgpu_class", &CStrFormat(&self.vgpu_class)) + .field("vgpu_signature", &HexFormatSlice(vgpu_signature)) + .field("features", &CStrFormat(&self.features)) + .field("max_instances", &self.max_instances) + .field("num_heads", &self.num_heads) + .field("max_resolution_x", &self.max_resolution_x) + .field("max_resolution_y", &self.max_resolution_y) + .field("max_pixels", &self.max_pixels) + .field("frl_config", &self.frl_config) + .field("cuda_enabled", &self.cuda_enabled) + .field("ecc_supported", &self.ecc_supported) + .field("mig_instance_size", &self.mig_instance_size) + .field("multi_vgpu_supported", &self.multi_vgpu_supported) + .field("vdev_id", &HexFormat(self.vdev_id)) + .field("pdev_id", &HexFormat(self.pdev_id)) + .field("fb_length", &HexFormat(self.fb_length)) + .field("mappable_video_size", &HexFormat(self.mappable_video_size)) + .field("fb_reservation", &HexFormat(self.fb_reservation)) + .field("encoder_capacity", &HexFormat(self.encoder_capacity)) + .field("bar1_length", &HexFormat(self.bar1_length)) + .field("frl_enable", &self.frl_enable) + .field("adapter_name", &CStrFormat(&self.adapter_name)) + .field( + "adapter_name_unicode", + &WideCharFormat(&self.adapter_name_unicode), + ) + .field( + "short_gpu_name_string", + &CStrFormat(&self.short_gpu_name_string), + ) + .field( + "licensed_product_name", + &CStrFormat(&self.licensed_product_name), + ) + .field("vgpu_extra_params", &HexFormatSlice(vgpu_extra_params)) + .finish() + } +} + +#[cfg(test)] +mod test { + use std::mem; + + use super::NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams; + + #[test] + fn verify_sizes() { + assert_eq!( + mem::size_of::(), + 0x738 + ); + } +} diff --git a/src/nvidia/error.rs b/src/nvidia/error.rs new file mode 100644 index 0000000..2b0f45e --- /dev/null +++ b/src/nvidia/error.rs @@ -0,0 +1,141 @@ +#![allow(unused)] + +///! When ioctl returns success (retval >= 0) but sets the status value of the arg structure to 3 +///! then `nvidia-vgpud` will sleep for a bit (first 0.1s then 1s then 10s) then issue the same +///! ioctl call again until the status differs from 3. It will attempt this for up to 24h before +///! giving up. +///! +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/5f40a5aee5ef9c92085836bf5b5a9056174f07f1/kernel-open/common/inc/nvstatuscodes.h + +pub const NV_OK: u32 = 0x00000000; +pub const NV_ERR_GENERIC: u32 = 0x0000ffff; +pub const NV_ERR_BROKEN_FB: u32 = 0x00000001; +pub const NV_ERR_BUFFER_TOO_SMALL: u32 = 0x00000002; +pub const NV_ERR_BUSY_RETRY: u32 = 0x00000003; +pub const NV_ERR_CALLBACK_NOT_SCHEDULED: u32 = 0x00000004; +pub const NV_ERR_CARD_NOT_PRESENT: u32 = 0x00000005; +pub const NV_ERR_CYCLE_DETECTED: u32 = 0x00000006; +pub const NV_ERR_DMA_IN_USE: u32 = 0x00000007; +pub const NV_ERR_DMA_MEM_NOT_LOCKED: u32 = 0x00000008; +pub const NV_ERR_DMA_MEM_NOT_UNLOCKED: u32 = 0x00000009; +pub const NV_ERR_DUAL_LINK_INUSE: u32 = 0x0000000a; +pub const NV_ERR_ECC_ERROR: u32 = 0x0000000b; +pub const NV_ERR_FIFO_BAD_ACCESS: u32 = 0x0000000c; +pub const NV_ERR_FREQ_NOT_SUPPORTED: u32 = 0x0000000d; +pub const NV_ERR_GPU_DMA_NOT_INITIALIZED: u32 = 0x0000000e; +pub const NV_ERR_GPU_IS_LOST: u32 = 0x0000000f; +pub const NV_ERR_GPU_IN_FULLCHIP_RESET: u32 = 0x00000010; +pub const NV_ERR_GPU_NOT_FULL_POWER: u32 = 0x00000011; +pub const NV_ERR_GPU_UUID_NOT_FOUND: u32 = 0x00000012; +pub const NV_ERR_HOT_SWITCH: u32 = 0x00000013; +pub const NV_ERR_I2C_ERROR: u32 = 0x00000014; +pub const NV_ERR_I2C_SPEED_TOO_HIGH: u32 = 0x00000015; +pub const NV_ERR_ILLEGAL_ACTION: u32 = 0x00000016; +pub const NV_ERR_IN_USE: u32 = 0x00000017; +pub const NV_ERR_INFLATE_COMPRESSED_DATA_FAILED: u32 = 0x00000018; +pub const NV_ERR_INSERT_DUPLICATE_NAME: u32 = 0x00000019; +pub const NV_ERR_INSUFFICIENT_RESOURCES: u32 = 0x0000001a; +pub const NV_ERR_INSUFFICIENT_PERMISSIONS: u32 = 0x0000001b; +pub const NV_ERR_INSUFFICIENT_POWER: u32 = 0x0000001c; +pub const NV_ERR_INVALID_ACCESS_TYPE: u32 = 0x0000001d; +pub const NV_ERR_INVALID_ADDRESS: u32 = 0x0000001e; +pub const NV_ERR_INVALID_ARGUMENT: u32 = 0x0000001f; +pub const NV_ERR_INVALID_BASE: u32 = 0x00000020; +pub const NV_ERR_INVALID_CHANNEL: u32 = 0x00000021; +pub const NV_ERR_INVALID_CLASS: u32 = 0x00000022; +pub const NV_ERR_INVALID_CLIENT: u32 = 0x00000023; +pub const NV_ERR_INVALID_COMMAND: u32 = 0x00000024; +pub const NV_ERR_INVALID_DATA: u32 = 0x00000025; +pub const NV_ERR_INVALID_DEVICE: u32 = 0x00000026; +pub const NV_ERR_INVALID_DMA_SPECIFIER: u32 = 0x00000027; +pub const NV_ERR_INVALID_EVENT: u32 = 0x00000028; +pub const NV_ERR_INVALID_FLAGS: u32 = 0x00000029; +pub const NV_ERR_INVALID_FUNCTION: u32 = 0x0000002a; +pub const NV_ERR_INVALID_HEAP: u32 = 0x0000002b; +pub const NV_ERR_INVALID_INDEX: u32 = 0x0000002c; +pub const NV_ERR_INVALID_IRQ_LEVEL: u32 = 0x0000002d; +pub const NV_ERR_INVALID_LIMIT: u32 = 0x0000002e; +pub const NV_ERR_INVALID_LOCK_STATE: u32 = 0x0000002f; +pub const NV_ERR_INVALID_METHOD: u32 = 0x00000030; +pub const NV_ERR_INVALID_OBJECT: u32 = 0x00000031; +pub const NV_ERR_INVALID_OBJECT_BUFFER: u32 = 0x00000032; +pub const NV_ERR_INVALID_OBJECT_HANDLE: u32 = 0x00000033; +pub const NV_ERR_INVALID_OBJECT_NEW: u32 = 0x00000034; +pub const NV_ERR_INVALID_OBJECT_OLD: u32 = 0x00000035; +pub const NV_ERR_INVALID_OBJECT_PARENT: u32 = 0x00000036; +pub const NV_ERR_INVALID_OFFSET: u32 = 0x00000037; +pub const NV_ERR_INVALID_OPERATION: u32 = 0x00000038; +pub const NV_ERR_INVALID_OWNER: u32 = 0x00000039; +pub const NV_ERR_INVALID_PARAM_STRUCT: u32 = 0x0000003a; +pub const NV_ERR_INVALID_PARAMETER: u32 = 0x0000003b; +pub const NV_ERR_INVALID_PATH: u32 = 0x0000003c; +pub const NV_ERR_INVALID_POINTER: u32 = 0x0000003d; +pub const NV_ERR_INVALID_REGISTRY_KEY: u32 = 0x0000003e; +pub const NV_ERR_INVALID_REQUEST: u32 = 0x0000003f; +pub const NV_ERR_INVALID_STATE: u32 = 0x00000040; +pub const NV_ERR_INVALID_STRING_LENGTH: u32 = 0x00000041; +pub const NV_ERR_INVALID_READ: u32 = 0x00000042; +pub const NV_ERR_INVALID_WRITE: u32 = 0x00000043; +pub const NV_ERR_INVALID_XLATE: u32 = 0x00000044; +pub const NV_ERR_IRQ_NOT_FIRING: u32 = 0x00000045; +pub const NV_ERR_IRQ_EDGE_TRIGGERED: u32 = 0x00000046; +pub const NV_ERR_MEMORY_TRAINING_FAILED: u32 = 0x00000047; +pub const NV_ERR_MISMATCHED_SLAVE: u32 = 0x00000048; +pub const NV_ERR_MISMATCHED_TARGET: u32 = 0x00000049; +pub const NV_ERR_MISSING_TABLE_ENTRY: u32 = 0x0000004a; +pub const NV_ERR_MODULE_LOAD_FAILED: u32 = 0x0000004b; +pub const NV_ERR_MORE_DATA_AVAILABLE: u32 = 0x0000004c; +pub const NV_ERR_MORE_PROCESSING_REQUIRED: u32 = 0x0000004d; +pub const NV_ERR_MULTIPLE_MEMORY_TYPES: u32 = 0x0000004e; +pub const NV_ERR_NO_FREE_FIFOS: u32 = 0x0000004f; +pub const NV_ERR_NO_INTR_PENDING: u32 = 0x00000050; +pub const NV_ERR_NO_MEMORY: u32 = 0x00000051; +pub const NV_ERR_NO_SUCH_DOMAIN: u32 = 0x00000052; +pub const NV_ERR_NO_VALID_PATH: u32 = 0x00000053; +pub const NV_ERR_NOT_COMPATIBLE: u32 = 0x00000054; +pub const NV_ERR_NOT_READY: u32 = 0x00000055; +pub const NV_ERR_NOT_SUPPORTED: u32 = 0x00000056; +pub const NV_ERR_OBJECT_NOT_FOUND: u32 = 0x00000057; +pub const NV_ERR_OBJECT_TYPE_MISMATCH: u32 = 0x00000058; +pub const NV_ERR_OPERATING_SYSTEM: u32 = 0x00000059; +pub const NV_ERR_OTHER_DEVICE_FOUND: u32 = 0x0000005a; +pub const NV_ERR_OUT_OF_RANGE: u32 = 0x0000005b; +pub const NV_ERR_OVERLAPPING_UVM_COMMIT: u32 = 0x0000005c; +pub const NV_ERR_PAGE_TABLE_NOT_AVAIL: u32 = 0x0000005d; +pub const NV_ERR_PID_NOT_FOUND: u32 = 0x0000005e; +pub const NV_ERR_PROTECTION_FAULT: u32 = 0x0000005f; +pub const NV_ERR_RC_ERROR: u32 = 0x00000060; +pub const NV_ERR_REJECTED_VBIOS: u32 = 0x00000061; +pub const NV_ERR_RESET_REQUIRED: u32 = 0x00000062; +pub const NV_ERR_STATE_IN_USE: u32 = 0x00000063; +pub const NV_ERR_SIGNAL_PENDING: u32 = 0x00000064; +pub const NV_ERR_TIMEOUT: u32 = 0x00000065; +pub const NV_ERR_TIMEOUT_RETRY: u32 = 0x00000066; +pub const NV_ERR_TOO_MANY_PRIMARIES: u32 = 0x00000067; +pub const NV_ERR_UVM_ADDRESS_IN_USE: u32 = 0x00000068; +pub const NV_ERR_MAX_SESSION_LIMIT_REACHED: u32 = 0x00000069; +pub const NV_ERR_LIB_RM_VERSION_MISMATCH: u32 = 0x0000006a; +pub const NV_ERR_PRIV_SEC_VIOLATION: u32 = 0x0000006b; +pub const NV_ERR_GPU_IN_DEBUG_MODE: u32 = 0x0000006c; +pub const NV_ERR_FEATURE_NOT_ENABLED: u32 = 0x0000006d; +pub const NV_ERR_RESOURCE_LOST: u32 = 0x0000006e; +pub const NV_ERR_PMU_NOT_READY: u32 = 0x0000006f; +pub const NV_ERR_FLCN_ERROR: u32 = 0x00000070; +pub const NV_ERR_FATAL_ERROR: u32 = 0x00000071; +pub const NV_ERR_MEMORY_ERROR: u32 = 0x00000072; +pub const NV_ERR_INVALID_LICENSE: u32 = 0x00000073; +pub const NV_ERR_NVLINK_INIT_ERROR: u32 = 0x00000074; +pub const NV_ERR_NVLINK_MINION_ERROR: u32 = 0x00000075; +pub const NV_ERR_NVLINK_CLOCK_ERROR: u32 = 0x00000076; +pub const NV_ERR_NVLINK_TRAINING_ERROR: u32 = 0x00000077; +pub const NV_ERR_NVLINK_CONFIGURATION_ERROR: u32 = 0x00000078; +pub const NV_ERR_RISCV_ERROR: u32 = 0x00000079; +pub const NV_ERR_FABRIC_MANAGER_NOT_PRESENT: u32 = 0x0000007a; +pub const NV_WARN_HOT_SWITCH: u32 = 0x00010001; +pub const NV_WARN_INCORRECT_PERFMON_DATA: u32 = 0x00010002; +pub const NV_WARN_MISMATCHED_SLAVE: u32 = 0x00010003; +pub const NV_WARN_MISMATCHED_TARGET: u32 = 0x00010004; +pub const NV_WARN_MORE_PROCESSING_REQUIRED: u32 = 0x00010005; +pub const NV_WARN_NOTHING_TO_DO: u32 = 0x00010006; +pub const NV_WARN_NULL_OBJECT: u32 = 0x00010007; +pub const NV_WARN_OUT_OF_RANGE: u32 = 0x00010008; diff --git a/src/nvidia/ioctl.rs b/src/nvidia/ioctl.rs new file mode 100644 index 0000000..9b66793 --- /dev/null +++ b/src/nvidia/ioctl.rs @@ -0,0 +1,4 @@ +use std::os::raw::c_ulong; + +/// Pulled from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/kernel-open/common/inc/nv-ioctl-numbers.h +pub const NV_IOCTL_MAGIC: c_ulong = b'F' as _; diff --git a/src/nvidia/mod.rs b/src/nvidia/mod.rs new file mode 100644 index 0000000..ba9492d --- /dev/null +++ b/src/nvidia/mod.rs @@ -0,0 +1,11 @@ +pub mod ctrl0000vgpu; +pub mod ctrl0080gpu; +pub mod ctrl2080bus; +pub mod ctrl2080gpu; +pub mod ctrl9096; +pub mod ctrla081; +pub mod ctrla082; +pub mod error; +pub mod ioctl; +pub mod nvos; +pub mod nvtypes; diff --git a/src/nvidia/nvos.rs b/src/nvidia/nvos.rs new file mode 100644 index 0000000..b25a8ac --- /dev/null +++ b/src/nvidia/nvos.rs @@ -0,0 +1,40 @@ +///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/src/common/sdk/nvidia/inc/nvos.h +use std::os::raw::{c_ulong, c_void}; + +use super::ioctl::NV_IOCTL_MAGIC; +use super::nvtypes::NvHandle; +use crate::ioctl::_IOWR; + +/// Value of the "request" argument used by `nvidia-vgpud` and `nvidia-vgpu-mgr` when calling +/// ioctl to read the PCI device ID, type, and many other things from the driver. +/// +/// Pulled from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/src/nvidia/arch/nvalloc/unix/include/nv_escape.h +/// and [`nvidia_ioctl`](https://github.com/NVIDIA/open-gpu-kernel-modules/blob/98553501593ef05bddcc438689ed1136f732d40a/kernel-open/nvidia/nv.c) +/// and [`__NV_IOWR`](https://github.com/NVIDIA/open-gpu-kernel-modules/blob/98553501593ef05bddcc438689ed1136f732d40a/kernel-open/common/inc/nv.h) +/// showing that `_IOWR` is used to derive the I/O control request codes. +pub const NV_ESC_RM_CONTROL: c_ulong = _IOWR::(NV_IOCTL_MAGIC, 0x2a); + +/// When issuing ioctl with `NV_ESC_RM_CONTROL` then the `argp` argument is a pointer to a +/// `NVOS54_PARAMETERS` structure like this. +/// +/// See [`NVOS54_PARAMETERS`](https://github.com/NVIDIA/open-gpu-kernel-modules/blob/d8f3bcff924776518f1e63286537c3cf365289ac/src/common/sdk/nvidia/inc/nvos.h) +//#[derive(Debug)] +#[repr(C)] +pub struct Nvos54Parameters { + /// Initialized prior to call. + pub h_client: NvHandle, + /// Initialized prior to call. + pub h_object: NvHandle, + /// Operation type, see comment below. + pub cmd: u32, + /// Set of flags for call. + pub flags: u32, + /// Pointer initialized prior to call. + /// Pointee initialized to 0 prior to call. + /// Pointee is written by ioctl call. + pub params: *mut c_void, + /// Size in bytes of the object referenced in `params`. + pub params_size: u32, + /// Written by ioctl call. See comment below. + pub status: u32, +} diff --git a/src/nvidia/nvtypes.rs b/src/nvidia/nvtypes.rs new file mode 100644 index 0000000..c8ae50d --- /dev/null +++ b/src/nvidia/nvtypes.rs @@ -0,0 +1 @@ +pub type NvHandle = u32; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..dd091f1 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,19 @@ +use std::fmt; + +#[derive(Clone, Copy)] +#[repr(C, align(8))] +pub struct AlignedU64(pub u64); + +impl fmt::Debug for AlignedU64 { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl fmt::LowerHex for AlignedU64 { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} diff --git a/src/uuid.rs b/src/uuid.rs new file mode 100644 index 0000000..4e3d8ab --- /dev/null +++ b/src/uuid.rs @@ -0,0 +1,25 @@ +use std::fmt; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct Uuid(pub u32, pub u16, pub u16, pub [u8; 8]); + +impl fmt::Display for Uuid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", + self.0, + self.1, + self.2, + self.3[0], + self.3[1], + self.3[2], + self.3[3], + self.3[4], + self.3[5], + self.3[6], + self.3[7] + ) + } +}