Compare commits
3 Commits
6e64101d09
...
1bb4074e2f
Author | SHA1 | Date | |
---|---|---|---|
1bb4074e2f | |||
689f7c8810 | |||
a1a01124de |
@ -2,6 +2,8 @@ use crate::drivers::vga::{self, Color, ColorCode};
|
||||
use crate::hlt_loop;
|
||||
use crate::memory::gdt;
|
||||
use crate::println;
|
||||
|
||||
use core::arch::asm;
|
||||
use lazy_static::lazy_static;
|
||||
use pic::{
|
||||
disk1_interrupt_handler, disk2_interrupt_handler, init_pic, keyboard_interrupt_handler,
|
||||
@ -12,6 +14,8 @@ use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
|
||||
pub mod pic;
|
||||
|
||||
const SYSCALL_32_INTERRUPT_NUMBER: usize = 0x80;
|
||||
|
||||
lazy_static! {
|
||||
static ref IDT: InterruptDescriptorTable = {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
@ -26,6 +30,7 @@ lazy_static! {
|
||||
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||
idt[InterruptIndex::HardDisk1.as_usize()].set_handler_fn(disk1_interrupt_handler);
|
||||
idt[InterruptIndex::HardDisk2.as_usize()].set_handler_fn(disk2_interrupt_handler);
|
||||
idt[SYSCALL_32_INTERRUPT_NUMBER].set_handler_fn(syscall_handler_32);
|
||||
idt
|
||||
};
|
||||
}
|
||||
@ -47,6 +52,44 @@ extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||
vga::change_color(color);
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn syscall_handler_32(_stack_frame: InterruptStackFrame) {
|
||||
let rax: u64;
|
||||
let rbx: u64;
|
||||
let rcx: u64;
|
||||
let rdx: u64;
|
||||
let rsi: u64;
|
||||
let rdi: u64;
|
||||
let rbp: u64;
|
||||
unsafe {
|
||||
asm!(
|
||||
"push rax",
|
||||
"push rbx",
|
||||
"push rcx",
|
||||
"push rdx",
|
||||
"push rsi",
|
||||
"push rdi",
|
||||
"push rbp",
|
||||
|
||||
"pop {rbp}",
|
||||
"pop {rdi}",
|
||||
"pop {rsi}",
|
||||
"pop {rdx}",
|
||||
"pop {rcx}",
|
||||
"pop {rbx}",
|
||||
"pop {rax}",
|
||||
rax = out(reg) rax,
|
||||
rbx = out(reg) rbx,
|
||||
rcx = out(reg) rcx,
|
||||
rdx = out(reg) rdx,
|
||||
rsi = out(reg) rsi,
|
||||
rdi = out(reg) rdi,
|
||||
rbp = out(reg) rbp,
|
||||
)
|
||||
}
|
||||
println!("Received syscall");
|
||||
crate::syscalls::syscall_routine(rax);
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn page_fault_handler(
|
||||
stack_frame: InterruptStackFrame,
|
||||
error_code: PageFaultErrorCode,
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::println;
|
||||
use crate::utils::mutex::AsyncMutex;
|
||||
|
||||
use super::thread::{Thread, ThreadId};
|
||||
@ -23,7 +24,7 @@ pub const K_THREAD_ID: ThreadId = ThreadId(0); // Kernel main thread identifier
|
||||
|
||||
struct ThreadStream {
|
||||
ids: ArrayQueue<ThreadId>,
|
||||
waker: AtomicWaker
|
||||
waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl ThreadStream {
|
||||
@ -35,9 +36,7 @@ impl ThreadStream {
|
||||
}
|
||||
|
||||
pub fn register(&mut self, id: ThreadId) {
|
||||
self.ids
|
||||
.push(id)
|
||||
.expect("Thread queue full");
|
||||
self.ids.push(id).expect("Thread queue full");
|
||||
self.waker.wake();
|
||||
}
|
||||
}
|
||||
@ -79,19 +78,29 @@ impl Scheduler {
|
||||
started: true,
|
||||
rsp: 0,
|
||||
base_stack: 0,
|
||||
is_blocked: false,
|
||||
};
|
||||
res.register(Arc::new(RefCell::new(k_thread)));
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
while let Some(id) = self.thread_queue.next().await {
|
||||
if let Some(thread) = self.get_thread(id) { // Thread still exists
|
||||
unsafe {
|
||||
(&mut*thread.as_ptr()).run();
|
||||
if let Some(thread) = self.get_thread(id) {
|
||||
// Thread still exists
|
||||
let blocked: bool;
|
||||
{
|
||||
blocked = thread.borrow().is_blocked;
|
||||
} // Drop thread borrow
|
||||
if !blocked {
|
||||
unsafe {
|
||||
(&mut *thread.as_ptr()).run();
|
||||
}
|
||||
|
||||
if !thread.borrow().is_blocked {
|
||||
self.thread_queue.register(id);
|
||||
}
|
||||
}
|
||||
self.thread_queue.register(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,6 +115,21 @@ impl Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block(&mut self, id: ThreadId) {
|
||||
if let Some(thread) = self.get_thread(id) {
|
||||
thread.borrow_mut().is_blocked = true;
|
||||
println!("Blocked thread {:?}", id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unblock(&mut self, id: ThreadId) {
|
||||
if let Some(thread) = self.get_thread(id) {
|
||||
thread.borrow_mut().is_blocked = false;
|
||||
self.thread_queue.register(id);
|
||||
println!("Unblocked thread {:?}", id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit(&mut self, id: ThreadId) {
|
||||
self.threads.remove(&id).unwrap().borrow().exit();
|
||||
}
|
||||
@ -123,4 +147,4 @@ pub async fn scheduler_run() {
|
||||
let mut scheduler = SCHEDULER.lock().await;
|
||||
SCHEDULER.force_unlock();
|
||||
scheduler.run().await;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::println;
|
||||
use crate::utils::mutex::AsyncMutex;
|
||||
|
||||
use super::scheduler::{SCHEDULER, K_THREAD_ID};
|
||||
use super::scheduler::{K_THREAD_ID, SCHEDULER};
|
||||
|
||||
use core::arch::asm;
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
@ -25,34 +25,22 @@ impl ThreadId {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit() {
|
||||
println!("Exiting thread");
|
||||
{
|
||||
let mut scheduler = SCHEDULER.try_lock().unwrap();
|
||||
scheduler.exit(*RUNNING_THREAD.try_lock().unwrap());
|
||||
} // Drop scheduler mutex guard
|
||||
|
||||
resume_k_thread();
|
||||
}
|
||||
|
||||
pub fn resume_k_thread() {
|
||||
let k_thread: *mut Thread;
|
||||
{
|
||||
let mut scheduler = SCHEDULER.try_lock().unwrap();
|
||||
k_thread = scheduler
|
||||
.get_thread(K_THREAD_ID)
|
||||
.unwrap()
|
||||
.as_ptr();
|
||||
k_thread = scheduler.get_thread(K_THREAD_ID).unwrap().as_ptr();
|
||||
} // Drop scheduler mutex guard
|
||||
|
||||
unsafe {
|
||||
(&mut* k_thread).run();
|
||||
(&mut *k_thread).run();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn routine() {
|
||||
println!("Routine executed");
|
||||
exit();
|
||||
crate::syscalls::syscall_routine(crate::syscalls::EXIT_ID); // Call exit
|
||||
println!("SHOULD NEVER BE DISPLAYED");
|
||||
}
|
||||
|
||||
pub struct Thread {
|
||||
@ -60,7 +48,8 @@ pub struct Thread {
|
||||
pub entry_point: u64,
|
||||
pub started: bool,
|
||||
pub rsp: u64,
|
||||
pub base_stack: u64
|
||||
pub base_stack: u64,
|
||||
pub is_blocked: bool,
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
@ -73,13 +62,17 @@ impl Thread {
|
||||
started: false,
|
||||
rsp: stack_bottom + STACK_SIZE as u64,
|
||||
base_stack: stack_bottom,
|
||||
is_blocked: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit(&self) {
|
||||
unsafe {
|
||||
dealloc(self.base_stack as *mut u8, Layout::new::<[u8; STACK_SIZE]>());
|
||||
dealloc(
|
||||
self.base_stack as *mut u8,
|
||||
Layout::new::<[u8; STACK_SIZE]>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,8 +91,8 @@ impl Thread {
|
||||
out = out(reg) current_rsp, // Save thread rsp
|
||||
);
|
||||
current_thread.borrow_mut().rsp = current_rsp;
|
||||
}
|
||||
else { // Thread does not exists anymore
|
||||
} else {
|
||||
// Thread does not exists anymore
|
||||
*current_thread_guard = self.id; // change running thread
|
||||
asm!( // Just switch to new thead without saving registers
|
||||
"push {rsp}", // Set stack pointer to the new thread
|
||||
|
3
src/syscalls/ids.rs
Normal file
3
src/syscalls/ids.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub type SyscallId = u64;
|
||||
|
||||
pub const EXIT_ID: u64 = 0;
|
@ -1 +1,71 @@
|
||||
use crate::println;
|
||||
use crate::proc::thread::{resume_k_thread, RUNNING_THREAD};
|
||||
use crate::proc::scheduler::SCHEDULER;
|
||||
use crate::task::executor::EXECUTOR;
|
||||
use crate::task::Task;
|
||||
|
||||
pub use ids::*;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
pub mod ids;
|
||||
pub mod io;
|
||||
pub mod proc;
|
||||
|
||||
pub type SyscallContextT = Arc<RefCell<SyscallContext>>;
|
||||
|
||||
pub struct SyscallContext {
|
||||
id: SyscallId,
|
||||
res: u64,
|
||||
thread_id: crate::proc::thread::ThreadId,
|
||||
}
|
||||
|
||||
impl SyscallContext {
|
||||
pub async fn run(&mut self) {
|
||||
println!("Running async syscall runner");
|
||||
self.dispatch().await;
|
||||
println!("Syscall end, unblocking thread");
|
||||
SCHEDULER.lock().await.unblock(self.thread_id);
|
||||
}
|
||||
|
||||
pub async fn dispatch(&mut self) {
|
||||
match self.id {
|
||||
EXIT_ID => proc::exit(self).await,
|
||||
_ => bad_syscall().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn syscall_runner(context: SyscallContextT) {
|
||||
context.borrow_mut().run().await;
|
||||
}
|
||||
|
||||
pub fn syscall_routine(syscall_id: SyscallId) -> u64 {
|
||||
println!("Running syscall");
|
||||
let context: SyscallContextT = Arc::new(RefCell::new(SyscallContext {
|
||||
id: syscall_id,
|
||||
res: 0,
|
||||
thread_id: *RUNNING_THREAD.try_lock().unwrap(),
|
||||
}));
|
||||
|
||||
println!("Spawning async syscall runner");
|
||||
EXECUTOR
|
||||
.try_lock()
|
||||
.unwrap()
|
||||
.spawn(Task::new(syscall_runner(context.clone())));
|
||||
|
||||
println!("Blocking thread");
|
||||
SCHEDULER
|
||||
.try_lock()
|
||||
.unwrap()
|
||||
.block(context.borrow().thread_id);
|
||||
println!("Returning to scheduler");
|
||||
resume_k_thread();
|
||||
|
||||
let res = context.borrow().res;
|
||||
res
|
||||
}
|
||||
|
||||
async fn bad_syscall() {}
|
||||
|
10
src/syscalls/proc.rs
Normal file
10
src/syscalls/proc.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use crate::println;
|
||||
use crate::proc::scheduler::SCHEDULER;
|
||||
|
||||
use super::SyscallContext;
|
||||
|
||||
pub async fn exit(context: &SyscallContext) {
|
||||
println!("Running exit(2)");
|
||||
let mut scheduler = SCHEDULER.lock().await;
|
||||
scheduler.exit(context.thread_id);
|
||||
}
|
Loading…
Reference in New Issue
Block a user