Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix scheduler #9

Merged
merged 10 commits into from
Sep 13, 2024
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 @@ -67,35 +48,22 @@ pub fn get_ipl() -> IPL {
IPL::from(ipl)
}

pub fn set_ipl(ipl: IPL) -> IPL {
let requested_ipl = ipl as u64;
let old_ipl = get_ipl() as 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));
}

IPL::from(old_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);
unsafe {
asm!("mov cr8, {}", in(reg) ipl as u64, options(nomem, nostack, preserves_flags));
0x6D70 marked this conversation as resolved.
Show resolved Hide resolved
}

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

unsafe {
asm!("mov cr8, {}", in(reg) ipl as u64, options(nomem, nostack, preserves_flags));
}
}
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));
}
}
24 changes: 15 additions & 9 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,23 +24,30 @@ 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();
if isr == 0x2f {
0x6D70 marked this conversation as resolved.
Show resolved Hide resolved
APIC.eoi();
}

match &handlers[isr] {
IRQHandler::Handler(handler) => {
Expand All @@ -59,7 +65,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) {
0x6D70 marked this conversation as resolved.
Show resolved Hide resolved
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
0x6D70 marked this conversation as resolved.
Show resolved Hide resolved
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