Skip to content

Commit

Permalink
Merge pull request #9 from anubis-rs/fix_scheduler
Browse files Browse the repository at this point in the history
Fix scheduler
  • Loading branch information
0x6D70 authored Sep 13, 2024
2 parents 79825de + c1c06a8 commit 242ba8a
Show file tree
Hide file tree
Showing 18 changed files with 178 additions and 120 deletions.
4 changes: 4 additions & 0 deletions build/linker-scripts/kernel.ld
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ SECTIONS
*(.bss .bss.*)
} :data

.got : {
*(.got)
} :data

. += CONSTANT(MAXPAGESIZE);

_kernel_end = .;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
use core::arch::asm;

use crate::cpu::current_cpu;
use crate::dpc::dpc_interrupt_dispatch;

#[macro_export]
macro_rules! lock_with_ipl {
($name:ident) => {{
let old = raise_ipl(IPL::DPC);
OnDrop::new($name.lock(), move || {
set_ipl(old);
})
}};
($name:ident, $ipl:expr) => {{
let _ = raise_ipl(IPL::DPC);
OnDrop::new($name.lock(), || {
set_ipl($ipl);
})
}};
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
#[repr(u8)]
#[allow(clippy::upper_case_acronyms)]
Expand Down Expand Up @@ -57,45 +38,34 @@ impl From<u8> for IPL {
}
}

pub fn get_ipl() -> IPL {
let ipl: u64;

fn set_ipl(ipl: IPL) {
unsafe {
asm!("mov {}, cr8", out(reg) ipl, options(nomem, nostack, preserves_flags));
asm!("mov cr8, {}", in(reg) ipl as u64, options(nomem, nostack, preserves_flags));
}

IPL::from(ipl)
}

pub fn set_ipl(ipl: IPL) -> IPL {
let requested_ipl = ipl as u64;
let old_ipl = get_ipl() as u64;
pub fn get_ipl() -> IPL {
let ipl: u64;

unsafe {
asm!("mov cr8, {}", in(reg) requested_ipl, options(nomem, nostack, preserves_flags));
}

if old_ipl > requested_ipl {
ipl_lowered(IPL::from(old_ipl), IPL::from(requested_ipl));
asm!("mov {}, cr8", out(reg) ipl, options(nomem, nostack, preserves_flags));
}

IPL::from(old_ipl)
IPL::from(ipl)
}

pub fn raise_ipl(ipl: IPL) -> IPL {
let old_ipl = get_ipl();

assert!(old_ipl as u64 <= ipl as u64);

if old_ipl < ipl {
set_ipl(ipl);
}
set_ipl(ipl);

old_ipl
}

pub fn ipl_lowered(_from: IPL, to: IPL) {
if (to as u8) < (IPL::DPC as u8) && !current_cpu().dpc_queue.read().dpcs.is_empty() {
dpc_interrupt_dispatch();
}
pub fn splx(ipl: IPL) {
assert!(ipl as u64 <= get_ipl() as u64);

set_ipl(ipl);
}
3 changes: 3 additions & 0 deletions crates/libxernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ pub mod collections;
pub mod on_drop;
pub mod sync;
pub mod syscall;

#[cfg(feature = "kernel")]
pub mod ipl;
26 changes: 26 additions & 0 deletions crates/libxernel/src/sync/spin.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use core::{
arch::asm,
cell::UnsafeCell,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, Ordering},
};

use crate::{
ipl::{raise_ipl, splx, IPL},
on_drop::OnDrop,
};

/// Simple data locking structure using a spin loop.
///
/// This spinlock will block threads waiting for the lock to become available.
Expand Down Expand Up @@ -74,6 +80,18 @@ impl<T: ?Sized> Spinlock<T> {
function(&mut *lock)
}

pub fn aquire(&self) -> OnDrop<SpinlockGuard<'_, T>, impl FnOnce()> {
let ipl = raise_ipl(IPL::DPC);
let callback = move || splx(ipl);
OnDrop::new(self.lock(), callback)
}

pub fn aquire_at(&self, ipl: IPL) -> OnDrop<SpinlockGuard<'_, T>, impl FnOnce()> {
let ipl = raise_ipl(ipl);
let callback = move || splx(ipl);
OnDrop::new(self.lock(), callback)
}

/// Unlocking a spinlock
///
/// With the drop approach the lock only gets released when the [`SpinlockGuard`] value goes out of scope.
Expand All @@ -83,6 +101,7 @@ impl<T: ?Sized> Spinlock<T> {
}

impl<T: ?Sized> SpinlockGuard<'_, T> {
// FIXME: Find a way to unlock when aquire is used. Since the spinlockguard can't be moved out of the OnDrop Type
/// Unlocking a spinlock
///
/// Sometimes it is nice to be able to unlock a lock when you want to.
Expand Down Expand Up @@ -112,3 +131,10 @@ impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
unsafe { &mut *self.lock.data.get() }
}
}

#[inline]
fn write_cr8(ipl: IPL) {
unsafe {
asm!("mov cr8, {}", in(reg) ipl as u64, options(nomem, nostack, preserves_flags));
}
}
22 changes: 12 additions & 10 deletions xernel/kernel/src/arch/amd64/interrupts/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
pub mod idt;
pub mod ipl;

use crate::arch::amd64::apic::APIC;
use crate::arch::amd64::{ports::outb, read_cr2};
use crate::dpc::dispatch_dpcs;
use crate::drivers::ps2::keyboard::keyboard;
use crate::sched::context::TrapFrame;
use core::arch::asm;
use core::sync::atomic::{compiler_fence, Ordering};
use idt::{IRQHandler, IDT_ENTRIES};
use ipl::IPL;

use self::ipl::{get_ipl, raise_ipl, set_ipl};
use libxernel::ipl::{get_ipl, raise_ipl, splx, IPL};

use super::apic::apic_spurious_interrupt;
use libxernel::sync::SpinlockIRQ;
Expand All @@ -25,24 +24,27 @@ pub fn init() {
handlers[0xE] = IRQHandler::Handler(page_fault_handler);
handlers[0x8] = IRQHandler::Handler(double_fault_handler);
handlers[0xF0] = IRQHandler::Handler(apic_spurious_interrupt);
// TODO: allocate vectors accordingly or manually set all known interrupt handlers here
handlers[0x2f] = IRQHandler::Handler(dispatch_dpcs);
handlers[0xd0] = IRQHandler::Handler(keyboard);
}

#[no_mangle]
extern "sysv64" fn generic_interrupt_handler(isr: usize, ctx: *mut TrapFrame) {
let mut ipl = IPL::from(isr >> 4);
let new_ipl = IPL::from(isr >> 4);
let current_ipl = get_ipl();

if (ipl as u8) < (get_ipl() as u8) {
if (new_ipl as u8) < (current_ipl as u8) {
panic!("IPL not less or equal");
}

ipl = raise_ipl(ipl);
raise_ipl(new_ipl);
enable();

let handlers = INTERRUPT_HANDLERS.lock();

let ctx = unsafe { &mut *ctx };

enable();

match &handlers[isr] {
IRQHandler::Handler(handler) => {
let handler = *handler;
Expand All @@ -59,7 +61,7 @@ extern "sysv64" fn generic_interrupt_handler(isr: usize, ctx: *mut TrapFrame) {

disable();

set_ipl(ipl);
splx(current_ipl);
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion xernel/kernel/src/arch/amd64/ioapic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl IOApic {
);

unsafe {
self.write_irq(1, 0x47, 0, false, true);
self.write_irq(1, 0xd0, 0, false, true);
debug!("IOAPICID: {:b}", self.read(0));
debug!("IOAPICVER: {:b}", self.read(1));
debug!("IOAPICARB: {:b}", self.read(2));
Expand Down
18 changes: 18 additions & 0 deletions xernel/kernel/src/arch/amd64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::cpu::register_cpu;
use crate::sched::context::Context;
use crate::KERNEL_PAGE_MAPPER;
use core::arch::{asm, global_asm};
use libxernel::ipl::IPL;
use limine::SmpInfo;
use x86_64::VirtAddr;

Expand Down Expand Up @@ -61,6 +62,23 @@ pub fn read_cr2() -> VirtAddr {
}
}

#[inline]
pub fn read_cr8() -> IPL {
let value: u64;

unsafe {
asm!("mov {}, cr8", out(reg) value, options(nomem, nostack, preserves_flags));
}
IPL::from(value)
}

#[inline]
pub fn write_cr8(ipl: IPL) {
unsafe {
asm!("mov cr8, {}", in(reg) ipl as u64, options(nomem, nostack, preserves_flags));
}
}

pub const FS_BASE: u32 = 0xC0000100;
pub const GS_BASE: u32 = 0xC0000101;
pub const KERNEL_GS_BASE: u32 = 0xC0000102;
Expand Down
1 change: 1 addition & 0 deletions xernel/kernel/src/arch/amd64/tsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::acpi::hpet;

pub static TSC_TICKS_PER_MS: AtomicU64 = AtomicU64::new(0);

// TODO: Use TSC Deadshot mode for apic
pub fn calibrate_tsc() {
let start: u64 = rdtsc();
hpet::sleep(10_000_000);
Expand Down
46 changes: 31 additions & 15 deletions xernel/kernel/src/cpu.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::arch::amd64::apic::APIC;
use crate::arch::amd64::{rdmsr, wrmsr, KERNEL_GS_BASE};
use crate::dpc::DpcQueue;
use crate::dpc::{DpcCall, DpcQueue};
use crate::sched::process::Process;
use crate::sched::thread::Thread;
use crate::timer::timer_event::TimerEvent;
use crate::timer::timer_queue::TimerQueue;
use alloc::boxed::Box;
use alloc::collections::VecDeque;
Expand All @@ -12,7 +13,8 @@ use core::cell::{Cell, UnsafeCell};
use core::ops::Deref;
use core::pin::Pin;
use core::sync::atomic::{AtomicUsize, Ordering};
use libxernel::sync::{Once, RwLock, Spinlock};
use libxernel::ipl::IPL;
use libxernel::sync::{Once, Spinlock};

static CPU_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

Expand Down Expand Up @@ -122,14 +124,28 @@ pub struct Cpu {

cpu_id: usize,
pub lapic_id: u32,
pub run_queue: RwLock<VecDeque<Arc<Thread>>>,
pub wait_queue: RwLock<VecDeque<Arc<Thread>>>,
pub current_thread: RwLock<Option<Arc<Thread>>>,
pub run_queue: Spinlock<VecDeque<Arc<Thread>>>,
pub wait_queue: Spinlock<VecDeque<Arc<Thread>>>,
pub current_thread: Spinlock<Option<Arc<Thread>>>,
pub idle_thread: Arc<Thread>,

pub timer_queue: RwLock<TimerQueue>,
pub dpc_queue: RwLock<DpcQueue>,
pub next: RwLock<Option<Arc<Thread>>>,
pub timer_queue: Spinlock<TimerQueue>,
pub dpc_queue: Spinlock<DpcQueue>,
pub next: Spinlock<Option<Arc<Thread>>>,
}

impl Cpu {
pub fn enqueue_timer(&self, event: TimerEvent) {
self.timer_queue.aquire_at(IPL::High).enqueue(event);
}

pub fn enqueue_dpc(&self, dpc: Box<dyn DpcCall>) {
self.dpc_queue.aquire_at(IPL::High).enqueue(dpc);
}

pub fn enqueue_thread(&self, thread: Arc<Thread>) {
self.run_queue.aquire().push_back(thread)
}
}

pub fn register_cpu() {
Expand All @@ -141,13 +157,13 @@ pub fn register_cpu() {
kernel_stack: Cell::new(0),
cpu_id,
lapic_id,
run_queue: RwLock::new(VecDeque::new()),
wait_queue: RwLock::new(VecDeque::new()),
current_thread: RwLock::new(None),
run_queue: Spinlock::new(VecDeque::new()),
wait_queue: Spinlock::new(VecDeque::new()),
current_thread: Spinlock::new(None),
idle_thread: Arc::new(Thread::idle_thread()),
timer_queue: RwLock::new(TimerQueue::new()),
dpc_queue: RwLock::new(DpcQueue::new()),
next: RwLock::new(None),
timer_queue: Spinlock::new(TimerQueue::new()),
dpc_queue: Spinlock::new(DpcQueue::new()),
next: Spinlock::new(None),
}));

// use KERNEL_GS_BASE to store the cpu_data
Expand All @@ -165,7 +181,7 @@ pub fn current_cpu() -> Pin<&'static Cpu> {
pub fn current_thread() -> Arc<Thread> {
current_cpu()
.current_thread
.read()
.aquire()
.clone()
.unwrap_or(current_cpu().idle_thread.clone())
}
Expand Down
Loading

0 comments on commit 242ba8a

Please sign in to comment.