From 2e4460ace66746ef1e49d4425b48170818206c7a Mon Sep 17 00:00:00 2001 From: Mathieu Strypsteen Date: Sun, 22 Dec 2024 09:27:14 +0100 Subject: [PATCH] Switch to usermode --- Cargo.lock | 10 +++++----- init/src/main.rs | 5 +++-- init/src/start.s | 11 +++++++++++ kernel/src/cpu/gdt.rs | 3 ++- kernel/src/cpu/isr.rs | 32 +++++++++++++++++++++++++------- kernel/src/cpu/usermode.s | 31 +++++++++++++++++++++++++++++++ kernel/src/main.rs | 23 +++++++++++------------ kernel/src/misc/elf.rs | 18 +++++++++++------- kernel/src/sys/task.rs | 16 +++++++++++++--- lib/acpica | 2 +- 10 files changed, 113 insertions(+), 38 deletions(-) create mode 100644 init/src/start.s create mode 100644 kernel/src/cpu/usermode.s diff --git a/Cargo.lock b/Cargo.lock index b5b8fd0..089b573 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,7 +64,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -319,7 +319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -453,9 +453,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" dependencies = [ "proc-macro2", "quote", @@ -501,7 +501,7 @@ checksum = "9b24e77d3fc1e617051e630f99da24bcae6328abab37b8f9216bb68d06804f9a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] diff --git a/init/src/main.rs b/init/src/main.rs index 378f073..da97a56 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -1,10 +1,11 @@ #![no_std] #![no_main] +use core::{arch::global_asm, panic::PanicInfo}; -use core::panic::PanicInfo; +global_asm!(include_str!("start.s"), options(att_syntax)); #[no_mangle] -extern "C" fn _start() -> ! { +extern "C" fn main() -> ! { loop {} } diff --git a/init/src/start.s b/init/src/start.s new file mode 100644 index 0000000..4d621f8 --- /dev/null +++ b/init/src/start.s @@ -0,0 +1,11 @@ +.text + +.global _start +_start: + mov $stack, %rsp + call main + +.section .bss +.align 16 +.skip 0x10000 +stack: diff --git a/kernel/src/cpu/gdt.rs b/kernel/src/cpu/gdt.rs index df4993e..6dae714 100644 --- a/kernel/src/cpu/gdt.rs +++ b/kernel/src/cpu/gdt.rs @@ -55,6 +55,7 @@ pub fn setup_gdt() { reserved4: 0, iopb_offset: size_of::() as u16, })); + tss.rsp[0] = allocate_stack(); tss.ist[0] = allocate_stack(); tss.ist[1] = allocate_stack(); let gdt = Box::leak(Box::new(GDT { @@ -113,7 +114,7 @@ pub fn setup_gdt() { })); let gdt_descriptor = Box::leak(Box::new(GDTDescriptor { limit: (size_of::() - 1) as u16, - base: gdt.entries.as_ptr() as u64, + base: gdt as *mut GDT as u64, })); unsafe { asm!(" diff --git a/kernel/src/cpu/isr.rs b/kernel/src/cpu/isr.rs index f0e5070..e7523f0 100644 --- a/kernel/src/cpu/isr.rs +++ b/kernel/src/cpu/isr.rs @@ -3,13 +3,18 @@ use core::{ sync::atomic::Ordering, }; +use kernel_common::instructions::hlt; use log::warn; -use crate::sys::{ - lapic::{get_current_lapic_id, send_eoi}, - locks::Spinlock, - scheduler::scheduler, - sync::{IN_ISR_HANDLER, LOCKS_HELD}, +use crate::{ + sys::{ + lapic::{get_current_lapic_id, send_eoi}, + locks::Spinlock, + scheduler::scheduler, + sync::{IN_ISR_HANDLER, LOCKS_HELD}, + task::{terminate_current_task, terminate_tasks}, + }, + BROADCASTED_PANIC, }; global_asm!(include_str!("isr.s"), options(att_syntax)); @@ -82,8 +87,10 @@ pub static ISR_HANDLERS: Spinlock<[Option; 256]> = Spinlock::new([None; 25 #[no_mangle] extern "C" fn isr_handler(state: &mut ISRState) { - if state.isr < 32 { - panic!("Exception: {}", EXCEPTIONS[state.isr as usize]); + if BROADCASTED_PANIC.load(Ordering::SeqCst) { + loop { + hlt(); + } } if 32 <= state.isr && state.isr <= 47 { return; // Legacy PIC interrupt @@ -103,6 +110,17 @@ extern "C" fn isr_handler(state: &mut ISRState) { } let lapic_id = get_current_lapic_id(); IN_ISR_HANDLER[lapic_id].store(true, Ordering::SeqCst); + if state.isr < 32 { + if state.cs == 0x1b && state.isr != 2 && state.isr != 8 { + warn!("Exception in usermode: {}", EXCEPTIONS[state.isr as usize]); + terminate_current_task(); + state.isr = ISR_SCHEDULER; + } else { + panic!("Exception: {}", EXCEPTIONS[state.isr as usize]); + } + } else { + terminate_tasks(); + } if state.isr == ISR_SCHEDULER { scheduler(state); debug_assert_eq!(LOCKS_HELD[lapic_id].load(Ordering::SeqCst), 0); diff --git a/kernel/src/cpu/usermode.s b/kernel/src/cpu/usermode.s new file mode 100644 index 0000000..1ae631e --- /dev/null +++ b/kernel/src/cpu/usermode.s @@ -0,0 +1,31 @@ +.text + +.global jump_usermode +jump_usermode: + mov $0x23, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + push $0x23 + push $0 + pushf + push $0x1b + push %rdi + + xor %rax, %rax + xor %rbx, %rbx + xor %rcx, %rcx + xor %rdx, %rdx + xor %rdi, %rdi + xor %rsi, %rsi + xor %rbp, %rbp + xor %r8, %r8 + xor %r9, %r9 + xor %r10, %r10 + xor %r11, %r11 + xor %r12, %r12 + xor %r13, %r13 + xor %r14, %r14 + xor %r15, %r15 + iretq diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 3707a0d..9779563 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -63,6 +63,7 @@ pub static BROADCASTED_PANIC: AtomicBool = AtomicBool::new(false); global_asm!(include_str!("cpu/boot.s"), options(att_syntax)); global_asm!(include_str!("cpu/trampoline.s"), options(att_syntax)); +global_asm!(include_str!("cpu/usermode.s"), options(att_syntax)); #[cfg(debug_assertions)] const INIT_BINARY: &[u8] = include_bytes!("../../target/x86_64-unknown-none/debug/init"); @@ -116,18 +117,16 @@ fn main() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { cli(); - if !BROADCASTED_PANIC.load(Ordering::SeqCst) { - if INTERRUPTS_SETUP.load(Ordering::SeqCst) { - smp_broadcast_panic(); - LOCKS_HELD[get_current_lapic_id()].fetch_add(1, Ordering::SeqCst); - } - error!("{}", info); - let str = format!("{}", info); - let mut display = PANIC_DISPLAY.lock(); - if let Some(display) = display.get_mut() { - display.clear(); - display.print(&str); - } + if INTERRUPTS_SETUP.load(Ordering::SeqCst) { + LOCKS_HELD[get_current_lapic_id()].fetch_add(1, Ordering::SeqCst); + smp_broadcast_panic(); + } + error!("{}", info); + let str = format!("{}", info); + let mut display = PANIC_DISPLAY.lock(); + if let Some(display) = display.get_mut() { + display.clear(); + display.print(&str); } loop { hlt(); diff --git a/kernel/src/misc/elf.rs b/kernel/src/misc/elf.rs index f4c6e72..ad939d7 100644 --- a/kernel/src/misc/elf.rs +++ b/kernel/src/misc/elf.rs @@ -1,4 +1,4 @@ -use core::{mem, ptr}; +use core::ptr; use elf::{abi::PT_LOAD, endian::LittleEndian, ElfBytes}; use log::info; @@ -8,10 +8,13 @@ use crate::{ sys::{lapic::get_current_lapic_id, task::CURRENT_TASKS}, }; -const USER_END: u64 = 0x800000000000; +const USER_END: u64 = 0x800000000000 - 0x1000; // Avoid accidentally jumping to non-canonical address + +extern "C" { + fn jump_usermode(address: u64) -> !; +} // TODO: Proper error handling -// TODO: Verify whether p_offset is within bounds pub fn load_binary() { let process; { @@ -30,10 +33,11 @@ pub fn load_binary() { } let write = i.p_flags & 2 != 0; let exec = i.p_flags & 1 != 0; - assert!(i.p_vaddr < USER_END); assert!(i.p_vaddr + i.p_memsz < USER_END); assert!(i.p_vaddr + i.p_memsz >= i.p_vaddr); assert!(i.p_filesz <= i.p_memsz); + assert!(i.p_offset + i.p_filesz <= binary.len() as u64); + assert!(i.p_offset + i.p_filesz >= i.p_offset); assert!(!write || !exec); let start = i.p_vaddr / 0x1000 * 0x1000; let end = (i.p_vaddr + i.p_memsz + 0xfff) / 0x1000 * 0x1000; @@ -48,14 +52,14 @@ pub fn load_binary() { } disable_user_memory_access(); unsafe { - // TODO: enable user flag - process.address_space.update_flags_range(start, size, false, write, exec); + process.address_space.update_flags_range(start, size, true, write, exec); } } entry = file.ehdr.e_entry; + assert!(entry < USER_END); } info!("Starting init..."); unsafe { - (mem::transmute:: !>(entry))(); + jump_usermode(entry); } } diff --git a/kernel/src/sys/task.rs b/kernel/src/sys/task.rs index 272a061..561621d 100644 --- a/kernel/src/sys/task.rs +++ b/kernel/src/sys/task.rs @@ -49,21 +49,25 @@ static RFLAGS: AtomicU64 = AtomicU64::new(0); pub static MULTITASKING_ENABLED: AtomicBool = AtomicBool::new(false); pub static STARTING_AP_ID: AtomicI64 = AtomicI64::new(-1); pub static ALL_APS_STARTED: AtomicBool = AtomicBool::new(false); +pub static TERMINATE_STASKS: [Spinlock>; 256] = [const { Spinlock::new(Vec::new()) }; 256]; pub fn allocate_stack() -> u64 { let stack: Vec = vec![0; STACK_SIZE]; stack.leak().as_mut_ptr() as u64 + STACK_SIZE as u64 } pub fn switch_task(current_state: &mut ISRState, new_task: Task) { + let lapic_id = get_current_lapic_id(); let mut current_tasks = CURRENT_TASKS.lock(); - if let Some(mut current_task) = current_tasks[get_current_lapic_id()].take() { + if let Some(mut current_task) = current_tasks[lapic_id].take() { current_task.state = *current_state; match current_task.task_state { TaskState::Ready => { SCHEDULER.lock().add_task(current_task); } TaskState::Idle => IDLE_TASKS.lock().push(current_task), - TaskState::Terminated => {} + TaskState::Terminated => { + TERMINATE_STASKS[lapic_id].lock().push(current_task); + } TaskState::Sleeping => sleep_internal(current_task), TaskState::SemaphoreBlocked => lock_semaphore_internal(current_task), } @@ -124,6 +128,9 @@ fn create_idle_task() { IDLE_TASKS.lock().push(idle_task); } } +pub fn terminate_current_task() { + CURRENT_TASKS.lock()[get_current_lapic_id()].as_mut().unwrap().task_state = TaskState::Terminated; +} extern "C" fn task_entry() -> ! { let func; { @@ -132,7 +139,7 @@ extern "C" fn task_entry() -> ! { } func(); { - CURRENT_TASKS.lock()[get_current_lapic_id()].as_mut().unwrap().task_state = TaskState::Terminated; + terminate_current_task(); } yield_task(); panic!("Failed to terminate task"); @@ -152,6 +159,9 @@ fn idle_main() { hlt(); } } +pub fn terminate_tasks() { + TERMINATE_STASKS[get_current_lapic_id()].lock().clear(); +} pub fn setup_multitasking() -> ! { let rflags = get_rflags(); RFLAGS.store(rflags, core::sync::atomic::Ordering::SeqCst); diff --git a/lib/acpica b/lib/acpica index 437f7e1..7dae721 160000 --- a/lib/acpica +++ b/lib/acpica @@ -1 +1 @@ -Subproject commit 437f7e1a0039d227d3952677c3f9f5ad9c814395 +Subproject commit 7dae72155bf06b0edda9f3aea713da1d48c1c418