From ecf8cf9fa5ef68284ee652d7b0f43880301b35a0 Mon Sep 17 00:00:00 2001 From: charlesbvll Date: Fri, 23 Jul 2021 20:29:13 +0200 Subject: [PATCH] refactoring --- src/allocator.rs | 41 +++++++++++------------- src/gdt.rs | 7 ++--- src/interrupts.rs | 67 ++++++++++++++++++---------------------- src/lib.rs | 67 ++++++++++++++++++++-------------------- src/memory.rs | 53 ++++++++++++++----------------- src/serial.rs | 4 +-- src/task/executor.rs | 34 ++++++++++---------- src/task/keyboard.rs | 51 ++++++++++++++++-------------- src/task/mod.rs | 13 +++++--- src/vga_buffer.rs | 34 ++++++++++---------- tests/basic_boot.rs | 3 +- tests/heap_allocation.rs | 13 ++++---- tests/stack_overflow.rs | 24 +++++++------- 13 files changed, 196 insertions(+), 215 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index a898a76..e2f1307 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,12 +1,23 @@ use alloc::alloc::{GlobalAlloc, Layout}; use core::ptr::null_mut; +use fixed_size_block::FixedSizeBlockAllocator; use x86_64::{ structures::paging::{ mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, }, VirtAddr, }; -use linked_list_allocator::LockedHeap; + +pub mod bump; +pub mod linked_list; +pub mod fixed_size_block; + +pub const HEAP_START: usize = 0x_4444_4444_0000; +pub const HEAP_SIZE: usize = 100 * 1024; + +#[global_allocator] +static ALLOCATOR: Locked = Locked::new( + FixedSizeBlockAllocator::new()); pub fn init_heap( mapper: &mut impl Mapper, @@ -36,23 +47,7 @@ pub fn init_heap( Ok(()) } - -pub mod bump; -use bump::BumpAllocator; - -pub mod linked_list; -use linked_list::LinkedListAllocator; - -pub mod fixed_size_block; -use fixed_size_block::FixedSizeBlockAllocator; - -#[global_allocator] -static ALLOCATOR: Locked = Locked::new( - FixedSizeBlockAllocator::new()); - pub struct Dummy; -pub const HEAP_START: usize = 0x_4444_4444_0000; -pub const HEAP_SIZE: usize = 100 * 1024; unsafe impl GlobalAlloc for Dummy { unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { @@ -64,11 +59,6 @@ unsafe impl GlobalAlloc for Dummy { } } -/// Align the given address `addr` upwards to alignment `align`. -fn align_up(addr: usize, align: usize) -> usize { - (addr + align - 1) & !(align - 1) -} - pub struct Locked { inner: spin::Mutex, } @@ -79,8 +69,13 @@ impl Locked { inner: spin::Mutex::new(inner), } } - + pub fn lock(&self) -> spin::MutexGuard { self.inner.lock() } +} + +/// Align the given address `addr` upwards to alignment `align`. +fn align_up(addr: usize, align: usize) -> usize { + (addr + align - 1) & !(align - 1) } \ No newline at end of file diff --git a/src/gdt.rs b/src/gdt.rs index 138c5b1..c93ece4 100644 --- a/src/gdt.rs +++ b/src/gdt.rs @@ -1,8 +1,7 @@ -use x86_64::VirtAddr; -use x86_64::structures::tss::TaskStateSegment; -use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor}; -use x86_64::structures::gdt::SegmentSelector; use lazy_static::lazy_static; +use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor, SegmentSelector}; +use x86_64::structures::tss::TaskStateSegment; +use x86_64::VirtAddr; pub const DOUBLE_FAULT_IST_INDEX: u16 = 0; diff --git a/src/interrupts.rs b/src/interrupts.rs index 9094ce1..fa99d26 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,35 +1,53 @@ -use x86_64::structures::idt::{PageFaultErrorCode, InterruptDescriptorTable, InterruptStackFrame}; -use pic8259::ChainedPics; - +use crate::{gdt, hlt_loop, print, println}; use lazy_static::lazy_static; - -use crate::println; -use crate::print; -use crate::gdt; -use crate::hlt_loop; - +use pic8259::ChainedPics; use spin; +use x86_64::structures::idt::{PageFaultErrorCode, InterruptDescriptorTable, InterruptStackFrame}; pub const PIC_1_OFFSET: u8 = 32; pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum InterruptIndex { + Timer = PIC_1_OFFSET, + Keyboard, +} + +impl InterruptIndex { + fn as_u8(self) -> u8 { + self as u8 + } + + fn as_usize(self) -> usize { + usize::from(self.as_u8()) + } +} + +pub static PICS: spin::Mutex = +spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); + lazy_static! { static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); unsafe { idt.double_fault.set_handler_fn(double_fault_handler) - .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); + .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); } idt[InterruptIndex::Timer.as_usize()] - .set_handler_fn(timer_interrupt_handler); + .set_handler_fn(timer_interrupt_handler); idt[InterruptIndex::Keyboard.as_usize()] - .set_handler_fn(keyboard_interrupt_handler); + .set_handler_fn(keyboard_interrupt_handler); idt.page_fault.set_handler_fn(page_fault_handler); idt }; } +pub fn init_idt() { + IDT.load(); +} + extern "x86-interrupt" fn page_fault_handler( stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode, @@ -80,31 +98,6 @@ extern "x86-interrupt" fn keyboard_interrupt_handler( } } - -pub fn init_idt() { - IDT.load(); -} - -pub static PICS: spin::Mutex = - spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); - -#[derive(Debug, Clone, Copy)] -#[repr(u8)] -pub enum InterruptIndex { - Timer = PIC_1_OFFSET, - Keyboard, -} - -impl InterruptIndex { - fn as_u8(self) -> u8 { - self as u8 - } - - fn as_usize(self) -> usize { - usize::from(self.as_u8()) - } -} - #[test_case] fn test_breakpoint_exception() { x86_64::instructions::interrupts::int3(); diff --git a/src/lib.rs b/src/lib.rs index 4658250..b031b86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,11 @@ #![feature(custom_test_frameworks)] #![feature(alloc_error_handler)] #![test_runner(crate::test_runner)] -#![reexport_test_harness_main = "test_main"] #![feature(abi_x86_interrupt)] #![feature(const_mut_refs)] +#![reexport_test_harness_main = "test_main"] +extern crate alloc; use core::panic::PanicInfo; pub mod serial; @@ -17,13 +18,12 @@ pub mod memory; pub mod allocator; pub mod task; -extern crate alloc; - -#[cfg(test)] -use bootloader::{entry_point, BootInfo}; - -#[cfg(test)] -entry_point!(test_kernel_main); +pub fn init() { + gdt::init(); + interrupts::init_idt(); + unsafe { interrupts::PICS.lock().initialize() }; + x86_64::instructions::interrupts::enable(); +} pub trait Testable { fn run(&self) -> (); @@ -31,7 +31,7 @@ pub trait Testable { impl Testable for T where - T: Fn(), +T: Fn(), { fn run(&self) { serial_print!("{}...\t", core::any::type_name::()); @@ -55,31 +55,6 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! { hlt_loop(); } -pub fn init() { - gdt::init(); - interrupts::init_idt(); - unsafe { interrupts::PICS.lock().initialize() }; - x86_64::instructions::interrupts::enable(); -} - -#[cfg(test)] -fn test_kernel_main(_boot_info: &'static BootInfo) -> ! { - init(); - test_main(); - hlt_loop(); -} - -#[cfg(test)] -#[panic_handler] -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 { @@ -100,4 +75,28 @@ pub fn hlt_loop() -> ! { loop { x86_64::instructions::hlt(); } +} + +#[cfg(test)] +use bootloader::{entry_point, BootInfo}; + +#[cfg(test)] +entry_point!(test_kernel_main); + +#[cfg(test)] +fn test_kernel_main(_boot_info: &'static BootInfo) -> ! { + init(); + test_main(); + hlt_loop(); +} + +#[cfg(test)] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + test_panic_handler(info) +} + +#[alloc_error_handler] +fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { + panic!("allocation error: {:?}", layout) } \ No newline at end of file diff --git a/src/memory.rs b/src/memory.rs index 40bc01e..3a17359 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,13 +1,28 @@ +use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; use x86_64::{ - structures::paging::{OffsetPageTable, - Page, PhysFrame, - Mapper, Size4KiB, - PageTable, FrameAllocator}, - PhysAddr, - VirtAddr + structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB}, + PhysAddr, VirtAddr, }; -use bootloader::bootinfo::MemoryMap; -use bootloader::bootinfo::MemoryRegionType; + +pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { + let level_4_table = active_level_4_table(physical_memory_offset); + OffsetPageTable::new(level_4_table, physical_memory_offset) +} + +/// Returns a mutable reference to the active level 4 table. +unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) + -> &'static mut PageTable +{ + use x86_64::registers::control::Cr3; + + let (level_4_table_frame, _) = Cr3::read(); + + let phys = level_4_table_frame.start_address(); + let virt = physical_memory_offset + phys.as_u64(); + let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); + + &mut *page_table_ptr // unsafe +} /// A FrameAllocator that returns usable frames from the bootloader's memory map. pub struct BootInfoFrameAllocator { @@ -27,7 +42,7 @@ impl BootInfoFrameAllocator { next: 0, } } - + fn usable_frames(&self) -> impl Iterator { // get usable regions from memory map let regions = self.memory_map.iter(); @@ -49,24 +64,4 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { self.next += 1; frame } -} - -pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { - let level_4_table = active_level_4_table(physical_memory_offset); - OffsetPageTable::new(level_4_table, physical_memory_offset) -} - -/// Returns a mutable reference to the active level 4 table. -unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) - -> &'static mut PageTable -{ - use x86_64::registers::control::Cr3; - - let (level_4_table_frame, _) = Cr3::read(); - - let phys = level_4_table_frame.start_address(); - let virt = physical_memory_offset + phys.as_u64(); - let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); - - &mut *page_table_ptr // unsafe } \ No newline at end of file diff --git a/src/serial.rs b/src/serial.rs index ed16aae..0062910 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -1,6 +1,6 @@ -use uart_16550::SerialPort; -use spin::Mutex; use lazy_static::lazy_static; +use spin::Mutex; +use uart_16550::SerialPort; lazy_static! { pub static ref SERIAL1: Mutex = { diff --git a/src/task/executor.rs b/src/task/executor.rs index 8396794..df4b9f6 100644 --- a/src/task/executor.rs +++ b/src/task/executor.rs @@ -1,9 +1,7 @@ use super::{Task, TaskId}; -use alloc::{collections::BTreeMap, sync::Arc}; -use core::task::Waker; +use alloc::{collections::BTreeMap, sync::Arc, task::Wake}; +use core::task::{Context, Poll, Waker}; use crossbeam_queue::ArrayQueue; -use core::task::{Context, Poll}; -use alloc::task::Wake; pub struct Executor { tasks: BTreeMap, @@ -11,11 +9,6 @@ pub struct Executor { waker_cache: BTreeMap, } -struct TaskWaker { - task_id: TaskId, - task_queue: Arc>, -} - impl Executor { pub fn new() -> Self { Executor { @@ -24,7 +17,7 @@ impl Executor { waker_cache: BTreeMap::new(), } } - + pub fn spawn(&mut self, task: Task) { let task_id = task.id; if self.tasks.insert(task.id, task).is_some() { @@ -32,7 +25,7 @@ impl Executor { } self.task_queue.push(task_id).expect("queue full"); } - + fn run_ready_tasks(&mut self) { // destructure `self` to avoid borrow checker errors let Self { @@ -40,15 +33,15 @@ impl Executor { task_queue, waker_cache, } = self; - + while let Ok(task_id) = task_queue.pop() { let task = match tasks.get_mut(&task_id) { Some(task) => task, None => continue, // task no longer exists }; let waker = waker_cache - .entry(task_id) - .or_insert_with(|| TaskWaker::new(task_id, task_queue.clone())); + .entry(task_id) + .or_insert_with(|| TaskWaker::new(task_id, task_queue.clone())); let mut context = Context::from_waker(waker); match task.poll(&mut context) { Poll::Ready(()) => { @@ -60,17 +53,17 @@ impl Executor { } } } - + pub fn run(&mut self) -> ! { loop { self.run_ready_tasks(); self.sleep_if_idle(); } } - + fn sleep_if_idle(&self) { use x86_64::instructions::interrupts::{self, enable_and_hlt}; - + interrupts::disable(); if self.task_queue.is_empty() { enable_and_hlt(); @@ -80,11 +73,16 @@ impl Executor { } } +struct TaskWaker { + task_id: TaskId, + task_queue: Arc>, +} + impl TaskWaker { fn wake_task(&self) { self.task_queue.push(self.task_id).expect("task_queue full"); } - + fn new(task_id: TaskId, task_queue: Arc>) -> Waker { Waker::from(Arc::new(TaskWaker { task_id, diff --git a/src/task/keyboard.rs b/src/task/keyboard.rs index 2219125..8d91d52 100644 --- a/src/task/keyboard.rs +++ b/src/task/keyboard.rs @@ -1,32 +1,18 @@ +use crate::{print, println}; use conquer_once::spin::OnceCell; +use core::{ + pin::Pin, + task::{Context, Poll}, +}; use crossbeam_queue::ArrayQueue; -use crate::println; -use core::{pin::Pin, task::{Poll, Context}}; -use futures_util::stream::Stream; -use futures_util::task::AtomicWaker; -use futures_util::stream::StreamExt; +use futures_util::{ + stream::{Stream, StreamExt}, + task::AtomicWaker, +}; use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; -use crate::print; -static WAKER: AtomicWaker = AtomicWaker::new(); static SCANCODE_QUEUE: OnceCell> = OnceCell::uninit(); - -pub async fn print_keypresses() { - let mut scancodes = ScancodeStream::new(); - let mut keyboard = Keyboard::new(layouts::Us104Key, ScancodeSet1, - HandleControl::Ignore); - - while let Some(scancode) = scancodes.next().await { - if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { - if let Some(key) = keyboard.process_keyevent(key_event) { - match key { - DecodedKey::Unicode(character) => print!("{}", character), - DecodedKey::RawKey(key) => print!("{:?}", key), - } - } - } - } -} +static WAKER: AtomicWaker = AtomicWaker::new(); pub(crate) fn add_scancode(scancode: u8) { if let Ok(queue) = SCANCODE_QUEUE.try_get() { @@ -74,4 +60,21 @@ impl Stream for ScancodeStream { Err(crossbeam_queue::PopError) => Poll::Pending, } } +} + +pub async fn print_keypresses() { + let mut scancodes = ScancodeStream::new(); + let mut keyboard = Keyboard::new(layouts::Us104Key, ScancodeSet1, + HandleControl::Ignore); + + while let Some(scancode) = scancodes.next().await { + if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { + if let Some(key) = keyboard.process_keyevent(key_event) { + match key { + DecodedKey::Unicode(character) => print!("{}", character), + DecodedKey::RawKey(key) => print!("{:?}", key), + } + } + } + } } \ No newline at end of file diff --git a/src/task/mod.rs b/src/task/mod.rs index 09658eb..2d21c6f 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -1,11 +1,14 @@ -use core::{future::Future, pin::Pin}; use alloc::boxed::Box; -use core::task::{Context, Poll}; -use core::sync::atomic::{AtomicU64, Ordering}; +use core::{ + future::Future, + pin::Pin, + sync::atomic::{AtomicU64, Ordering}, + task::{Context, Poll}, +}; -pub mod simple_executor; -pub mod keyboard; pub mod executor; +pub mod keyboard; +pub mod simple_executor; pub struct Task { id: TaskId, diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index 61b3a25..48bc238 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -1,5 +1,16 @@ +use core::fmt; +use lazy_static::lazy_static; +use spin::Mutex; use volatile::Volatile; +lazy_static! { + pub static ref WRITER: Mutex = Mutex::new(Writer { + column_position: 0, + color_code: ColorCode::new(Color::Yellow, Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, + }); +} + const BUFFER_HEIGHT: usize = 25; const BUFFER_WIDTH: usize = 80; @@ -29,6 +40,12 @@ pub enum Color { #[repr(transparent)] struct ColorCode(u8); +impl ColorCode { + 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 { @@ -47,11 +64,6 @@ pub struct Writer { buffer: &'static mut Buffer, } -impl ColorCode { - fn new(foreground: Color, background: Color) -> ColorCode { - ColorCode((background as u8) << 4 | (foreground as u8)) - } - } impl Writer { pub fn write_byte(&mut self, byte: u8) { @@ -109,18 +121,6 @@ impl Writer { } } -use spin::Mutex; -use lazy_static::lazy_static; -lazy_static! { - pub static ref WRITER: Mutex = Mutex::new(Writer { - column_position: 0, - color_code: ColorCode::new(Color::Yellow, Color::Black), - buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, - }); -} - -use core::fmt; - impl fmt::Write for Writer { fn write_str(&mut self, s: &str) -> fmt::Result { self.write_string(s); diff --git a/tests/basic_boot.rs b/tests/basic_boot.rs index 17eba8f..6d62f9f 100644 --- a/tests/basic_boot.rs +++ b/tests/basic_boot.rs @@ -4,6 +4,7 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(rust_os::test_runner)] +use rust_os::println; use core::panic::PanicInfo; #[no_mangle] @@ -18,8 +19,6 @@ fn panic(info: &PanicInfo) -> ! { rust_os::test_panic_handler(info) } -use rust_os::println; - #[test_case] fn test_println() { println!("test_println output"); diff --git a/tests/heap_allocation.rs b/tests/heap_allocation.rs index 9af1ed2..1867fbd 100644 --- a/tests/heap_allocation.rs +++ b/tests/heap_allocation.rs @@ -6,10 +6,9 @@ extern crate alloc; +use alloc::{boxed::Box, vec::Vec}; use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; -use alloc::boxed::Box; -use alloc::vec::Vec; use rust_os::allocator::HEAP_SIZE; entry_point!(main); @@ -32,11 +31,6 @@ fn main(boot_info: &'static BootInfo) -> ! { loop {} } -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - rust_os::test_panic_handler(info) -} - #[test_case] fn simple_allocation() { let heap_value_1 = Box::new(41); @@ -71,4 +65,9 @@ fn many_boxes_long_lived() { assert_eq!(*x, i); } assert_eq!(*long_lived, 1); +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + rust_os::test_panic_handler(info) } \ No newline at end of file diff --git a/tests/stack_overflow.rs b/tests/stack_overflow.rs index 8a23aec..64e1a49 100644 --- a/tests/stack_overflow.rs +++ b/tests/stack_overflow.rs @@ -3,11 +3,9 @@ #![feature(abi_x86_interrupt)] use core::panic::PanicInfo; -use rust_os::serial_print; use lazy_static::lazy_static; -use x86_64::structures::idt::InterruptDescriptorTable; -use rust_os::{exit_qemu, QemuExitCode, serial_println}; -use x86_64::structures::idt::InterruptStackFrame; +use rust_os::{exit_qemu, QemuExitCode, serial_print, serial_println}; +use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; #[no_mangle] pub extern "C" fn _start() -> ! { @@ -28,20 +26,15 @@ fn stack_overflow() { volatile::Volatile::new(0).read(); // prevent tail recursion optimizations } -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - rust_os::test_panic_handler(info) -} - lazy_static! { static ref TEST_IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); unsafe { idt.double_fault - .set_handler_fn(test_double_fault_handler) - .set_stack_index(rust_os::gdt::DOUBLE_FAULT_IST_INDEX); + .set_handler_fn(test_double_fault_handler) + .set_stack_index(rust_os::gdt::DOUBLE_FAULT_IST_INDEX); } - + idt }; } @@ -57,4 +50,9 @@ extern "x86-interrupt" fn test_double_fault_handler( serial_println!("[ok]"); exit_qemu(QemuExitCode::Success); loop {} -} \ No newline at end of file +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + rust_os::test_panic_handler(info) +}