Switch to usermode
All checks were successful
Build / build (push) Successful in 2m50s

This commit is contained in:
Mathieu Strypsteen 2024-12-22 09:27:14 +01:00
parent 5b491989da
commit 2e4460ace6
10 changed files with 113 additions and 38 deletions

10
Cargo.lock generated
View file

@ -64,7 +64,7 @@ dependencies = [
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"syn 2.0.90", "syn 2.0.91",
] ]
[[package]] [[package]]
@ -319,7 +319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn 2.0.90", "syn 2.0.91",
] ]
[[package]] [[package]]
@ -453,9 +453,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.90" version = "2.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -501,7 +501,7 @@ checksum = "9b24e77d3fc1e617051e630f99da24bcae6328abab37b8f9216bb68d06804f9a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.90", "syn 2.0.91",
] ]
[[package]] [[package]]

View file

@ -1,10 +1,11 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use core::{arch::global_asm, panic::PanicInfo};
use core::panic::PanicInfo; global_asm!(include_str!("start.s"), options(att_syntax));
#[no_mangle] #[no_mangle]
extern "C" fn _start() -> ! { extern "C" fn main() -> ! {
loop {} loop {}
} }

11
init/src/start.s Normal file
View file

@ -0,0 +1,11 @@
.text
.global _start
_start:
mov $stack, %rsp
call main
.section .bss
.align 16
.skip 0x10000
stack:

View file

@ -55,6 +55,7 @@ pub fn setup_gdt() {
reserved4: 0, reserved4: 0,
iopb_offset: size_of::<TSS>() as u16, iopb_offset: size_of::<TSS>() as u16,
})); }));
tss.rsp[0] = allocate_stack();
tss.ist[0] = allocate_stack(); tss.ist[0] = allocate_stack();
tss.ist[1] = allocate_stack(); tss.ist[1] = allocate_stack();
let gdt = Box::leak(Box::new(GDT { let gdt = Box::leak(Box::new(GDT {
@ -113,7 +114,7 @@ pub fn setup_gdt() {
})); }));
let gdt_descriptor = Box::leak(Box::new(GDTDescriptor { let gdt_descriptor = Box::leak(Box::new(GDTDescriptor {
limit: (size_of::<GDT>() - 1) as u16, limit: (size_of::<GDT>() - 1) as u16,
base: gdt.entries.as_ptr() as u64, base: gdt as *mut GDT as u64,
})); }));
unsafe { unsafe {
asm!(" asm!("

View file

@ -3,13 +3,18 @@ use core::{
sync::atomic::Ordering, sync::atomic::Ordering,
}; };
use kernel_common::instructions::hlt;
use log::warn; use log::warn;
use crate::sys::{ use crate::{
lapic::{get_current_lapic_id, send_eoi}, sys::{
locks::Spinlock, lapic::{get_current_lapic_id, send_eoi},
scheduler::scheduler, locks::Spinlock,
sync::{IN_ISR_HANDLER, LOCKS_HELD}, 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)); global_asm!(include_str!("isr.s"), options(att_syntax));
@ -82,8 +87,10 @@ pub static ISR_HANDLERS: Spinlock<[Option<fn()>; 256]> = Spinlock::new([None; 25
#[no_mangle] #[no_mangle]
extern "C" fn isr_handler(state: &mut ISRState) { extern "C" fn isr_handler(state: &mut ISRState) {
if state.isr < 32 { if BROADCASTED_PANIC.load(Ordering::SeqCst) {
panic!("Exception: {}", EXCEPTIONS[state.isr as usize]); loop {
hlt();
}
} }
if 32 <= state.isr && state.isr <= 47 { if 32 <= state.isr && state.isr <= 47 {
return; // Legacy PIC interrupt return; // Legacy PIC interrupt
@ -103,6 +110,17 @@ extern "C" fn isr_handler(state: &mut ISRState) {
} }
let lapic_id = get_current_lapic_id(); let lapic_id = get_current_lapic_id();
IN_ISR_HANDLER[lapic_id].store(true, Ordering::SeqCst); 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 { if state.isr == ISR_SCHEDULER {
scheduler(state); scheduler(state);
debug_assert_eq!(LOCKS_HELD[lapic_id].load(Ordering::SeqCst), 0); debug_assert_eq!(LOCKS_HELD[lapic_id].load(Ordering::SeqCst), 0);

31
kernel/src/cpu/usermode.s Normal file
View file

@ -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

View file

@ -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/boot.s"), options(att_syntax));
global_asm!(include_str!("cpu/trampoline.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)] #[cfg(debug_assertions)]
const INIT_BINARY: &[u8] = include_bytes!("../../target/x86_64-unknown-none/debug/init"); const INIT_BINARY: &[u8] = include_bytes!("../../target/x86_64-unknown-none/debug/init");
@ -116,18 +117,16 @@ fn main() {
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
cli(); cli();
if !BROADCASTED_PANIC.load(Ordering::SeqCst) { if INTERRUPTS_SETUP.load(Ordering::SeqCst) {
if INTERRUPTS_SETUP.load(Ordering::SeqCst) { LOCKS_HELD[get_current_lapic_id()].fetch_add(1, Ordering::SeqCst);
smp_broadcast_panic(); smp_broadcast_panic();
LOCKS_HELD[get_current_lapic_id()].fetch_add(1, Ordering::SeqCst); }
} error!("{}", info);
error!("{}", info); let str = format!("{}", info);
let str = format!("{}", info); let mut display = PANIC_DISPLAY.lock();
let mut display = PANIC_DISPLAY.lock(); if let Some(display) = display.get_mut() {
if let Some(display) = display.get_mut() { display.clear();
display.clear(); display.print(&str);
display.print(&str);
}
} }
loop { loop {
hlt(); hlt();

View file

@ -1,4 +1,4 @@
use core::{mem, ptr}; use core::ptr;
use elf::{abi::PT_LOAD, endian::LittleEndian, ElfBytes}; use elf::{abi::PT_LOAD, endian::LittleEndian, ElfBytes};
use log::info; use log::info;
@ -8,10 +8,13 @@ use crate::{
sys::{lapic::get_current_lapic_id, task::CURRENT_TASKS}, 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: Proper error handling
// TODO: Verify whether p_offset is within bounds
pub fn load_binary() { pub fn load_binary() {
let process; let process;
{ {
@ -30,10 +33,11 @@ pub fn load_binary() {
} }
let write = i.p_flags & 2 != 0; let write = i.p_flags & 2 != 0;
let exec = i.p_flags & 1 != 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 < USER_END);
assert!(i.p_vaddr + i.p_memsz >= i.p_vaddr); assert!(i.p_vaddr + i.p_memsz >= i.p_vaddr);
assert!(i.p_filesz <= i.p_memsz); 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); assert!(!write || !exec);
let start = i.p_vaddr / 0x1000 * 0x1000; let start = i.p_vaddr / 0x1000 * 0x1000;
let end = (i.p_vaddr + i.p_memsz + 0xfff) / 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(); disable_user_memory_access();
unsafe { unsafe {
// TODO: enable user flag process.address_space.update_flags_range(start, size, true, write, exec);
process.address_space.update_flags_range(start, size, false, write, exec);
} }
} }
entry = file.ehdr.e_entry; entry = file.ehdr.e_entry;
assert!(entry < USER_END);
} }
info!("Starting init..."); info!("Starting init...");
unsafe { unsafe {
(mem::transmute::<u64, extern "C" fn() -> !>(entry))(); jump_usermode(entry);
} }
} }

View file

@ -49,21 +49,25 @@ static RFLAGS: AtomicU64 = AtomicU64::new(0);
pub static MULTITASKING_ENABLED: AtomicBool = AtomicBool::new(false); pub static MULTITASKING_ENABLED: AtomicBool = AtomicBool::new(false);
pub static STARTING_AP_ID: AtomicI64 = AtomicI64::new(-1); pub static STARTING_AP_ID: AtomicI64 = AtomicI64::new(-1);
pub static ALL_APS_STARTED: AtomicBool = AtomicBool::new(false); pub static ALL_APS_STARTED: AtomicBool = AtomicBool::new(false);
pub static TERMINATE_STASKS: [Spinlock<Vec<Task>>; 256] = [const { Spinlock::new(Vec::new()) }; 256];
pub fn allocate_stack() -> u64 { pub fn allocate_stack() -> u64 {
let stack: Vec<u8> = vec![0; STACK_SIZE]; let stack: Vec<u8> = vec![0; STACK_SIZE];
stack.leak().as_mut_ptr() as u64 + STACK_SIZE as u64 stack.leak().as_mut_ptr() as u64 + STACK_SIZE as u64
} }
pub fn switch_task(current_state: &mut ISRState, new_task: Task) { 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(); 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; current_task.state = *current_state;
match current_task.task_state { match current_task.task_state {
TaskState::Ready => { TaskState::Ready => {
SCHEDULER.lock().add_task(current_task); SCHEDULER.lock().add_task(current_task);
} }
TaskState::Idle => IDLE_TASKS.lock().push(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::Sleeping => sleep_internal(current_task),
TaskState::SemaphoreBlocked => lock_semaphore_internal(current_task), TaskState::SemaphoreBlocked => lock_semaphore_internal(current_task),
} }
@ -124,6 +128,9 @@ fn create_idle_task() {
IDLE_TASKS.lock().push(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() -> ! { extern "C" fn task_entry() -> ! {
let func; let func;
{ {
@ -132,7 +139,7 @@ extern "C" fn task_entry() -> ! {
} }
func(); func();
{ {
CURRENT_TASKS.lock()[get_current_lapic_id()].as_mut().unwrap().task_state = TaskState::Terminated; terminate_current_task();
} }
yield_task(); yield_task();
panic!("Failed to terminate task"); panic!("Failed to terminate task");
@ -152,6 +159,9 @@ fn idle_main() {
hlt(); hlt();
} }
} }
pub fn terminate_tasks() {
TERMINATE_STASKS[get_current_lapic_id()].lock().clear();
}
pub fn setup_multitasking() -> ! { pub fn setup_multitasking() -> ! {
let rflags = get_rflags(); let rflags = get_rflags();
RFLAGS.store(rflags, core::sync::atomic::Ordering::SeqCst); RFLAGS.store(rflags, core::sync::atomic::Ordering::SeqCst);

@ -1 +1 @@
Subproject commit 437f7e1a0039d227d3952677c3f9f5ad9c814395 Subproject commit 7dae72155bf06b0edda9f3aea713da1d48c1c418