From 6ebc6ada0994db42bd496a0dc67408d2bc27a698 Mon Sep 17 00:00:00 2001 From: csd4ni3l <96988024+csd4ni3l@users.noreply.github.com> Date: Tue, 26 May 2026 09:53:59 +0200 Subject: [PATCH] Increase kernel stack size to 2mb, move from cooperative to timer preemption based scheduling, add correct save_lock on aarch64, add simple IPC (read, write, manage), and simple and unsecure SHM, add per-process kernel stacks, add copy_cstr_to_user, always use run_next for aarch64, remove primitives from the kernel --- GNUmakefile | 5 +- build_and_run.sh | 2 +- config.mk | 4 +- kernel/Cargo.lock | 5 +- kernel/Cargo.toml | 1 + kernel/src/arch/aarch64/init.rs | 36 ++- kernel/src/arch/aarch64/interrupts.rs | 67 ++--- kernel/src/arch/aarch64/mod.rs | 1 - kernel/src/arch/aarch64/paging.rs | 3 +- kernel/src/arch/aarch64/usermode.rs | 15 -- kernel/src/arch/arch.rs | 64 +++-- kernel/src/arch/syscall.rs | 308 ++++++++++++++++++---- kernel/src/arch/x86_64/gdt.rs | 57 ++-- kernel/src/arch/x86_64/init.rs | 28 +- kernel/src/arch/x86_64/interrupts.rs | 122 ++++++++- kernel/src/arch/x86_64/syscall.rs | 88 ++++--- kernel/src/config.rs | 2 +- kernel/src/driver/elf/loader.rs | 148 ++++++++++- kernel/src/driver/graphics/base.rs | 3 - kernel/src/driver/graphics/font_render.rs | 14 +- kernel/src/driver/graphics/mod.rs | 6 +- kernel/src/driver/graphics/primitives.rs | 178 ------------- kernel/src/driver/io/fs/assets.rs | 8 +- kernel/src/driver/ipc.rs | 143 ++++++++++ kernel/src/driver/mod.rs | 1 + kernel/src/driver/serial.rs | 3 +- kernel/src/main.rs | 13 +- kernel/src/mm/address_space.rs | 14 +- kernel/src/mm/mod.rs | 1 + kernel/src/mm/shm.rs | 18 ++ kernel/src/mm/usercopy.rs | 17 +- kernel/src/task/context.rs | 14 +- kernel/src/task/process.rs | 13 +- kernel/src/task/scheduler.rs | 132 ++++++++-- user/apps/doomgeneric | 2 +- user/init | 2 +- user/libxunil | 2 +- 37 files changed, 1065 insertions(+), 475 deletions(-) delete mode 100644 kernel/src/arch/aarch64/usermode.rs delete mode 100644 kernel/src/driver/graphics/base.rs delete mode 100644 kernel/src/driver/graphics/primitives.rs create mode 100644 kernel/src/driver/ipc.rs create mode 100644 kernel/src/mm/shm.rs diff --git a/GNUmakefile b/GNUmakefile index 72f6f3b..e624711 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -13,6 +13,9 @@ all: $(IMAGE_NAME).iso .PHONY: run run: run-$(KARCH) +.PHONY: debug +debug: debug-$(KARCH) + .PHONY: run-x86_64 run-x86_64: edk2-ovmf $(IMAGE_NAME).iso qemu-system-$(KARCH) \ @@ -64,7 +67,7 @@ debug-aarch64: edk2-ovmf $(IMAGE_NAME).iso -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -cdrom $(IMAGE_NAME).iso \ -semihosting-config enable=on,target=native \ - -d in_asm,int,mmu -dfilter 0xffffffff80000000..0xffffffff80010000 -D /tmp/qemu_trace.log 2>/dev/null \ + -d in_asm,int,mmu -D /tmp/qemu_trace.log 2>/dev/null \ $(QEMUFLAGS) edk2-ovmf: diff --git a/build_and_run.sh b/build_and_run.sh index cdc709f..541493b 100644 --- a/build_and_run.sh +++ b/build_and_run.sh @@ -1,4 +1,4 @@ -export KARCH=x86_64 +export KARCH=aarch64 bash build_libxunil.sh bash build_init.sh bash build_doomgeneric.sh diff --git a/config.mk b/config.mk index 2e45572..152d679 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -export KARCH ?= x86_64 +export KARCH ?= aarch64 export OUTPUT ?= kernel -export MEMORY ?= 4G +export MEMORY ?= 1G export TIMER_FREQUENCY_HZ ?= 1000 diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 0aa6674..d2de632 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -7,6 +7,7 @@ name = "XunilOS" version = "0.1.0" dependencies = [ "aarch64-cpu", + "bitflags", "fdt", "font8x8", "heapless", @@ -36,9 +37,9 @@ checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "byteorder" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 26b6825..9027837 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -9,6 +9,7 @@ test = false bench = false [dependencies] +bitflags = "2.11.1" font8x8 = { version = "0.3.1", default-features = false } heapless = "0.9.2" lazy_static = { version = "1.5.0", features = ["spin_no_std"] } diff --git a/kernel/src/arch/aarch64/init.rs b/kernel/src/arch/aarch64/init.rs index 5b0855b..477ea0b 100644 --- a/kernel/src/arch/aarch64/init.rs +++ b/kernel/src/arch/aarch64/init.rs @@ -1,18 +1,22 @@ use crate::{ - arch::aarch64::{ - heap::init_heap, - interrupts::init_interrupts, - paging::{AArchPageTable, initialize_paging_aarch64}, + arch::{ + aarch64::{ + heap::init_heap, + interrupts::init_interrupts, + paging::{AArchPageTable, initialize_paging_aarch64}, + }, + arch::KERNEL_MAPPER, }, - driver::io::virtio::scan_virtio_devices, + driver::{io::virtio::scan_virtio_devices, ipc::init_ipc}, + mm::shm::init_shm, }; use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse}; // needs to be page aligned since we map it into the page table #[repr(align(4096))] -pub struct Stack(pub [u8; 64 * 1024]); +pub struct Stack(pub [u8; 2048 * 1024]); -pub static KERNEL_STACK: Stack = Stack([0; 64 * 1024]); +pub static KERNEL_STACK: Stack = Stack([0; 2048 * 1024]); #[unsafe(naked)] pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) { @@ -21,10 +25,11 @@ pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) { "msr spsel, #1", "adrp x1, {stack}", "add x1, x1, :lo12:{stack}", - "add sp, x1, {size}", + "mov x2, {size}", + "add sp, x1, x2", "b kernel_main_aarch64", stack = sym KERNEL_STACK, - size = const 64 * 1024, + size = const 2048usize * 1024, ); } @@ -33,6 +38,8 @@ pub extern "C" fn init_aarch64(mapper: &mut AArchPageTable) { init_heap(mapper); scan_virtio_devices(); init_interrupts(); + init_ipc(); + init_shm(); } pub fn preinit_aarch64<'a>( @@ -40,10 +47,17 @@ pub fn preinit_aarch64<'a>( memory_map_response: &'a MemoryMapResponse, executable_address_response: &ExecutableAddressResponse, ) { - let mut mapper = initialize_paging_aarch64( + let mapper: AArchPageTable = initialize_paging_aarch64( hhdm_response, memory_map_response, executable_address_response, ); - unsafe { init_aarch64_trampoline(&mut mapper) }; + #[allow(static_mut_refs)] + unsafe { + *KERNEL_MAPPER.get_mut() = Some(mapper) + }; + #[allow(static_mut_refs)] + unsafe { + init_aarch64_trampoline(KERNEL_MAPPER.get_mut().as_mut().unwrap()) + }; } diff --git a/kernel/src/arch/aarch64/interrupts.rs b/kernel/src/arch/aarch64/interrupts.rs index 8be82d1..fc05054 100644 --- a/kernel/src/arch/aarch64/interrupts.rs +++ b/kernel/src/arch/aarch64/interrupts.rs @@ -1,15 +1,13 @@ use core::{arch::global_asm, sync::atomic::Ordering}; use crate::{ - arch::syscall::{check_and_reschedule, syscall_dispatch}, + arch::{arch::do_interrupt, syscall::syscall_dispatch}, config::TIMER_FREQUENCY_HZ, - driver::{ - graphics::framebuffer::with_framebuffer, - io::virtio::{KEYBOARD_SLOT, MOUSE_SLOT, input::input_interrupt}, - serial::with_serial_console, - timer::TIMER, + driver::io::virtio::{KEYBOARD_SLOT, MOUSE_SLOT, input::input_interrupt}, + task::{ + context::{UserContext, ctx_save}, + scheduler::check_and_reschedule, }, - task::context::{UserContext, ctx_save}, }; global_asm!( @@ -54,7 +52,7 @@ macro_rules! exception_handler { #[unsafe(no_mangle)] unsafe extern "C" fn $name() { core::arch::naked_asm!( - "sub sp, sp, #288", + "sub sp, sp, #304", "stp x0, x1, [sp, #0]", "stp x2, x3, [sp, #16]", "stp x4, x5, [sp, #32]", @@ -70,8 +68,6 @@ macro_rules! exception_handler { "stp x24, x25, [sp, #192]", "stp x26, x27, [sp, #208]", "stp x28, x29, [sp, #224]", - "mrs x2, sp_el0", - "str x2, [sp, #280]", "mrs x0, elr_el1", "mrs x1, spsr_el1", "stp x30, x0, [sp, #240]", @@ -79,6 +75,10 @@ macro_rules! exception_handler { "mrs x2, esr_el1", "mrs x3, far_el1", "stp x2, x3, [sp, #264]", + "mrs x2, sp_el0", + "str x2, [sp, #280]", + "add x4, sp, #304", // compute stack ptr ourself instead of accessing sp_el1 + "str x4, [sp, #288]", "mov x0, sp", concat!("bl ", stringify!($rust_handler)), "ldr x2, [sp, #280]", @@ -102,7 +102,7 @@ macro_rules! exception_handler { "ldp x24, x25, [sp, #192]", "ldp x26, x27, [sp, #208]", "ldp x28, x29, [sp, #224]", - "add sp, sp, #288", + "add sp, sp, #304", "eret" ); } @@ -203,33 +203,34 @@ unsafe extern "C" fn irq_handler(ctx: *mut UserContext) { match interrupt_id { 30 => { - TIMER.interrupt(); - - let t = TIMER.interrupt_count.load(Ordering::Relaxed); - - if t % 60 == 0 { - with_framebuffer(|fb| { - with_serial_console(|serial_console| serial_console.render(fb)); - fb.present(); - }); - } - let ticks = timer_ticks_per_irq(); unsafe { core::arch::asm!("msr cntp_tval_el0, {}", in(reg) ticks) }; unsafe { core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) 1u64) }; + + unsafe { + gic_eoi(interrupt_id); + } + + ctx_save(ctx); + do_interrupt(); + check_and_reschedule(); } interrupt_id if keyboard_irq == interrupt_id as u64 => { input_interrupt("kbd"); + unsafe { + gic_eoi(interrupt_id); + } } interrupt_id if mouse_irq == interrupt_id as u64 => { input_interrupt("mouse"); + unsafe { + gic_eoi(interrupt_id); + } } - _ => {} - } - - unsafe { - gic_eoi(interrupt_id); + _ => unsafe { + gic_eoi(interrupt_id); + }, } } @@ -237,8 +238,8 @@ fn handle_aborts(ec: u64, ctx: &UserContext) { match ec { ec if ec == 0x25 || ec == 0x24 => { panic!( - "Data abort at VA={:#x} ELR={:#x} ESR={:#x}", - ctx.far_el1, ctx.elr_el1, ctx.esr_el1 + "Data abort at VA={:#x} ELR={:#x} ESR={:#x} FAR={:#x}", + ctx.far_el1, ctx.elr_el1, ctx.esr_el1, ctx.far_el1 ); } ec if ec == 0x21 || ec == 0x20 => { @@ -276,8 +277,6 @@ unsafe extern "C" fn sync_handler_user(ctx: *mut UserContext) { } as u64; ctx_save(ctx as *const UserContext); - - let _ = unsafe { check_and_reschedule() }; } _ => handle_aborts(ec, ctx), }; @@ -296,10 +295,16 @@ pub unsafe fn run_next(ctx: *const UserContext, user_sp: u64) { core::arch::naked_asm!( "mov x30, x0", "msr sp_el0, x1", + "isb", + "ldr x2, [x30, #288]", + "mov sp, x2", + "isb", "ldr x2, [x30, #248]", "msr elr_el1, x2", + "isb", "ldr x3, [x30, #256]", "msr spsr_el1, x3", + "isb", "ldp x0, x1, [x30, #0]", "ldp x2, x3, [x30, #16]", "ldp x4, x5, [x30, #32]", diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 86fb8e3..db2574b 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -3,4 +3,3 @@ pub mod heap; pub mod init; pub mod interrupts; pub mod paging; -pub mod usermode; diff --git a/kernel/src/arch/aarch64/paging.rs b/kernel/src/arch/aarch64/paging.rs index 5310276..cc08e43 100644 --- a/kernel/src/arch/aarch64/paging.rs +++ b/kernel/src/arch/aarch64/paging.rs @@ -67,6 +67,7 @@ fn phys_to_virt(phys: u64) -> *mut u64 { pub fn tlb_flush() { unsafe { core::arch::asm!( + "dsb ishst", "tlbi vmalle1is", // invalidate TLB "dsb ish", // wait for tlb flush "isb", @@ -179,7 +180,7 @@ pub fn initialize_paging_aarch64<'a>( let stack_phys = KERNEL_STACK.0.as_ptr() as u64 - k_virt_base + k_phys_base; let stack_virt = KERNEL_STACK.0.as_ptr() as u64; - page_table.map_range(stack_virt, stack_phys, 64 * 1024, kernel_data_flags()); + page_table.map_range(stack_virt, stack_phys, 2048 * 1024, kernel_data_flags()); set_page_table(page_table.root_phys); tlb_flush(); diff --git a/kernel/src/arch/aarch64/usermode.rs b/kernel/src/arch/aarch64/usermode.rs deleted file mode 100644 index 5b3cee2..0000000 --- a/kernel/src/arch/aarch64/usermode.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[allow(unused_variables)] -pub fn enter_usermode_aarch64(entry: u64, stack_ptr: u64, should_swapgs: bool) -> ! { - unsafe { - core::arch::asm!( - "msr sp_el0, {sp}", - "msr elr_el1, {entry}", - "msr spsr_el1, xzr", - "isb", - "eret", - sp = in(reg) stack_ptr, - entry = in(reg) entry, - options(noreturn) - ) - }; -} diff --git a/kernel/src/arch/arch.rs b/kernel/src/arch/arch.rs index 65b261c..e71edd0 100644 --- a/kernel/src/arch/arch.rs +++ b/kernel/src/arch/arch.rs @@ -5,6 +5,7 @@ pub use crate::arch::x86_64::paging::FRAME_ALLOCATOR_X86_64 as FRAME_ALLOCATOR; use crate::arch::x86_64::{init::init_x86_64, usermode::enter_usermode_x86_64}; #[cfg(target_arch = "aarch64")] use limine::response::ExecutableAddressResponse; +use spin::mutex::Mutex; #[cfg(target_arch = "x86_64")] use x86_64::{ instructions::interrupts::without_interrupts, @@ -17,12 +18,18 @@ use aarch64_cpu::registers::{DAIF, Writeable}; #[cfg(target_arch = "aarch64")] pub use crate::arch::aarch64::paging::FRAME_ALLOCATOR_AARCH64 as FRAME_ALLOCATOR; #[cfg(target_arch = "aarch64")] -use crate::arch::aarch64::{ - init::init_aarch64, paging::AArchPageTable, usermode::enter_usermode_aarch64, -}; +use crate::arch::aarch64::{init::init_aarch64, paging::AArchPageTable}; -use crate::{driver::timer::TIMER, util::align_up}; -use core::{arch::asm, sync::atomic::AtomicU64}; +use crate::{ + config::TIMER_FREQUENCY_HZ, + driver::timer::TIMER, + task::scheduler::{CURRENT_PID, SCHEDULER}, + util::align_up, +}; +use core::{ + arch::asm, + sync::atomic::{AtomicU64, Ordering}, +}; use limine::{ memory_map::{Entry, EntryType}, response::{HhdmResponse, MemoryMapResponse}, @@ -33,6 +40,14 @@ const UART: *mut u8 = 0x0900_0000 as *mut u8; pub static HHDM_OFFSET: AtomicU64 = AtomicU64::new(0); +#[cfg(target_arch = "aarch64")] +type PageTable = AArchPageTable; + +#[cfg(target_arch = "x86_64")] +type PageTable<'a> = OffsetPageTable<'a>; + +pub static mut KERNEL_MAPPER: Mutex> = Mutex::new(None); + #[derive(Clone, Copy)] #[allow(dead_code)] pub struct UsableRegion { @@ -106,14 +121,12 @@ pub fn init(mapper: &mut AArchPageTable) { init_aarch64(mapper); } -#[cfg(target_arch = "x86_64")] -pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) { - enter_usermode_x86_64(entry, stack_ptr, should_swapgs); -} +pub static GLOBAL_TICK_COUNT: AtomicU64 = AtomicU64::new(0); -#[cfg(target_arch = "aarch64")] -pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) { - enter_usermode_aarch64(entry, stack_ptr, should_swapgs); +#[unsafe(no_mangle)] +pub extern "C" fn do_interrupt() { + TIMER.interrupt(); + GLOBAL_TICK_COUNT.fetch_add(1, Ordering::Relaxed); } #[cfg(target_arch = "x86_64")] @@ -123,18 +136,12 @@ pub fn safe_lock R>(f: F) -> R { #[cfg(target_arch = "aarch64")] pub fn safe_lock R>(f: F) -> R { - // #[cfg(target_arch = "aarch64")] - // { - // DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Masked + DAIF::F::Masked); - // } - + let old_daif: u64; + unsafe { core::arch::asm!("mrs {}, daif", out(reg) old_daif) }; + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); + DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Masked + DAIF::F::Masked); let r = f(); - - // #[cfg(target_arch = "aarch64")] - // { - // DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked); - // } - + unsafe { core::arch::asm!("msr daif, {}", in(reg) old_daif) }; r } @@ -175,17 +182,6 @@ pub fn idle() { } } -pub fn sleep(ticks: u64) { - let start = TIMER.now(); - while start.ticks_since() < ticks { - #[cfg(target_arch = "aarch64")] - { - DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked); - } - idle(); - } -} - pub fn infinite_idle() -> ! { loop { idle() diff --git a/kernel/src/arch/syscall.rs b/kernel/src/arch/syscall.rs index bd8f719..a9170b0 100644 --- a/kernel/src/arch/syscall.rs +++ b/kernel/src/arch/syscall.rs @@ -1,7 +1,10 @@ #![allow(dead_code, unused_imports)] +use core::sync::atomic::Ordering; + #[cfg(target_arch = "x86_64")] use crate::arch::x86_64::paging::create_and_map_multiple_pages; use alloc::vec; +use alloc::{string::String, vec::Vec}; #[cfg(target_arch = "x86_64")] use x86_64::{ PhysAddr, VirtAddr, @@ -18,7 +21,8 @@ use crate::driver::io::ps2::process_scancodes; #[cfg(target_arch = "aarch64")] use crate::driver::io::virtio::input::process_keycodes; use crate::{ - arch::arch::{FRAME_ALLOCATOR, serial_print, sleep}, + arch::arch::{FRAME_ALLOCATOR, GLOBAL_TICK_COUNT, serial_print}, + config::TIMER_FREQUENCY_HZ, driver::{ elf::loader::run_elf, graphics::framebuffer::{FRAMEBUFFER, USER_FB_BASE, with_framebuffer}, @@ -26,9 +30,14 @@ use crate::{ fs::vfs::{vfs_close, vfs_lseek, vfs_open, vfs_read}, keyboard::KeyboardEvent, }, + ipc::{Permissions, create_port, manage_port, read_port, write_port}, timer::TIMER, }, - print, + mm::{ + shm::{NEXT_SHM_ID, SHM_REGISTRY, SHM_SLOT_SIZE, SharedMemory, USER_SHM_BASE}, + usercopy::copy_cstr_to_user, + }, + print, println, task::{ process::ProcessState, scheduler::{SCHEDULER, current_pid}, @@ -64,6 +73,11 @@ const CLOCK_GETTIME: usize = 228; const EXIT_GROUP: usize = 231; const KBD_READ: usize = 666; const SLEEP: usize = 909090; // zzz haha +const IPC_CREATE: usize = 500; +const IPC_READ: usize = 501; +const IPC_WRITE: usize = 502; +const IPC_MANAGE: usize = 503; +const SHM_OPEN: usize = 600; pub const MAP_FRAMEBUFFER: usize = 5555; pub const FRAMEBUFFER_SWAP: usize = 6666; @@ -224,6 +238,7 @@ fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize { to_copy * size_of::(), ) { process.kbd_buffer.drain(0..to_copy); + return to_copy as isize; } else { return -1; @@ -367,22 +382,6 @@ pub fn exec(arg0: isize) -> isize { 0 } -pub fn set_reschedule(should_reschedule: bool) { - let pid = current_pid().unwrap_or(0); - - if pid == 0 { - return; - } - - let mut scheduler = SCHEDULER.lock(); - - if let Some(process) = scheduler.processes.get_mut(&pid) { - process.should_reschedule = should_reschedule; - } - - drop(scheduler); -} - pub fn exit() -> isize { serial_print("Process Exited."); let pid = current_pid().unwrap_or(0); @@ -415,31 +414,246 @@ pub fn exit() -> isize { crate::arch::arch::infinite_idle(); } -#[unsafe(no_mangle)] -pub unsafe extern "C" fn check_and_reschedule() -> usize { +fn sleep(ticks: isize) -> isize { + let ticks = (ticks as usize) * TIMER_FREQUENCY_HZ / 1000; + let pid = current_pid().unwrap_or(0); if pid == 0 { return 0; } - let should = SCHEDULER - .with_process(pid, |process| process.should_reschedule) - .unwrap_or(false); + SCHEDULER.with_process(pid, |process| { + process.info.wake_tick = Some(TIMER.now().elapsed() + ticks as u64); + process.state = ProcessState::Blocked; + }); - if !should { + 0 +} + +fn ipc_create(name_ptr: isize, default_permissions: isize) -> isize { + let pid = current_pid().unwrap_or(0); + + if pid == 0 { return 0; } - let next_task = SCHEDULER.next_task(); + let default_permissions = Permissions::from_bits_retain(default_permissions as u32); - if next_task == pid { + let name = match SCHEDULER.with_process(pid, |process| { + let address_space = process.address_space.as_mut().ok_or::(-1)?; + copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256) + }) { + Some(Ok(p)) => p, + _ => return -1, + }; + + create_port(name, pid, default_permissions); + + 0 +} + +fn ipc_read(name_ptr: isize, output_ptr: isize, from: isize) -> isize { + let pid = current_pid().unwrap_or(0); + if pid == 0 { + return 0; + } + let name = match SCHEDULER.with_process(pid, |process| { + let address_space = process.address_space.as_mut().ok_or::(-1)?; + copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256) + }) { + Some(Ok(p)) => p, + _ => return 0, + }; + return match read_port(name, pid, from as i64) { + Some(message) => { + let sender = message.from as isize; + SCHEDULER + .with_process(pid, |process| { + process + .address_space + .as_mut() + .map(|address_space| { + copy_cstr_to_user( + &mut address_space.mapper, + message.content, + output_ptr as *mut u8, + ) + }) + .unwrap_or(Ok(())) + }) + .unwrap_or(Ok(())) + .map(|_| sender) + .unwrap_or(0) + } + None => 0, + }; +} + +fn ipc_write(name_ptr: isize, message_ptr: isize) -> isize { + let pid = current_pid().unwrap_or(0); + + if pid == 0 { return 0; } - SCHEDULER.switch_to(next_task, true); + let (name, message) = match SCHEDULER.with_process(pid, |process| { + let address_space = process.address_space.as_mut().ok_or::(-1)?; + let name = copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256)?; + let message = + copy_cstr_from_user(&mut address_space.mapper, message_ptr as *const u8, 256)?; + Ok::<(String, String), isize>((name, message)) + }) { + Some(Ok((name, message))) => (name, message), + _ => return -1, + }; - 1 + return match write_port(name, pid, message) { + true => 0, + _ => -1, + }; +} + +fn ipc_manage(name_ptr: isize, pid_to_set: isize, permissions: isize) -> isize { + let pid = current_pid().unwrap_or(0); + + if pid == 0 { + return 0; + } + + let permissions = Permissions::from_bits_retain(permissions as u32); + + let name = match SCHEDULER.with_process(pid, |process| { + let address_space = process.address_space.as_mut().ok_or::(-1)?; + copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256) + }) { + Some(Ok(p)) => p, + _ => return -1, + }; + + return match manage_port(name, pid, pid_to_set as u64, permissions) { + true => 0, + _ => -1, + }; +} + +fn shm_open(name_ptr: isize, size: isize) -> isize { + if size > (SHM_SLOT_SIZE as f64 * 0.8) as isize { + return -1; + } + + let pid = current_pid().unwrap_or(0); + + if pid == 0 { + return 0; + } + + SCHEDULER + .with_process(pid, |process| -> Result { + let address_space = process.address_space.as_mut().ok_or::(-1)?; + + let name = copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256)?; + + #[allow(dead_code, unused_mut, unused_variables)] + let mut map_page = |virt: u64, phys: u64| {}; + + #[cfg(target_arch = "x86_64")] + let mut map_page = |virt: u64, phys: u64| unsafe { + let frame = PhysFrame::::containing_address(PhysAddr::new(phys)); + + let page = Page::::containing_address(VirtAddr::new(virt)); + + let mut frame_allocator = FRAME_ALLOCATOR.lock(); + + address_space + .mapper + .map_to( + page, + frame, + PageTableFlags::PRESENT + | PageTableFlags::WRITABLE + | PageTableFlags::USER_ACCESSIBLE + | PageTableFlags::NO_EXECUTE, + &mut *frame_allocator, + ) + .unwrap() + .flush(); + }; + + #[cfg(target_arch = "aarch64")] + let map_page = |virt: u64, phys: u64| { + use crate::arch::aarch64::paging::user_data_flags; + + address_space.mapper.map_page(virt, phys, user_data_flags()); + }; + + let size = size as usize; + + let mut shm_registry_opt = SHM_REGISTRY.lock(); + + let shm_registry = shm_registry_opt + .as_mut() + .expect("Could not get SHM registry"); + + if let Some(shared_memory) = shm_registry.get(&name) { + for (i, page) in shared_memory.phys_pages.iter().enumerate() { + map_page( + USER_SHM_BASE + shared_memory.id * SHM_SLOT_SIZE + i as u64 * 4096, + *page, + ); + } + #[cfg(target_arch = "aarch64")] + crate::arch::aarch64::paging::tlb_flush(); + + Ok(shared_memory.id as isize) + } else { + let mut page_count = align_up(size as u64, 4096) / 4096; + if size as u64 % 4096 == 0 { + // Map one extra page to tolerate end-boundary reads. + page_count += 1; + } + + let mut phys_pages = Vec::new(); + + #[cfg(target_arch = "aarch64")] + for _ in 0..page_count { + use crate::arch::aarch64::paging::alloc_frame; + + phys_pages.push(alloc_frame().expect("Could not allocate frame")); + } + + #[cfg(target_arch = "x86_64")] + for _ in 0..page_count { + let mut frame_allocator = FRAME_ALLOCATOR.lock(); + + phys_pages.push( + frame_allocator + .allocate_frame() + .expect("Could not allocate frame") + .start_address() + .as_u64(), + ); + } + + let id = NEXT_SHM_ID.fetch_add(1, Ordering::Relaxed); + + shm_registry.insert(name.clone(), SharedMemory { id, phys_pages }); + + let shared_memory = shm_registry.get(&name.clone()).ok_or::(-1)?; + for (i, page) in shared_memory.phys_pages.iter().enumerate() { + map_page( + USER_SHM_BASE + shared_memory.id * SHM_SLOT_SIZE + i as u64 * 4096, + *page, + ); + } + #[cfg(target_arch = "aarch64")] + crate::arch::aarch64::paging::tlb_flush(); + + Ok(shared_memory.id as isize) + } + }) + .unwrap_or(Err(-1)) + .unwrap_or(-1) } #[allow(unused_variables)] @@ -453,27 +667,6 @@ pub unsafe extern "C" fn syscall_dispatch( arg4: isize, arg5: isize, ) -> isize { - #[cfg(target_arch = "x86_64")] - interrupts::enable(); - - set_reschedule(match num { - BRK => false, - READ => false, - WRITE => false, - OPEN => true, - CLOSE => true, - LSEEK => false, - EXIT => true, - SLEEP => true, - CLOCK_GETTIME => false, - MAP_FRAMEBUFFER => false, - KBD_READ => false, - FRAMEBUFFER_SWAP => false, - GETPID => false, - EXECVE => true, - _ => false, - }); - match num { BRK => unsafe { sbrk(arg0) }, READ => read(arg0, arg1, arg2, arg3) as isize, @@ -498,12 +691,9 @@ pub unsafe extern "C" fn syscall_dispatch( CLOSE => close(arg0), LSEEK => vfs_lseek(arg0 as i64, arg1 as i64, arg2 as i32) as isize, EXIT => exit(), - SLEEP => { - sleep(arg0 as u64); - 0 - } + SLEEP => sleep(arg0), EXECVE => exec(arg0), - CLOCK_GETTIME => TIMER.now().elapsed() as isize, + CLOCK_GETTIME => ((TIMER.now().elapsed() as usize) * (TIMER_FREQUENCY_HZ / 1000)) as isize, MAP_FRAMEBUFFER => map_framebuffer(), KBD_READ => kbd_read(arg0 as *mut KeyboardEvent, arg1), GETPID => { @@ -514,12 +704,16 @@ pub unsafe extern "C" fn syscall_dispatch( _ => return pid as isize, } } + IPC_CREATE => ipc_create(arg0, arg1), + IPC_READ => ipc_read(arg0, arg1, arg2), + IPC_WRITE => ipc_write(arg0, arg1), + IPC_MANAGE => ipc_manage(arg0, arg1, arg2), + SHM_OPEN => shm_open(arg0, arg1), FRAMEBUFFER_SWAP => { - with_framebuffer(|fb| { - fb.present(); - }); + with_framebuffer(|fb| fb.present()); 0 } + _ => -38, // syscall not found } } diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/x86_64/gdt.rs index a40aeca..f7b321c 100644 --- a/kernel/src/arch/x86_64/gdt.rs +++ b/kernel/src/arch/x86_64/gdt.rs @@ -1,4 +1,8 @@ +use core::mem::MaybeUninit; + +use alloc::boxed::Box; use lazy_static::lazy_static; +use spin::mutex::Mutex; use x86_64::VirtAddr; use x86_64::instructions::segmentation::{CS, DS, ES, SS, Segment}; use x86_64::instructions::tables::load_tss; @@ -6,31 +10,35 @@ use x86_64::structures::{ gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector}, tss::TaskStateSegment, }; - +pub const TIMER_IST_INDEX: u16 = 1; pub const DOUBLE_FAULT_IST_INDEX: u16 = 0; -lazy_static! { - #[repr(C, align(4096))] - pub static ref TSS: TaskStateSegment = { - let mut tss = TaskStateSegment::new(); - tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; +pub static TSS_MUTEX: Mutex> = Mutex::new(None); - let stack_start = VirtAddr::from_ptr(&raw const STACK); - let stack_end = stack_start + STACK_SIZE as u64; - stack_end - }; - tss.privilege_stack_table[0] = { - const STACK_SIZE: usize = 4096 * 5; - static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; +#[allow(static_mut_refs)] +fn make_tss() -> &'static mut TaskStateSegment { + static mut TSS_STORAGE: MaybeUninit = MaybeUninit::uninit(); + + unsafe { + let tss_ptr = TSS_STORAGE.as_mut_ptr(); + tss_ptr.write(TaskStateSegment::new()); + let tss: &mut TaskStateSegment = &mut *tss_ptr; + + const STACK_SIZE: usize = 4096 * 5; + static mut DOUBLE_FAULT_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let df_start = VirtAddr::from_ptr(&DOUBLE_FAULT_STACK as *const _); + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = df_start + STACK_SIZE as u64; + + static mut PRIVILEGE_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let p_start = VirtAddr::from_ptr(&PRIVILEGE_STACK as *const _); + tss.privilege_stack_table[0] = p_start + STACK_SIZE as u64; + + static mut TIMER_IST_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + let ti_start = VirtAddr::from_ptr(&TIMER_IST_STACK as *const _); + tss.interrupt_stack_table[TIMER_IST_INDEX as usize] = ti_start + STACK_SIZE as u64; - let stack_start = VirtAddr::from_ptr(&raw const STACK); - let stack_end = stack_start + STACK_SIZE as u64; - stack_end - }; tss - }; + } } lazy_static! { @@ -45,6 +53,10 @@ lazy_static! { SegmentSelector ) ) = { + let tss: &'static mut TaskStateSegment = make_tss(); + let tss_ptr: *mut TaskStateSegment = tss as *mut _; + *TSS_MUTEX.lock() = Some(tss); + let mut gdt = GlobalDescriptorTable::new(); let kernel_code_selector = gdt.append(Descriptor::kernel_code_segment()); let kernel_data_selector = gdt.append(Descriptor::kernel_data_segment()); @@ -59,7 +71,10 @@ lazy_static! { let user_data_selector = gdt.append(Descriptor::user_data_segment()); let user_code_selector = gdt.append(Descriptor::user_code_segment()); - let tss_selector = gdt.append(Descriptor::tss_segment(&TSS)); + + let tss_ref: &'static TaskStateSegment = unsafe { &*tss_ptr }; + let tss_selector = gdt.append(Descriptor::tss_segment(tss_ref)); + ( gdt, ( diff --git a/kernel/src/arch/x86_64/init.rs b/kernel/src/arch/x86_64/init.rs index 5fd3993..92dbbcb 100644 --- a/kernel/src/arch/x86_64/init.rs +++ b/kernel/src/arch/x86_64/init.rs @@ -1,14 +1,18 @@ use crate::{ - arch::x86_64::{ - gdt::load_gdt_x86_64, - heap::init_heap, - interrupts::{PICS, init_idt_x86_64}, - kmi::setup_kmi, - paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64}, - syscall::init_syscalls, + arch::{ + arch::serial_print, + x86_64::{ + gdt::load_gdt_x86_64, + heap::init_heap, + interrupts::{PICS, init_idt_x86_64}, + kmi::setup_kmi, + paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64}, + syscall::init_syscalls, + }, }, config::TIMER_FREQUENCY_HZ, - driver::io::mouse::MOUSE, + driver::{io::mouse::MOUSE, ipc::init_ipc}, + mm::shm::init_shm, }; use x86_64::{ @@ -79,9 +83,8 @@ pub fn init_x86_64<'a>( } let kmi_status = setup_kmi(); - set_pit_interval(); - interrupts::enable(); + set_pit_interval(); let mut mapper = memory_management_init(hhdm_response, memory_map_response); @@ -89,7 +92,12 @@ pub fn init_x86_64<'a>( .ok() .expect("Failed to initalize heap"); + interrupts::enable(); + MOUSE.set_status(kmi_status); + init_ipc(); + init_shm(); + return mapper; } diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs index d4cbfe3..b14ef8b 100644 --- a/kernel/src/arch/x86_64/interrupts.rs +++ b/kernel/src/arch/x86_64/interrupts.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::Ordering; +use core::{arch::naked_asm, sync::atomic::Ordering}; use crate::{ arch::{arch::serial_print, x86_64::gdt}, @@ -15,6 +15,7 @@ use lazy_static::lazy_static; use pic8259::ChainedPics; use spin::Mutex; use x86_64::{ + VirtAddr, registers::control::Cr2, structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}, }; @@ -50,8 +51,10 @@ lazy_static! { idt.double_fault .set_handler_fn(double_fault_handler) .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); + idt[InterruptIndex::Timer.as_u8()] + .set_handler_addr(VirtAddr::new(timer_interrupt_handler as *const u8 as u64)) + .set_stack_index(gdt::TIMER_IST_INDEX); } - idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler); idt.page_fault.set_handler_fn(page_fault_handler); idt.general_protection_fault.set_handler_fn(gpf_handler); idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler); @@ -99,17 +102,114 @@ pub extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStack panic!("EXCEPTION: INVALID OPCODE\n{:#?}", stack_frame); } -extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { - TIMER.interrupt(); +#[unsafe(naked)] +pub fn timer_interrupt_handler() { + naked_asm!( + r#" + test qword ptr [rsp + 8], 3 + jz .from_kernel - let t = TIMER.interrupt_count.load(Ordering::Relaxed); - if t % 60 == 0 { - with_framebuffer(|fb| { - with_serial_console(|serial_console| serial_console.render(fb)); - fb.present(); - }); - } + swapgs + sub rsp, 144 + + mov [rsp + 0], r15 + mov [rsp + 8], r14 + mov [rsp + 16], r13 + mov [rsp + 24], r12 + mov [rsp + 32], r11 + mov [rsp + 40], r10 + mov [rsp + 48], r9 + mov [rsp + 56], r8 + mov [rsp + 64], rsi + mov [rsp + 72], rdi + mov [rsp + 80], rbp + mov [rsp + 88], rdx + mov [rsp + 96], rcx + mov [rsp + 104], rbx + mov [rsp + 112], rax + + mov rax, [rsp + 144 + 0] + mov [rsp + 128], rax + mov rax, [rsp + 144 + 16] + mov [rsp + 136], rax + mov rax, [rsp + 144 + 24] + mov [rsp + 120], rax + + mov rdi, rsp + + call ctx_save + call do_interrupt + call eoi + call check_and_reschedule + test rax, rax + jnz .switched + + mov rax, [rsp + 112] + mov rbx, [rsp + 104] + mov rcx, [rsp + 96] + mov rdx, [rsp + 88] + mov rbp, [rsp + 80] + mov rdi, [rsp + 72] + mov rsi, [rsp + 64] + mov r8, [rsp + 56] + mov r9, [rsp + 48] + mov r10, [rsp + 40] + mov r11, [rsp + 32] + mov r12, [rsp + 24] + mov r13, [rsp + 16] + mov r14, [rsp + 8] + mov r15, [rsp + 0] + + add rsp, 144 + swapgs + iretq + + .from_kernel: + push rbp + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + + call do_interrupt + call eoi + + pop rax + pop rbx + pop rcx + pop rdx + pop rsi + pop rdi + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + pop rbp + iretq + + .switched: + ud2 + "# + ) +} + +#[unsafe(no_mangle)] +extern "C" fn eoi() { unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); diff --git a/kernel/src/arch/x86_64/syscall.rs b/kernel/src/arch/x86_64/syscall.rs index 9b6a222..16eb8de 100644 --- a/kernel/src/arch/x86_64/syscall.rs +++ b/kernel/src/arch/x86_64/syscall.rs @@ -3,7 +3,7 @@ use core::arch::asm; use x86_64::instructions::tlb::flush_all; use crate::{ - arch::x86_64::gdt::{GDT, TSS}, + arch::x86_64::gdt::{GDT, TSS_MUTEX}, task::context::UserContext, }; @@ -21,7 +21,7 @@ pub struct PerCpuData { pub kernel_rsp: u64, } -static mut PER_CPU: PerCpuData = PerCpuData { +pub static mut PER_CPU: PerCpuData = PerCpuData { user_rsp: 0, kernel_rsp: 0, }; @@ -65,8 +65,9 @@ pub fn init_syscalls() { asm!("mov gs, ax", in("ax") 0u16); - let kernel_stack_top = TSS.privilege_stack_table[0].as_u64(); - PER_CPU.kernel_rsp = kernel_stack_top; + if let Some(tss) = TSS_MUTEX.lock().as_ref() { + PER_CPU.kernel_rsp = tss.privilege_stack_table[0].as_u64(); + } #[allow(function_casts_as_integer)] wrmsr(IA32_LSTAR, syscall_entry as u64); // set syscall entry function @@ -94,7 +95,7 @@ unsafe extern "C" fn syscall_entry() { mov gs:[0], rsp mov rsp, gs:[8] - sub rsp, 128 + sub rsp, 144 mov qword ptr [rsp + 0], r15 mov qword ptr [rsp + 8], r14 @@ -115,6 +116,11 @@ unsafe extern "C" fn syscall_entry() { mov rax, qword ptr gs:[0] mov qword ptr [rsp + 120], rax + mov rax, qword ptr [rsp + 96] + mov qword ptr [rsp + 128], rax + mov rax, qword ptr [rsp + 32] + mov qword ptr [rsp + 136], rax + mov rbx, rsp // rbx = frame base // ctx_save(frame) @@ -123,7 +129,6 @@ unsafe extern "C" fn syscall_entry() { call ctx_save mov rsp, rbx - // syscall_dispatch(num,arg0..arg5) mov rdi, qword ptr [rbx + 112] mov rsi, qword ptr [rbx + 72] mov rdx, qword ptr [rbx + 64] @@ -131,28 +136,23 @@ unsafe extern "C" fn syscall_entry() { mov r8, qword ptr [rbx + 40] mov r9, qword ptr [rbx + 56] - lea rsp, [rbx - 24] // rsp%16==8 before call + lea rsp, [rbx - 24] mov rax, qword ptr [rbx + 48] mov qword ptr [rsp + 0], rax call syscall_dispatch mov rsp, rbx - // save return value into frame (so normal restore uses it) mov qword ptr [rbx + 112], rax - // ctx_save(frame) again so saved_ctx.rax reflects return value mov rdi, rbx lea rsp, [rbx - 8] call ctx_save mov rsp, rbx - // maybe switch tasks (this should not return if it switches) - lea rsp, [rbx - 8] - call check_and_reschedule - mov rsp, rbx - - test rax, rax - jnz .done + mov rax, qword ptr [rsp + 128] + mov qword ptr [rsp + 96], rax + mov rax, qword ptr [rsp + 136] + mov qword ptr [rsp + 32], rax // restore registers from frame mov rax, qword ptr [rsp + 112] @@ -165,12 +165,11 @@ unsafe extern "C" fn syscall_entry() { mov r8, qword ptr [rsp + 56] mov r9, qword ptr [rsp + 48] mov r10, qword ptr [rsp + 40] - mov r11, qword ptr [rsp + 32] // rflags — sysretq loads RFLAGS from r11 + mov r11, qword ptr [rsp + 32] mov r12, qword ptr [rsp + 24] mov r13, qword ptr [rsp + 16] mov r14, qword ptr [rsp + 8] mov r15, qword ptr [rsp + 0] - // don't restore rsp from frame — use the user rsp we saved in gs:[0] mov rsp, qword ptr gs:[0] swapgs sysretq @@ -182,27 +181,40 @@ unsafe extern "C" fn syscall_entry() { #[unsafe(naked)] #[unsafe(no_mangle)] -pub unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) { +pub unsafe fn run_next(ctx: *const UserContext, user_rsp: u64, user_cs: u64, user_ss: u64) { core::arch::naked_asm!( - "mov gs:[0], rsi", // store new user rsp - "mov rsp, rdi", - "mov r15, qword ptr [rsp + 0]", - "mov r14, qword ptr [rsp + 8]", - "mov r13, qword ptr [rsp + 16]", - "mov r12, qword ptr [rsp + 24]", - "mov r11, qword ptr [rsp + 32]", // rflags - "mov r10, qword ptr [rsp + 40]", - "mov r9, qword ptr [rsp + 48]", - "mov r8, qword ptr [rsp + 56]", - "mov rsi, qword ptr [rsp + 64]", - "mov rdi, qword ptr [rsp + 72]", - "mov rbp, qword ptr [rsp + 80]", - "mov rdx, qword ptr [rsp + 88]", - "mov rcx, qword ptr [rsp + 96]", // rip - "mov rbx, qword ptr [rsp + 104]", - "mov rax, qword ptr [rsp + 112]", - "mov rsp, qword ptr [rsp + 120]", // user rsp + // rdi = ctx, rsi = user_rsp, rdx = user_cs, rcx = user_ss + "mov gs:[0], rsi", + "mov rax, rcx", + "and eax, 0xFFFC", + "mov ds, ax", + "mov es, ax", + // save ctx ptr on stack, then build iret frame + "push rdi", + "push rcx", + "push rsi", + "push qword ptr [rdi + 136]", + "push rdx", + "push qword ptr [rdi + 128]", + // load all gp regs via rdi + "mov r15, qword ptr [rdi + 0]", + "mov r14, qword ptr [rdi + 8]", + "mov r13, qword ptr [rdi + 16]", + "mov r12, qword ptr [rdi + 24]", + "mov r11, qword ptr [rdi + 32]", + "mov r10, qword ptr [rdi + 40]", + "mov r9, qword ptr [rdi + 48]", + "mov r8, qword ptr [rdi + 56]", + "mov rsi, qword ptr [rdi + 64]", + "mov rbp, qword ptr [rdi + 80]", + "mov rdx, qword ptr [rdi + 88]", + "mov rcx, qword ptr [rdi + 96]", + // ctx_ptr is at [rsp + 40] + "mov rax, qword ptr [rsp + 40]", + "mov rbx, qword ptr [rax + 104]", + "mov rdi, qword ptr [rax + 72]", + "mov rax, qword ptr [rax + 112]", "swapgs", - "sysretq", + "iretq", ); } diff --git a/kernel/src/config.rs b/kernel/src/config.rs index 1a3ed00..82f0fdc 100644 --- a/kernel/src/config.rs +++ b/kernel/src/config.rs @@ -1,2 +1,2 @@ pub const TIMER_FREQUENCY_HZ: usize = 1000; -pub const KARCH: &str = "x86_64"; \ No newline at end of file +pub const KARCH: &str = "aarch64"; \ No newline at end of file diff --git a/kernel/src/driver/elf/loader.rs b/kernel/src/driver/elf/loader.rs index 0fee253..e3927a5 100644 --- a/kernel/src/driver/elf/loader.rs +++ b/kernel/src/driver/elf/loader.rs @@ -1,7 +1,10 @@ -use core::ptr::null; +use core::{ + ptr::null, + sync::atomic::{AtomicU64, Ordering}, +}; #[cfg(target_arch = "x86_64")] -use crate::arch::x86_64::paging::create_and_map_multiple_pages; +use crate::arch::x86_64::{interrupts, paging::create_and_map_multiple_pages}; #[allow(unused_imports)] use crate::driver::elf::{ header::{ @@ -13,11 +16,19 @@ use crate::driver::elf::{ #[cfg(target_arch = "aarch64")] use crate::arch::aarch64::paging::{ - AArchPageTable, create_and_map_multiple_pages, user_data_flags, + AArchPageTable, create_and_map_multiple_pages, kernel_data_flags, user_data_flags, +}; +use crate::{ + arch::arch::KERNEL_MAPPER, + mm::address_space::AddressSpace, + println, + task::{context::UserContext, scheduler::SCHEDULER}, }; -use crate::{mm::address_space::AddressSpace, println, task::scheduler::SCHEDULER}; #[cfg(target_arch = "x86_64")] -use x86_64::structures::paging::{OffsetPageTable, PageTableFlags}; +use x86_64::{ + registers::control::{Cr3, Cr3Flags}, + structures::paging::{OffsetPageTable, PageTableFlags, PhysFrame, Size4KiB}, +}; #[cfg(target_arch = "aarch64")] type PageTable = AArchPageTable; @@ -25,6 +36,29 @@ type PageTable = AArchPageTable; #[cfg(target_arch = "x86_64")] type PageTable<'a> = OffsetPageTable<'a>; +static mut NEXT_KERNEL_STACK_ADDR: AtomicU64 = AtomicU64::new(0xFFFF_FFFF_7000_0000); + +pub fn next_kstack(mapper: &mut PageTable) -> u64 { + const PAGES: u64 = 2048; + #[allow(static_mut_refs)] + let addr = unsafe { NEXT_KERNEL_STACK_ADDR.fetch_add(PAGES * 4096, Ordering::Relaxed) }; + + #[cfg(target_arch = "aarch64")] + create_and_map_multiple_pages(mapper, PAGES, addr, kernel_data_flags()); + + #[cfg(target_arch = "x86_64")] + create_and_map_multiple_pages( + mapper, + PAGES, + addr, + PageTableFlags::PRESENT | PageTableFlags::WRITABLE, + ); + + assert!(addr & 0xF == 0, "kernel stack isn't 16 byte aligned"); + + addr + PAGES * 4096 +} + pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool { #[cfg(target_arch = "x86_64")] let required_machine = EM_X86_64; @@ -73,20 +107,54 @@ pub fn load_file(mapper: &mut PageTable, elf_bytes: &[u8]) -> (*const u8, u64) { } pub fn run_elf(file_bytes: &[u8], should_swapgs: bool, switch_to: bool) { + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("msr daifset, #2") + }; + + #[cfg(target_arch = "x86_64")] + { + use x86_64::instructions::interrupts; + interrupts::disable(); + } + let stack_base: u64 = 0x0000_7fff_0000_0000; let page_count = 4096; // 16 mib let page_size = 0x1000u64; let stack_top = stack_base + (page_count as u64 * page_size); if let Some(mut address_space) = AddressSpace::new() { + #[cfg(target_arch = "aarch64")] + let previous_pt_ptr: u64; + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("mrs {}, ttbr0_el1", out(reg) previous_pt_ptr) + }; + + #[cfg(target_arch = "x86_64")] + let previous_pt: (PhysFrame, Cr3Flags); + + #[cfg(target_arch = "x86_64")] + { + use x86_64::registers::control::Cr3; + + previous_pt = Cr3::read(); + } + address_space.use_address_space(); let (entry_point, heap_base) = load_file(&mut address_space.mapper, file_bytes); println!("Entry point: {:?}", entry_point); + #[allow(static_mut_refs)] let process_pid = SCHEDULER - .spawn_process(entry_point as u64, stack_top, heap_base) + .spawn_process( + entry_point as u64, + stack_top, + next_kstack(unsafe { KERNEL_MAPPER.get_mut().as_mut().unwrap() }), + heap_base, + ) .unwrap(); #[cfg(target_arch = "aarch64")] @@ -109,8 +177,76 @@ pub fn run_elf(file_bytes: &[u8], should_swapgs: bool, switch_to: bool) { process.address_space = Some(address_space) }); + #[cfg(target_arch = "aarch64")] + SCHEDULER.with_process(process_pid, |process| { + process.saved_ctx = Some(UserContext { + x0: 0, + x1: 0, + x2: 0, + x3: 0, + x4: 0, + x5: 0, + x6: 0, + x7: 0, + x8: 0, + x9: 0, + x10: 0, + x11: 0, + x12: 0, + x13: 0, + x14: 0, + x15: 0, + x16: 0, + x17: 0, + x18: 0, + x19: 0, + x20: 0, + x21: 0, + x22: 0, + x23: 0, + x24: 0, + x25: 0, + x26: 0, + x27: 0, + x28: 0, + x29: 0, + x30: 0, + elr_el1: entry_point as u64, + spsr_el1: 0, + esr_el1: 0, + far_el1: 0, + sp_el0: process.stack_top, + sp_el1: process.kernel_stack_top, + _pad1: 0, + }); + }); + if switch_to { + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("msr daifset, #2") + }; SCHEDULER.switch_to(process_pid, should_swapgs); + } else { + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!( + "msr ttbr0_el1, {root}", + "dsb ishst", + "tlbi vmalle1is", + "dsb ish", + "isb", + root = in(reg) previous_pt_ptr + ); + } + + #[cfg(target_arch = "x86_64")] + unsafe { + use x86_64::instructions::interrupts; + + Cr3::write(previous_pt.0, previous_pt.1); + interrupts::enable(); + }; } } else { return; diff --git a/kernel/src/driver/graphics/base.rs b/kernel/src/driver/graphics/base.rs deleted file mode 100644 index 0c7bed4..0000000 --- a/kernel/src/driver/graphics/base.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn rgb(r: u8, g: u8, b: u8) -> u32 { - ((r as u32) << 16) | ((g as u32) << 8) | (b as u32) -} diff --git a/kernel/src/driver/graphics/font_render.rs b/kernel/src/driver/graphics/font_render.rs index 51e1dcf..2dd48a4 100644 --- a/kernel/src/driver/graphics/font_render.rs +++ b/kernel/src/driver/graphics/font_render.rs @@ -1,9 +1,21 @@ extern crate font8x8; use crate::driver::graphics::framebuffer::Framebuffer; -use crate::driver::graphics::primitives::rectangle_filled; use font8x8::legacy::BASIC_LEGACY; +pub fn rectangle_filled( + framebuffer: &mut Framebuffer, + x: usize, + y: usize, + width: usize, + height: usize, + color: u32, +) { + for yy in y..y + height { + framebuffer.fill_span(x, yy, width, color); + } +} + pub fn render_char( framebuffer: &mut Framebuffer, start_x: usize, diff --git a/kernel/src/driver/graphics/mod.rs b/kernel/src/driver/graphics/mod.rs index e84f8b9..66487e0 100644 --- a/kernel/src/driver/graphics/mod.rs +++ b/kernel/src/driver/graphics/mod.rs @@ -1,4 +1,6 @@ -pub mod base; pub mod font_render; pub mod framebuffer; -pub mod primitives; + +pub fn rgb(r: u8, g: u8, b: u8) -> u32 { + ((r as u32) << 16) | ((g as u32) << 8) | (b as u32) +} diff --git a/kernel/src/driver/graphics/primitives.rs b/kernel/src/driver/graphics/primitives.rs deleted file mode 100644 index d0f7a6e..0000000 --- a/kernel/src/driver/graphics/primitives.rs +++ /dev/null @@ -1,178 +0,0 @@ -use crate::driver::graphics::framebuffer::Framebuffer; - -pub fn line(framebuffer: &mut Framebuffer, x0: usize, y0: usize, x1: usize, y1: usize, color: u32) { - if y0 == y1 { - let (xa, xb) = if x0 <= x1 { (x0, x1) } else { (x1, x0) }; - framebuffer.fill_span(xa, y0, xb - xa + 1, color); - return; - } - if x0 == x1 { - let (ya, yb) = if y0 <= y1 { (y0, y1) } else { (y1, y0) }; - for yy in ya..=yb { - framebuffer.put_pixel(x0, yy, color); - } - return; - } - - let mut x0 = x0 as isize; - let mut y0 = y0 as isize; - let x1 = x1 as isize; - let y1 = y1 as isize; - - let mut dx: isize = x1 - x0; - let mut dy: isize = y1 - y0; - - if dx < 0 { - dx = -dx; - } - if dy < 0 { - dy = -dy; - } - - let step_x: isize = if x0 < x1 { 1 } else { -1 }; - let step_y: isize = if y0 < y1 { 1 } else { -1 }; - - let mut error: isize = dx - dy; - - loop { - framebuffer.put_pixel(x0 as usize, y0 as usize, color); - - let e2: isize = 2 * error; - if e2 > -dy { - error -= dy; - x0 += step_x; - } - if e2 < dx { - error += dx; - y0 += step_y; - } - - if x0 == x1 && y0 == y1 { - break; - } - } -} - -pub fn triangle_outline( - framebuffer: &mut Framebuffer, - x1: usize, - y1: usize, - x2: usize, - y2: usize, - x3: usize, - y3: usize, - color: u32, -) { - line(framebuffer, x1, y1, x2, y2, color); - line(framebuffer, x1, y1, x3, y3, color); - line(framebuffer, x2, y2, x3, y3, color); -} - -pub fn circle_outline( - framebuffer: &mut Framebuffer, - cx: usize, - cy: usize, - radius: usize, - color: u32, -) { - let mut x = radius as isize; - let mut y: isize = 0; - let mut d = 1 - x; - let cx = cx as isize; - let cy = cy as isize; - - #[inline(always)] - fn plot_points( - framebuffer: &mut Framebuffer, - cx: isize, - cy: isize, - x: isize, - y: isize, - color: u32, - ) { - framebuffer.put_pixel((cx + x) as usize, (cy + y) as usize, color); - framebuffer.put_pixel((cx + y) as usize, (cy + x) as usize, color); - framebuffer.put_pixel((cx - y) as usize, (cy + x) as usize, color); - framebuffer.put_pixel((cx - x) as usize, (cy + y) as usize, color); - framebuffer.put_pixel((cx - x) as usize, (cy - y) as usize, color); - framebuffer.put_pixel((cx - y) as usize, (cy - x) as usize, color); - framebuffer.put_pixel((cx + y) as usize, (cy - x) as usize, color); - framebuffer.put_pixel((cx + x) as usize, (cy - y) as usize, color); - } - - while y <= x { - plot_points(framebuffer, cx, cy, x, y, color); - y += 1; - - if d <= 0 { - d += 2 * y + 1; - } else { - x -= 1; - d += 2 * (y - x) + 1; - } - } -} - -pub fn circle_filled( - framebuffer: &mut Framebuffer, - x0: usize, - y0: usize, - radius: usize, - color: u32, -) { - let mut x = radius as isize; - let mut y: isize = 0; - let mut x_change: isize = 1 - (radius as isize * 2); - let mut y_change: isize = 0; - let mut radius_error: isize = 0; - - while x >= y { - let mut i = x0 as isize - x; - while i <= x0 as isize + x { - framebuffer.put_pixel(i as usize, (y0 as isize + y) as usize, color); - framebuffer.put_pixel(i as usize, (y0 as isize - y) as usize, color); - i += 1; - } - let mut i = x0 as isize - y; - while i <= x0 as isize + y { - framebuffer.put_pixel(i as usize, (y0 as isize + x) as usize, color); - framebuffer.put_pixel(i as usize, (y0 as isize - x) as usize, color); - i += 1; - } - y += 1; - radius_error += y_change; - y_change += 2; - if (radius_error * 2) + x_change > 0 { - x -= 1; - radius_error += x_change; - x_change += 2; - } - } -} - -pub fn rectangle_filled( - framebuffer: &mut Framebuffer, - x: usize, - y: usize, - width: usize, - height: usize, - color: u32, -) { - for yy in y..y + height { - framebuffer.fill_span(x, yy, width, color); - } -} - -pub fn rectangle_outline( - framebuffer: &mut Framebuffer, - x: usize, - y: usize, - width: usize, - height: usize, - color: u32, -) { - line(framebuffer, x, y, x + width, y, color); // bottomleft -> bottomright - line(framebuffer, x, y + height, x + width, y + height, color); // topleft -> topright - line(framebuffer, x, y, x, y + height, color); // bottomleft -> topleft - line(framebuffer, x + width, y, x + width, y + height, color); // bottomright -> topright -} diff --git a/kernel/src/driver/io/fs/assets.rs b/kernel/src/driver/io/fs/assets.rs index fe6a6ed..92d9f39 100644 --- a/kernel/src/driver/io/fs/assets.rs +++ b/kernel/src/driver/io/fs/assets.rs @@ -1,5 +1,5 @@ -pub static INIT_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/init"); +pub static INIT_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/init"); pub static DOOM_WAD: &[u8] = include_bytes!("../../../../../assets/doom1.wad"); -pub static DOOM_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/doomgeneric"); -pub static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/helloworld.elf"); -pub static BADAPPLE_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/badapple"); \ No newline at end of file +pub static DOOM_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/doomgeneric"); +pub static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/helloworld.elf"); +pub static BADAPPLE_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/badapple"); \ No newline at end of file diff --git a/kernel/src/driver/ipc.rs b/kernel/src/driver/ipc.rs new file mode 100644 index 0000000..2754d90 --- /dev/null +++ b/kernel/src/driver/ipc.rs @@ -0,0 +1,143 @@ +use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec}; +use bitflags::bitflags; +use spin::Mutex; + +use crate::arch::arch::safe_lock; + +type PID = u64; + +bitflags! { + #[derive(Debug)] + pub struct Permissions: u32 { + const READ = 1 << 0; + const WRITE = 1 << 1; + const MANAGE = 1 << 2; + } +} + +#[derive(Clone)] +pub struct Message { + pub from: PID, + pub content: String, +} + +pub struct Port { + pub messages: Vec, + pub permissions: BTreeMap, + pub default_permissions: Permissions, +} + +pub static PORTS: Mutex>> = Mutex::new(None); + +pub fn init_ipc() { + *PORTS.lock() = Some(BTreeMap::new()); +} + +pub fn create_port(name: String, pid: u64, default_permissions: Permissions) { + let mut permissions = BTreeMap::new(); + permissions.insert( + pid as PID, + Permissions::READ | Permissions::WRITE | Permissions::MANAGE, + ); + + safe_lock(|| { + PORTS.lock().as_mut().expect("IPC not initialized").insert( + name, + Port { + messages: Vec::new(), + permissions, + default_permissions, + }, + ); + }); +} + +pub fn read_port(name: String, pid: u64, from: i64) -> Option { + safe_lock(|| { + let mut guard = PORTS.lock(); + let ports = guard.as_mut().expect("IPC not initialized"); + + if let Some(port) = ports.get_mut(&name) { + let permissions = port + .permissions + .get(&pid) + .unwrap_or(&port.default_permissions); + + if !permissions.contains(Permissions::READ) { + return None; + } + + if from != -1 { + if let Some(index) = port + .messages + .iter() + .position(|message| message.from == from as u64) + { + return Some(port.messages.remove(index)); + } + + None + } else { + if let Some(index) = port + .messages + .iter() + .position(|message| message.from != pid as u64) + { + return Some(port.messages.remove(index)); + } + None + } + } else { + None + } + }) +} + +pub fn write_port(name: String, pid: u64, message: String) -> bool { + return safe_lock(|| { + let mut guard = PORTS.lock(); + let ports = guard.as_mut().expect("IPC not initialized"); + if let Some(port) = ports.get_mut(&name) { + let permissions = port + .permissions + .get(&pid) + .unwrap_or(&port.default_permissions); + + if permissions.contains(Permissions::WRITE) { + port.messages.push(Message { + from: pid, + content: message, + }); + + return true; + } else { + return false; + } + } else { + return false; + } + }); +} + +pub fn manage_port(name: String, pid: u64, pid_to_set: u64, new_permissions: Permissions) -> bool { + return safe_lock(|| { + let mut guard = PORTS.lock(); + let ports = guard.as_mut().expect("IPC not initialized"); + if let Some(port) = ports.get_mut(&name) { + let permissions = port + .permissions + .get(&pid) + .unwrap_or(&port.default_permissions); + + if permissions.contains(Permissions::MANAGE) { + port.permissions.insert(pid_to_set, new_permissions); + + return true; + } else { + return false; + } + } else { + return false; + } + }); +} diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 0893fa6..fe9b2c6 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -1,5 +1,6 @@ pub mod elf; pub mod graphics; pub mod io; +pub mod ipc; pub mod serial; pub mod timer; diff --git a/kernel/src/driver/serial.rs b/kernel/src/driver/serial.rs index 9ef5a4d..be9c3ef 100644 --- a/kernel/src/driver/serial.rs +++ b/kernel/src/driver/serial.rs @@ -2,7 +2,7 @@ use crate::alloc::string::ToString; use crate::arch::arch::serial_print; use crate::driver::graphics::font_render::render_text; use crate::driver::graphics::framebuffer::Framebuffer; -use crate::{arch::arch::safe_lock, driver::graphics::base::rgb}; +use crate::{arch::arch::safe_lock, driver::graphics::rgb}; use alloc::string::String; use core::fmt::{self, Write}; use spin::Mutex; @@ -15,6 +15,7 @@ pub struct ConsoleWriter<'a> { impl Write for ConsoleWriter<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { + serial_print(s); self.console.print(s, self.fb); Ok(()) } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 3c56f78..0caefba 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -18,8 +18,12 @@ use limine::{ #[cfg(target_arch = "aarch64")] use crate::arch::aarch64::paging::AArchPageTable; +#[cfg(target_arch = "x86_64")] +use crate::arch::arch::KERNEL_MAPPER; #[cfg(target_arch = "aarch64")] -use crate::driver::{graphics::primitives::rectangle_filled, io::virtio::input::init_keyboard}; +use crate::driver::io::virtio::input::init_keyboard; +#[cfg(target_arch = "aarch64")] +use crate::util::U64Buf; #[cfg(target_arch = "aarch64")] use aarch64_cpu::registers::{DAIF, Writeable}; @@ -30,8 +34,8 @@ use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_p use crate::driver::{ elf::loader::run_elf, graphics::{ - base::rgb, framebuffer::{init_framebuffer, with_framebuffer}, + rgb, }, io::fs::assets::INIT_ELF, serial::{ConsoleWriter, init_serial_console, with_serial_console}, @@ -234,6 +238,11 @@ pub unsafe fn kernel_main_x86_64() -> ! { init_keyboard(); + #[allow(static_mut_refs)] + unsafe { + *KERNEL_MAPPER.get_mut() = Some(mapper) + }; + if let Some(date_at_boot_response) = DATE_AT_BOOT_REQUEST.get_response() { TIMER.set_date_at_boot(date_at_boot_response.timestamp().as_secs()); } else { diff --git a/kernel/src/mm/address_space.rs b/kernel/src/mm/address_space.rs index 8d0ecb2..2dab66f 100644 --- a/kernel/src/mm/address_space.rs +++ b/kernel/src/mm/address_space.rs @@ -8,7 +8,7 @@ use x86_64::{ }; #[cfg(target_arch = "aarch64")] -use crate::arch::aarch64::paging::{AArchPageTable, tlb_flush}; +use crate::arch::aarch64::paging::AArchPageTable; #[cfg(target_arch = "x86_64")] use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET}; @@ -90,11 +90,13 @@ impl AddressSpace { core::arch::asm!( "msr ttbr0_el1, {root}", "isb", - root = in(reg) self.ttbr0_phys - ); - } - - tlb_flush(); + "dsb ishst", + "tlbi vmalle1is", + "dsb ish", + "isb", + root = in(reg) self.mapper.root_phys + ) + }; } } diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 7c49e7e..bf38deb 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -1,3 +1,4 @@ pub mod address_space; pub mod heap; +pub mod shm; pub mod usercopy; diff --git a/kernel/src/mm/shm.rs b/kernel/src/mm/shm.rs new file mode 100644 index 0000000..be2ff4a --- /dev/null +++ b/kernel/src/mm/shm.rs @@ -0,0 +1,18 @@ +use core::sync::atomic::AtomicU64; + +use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec}; +use spin::mutex::Mutex; + +pub const USER_SHM_BASE: u64 = 0x0000_7000_0000_0000; +pub static SHM_REGISTRY: Mutex>> = Mutex::new(None); +pub static NEXT_SHM_ID: AtomicU64 = AtomicU64::new(1); +pub const SHM_SLOT_SIZE: u64 = 64 * 1024 * 1024; + +pub struct SharedMemory { + pub id: u64, + pub phys_pages: Vec, +} + +pub fn init_shm() { + *SHM_REGISTRY.lock() = Some(BTreeMap::new()); +} diff --git a/kernel/src/mm/usercopy.rs b/kernel/src/mm/usercopy.rs index 9f73f1e..95a2a48 100644 --- a/kernel/src/mm/usercopy.rs +++ b/kernel/src/mm/usercopy.rs @@ -1,4 +1,5 @@ use alloc::{ + ffi::CString, string::{String, ToString}, vec::Vec, }; @@ -128,7 +129,7 @@ pub fn copy_cstr_from_user( return Err(-14); } - let mut buf: Vec = Vec::with_capacity(64); + let mut buf: Vec = Vec::with_capacity(max_len); for i in 0..max_len { let mut byte = 0u8; @@ -143,3 +144,17 @@ pub fn copy_cstr_from_user( Err(-36) } + +pub fn copy_cstr_to_user( + mapper: &mut PageTable, + kernel_str: String, + user_ptr: *mut u8, +) -> Result<(), isize> { + if user_ptr.is_null() { + return Err(-14); + } + let c_string = CString::new(kernel_str).map_err(|_| -14isize)?; + let len = c_string.count_bytes(); + let _ = copy_to_user(mapper, user_ptr, c_string.into_raw() as *const u8, len); + Ok(()) +} diff --git a/kernel/src/task/context.rs b/kernel/src/task/context.rs index 89fca13..c058152 100644 --- a/kernel/src/task/context.rs +++ b/kernel/src/task/context.rs @@ -4,12 +4,11 @@ use crate::task::scheduler::{SCHEDULER, current_pid}; #[repr(C)] #[derive(Clone, Copy)] pub struct UserContext { - //general purpose data regs pub r15: u64, pub r14: u64, pub r13: u64, pub r12: u64, - pub r11: u64, // rflags + pub r11: u64, pub r10: u64, pub r9: u64, pub r8: u64, @@ -17,10 +16,12 @@ pub struct UserContext { pub rdi: u64, pub rbp: u64, pub rdx: u64, - pub rcx: u64, // rip + pub rcx: u64, pub rbx: u64, pub rax: u64, - pub rsp: u64, // user rsp + pub rsp: u64, + pub rip: u64, + pub rflags: u64, } #[cfg(target_arch = "aarch64")] @@ -63,6 +64,8 @@ pub struct UserContext { pub esr_el1: u64, // exception type pub far_el1: u64, // fault type pub sp_el0: u64, + pub sp_el1: u64, + pub _pad1: u64, } #[unsafe(no_mangle)] @@ -70,7 +73,8 @@ pub extern "C" fn ctx_save(regs: *const UserContext) { if let Some(pid) = current_pid() { let mut guard = SCHEDULER.lock(); if let Some(process) = guard.processes.get_mut(&pid) { - let saved_ctx = unsafe { core::ptr::read(regs) }; + let saved_ctx = unsafe { core::ptr::read_unaligned(regs) }; + process.saved_ctx = Some(saved_ctx); } } diff --git a/kernel/src/task/process.rs b/kernel/src/task/process.rs index c6f0e16..1528185 100644 --- a/kernel/src/task/process.rs +++ b/kernel/src/task/process.rs @@ -1,8 +1,10 @@ +use core::sync::atomic::Ordering; + use alloc::vec::Vec; use crate::{ - driver::io::keyboard::KeyboardEvent, mm::address_space::AddressSpace, - task::context::UserContext, + arch::arch::GLOBAL_TICK_COUNT, driver::io::keyboard::KeyboardEvent, + mm::address_space::AddressSpace, task::context::UserContext, }; pub enum ProcessState { @@ -22,13 +24,14 @@ pub struct Process { pub pid: u64, pub state: ProcessState, pub stack_top: u64, + pub kernel_stack_top: u64, pub heap_base: u64, pub heap_end: u64, pub kbd_buffer: Vec, pub address_space: Option, pub saved_ctx: Option, - pub should_reschedule: bool, pub user_entry: u64, + pub last_switch_tick: u64, pub info: ProcessInfo, } impl Process { @@ -36,19 +39,21 @@ impl Process { pid: u64, user_entry: u64, stack_top: u64, + kernel_stack_top: u64, heap_base: u64, heap_end: u64, ) -> Process { Process { pid, stack_top, + kernel_stack_top, state: ProcessState::Ready, heap_base, heap_end, + last_switch_tick: GLOBAL_TICK_COUNT.load(Ordering::Relaxed), kbd_buffer: Vec::new(), address_space: None, saved_ctx: None, - should_reschedule: false, user_entry, info: ProcessInfo { exit_code: 0, diff --git a/kernel/src/task/scheduler.rs b/kernel/src/task/scheduler.rs index 5d8d374..dc58b54 100644 --- a/kernel/src/task/scheduler.rs +++ b/kernel/src/task/scheduler.rs @@ -3,16 +3,31 @@ use core::sync::atomic::{AtomicU64, Ordering}; use alloc::{collections::btree_map::BTreeMap, vec::Vec}; use crate::{ - arch::arch::{enter_usermode, safe_lock}, - task::context::UserContext, - task::process::{Process, ProcessState}, + arch::arch::{GLOBAL_TICK_COUNT, safe_lock}, + config::TIMER_FREQUENCY_HZ, + driver::timer::TIMER, + task::{ + context::UserContext, + process::{Process, ProcessState}, + }, util::Locked, }; #[cfg(target_arch = "aarch64")] use crate::arch::aarch64::interrupts::run_next; #[cfg(target_arch = "x86_64")] -use crate::arch::x86_64::syscall::run_next; +use crate::arch::x86_64::{ + gdt::{user_code_selector, user_data_selector}, + syscall::run_next, + usermode::enter_usermode_x86_64, +}; +#[cfg(target_arch = "x86_64")] +use x86_64::structures::gdt::SegmentSelector; + +#[cfg(target_arch = "x86_64")] +fn with_rpl3(ss: SegmentSelector) -> u64 { + (ss.0 as u64) | 3 +} pub static CURRENT_PID: AtomicU64 = AtomicU64::new(0); @@ -44,11 +59,24 @@ impl Scheduler { } impl Locked { - pub fn spawn_process(&self, entry_point: u64, stack_top: u64, heap_base: u64) -> Option { + pub fn spawn_process( + &self, + entry_point: u64, + stack_top: u64, + kernel_stack_top: u64, + heap_base: u64, + ) -> Option { let mut guard = safe_lock(|| self.lock()); let pid = guard.next_pid; guard.next_pid += 1; - let process = Process::new(pid, entry_point, stack_top, heap_base, heap_base); + let process = Process::new( + pid, + entry_point, + stack_top, + kernel_stack_top, + heap_base, + heap_base, + ); guard.processes.insert(pid, process); Some(pid) @@ -58,6 +86,15 @@ impl Locked { if let Some(previous_pid) = current_pid() { let mut guard = safe_lock(|| self.lock()); + for process in guard.processes.values_mut() { + if process.info.wake_tick.is_some() { + if TIMER.now().elapsed() >= process.info.wake_tick.unwrap() { + process.state = ProcessState::Ready; + process.info.wake_tick = None; + } + } + } + if let Some(process) = guard.processes.get_mut(&previous_pid) { if matches!(process.state, ProcessState::Running) { process.state = ProcessState::Ready; @@ -89,8 +126,9 @@ impl Locked { }; } + #[allow(unused_variables)] pub fn switch_to(&self, pid: u64, should_swapgs: bool) { - let (ctx_opt, entry, stack_top) = { + let (ctx_opt, entry, stack_top, kernel_stack_top) = { let mut guard = safe_lock(|| self.lock()); if let Some(previous_pid) = current_pid() { @@ -113,29 +151,45 @@ impl Locked { new_process.saved_ctx, new_process.user_entry, new_process.stack_top, + new_process.kernel_stack_top, ) }; set_current_pid(Some(pid)); + #[cfg(target_arch = "x86_64")] + unsafe { + use x86_64::VirtAddr; + + use crate::arch::x86_64::{gdt::TSS_MUTEX, syscall::PER_CPU}; + + PER_CPU.kernel_rsp = kernel_stack_top; + if let Some(tss) = TSS_MUTEX.lock().as_mut() { + tss.privilege_stack_table[0] = VirtAddr::new(kernel_stack_top); + } + } + + #[cfg(target_arch = "aarch64")] + unsafe { + let saved_ctx = ctx_opt.expect("Could not get user context"); + run_next((&saved_ctx) as *const UserContext, saved_ctx.sp_el0); + } + + #[cfg(target_arch = "x86_64")] match ctx_opt { - #[allow(unused_variables, unused_unsafe)] Some(saved_ctx) => unsafe { - #[cfg(target_arch = "x86_64")] - run_next((&saved_ctx) as *const UserContext, saved_ctx.rsp); - #[cfg(target_arch = "aarch64")] - run_next((&saved_ctx) as *const UserContext, saved_ctx.sp_el0); + let user_cs = with_rpl3(user_code_selector()); + let user_ss = with_rpl3(user_data_selector()); + run_next( + (&saved_ctx) as *const UserContext, + saved_ctx.rsp, + user_cs, + user_ss, + ); }, - None => enter_usermode( - entry as u64, - (stack_top & !0xF) - - cfg_select! { - target_arch = "x86_64" => 8, - target_arch = "aarch64" => 16, - _ => 8 - }, - should_swapgs, - ), + None => { + enter_usermode_x86_64(entry as u64, (stack_top & !0xF) - 8, should_swapgs); + } } } @@ -150,3 +204,37 @@ impl Locked { } pub static SCHEDULER: Locked = Locked::new(Scheduler::new()); + +#[unsafe(no_mangle)] +pub extern "C" fn check_and_reschedule() -> isize { + let current_pid = CURRENT_PID.load(Ordering::Relaxed); + let should = safe_lock(|| { + let mut scheduler = SCHEDULER.lock(); + + if let Some(process) = scheduler.processes.get_mut(¤t_pid) { + let elapsed = GLOBAL_TICK_COUNT.load(Ordering::Relaxed) - process.last_switch_tick; + if elapsed >= (TIMER_FREQUENCY_HZ / 60) as u64 { + process.last_switch_tick = GLOBAL_TICK_COUNT.load(Ordering::Relaxed); + true + } else { + false + } + } else { + false + } + }); + + if should { + let next_task = SCHEDULER.next_task(); + + if next_task == current_pid { + return 0; + } + + SCHEDULER.switch_to(next_task, true); + + 1 + } else { + 0 + } +} diff --git a/user/apps/doomgeneric b/user/apps/doomgeneric index 6ce96f7..c8cde8f 160000 --- a/user/apps/doomgeneric +++ b/user/apps/doomgeneric @@ -1 +1 @@ -Subproject commit 6ce96f770ee7290204245056f3d0a9f87cda1f6f +Subproject commit c8cde8fe456d3ef3b1d7ee1894952ea3119773d4 diff --git a/user/init b/user/init index 417af31..2c1ffa3 160000 --- a/user/init +++ b/user/init @@ -1 +1 @@ -Subproject commit 417af31481b2be5c78ff6ca2955ea085d2d07316 +Subproject commit 2c1ffa31d61358f68cd9d5a875df0c5332ca0114 diff --git a/user/libxunil b/user/libxunil index e029139..a6448bc 160000 --- a/user/libxunil +++ b/user/libxunil @@ -1 +1 @@ -Subproject commit e029139d657b338a59c6ab33a1f2ba88c78d92da +Subproject commit a6448bc1f25eebe051f4952ab0675ad7a7ecafb2