refactoring
This commit is contained in:
parent
d609af0b6e
commit
ecf8cf9fa5
@ -1,12 +1,23 @@
|
|||||||
use alloc::alloc::{GlobalAlloc, Layout};
|
use alloc::alloc::{GlobalAlloc, Layout};
|
||||||
use core::ptr::null_mut;
|
use core::ptr::null_mut;
|
||||||
|
use fixed_size_block::FixedSizeBlockAllocator;
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
structures::paging::{
|
structures::paging::{
|
||||||
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
||||||
},
|
},
|
||||||
VirtAddr,
|
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(
|
pub fn init_heap(
|
||||||
mapper: &mut impl Mapper<Size4KiB>,
|
mapper: &mut impl Mapper<Size4KiB>,
|
||||||
@ -36,23 +47,7 @@ pub fn init_heap(
|
|||||||
Ok(())
|
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 struct Dummy;
|
||||||
pub const HEAP_START: usize = 0x_4444_4444_0000;
|
|
||||||
pub const HEAP_SIZE: usize = 100 * 1024;
|
|
||||||
|
|
||||||
unsafe impl GlobalAlloc for Dummy {
|
unsafe impl GlobalAlloc for Dummy {
|
||||||
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
|
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> {
|
pub struct Locked<A> {
|
||||||
inner: spin::Mutex<A>,
|
inner: spin::Mutex<A>,
|
||||||
}
|
}
|
||||||
@ -79,8 +69,13 @@ impl<A> Locked<A> {
|
|||||||
inner: spin::Mutex::new(inner),
|
inner: spin::Mutex::new(inner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lock(&self) -> spin::MutexGuard<A> {
|
pub fn lock(&self) -> spin::MutexGuard<A> {
|
||||||
self.inner.lock()
|
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)
|
||||||
}
|
}
|
||||||
@ -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 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;
|
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
|
||||||
|
|
||||||
|
|||||||
@ -1,35 +1,53 @@
|
|||||||
use x86_64::structures::idt::{PageFaultErrorCode, InterruptDescriptorTable, InterruptStackFrame};
|
use crate::{gdt, hlt_loop, print, println};
|
||||||
use pic8259::ChainedPics;
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use pic8259::ChainedPics;
|
||||||
use crate::println;
|
|
||||||
use crate::print;
|
|
||||||
use crate::gdt;
|
|
||||||
use crate::hlt_loop;
|
|
||||||
|
|
||||||
use spin;
|
use spin;
|
||||||
|
use x86_64::structures::idt::{PageFaultErrorCode, InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
pub const PIC_1_OFFSET: u8 = 32;
|
pub const PIC_1_OFFSET: u8 = 32;
|
||||||
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
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! {
|
lazy_static! {
|
||||||
static ref IDT: InterruptDescriptorTable = {
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||||
unsafe {
|
unsafe {
|
||||||
idt.double_fault.set_handler_fn(double_fault_handler)
|
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()]
|
idt[InterruptIndex::Timer.as_usize()]
|
||||||
.set_handler_fn(timer_interrupt_handler);
|
.set_handler_fn(timer_interrupt_handler);
|
||||||
idt[InterruptIndex::Keyboard.as_usize()]
|
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.page_fault.set_handler_fn(page_fault_handler);
|
||||||
idt
|
idt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_idt() {
|
||||||
|
IDT.load();
|
||||||
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn page_fault_handler(
|
extern "x86-interrupt" fn page_fault_handler(
|
||||||
stack_frame: InterruptStackFrame,
|
stack_frame: InterruptStackFrame,
|
||||||
error_code: PageFaultErrorCode,
|
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]
|
#[test_case]
|
||||||
fn test_breakpoint_exception() {
|
fn test_breakpoint_exception() {
|
||||||
x86_64::instructions::interrupts::int3();
|
x86_64::instructions::interrupts::int3();
|
||||||
|
|||||||
67
src/lib.rs
67
src/lib.rs
@ -3,10 +3,11 @@
|
|||||||
#![feature(custom_test_frameworks)]
|
#![feature(custom_test_frameworks)]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![test_runner(crate::test_runner)]
|
#![test_runner(crate::test_runner)]
|
||||||
#![reexport_test_harness_main = "test_main"]
|
|
||||||
#![feature(abi_x86_interrupt)]
|
#![feature(abi_x86_interrupt)]
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
@ -17,13 +18,12 @@ pub mod memory;
|
|||||||
pub mod allocator;
|
pub mod allocator;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
|
|
||||||
extern crate alloc;
|
pub fn init() {
|
||||||
|
gdt::init();
|
||||||
#[cfg(test)]
|
interrupts::init_idt();
|
||||||
use bootloader::{entry_point, BootInfo};
|
unsafe { interrupts::PICS.lock().initialize() };
|
||||||
|
x86_64::instructions::interrupts::enable();
|
||||||
#[cfg(test)]
|
}
|
||||||
entry_point!(test_kernel_main);
|
|
||||||
|
|
||||||
pub trait Testable {
|
pub trait Testable {
|
||||||
fn run(&self) -> ();
|
fn run(&self) -> ();
|
||||||
@ -31,7 +31,7 @@ pub trait Testable {
|
|||||||
|
|
||||||
impl<T> Testable for T
|
impl<T> Testable for T
|
||||||
where
|
where
|
||||||
T: Fn(),
|
T: Fn(),
|
||||||
{
|
{
|
||||||
fn run(&self) {
|
fn run(&self) {
|
||||||
serial_print!("{}...\t", core::any::type_name::<T>());
|
serial_print!("{}...\t", core::any::type_name::<T>());
|
||||||
@ -55,31 +55,6 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! {
|
|||||||
hlt_loop();
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
pub enum QemuExitCode {
|
pub enum QemuExitCode {
|
||||||
@ -100,4 +75,28 @@ pub fn hlt_loop() -> ! {
|
|||||||
loop {
|
loop {
|
||||||
x86_64::instructions::hlt();
|
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)
|
||||||
}
|
}
|
||||||
@ -1,13 +1,28 @@
|
|||||||
|
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
structures::paging::{OffsetPageTable,
|
structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
|
||||||
Page, PhysFrame,
|
PhysAddr, VirtAddr,
|
||||||
Mapper, Size4KiB,
|
|
||||||
PageTable, FrameAllocator},
|
|
||||||
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.
|
/// A FrameAllocator that returns usable frames from the bootloader's memory map.
|
||||||
pub struct BootInfoFrameAllocator {
|
pub struct BootInfoFrameAllocator {
|
||||||
@ -27,7 +42,7 @@ impl BootInfoFrameAllocator {
|
|||||||
next: 0,
|
next: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
|
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
|
||||||
// get usable regions from memory map
|
// get usable regions from memory map
|
||||||
let regions = self.memory_map.iter();
|
let regions = self.memory_map.iter();
|
||||||
@ -49,24 +64,4 @@ unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
|
|||||||
self.next += 1;
|
self.next += 1;
|
||||||
frame
|
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
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use uart_16550::SerialPort;
|
|
||||||
use spin::Mutex;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
|
use uart_16550::SerialPort;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref SERIAL1: Mutex<SerialPort> = {
|
pub static ref SERIAL1: Mutex<SerialPort> = {
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
use super::{Task, TaskId};
|
use super::{Task, TaskId};
|
||||||
use alloc::{collections::BTreeMap, sync::Arc};
|
use alloc::{collections::BTreeMap, sync::Arc, task::Wake};
|
||||||
use core::task::Waker;
|
use core::task::{Context, Poll, Waker};
|
||||||
use crossbeam_queue::ArrayQueue;
|
use crossbeam_queue::ArrayQueue;
|
||||||
use core::task::{Context, Poll};
|
|
||||||
use alloc::task::Wake;
|
|
||||||
|
|
||||||
pub struct Executor {
|
pub struct Executor {
|
||||||
tasks: BTreeMap<TaskId, Task>,
|
tasks: BTreeMap<TaskId, Task>,
|
||||||
@ -11,11 +9,6 @@ pub struct Executor {
|
|||||||
waker_cache: BTreeMap<TaskId, Waker>,
|
waker_cache: BTreeMap<TaskId, Waker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TaskWaker {
|
|
||||||
task_id: TaskId,
|
|
||||||
task_queue: Arc<ArrayQueue<TaskId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Executor {
|
impl Executor {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Executor {
|
Executor {
|
||||||
@ -24,7 +17,7 @@ impl Executor {
|
|||||||
waker_cache: BTreeMap::new(),
|
waker_cache: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn(&mut self, task: Task) {
|
pub fn spawn(&mut self, task: Task) {
|
||||||
let task_id = task.id;
|
let task_id = task.id;
|
||||||
if self.tasks.insert(task.id, task).is_some() {
|
if self.tasks.insert(task.id, task).is_some() {
|
||||||
@ -32,7 +25,7 @@ impl Executor {
|
|||||||
}
|
}
|
||||||
self.task_queue.push(task_id).expect("queue full");
|
self.task_queue.push(task_id).expect("queue full");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ready_tasks(&mut self) {
|
fn run_ready_tasks(&mut self) {
|
||||||
// destructure `self` to avoid borrow checker errors
|
// destructure `self` to avoid borrow checker errors
|
||||||
let Self {
|
let Self {
|
||||||
@ -40,15 +33,15 @@ impl Executor {
|
|||||||
task_queue,
|
task_queue,
|
||||||
waker_cache,
|
waker_cache,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
while let Ok(task_id) = task_queue.pop() {
|
while let Ok(task_id) = task_queue.pop() {
|
||||||
let task = match tasks.get_mut(&task_id) {
|
let task = match tasks.get_mut(&task_id) {
|
||||||
Some(task) => task,
|
Some(task) => task,
|
||||||
None => continue, // task no longer exists
|
None => continue, // task no longer exists
|
||||||
};
|
};
|
||||||
let waker = waker_cache
|
let waker = waker_cache
|
||||||
.entry(task_id)
|
.entry(task_id)
|
||||||
.or_insert_with(|| TaskWaker::new(task_id, task_queue.clone()));
|
.or_insert_with(|| TaskWaker::new(task_id, task_queue.clone()));
|
||||||
let mut context = Context::from_waker(waker);
|
let mut context = Context::from_waker(waker);
|
||||||
match task.poll(&mut context) {
|
match task.poll(&mut context) {
|
||||||
Poll::Ready(()) => {
|
Poll::Ready(()) => {
|
||||||
@ -60,17 +53,17 @@ impl Executor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> ! {
|
pub fn run(&mut self) -> ! {
|
||||||
loop {
|
loop {
|
||||||
self.run_ready_tasks();
|
self.run_ready_tasks();
|
||||||
self.sleep_if_idle();
|
self.sleep_if_idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sleep_if_idle(&self) {
|
fn sleep_if_idle(&self) {
|
||||||
use x86_64::instructions::interrupts::{self, enable_and_hlt};
|
use x86_64::instructions::interrupts::{self, enable_and_hlt};
|
||||||
|
|
||||||
interrupts::disable();
|
interrupts::disable();
|
||||||
if self.task_queue.is_empty() {
|
if self.task_queue.is_empty() {
|
||||||
enable_and_hlt();
|
enable_and_hlt();
|
||||||
@ -80,11 +73,16 @@ impl Executor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TaskWaker {
|
||||||
|
task_id: TaskId,
|
||||||
|
task_queue: Arc<ArrayQueue<TaskId>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl TaskWaker {
|
impl TaskWaker {
|
||||||
fn wake_task(&self) {
|
fn wake_task(&self) {
|
||||||
self.task_queue.push(self.task_id).expect("task_queue full");
|
self.task_queue.push(self.task_id).expect("task_queue full");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>) -> Waker {
|
fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>) -> Waker {
|
||||||
Waker::from(Arc::new(TaskWaker {
|
Waker::from(Arc::new(TaskWaker {
|
||||||
task_id,
|
task_id,
|
||||||
|
|||||||
@ -1,32 +1,18 @@
|
|||||||
|
use crate::{print, println};
|
||||||
use conquer_once::spin::OnceCell;
|
use conquer_once::spin::OnceCell;
|
||||||
|
use core::{
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
use crossbeam_queue::ArrayQueue;
|
use crossbeam_queue::ArrayQueue;
|
||||||
use crate::println;
|
use futures_util::{
|
||||||
use core::{pin::Pin, task::{Poll, Context}};
|
stream::{Stream, StreamExt},
|
||||||
use futures_util::stream::Stream;
|
task::AtomicWaker,
|
||||||
use futures_util::task::AtomicWaker;
|
};
|
||||||
use futures_util::stream::StreamExt;
|
|
||||||
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||||
use crate::print;
|
|
||||||
|
|
||||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
|
||||||
static SCANCODE_QUEUE: OnceCell<ArrayQueue<u8>> = OnceCell::uninit();
|
static SCANCODE_QUEUE: OnceCell<ArrayQueue<u8>> = OnceCell::uninit();
|
||||||
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn add_scancode(scancode: u8) {
|
pub(crate) fn add_scancode(scancode: u8) {
|
||||||
if let Ok(queue) = SCANCODE_QUEUE.try_get() {
|
if let Ok(queue) = SCANCODE_QUEUE.try_get() {
|
||||||
@ -74,4 +60,21 @@ impl Stream for ScancodeStream {
|
|||||||
Err(crossbeam_queue::PopError) => Poll::Pending,
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +1,14 @@
|
|||||||
use core::{future::Future, pin::Pin};
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use core::task::{Context, Poll};
|
use core::{
|
||||||
use core::sync::atomic::{AtomicU64, Ordering};
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
sync::atomic::{AtomicU64, Ordering},
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod simple_executor;
|
|
||||||
pub mod keyboard;
|
|
||||||
pub mod executor;
|
pub mod executor;
|
||||||
|
pub mod keyboard;
|
||||||
|
pub mod simple_executor;
|
||||||
|
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
id: TaskId,
|
id: TaskId,
|
||||||
|
|||||||
@ -1,5 +1,16 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
use volatile::Volatile;
|
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_HEIGHT: usize = 25;
|
||||||
const BUFFER_WIDTH: usize = 80;
|
const BUFFER_WIDTH: usize = 80;
|
||||||
|
|
||||||
@ -29,6 +40,12 @@ pub enum Color {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct ColorCode(u8);
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct ScreenChar {
|
struct ScreenChar {
|
||||||
@ -47,11 +64,6 @@ pub struct Writer {
|
|||||||
buffer: &'static mut Buffer,
|
buffer: &'static mut Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColorCode {
|
|
||||||
fn new(foreground: Color, background: Color) -> ColorCode {
|
|
||||||
ColorCode((background as u8) << 4 | (foreground as u8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Writer {
|
impl Writer {
|
||||||
pub fn write_byte(&mut self, byte: u8) {
|
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 {
|
impl fmt::Write for Writer {
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
self.write_string(s);
|
self.write_string(s);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#![reexport_test_harness_main = "test_main"]
|
#![reexport_test_harness_main = "test_main"]
|
||||||
#![test_runner(rust_os::test_runner)]
|
#![test_runner(rust_os::test_runner)]
|
||||||
|
|
||||||
|
use rust_os::println;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -18,8 +19,6 @@ fn panic(info: &PanicInfo) -> ! {
|
|||||||
rust_os::test_panic_handler(info)
|
rust_os::test_panic_handler(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
use rust_os::println;
|
|
||||||
|
|
||||||
#[test_case]
|
#[test_case]
|
||||||
fn test_println() {
|
fn test_println() {
|
||||||
println!("test_println output");
|
println!("test_println output");
|
||||||
|
|||||||
@ -6,10 +6,9 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
use bootloader::{entry_point, BootInfo};
|
use bootloader::{entry_point, BootInfo};
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use alloc::boxed::Box;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use rust_os::allocator::HEAP_SIZE;
|
use rust_os::allocator::HEAP_SIZE;
|
||||||
|
|
||||||
entry_point!(main);
|
entry_point!(main);
|
||||||
@ -32,11 +31,6 @@ fn main(boot_info: &'static BootInfo) -> ! {
|
|||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
|
||||||
rust_os::test_panic_handler(info)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test_case]
|
#[test_case]
|
||||||
fn simple_allocation() {
|
fn simple_allocation() {
|
||||||
let heap_value_1 = Box::new(41);
|
let heap_value_1 = Box::new(41);
|
||||||
@ -71,4 +65,9 @@ fn many_boxes_long_lived() {
|
|||||||
assert_eq!(*x, i);
|
assert_eq!(*x, i);
|
||||||
}
|
}
|
||||||
assert_eq!(*long_lived, 1);
|
assert_eq!(*long_lived, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
rust_os::test_panic_handler(info)
|
||||||
}
|
}
|
||||||
@ -3,11 +3,9 @@
|
|||||||
#![feature(abi_x86_interrupt)]
|
#![feature(abi_x86_interrupt)]
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use rust_os::serial_print;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use x86_64::structures::idt::InterruptDescriptorTable;
|
use rust_os::{exit_qemu, QemuExitCode, serial_print, serial_println};
|
||||||
use rust_os::{exit_qemu, QemuExitCode, serial_println};
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
use x86_64::structures::idt::InterruptStackFrame;
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn _start() -> ! {
|
pub extern "C" fn _start() -> ! {
|
||||||
@ -28,20 +26,15 @@ fn stack_overflow() {
|
|||||||
volatile::Volatile::new(0).read(); // prevent tail recursion optimizations
|
volatile::Volatile::new(0).read(); // prevent tail recursion optimizations
|
||||||
}
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
|
||||||
rust_os::test_panic_handler(info)
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref TEST_IDT: InterruptDescriptorTable = {
|
static ref TEST_IDT: InterruptDescriptorTable = {
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
idt.double_fault
|
idt.double_fault
|
||||||
.set_handler_fn(test_double_fault_handler)
|
.set_handler_fn(test_double_fault_handler)
|
||||||
.set_stack_index(rust_os::gdt::DOUBLE_FAULT_IST_INDEX);
|
.set_stack_index(rust_os::gdt::DOUBLE_FAULT_IST_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
idt
|
idt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -57,4 +50,9 @@ extern "x86-interrupt" fn test_double_fault_handler(
|
|||||||
serial_println!("[ok]");
|
serial_println!("[ok]");
|
||||||
exit_qemu(QemuExitCode::Success);
|
exit_qemu(QemuExitCode::Success);
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
rust_os::test_panic_handler(info)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user