refactoring

This commit is contained in:
charlesbvll 2021-07-23 20:29:13 +02:00
parent d609af0b6e
commit ecf8cf9fa5
13 changed files with 196 additions and 215 deletions

View File

@ -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<FixedSizeBlockAllocator> = Locked::new(
FixedSizeBlockAllocator::new());
pub fn init_heap(
mapper: &mut impl Mapper<Size4KiB>,
@ -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<FixedSizeBlockAllocator> = 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<A> {
inner: spin::Mutex<A>,
}
@ -79,8 +69,13 @@ impl<A> Locked<A> {
inner: spin::Mutex::new(inner),
}
}
pub fn lock(&self) -> spin::MutexGuard<A> {
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)
}

View File

@ -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;

View File

@ -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<ChainedPics> =
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<ChainedPics> =
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();

View File

@ -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<T> Testable for T
where
T: Fn(),
T: Fn(),
{
fn run(&self) {
serial_print!("{}...\t", core::any::type_name::<T>());
@ -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)
}

View File

@ -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<Item = PhysFrame> {
// get usable regions from memory map
let regions = self.memory_map.iter();
@ -49,24 +64,4 @@ unsafe impl FrameAllocator<Size4KiB> 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
}

View File

@ -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<SerialPort> = {

View File

@ -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<TaskId, Task>,
@ -11,11 +9,6 @@ pub struct Executor {
waker_cache: BTreeMap<TaskId, Waker>,
}
struct TaskWaker {
task_id: TaskId,
task_queue: Arc<ArrayQueue<TaskId>>,
}
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<ArrayQueue<TaskId>>,
}
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<ArrayQueue<TaskId>>) -> Waker {
Waker::from(Arc::new(TaskWaker {
task_id,

View File

@ -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<ArrayQueue<u8>> = 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),
}
}
}
}
}

View File

@ -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,

View File

@ -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<Writer> = 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<Writer> = 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);

View File

@ -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");

View File

@ -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)
}

View File

@ -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 {}
}
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
rust_os::test_panic_handler(info)
}