From 8be1f2410e81cdefb3ad19d4052cb0a14d2062b4 Mon Sep 17 00:00:00 2001 From: Erin Date: Fri, 20 May 2022 17:11:32 +0200 Subject: [PATCH] Added simple task switcher (x86-64) --- ableos/src/arch/x86_64/init.rs | 21 +----- ableos/src/arch/x86_64/interrupts.rs | 26 ++++++- ableos/src/arch/x86_64/mod.rs | 2 + ableos/src/arch/x86_64/task_switcher.rs | 83 ++++++++++++++++++++++ ableos/src/kmain.rs | 7 -- ableos/src/scheduler.rs | 28 ++++++++ ableos/src/scheduler/capabilities.rs | 87 ----------------------- ableos/src/scheduler/mod.rs | 94 ------------------------- ableos/src/scheduler/priority.rs | 10 --- ableos/src/scheduler/proc.rs | 24 ------- 10 files changed, 138 insertions(+), 244 deletions(-) create mode 100644 ableos/src/arch/x86_64/task_switcher.rs create mode 100644 ableos/src/scheduler.rs delete mode 100644 ableos/src/scheduler/capabilities.rs delete mode 100644 ableos/src/scheduler/mod.rs delete mode 100644 ableos/src/scheduler/priority.rs delete mode 100644 ableos/src/scheduler/proc.rs diff --git a/ableos/src/arch/x86_64/init.rs b/ableos/src/arch/x86_64/init.rs index 18da0c2..d7275d7 100644 --- a/ableos/src/arch/x86_64/init.rs +++ b/ableos/src/arch/x86_64/init.rs @@ -1,17 +1,10 @@ // #![allow(clippy::print_literal)] use super::{gdt, interrupts}; -use crate::{ - logger, - scheduler::{capabilities::Capabilities, SCHEDULER}, - serial_println, -}; +use crate::{logger, serial_println}; /// x86_64 initialization pub fn init() { - use crate::{ - network::socket::SimpleSock, relib::network::socket::Socket, - scheduler::priority::Priority::High, stdio::StdIo, - }; + use crate::{network::socket::SimpleSock, relib::network::socket::Socket}; let mut log_socket_id = SimpleSock::new(); log_socket_id.register_protocol("Logger".to_string()); @@ -26,16 +19,6 @@ pub fn init() { gdt::init(); - let mut scheduler = SCHEDULER.lock(); - let process_0 = scheduler.new_process( - Capabilities::empty(), - High, - "".to_string(), - StdIo::new("null".to_string()), - ); - scheduler.add_process(process_0); - drop(scheduler); - interrupts::init_idt(); unsafe { interrupts::PICS.lock().initialize() }; x86_64::instructions::interrupts::enable(); diff --git a/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index ad601ec..dc2fea6 100644 --- a/ableos/src/arch/x86_64/interrupts.rs +++ b/ableos/src/arch/x86_64/interrupts.rs @@ -67,11 +67,31 @@ extern "x86-interrupt" fn double_fault_handler( ); } +#[naked] extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { - kernel::tick(); + use super::task_switcher; + unsafe { - PICS.lock() - .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); + asm!( + // Kernel tick + "push rax", + "call {tick}", + "pop rax", + + // Push task's state onto stack + // and save task pointer into scheduler + task_switcher::save_tasks_state!(), + "mov rdi, rsp", + "call {save}", + + // Switch to next task (interrupt'll be returned there) + "jmp {switch_to_next}", + + tick = sym kernel::tick, + save = sym task_switcher::save_and_enqueue, + switch_to_next = sym task_switcher::switch_to_next, + options(noreturn), + ); } } diff --git a/ableos/src/arch/x86_64/mod.rs b/ableos/src/arch/x86_64/mod.rs index 35e70c7..9ee80a9 100644 --- a/ableos/src/arch/x86_64/mod.rs +++ b/ableos/src/arch/x86_64/mod.rs @@ -4,6 +4,8 @@ pub mod init; pub mod interrupts; pub mod memory; +mod task_switcher; + use crate::arch::drivers::allocator; use bootloader::{entry_point, BootInfo}; use x86_64::{instructions::hlt, VirtAddr}; diff --git a/ableos/src/arch/x86_64/task_switcher.rs b/ableos/src/arch/x86_64/task_switcher.rs new file mode 100644 index 0000000..001ac39 --- /dev/null +++ b/ableos/src/arch/x86_64/task_switcher.rs @@ -0,0 +1,83 @@ +use crate::scheduler::{Task, SCHEDULER}; + +/// Saves task's state onto stack +macro_rules! save_tasks_state { + () => { + " + // Copy task's state + push [rsp + 32] // SS + push [rsp + 32] // RSP + push [rsp + 32] // RFLAGS + push [rsp + 32] // CS + push [rsp + 32] // RIP + + // Save task's registers + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + " + }; +} + +pub(super) use save_tasks_state; + +/// Save provided stack pointer into scheduler's queue +pub extern "C" fn save_and_enqueue(sp: u64) { + SCHEDULER.lock().enqueue_suspended(sp); +} + +// Fetch and load next task +pub unsafe extern "C" fn switch_to_next() -> ! { + // Fetch next task + let next = SCHEDULER.lock().pop().expect("no task in the task queue"); + match next { + Task::Suspended(sp) => asm!( + // Restore task's registers + "mov rsp, {}", + "pop rax", + "pop rbx", + "pop rcx", + "pop rdx", + "pop rsi", + "pop rdi", + "pop r8", + "pop r9", + "pop r10", + "pop r11", + "pop r12", + "pop r13", + "pop r14", + "pop r15", + + // Copy things up the stack + "add rsp, 80", // Move 8 bytes above exception stack frame + "push [rsp - 48]", // SS + "push [rsp - 48]", // RSP + "push [rsp - 48]", // RFLAGS + "push [rsp - 48]", // CS + "push [rsp - 48]", // RIP + + // Signalise end of the interrupt and return + "push rax", + "mov al, 32", + "out 20h, al", + "pop rax", + "iretq", + + in(reg) sp, + options(noreturn), + ), + Task::Spawn(_) => todo!("task spawning"), + } +} diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index f0f1fb2..d8e304d 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -1,7 +1,6 @@ #![allow(clippy::empty_loop)] use crate::arch::drivers::sysinfo::master; -use crate::scheduler::SCHEDULER; use crate::{ arch::{init, sloop}, relib::network::socket::{SimpleSock, Socket}, @@ -24,12 +23,6 @@ pub fn kernel_main() -> ! { } else { log::set_max_level(log::LevelFilter::Off); } - let scheduler = SCHEDULER.lock(); - for proc in &scheduler.execution_queue { - trace!("{:?}", proc); - } - - drop(scheduler); // start_facepalm(); scratchpad(); diff --git a/ableos/src/scheduler.rs b/ableos/src/scheduler.rs new file mode 100644 index 0000000..3b657de --- /dev/null +++ b/ableos/src/scheduler.rs @@ -0,0 +1,28 @@ +use alloc::collections::VecDeque; +use spin::{Lazy, Mutex}; + +pub static SCHEDULER: Lazy> = Lazy::new(|| Mutex::new(Scheduler::default())); + +pub enum Task { + Suspended(u64), + Spawn(fn()), +} + +#[derive(Default)] +pub struct Scheduler { + task_queue: VecDeque, +} + +impl Scheduler { + pub fn enqueue_spawn(&mut self, f: fn()) { + self.task_queue.push_back(Task::Spawn(f)); + } + + pub fn enqueue_suspended(&mut self, sp: u64) { + self.task_queue.push_back(Task::Suspended(sp)); + } + + pub fn pop(&mut self) -> Option { + self.task_queue.pop_front() + } +} diff --git a/ableos/src/scheduler/capabilities.rs b/ableos/src/scheduler/capabilities.rs deleted file mode 100644 index 2d0bf87..0000000 --- a/ableos/src/scheduler/capabilities.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![allow(missing_docs)] - -pub type SoundCardID = u8; -pub type DeviceID = u8; -pub type ControllerID = u8; - -#[derive(Clone, Debug, PartialEq)] -pub enum FileAccess { - All, - Some(Vec), - None, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum ControllerAccess { - All, - Some(Vec), - None, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum SoundCardAccess { - All, - Some(Vec), - None, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum MouseAccess { - Yes, - No, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum KeyboardAccess { - Yes, - No, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum NetworkAccess { - Yes, - No, -} - -/// A set of capabilities that a process has -#[derive(Clone, Debug, PartialEq)] -pub struct Capabilities { - // TODO: Add more capabilities - pub files: FileAccess, - pub mouse: MouseAccess, - pub keyboard: KeyboardAccess, - pub controllers: ControllerAccess, - pub sound_cards: SoundCardAccess, - pub network_access: NetworkAccess, -} - -impl Capabilities { - /// Generate a set of empty capabilities - pub fn empty() -> Self { - Self { - files: FileAccess::None, - mouse: MouseAccess::No, - keyboard: KeyboardAccess::No, - controllers: ControllerAccess::None, - sound_cards: SoundCardAccess::None, - network_access: NetworkAccess::No, - } - } - - /// Generate a set of capabilities that allows all access - /// to all devices - /// - /// # Safety - /// This is a very dangerous function and should not be used - /// unless you know what you are doing - pub unsafe fn all() -> Self { - Self { - files: FileAccess::All, - mouse: MouseAccess::Yes, - keyboard: KeyboardAccess::Yes, - controllers: ControllerAccess::All, - sound_cards: SoundCardAccess::All, - network_access: NetworkAccess::Yes, - } - } -} diff --git a/ableos/src/scheduler/mod.rs b/ableos/src/scheduler/mod.rs deleted file mode 100644 index 875a7e4..0000000 --- a/ableos/src/scheduler/mod.rs +++ /dev/null @@ -1,94 +0,0 @@ -pub mod capabilities; -pub mod priority; -pub mod proc; - -use crate::scheduler::capabilities::Capabilities; -use crate::{arch::generate_process_pass, stdio::StdIo}; -use kernel::proccess::PID; -use priority::Priority; -use proc::Process; - -pub static SCHEDULER: spin::Mutex = spin::Mutex::new(Scheduler::new()); - -/// Add additional wake conditions to the list -#[derive(Clone, Debug)] -pub enum WakeCondition { - /// Wake when the process has been blocked for a certain amount of time - TimerInterrupt(u64), - SocketRead(PID), - SocketWrite(PID), - SocketOpen(PID), - SocketClose(PID), - // HardwareEvent, -} - -// NOTE: Define what is a sleeping process in the context of the ableOS kernel. -// Blocked processes are processes that are waiting for a certain event to occur. -#[derive(Clone, Debug)] -pub struct BlockedProcess { - pub pid: PID, - pub wake_condition: WakeCondition, -} - -pub struct Scheduler { - pub free_pid: PID, - pub process_exec_time: u64, - pub execution_queue: Vec, - pub sleeping_queue: Vec, - pub blocked_queue: Vec, - // All timed processes sorted by wake time -} - -impl Scheduler { - /// Create a new scheduler - pub const fn new() -> Self { - Self { - free_pid: 0, - process_exec_time: 0, - execution_queue: Vec::new(), - sleeping_queue: Vec::new(), - blocked_queue: Vec::new(), - } - } - - /// Change the current process to the next process in the list - pub fn next_process(&mut self) { - self.process_exec_time = 0; - let previous_task = self.execution_queue[0].clone(); - self.execution_queue.remove(0); - self.execution_queue.push(previous_task); - } - - pub fn add_process(&mut self, mut process: Process) { - process.pid = self.free_pid; - self.free_pid += 1; - self.execution_queue.push(process); - } - - pub fn new_process( - &mut self, - capabilities: Capabilities, - priority: Priority, - working_dir: String, - stdio: StdIo, - ) -> Process { - Process { - pid: 0, - priority, - working_dir, - stdio, - password: generate_process_pass(), - capabilities, - } - } - - pub fn sleep_process(&mut self, process: &mut Process) { - let sleeping_process = BlockedProcess { - pid: process.pid, - wake_condition: WakeCondition::TimerInterrupt(0), - }; - - self.sleeping_queue.push(sleeping_process); - self.execution_queue.remove(0); - } -} diff --git a/ableos/src/scheduler/priority.rs b/ableos/src/scheduler/priority.rs deleted file mode 100644 index f74992f..0000000 --- a/ableos/src/scheduler/priority.rs +++ /dev/null @@ -1,10 +0,0 @@ -/// Scheduler priority model -#[derive(Clone, Copy, Debug)] -pub enum Priority { - /// Exclusively Kernel space | 20 Timer Tick execution time - High, - /// Kernel / User space | 15 Timer Tick execution time - Medium, - /// low priority userspace code | 10 Timer Tick execution time - Low, -} diff --git a/ableos/src/scheduler/proc.rs b/ableos/src/scheduler/proc.rs deleted file mode 100644 index 1770f07..0000000 --- a/ableos/src/scheduler/proc.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Process definition and general utilities surrounding them - -use super::capabilities::Capabilities; -use super::priority::Priority; -use crate::stdio::StdIo; -use kernel::proccess::PID; - -/// A process -#[derive(Clone, Debug)] -pub struct Process { - /// Internal PID - pub pid: PID, - - /// Process password - pub password: u128, - /// - pub capabilities: Capabilities, - /// A process's priority - pub priority: Priority, - - /// A process's current working directory - pub working_dir: String, - pub stdio: StdIo, -}