• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NVIDIA / nvrc / 19144475043

06 Nov 2025 05:35PM UTC coverage: 36.62% (-1.5%) from 38.153%
19144475043

push

github

web-flow
Merge pull request #75 from zvonkok/address-soon-issues

refactor: address 'soon' issues from code analysis

0 of 42 new or added lines in 5 files covered. (0.0%)

2 existing lines in 2 files now uncovered.

286 of 781 relevant lines covered (36.62%)

0.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.26
/src/gpu.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright (c) NVIDIA CORPORATION
3

4
#[cfg(feature = "confidential")]
5
pub mod confidential {
6
    use super::super::NVRC;
7
    use crate::pci_ids::DeviceType;
8
    use anyhow::{anyhow, Context, Result};
9
    use nix::sys::mman::{mmap, munmap, MapFlags, ProtFlags};
10
    use std::fs::{self, File};
11
    use std::ptr;
12

13
    const EMBEDDED_PCI_IDS: &str = include_str!("pci_ids_embedded.txt");
14

15
    #[derive(Debug, PartialEq, Clone, Copy)]
16
    pub enum GpuArchitecture {
17
        Hopper,
18
        Blackwell,
19
        Unknown,
20
    }
21
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
22
    pub enum CC {
23
        On,
24
        Off,
25
        Devtools,
26
    }
27

28
    impl GpuArchitecture {
29
        pub const CC_STATE_MASK: u32 = 0x3;
30
        pub fn cc_register(&self) -> Result<u64> {
1✔
31
            match self {
1✔
32
                GpuArchitecture::Hopper => Ok(0x001182cc),
1✔
33
                GpuArchitecture::Blackwell => Ok(0x590),
1✔
34
                GpuArchitecture::Unknown => Err(anyhow::anyhow!(
1✔
35
                    "Cannot determine CC register for unknown GPU architecture."
36
                )),
37
            }
38
        }
39

40
        pub fn parse_cc_mode(&self, reg_value: u32) -> Result<CC> {
1✔
41
            if matches!(self, GpuArchitecture::Unknown) {
1✔
42
                return Err(anyhow::anyhow!(
1✔
43
                    "Cannot parse CC mode for unknown GPU architecture."
44
                ));
45
            }
46
            let cc_state = reg_value & Self::CC_STATE_MASK;
1✔
47
            let mode = match cc_state {
1✔
48
                0x1 => CC::On,
1✔
49
                0x3 => CC::Devtools,
1✔
50
                _ => CC::Off,
1✔
51
            };
52
            Ok(mode)
1✔
53
        }
54
    }
55

56
    fn classify_gpu_architecture(device_name: &str) -> GpuArchitecture {
1✔
57
        let name_lower = device_name.to_lowercase();
1✔
58
        if name_lower.contains("h100")
2✔
59
            || name_lower.contains("h800")
2✔
60
            || name_lower.contains("hopper")
1✔
61
            || name_lower.contains("gh100")
1✔
62
        {
63
            return GpuArchitecture::Hopper;
1✔
64
        }
65
        if name_lower.contains("b100")
1✔
66
            || name_lower.contains("b200")
2✔
67
            || name_lower.contains("blackwell")
1✔
68
            || name_lower.contains("gb100")
1✔
69
            || name_lower.contains("gb200")
1✔
70
        {
71
            return GpuArchitecture::Blackwell;
1✔
72
        }
73
        GpuArchitecture::Unknown
1✔
74
    }
75

76
    fn get_gpu_architecture_by_device_id(device_id: u16, bdf: &str) -> Result<GpuArchitecture> {
1✔
77
        // Single-pass scan of embedded DB (avoid allocating HashMap per call)
78
        let needle = format!("\t{:04x} ", device_id).to_lowercase();
1✔
79
        for line in EMBEDDED_PCI_IDS.lines() {
1✔
80
            // Start scanning only inside NVIDIA vendor section
81
            if line.starts_with("10de  NVIDIA") || line.starts_with("10de  Nvidia") {
2✔
82
                // from here until a non-indented or new vendor line we search device entries
83
                continue; // device lines are indented
84
            }
85
            if line.starts_with('\t') && !line.starts_with("\t\t") {
2✔
86
                let lower = line.to_lowercase();
1✔
87
                if lower.contains(&needle) {
2✔
88
                    // Extract name after the id token
89
                    if let Some(rest) = line
1✔
90
                        .trim_start()
91
                        .strip_prefix(&format!("{:04x}  ", device_id))
1✔
92
                    {
93
                        let arch = classify_gpu_architecture(rest);
2✔
94
                        if arch == GpuArchitecture::Unknown {
2✔
95
                            return Err(anyhow::anyhow!("Device 0x{:04x} ('{}') at BDF {} unsupported (need Hopper/Blackwell)", device_id, rest.trim(), bdf));
2✔
96
                        }
97
                        return Ok(arch);
2✔
98
                    }
99
                }
100
            } else if !line.starts_with('\t') && line.starts_with("10df") {
5✔
101
                // next vendor, stop early
102
                break;
103
            }
104
        }
105
        Err(anyhow::anyhow!(
2✔
106
            "Device ID 0x{:04x} not found in embedded PCI DB for BDF {}",
107
            device_id,
108
            bdf
109
        ))
110
    }
111

112
    /// Read BAR0 size from sysfs resource file
NEW
113
    fn read_bar0_size(bdf: &str) -> Result<usize> {
×
NEW
114
        let resource_path = format!("/sys/bus/pci/devices/{bdf}/resource");
×
NEW
115
        let content = fs::read_to_string(&resource_path)
×
NEW
116
            .with_context(|| format!("Failed to read {resource_path}"))?;
×
117

118
        // First line contains BAR0: start_addr end_addr flags
NEW
119
        let first_line = content
×
120
            .lines()
121
            .next()
NEW
122
            .ok_or_else(|| anyhow!("Empty resource file for {bdf}"))?;
×
123

NEW
124
        let parts: Vec<&str> = first_line.split_whitespace().collect();
×
NEW
125
        if parts.len() < 2 {
×
NEW
126
            return Err(anyhow!("Invalid resource file format for {bdf}"));
×
127
        }
128

NEW
129
        let start_addr = u64::from_str_radix(parts[0].trim_start_matches("0x"), 16)
×
NEW
130
            .with_context(|| format!("Failed to parse start address for {bdf}"))?;
×
NEW
131
        let end_addr = u64::from_str_radix(parts[1].trim_start_matches("0x"), 16)
×
NEW
132
            .with_context(|| format!("Failed to parse end address for {bdf}"))?;
×
133

NEW
134
        Ok((end_addr - start_addr + 1) as usize)
×
135
    }
136

137
    impl NVRC {
138
        fn query_cc_mode_bar0(&self, bdf: &str, device_id: u16) -> Result<CC> {
×
139
            let resource = format!("/sys/bus/pci/devices/{bdf}/resource0");
×
140
            let arch = get_gpu_architecture_by_device_id(device_id, bdf)
×
141
                .with_context(|| format!("arch lookup failed for BDF {bdf}"))?;
×
142
            let reg = arch.cc_register()?;
×
143
            debug!("BDF {bdf}: arch={:?} cc_reg=0x{:x}", arch, reg);
×
144

145
            // Read BAR0 size and validate register offset
NEW
146
            let bar0_size = read_bar0_size(bdf)
×
NEW
147
                .with_context(|| format!("Failed to read BAR0 size for {bdf}"))?;
×
148

NEW
149
            if reg as usize >= bar0_size {
×
NEW
150
                return Err(anyhow!(
×
151
                    "Register offset 0x{:x} exceeds BAR0 size 0x{:x} for {bdf}",
152
                    reg,
153
                    bar0_size
154
                ));
155
            }
156

UNCOV
157
            let file =
×
158
                File::open(&resource).with_context(|| format!("open BAR0 failed for {bdf}"))?;
159
            let ps = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
×
160
            let page = (reg as usize / ps) * ps;
×
NEW
161
            let off = reg as usize - page; // Equivalent to reg % ps, always < ps
×
162
            let map_len = ps;
163
            let map = unsafe {
164
                mmap(
165
                    None,
166
                    std::num::NonZeroUsize::new(map_len).unwrap(),
×
167
                    ProtFlags::PROT_READ,
168
                    MapFlags::MAP_SHARED,
169
                    &file,
170
                    page as i64,
171
                )
172
                .with_context(|| format!("mmap BAR0 failed for {bdf}"))?
×
173
            };
174
            let mode = unsafe {
175
                let reg_ptr = map.as_ptr().cast::<u8>().add(off).cast::<u32>();
×
176
                let val = ptr::read_volatile(reg_ptr);
×
177
                let m = arch
×
178
                    .parse_cc_mode(val)
×
179
                    .with_context(|| format!("parse CC mode failed (val=0x{val:x}) for {bdf}"))?;
×
180
                debug!("BDF {bdf}: CC mode {:?} (raw=0x{:x})", m, val);
×
181
                m
182
            };
183
            unsafe { munmap(map, map_len).with_context(|| format!("munmap failed for {bdf}"))? };
×
184
            Ok(mode)
×
185
        }
186
        pub fn query_gpu_cc_mode(&mut self) -> Result<()> {
×
187
            let mut aggregate: Option<CC> = None;
×
188
            for d in self
×
189
                .nvidia_devices
190
                .iter()
×
191
                .filter(|d| matches!(d.device_type, DeviceType::Gpu))
×
192
            {
193
                let m = self.query_cc_mode_bar0(&d.bdf, d.device_id)?;
×
194
                if let Some(prev) = aggregate {
×
195
                    if prev != m {
×
196
                        return Err(anyhow::anyhow!(
×
197
                            "Inconsistent CC mode: {} has {:?} expected {:?}",
198
                            d.bdf,
199
                            m,
200
                            prev
201
                        ));
202
                    }
203
                } else {
204
                    aggregate = Some(m);
×
205
                }
206
            }
207
            self.gpu_cc_mode = aggregate; // None if no GPUs
×
208
            if self.gpu_cc_mode.is_none() {
×
209
                debug!("No GPUs for CC mode query");
×
210
            }
211
            Ok(())
×
212
        }
213
    }
214

215
    #[cfg(test)]
216
    mod tests {
217
        use super::*;
218

219
        #[test]
220
        fn classify_arch_names() {
221
            assert_eq!(
222
                classify_gpu_architecture("NVIDIA H100 PCIe"),
223
                GpuArchitecture::Hopper
224
            );
225
            assert_eq!(classify_gpu_architecture("GH100"), GpuArchitecture::Hopper);
226
            assert_eq!(
227
                classify_gpu_architecture("GB100 [B200]"),
228
                GpuArchitecture::Blackwell
229
            );
230
            assert_eq!(
231
                classify_gpu_architecture("Random Device"),
232
                GpuArchitecture::Unknown
233
            );
234
        }
235

236
        #[test]
237
        fn cc_register_values() {
238
            assert_eq!(GpuArchitecture::Hopper.cc_register().unwrap(), 0x001182cc);
239
            assert_eq!(GpuArchitecture::Blackwell.cc_register().unwrap(), 0x590);
240
            assert!(GpuArchitecture::Unknown.cc_register().is_err());
241
        }
242

243
        #[test]
244
        fn parse_cc_modes() {
245
            let h = GpuArchitecture::Hopper;
246
            assert_eq!(h.parse_cc_mode(0x0).unwrap(), CC::Off);
247
            assert_eq!(h.parse_cc_mode(0x1).unwrap(), CC::On);
248
            assert_eq!(h.parse_cc_mode(0x3).unwrap(), CC::Devtools);
249
            assert!(GpuArchitecture::Unknown.parse_cc_mode(0x1).is_err());
250
        }
251

252
        #[test]
253
        fn lookup_hopper() {
254
            // 2302  GH100
255
            let a = get_gpu_architecture_by_device_id(0x2302, "0000:01:00.0").unwrap();
256
            assert_eq!(a, GpuArchitecture::Hopper);
257
        }
258

259
        #[test]
260
        fn lookup_blackwell() {
261
            // 2901  GB100 [B200]
262
            let a = get_gpu_architecture_by_device_id(0x2901, "0000:02:00.0").unwrap();
263
            assert_eq!(a, GpuArchitecture::Blackwell);
264
        }
265

266
        #[test]
267
        fn lookup_unsupported_device_in_vendor_section() {
268
            // 1af1  GA100GL [A100 NVSwitch] -> does not match hopper/blackwell patterns
269
            let r = get_gpu_architecture_by_device_id(0x1af1, "0000:03:00.0");
270
            assert!(r.is_err());
271
            assert!(format!("{}", r.unwrap_err()).contains("unsupported"));
272
        }
273

274
        #[test]
275
        fn lookup_not_found() {
276
            let r = get_gpu_architecture_by_device_id(0xdead, "0000:04:00.0");
277
            assert!(r.is_err());
278
            assert!(format!("{}", r.unwrap_err()).contains("not found"));
279
        }
280
    }
281
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc