diff --git a/.cargo/config.toml b/.cargo/config.toml index 9d8d08c..1c6c25e 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,6 @@ [unstable] build-std-features = ["compiler-builtins-mem"] -build-std = ["core", "compiler_builtins"] +build-std = ["core", "compiler_builtins", "alloc"] [build] target = "x86_64-rust_os.json" diff --git a/Cargo.lock b/Cargo.lock index 7e9d4c0..b6697ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,6 +29,30 @@ dependencies = [ "spin", ] +[[package]] +name = "linked_list_allocator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0b725207570aa16096962d0b20c79f8a543df2280bd3c903022b9b0b4d7ea68" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "pc-keyboard" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6f2d937e3b8d63449b01401e2bae4041bc9dd1129c2e3e0d239407cf6635ac" + [[package]] name = "pic8259" version = "0.10.1" @@ -44,6 +68,8 @@ version = "0.1.0" dependencies = [ "bootloader", "lazy_static", + "linked_list_allocator", + "pc-keyboard", "pic8259", "spin", "uart_16550", @@ -51,12 +77,27 @@ dependencies = [ "x86_64", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spinning_top" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" +dependencies = [ + "lock_api", +] + [[package]] name = "uart_16550" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index a6da8d8..b2ed612 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,13 +4,14 @@ version = "0.1.0" edition = "2018" [dependencies] -bootloader = "0.9.8" +bootloader = { version = "0.9.8", features = ["map_physical_memory"]} volatile = "0.2.6" spin = "0.5.2" x86_64 = "0.14.2" uart_16550 = "0.2.0" pic8259 = "0.10.1" pc-keyboard = "0.5.0" +linked_list_allocator = "0.9.0" [dependencies.lazy_static] version = "1.0" diff --git a/src/interrupts.rs b/src/interrupts.rs index d7b33ae..ae33856 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,9 +1,17 @@ -use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; -use crate::println; -use crate::print; +use x86_64::structures::idt::{PageFaultErrorCode, InterruptDescriptorTable, InterruptStackFrame}; +use pic8259::ChainedPics; use lazy_static::lazy_static; + +use crate::println; +use crate::print; use crate::gdt; +use crate::hlt_loop; + +use spin; + +pub const PIC_1_OFFSET: u8 = 32; +pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; lazy_static! { static ref IDT: InterruptDescriptorTable = { @@ -17,9 +25,23 @@ lazy_static! { .set_handler_fn(timer_interrupt_handler); idt[InterruptIndex::Keyboard.as_usize()] .set_handler_fn(keyboard_interrupt_handler); + idt.page_fault.set_handler_fn(page_fault_handler); idt }; } + +extern "x86-interrupt" fn page_fault_handler( + stack_frame: InterruptStackFrame, + error_code: PageFaultErrorCode, +) { + use x86_64::registers::control::Cr2; + + println!("EXCEPTION: PAGE FAULT"); + println!("Accessed Address: {:?}", Cr2::read()); + println!("Error Code: {:?}", error_code); + println!("{:#?}", stack_frame); + hlt_loop(); +} extern "x86-interrupt" fn double_fault_handler( stack_frame: InterruptStackFrame, _error_code: u64) -> ! @@ -37,6 +59,12 @@ extern "x86-interrupt" fn timer_interrupt_handler( } } +extern "x86-interrupt" fn breakpoint_handler( + stack_frame: InterruptStackFrame) +{ + println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); +} + extern "x86-interrupt" fn keyboard_interrupt_handler( _stack_frame: InterruptStackFrame) { @@ -75,23 +103,6 @@ pub fn init_idt() { IDT.load(); } -#[test_case] -fn test_breakpoint_exception() { - x86_64::instructions::interrupts::int3(); -} - -extern "x86-interrupt" fn breakpoint_handler( - stack_frame: InterruptStackFrame) -{ - println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); -} - -use pic8259::ChainedPics; -use spin; - -pub const PIC_1_OFFSET: u8 = 32; -pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; - pub static PICS: spin::Mutex = spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); @@ -110,4 +121,9 @@ impl InterruptIndex { fn as_usize(self) -> usize { usize::from(self.as_u8()) } +} + +#[test_case] +fn test_breakpoint_exception() { + x86_64::instructions::interrupts::int3(); } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 30bc9e3..37756e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![cfg_attr(test, no_main)] #![feature(custom_test_frameworks)] +#![feature(alloc_error_handler)] #![test_runner(crate::test_runner)] #![reexport_test_harness_main = "test_main"] #![feature(abi_x86_interrupt)] @@ -11,6 +12,16 @@ pub mod serial; pub mod vga_buffer; pub mod interrupts; pub mod gdt; +pub mod memory; +pub mod allocator; + +extern crate alloc; + +#[cfg(test)] +use bootloader::{entry_point, BootInfo}; + +#[cfg(test)] +entry_point!(test_kernel_main); pub trait Testable { fn run(&self) -> (); @@ -50,9 +61,8 @@ pub fn init() { } #[cfg(test)] -#[no_mangle] -pub extern "C" fn _start() -> ! { - init(); // new +fn test_kernel_main(_boot_info: &'static BootInfo) -> ! { + init(); test_main(); hlt_loop(); } @@ -63,6 +73,11 @@ fn panic(info: &PanicInfo) -> ! { test_panic_handler(info) } +#[alloc_error_handler] +fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { + panic!("allocation error: {:?}", layout) +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum QemuExitCode { diff --git a/src/main.rs b/src/main.rs index 3caf346..f873e59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,50 @@ #![test_runner(rust_os::test_runner)] #![reexport_test_harness_main = "test_main"] +extern crate alloc; + +use alloc::{boxed::Box, vec, vec::Vec, rc::Rc}; use core::panic::PanicInfo; use rust_os::println; +use bootloader::{BootInfo, entry_point}; +use x86_64::VirtAddr; + +entry_point!(kernel_main); + +fn kernel_main(boot_info: &'static BootInfo) -> ! { + use rust_os::allocator; + use rust_os::memory::{self, BootInfoFrameAllocator}; -#[no_mangle] -pub extern "C" fn _start() -> ! { println!("Hello World{}", "!"); - rust_os::init(); - // as before + let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); + let mut mapper = unsafe { memory::init(phys_mem_offset) }; + let mut frame_allocator = unsafe { + BootInfoFrameAllocator::init(&boot_info.memory_map) + }; + + allocator::init_heap(&mut mapper, &mut frame_allocator) + .expect("heap initialization failed"); + + // allocate a number on the heap + let heap_value = Box::new(41); + println!("heap_value at {:p}", heap_value); + + // create a dynamically sized vector + let mut vec = Vec::new(); + for i in 0..500 { + vec.push(i); + } + println!("vec at {:p}", vec.as_slice()); + + // create a reference counted vector -> will be freed when count reaches 0 + let reference_counted = Rc::new(vec![1, 2, 3]); + let cloned_reference = reference_counted.clone(); + println!("current reference count is {}", Rc::strong_count(&cloned_reference)); + core::mem::drop(reference_counted); + println!("reference count is {} now", Rc::strong_count(&cloned_reference)); + #[cfg(test)] test_main(); @@ -21,7 +55,6 @@ pub extern "C" fn _start() -> ! { rust_os::hlt_loop(); } -/// This function is called on panic. #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! {