Merge branch 'dev'
This commit is contained in:
		
						commit
						ebbd8da333
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
/kernel/target
 | 
			
		||||
target
 | 
			
		||||
/kernel/Cargo.lock
 | 
			
		||||
/build
 | 
			
		||||
/binutils
 | 
			
		||||
/gcc
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,4 +3,8 @@ name = "kernel"
 | 
			
		|||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[workspace]
 | 
			
		||||
members = ["std"]
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
std = { path = "std" }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +1,16 @@
 | 
			
		|||
#![no_std]
 | 
			
		||||
#![no_main]
 | 
			
		||||
 | 
			
		||||
use std::println;
 | 
			
		||||
 | 
			
		||||
#[no_mangle]
 | 
			
		||||
pub extern "C" fn kernel_main() -> ! {
 | 
			
		||||
    let vga_buffer = 0xb8000 as *mut u8;
 | 
			
		||||
 | 
			
		||||
    let string: &[u8] = b":3";
 | 
			
		||||
    for (i, &byte) in string.iter().enumerate() {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            *vga_buffer.offset(i as isize * 2) = byte;
 | 
			
		||||
            *vga_buffer.offset(i as isize * 2 + 1) = 0xf;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    let a = 4;
 | 
			
		||||
    println!("Hiii :3");
 | 
			
		||||
    println!("{}", a);
 | 
			
		||||
    loop {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
#[panic_handler]
 | 
			
		||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
 | 
			
		||||
    loop {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								kernel/Cargo.lock → kernel/std/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								kernel/Cargo.lock → kernel/std/Cargo.lock
									
									
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -3,5 +3,5 @@
 | 
			
		|||
version = 3
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kernel"
 | 
			
		||||
name = "std"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
							
								
								
									
										8
									
								
								kernel/std/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								kernel/std/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "std"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
 | 
			
		||||
spin = "0.9.8"
 | 
			
		||||
							
								
								
									
										3
									
								
								kernel/std/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								kernel/std/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
#![no_std]
 | 
			
		||||
 | 
			
		||||
pub mod vga_buffer;
 | 
			
		||||
							
								
								
									
										132
									
								
								kernel/std/src/vga_buffer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								kernel/std/src/vga_buffer.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,132 @@
 | 
			
		|||
use core::fmt::{self, Write};
 | 
			
		||||
 | 
			
		||||
use lazy_static::lazy_static;
 | 
			
		||||
use spin::Mutex;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
#[repr(u8)]
 | 
			
		||||
pub enum Color {
 | 
			
		||||
    Black = 0,
 | 
			
		||||
    Blue = 1,
 | 
			
		||||
    Green = 2,
 | 
			
		||||
    Cyan = 3,
 | 
			
		||||
    Red = 4,
 | 
			
		||||
    Magenta = 5,
 | 
			
		||||
    Brown = 6,
 | 
			
		||||
    LightGray = 7,
 | 
			
		||||
    DarkGray = 8,
 | 
			
		||||
    LightBlue = 9,
 | 
			
		||||
    LightGreen = 10,
 | 
			
		||||
    LightCyan = 11,
 | 
			
		||||
    LightRed = 12,
 | 
			
		||||
    Pink = 13,
 | 
			
		||||
    Yellow = 14,
 | 
			
		||||
    White = 15,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
#[repr(transparent)]
 | 
			
		||||
pub struct ColorCode(u8);
 | 
			
		||||
 | 
			
		||||
impl ColorCode {
 | 
			
		||||
    pub fn new(foreground: Color, background: Color) -> ColorCode {
 | 
			
		||||
        ColorCode((background as u8) << 4 | (foreground as u8))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct ScreenChar {
 | 
			
		||||
    ascii_character: u8,
 | 
			
		||||
    color_code: ColorCode,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const BUFFER_HEIGHT: usize = 25;
 | 
			
		||||
const BUFFER_WIDTH: usize = 80;
 | 
			
		||||
 | 
			
		||||
#[repr(transparent)]
 | 
			
		||||
struct Buffer {
 | 
			
		||||
    chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Writer {
 | 
			
		||||
    col: usize,
 | 
			
		||||
    row: usize,
 | 
			
		||||
    buffer: &'static mut Buffer,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Writer {
 | 
			
		||||
    pub fn write_byte(&mut self, byte: u8) {
 | 
			
		||||
        self.write_byte_color(byte, ColorCode::new(Color::White, Color::Black));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write_byte_color(&mut self, byte: u8, color: ColorCode) {
 | 
			
		||||
        match byte {
 | 
			
		||||
            b'\n' => self.new_line(),
 | 
			
		||||
            byte => {
 | 
			
		||||
                if self.col >= BUFFER_WIDTH {
 | 
			
		||||
                    self.new_line();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let row = self.row;
 | 
			
		||||
                let col = self.col;
 | 
			
		||||
 | 
			
		||||
                let color_code = color;
 | 
			
		||||
                self.buffer.chars[row][col] = ScreenChar {
 | 
			
		||||
                    ascii_character: byte,
 | 
			
		||||
                    color_code,
 | 
			
		||||
                };
 | 
			
		||||
                self.col += 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write_string(&mut self, s: &str) {
 | 
			
		||||
        self.write_string_color(s, ColorCode::new(Color::White, Color::Black));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write_string_color(&mut self, s: &str, color: ColorCode) {
 | 
			
		||||
        for char in s.bytes() {
 | 
			
		||||
            match char {
 | 
			
		||||
                0x20..=0x7e | b'\n' => self.write_byte_color(char, color),
 | 
			
		||||
                _ => self.write_byte(0xfe),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new_line(&mut self) {
 | 
			
		||||
        self.row += 1;
 | 
			
		||||
        self.col = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Write for Writer {
 | 
			
		||||
    fn write_str(&mut self, s: &str) -> fmt::Result {
 | 
			
		||||
        self.write_string(s);
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lazy_static! {
 | 
			
		||||
    pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer {
 | 
			
		||||
        col: 0,
 | 
			
		||||
        row: 0,
 | 
			
		||||
        buffer: unsafe { &mut *(0xB8000 as *mut Buffer) },
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[doc(hidden)]
 | 
			
		||||
pub fn _print(args: fmt::Arguments) {
 | 
			
		||||
    WRITER.lock().write_fmt(args).unwrap()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! print {
 | 
			
		||||
    ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! println {
 | 
			
		||||
    () => ($crate::print!("\n"));
 | 
			
		||||
    ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -350,6 +350,15 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
 | 
			
		|||
# Building the kernel
 | 
			
		||||
To build the kernel I just run `cargo build` in the `kernel` directory. This will produce a binary called `kernel/target/i686-bare-metal/debug/kernel.elf`. I now have a multiboot enabled kernel :)
 | 
			
		||||
 | 
			
		||||
# Grub
 | 
			
		||||
Now to turn the kernel into a ISO file with a bootloader, I used grub. To configure grub I needed to create a directory for it. I made `build/isodir/boot/grub/grub.cfg` containing this:
 | 
			
		||||
```
 | 
			
		||||
menuentry "geos" {
 | 
			
		||||
	multiboot /boot/geos.bin
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
Then I copied `kernel/target/i686-bare-metal/debug/kernel.elf` to `isodir/boot/geos.bin`. Then I ran `grub-mkrescue -o build/geos.iso build/isodir` to make an ISO containing my OS and grub. Yippee
 | 
			
		||||
 | 
			
		||||
# File structure
 | 
			
		||||
```
 | 
			
		||||
geos/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										189
									
								
								log/2024-03-27.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								log/2024-03-27.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,189 @@
 | 
			
		|||
# VGA text
 | 
			
		||||
Hello. Today I succesfully made a `println!` macro.
 | 
			
		||||
 | 
			
		||||
## std
 | 
			
		||||
To following conventions I decided to make a `std` library. To do this I made a workspace in `kernel/`.
 | 
			
		||||
 | 
			
		||||
`kernel/Cargo.toml`
 | 
			
		||||
```toml
 | 
			
		||||
[package]
 | 
			
		||||
name = "kernel"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[workspace]
 | 
			
		||||
members = ["std"]
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
std = { path = "std" }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## lib.rs
 | 
			
		||||
To not have one big spaghetti file I separated out all the individal modules into different files.
 | 
			
		||||
`kernel/std/src/lib.rs`
 | 
			
		||||
```rust
 | 
			
		||||
#![no_std]
 | 
			
		||||
 | 
			
		||||
pub mod vga_buffer;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## vga_buffer.rs
 | 
			
		||||
First step for a VGA text driver is to be able to represent data.
 | 
			
		||||
 | 
			
		||||
`kernel/std/src/lib.rs`
 | 
			
		||||
```rust
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
#[repr(u8)]
 | 
			
		||||
pub enum Color {
 | 
			
		||||
    Black = 0,
 | 
			
		||||
    Blue = 1,
 | 
			
		||||
    Green = 2,
 | 
			
		||||
    Cyan = 3,
 | 
			
		||||
    Red = 4,
 | 
			
		||||
    Magenta = 5,
 | 
			
		||||
    Brown = 6,
 | 
			
		||||
    LightGray = 7,
 | 
			
		||||
    DarkGray = 8,
 | 
			
		||||
    LightBlue = 9,
 | 
			
		||||
    LightGreen = 10,
 | 
			
		||||
    LightCyan = 11,
 | 
			
		||||
    LightRed = 12,
 | 
			
		||||
    Pink = 13,
 | 
			
		||||
    Yellow = 14,
 | 
			
		||||
    White = 15,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
#[repr(transparent)] // Store this as a u8
 | 
			
		||||
pub struct ColorCode(u8);
 | 
			
		||||
 | 
			
		||||
impl ColorCode {
 | 
			
		||||
    pub fn new(foreground: Color, background: Color) -> ColorCode {
 | 
			
		||||
        ColorCode((background as u8) << 4 | (foreground as u8))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
#[repr(C)] // Tells rust to store this like a struct in C, i.e. store this as 2 bytes
 | 
			
		||||
struct ScreenChar {
 | 
			
		||||
    ascii_character: u8,
 | 
			
		||||
    color_code: ColorCode,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const BUFFER_HEIGHT: usize = 25;
 | 
			
		||||
const BUFFER_WIDTH: usize = 80;
 | 
			
		||||
 | 
			
		||||
#[repr(transparent)]
 | 
			
		||||
struct Buffer {
 | 
			
		||||
    chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Now I can represent the VGA text buffer. To write to this I want to make a writer struct that implements `fmt::Write`.
 | 
			
		||||
```rust
 | 
			
		||||
pub struct Writer {
 | 
			
		||||
    col: usize,
 | 
			
		||||
    row: usize,
 | 
			
		||||
    buffer: &'static mut Buffer,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Writer {
 | 
			
		||||
    pub fn write_byte(&mut self, byte: u8) {
 | 
			
		||||
        self.write_byte_color(byte, ColorCode::new(Color::White, Color::Black));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write_byte_color(&mut self, byte: u8, color: ColorCode) {
 | 
			
		||||
        match byte {
 | 
			
		||||
            b'\n' => self.new_line(),
 | 
			
		||||
            byte => {
 | 
			
		||||
                if self.col >= BUFFER_WIDTH {
 | 
			
		||||
                    self.new_line();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let row = self.row;
 | 
			
		||||
                let col = self.col;
 | 
			
		||||
 | 
			
		||||
                let color_code = color;
 | 
			
		||||
                self.buffer.chars[row][col] = ScreenChar {
 | 
			
		||||
                    ascii_character: byte,
 | 
			
		||||
                    color_code,
 | 
			
		||||
                };
 | 
			
		||||
                self.col += 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write_string(&mut self, s: &str) {
 | 
			
		||||
        self.write_string_color(s, ColorCode::new(Color::White, Color::Black));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write_string_color(&mut self, s: &str, color: ColorCode) {
 | 
			
		||||
        for char in s.bytes() {
 | 
			
		||||
            match char {
 | 
			
		||||
                0x20..=0x7e | b'\n' => self.write_byte_color(char, color), // Ascii Character
 | 
			
		||||
                _ => self.write_byte(0xfe), // Non ascii
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new_line(&mut self) {
 | 
			
		||||
        self.row += 1;
 | 
			
		||||
        self.col = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Write for Writer {
 | 
			
		||||
    fn write_str(&mut self, s: &str) -> fmt::Result {
 | 
			
		||||
        self.write_string(s);
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The problem now becomes that I can create a `Writer` but I don't have a global position, so it will just overwrite what I wrote last time. To solve this I can use a static variable. But a static variable won't be mutable. This can be solved with `Mutex` in the spin crate and `lazy_static`.
 | 
			
		||||
 | 
			
		||||
`kernel/std/Cargo.toml`
 | 
			
		||||
```toml
 | 
			
		||||
[package]
 | 
			
		||||
name = "std"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
 | 
			
		||||
spin = "0.9.8"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
and to make a static variable I wrote (copied from [here](https://os.phil-opp.com/vga-text-mode/)) this
 | 
			
		||||
```rust
 | 
			
		||||
lazy_static! {
 | 
			
		||||
    pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer {
 | 
			
		||||
        col: 0,
 | 
			
		||||
        row: 0,
 | 
			
		||||
        buffer: unsafe { &mut *(0xB8000 as *mut Buffer) },
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
in `kernel/std/src/vga_buffer.rs`.
 | 
			
		||||
 | 
			
		||||
Last step is just to add a function and 2 macros
 | 
			
		||||
```rust
 | 
			
		||||
#[doc(hidden)]
 | 
			
		||||
pub fn _print(args: fmt::Arguments) {
 | 
			
		||||
    WRITER.lock().write_fmt(args).unwrap()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! print {
 | 
			
		||||
    ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! println {
 | 
			
		||||
    () => ($crate::print!("\n"));
 | 
			
		||||
    ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Huge thanks to @phil-opp for [os.phil-opp.com](https://os.phil-opp.com/)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in a new issue