diff --git a/Cargo.lock b/Cargo.lock index 8894932..5ca9fb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,11 +13,28 @@ name = "kernel" version = "0.1.0" dependencies = [ "bootloader", + "lazy_static", + "spin", "volatile", ] [[package]] -name = "volatile" -version = "0.4.5" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "volatile" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b06ad3ed06fef1713569d547cdbdb439eafed76341820fb0e0344f29a41945" diff --git a/Cargo.toml b/Cargo.toml index 8587d9e..ed53599 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,17 @@ edition = "2018" [profile.dev] panic = "abort" +overflow-checks = false [profile.release] panic = "abort" + +[dependencies.lazy_static] +version = "1.0" +features = ["spin_no_std"] + [dependencies] bootloader = "0.9.23" -volatile = "0.4.5" \ No newline at end of file +volatile = "0.2.6" +spin = "0.5.2" \ No newline at end of file diff --git a/run.sh b/run.sh index c61c593..4830650 100755 --- a/run.sh +++ b/run.sh @@ -1,5 +1,5 @@ #!/bin/sh -cargo +nightly build +cargo +nightly build || exit 1 cargo +nightly bootimage qemu-system-x86_64 -drive format=raw,file=target/x86_64-none-generic/debug/bootimage-kernel.bin \ No newline at end of file diff --git a/src/interrupts.rs b/src/interrupts.rs new file mode 100644 index 0000000..4bc62d2 --- /dev/null +++ b/src/interrupts.rs @@ -0,0 +1,91 @@ +// IDT - Interrupt Descriptor Table + +use core::arch::asm; +use core::mem::size_of; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IdtEntry { + pub offset_low: u16, + pub selector: u16, + pub flags: u8, + pub offset_middle: u16, + pub offset_high: u32, + pub zero: u32, +} + +pub struct InterruptStackFrame { + pub instruction_pointer: u64, + pub code_segment: u64, + pub cpu_flags: u64, + pub stack_pointer: u64, + pub stack_segment: u64, +} + +pub type HandlerFunc = extern "C" fn(&mut InterruptStackFrame); + +pub struct Idt { + pub entries: [IdtEntry; 256], +} + +#[allow(dead_code)] +impl Idt { + pub fn new() -> Idt { + Idt { + entries: [IdtEntry { + offset_low: 0, + selector: 0, + flags: 0, + offset_middle: 0, + offset_high: 0, + zero: 0, + }; 256], + } + } + + pub fn set_handler(&mut self, index: u8, handler: HandlerFunc) { + let offset = handler as u64; + let offset_low = offset as u16; + let offset_middle = (offset >> 16) as u16; + let offset_high = (offset >> 32) as u32; + + self.entries[index as usize] = IdtEntry { + offset_low, + selector: 0x08, + flags: 0x8e, + offset_middle, + offset_high, + zero: 0, + }; + } + + pub fn load(&self) { + let mut idtr: [u16; 3] = [0; 3]; + idtr[0] = (size_of::() - 1) as u16; + idtr[1] = self as *const _ as u16; + idtr[2] = (self as *const _ as u32 >> 16) as u16; + unsafe { + asm!( + "lidt ({0})", + in(reg) &idtr, + ); + } + } + + pub fn load_idt() -> Idt { + let mut idt = Idt::new(); + idt.load(); + idt + } + + pub fn enable_interrupts() { + unsafe { + asm!("sti"); + } + } + + pub fn disable_interrupts() { + unsafe { + asm!("cli"); + } + } +} diff --git a/src/io/mod.rs b/src/io/mod.rs index 5826a79..593a90a 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -1 +1,3 @@ -pub mod vga; +use core::arch::asm; + +pub mod vga; \ No newline at end of file diff --git a/src/io/vga/buffer.rs b/src/io/vga/buffer.rs index 2554d52..82b83e2 100644 --- a/src/io/vga/buffer.rs +++ b/src/io/vga/buffer.rs @@ -1,3 +1,5 @@ +use core::fmt; +use volatile::Volatile; use crate::io::vga::colors::ColorCode; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -12,13 +14,13 @@ const BUFFER_WIDTH: usize = 80; #[repr(transparent)] pub struct Buffer { - chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], + chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], } pub struct Writer { - pub(crate) column_position: usize, - pub(crate) color_code: ColorCode, - pub(crate) buffer: &'static mut Buffer, + pub column_position: usize, + pub color_code: ColorCode, + pub buffer: &'static mut Buffer, } impl Writer { @@ -34,22 +36,36 @@ impl Writer { let col = self.column_position; let color_code = self.color_code; - self.buffer.chars[row][col] = ScreenChar { + self.buffer.chars[row][col].write(ScreenChar { ascii_character: byte, color_code, - }; + }); self.column_position += 1; } } } - fn new_line(&mut self) { - unimplemented!(); + pub fn new_line(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + let character = self.buffer.chars[row][col].read(); + self.buffer.chars[row - 1][col].write(character); + } + } + self.clear_row(BUFFER_HEIGHT - 1); + self.column_position = 0; } -} + pub fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + ascii_character: b' ', + color_code: self.color_code, + }; + for col in 0..BUFFER_WIDTH { + self.buffer.chars[row][col].write(blank); + } + } -impl Writer { pub fn write_string(&mut self, s: &str) { for byte in s.bytes() { match byte { @@ -58,7 +74,14 @@ impl Writer { // not part of printable ASCII range _ => self.write_byte(0xfe), } - } } +} + + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_string(s); + Ok(()) + } } \ No newline at end of file diff --git a/src/io/vga/mod.rs b/src/io/vga/mod.rs index 144d4b5..0a1750b 100644 --- a/src/io/vga/mod.rs +++ b/src/io/vga/mod.rs @@ -1,2 +1,31 @@ pub mod colors; -pub mod buffer; \ No newline at end of file +pub mod buffer; + +use core::fmt; +use lazy_static::lazy_static; +use spin::Mutex; + +lazy_static! { + pub static ref WRITER: Mutex = Mutex::new(buffer::Writer { + column_position: 0, + color_code: colors::ColorCode::new(colors::Color::Yellow, colors::Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut buffer::Buffer) }, + }); +} + +#[macro_export] +macro_rules! println { + () => (print!("\n")); + ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::io::vga::_print(format_args!($($arg)*))); +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + WRITER.lock().write_fmt(args).unwrap(); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5abb595..3328f05 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,31 @@ #![no_std] #![no_main] +use core::arch::asm; use core::panic::PanicInfo; -use crate::io::vga::buffer::{Buffer, Writer}; +use bootloader::{BootInfo, entry_point}; use crate::io::vga::colors::{Color, ColorCode}; mod io; +mod mem; +mod interrupts; + +entry_point!(kernel_main); +fn kernel_main(boot_info: &'static BootInfo) -> ! { + mem::gdt::init(); + let mut idt = interrupts::Idt::new(); + fn test_interrupt_handler(_stack_frame: &mut interrupts::InterruptStackFrame) { + println!("test interrupt handler"); + } -#[no_mangle] -#[panic_handler] -pub extern "C" fn panic_handler(_info: &PanicInfo) -> ! { loop {} } #[no_mangle] -pub extern "C" fn _start() -> ! { - let mut writer = Writer { - column_position: 0, - color_code: ColorCode::new(Color::Yellow, Color::Black), - buffer: unsafe { &mut *(0xb8000 as *mut Buffer) } - }; - - writer.write_string("Hello World\n"); - +#[panic_handler] +pub extern "C" fn panic_handler(_info: &PanicInfo) -> ! { + io::vga::WRITER.lock().color_code = ColorCode::new(Color::Red, Color::Black); + println!("\n!!! PANIC !!!"); + println!("{}", _info); loop {} -} \ No newline at end of file +} diff --git a/src/mem/gdt.rs b/src/mem/gdt.rs new file mode 100644 index 0000000..95d7d78 --- /dev/null +++ b/src/mem/gdt.rs @@ -0,0 +1,98 @@ +use core::arch::asm; + +pub const GDT_NULL: u64 = 0x0000000000000000; // Null descriptor +pub const GDT_KERNEL_CODE: u64 = 0x00af9a000000ffff; // Kernel code descriptor +pub const GDT_KERNEL_DATA: u64 = 0x00cf92000000ffff; // Kernel data descriptor +pub const GDT_USER_CODE: u64 = 0x00afba000000ffff; // User code descriptor +pub const GDT_USER_DATA: u64 = 0x00cfb2000000ffff; // User data descriptor +pub const GDT_TSS: u64 = 0x0080890000000067; // TSS descriptor + +pub struct GdtEntry { + pub limit_low: u16, + pub base_low: u16, + pub base_middle: u8, + pub access: u8, + pub granularity: u8, + pub base_high: u8, +} + +pub struct Gdt { + pub entries: [GdtEntry; 6], +} + +#[allow(dead_code)] +impl Gdt { + pub fn new() -> Gdt { + Gdt { + entries: [ + GdtEntry { + limit_low: 0, + base_low: 0, + base_middle: 0, + access: 0, + granularity: 0, + base_high: 0, + }, + GdtEntry { + limit_low: 0, + base_low: 0, + base_middle: 0, + access: 0x9a, + granularity: 0xa0, + base_high: 0, + }, + GdtEntry { + limit_low: 0, + base_low: 0, + base_middle: 0, + access: 0x92, + granularity: 0xc0, + base_high: 0, + }, + GdtEntry { + limit_low: 0, + base_low: 0, + base_middle: 0, + access: 0xfa, + granularity: 0xa0, + base_high: 0, + }, + GdtEntry { + limit_low: 0, + base_low: 0, + base_middle: 0, + access: 0xf2, + granularity: 0xc0, + base_high: 0, + }, + GdtEntry { + limit_low: 0, + base_low: 0, + base_middle: 0, + access: 0x89, + granularity: 0x67, + base_high: 0, + }, + ], + } + } + + pub fn load(&self) { + let mut gdtr: [u16; 3] = [0; 3]; + gdtr[0] = (core::mem::size_of::() - 1) as u16; + gdtr[1] = self as *const _ as u16; + gdtr[2] = (self as *const _ as u32 >> 16) as u16; + unsafe { + asm!( + "lgdt ({0})", + in(reg) gdtr.as_ptr(), + options(nostack) + ); + } + } +} + +pub fn init() { + let gdt = Gdt::new(); + gdt.load(); +} \ No newline at end of file diff --git a/src/mem/mod.rs b/src/mem/mod.rs new file mode 100644 index 0000000..eb2f23b --- /dev/null +++ b/src/mem/mod.rs @@ -0,0 +1 @@ +pub mod gdt; \ No newline at end of file