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}