nvidia: refactor everything out of the main class and use official naming and structs where possible

This commit is contained in:
Matt Bilker
2022-12-07 12:16:25 +00:00
parent 17d81e0dbd
commit 72abe3c927
16 changed files with 703 additions and 374 deletions

View File

@@ -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<T>(b: c_ulong, c: c_ulong) -> c_ulong {
pub const fn _IOWR<T>(b: c_ulong, c: c_ulong) -> c_ulong {
_IOC(_IOC_READ | _IOC_WRITE, b, c, mem::size_of::<T>() as c_ulong)
}

View File

@@ -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<Option<Uuid>> = 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::<Nvos54Parameters>(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::<LoadVgpuConfig2>();
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<C: VgpuConfigLike>(
true
}
#[cfg(test)]
mod test {
use std::mem;
use super::{LoadVgpuConfig2, VgpuConfig, VgpuConfig2, VgpuStart};
#[test]
fn verify_sizes() {
assert_eq!(mem::size_of::<VgpuStart>(), 0x420);
assert_eq!(mem::size_of::<VgpuConfig>(), 0x738);
assert_eq!(mem::size_of::<VgpuConfig2>(), 0x1358);
assert_eq!(mem::size_of::<LoadVgpuConfig2>(), 0x1360);
}
}

View File

@@ -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::<Nv0000CtrlVgpuGetStartDataParams>(), 0x420);
}
}

11
src/nvidia/ctrl0080gpu.rs Normal file
View File

@@ -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,
}

13
src/nvidia/ctrl2080bus.rs Normal file
View File

@@ -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,
}

View File

@@ -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;

3
src/nvidia/ctrl9096.rs Normal file
View File

@@ -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;

153
src/nvidia/ctrla081.rs Normal file
View File

@@ -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::<NvA081CtrlVgpuInfo>(), 0x1358);
assert_eq!(
mem::size_of::<NvA081CtrlVgpuConfigGetVgpuTypeInfoParams>(),
0x1360
);
}
}

108
src/nvidia/ctrla082.rs Normal file
View File

@@ -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::<NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams>(),
0x738
);
}
}

141
src/nvidia/error.rs Normal file
View File

@@ -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;

4
src/nvidia/ioctl.rs Normal file
View File

@@ -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 _;

11
src/nvidia/mod.rs Normal file
View File

@@ -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;

40
src/nvidia/nvos.rs Normal file
View File

@@ -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::<Nvos54Parameters>(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,
}

1
src/nvidia/nvtypes.rs Normal file
View File

@@ -0,0 +1 @@
pub type NvHandle = u32;

19
src/utils.rs Normal file
View File

@@ -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)
}
}

25
src/uuid.rs Normal file
View File

@@ -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]
)
}
}