use super::{CcMode, TeeError, TeeResult};
use std::process::Command;
pub fn query_cc_mode(device_id: u32) -> TeeResult<CcMode> {
if let Ok(mode) = query_cc_mode_nvidia_smi(device_id) {
return Ok(mode);
}
if let Ok(mode) = query_cc_mode_nvtrust(device_id) {
return Ok(mode);
}
query_cc_mode_sysfs(device_id)
}
fn query_cc_mode_nvidia_smi(device_id: u32) -> TeeResult<CcMode> {
let output = Command::new("nvidia-smi")
.args([
"-i",
&device_id.to_string(),
"--query-gpu=cc_mode",
"--format=csv,noheader",
])
.output()
.map_err(|e| TeeError::DriverError(format!("nvidia-smi failed: {}", e)))?;
if !output.status.success() {
return Err(TeeError::DriverError(
"nvidia-smi cc_mode query not supported".into(),
));
}
let stdout = String::from_utf8_lossy(&output.stdout);
parse_cc_mode(stdout.trim())
}
#[allow(unused_variables)]
fn query_cc_mode_nvtrust(device_id: u32) -> TeeResult<CcMode> {
let output = Command::new("nvidia-smi")
.args(["conf-compute", "-gcs"])
.output()
.map_err(|e| TeeError::DriverError(format!("nvidia-smi conf-compute failed: {}", e)))?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if line.contains("CC Mode") || line.contains("Confidential Compute") {
if line.contains("ON") || line.contains("Enabled") {
return Ok(CcMode::On);
} else if line.contains("DEVTOOLS") || line.contains("DevTools") {
return Ok(CcMode::DevTools);
} else if line.contains("OFF") || line.contains("Disabled") {
return Ok(CcMode::Off);
}
}
}
}
Err(TeeError::DriverError("Could not parse CC mode".into()))
}
fn query_cc_mode_sysfs(device_id: u32) -> TeeResult<CcMode> {
let _sysfs_path = format!(
"/sys/bus/pci/devices/*/nvidia/{}/conf_compute_mode",
device_id
);
if let Ok(entries) = std::fs::read_dir("/sys/bus/pci/devices") {
for entry in entries.flatten() {
let cc_path = entry.path().join(format!("nvidia/{}/conf_compute_mode", device_id));
if cc_path.exists() {
if let Ok(mode_str) = std::fs::read_to_string(&cc_path) {
return parse_cc_mode(mode_str.trim());
}
}
}
}
tracing::warn!(
device_id = device_id,
"Could not determine CC mode, assuming Off"
);
Ok(CcMode::Off)
}
fn parse_cc_mode(s: &str) -> TeeResult<CcMode> {
let s_lower = s.to_lowercase();
if s_lower.contains("on") || s_lower.contains("enabled") || s == "1" {
Ok(CcMode::On)
} else if s_lower.contains("devtools") || s_lower.contains("dev") || s == "2" {
Ok(CcMode::DevTools)
} else if s_lower.contains("off") || s_lower.contains("disabled") || s == "0" {
Ok(CcMode::Off)
} else {
Err(TeeError::DriverError(format!(
"Unknown CC mode: {}",
s
)))
}
}
pub fn set_cc_mode(device_id: u32, mode: CcMode) -> TeeResult<()> {
let mode_str = match mode {
CcMode::Off => "off",
CcMode::On => "on",
CcMode::DevTools => "devtools",
};
let output = Command::new("nvidia-smi")
.args([
"conf-compute",
"-scc",
mode_str,
"-i",
&device_id.to_string(),
])
.output()
.map_err(|e| TeeError::DriverError(format!("Failed to set CC mode: {}", e)))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(TeeError::DriverError(format!(
"Failed to set CC mode: {}",
stderr
)));
}
tracing::info!(
device_id = device_id,
mode = %mode,
"CC mode set (reboot required)"
);
Ok(())
}
pub fn supports_cc(device_id: u32) -> TeeResult<bool> {
let output = Command::new("nvidia-smi")
.args([
"-i",
&device_id.to_string(),
"--query-gpu=name",
"--format=csv,noheader",
])
.output()
.map_err(|e| TeeError::DriverError(format!("nvidia-smi failed: {}", e)))?;
if !output.status.success() {
return Err(TeeError::DriverError("Could not query GPU name".into()));
}
let name = String::from_utf8_lossy(&output.stdout);
let name_upper = name.to_uppercase();
let supported = name_upper.contains("H100")
|| name_upper.contains("H200")
|| name_upper.contains("B200")
|| name_upper.contains("B100");
Ok(supported)
}
pub fn query_cc_settings(device_id: u32) -> TeeResult<CcSettings> {
let output = Command::new("nvidia-smi")
.args(["conf-compute", "-gcs", "-i", &device_id.to_string()])
.output()
.map_err(|e| TeeError::DriverError(format!("nvidia-smi conf-compute failed: {}", e)))?;
if !output.status.success() {
return Err(TeeError::DriverError(
"Failed to query CC settings".into(),
));
}
let stdout = String::from_utf8_lossy(&output.stdout);
parse_cc_settings(&stdout)
}
#[derive(Debug, Clone)]
pub struct CcSettings {
pub mode: CcMode,
pub pending_mode: Option<CcMode>,
pub ppcie_enabled: bool,
pub multi_gpu_mode: Option<String>,
pub driver_version: String,
pub vbios_version: String,
}
fn parse_cc_settings(output: &str) -> TeeResult<CcSettings> {
let mut settings = CcSettings {
mode: CcMode::Off,
pending_mode: None,
ppcie_enabled: false,
multi_gpu_mode: None,
driver_version: String::new(),
vbios_version: String::new(),
};
for line in output.lines() {
let line = line.trim();
if line.contains("CC Mode") || line.contains("Current CC Mode") {
if line.contains("ON") {
settings.mode = CcMode::On;
} else if line.contains("DEVTOOLS") {
settings.mode = CcMode::DevTools;
}
} else if line.contains("Pending CC Mode") {
if line.contains("ON") {
settings.pending_mode = Some(CcMode::On);
} else if line.contains("DEVTOOLS") {
settings.pending_mode = Some(CcMode::DevTools);
} else if line.contains("OFF") {
settings.pending_mode = Some(CcMode::Off);
}
} else if line.contains("PPCIE") || line.contains("Protected PCIe") {
settings.ppcie_enabled = line.contains("Enabled") || line.contains("ON");
} else if line.contains("Multi-GPU") {
if let Some(mode) = line.split(':').nth(1) {
settings.multi_gpu_mode = Some(mode.trim().to_string());
}
} else if line.contains("Driver Version") {
if let Some(version) = line.split(':').nth(1) {
settings.driver_version = version.trim().to_string();
}
} else if line.contains("VBIOS") {
if let Some(version) = line.split(':').nth(1) {
settings.vbios_version = version.trim().to_string();
}
}
}
Ok(settings)
}
pub fn verify_cc_configuration(device_id: u32) -> TeeResult<CcVerificationResult> {
let mut result = CcVerificationResult::default();
result.gpu_supported = supports_cc(device_id)?;
if !result.gpu_supported {
return Ok(result);
}
result.cc_mode = query_cc_mode(device_id)?;
result.cc_enabled = matches!(result.cc_mode, CcMode::On | CcMode::DevTools);
if let Ok(settings) = query_cc_settings(device_id) {
result.driver_version = settings.driver_version;
result.ppcie_enabled = settings.ppcie_enabled;
if let Some(major) = result.driver_version.split('.').next() {
if let Ok(major_num) = major.parse::<u32>() {
result.driver_compatible = major_num >= 550;
}
}
}
Ok(result)
}
#[derive(Debug, Clone, Default)]
pub struct CcVerificationResult {
pub gpu_supported: bool,
pub cc_enabled: bool,
pub cc_mode: CcMode,
pub ppcie_enabled: bool,
pub driver_version: String,
pub driver_compatible: bool,
}
impl Default for CcMode {
fn default() -> Self {
CcMode::Off
}
}
impl CcVerificationResult {
pub fn is_production_ready(&self) -> bool {
self.gpu_supported
&& self.cc_enabled
&& self.cc_mode == CcMode::On
&& self.driver_compatible
}
pub fn status_message(&self) -> String {
if !self.gpu_supported {
return "GPU does not support Confidential Computing (need H100/H200/B200)".into();
}
if !self.cc_enabled {
return format!(
"CC mode is {}, needs to be enabled via: nvidia-smi conf-compute -scc on",
self.cc_mode
);
}
if !self.driver_compatible {
return format!(
"Driver version {} is not compatible, need r550 or later",
self.driver_version
);
}
if self.cc_mode == CcMode::DevTools {
return "CC mode is DevTools (debugging enabled) - use 'on' for production".into();
}
"Configuration is production ready".into()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_cc_mode() {
assert_eq!(parse_cc_mode("on").unwrap(), CcMode::On);
assert_eq!(parse_cc_mode("ON").unwrap(), CcMode::On);
assert_eq!(parse_cc_mode("Enabled").unwrap(), CcMode::On);
assert_eq!(parse_cc_mode("1").unwrap(), CcMode::On);
assert_eq!(parse_cc_mode("off").unwrap(), CcMode::Off);
assert_eq!(parse_cc_mode("OFF").unwrap(), CcMode::Off);
assert_eq!(parse_cc_mode("Disabled").unwrap(), CcMode::Off);
assert_eq!(parse_cc_mode("0").unwrap(), CcMode::Off);
assert_eq!(parse_cc_mode("devtools").unwrap(), CcMode::DevTools);
assert_eq!(parse_cc_mode("DEVTOOLS").unwrap(), CcMode::DevTools);
assert_eq!(parse_cc_mode("2").unwrap(), CcMode::DevTools);
}
#[test]
fn test_verification_result() {
let mut result = CcVerificationResult::default();
assert!(!result.is_production_ready());
result.gpu_supported = true;
result.cc_enabled = true;
result.cc_mode = CcMode::On;
result.driver_compatible = true;
assert!(result.is_production_ready());
}
}