Skip to main content

csv_rs/api/dcu/
ioctl.rs

1// Copyright (C) Hygon Info Technologies Ltd.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6use super::types::{AttestationReport, AttestationResponse};
7use iocuddle::{Group, Ioctl, WriteRead};
8use libc::c_void;
9use log::*;
10use std::io;
11
12/// Page size constant used for memory allocation (4KB)
13const PAGE_SIZE: usize = 4096;
14
15/// IOCTL command enumeration for DCU device operations
16pub enum DcuDeviceIoctl {
17    /// Command to request attestation report from device
18    GetReport = 0x17,
19    /// Placeholder for undefined/unused commands
20    _Undefined,
21}
22
23/// IOCTL group identifier for DCU device ('M' magic number)
24const DCU: Group = Group::new(b'M');
25
26/// Predefined IOCTL command for getting attestation reports
27/// Uses write-read operation mode with MkfdIoctlSecurityAttestationArgs structure
28pub const DCU_GET_REPORT: Ioctl<WriteRead, &MkfdIoctlSecurityAttestationArgs> =
29    unsafe { DCU.write_read(DcuDeviceIoctl::GetReport as u8) };
30
31/// IOCTL arguments structure for security attestation requests
32/// Note: Maintains #[repr(C)] for compatibility with kernel interface
33#[repr(C)]
34pub struct MkfdIoctlSecurityAttestationArgs {
35    /// DCU identifier for target device
36    pub dcu_id: u32,
37    /// For compatibility
38    pub cmd_id: u32,
39    /// Message version number(default 1)
40    pub version: u32,
41    /// Request structure address
42    pub request_data: *mut c_void,
43    /// Request structure size
44    pub request_size: u64,
45    /// Response structure address
46    pub response_data: *mut c_void,
47    /// Response structure size
48    pub response_size: u64,
49    /// Firmware error address
50    pub fw_err: u64,
51}
52
53impl MkfdIoctlSecurityAttestationArgs {
54    /// Creates a new instance with default values
55    /// Note: Buffers are initialized as null pointers
56    pub fn new() -> Self {
57        Self {
58            dcu_id: 0,
59            cmd_id: 0,
60            version: 1,
61            request_data: std::ptr::null_mut(),
62            request_size: 0,
63            response_data: std::ptr::null_mut(),
64            response_size: 0,
65            fw_err: 0,
66        }
67    }
68
69    /// Configures attestation arguments with DCU ID and nonce
70    ///
71    /// # Safety
72    /// Contains unsafe operations for memory allocation and pointer manipulation
73    ///
74    /// # Arguments
75    /// * `dcu_id` - Target DCU device identifier
76    /// * `userdata` - 64-byte cryptographic nonce for attestation
77    pub fn set_attestation_args(&mut self, dcu_id: u32, userdata: [u8; 64]) -> std::io::Result<()> {
78        unsafe {
79            // Allocate page-aligned request buffer
80            self.request_data = libc::malloc(PAGE_SIZE);
81            if self.request_data.is_null() {
82                return Err(std::io::Error::last_os_error());
83            }
84
85            // Initialize request buffer with zeros
86            libc::memset(self.request_data, 0, PAGE_SIZE);
87            self.request_size = PAGE_SIZE as u64;
88
89            // Copy nonce into request buffer
90            std::ptr::copy_nonoverlapping(
91                userdata.as_ptr(),
92                self.request_data as *mut u8,
93                userdata.len(),
94            );
95
96            // Debug output: hex dump of nonce in request buffer
97            trace!("Generated random number for DCU report request");
98            hex_dump(self.request_data as *const u8, 64);
99
100            // Allocate page-aligned response buffer
101            self.response_data = libc::malloc(PAGE_SIZE);
102            if self.response_data.is_null() {
103                // Cleanup request buffer on allocation failure
104                libc::free(self.request_data);
105                return Err(std::io::Error::last_os_error());
106            }
107
108            // Initialize response buffer with zeros
109            libc::memset(self.response_data, 0, PAGE_SIZE);
110            self.response_size = PAGE_SIZE as u64;
111
112            // Set target DCU identifier
113            self.dcu_id = dcu_id;
114            Ok(())
115        }
116    }
117
118    /// Releases allocated memory buffers
119    ///
120    /// # Safety
121    /// Must only be called when buffers are no longer needed
122    /// Calling with dangling pointers is undefined behavior
123    pub unsafe fn free_buffers(&mut self) {
124        if !self.request_data.is_null() {
125            libc::free(self.request_data);
126            self.request_data = std::ptr::null_mut();
127        }
128        if !self.response_data.is_null() {
129            libc::free(self.response_data);
130            self.response_data = std::ptr::null_mut();
131        }
132    }
133
134    /// Extracts attestation report from response buffer
135    ///
136    /// Returns:
137    /// - Some(AttestationReport) if valid report exists
138    /// - None if response buffer contains no valid report
139    pub fn extract_report(&mut self) -> Result<Option<AttestationReport>, io::Error> {
140        unsafe {
141            if let Some(response) = AttestationResponse::from_raw(self.response_data) {
142                return Ok(Some(response.report.clone()));
143            }
144        }
145        Ok(None)
146    }
147}
148
149impl Default for MkfdIoctlSecurityAttestationArgs {
150    fn default() -> Self {
151        Self::new()
152    }
153}
154
155/// Automatic cleanup implementation to prevent memory leaks
156impl Drop for MkfdIoctlSecurityAttestationArgs {
157    fn drop(&mut self) {
158        unsafe { self.free_buffers() }
159    }
160}
161
162/// Utility function for debugging memory contents with logging
163///
164/// # Arguments
165/// * `data` - Pointer to memory region
166/// * `len` - Number of bytes to dump
167fn hex_dump(data: *const u8, len: usize) {
168    let mut output = String::new();
169
170    for i in 0..len {
171        unsafe {
172            output.push_str(&format!("{:02x} ", *data.add(i)));
173        }
174        if (i + 1) % 16 == 0 {
175            output.push('\n');
176        }
177    }
178
179    trace!("Memory dump:\n{}", output);
180}