diff --git a/Cargo.lock b/Cargo.lock index 4d5dc3a..5bb038f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,9 @@ dependencies = [ [[package]] name = "init" version = "0.1.0" +dependencies = [ + "libusr", +] [[package]] name = "kernel" @@ -77,6 +80,10 @@ dependencies = [ "tock-registers", ] +[[package]] +name = "libusr" +version = "0.1.0" + [[package]] name = "memoffset" version = "0.5.6" diff --git a/Cargo.toml b/Cargo.toml index 540262c..bbf5076 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" [workspace] members = [ "kernel", + "libusr", "init", "error" ] diff --git a/Makefile b/Makefile index 26f408e..9861b99 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ all: kernel kernel: cd kernel && cargo build $(CARGO_BUILD_OPTS) - cd init && cargo build --target=../etc/$(ARCH)-osdev5.json -Z build-std=core + cd init && cargo build --target=../etc/$(ARCH)-osdev5.json -Z build-std=core,alloc,compiler_builtins cp target/$(ARCH)-osdev5/debug/init $(O)/initrd.img ifeq ($(ARCH),aarch64) $(LLVM_BASE)/llvm-strip -o $(O)/kernel.strip $(O)/kernel diff --git a/init/Cargo.toml b/init/Cargo.toml index f922052..a687bfa 100644 --- a/init/Cargo.toml +++ b/init/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +libusr = { path = "../libusr" } diff --git a/init/src/main.rs b/init/src/main.rs index dc8a51c..21b1a8e 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -1,27 +1,11 @@ -#![feature(asm)] #![no_std] #![no_main] -use core::panic::PanicInfo; +#[macro_use] +extern crate libusr; -#[link_section = ".text._start"] #[no_mangle] -extern "C" fn _start(arg: usize) -> ! { - let mut c0 = arg; - let mut c1: usize; - loop { - unsafe { - asm!("mrs {}, cntpct_el0", out(reg) c1); - asm!("svc #0", inout("x0") c0, in("x1") c1); - } - - for _ in 0..1000000 { - unsafe { asm!("nop"); } - } - } -} - -#[panic_handler] -fn panic_handler(_pi: &PanicInfo) -> ! { - loop {} +fn main() -> i32 { + trace!("Hello from userspace"); + 123 } diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 3e3fb2d..29d16d8 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -3,6 +3,7 @@ use crate::arch::machine; use crate::debug::Level; use crate::dev::irq::{IntController, IrqContext}; +use crate::syscall; use cortex_a::registers::{ESR_EL1, FAR_EL1}; use tock_registers::interfaces::Readable; @@ -18,7 +19,7 @@ pub const EC_SVC_AA64: u64 = 0b010101; #[derive(Debug)] #[repr(C)] struct ExceptionFrame { - x: [u64; 32], + x: [usize; 32], spsr_el1: u64, elr_el1: u64, sp_el0: u64, @@ -81,8 +82,12 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { dump_data_abort(Level::Error, esr, far); } EC_SVC_AA64 => { - infoln!("{:#x} {:#x}", exc.x[0], exc.x[1]); - exc.x[0] += 1; + unsafe { + match syscall::syscall(exc.x[8], &exc.x[..6]) { + Ok(val) => exc.x[0] = val, + Err(_) => exc.x[0] = usize::MAX, + } + } return; } _ => {} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index b2e164c..853d519 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -31,6 +31,8 @@ pub mod mem; pub mod proc; pub mod sync; pub mod util; +#[allow(missing_docs)] +pub mod syscall; #[panic_handler] fn panic_handler(pi: &core::panic::PanicInfo) -> ! { diff --git a/kernel/src/proc/mod.rs b/kernel/src/proc/mod.rs index ab3eb50..576364f 100644 --- a/kernel/src/proc/mod.rs +++ b/kernel/src/proc/mod.rs @@ -57,13 +57,15 @@ pub unsafe fn enter(initrd: Option<(usize, usize)>) -> ! { if let Some((start, end)) = initrd { let initrd = Box::into_raw(Box::new((mem::virtualize(start), mem::virtualize(end)))); - spawn!(fn (initrd_ptr: usize) { - debugln!("Running kernel init process"); + for _ in 0..4 { + spawn!(fn (initrd_ptr: usize) { + debugln!("Running kernel init process"); - let (start, _end) = unsafe { *(initrd_ptr as *const (usize, usize)) }; - Process::execve(|space| elf::load_elf(space, start as *const u8), 0).unwrap(); - panic!("This code should not run"); - }, initrd as usize); + let (start, _end) = unsafe { *(initrd_ptr as *const (usize, usize)) }; + Process::execve(|space| elf::load_elf(space, start as *const u8), 0).unwrap(); + panic!("This code should not run"); + }, initrd as usize); + } } SCHED.enter(); } diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 8b272b2..672c6c4 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -125,6 +125,11 @@ impl Process { const USTACK_VIRT_TOP: usize = 0x100000000; const USTACK_PAGES: usize = 4; + /// Returns currently executing process + pub fn current() -> ProcessRef { + SCHED.current_process() + } + /// Schedules an initial thread for execution /// /// # Safety @@ -190,6 +195,7 @@ impl Process { state: State::Ready, }), }); + debugln!("New kernel process: {}", id); assert!(PROCESSES.lock().insert(id, res.clone()).is_none()); Ok(res) } @@ -263,10 +269,7 @@ impl Process { old_pid, lock.id ); - assert!( - proc_lock.insert(lock.id, proc.clone()).is_none(), - "Failed to downgrade kernel process (add user pid)" - ); + assert!(proc_lock.insert(lock.id, proc.clone()).is_none()); unsafe { SCHED.hack_current_pid(lock.id); } diff --git a/kernel/src/proc/sched.rs b/kernel/src/proc/sched.rs index f124fb4..3f2f598 100644 --- a/kernel/src/proc/sched.rs +++ b/kernel/src/proc/sched.rs @@ -66,7 +66,7 @@ impl Scheduler { PROCESSES.lock().get(&id).unwrap().clone() }; - asm!("msr daifclr, #2"); + asm!("msr daifset, #2"); Process::enter(thread) } @@ -103,7 +103,7 @@ impl Scheduler { let lock = PROCESSES.lock(); ( lock.get(¤t).unwrap().clone(), - lock.get(&next).unwrap().clone(), + lock.get(&next).unwrap().clone() ) }; @@ -112,7 +112,7 @@ impl Scheduler { if !Rc::ptr_eq(&from, &to) { unsafe { - asm!("msr daifclr, #2"); + asm!("msr daifset, #2"); Process::switch(from, to, discard); } } diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs new file mode 100644 index 0000000..7710812 --- /dev/null +++ b/kernel/src/syscall.rs @@ -0,0 +1,60 @@ +use crate::mem; +use error::Errno; + +fn translate(virt: usize) -> Option { + let mut res: usize; + unsafe { + asm!("at s1e1r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res); + } + if res & 1 == 0 { + Some(res & !(0xFFF | (0xFF << 56))) + } else { + None + } +} + +fn validate_user_ptr(base: usize, len: usize) -> Result<(), Errno> { + if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET { + warnln!("User region refers to kernel memory: base={:#x}, len={:#x}", base, len); + return Err(Errno::InvalidArgument); + } + + for i in (base / mem::PAGE_SIZE)..((base + len + mem::PAGE_SIZE - 1) / mem::PAGE_SIZE) { + if translate(i * mem::PAGE_SIZE).is_none() { + warnln!( + "User region refers to unmapped memory: base={:#x}, len={:#x} (page {:#x})", + base, + len, + i * mem::PAGE_SIZE + ); + return Err(Errno::InvalidArgument); + } + } + + Ok(()) +} + +pub unsafe fn syscall(num: usize, args: &[usize]) -> Result { + match num { + // sys_exit + 1 => { + use crate::proc::Process; + Process::current().exit(args[0] as i32); + unreachable!(); + } + // sys_ex_debug_trace + 120 => { + use crate::debug::Level; + validate_user_ptr(args[0], args[1])?; + + let buf = core::slice::from_raw_parts(args[0] as *const u8, args[1]); + print!(Level::Debug, "[trace] "); + for &byte in buf.iter() { + print!(Level::Debug, "{}", byte as char); + } + println!(Level::Debug, ""); + Ok(args[1]) + } + _ => panic!("Undefined system call: {}", num), + } +} diff --git a/libusr/Cargo.toml b/libusr/Cargo.toml new file mode 100644 index 0000000..714ee4e --- /dev/null +++ b/libusr/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "libusr" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs new file mode 100644 index 0000000..5ae4587 --- /dev/null +++ b/libusr/src/lib.rs @@ -0,0 +1,29 @@ +#![feature( + asm, + alloc_error_handler, +)] +#![no_std] + +use core::panic::PanicInfo; + +mod sys; +pub mod mem; +pub mod os; + +#[link_section = ".text._start"] +#[no_mangle] +extern "C" fn _start(_arg: usize) -> ! { + extern "Rust" { + fn main() -> i32; + } + unsafe { + sys::sys_exit(main()); + } +} + +#[panic_handler] +fn panic_handler(pi: &PanicInfo) -> ! { + // TODO formatted messages + trace!("Panic ocurred: {}", pi); + sys::sys_exit(-1); +} diff --git a/libusr/src/mem.rs b/libusr/src/mem.rs new file mode 100644 index 0000000..6d667be --- /dev/null +++ b/libusr/src/mem.rs @@ -0,0 +1,31 @@ +#[no_mangle] +pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *mut u8, mut len: usize) -> *mut u8 { + while len != 0 { + len -= 1; + *dst.add(len) = *src.add(len); + } + dst +} + +#[no_mangle] +pub unsafe extern "C" fn memcmp(a: *mut u8, b: *mut u8, mut len: usize) -> isize { + while len != 0 { + len -= 1; + if *a.add(len) < *b.add(len) { + return -1; + } + if *a.add(len) > *b.add(len) { + return 1; + } + } + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn memset(buf: *mut u8, val: u8, mut len: usize) -> *mut u8 { + while len != 0 { + len -= 1; + *buf.add(len) = val; + } + buf +} diff --git a/libusr/src/os.rs b/libusr/src/os.rs new file mode 100644 index 0000000..afbc0ca --- /dev/null +++ b/libusr/src/os.rs @@ -0,0 +1,33 @@ +use crate::sys; +use core::fmt; + +#[macro_export] +macro_rules! trace { + ($($args:tt)+) => ($crate::os::_trace(format_args!($($args)+))) +} + +struct BufferWriter<'a> { + buf: &'a mut [u8], + pos: usize, +} + +impl fmt::Write for BufferWriter<'_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + self.buf[self.pos] = byte; + self.pos += 1; + } + Ok(()) + } +} + +pub fn _trace(args: fmt::Arguments) { + use core::fmt::Write; + static mut BUFFER: [u8; 4096] = [0; 4096]; + let mut writer = BufferWriter { + buf: unsafe { &mut BUFFER }, + pos: 0, + }; + writer.write_fmt(args).ok(); + sys::sys_ex_debug_trace(unsafe { &BUFFER } as *const _, writer.pos); +} diff --git a/libusr/src/sys.rs b/libusr/src/sys.rs new file mode 100644 index 0000000..ba68e54 --- /dev/null +++ b/libusr/src/sys.rs @@ -0,0 +1,27 @@ +macro_rules! syscall { + ($num:expr, $a0:expr) => {{ + let mut res: usize = $a0; + unsafe { + asm!("svc #0", inout("x0") res, in("x8") $num, options(nostack)); + } + res + }}; + ($num:expr, $a0:expr, $a1:expr) => {{ + let mut res: usize = $a0; + unsafe { + asm!("svc #0", inout("x0") res, in("x1") $a1, in("x8") $num, options(nostack)); + } + res + }}; +} + +#[inline(always)] +pub fn sys_exit(status: i32) -> ! { + syscall!(1, status as usize); + loop {} +} + +#[inline(always)] +pub fn sys_ex_debug_trace(msg: *const u8, len: usize) -> usize { + syscall!(120, msg as usize, len) +}