keos/
util.rs

1//! Debugging Utilities.
2
3use alloc::string::String;
4use core::fmt::Write;
5
6use crate::{KernelError, fs::RegularFile};
7
8/// Dumps the bytes in `buf` to the console as hex bytes, arranged 16 per line.
9///
10/// Each line is buffered into a String and printed in a single operation to
11/// avoid console race conditions in multi-threaded environments.
12///
13/// # Arguments
14///
15/// * `ofs` - The starting offset for the first byte in `buf`.
16/// * `buf` - The slice of bytes to dump.
17/// * `ascii` - A flag to enable or disable the ASCII character view.
18///
19/// # Usage
20///
21/// ```
22/// let my_data: &[u8] = &[0xDE, 0xAD, 0xBE, 0xEF];
23/// // This is a safe function and can be called directly.
24/// hex_dump_slice(0x100, my_data, true);
25/// ```
26pub fn hex_dump_slice(ofs: usize, buf: &[u8], ascii: bool) {
27    const PER_LINE: usize = 16; // Maximum bytes per line.
28
29    // Create mutable local variables from the immutable arguments to track state.
30    let mut current_ofs = ofs;
31    let mut current_buf = buf;
32
33    // Loop until all bytes in the buffer have been processed.
34    while !current_buf.is_empty() {
35        // Create a mutable string to buffer the output for the current line.
36        let mut line_buffer = String::new();
37
38        // --- Calculate this line's layout ---
39
40        // `start_col` is the column (0-15) where the first byte of this iteration will
41        // be printed.
42        let start_col = current_ofs % PER_LINE;
43
44        // Determine how many bytes from the buffer we will print on this line.
45        let bytes_on_this_line = (PER_LINE - start_col).min(current_buf.len());
46
47        // `end_col` is the column where our printing will stop.
48        let end_col = start_col + bytes_on_this_line;
49
50        // --- Build the line string ---
51
52        // The offset printed at the start of the line is always rounded down.
53        // The .unwrap() is safe because writing to a String should not fail.
54        write!(&mut line_buffer, "{:016x}  ", current_ofs - start_col).unwrap();
55
56        // --- Append the hex representation ---
57
58        // 1. Append leading spaces for alignment.
59        for _ in 0..start_col {
60            write!(&mut line_buffer, "   ").unwrap();
61        }
62
63        // 2. Append the hex value for each byte.
64        for (i, c) in current_buf.iter().enumerate().take(bytes_on_this_line) {
65            let current_col = start_col + i;
66            write!(&mut line_buffer, "{c:02x}").unwrap();
67            if current_col == PER_LINE / 2 - 1 {
68                write!(&mut line_buffer, "-").unwrap();
69            } else {
70                write!(&mut line_buffer, " ").unwrap();
71            }
72        }
73
74        // --- Append the ASCII representation (if requested) ---
75        if ascii {
76            // 3. Append trailing spaces to align the ASCII section.
77            for _ in end_col..PER_LINE {
78                write!(&mut line_buffer, "   ").unwrap();
79            }
80
81            write!(&mut line_buffer, "|").unwrap();
82
83            // 1. Append leading spaces for alignment.
84            for _ in 0..start_col {
85                write!(&mut line_buffer, " ").unwrap();
86            }
87
88            // 2. Append the character for each byte.
89            for c in current_buf {
90                if (0x20..0x7e).contains(c) {
91                    write!(&mut line_buffer, "{}", *c as char).unwrap();
92                } else {
93                    write!(&mut line_buffer, ".").unwrap();
94                }
95            }
96
97            // 3. Append trailing spaces to align the final bar.
98            for _ in end_col..PER_LINE {
99                write!(&mut line_buffer, " ").unwrap();
100            }
101            write!(&mut line_buffer, "|").unwrap();
102        }
103
104        // Print the fully constructed line buffer at once.
105        println!("{}", line_buffer);
106
107        // --- Update state for the next iteration ---
108
109        // Advance the buffer slice past the bytes we just printed.
110        current_buf = &current_buf[bytes_on_this_line..];
111        // Increment the master offset.
112        current_ofs += bytes_on_this_line;
113    }
114}
115
116/// Dumps the memory occupied by a value of type `T` to the console.
117///
118/// This function takes a raw pointer to the data. The size of the data to dump
119/// is determined by `core::mem::size_of::<T>()`. This function handles
120/// potentially unaligned pointers by first performing an unaligned read.
121///
122/// # Safety
123///
124/// The caller must ensure that `ptr` is valid for reads of `size_of::<T>()`
125/// bytes for the duration of this function call. The pointer does **not** need
126/// to be aligned.
127///
128/// # Arguments
129///
130/// * `ofs` - The starting offset for the first byte.
131/// * `ptr` - A raw pointer to the data to be dumped.
132/// * `ascii` - A flag to enable or disable the ASCII character view.
133///
134/// # Usage
135///
136/// ```
137/// let my_data: u32 = 0x12345678;
138/// // This function is unsafe and must be called within an unsafe block.
139/// unsafe {
140///     hex_dump(0, &my_data, true);
141/// }
142/// ```
143pub unsafe fn hex_dump<T>(ofs: usize, ptr: *const T, ascii: bool) {
144    unsafe {
145        // To safely handle potentially unaligned pointers, we first perform an
146        // unaligned read into a local variable on the stack. This `value` is
147        // guaranteed to have the correct alignment for type T.
148        let value: T = core::ptr::read_unaligned(ptr);
149
150        // Now we can safely get a pointer to the local, aligned variable.
151        let aligned_ptr: *const T = &value;
152
153        // Determine the size of the data based on its type.
154        let size = core::mem::size_of::<T>();
155
156        // Create a byte slice from the aligned pointer and size. This is safe
157        // because `aligned_ptr` points to a valid, local variable.
158        let slice = core::slice::from_raw_parts(aligned_ptr as *const u8, size);
159
160        // Call the safe, slice-based implementation.
161        hex_dump_slice(ofs, slice, ascii)
162    }
163}
164
165/// Copy a RegularFile's content into another RegularFile.
166pub fn copy_file(src: &RegularFile, dest: &RegularFile) -> Result<(), KernelError> {
167    let mut buf: [u8; 4096] = [0u8; 4096];
168    let size = src.size();
169
170    for i in 0..=(size / 4096) {
171        let position = i * 4096;
172        let size_to_copy = if (i + 1) * 4096 > size {
173            size % 4096
174        } else {
175            4096
176        };
177
178        src.read(position, &mut buf[..size_to_copy])?;
179        dest.write(position, &buf[..size_to_copy])?;
180    }
181    dest.writeback()?;
182
183    Ok(())
184}