summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel.rs38
-rw-r--r--src/qemu/mod.rs26
-rw-r--r--src/serial/buffer.rs36
-rw-r--r--src/sync.rs75
-rw-r--r--src/tests.rs34
-rw-r--r--src/vga/buffer.rs257
-rw-r--r--src/vga/mod.rs38
7 files changed, 253 insertions, 251 deletions
diff --git a/src/kernel.rs b/src/kernel.rs
index 42de2be..c040a4b 100644
--- a/src/kernel.rs
+++ b/src/kernel.rs
@@ -13,9 +13,9 @@ mod serial;
mod sync;
mod tests;
mod vga;
+use core::panic::PanicInfo;
use serial::*;
use vga::*;
-use core::panic::PanicInfo;
#[cfg(test)]
mod qemu;
@@ -28,42 +28,42 @@ use tests::*;
#[cfg(test)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
- serial_println!("[failed]\n");
- serial_println!("Error: {}\n", info);
- exit_qemu(QemuExitCode::Failed);
- loop {}
+ serial_println!("[failed]\n");
+ serial_println!("Error: {}\n", info);
+ exit_qemu(QemuExitCode::Failed);
+ loop {}
}
/// This function is called on panic.
#[cfg(not(test))]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
- println!("{}", info);
- loop {}
+ println!("{}", info);
+ loop {}
}
/// # Initialization
///
/// Provides serial and VGA initialization.
fn kernel_init() {
- WRITER.init();
- SERIAL1.init();
+ WRITER.init();
+ SERIAL1.init();
}
/// # x86_64 Kernel
#[no_mangle]
pub extern "C" fn _start() -> ! {
- kernel_init();
+ kernel_init();
- #[cfg(not(test))]
- {
- WRITER.write_string("Hello World!");
- WRITER.write_string("\n\nHi\n");
- println!("{}", 5);
- }
+ #[cfg(not(test))]
+ {
+ WRITER.write_string("Hello World!");
+ WRITER.write_string("\n\nHi\n");
+ println!("{}", 5);
+ }
- #[cfg(test)]
- test_main();
+ #[cfg(test)]
+ test_main();
- loop {}
+ loop {}
}
diff --git a/src/qemu/mod.rs b/src/qemu/mod.rs
index 4c1ab37..2a0e990 100644
--- a/src/qemu/mod.rs
+++ b/src/qemu/mod.rs
@@ -8,24 +8,24 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum QemuExitCode {
- /// # Success
- ///
- /// Exit QEMU successfully
- Success = 0x10,
- /// # Failure
- ///
- /// Exit QEMU with error
- Failed = 0x11,
+ /// # Success
+ ///
+ /// Exit QEMU successfully
+ Success = 0x10,
+ /// # Failure
+ ///
+ /// Exit QEMU with error
+ Failed = 0x11,
}
/// # Exit QEMU
///
/// Exit QEMU with an exit code
pub fn exit_qemu(exit_code: QemuExitCode) {
- use x86_64::instructions::port::Port;
+ use x86_64::instructions::port::Port;
- unsafe {
- let mut port = Port::new(0xf4);
- port.write(exit_code as u32);
- }
+ unsafe {
+ let mut port = Port::new(0xf4);
+ port.write(exit_code as u32);
+ }
}
diff --git a/src/serial/buffer.rs b/src/serial/buffer.rs
index f40771f..b0f704e 100644
--- a/src/serial/buffer.rs
+++ b/src/serial/buffer.rs
@@ -1,35 +1,35 @@
-use crate::sync::NullLock;
use crate::sync::interface::Mutex;
+use crate::sync::NullLock;
use uart_16550::SerialPort;
pub struct Serial {
- buffer: Option<SerialPort>,
+ buffer: Option<SerialPort>,
}
impl Serial {
- pub const fn new() -> Self {
- Serial { buffer: None }
- }
+ pub const fn new() -> Self {
+ Serial { buffer: None }
+ }
}
impl NullLock<Serial> {
- pub fn init(&self) {
- self.lock(|serial| {
- let mut serial_port = unsafe { SerialPort::new(0x3F8) };
- serial_port.init();
- serial.buffer = Some(serial_port);
- });
- }
+ pub fn init(&self) {
+ self.lock(|serial| {
+ let mut serial_port = unsafe { SerialPort::new(0x3F8) };
+ serial_port.init();
+ serial.buffer = Some(serial_port);
+ });
+ }
}
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
- use core::fmt::Write;
- SERIAL1.lock(|serial| {
- if let Some(buffer) = &mut serial.buffer {
- buffer.write_fmt(args).expect("printing to serial failed!");
- }
- })
+ use core::fmt::Write;
+ SERIAL1.lock(|serial| {
+ if let Some(buffer) = &mut serial.buffer {
+ buffer.write_fmt(args).expect("printing to serial failed!");
+ }
+ })
}
/// Prints to the host through the serial interface.
diff --git a/src/sync.rs b/src/sync.rs
index cd626fa..5afa620 100644
--- a/src/sync.rs
+++ b/src/sync.rs
@@ -7,29 +7,32 @@ use core::cell::UnsafeCell;
///
/// 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;
- }
+ /// # 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>,
+pub struct NullLock<T>
+where
+ T: ?Sized,
+{
+ /// The internal data to safely share
+ data: UnsafeCell<T>,
}
/// # Allow thread sharing
@@ -38,25 +41,25 @@ unsafe impl<T> Send for NullLock<T> where T: ?Sized + Send {}
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),
- }
- }
+ /// # 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;
+ /// # 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() };
+ /// # 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)
- }
+ f(data)
+ }
}
diff --git a/src/tests.rs b/src/tests.rs
index 745672a..bcdbed1 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -1,4 +1,4 @@
-use crate::{serial_print,serial_println};
+use crate::{serial_print, serial_println};
#[cfg(test)]
use crate::qemu::*;
@@ -7,21 +7,21 @@ use crate::qemu::*;
///
/// Trait for test functions
pub trait Testable {
- fn run(&self) -> ();
+ fn run(&self) -> ();
}
impl<T> Testable for T
where
- T: Fn(),
+ T: Fn(),
{
- /// # Default run
- ///
- /// Run each test and print results to output
- fn run(&self) {
- serial_print!("{}...\t", core::any::type_name::<T>());
- self();
- serial_println!("[ok]");
- }
+ /// # Default run
+ ///
+ /// Run each test and print results to output
+ fn run(&self) {
+ serial_print!("{}...\t", core::any::type_name::<T>());
+ self();
+ serial_println!("[ok]");
+ }
}
/// # Run tests
@@ -29,11 +29,11 @@ where
/// Run each of the tests
#[cfg(test)]
pub fn test_runner(tests: &[&dyn Testable]) {
- serial_println!("Running {} tests", tests.len());
- for test in tests {
- test.run();
- }
- exit_qemu(QemuExitCode::Success);
+ serial_println!("Running {} tests", tests.len());
+ for test in tests {
+ test.run();
+ }
+ exit_qemu(QemuExitCode::Success);
}
/// # Trivial test
@@ -41,5 +41,5 @@ pub fn test_runner(tests: &[&dyn Testable]) {
/// This test ought to succeed no matter what
#[test_case]
fn trivial_assertion() {
- assert_eq!(1, 1);
+ assert_eq!(1, 1);
}
diff --git a/src/vga/buffer.rs b/src/vga/buffer.rs
index 4ca001c..1ae4ff8 100644
--- a/src/vga/buffer.rs
+++ b/src/vga/buffer.rs
@@ -1,14 +1,14 @@
use super::*;
+use crate::sync::interface::Mutex;
+use crate::sync::NullLock;
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,
+ ascii_character: u8,
+ color_code: ColorCode,
}
const BUFFER_HEIGHT: usize = 25;
@@ -16,128 +16,127 @@ const BUFFER_WIDTH: usize = 80;
#[repr(transparent)]
struct Buffer {
- chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
+ chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
pub struct VgaWriter {
- column_position: usize,
- color_code: ColorCode,
- buffer: Option<&'static mut Buffer>,
+ 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),
- }
-
- }
- }
+ 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);
- });
- }
-
- #[allow(dead_code)]
- pub fn write_string(&self, s: &str) {
- self.lock(|writer| {
- writer.write_string(s);
- });
- }
+ #[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);
+ });
+ }
+
+ #[allow(dead_code)]
+ 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(())
- }
+ 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) });
- })
- }
+ 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();
- });
+ use core::fmt::Write;
+ WRITER.lock(|writer| {
+ writer.write_fmt(args).unwrap();
+ });
}
#[macro_export]
@@ -152,38 +151,38 @@ macro_rules! println {
}
pub static WRITER: NullLock<VgaWriter> = NullLock::new(VgaWriter {
- column_position: 0,
- color_code: ColorCode::new(Color::LightBlue, Color::Black),
- buffer: None,
+ column_position: 0,
+ color_code: ColorCode::new(Color::LightBlue, Color::Black),
+ buffer: None,
});
#[test_case]
fn test_println_simple() {
- println!("test_println_simple output");
+ println!("test_println_simple output");
}
#[test_case]
fn test_println_many() {
- for _ in 0..200 {
- println!("test_println_many output");
- }
+ for _ in 0..200 {
+ println!("test_println_many output");
+ }
}
#[test_case]
fn test_println_output() {
- let s = "Some test string that fits on a single line";
- println!("{}", s);
- for (i, c) in s.chars().enumerate() {
- let screen_char = WRITER.lock(|writer| {
- if let Some(buffer) = &writer.buffer {
- return buffer.chars[BUFFER_HEIGHT - 2][i].read();
- } else {
- return ScreenChar {
- ascii_character: b' ',
- color_code: ColorCode::new(Color::LightBlue, Color::Black),
- };
- }
- });
- assert_eq!(char::from(screen_char.ascii_character), c);
- }
+ let s = "Some test string that fits on a single line";
+ println!("{}", s);
+ for (i, c) in s.chars().enumerate() {
+ let screen_char = WRITER.lock(|writer| {
+ if let Some(buffer) = &writer.buffer {
+ return buffer.chars[BUFFER_HEIGHT - 2][i].read();
+ } else {
+ return ScreenChar {
+ ascii_character: b' ',
+ color_code: ColorCode::new(Color::LightBlue, Color::Black),
+ };
+ }
+ });
+ assert_eq!(char::from(screen_char.ascii_character), c);
+ }
}
diff --git a/src/vga/mod.rs b/src/vga/mod.rs
index 13dffe0..02aefff 100644
--- a/src/vga/mod.rs
+++ b/src/vga/mod.rs
@@ -5,29 +5,29 @@ pub use buffer::*;
#[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,
+ 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))
- }
+ const fn new(foreground: Color, background: Color) -> ColorCode {
+ ColorCode((background as u8) << 4 | (foreground as u8))
+ }
}