From e06d519d17b40d57f47d0489cb7291eddbc65a81 Mon Sep 17 00:00:00 2001
From: jthulhu <adrien.lc.mathieu@gmail.com>
Date: Thu, 23 Feb 2023 10:35:20 +0100
Subject: [PATCH 1/6] WIP

---
 kernel/src/.dir-locals.el |   3 +-
 kernel/src/basic_vga.rs   | 240 ++++++++++++++++++++++++++++----------
 kernel/src/main.rs        |  90 +++++++-------
 3 files changed, 226 insertions(+), 107 deletions(-)

diff --git a/kernel/src/.dir-locals.el b/kernel/src/.dir-locals.el
index 48154b9..7a36f6f 100644
--- a/kernel/src/.dir-locals.el
+++ b/kernel/src/.dir-locals.el
@@ -1,2 +1,3 @@
 ((nil . ((lsp-rust-all-targets . nil)
-	 (lsp-rust-analyzer-cargo-target "x86_64-unknown-none"))))
+	 ;; (lsp-rust-analyzer-cargo-target "x86_64-unknown-none")
+	 )))
diff --git a/kernel/src/basic_vga.rs b/kernel/src/basic_vga.rs
index 2d5f90c..d5dd1c0 100644
--- a/kernel/src/basic_vga.rs
+++ b/kernel/src/basic_vga.rs
@@ -1,6 +1,57 @@
 use bootloader_api::info::{FrameBuffer, FrameBufferInfo, PixelFormat};
 
-use core::{fmt, marker::PhantomData};
+use core::{
+    fmt::{self, Arguments},
+    marker::PhantomData,
+};
+
+type Color = [u8; 3];
+
+static mut VGA: Option<Vga<'static>> = None;
+
+/// This initializes the console with a framebuffer. This is required to be subsequently able
+/// to print things to the console.
+///
+/// # Safety
+///
+/// No thread-concurrent access must be made to the console, including the initialization.
+pub unsafe fn init(frame_buffer: &'static mut FrameBuffer) {
+    let mut vga = Vga::new(frame_buffer);
+    let (width, height) = vga.window_size();
+    vga.fill_rect(0, 0, width, height, Vga::BLACK);
+    VGA = Some(vga);
+}
+
+
+/// # Safety
+///
+/// No thread-concurrent access must be made to the VGA. A single exclusive borrow can live at
+/// any time.
+pub unsafe fn vga<'a>() -> &'a mut Vga<'static> {
+    VGA.as_mut().unwrap()
+}
+
+#[macro_export]
+macro_rules! print {
+    ($($arg:tt)*) => {
+	// SAFETY: /!\ None so far /!\
+	unsafe {
+            $crate::basic_vga::print(format_args!($($arg)*))
+	}
+    };
+}
+
+#[macro_export]
+macro_rules! println {
+    ($($arg:tt)*) => {
+	$crate::print!("{}\n", format_args!($($arg)*))
+    };
+}
+
+pub unsafe fn print(args: Arguments) {
+    use core::fmt::Write;
+    vga().console().write_fmt(args).unwrap();
+}
 
 pub struct Vga<'a> {
     buffer_start: *mut u8,
@@ -17,6 +68,12 @@ impl<'a> From<&'a mut FrameBuffer> for Vga<'a> {
 }
 
 impl<'a> Vga<'a> {
+    const BLACK: Color = [0; 3];
+    const WHITE: Color = [255; 3];
+    const RED: Color = [255, 0, 0];
+    const GREEN: Color = [0, 255, 0];
+    const BLUE: Color = [0, 0, 255];
+    
     pub fn new(frame_buffer: &'a mut FrameBuffer) -> Self {
         Self {
             buffer_start: frame_buffer.buffer_mut().as_mut_ptr(),
@@ -26,56 +83,91 @@ impl<'a> Vga<'a> {
         }
     }
 
+    #[inline]
     pub fn get_pixel(&self, x: usize, y: usize) -> [u8; 3] {
-        let info = self.info;
-        let offset = (info.stride * y + x) * info.bytes_per_pixel;
-        let buffer = self.buffer_start.wrapping_add(offset);
-        match info.pixel_format {
-            PixelFormat::Rgb => unsafe {
-                [
-                    buffer.wrapping_add(0).read_volatile(),
-                    buffer.wrapping_add(1).read_volatile(),
-                    buffer.wrapping_add(2).read_volatile(),
-                ]
-            },
-            PixelFormat::Bgr => unsafe {
-                [
-                    buffer.wrapping_add(2).read_volatile(),
-                    buffer.wrapping_add(1).read_volatile(),
-                    buffer.wrapping_add(0).read_volatile(),
-                ]
-            },
+        assert!(self.is_valid(x, y));
+
+        unsafe { self.get_pixel_uncheck(x, y) }
+    }
+
+    /// Returns the color of a pixel.
+    ///
+    /// # Safety
+    ///
+    /// The safety conditions of this function are the same of [`pixel_at_unchecked`].
+    pub unsafe fn get_pixel_uncheck(&self, x: usize, y: usize) -> [u8; 3] {
+        let buffer = self.pixel_at_unchecked(x, y);
+        match self.info.pixel_format {
+            PixelFormat::Rgb => [
+                buffer.offset(0).read_volatile(),
+                buffer.offset(1).read_volatile(),
+                buffer.offset(2).read_volatile(),
+            ],
+            PixelFormat::Bgr => [
+                buffer.offset(2).read_volatile(),
+                buffer.offset(1).read_volatile(),
+                buffer.offset(0).read_volatile(),
+            ],
             PixelFormat::U8 => {
-                let c = unsafe { buffer.read_volatile() };
+                let c = buffer.read_volatile();
                 [c, c, c]
             }
             PixelFormat::Unknown {
                 red_position,
                 green_position,
                 blue_position,
-            } => unsafe {
-                [
-                    buffer.wrapping_add(red_position as _).read_volatile(),
-                    buffer.wrapping_add(green_position as _).read_volatile(),
-                    buffer.wrapping_add(blue_position as _).read_volatile(),
-                ]
-            },
+            } => [
+                buffer.offset(red_position as _).read_volatile(),
+                buffer.offset(green_position as _).read_volatile(),
+                buffer.offset(blue_position as _).read_volatile(),
+            ],
             _ => [0, 0, 0],
         }
     }
 
-    pub fn put_pixel(&mut self, x: usize, y: usize, rgb: [u8; 3]) {
-        let info = self.info;
-        let offset = (info.stride * y + x) * info.bytes_per_pixel;
-        Self::color(rgb)(self.buffer_start.wrapping_add(offset), info.pixel_format);
+    /// Returns an address pointing to where the pixel lie in the actual memory, without checking
+    /// if the coordinates are within bounds.
+    ///
+    /// # Safety
+    ///
+    /// The caller of this function must ensure the coordinates are within the bounds of the
+    /// framebuffer.
+    pub unsafe fn pixel_at_unchecked(&self, x: usize, y: usize) -> *mut u8 {
+        let offset = (self.info.stride * y + x) * self.info.bytes_per_pixel;
+        self.buffer_start.offset(offset as isize)
+    }
+
+    pub fn pixel_at(&mut self, x: usize, y: usize) -> *mut u8 {
+        assert!(self.is_valid(x, y));
+        // SAFETY: We have ensured (see above) that the coordinates are within bounds.
+        unsafe { self.pixel_at_unchecked(x, y) }
+    }
+
+    /// Set the color of a pixel, without checking of the coordinates are within bounds.
+    ///
+    /// # Safety
+    ///
+    /// The safety conditions of this function are the same of [`pixel_at_unchecked`].
+    pub unsafe fn put_pixel_unchecked(&mut self, x: usize, y: usize, rgb: [u8; 3]) {
+        Self::color(rgb)(self.pixel_at_unchecked(x, y), self.info.pixel_format);
+    }
+
+    /// Check is the coordinates are within the bounds of the framebuffer.
+    #[inline]
+    pub fn is_valid(&self, x: usize, y: usize) -> bool {
+        x < self.info.width && y < self.info.height
     }
 
     pub fn fill_rect(&mut self, x: usize, y: usize, dx: usize, dy: usize, rgb: [u8; 3]) {
         let info = self.info;
+        assert!(
+            dx == 0 || dy == 0 || (self.is_valid(x, y) && self.is_valid(x + dx - 1, y + dy - 1))
+        );
         for x in x..(x + dx) {
             for y in y..(y + dy) {
-                let offset = (info.stride * y + x) * info.bytes_per_pixel;
-                Self::color(rgb)(self.buffer_start.wrapping_add(offset), info.pixel_format);
+                // SAFETY: We have checked that the corners are within bounds, so the whole
+                // rectangle is within bounds.
+                Self::color(rgb)(unsafe { self.pixel_at_unchecked(x, y) }, info.pixel_format);
             }
         }
     }
@@ -124,11 +216,10 @@ impl<'a> Vga<'a> {
     }
 
     pub fn load_default_font() -> &'static [u8; 4096] {
-        static FONT: &'static [u8; 4096] = include_bytes!("../../assets/font");
+        static FONT: &[u8; 4096] = include_bytes!("../../assets/font");
         FONT
     }
 
-    /// color : 0xRRGGBB
     pub fn write_char(
         &mut self,
         font: &[u8; 4096],
@@ -137,21 +228,38 @@ impl<'a> Vga<'a> {
         y: usize,
         fg: [u8; 3],
         bg: [u8; 3],
+    ) {
+        assert!(self.is_valid(x + 7, y + 15));
+        unsafe { self.write_char_unchecked(font, char, x, y, fg, bg) }
+    }
+
+    /// color : 0xRRGGBB
+    pub unsafe fn write_char_unchecked(
+        &mut self,
+        font: &[u8; 4096],
+        char: u8,
+        x: usize,
+        y: usize,
+        fg: [u8; 3],
+        bg: [u8; 3],
     ) {
         let mask = [128, 64, 32, 16, 8, 4, 2, 1];
         let glyph = char as usize * 16;
-
         for cy in 0..16 {
             for cx in 0..8 {
-                self.put_pixel(
-                    x + cx,
-                    y + cy - 12,
-                    if font[glyph + cy] & mask[cx] != 0 {
-                        fg
-                    } else {
-                        bg
-                    },
-                )
+                // SAFETY: the rectangle that contains the glyph has the outermost corner within
+                // bounds (see assert above), so all the pixels of the glyph are within bounds.
+                unsafe {
+                    self.put_pixel_unchecked(
+                        x + cx,
+                        y + cy - 12,
+                        if font[glyph + cy] & mask[cx] != 0 {
+                            fg
+                        } else {
+                            bg
+                        },
+                    )
+                }
             }
         }
     }
@@ -304,13 +412,22 @@ impl VgaConsole<'_, '_> {
 
         for y in 0..self.vga.info.height - 16 {
             for x in 0..self.vga.info.width {
-                self.vga.put_pixel(x, y, self.vga.get_pixel(x, y + 16));
+                // SAFETY: we know that the coordinates are within the bounds, since the bounds
+                // defined above are exactly the framebuffer's.
+                unsafe {
+                    self.vga
+                        .put_pixel_unchecked(x, y, self.vga.get_pixel_uncheck(x, y + 16));
+                }
             }
         }
         for y in 0..16 {
             for x in 0..self.vga.info.width {
-                self.vga
-                    .put_pixel(x, self.vga.info.height - 16 + y, [0, 0, 0]);
+                // SAFETY: `x` is definitively within bounds
+                // /!\ WE DONT KNOW WHETHER THE FRAME BUFFER IS BIG ENOUGH /!\
+                unsafe {
+                    self.vga
+                        .put_pixel_unchecked(x, self.vga.info.height - 16 + y, [0, 0, 0]);
+                }
             }
         }
     }
@@ -318,20 +435,23 @@ impl VgaConsole<'_, '_> {
 
 impl fmt::Write for VgaConsole<'_, '_> {
     fn write_str(&mut self, s: &str) -> fmt::Result {
-        for c in s.as_bytes() {
-            if *c == '\n' as u8 {
+        for &c in s.as_bytes() {
+            if c == '\n' as u8 {
                 self.newline();
                 continue;
             }
-
-            self.vga.write_char(
-                self.font(),
-                *c,
-                self.column() * 8,
-                (self.line() + 1) * 16,
-                self.fg(),
-                self.bg(),
-            );
+            // SAFETY: according to someone, the internal state of the console is ok, so we don't
+            // write outside of the bounds. /!\ THIS IS FISHY /!\
+            unsafe {
+                self.vga.write_char_unchecked(
+                    self.font(),
+                    c,
+                    self.column() * 8,
+                    (self.line() + 1) * 16,
+                    self.fg(),
+                    self.bg(),
+                );
+            }
             self.set_column(self.column() + 1);
             if self.column() == self.width() {
                 self.newline();
@@ -340,3 +460,5 @@ impl fmt::Write for VgaConsole<'_, '_> {
         Ok(())
     }
 }
+
+unsafe impl Sync for Vga<'_> {}
diff --git a/kernel/src/main.rs b/kernel/src/main.rs
index 0eabf19..929db6a 100644
--- a/kernel/src/main.rs
+++ b/kernel/src/main.rs
@@ -13,61 +13,57 @@ use crate::primitives::halt;
 
 entry_point!(main);
 fn main(boot_info: &'static mut BootInfo) -> ! {
-    #[allow(non_snake_case)]
-    let mut VGA = Vga::new(boot_info.framebuffer.as_mut().unwrap());
-    let font = Vga::load_default_font();
-
-    let black = [0, 0, 0];
-    let white = [255, 255, 255];
-
-    let (width, height) = VGA.window_size();
-    let console_width = VGA.console().width();
-    let console_height = VGA.console().height();
-    VGA.fill_rect(0, 0, width, height, black);
-
-    let mut console = VGA.console();
-    console.set_line(2);
-    let col = console.column();
-    write!(console, "abc").unwrap();
-    console.set_column(console.column() + 1);
-    write!(console, "def").unwrap();
-    console.set_column(col);
-    console.set_line(console.line() + 1);
-    write!(console, "hij").unwrap();
-    console.set_column(console.column() + 1);
-    write!(console, "klm").unwrap();
+    // SAFETY: I have no idea what I am doing
+    unsafe {
+	init(boot_info.framebuffer.as_mut().unwrap());
+    }
+    println!("Hello, world!");
 
-    VGA.write_bytes(font, b"Hello\nWorld!", 100, 100, white, black, 4);
+    // let mut console = VGA.console();
+    // console.set_line(2);
+    // let col = console.column();
+    // write!(console, "abc").unwrap();
+    // console.set_column(console.column() + 1);
+    // write!(console, "def").unwrap();
+    // console.set_column(col);
+    // console.set_line(console.line() + 1);
+    // write!(console, "hij").unwrap();
+    // console.set_column(console.column() + 1);
+    // write!(console, "klm").unwrap();
 
-    VGA.console().set_column(0);
-    VGA.console().set_line(0);
+    // VGA.write_bytes(font, b"Hello\nWorld!", 100, 100, white, black, 4);
 
-    write!(
-        VGA.console(),
-        "{}x{}|{}x{}",
-        width,
-        height,
-        console_width,
-        console_height
-    )
-    .unwrap();
+    // VGA.console().set_column(0);
+    // VGA.console().set_line(0);
 
-    let mut console = VGA.console();
-    console.set_line(0);
-    for i in 0..55 {
-        console.set_column(100);
-        write!(console, "{}\n", i).unwrap();
-        if i == 10 {
-            console.newline();
-        }
-    }
+    // write!(
+    //     VGA.console(),
+    //     "{}x{}|{}x{}",
+    //     width,
+    //     height,
+    //     console_width,
+    //     console_height
+    // )
+    // .unwrap();
 
-    VGA.fill_rect(1200, 640, 80, 80, [255, 0, 0]);
+    // let mut console = VGA.console();
+    // console.set_line(0);
+    // for i in 0..55 {
+    //     console.set_column(100);
+    //     write!(console, "{}\n", i).unwrap();
+    //     if i == 10 {
+    //         console.newline();
+    //     }
+    // }
 
-    halt()
+    // VGA.fill_rect(1200, 640, 80, 80, [255, 0, 0]);
+    panic!("AHA");
+    // halt()
 }
 
 #[panic_handler]
-fn panic(_panic_info: &panic::PanicInfo) -> ! {
+fn panic(panic_info: &panic::PanicInfo) -> ! {
+    println!("=== KERNEL PANIC ===");
+    println!("{}", panic_info);
     halt()
 }
-- 
GitLab


From fe4750b948bd78740e809d930691ee0b72ef37dd Mon Sep 17 00:00:00 2001
From: Simon Dima <simon.dima@ens.psl.eu>
Date: Thu, 23 Feb 2023 13:06:33 +0100
Subject: [PATCH 2/6] Fixed a few clippy lints

---
 .gitignore              |  1 +
 kernel/src/basic_vga.rs | 27 +++++++++++----------------
 2 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/.gitignore b/.gitignore
index ea8c4bf..e9868bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 /target
+*.swp
diff --git a/kernel/src/basic_vga.rs b/kernel/src/basic_vga.rs
index d5dd1c0..a510294 100644
--- a/kernel/src/basic_vga.rs
+++ b/kernel/src/basic_vga.rs
@@ -22,7 +22,6 @@ pub unsafe fn init(frame_buffer: &'static mut FrameBuffer) {
     VGA = Some(vga);
 }
 
-
 /// # Safety
 ///
 /// No thread-concurrent access must be made to the VGA. A single exclusive borrow can live at
@@ -73,7 +72,7 @@ impl<'a> Vga<'a> {
     const RED: Color = [255, 0, 0];
     const GREEN: Color = [0, 255, 0];
     const BLUE: Color = [0, 0, 255];
-    
+
     pub fn new(frame_buffer: &'a mut FrameBuffer) -> Self {
         Self {
             buffer_start: frame_buffer.buffer_mut().as_mut_ptr(),
@@ -134,7 +133,7 @@ impl<'a> Vga<'a> {
     /// framebuffer.
     pub unsafe fn pixel_at_unchecked(&self, x: usize, y: usize) -> *mut u8 {
         let offset = (self.info.stride * y + x) * self.info.bytes_per_pixel;
-        self.buffer_start.offset(offset as isize)
+        self.buffer_start.add(offset)
     }
 
     pub fn pixel_at(&mut self, x: usize, y: usize) -> *mut u8 {
@@ -178,14 +177,14 @@ impl<'a> Vga<'a> {
             PixelFormat::Rgb => {
                 for i in 0..3 {
                     unsafe {
-                        buffer.offset(i as isize).write_volatile(rgb[i]);
+                        buffer.add(i).write_volatile(rgb[i]);
                     }
                 }
             }
             PixelFormat::Bgr => {
                 for i in 0..3 {
                     unsafe {
-                        buffer.offset(i as isize).write_volatile(rgb[i]);
+                        buffer.add(i).write_volatile(rgb[i]);
                     }
                 }
             }
@@ -246,18 +245,14 @@ impl<'a> Vga<'a> {
         let mask = [128, 64, 32, 16, 8, 4, 2, 1];
         let glyph = char as usize * 16;
         for cy in 0..16 {
-            for cx in 0..8 {
+            for (cx, msk) in mask.iter().enumerate() {
                 // SAFETY: the rectangle that contains the glyph has the outermost corner within
                 // bounds (see assert above), so all the pixels of the glyph are within bounds.
                 unsafe {
                     self.put_pixel_unchecked(
                         x + cx,
                         y + cy - 12,
-                        if font[glyph + cy] & mask[cx] != 0 {
-                            fg
-                        } else {
-                            bg
-                        },
+                        if font[glyph + cy] & msk != 0 { fg } else { bg },
                     )
                 }
             }
@@ -278,7 +273,7 @@ impl<'a> Vga<'a> {
     ) {
         let mut char_in_line = 0;
         for c in text {
-            if *c == '\n' as u8 {
+            if *c == b'\n' {
                 x -= 8 * char_in_line;
                 y += 16;
                 char_in_line = 0;
@@ -298,14 +293,14 @@ impl<'a> Vga<'a> {
 
     /// zeroes tab and writes the digit of the number in tab, returning a slice of it
     pub fn print_u32(mut n: u32, tab: &mut [u8; 20]) -> &[u8] {
-        *tab = [0 as u8; 20];
+        *tab = [0_u8; 20];
         if n == 0 {
-            tab[0] = '0' as u8;
+            tab[0] = b'0';
             return &tab[0..1];
         }
         let mut i = 0;
         while n != 0 {
-            tab[19 - i] = '0' as u8 + (n % 10) as u8;
+            tab[19 - i] = b'0' + (n % 10) as u8;
             n /= 10;
             i += 1;
         }
@@ -436,7 +431,7 @@ impl VgaConsole<'_, '_> {
 impl fmt::Write for VgaConsole<'_, '_> {
     fn write_str(&mut self, s: &str) -> fmt::Result {
         for &c in s.as_bytes() {
-            if c == '\n' as u8 {
+            if c == b'\n' {
                 self.newline();
                 continue;
             }
-- 
GitLab


From ad48b647ec246f98b0ff8036e12432248d3effcc Mon Sep 17 00:00:00 2001
From: jthulhu <adrien.lc.mathieu@gmail.com>
Date: Thu, 23 Feb 2023 16:53:39 +0100
Subject: [PATCH 3/6] [kernel/{main,vga}] Remove UB!!!! (and also, it works).

---
 kernel/src/main.rs                  |   6 +-
 kernel/src/{basic_vga.rs => vga.rs} | 139 +++++++++++++++++-----------
 2 files changed, 88 insertions(+), 57 deletions(-)
 rename kernel/src/{basic_vga.rs => vga.rs} (75%)

diff --git a/kernel/src/main.rs b/kernel/src/main.rs
index 929db6a..4520031 100644
--- a/kernel/src/main.rs
+++ b/kernel/src/main.rs
@@ -3,12 +3,12 @@
 
 use bootloader_api::{entry_point, BootInfo};
 
-use core::{fmt::Write, panic};
+use core::panic;
 
-mod basic_vga;
+mod vga;
 mod primitives;
 
-use crate::basic_vga::*;
+use crate::vga::*;
 use crate::primitives::halt;
 
 entry_point!(main);
diff --git a/kernel/src/basic_vga.rs b/kernel/src/vga.rs
similarity index 75%
rename from kernel/src/basic_vga.rs
rename to kernel/src/vga.rs
index a510294..81ceeb9 100644
--- a/kernel/src/basic_vga.rs
+++ b/kernel/src/vga.rs
@@ -2,41 +2,44 @@ use bootloader_api::info::{FrameBuffer, FrameBufferInfo, PixelFormat};
 
 use core::{
     fmt::{self, Arguments},
-    marker::PhantomData,
+    marker::PhantomData, sync::atomic::{AtomicUsize, AtomicU8, Ordering}, mem::MaybeUninit,
 };
 
 type Color = [u8; 3];
 
-static mut VGA: Option<Vga<'static>> = None;
+// This is only mutable for initialization, otherwise it's "read-only"
+static mut VGA: MaybeUninit<Vga<'static>> = MaybeUninit::uninit();
 
-/// This initializes the console with a framebuffer. This is required to be subsequently able
+/// Initialize the console with a framebuffer. This is required to be subsequently able
 /// to print things to the console.
 ///
 /// # Safety
 ///
-/// No thread-concurrent access must be made to the console, including the initialization.
+/// This function must be called exactly once, and it must return before the VGA structure is
+/// accessed.
 pub unsafe fn init(frame_buffer: &'static mut FrameBuffer) {
     let mut vga = Vga::new(frame_buffer);
     let (width, height) = vga.window_size();
     vga.fill_rect(0, 0, width, height, Vga::BLACK);
-    VGA = Some(vga);
+    VGA.write(vga);
 }
 
-/// # Safety
-///
-/// No thread-concurrent access must be made to the VGA. A single exclusive borrow can live at
-/// any time.
-pub unsafe fn vga<'a>() -> &'a mut Vga<'static> {
-    VGA.as_mut().unwrap()
+/// Get a borrow of the VGA.
+pub fn vga<'a>() -> &'a Vga<'static> {
+    // SAFETY: The VGA *must* have been initialized, it's literally the *first* thing that this
+    // whole kernel does. If it's not, use `git blame` to find the culprit and throw them out
+    // of a window.
+    //
+    // I've warned you...
+    unsafe {
+	VGA.assume_init_ref()
+    }
 }
 
 #[macro_export]
 macro_rules! print {
     ($($arg:tt)*) => {
-	// SAFETY: /!\ None so far /!\
-	unsafe {
-            $crate::basic_vga::print(format_args!($($arg)*))
-	}
+        $crate::vga::print(format_args!($($arg)*))
     };
 }
 
@@ -47,7 +50,7 @@ macro_rules! println {
     };
 }
 
-pub unsafe fn print(args: Arguments) {
+pub fn print(args: Arguments) {
     use core::fmt::Write;
     vga().console().write_fmt(args).unwrap();
 }
@@ -147,7 +150,7 @@ impl<'a> Vga<'a> {
     /// # Safety
     ///
     /// The safety conditions of this function are the same of [`pixel_at_unchecked`].
-    pub unsafe fn put_pixel_unchecked(&mut self, x: usize, y: usize, rgb: [u8; 3]) {
+    pub unsafe fn put_pixel_unchecked(&self, x: usize, y: usize, rgb: [u8; 3]) {
         Self::color(rgb)(self.pixel_at_unchecked(x, y), self.info.pixel_format);
     }
 
@@ -157,7 +160,7 @@ impl<'a> Vga<'a> {
         x < self.info.width && y < self.info.height
     }
 
-    pub fn fill_rect(&mut self, x: usize, y: usize, dx: usize, dy: usize, rgb: [u8; 3]) {
+    pub fn fill_rect(&self, x: usize, y: usize, dx: usize, dy: usize, rgb: [u8; 3]) {
         let info = self.info;
         assert!(
             dx == 0 || dy == 0 || (self.is_valid(x, y) && self.is_valid(x + dx - 1, y + dy - 1))
@@ -220,7 +223,7 @@ impl<'a> Vga<'a> {
     }
 
     pub fn write_char(
-        &mut self,
+        &self,
         font: &[u8; 4096],
         char: u8,
         x: usize,
@@ -234,7 +237,7 @@ impl<'a> Vga<'a> {
 
     /// color : 0xRRGGBB
     pub unsafe fn write_char_unchecked(
-        &mut self,
+        &self,
         font: &[u8; 4096],
         char: u8,
         x: usize,
@@ -262,7 +265,7 @@ impl<'a> Vga<'a> {
     // line length in characters, 0 means no limit
     // handle newline
     pub fn write_bytes(
-        &mut self,
+        &self,
         font: &[u8; 4096],
         text: &[u8],
         mut x: usize,
@@ -307,28 +310,28 @@ impl<'a> Vga<'a> {
         &tab[20 - i..]
     }
 
-    pub fn console(&mut self) -> VgaConsole<'_, 'a> {
+    pub fn console(&self) -> VgaConsole<'_, 'a> {
         VgaConsole { vga: self }
     }
 }
 
 #[repr(C)]
 struct VgaConsoleState {
-    column: usize,
-    line: usize,
-    fg: [u8; 3],
-    bg: [u8; 3],
-    font: Option<&'static [u8; 4096]>,
+    column: AtomicUsize,
+    line: AtomicUsize,
+    fg: [AtomicU8; 3],
+    bg: [AtomicU8; 3],
+    font: &'static [u8; 4096],
 }
 
 impl VgaConsoleState {
     pub fn new() -> Self {
         Self {
-            column: 0,
-            line: 0,
-            fg: [255, 255, 255],
-            bg: [0, 0, 0],
-            font: None,
+            column: AtomicUsize::new(0),
+            line: AtomicUsize::new(0),
+            fg: [AtomicU8::new(255), AtomicU8::new(255), AtomicU8::new(255)],
+            bg: [AtomicU8::new(0), AtomicU8::new(0), AtomicU8::new(0)],
+            font: Vga::load_default_font(),
         }
     }
 }
@@ -340,11 +343,11 @@ impl Default for VgaConsoleState {
 }
 
 pub struct VgaConsole<'a, 'b> {
-    vga: &'a mut Vga<'b>,
+    vga: &'a Vga<'b>,
 }
 
 impl VgaConsole<'_, '_> {
-    pub fn width(&mut self) -> usize {
+    pub fn width(&self) -> usize {
         self.vga.info.width / 8
     }
 
@@ -353,51 +356,79 @@ impl VgaConsole<'_, '_> {
     }
 
     pub fn column(&self) -> usize {
-        self.vga.console_state.column
+        self.vga.console_state.column.load(Ordering::Relaxed)
     }
 
     pub fn line(&self) -> usize {
-        self.vga.console_state.line
+        self.vga.console_state.line.load(Ordering::Relaxed)
     }
 
-    pub fn set_column(&mut self, column: usize) {
-        debug_assert!(column < self.width());
-        self.vga.console_state.column = column;
+    /// # Safety
+    ///
+    /// `column` must be less than `self.width()`. For a safe counterpart, see [`set_column`]
+    pub unsafe fn set_column_unchecked(&self, column: usize) {
+	self.vga.console_state.column.store(column, Ordering::Relaxed);
     }
 
-    pub fn set_line(&mut self, line: usize) {
-        debug_assert!(line < self.height() - 1);
-        self.vga.console_state.line = line;
+    /// Change the column of the cursor. The column must be within bounds.
+    ///
+    /// # Panic
+    ///
+    /// This will panic if the column is not within bounds.
+    pub fn set_column(&self, column: usize) {
+        assert!(column < self.width());
+        // SAFETY: We have ensured above that `column < self.width`.
+	unsafe {
+	    self.set_column_unchecked(column)
+	}
+    }
+
+    /// # Safety
+    ///
+    /// `line` must be less than `self.height - 1`
+    pub unsafe fn set_line_unchecked(&self, line: usize) {
+	self.vga.console_state.line.store(line, Ordering::Relaxed);
+    }
+    
+    pub fn set_line(&self, line: usize) {
+        assert!(line < self.height() - 1);
+	// SAFETY: We have ensured above that `line < self.height - 1`.
+	unsafe {
+            self.set_line_unchecked(line);
+	}
     }
 
     pub fn fg(&self) -> [u8; 3] {
-        self.vga.console_state.fg
+        [self.vga.console_state.fg[0].load(Ordering::Relaxed),
+	 self.vga.console_state.fg[1].load(Ordering::Relaxed),
+	 self.vga.console_state.fg[2].load(Ordering::Relaxed)]
     }
 
     pub fn bg(&self) -> [u8; 3] {
-        self.vga.console_state.bg
+        [self.vga.console_state.bg[0].load(Ordering::Relaxed),
+	 self.vga.console_state.bg[1].load(Ordering::Relaxed),
+	 self.vga.console_state.bg[2].load(Ordering::Relaxed)]
     }
 
-    pub fn set_fg(&mut self, color: [u8; 3]) {
-        self.vga.console_state.fg = color;
+    pub fn set_fg(&self, color: [u8; 3]) {
+        self.vga.console_state.fg[0].store(color[0], Ordering::Relaxed);
+	self.vga.console_state.fg[1].store(color[1], Ordering::Relaxed);
+	self.vga.console_state.fg[2].store(color[2], Ordering::Relaxed);
     }
 
-    pub fn set_bg(&mut self, color: [u8; 3]) {
-        self.vga.console_state.bg = color;
+    pub fn set_bg(&self, color: [u8; 3]) {
+        self.vga.console_state.bg[0].store(color[0], Ordering::Relaxed);
+	self.vga.console_state.bg[1].store(color[1], Ordering::Relaxed);
+	self.vga.console_state.bg[2].store(color[2], Ordering::Relaxed);
     }
 
     pub fn font(&self) -> &'static [u8; 4096] {
         self.vga
             .console_state
             .font
-            .unwrap_or(Vga::load_default_font())
-    }
-
-    pub fn set_font(&mut self, font: &'static [u8; 4096]) {
-        self.vga.console_state.font = Some(font);
     }
 
-    pub fn newline(&mut self) {
+    pub fn newline(&self) {
         self.set_column(0);
 
         if self.line() < self.height() - 2 {
-- 
GitLab


From 7a5b7834fec205895b6e9628873075d3a44c132d Mon Sep 17 00:00:00 2001
From: jthulhu <adrien.lc.mathieu@gmail.com>
Date: Thu, 23 Feb 2023 17:21:40 +0100
Subject: [PATCH 4/6] [kernel/vga] Removed useless mutability.

---
 kernel/src/vga.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/src/vga.rs b/kernel/src/vga.rs
index 81ceeb9..e7cc456 100644
--- a/kernel/src/vga.rs
+++ b/kernel/src/vga.rs
@@ -2,7 +2,7 @@ use bootloader_api::info::{FrameBuffer, FrameBufferInfo, PixelFormat};
 
 use core::{
     fmt::{self, Arguments},
-    marker::PhantomData, sync::atomic::{AtomicUsize, AtomicU8, Ordering}, mem::MaybeUninit,
+    marker::PhantomData, mem::MaybeUninit,
 };
 
 type Color = [u8; 3];
@@ -18,7 +18,7 @@ static mut VGA: MaybeUninit<Vga<'static>> = MaybeUninit::uninit();
 /// This function must be called exactly once, and it must return before the VGA structure is
 /// accessed.
 pub unsafe fn init(frame_buffer: &'static mut FrameBuffer) {
-    let mut vga = Vga::new(frame_buffer);
+    let vga = Vga::new(frame_buffer);
     let (width, height) = vga.window_size();
     vga.fill_rect(0, 0, width, height, Vga::BLACK);
     VGA.write(vga);
-- 
GitLab


From db8abea830bcc03fba1b936e86e8115ac9f47a54 Mon Sep 17 00:00:00 2001
From: Simon Dima <simon.dima@ens.psl.eu>
Date: Thu, 23 Feb 2023 17:35:02 +0100
Subject: [PATCH 5/6] Added Color struct

---
 kernel/src/vga.rs | 224 +++++++++++++++++++++++++---------------------
 1 file changed, 121 insertions(+), 103 deletions(-)

diff --git a/kernel/src/vga.rs b/kernel/src/vga.rs
index 81ceeb9..47097b7 100644
--- a/kernel/src/vga.rs
+++ b/kernel/src/vga.rs
@@ -2,10 +2,17 @@ use bootloader_api::info::{FrameBuffer, FrameBufferInfo, PixelFormat};
 
 use core::{
     fmt::{self, Arguments},
-    marker::PhantomData, sync::atomic::{AtomicUsize, AtomicU8, Ordering}, mem::MaybeUninit,
+    marker::PhantomData,
+    mem::MaybeUninit,
+    sync::atomic::{AtomicU8, AtomicUsize, Ordering},
 };
 
-type Color = [u8; 3];
+#[derive(Clone, Copy)]
+pub struct Color {
+    red: u8,
+    green: u8,
+    blue: u8,
+}
 
 // This is only mutable for initialization, otherwise it's "read-only"
 static mut VGA: MaybeUninit<Vga<'static>> = MaybeUninit::uninit();
@@ -18,7 +25,7 @@ static mut VGA: MaybeUninit<Vga<'static>> = MaybeUninit::uninit();
 /// This function must be called exactly once, and it must return before the VGA structure is
 /// accessed.
 pub unsafe fn init(frame_buffer: &'static mut FrameBuffer) {
-    let mut vga = Vga::new(frame_buffer);
+    let vga = Vga::new(frame_buffer);
     let (width, height) = vga.window_size();
     vga.fill_rect(0, 0, width, height, Vga::BLACK);
     VGA.write(vga);
@@ -31,9 +38,7 @@ pub fn vga<'a>() -> &'a Vga<'static> {
     // of a window.
     //
     // I've warned you...
-    unsafe {
-	VGA.assume_init_ref()
-    }
+    unsafe { VGA.assume_init_ref() }
 }
 
 #[macro_export]
@@ -70,11 +75,31 @@ impl<'a> From<&'a mut FrameBuffer> for Vga<'a> {
 }
 
 impl<'a> Vga<'a> {
-    const BLACK: Color = [0; 3];
-    const WHITE: Color = [255; 3];
-    const RED: Color = [255, 0, 0];
-    const GREEN: Color = [0, 255, 0];
-    const BLUE: Color = [0, 0, 255];
+    const BLACK: Color = Color {
+        red: 0,
+        green: 0,
+        blue: 0,
+    };
+    const WHITE: Color = Color {
+        red: 255,
+        green: 255,
+        blue: 255,
+    };
+    const RED: Color = Color {
+        red: 255,
+        green: 0,
+        blue: 0,
+    };
+    const GREEN: Color = Color {
+        red: 0,
+        green: 255,
+        blue: 0,
+    };
+    const BLUE: Color = Color {
+        red: 0,
+        green: 0,
+        blue: 255,
+    };
 
     pub fn new(frame_buffer: &'a mut FrameBuffer) -> Self {
         Self {
@@ -86,10 +111,10 @@ impl<'a> Vga<'a> {
     }
 
     #[inline]
-    pub fn get_pixel(&self, x: usize, y: usize) -> [u8; 3] {
+    pub fn get_pixel(&self, x: usize, y: usize) -> Color {
         assert!(self.is_valid(x, y));
 
-        unsafe { self.get_pixel_uncheck(x, y) }
+        unsafe { self.get_pixel_unchecked(x, y) }
     }
 
     /// Returns the color of a pixel.
@@ -97,33 +122,37 @@ impl<'a> Vga<'a> {
     /// # Safety
     ///
     /// The safety conditions of this function are the same of [`pixel_at_unchecked`].
-    pub unsafe fn get_pixel_uncheck(&self, x: usize, y: usize) -> [u8; 3] {
+    pub unsafe fn get_pixel_unchecked(&self, x: usize, y: usize) -> Color {
         let buffer = self.pixel_at_unchecked(x, y);
         match self.info.pixel_format {
-            PixelFormat::Rgb => [
-                buffer.offset(0).read_volatile(),
-                buffer.offset(1).read_volatile(),
-                buffer.offset(2).read_volatile(),
-            ],
-            PixelFormat::Bgr => [
-                buffer.offset(2).read_volatile(),
-                buffer.offset(1).read_volatile(),
-                buffer.offset(0).read_volatile(),
-            ],
+            PixelFormat::Rgb => Color {
+                red: buffer.offset(0).read_volatile(),
+                green: buffer.offset(1).read_volatile(),
+                blue: buffer.offset(2).read_volatile(),
+            },
+            PixelFormat::Bgr => Color {
+                red: buffer.offset(2).read_volatile(),
+                green: buffer.offset(1).read_volatile(),
+                blue: buffer.offset(0).read_volatile(),
+            },
             PixelFormat::U8 => {
                 let c = buffer.read_volatile();
-                [c, c, c]
+                Color {
+                    red: c,
+                    green: c,
+                    blue: c,
+                }
             }
             PixelFormat::Unknown {
                 red_position,
                 green_position,
                 blue_position,
-            } => [
-                buffer.offset(red_position as _).read_volatile(),
-                buffer.offset(green_position as _).read_volatile(),
-                buffer.offset(blue_position as _).read_volatile(),
-            ],
-            _ => [0, 0, 0],
+            } => Color {
+                red: buffer.add(red_position as _).read_volatile(),
+                green: buffer.add(green_position as _).read_volatile(),
+                blue: buffer.add(blue_position as _).read_volatile(),
+            },
+            _ => panic!("unknown pixel format"),
         }
     }
 
@@ -150,8 +179,8 @@ impl<'a> Vga<'a> {
     /// # Safety
     ///
     /// The safety conditions of this function are the same of [`pixel_at_unchecked`].
-    pub unsafe fn put_pixel_unchecked(&self, x: usize, y: usize, rgb: [u8; 3]) {
-        Self::color(rgb)(self.pixel_at_unchecked(x, y), self.info.pixel_format);
+    pub unsafe fn put_pixel_unchecked(&self, x: usize, y: usize, color: Color) {
+        self.color_pixel_unchecked(self.pixel_at_unchecked(x, y), color);
     }
 
     /// Check is the coordinates are within the bounds of the framebuffer.
@@ -160,7 +189,7 @@ impl<'a> Vga<'a> {
         x < self.info.width && y < self.info.height
     }
 
-    pub fn fill_rect(&self, x: usize, y: usize, dx: usize, dy: usize, rgb: [u8; 3]) {
+    pub fn fill_rect(&self, x: usize, y: usize, dx: usize, dy: usize, color: Color) {
         let info = self.info;
         assert!(
             dx == 0 || dy == 0 || (self.is_valid(x, y) && self.is_valid(x + dx - 1, y + dy - 1))
@@ -169,46 +198,40 @@ impl<'a> Vga<'a> {
             for y in y..(y + dy) {
                 // SAFETY: We have checked that the corners are within bounds, so the whole
                 // rectangle is within bounds.
-                Self::color(rgb)(unsafe { self.pixel_at_unchecked(x, y) }, info.pixel_format);
+                unsafe {
+                    self.color_pixel_unchecked(self.pixel_at_unchecked(x, y), color);
+                }
             }
         }
     }
 
     #[inline(always)]
-    fn color(rgb: [u8; 3]) -> impl Fn(*mut u8, PixelFormat) {
-        move |buffer, format| match format {
+    unsafe fn color_pixel_unchecked(&self, pix: *mut u8, col: Color) {
+        match self.info.pixel_format {
             PixelFormat::Rgb => {
-                for i in 0..3 {
-                    unsafe {
-                        buffer.add(i).write_volatile(rgb[i]);
-                    }
-                }
+                pix.add(0).write_volatile(col.red);
+                pix.add(1).write_volatile(col.green);
+                pix.add(2).write_volatile(col.blue);
             }
             PixelFormat::Bgr => {
-                for i in 0..3 {
-                    unsafe {
-                        buffer.add(i).write_volatile(rgb[i]);
-                    }
-                }
+                pix.add(0).write_volatile(col.blue);
+                pix.add(1).write_volatile(col.green);
+                pix.add(2).write_volatile(col.red);
             }
             PixelFormat::U8 => {
-                let c = 30 * rgb[0] as u16 + 59 * rgb[1] as u16 + 11 * rgb[2] as u16;
-                unsafe {
-                    buffer.write_volatile((c / 100) as u8);
-                }
+                let c = 30 * col.red as u16 + 59 * col.green as u16 + 11 * col.blue as u16;
+                pix.write_volatile((c / 100) as u8);
             }
             PixelFormat::Unknown {
                 red_position,
                 green_position,
                 blue_position,
-            } => unsafe {
-                buffer.offset(red_position as isize).write_volatile(rgb[0]);
-                buffer
-                    .offset(green_position as isize)
-                    .write_volatile(rgb[1]);
-                buffer.offset(blue_position as isize).write_volatile(rgb[2]);
-            },
-            _ => {}
+            } => {
+                pix.add(red_position as usize).write_volatile(col.red);
+                pix.add(green_position as usize).write_volatile(col.green);
+                pix.add(blue_position as usize).write_volatile(col.blue);
+            }
+            _ => panic!("unknown pixel format"),
         }
     }
 
@@ -222,17 +245,9 @@ impl<'a> Vga<'a> {
         FONT
     }
 
-    pub fn write_char(
-        &self,
-        font: &[u8; 4096],
-        char: u8,
-        x: usize,
-        y: usize,
-        fg: [u8; 3],
-        bg: [u8; 3],
-    ) {
+    pub fn write_char(&self, font: &[u8; 4096], chr: u8, x: usize, y: usize, fg: Color, bg: Color) {
         assert!(self.is_valid(x + 7, y + 15));
-        unsafe { self.write_char_unchecked(font, char, x, y, fg, bg) }
+        unsafe { self.write_char_unchecked(font, chr, x, y, fg, bg) }
     }
 
     /// color : 0xRRGGBB
@@ -242,8 +257,8 @@ impl<'a> Vga<'a> {
         char: u8,
         x: usize,
         y: usize,
-        fg: [u8; 3],
-        bg: [u8; 3],
+        fg: Color,
+        bg: Color,
     ) {
         let mask = [128, 64, 32, 16, 8, 4, 2, 1];
         let glyph = char as usize * 16;
@@ -270,8 +285,8 @@ impl<'a> Vga<'a> {
         text: &[u8],
         mut x: usize,
         mut y: usize,
-        fg: [u8; 3],
-        bg: [u8; 3],
+        fg: Color,
+        bg: Color,
         line_length: usize,
     ) {
         let mut char_in_line = 0;
@@ -367,7 +382,10 @@ impl VgaConsole<'_, '_> {
     ///
     /// `column` must be less than `self.width()`. For a safe counterpart, see [`set_column`]
     pub unsafe fn set_column_unchecked(&self, column: usize) {
-	self.vga.console_state.column.store(column, Ordering::Relaxed);
+        self.vga
+            .console_state
+            .column
+            .store(column, Ordering::Relaxed);
     }
 
     /// Change the column of the cursor. The column must be within bounds.
@@ -378,54 +396,54 @@ impl VgaConsole<'_, '_> {
     pub fn set_column(&self, column: usize) {
         assert!(column < self.width());
         // SAFETY: We have ensured above that `column < self.width`.
-	unsafe {
-	    self.set_column_unchecked(column)
-	}
+        unsafe { self.set_column_unchecked(column) }
     }
 
     /// # Safety
     ///
     /// `line` must be less than `self.height - 1`
     pub unsafe fn set_line_unchecked(&self, line: usize) {
-	self.vga.console_state.line.store(line, Ordering::Relaxed);
+        self.vga.console_state.line.store(line, Ordering::Relaxed);
     }
-    
+
     pub fn set_line(&self, line: usize) {
         assert!(line < self.height() - 1);
-	// SAFETY: We have ensured above that `line < self.height - 1`.
-	unsafe {
+        // SAFETY: We have ensured above that `line < self.height - 1`.
+        unsafe {
             self.set_line_unchecked(line);
-	}
+        }
     }
 
-    pub fn fg(&self) -> [u8; 3] {
-        [self.vga.console_state.fg[0].load(Ordering::Relaxed),
-	 self.vga.console_state.fg[1].load(Ordering::Relaxed),
-	 self.vga.console_state.fg[2].load(Ordering::Relaxed)]
+    pub fn fg(&self) -> Color {
+        Color {
+            red: self.vga.console_state.fg[0].load(Ordering::Relaxed),
+            green: self.vga.console_state.fg[1].load(Ordering::Relaxed),
+            blue: self.vga.console_state.fg[2].load(Ordering::Relaxed),
+        }
     }
 
-    pub fn bg(&self) -> [u8; 3] {
-        [self.vga.console_state.bg[0].load(Ordering::Relaxed),
-	 self.vga.console_state.bg[1].load(Ordering::Relaxed),
-	 self.vga.console_state.bg[2].load(Ordering::Relaxed)]
+    pub fn bg(&self) -> Color {
+        Color {
+            red: self.vga.console_state.bg[0].load(Ordering::Relaxed),
+            green: self.vga.console_state.bg[1].load(Ordering::Relaxed),
+            blue: self.vga.console_state.bg[2].load(Ordering::Relaxed),
+        }
     }
 
-    pub fn set_fg(&self, color: [u8; 3]) {
-        self.vga.console_state.fg[0].store(color[0], Ordering::Relaxed);
-	self.vga.console_state.fg[1].store(color[1], Ordering::Relaxed);
-	self.vga.console_state.fg[2].store(color[2], Ordering::Relaxed);
+    pub fn set_fg(&self, color: Color) {
+        self.vga.console_state.fg[0].store(color.red, Ordering::Relaxed);
+        self.vga.console_state.fg[1].store(color.green, Ordering::Relaxed);
+        self.vga.console_state.fg[2].store(color.blue, Ordering::Relaxed);
     }
 
-    pub fn set_bg(&self, color: [u8; 3]) {
-        self.vga.console_state.bg[0].store(color[0], Ordering::Relaxed);
-	self.vga.console_state.bg[1].store(color[1], Ordering::Relaxed);
-	self.vga.console_state.bg[2].store(color[2], Ordering::Relaxed);
+    pub fn set_bg(&self, color: Color) {
+        self.vga.console_state.bg[0].store(color.red, Ordering::Relaxed);
+        self.vga.console_state.bg[1].store(color.green, Ordering::Relaxed);
+        self.vga.console_state.bg[2].store(color.blue, Ordering::Relaxed);
     }
 
     pub fn font(&self) -> &'static [u8; 4096] {
-        self.vga
-            .console_state
-            .font
+        self.vga.console_state.font
     }
 
     pub fn newline(&self) {
@@ -442,7 +460,7 @@ impl VgaConsole<'_, '_> {
                 // defined above are exactly the framebuffer's.
                 unsafe {
                     self.vga
-                        .put_pixel_unchecked(x, y, self.vga.get_pixel_uncheck(x, y + 16));
+                        .put_pixel_unchecked(x, y, self.vga.get_pixel_unchecked(x, y + 16));
                 }
             }
         }
@@ -452,7 +470,7 @@ impl VgaConsole<'_, '_> {
                 // /!\ WE DONT KNOW WHETHER THE FRAME BUFFER IS BIG ENOUGH /!\
                 unsafe {
                     self.vga
-                        .put_pixel_unchecked(x, self.vga.info.height - 16 + y, [0, 0, 0]);
+                        .put_pixel_unchecked(x, self.vga.info.height - 16 + y, Vga::BLACK);
                 }
             }
         }
-- 
GitLab


From b3e0ea25d34f1f63b7b4a61ffd0b80253c34bf91 Mon Sep 17 00:00:00 2001
From: Simon Dima <simon.dima@gmail.com>
Date: Wed, 1 Mar 2023 14:56:14 +0100
Subject: [PATCH 6/6] Print QEMU command being run

---
 src/main.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main.rs b/src/main.rs
index 49d9a27..cfe77dd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -25,6 +25,7 @@ fn main() {
     }
     // log interrupt and exception
     // cmd.arg("-d").arg("int");
+    println!("running {cmd:?}");
     let mut child = cmd.spawn().unwrap();
     child.wait().unwrap();
 }
-- 
GitLab