2024-03-27
This commit is contained in:
		
							parent
							
								
									8e6d2783f4
								
							
						
					
					
						commit
						b377ef3ef3
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -1,4 +1,5 @@ | ||||||
| /kernel/target | target | ||||||
|  | /kernel/Cargo.lock | ||||||
| /build | /build | ||||||
| /binutils | /binutils | ||||||
| /gcc | /gcc | ||||||
|  |  | ||||||
|  | @ -3,4 +3,8 @@ name = "kernel" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| edition = "2021" | edition = "2021" | ||||||
| 
 | 
 | ||||||
|  | [workspace] | ||||||
|  | members = ["std"] | ||||||
|  | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
|  | std = { path = "std" } | ||||||
|  |  | ||||||
|  | @ -1,19 +1,13 @@ | ||||||
| #![no_std] | #![no_std] | ||||||
| #![no_main] | #![no_main] | ||||||
| 
 | 
 | ||||||
|  | use std::println; | ||||||
|  | 
 | ||||||
| #[no_mangle] | #[no_mangle] | ||||||
| pub extern "C" fn kernel_main() -> ! { | pub extern "C" fn kernel_main() -> ! { | ||||||
|     let vga_buffer = 0xb8000 as *mut u8; |     let a = 4; | ||||||
| 
 |     println!("Hiii :3"); | ||||||
|     let string: &[u8] = b":3"; |     println!("{}", a); | ||||||
|     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; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     loop {} |     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 | version = 3 | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "kernel" | name = "std" | ||||||
| version = "0.1.0" | 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)*))); | ||||||
|  | } | ||||||
							
								
								
									
										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