diff options
| -rw-r--r-- | .cargo/config.toml | 9 | ||||
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Cargo.toml | 17 | ||||
| -rw-r--r-- | src/.kernel.rs.swp | bin | 0 -> 12288 bytes | |||
| -rw-r--r-- | src/.sync.rs.swp | bin | 0 -> 12288 bytes | |||
| -rw-r--r-- | src/kernel.rs | 34 | ||||
| -rw-r--r-- | src/sync.rs | 62 | ||||
| -rw-r--r-- | src/vga/.buffer.rs.swp | bin | 0 -> 20480 bytes | |||
| -rw-r--r-- | src/vga/.mod.rs.swp | bin | 0 -> 12288 bytes | |||
| -rw-r--r-- | src/vga/buffer.rs | 157 | ||||
| -rw-r--r-- | src/vga/mod.rs | 33 | ||||
| -rw-r--r-- | x86_64-petrichor.json | 15 |
12 files changed, 329 insertions, 0 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..bd1221a --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,9 @@ +[unstable] +build-std-features = ["compiler-builtins-mem"] +build-std = ["core", "compiler_builtins"] + +[build] +target = "x86_64-petrichor.json" + +[target.'cfg(target_os = "none")'] +runner = "bootimage runner" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0e5f36a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "petrichor" +version = "0.1.0" +edition = "2021" +authors = [ "Christian Cunningham <c@localhost>" ] + +[[bin]] +name = "petrichor" +path = "src/kernel.rs" + +[dependencies] +bootloader = "0.9.8" +volatile = "0.2.6" + +[package.metadata.bootimage] +#run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}", "-serial", "mon:stdio"] +run-args = ["-serial", "mon:stdio"] diff --git a/src/.kernel.rs.swp b/src/.kernel.rs.swp Binary files differnew file mode 100644 index 0000000..ed00d5b --- /dev/null +++ b/src/.kernel.rs.swp diff --git a/src/.sync.rs.swp b/src/.sync.rs.swp Binary files differnew file mode 100644 index 0000000..462e2ef --- /dev/null +++ b/src/.sync.rs.swp diff --git a/src/kernel.rs b/src/kernel.rs new file mode 100644 index 0000000..8218691 --- /dev/null +++ b/src/kernel.rs @@ -0,0 +1,34 @@ +//! # Kernel +//! +//! Kernel Start + +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points +#![feature(const_mut_refs)] + +mod sync; +mod vga; +use vga::*; +use core::panic::PanicInfo; + +/// This function is called on panic. +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +fn kernel_init() { + WRITER.init(); +} + +#[no_mangle] +pub extern "C" fn _start() -> ! { + kernel_init(); + + WRITER.write_string("Hello World!"); + WRITER.write_string("\n\nHi\n"); + println!("{}", 5); + //print_something(); + + loop {} +} diff --git a/src/sync.rs b/src/sync.rs new file mode 100644 index 0000000..cd626fa --- /dev/null +++ b/src/sync.rs @@ -0,0 +1,62 @@ +//! # Synchronization module +//! +//! Provides synchronization objects for thread-safe memory sharing. +use core::cell::UnsafeCell; + +/// # Synchronization interfaces +/// +/// Provides Synchronization traits. +pub mod interface { + /// # Mutex Trait + /// + /// Basic Locking primitive to allow single-process access to data + pub trait Mutex { + /// # The data + /// + /// Each mutex protects some internal data from modification across + /// processes when it is in use. This is important if the process + /// is preempted while the function is using it. + type Data; + /// # Locking mechanism + /// + /// Locks the mutex to access the data in a closure. + /// The data can be read and modified in this closure without worry + /// of poisoning the data across processes. + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; + } +} + +/// # Basic Lock Structure +pub struct NullLock<T> where T: ?Sized { + /// The internal data to safely share + data: UnsafeCell<T>, +} + +/// # Allow thread sharing +unsafe impl<T> Send for NullLock<T> where T: ?Sized + Send {} +/// # Allow thread sharing +unsafe impl<T> Sync for NullLock<T> where T: ?Sized + Send {} + +impl<T> NullLock<T> { + /// # Create a new instance of the lock + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +impl<T> interface::Mutex for NullLock<T> { + /// # Underlying data of the lock + type Data = T; + + /// # Locking mechanism + /// + /// Locks the Mutex, and passes a mutable reference + /// to the encapsulated data to a closure. + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut T) -> R) -> R { + let data = unsafe { &mut *self.data.get() }; + + f(data) + } +} diff --git a/src/vga/.buffer.rs.swp b/src/vga/.buffer.rs.swp Binary files differnew file mode 100644 index 0000000..0ce0feb --- /dev/null +++ b/src/vga/.buffer.rs.swp diff --git a/src/vga/.mod.rs.swp b/src/vga/.mod.rs.swp Binary files differnew file mode 100644 index 0000000..6071785 --- /dev/null +++ b/src/vga/.mod.rs.swp diff --git a/src/vga/buffer.rs b/src/vga/buffer.rs new file mode 100644 index 0000000..34c665d --- /dev/null +++ b/src/vga/buffer.rs @@ -0,0 +1,157 @@ +use super::*; +use core::fmt; +use volatile::Volatile; +use crate::sync::NullLock; +use crate::sync::interface::Mutex; + +#[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: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +pub struct VgaWriter { + column_position: usize, + color_code: ColorCode, + buffer: Option<&'static mut Buffer>, +} + +impl VgaWriter { + pub fn write_byte(&mut self, byte: u8) { + match byte { + b'\n' => self.new_line(), + byte => { + if self.column_position >= BUFFER_WIDTH { + self.new_line(); + } + + let row = BUFFER_HEIGHT - 1; + let col = self.column_position; + + let color_code = self.color_code; + if let Some(buffer) = &mut self.buffer { + buffer.chars[row][col].write(ScreenChar { +ascii_character: byte, +color_code, +}); + } + self.column_position += 1; + } + } + } + + fn new_line(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + if let Some(buffer) = &mut self.buffer { + let character = buffer.chars[row][col].read(); + buffer.chars[row - 1][col].write(character); + } + } + } + self.clear_row(BUFFER_HEIGHT - 1); + self.column_position = 0; + } + + fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + ascii_character: b' ', + color_code: self.color_code, + }; + for col in 0..BUFFER_WIDTH { + if let Some(buffer) = &mut self.buffer { + buffer.chars[row][col].write(blank); + } + } + } + + pub fn write_string(&mut self, s: &str) { + for byte in s.bytes() { + match byte { + // printable ASCII byte or newline + 0x20..=0x7e | b'\n' => self.write_byte(byte), + // not part of printable ASCII range + _ => self.write_byte(0xfe), + } + + } + } +} + +impl NullLock<VgaWriter> { + #[allow(dead_code)] + pub fn write_byte(&self, byte: u8) { + self.lock(|writer| { + writer.write_byte(byte); + }); + } + + #[allow(dead_code)] + fn new_line(&self) { + self.lock(|writer| { + writer.new_line(); + }); + } + + #[allow(dead_code)] + fn clear_row(&self, row: usize) { + self.lock(|writer| { + writer.clear_row(row); + }); + } + + pub fn write_string(&self, s: &str) { + self.lock(|writer| { + writer.write_string(s); + }); + } +} + +impl fmt::Write for VgaWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_string(s); + Ok(()) + } +} + +impl NullLock<VgaWriter> { + pub fn init(&self) { + self.lock(|writer| { + writer.buffer = Some(unsafe { &mut *(0xb8000 as *mut Buffer) }); + }) + } +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + WRITER.lock(|writer| { + writer.write_fmt(args).unwrap(); + }); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::vga::_print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => (print!("\n")); + ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); +} + +pub static WRITER: NullLock<VgaWriter> = NullLock::new(VgaWriter { + column_position: 0, + color_code: ColorCode::new(Color::Yellow, Color::Black), + buffer: None, +}); diff --git a/src/vga/mod.rs b/src/vga/mod.rs new file mode 100644 index 0000000..13dffe0 --- /dev/null +++ b/src/vga/mod.rs @@ -0,0 +1,33 @@ +mod buffer; +pub use buffer::*; + +#[allow(dead_code)] +#[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)] +struct ColorCode(u8); + +impl ColorCode { + const fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 4 | (foreground as u8)) + } +} diff --git a/x86_64-petrichor.json b/x86_64-petrichor.json new file mode 100644 index 0000000..1972d9b --- /dev/null +++ b/x86_64-petrichor.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" +} |
