From afc6ccc8dd8030d22388fea9f2c89dfd3f80b0ff Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 13:46:36 +0200 Subject: [PATCH 01/42] feature: basic signal handling --- kernel/src/arch/aarch64/context.rs | 37 ++++++++- kernel/src/arch/aarch64/exception.rs | 6 +- kernel/src/mem/virt/table.rs | 6 +- kernel/src/proc/process.rs | 116 +++++++++++++++++++++++++-- kernel/src/syscall/mod.rs | 39 +++++++-- libusr/src/lib.rs | 14 ++++ syscall/src/abi.rs | 4 + syscall/src/calls.rs | 17 ++++ syscall/src/lib.rs | 1 + syscall/src/signal.rs | 29 +++++++ user/src/shell/main.rs | 10 +++ 11 files changed, 261 insertions(+), 18 deletions(-) create mode 100644 syscall/src/signal.rs diff --git a/kernel/src/arch/aarch64/context.rs b/kernel/src/arch/aarch64/context.rs index b86f0bd..aa48ac8 100644 --- a/kernel/src/arch/aarch64/context.rs +++ b/kernel/src/arch/aarch64/context.rs @@ -18,7 +18,7 @@ pub struct Context { /// Thread's kernel stack pointer pub k_sp: usize, // 0x00 - stack_base_phys: usize, + stack_base: usize, stack_page_count: usize, } @@ -35,7 +35,7 @@ impl Context { Self { k_sp: stack.sp, - stack_base_phys: stack.bp, + stack_base: stack.bp, stack_page_count: 8, } } @@ -85,7 +85,7 @@ impl Context { Self { k_sp: stack.sp, - stack_base_phys: stack.bp, + stack_base: stack.bp, stack_page_count: 8, } } @@ -104,11 +104,33 @@ impl Context { Self { k_sp: stack.sp, - stack_base_phys: stack.bp, + stack_base: stack.bp, stack_page_count: 8, } } + pub fn user_empty() -> Self { + let mut stack = Stack::new(8); + Self { + k_sp: stack.sp, + stack_base: stack.bp, + stack_page_count: 8 + } + } + + pub unsafe fn setup_signal_entry(&mut self, entry: usize, arg: usize, ttbr0: usize, ustack: usize) { + let mut stack = Stack::from_base_size(self.stack_base, self.stack_page_count); + + stack.push(entry); + stack.push(arg); + stack.push(0); + stack.push(ustack); + + stack.setup_common(__aa64_ctx_enter_user as usize, ttbr0); + + self.k_sp = stack.sp; + } + /// Performs initial thread entry /// /// # Safety @@ -140,6 +162,13 @@ impl Stack { } } + pub unsafe fn from_base_size(bp: usize, page_count: usize) -> Stack { + Stack { + bp, + sp: bp + page_count * mem::PAGE_SIZE + } + } + pub fn setup_common(&mut self, entry: usize, ttbr: usize) { self.push(0); self.push(ttbr); diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 7be2b26..e1e786d 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -6,7 +6,7 @@ use crate::dev::irq::{IntController, IrqContext}; use crate::proc::{sched, Process}; use crate::mem; use crate::syscall; -use ::syscall::abi; +use ::syscall::{abi, signal::Signal}; use cortex_a::registers::{ESR_EL1, FAR_EL1}; use tock_registers::interfaces::Readable; @@ -76,7 +76,7 @@ fn dump_data_abort(level: Level, esr: u64, far: u64) { } else { print!(level, " at UNKNOWN"); } - println!(level, ""); + println!(level, "\x1B[0m"); } #[no_mangle] @@ -95,7 +95,7 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { if let Err(e) = proc.manipulate_space(|space| space.try_cow_copy(far)) { // Kill program dump_data_abort(Level::Error, esr, far as u64); - panic!("CoW copy returned {:?}", e); + proc.enter_signal(Signal::SegmentationFault); } unsafe { diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index 3f099b8..bd74a9c 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -204,7 +204,7 @@ impl Space { } else { l2_table[l2i] = Entry::table(phys, flags | MapAttributes::ACCESS); #[cfg(feature = "verbose")] - debugln!("Map {:#x} -> {:#x}", virt, phys); + debugln!("{:#p} Map {:#x} -> {:#x}, {:?}", self, virt, phys, flags); Ok(()) } } @@ -323,4 +323,8 @@ impl Space { mem::memset(space as *mut Space as *mut u8, 0, 4096); } } + + pub fn address_phys(&mut self) -> usize { + (self as *mut _ as usize) - mem::KERNEL_OFFSET + } } diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 9d2c2c1..dac3453 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -12,6 +12,7 @@ use core::cell::UnsafeCell; use core::fmt; use core::sync::atomic::{AtomicU32, Ordering}; use error::Errno; +use syscall::signal::Signal; pub use crate::arch::platform::context::{self, Context}; @@ -47,14 +48,19 @@ struct ProcessInner { id: Pid, wait_flag: bool, exit: Option, + signal_entry: usize, + signal_stack: usize, } /// Structure describing an operating system process #[allow(dead_code)] pub struct Process { ctx: UnsafeCell, + signal_ctx: UnsafeCell, inner: IrqSafeSpinLock, exit_wait: Wait, + signal_state: AtomicU32, + signal_pending: AtomicU32, /// Process I/O context pub io: IrqSafeSpinLock, } @@ -154,6 +160,90 @@ impl Process { PROCESSES.lock().get(&pid).cloned() } + pub fn set_signal(&self, signal: Signal) { + let mut lock = self.inner.lock(); + + match lock.state { + State::Running => { + drop(lock); + self.enter_signal(signal); + } + State::Waiting => { + // TODO abort whatever the process is waiting for + todo!() + } + State::Ready => { + todo!() + } + State::Finished => { + // TODO report error back + todo!() + } + } + } + + pub fn return_from_signal(&self) { + if self.signal_pending.load(Ordering::Acquire) == 0 { + panic!("TODO handle cases when returning from no signal"); + } + self.signal_pending.store(0, Ordering::Release); + + let src_ctx = self.signal_ctx.get(); + let dst_ctx = self.ctx.get(); + + assert_eq!(self.inner.lock().state, State::Running); + + unsafe { + (&mut *src_ctx).switch(&mut *dst_ctx); + } + } + + pub fn enter_signal(&self, signal: Signal) { + if self + .signal_pending + .compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed) + .is_err() + { + panic!("Already handling a signal (maybe handle this case)"); + } + + let mut lock = self.inner.lock(); + let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; + + let dst_id = lock.id; + let dst_space_phys = lock.space.as_mut().unwrap().address_phys(); + let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48); + + debugln!( + "Signal entry: pc={:#x}, sp={:#x}, ttbr0={:#x}", + lock.signal_entry, + lock.signal_stack, + dst_ttbr0 + ); + assert_eq!(lock.state, State::Running); + + unsafe { + signal_ctx.setup_signal_entry( + lock.signal_entry, + signal as usize, + dst_ttbr0, + lock.signal_stack, + ); + } + let src_ctx = self.ctx.get(); + drop(lock); + + unsafe { + (&mut *src_ctx).switch(signal_ctx); + } + } + + pub fn setup_signal_context(&self, entry: usize, stack: usize) { + let mut lock = self.inner.lock(); + lock.signal_entry = entry; + lock.signal_stack = stack; + } + /// Schedules an initial thread for execution /// /// # Safety @@ -163,9 +253,7 @@ impl Process { pub unsafe fn enter(proc: ProcessRef) -> ! { // FIXME use some global lock to guarantee atomicity of thread entry? proc.inner.lock().state = State::Running; - let ctx = proc.ctx.get(); - - (&mut *ctx).enter() + proc.current_context().enter() } #[inline] @@ -176,6 +264,14 @@ impl Process { f(self.inner.lock().space.as_mut().unwrap()) } + fn current_context(&self) -> &mut Context { + if self.signal_pending.load(Ordering::Acquire) != 0 { + unsafe { &mut *self.signal_ctx.get() } + } else { + unsafe { &mut *self.ctx.get() } + } + } + /// Schedules a next thread for execution /// /// # Safety @@ -197,8 +293,8 @@ impl Process { dst_lock.state = State::Running; } - let src_ctx = src.ctx.get(); - let dst_ctx = dst.ctx.get(); + let src_ctx = src.current_context(); + let dst_ctx = dst.current_context(); (&mut *src_ctx).switch(&mut *dst_ctx); } @@ -237,9 +333,14 @@ impl Process { let id = Pid::new_kernel(); let res = Rc::new(Self { ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), + signal_ctx: UnsafeCell::new(Context::user_empty()), io: IrqSafeSpinLock::new(ProcessIo::new()), exit_wait: Wait::new(), + signal_state: AtomicU32::new(0), + signal_pending: AtomicU32::new(0), inner: IrqSafeSpinLock::new(ProcessInner { + signal_entry: 0, + signal_stack: 0, id, exit: None, space: None, @@ -265,9 +366,14 @@ impl Process { let dst = Rc::new(Self { ctx: UnsafeCell::new(Context::fork(frame, dst_ttbr0)), + signal_ctx: UnsafeCell::new(Context::user_empty()), io: IrqSafeSpinLock::new(src_io.fork()?), exit_wait: Wait::new(), + signal_state: AtomicU32::new(0), + signal_pending: AtomicU32::new(0), inner: IrqSafeSpinLock::new(ProcessInner { + signal_entry: 0, + signal_stack: 0, id: dst_id, exit: None, space: Some(dst_space), diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index aa3d68a..bbcb11e 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -10,9 +10,10 @@ use error::Errno; use libcommon::{Read, Write}; use syscall::{ abi, + signal::Signal, stat::{AT_EMPTY_PATH, AT_FDCWD}, }; -use vfs::{FileMode, OpenFlags, Stat, VnodeRef, IoctlCmd}; +use vfs::{FileMode, IoctlCmd, OpenFlags, Stat, VnodeRef}; pub mod arg; pub use arg::*; @@ -131,8 +132,8 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { Ok(exit) => { *status = i32::from(exit); Ok(0) - }, - _ => todo!() + } + _ => todo!(), } } abi::SYS_IOCTL => { @@ -144,7 +145,7 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?; node.ioctl(cmd, args[2], args[3]) - }, + } // Extra system calls abi::SYS_EX_DEBUG_TRACE => { @@ -168,6 +169,34 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { } res.map(|_| 0) } - _ => panic!("Undefined system call: {}", num), + abi::SYS_EX_SIGNAL => { + let proc = Process::current(); + proc.setup_signal_context(args[0], args[1]); + Ok(0) + } + abi::SYS_EX_SIGRETURN => { + let proc = Process::current(); + proc.return_from_signal(); + panic!("This code won't run"); + } + abi::SYS_EX_KILL => { + let pid = args[0] as i32; + let signal = Signal::try_from(args[1] as u32)?; + let proc = if pid > 0 { + Process::get(unsafe { Pid::from_raw(pid as u32) }).ok_or(Errno::DoesNotExist)? + } else if pid == 0 { + Process::current() + } else { + todo!() + }; + proc.set_signal(signal); + Ok(0) + } + _ => { + let proc = Process::current(); + errorln!("Undefined system call: {}", num); + proc.enter_signal(Signal::InvalidSystemCall); + todo!() + } } } diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index ee8532b..c17b619 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -10,9 +10,20 @@ pub mod os; pub mod sys { pub use syscall::calls::*; pub use syscall::stat::*; + pub use syscall::signal::Signal; pub use syscall::termios; } +#[inline(never)] +extern "C" fn _signal_handler(arg: sys::Signal) -> ! { + trace!("Entered signal handler: arg={:?}", arg); + unsafe { + sys::sys_ex_sigreturn(); + } +} + +static mut SIGNAL_STACK: [u8; 4096] = [0; 4096]; + #[link_section = ".text._start"] #[no_mangle] extern "C" fn _start(_arg: usize) -> ! { @@ -20,6 +31,9 @@ extern "C" fn _start(_arg: usize) -> ! { fn main() -> i32; } unsafe { + SIGNAL_STACK[0] = 1; + sys::sys_ex_signal(_signal_handler as usize, SIGNAL_STACK.as_ptr() as usize + 4096); + sys::sys_exit(main()); } } diff --git a/syscall/src/abi.rs b/syscall/src/abi.rs index 3cff16c..b14c321 100644 --- a/syscall/src/abi.rs +++ b/syscall/src/abi.rs @@ -1,6 +1,10 @@ pub const SYS_EX_DEBUG_TRACE: usize = 128; pub const SYS_EX_NANOSLEEP: usize = 129; +pub const SYS_EX_SIGNAL: usize = 130; +pub const SYS_EX_SIGRETURN: usize = 131; +pub const SYS_EX_KILL: usize = 132; + pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; pub const SYS_WRITE: usize = 3; diff --git a/syscall/src/calls.rs b/syscall/src/calls.rs index 8e347c6..fa14257 100644 --- a/syscall/src/calls.rs +++ b/syscall/src/calls.rs @@ -1,6 +1,7 @@ use crate::abi; use crate::{ ioctl::IoctlCmd, + signal::Signal, stat::{FileMode, OpenFlags, Stat}, }; use core::mem::size_of; @@ -198,3 +199,19 @@ pub unsafe fn sys_ioctl(fd: u32, cmd: IoctlCmd, ptr: usize, len: usize) -> isize argn!(len) ) as isize } + +#[inline(always)] +pub unsafe fn sys_ex_signal(entry: usize, stack: usize) { + syscall!(abi::SYS_EX_SIGNAL, argn!(entry), argn!(stack)); +} + +#[inline(always)] +pub unsafe fn sys_ex_sigreturn() -> ! { + syscall!(abi::SYS_EX_SIGRETURN); + unreachable!(); +} + +#[inline(always)] +pub unsafe fn sys_ex_kill(pid: u32, signum: Signal) -> i32 { + syscall!(abi::SYS_EX_KILL, argn!(pid), argn!(signum as u32)) as i32 +} diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 1b8eb00..e214f37 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -8,6 +8,7 @@ pub mod abi; pub mod stat; pub mod ioctl; pub mod termios; +pub mod signal; #[cfg(feature = "user")] pub mod calls; diff --git a/syscall/src/signal.rs b/syscall/src/signal.rs new file mode 100644 index 0000000..eeb47ec --- /dev/null +++ b/syscall/src/signal.rs @@ -0,0 +1,29 @@ +use error::Errno; + +#[derive(Clone, Copy, PartialEq, Debug)] +#[repr(u32)] +pub enum Signal { + Interrupt = 2, + IllegalInstruction = 4, + FloatError = 8, + Kill = 9, + SegmentationFault = 11, + InvalidSystemCall = 31 +} + +impl TryFrom for Signal { + type Error = Errno; + + #[inline] + fn try_from(u: u32) -> Result { + match u { + 2 => Ok(Self::Interrupt), + 4 => Ok(Self::IllegalInstruction), + 8 => Ok(Self::FloatError), + 9 => Ok(Self::Kill), + 11 => Ok(Self::SegmentationFault), + 31 => Ok(Self::InvalidSystemCall), + _ => Err(Errno::InvalidArgument) + } + } +} diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index b327102..48157aa 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -4,6 +4,8 @@ #[macro_use] extern crate libusr; +use libusr::sys::Signal; + fn readline(fd: i32, buf: &mut [u8]) -> Result<&str, ()> { let count = unsafe { libusr::sys::sys_read(fd, buf) }; if count >= 0 { @@ -26,6 +28,14 @@ fn main() -> i32 { println!(":: {:?}", line); + if line == "test" { + unsafe { + libusr::sys::sys_ex_kill(0, Signal::Interrupt); + } + trace!("Returned from signal"); + continue; + } + if line == "quit" || line == "exit" { break; } From 67ab37865e70f40787dcc97a296fde11097992ab Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 14:40:08 +0200 Subject: [PATCH 02/42] feature: statistics for phys mem module --- Makefile | 3 ++ kernel/src/dev/tty.rs | 8 +++++ kernel/src/mem/phys/manager.rs | 57 ++++++++++++++++++++++++++++-- kernel/src/mem/phys/mod.rs | 64 ++++++++++++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 0414121..7087819 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,9 @@ endif CARGO_BUILD_OPTS=$(CARGO_COMMON_OPTS) \ --target=../etc/$(ARCH)-$(MACH).json +ifeq ($(VERBOSE),1) +CARGO_BUILD_OPTS+=--features verbose +endif ifneq ($(MACH),) CARGO_BUILD_OPTS+=--features mach_$(MACH) endif diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 6a87eba..744d6a1 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -61,6 +61,14 @@ pub trait TtyDevice: SerialDevice { let ring = self.ring(); let config = ring.config.lock(); + if byte == b'@' { + use crate::mem::phys; + let stat = phys::statistics(); + debugln!("Physical memory stats:"); + debugln!("{:#?}", stat); + return; + } + if byte == b'\r' && config.iflag.contains(TermiosIflag::ICRNL) { byte = b'\n'; } diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 0b3fdc4..89709ec 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -1,4 +1,4 @@ -use super::{PageInfo, PageUsage}; +use super::{PageInfo, PageUsage, PageStatistics}; use crate::mem::{memcpy, memset, virtualize, PAGE_SIZE}; use crate::sync::IrqSafeSpinLock; use core::mem; @@ -10,10 +10,12 @@ pub unsafe trait Manager { fn free_page(&mut self, page: usize) -> Result<(), Errno>; fn copy_cow_page(&mut self, src: usize) -> Result; fn fork_page(&mut self, src: usize) -> Result; + fn statistics(&self) -> PageStatistics; // TODO status() } pub struct SimpleManager { pages: &'static mut [PageInfo], + stats: PageStatistics, base_index: usize, } impl SimpleManager { @@ -32,6 +34,14 @@ impl SimpleManager { } Self { base_index: base / PAGE_SIZE, + stats: PageStatistics { + available: 0, + kernel: 0, + kernel_heap: 0, + paging: 0, + user_private: 0, + filesystem: 0 + }, pages, } } @@ -39,6 +49,7 @@ impl SimpleManager { let page = &mut self.pages[self.page_index(addr)]; assert!(page.refcount == 0 && page.usage == PageUsage::Reserved); page.usage = PageUsage::Available; + self.stats.available += 1; } fn page_index(&self, page: usize) -> usize { @@ -56,11 +67,41 @@ impl SimpleManager { } Err(Errno::OutOfMemory) } + + fn update_stats_alloc(&mut self, pu: PageUsage, count: usize) { + let field = match pu { + PageUsage::Kernel => &mut self.stats.kernel, + PageUsage::KernelHeap => &mut self.stats.kernel_heap, + PageUsage::Paging => &mut self.stats.paging, + PageUsage::UserPrivate => &mut self.stats.user_private, + PageUsage::Filesystem => &mut self.stats.filesystem, + _ => panic!("TODO {:?}", pu), + }; + *field += count; + self.stats.available -= count; + } + + fn update_stats_free(&mut self, pu: PageUsage, count: usize) { + let field = match pu { + PageUsage::Kernel => &mut self.stats.kernel, + PageUsage::KernelHeap => &mut self.stats.kernel_heap, + PageUsage::Paging => &mut self.stats.paging, + PageUsage::UserPrivate => &mut self.stats.user_private, + PageUsage::Filesystem => &mut self.stats.filesystem, + _ => panic!("TODO {:?}", pu), + }; + *field -= count; + self.stats.available += count; + } } unsafe impl Manager for SimpleManager { fn alloc_page(&mut self, pu: PageUsage) -> Result { - self.alloc_single_index(pu) - .map(|r| (self.base_index + r) * PAGE_SIZE) + let res = self.alloc_single_index(pu) + .map(|r| (self.base_index + r) * PAGE_SIZE); + if res.is_ok() { + self.update_stats_alloc(pu, 1); + } + res } fn alloc_contiguous_pages(&mut self, pu: PageUsage, count: usize) -> Result { 'l0: for i in 0..self.pages.len() { @@ -75,6 +116,7 @@ unsafe impl Manager for SimpleManager { page.usage = pu; page.refcount = 1; } + self.update_stats_alloc(pu, count); return Ok((self.base_index + i) * PAGE_SIZE); } Err(Errno::OutOfMemory) @@ -83,6 +125,7 @@ unsafe impl Manager for SimpleManager { let index = self.page_index(addr); let page = &mut self.pages[index]; + let usage = page.usage; assert!(page.usage != PageUsage::Reserved && page.usage != PageUsage::Available); if page.refcount > 1 { @@ -92,6 +135,10 @@ unsafe impl Manager for SimpleManager { page.usage = PageUsage::Available; page.refcount = 0; } + + drop(page); + self.update_stats_free(usage, 1); + Ok(()) } @@ -130,6 +177,10 @@ unsafe impl Manager for SimpleManager { } Ok(src) } + + fn statistics(&self) -> PageStatistics { + self.stats.clone() + } } pub(super) static MANAGER: IrqSafeSpinLock> = IrqSafeSpinLock::new(None); diff --git a/kernel/src/mem/phys/mod.rs b/kernel/src/mem/phys/mod.rs index 4a395ac..38e541c 100644 --- a/kernel/src/mem/phys/mod.rs +++ b/kernel/src/mem/phys/mod.rs @@ -32,6 +32,16 @@ pub enum PageUsage { Filesystem, } +#[derive(Clone, Debug)] +pub struct PageStatistics { + available: usize, + kernel: usize, + kernel_heap: usize, + paging: usize, + user_private: usize, + filesystem: usize, +} + /// Data structure representing a single physical memory page pub struct PageInfo { refcount: usize, @@ -66,18 +76,57 @@ impl Iterator for SimpleMemoryIterator { } } +#[cfg(feature = "verbose")] +fn trace_alloc(loc: &core::panic::Location, pu: PageUsage, base: usize, count: usize) { + use crate::debug::Level; + println!( + Level::Debug, + "\x1B[36;1m[phys/alloc] {}:{} {:?} {:#x}..{:#x}\x1B[0m", + loc.file(), + loc.line(), + pu, + base, + base + count * PAGE_SIZE + ); +} + +#[cfg(feature = "verbose")] +fn trace_free(loc: &core::panic::Location, page: usize) { + use crate::debug::Level; + println!( + Level::Debug, + "\x1B[36;1m[phys/free] {}:{} {:#x}..{:#x}\x1B[0m", + loc.file(), + loc.line(), + page, + page + PAGE_SIZE + ); +} + /// Allocates a contiguous range of `count` physical memory pages. +#[cfg_attr(feature = "verbose", track_caller)] pub fn alloc_contiguous_pages(pu: PageUsage, count: usize) -> Result { - MANAGER + let res = MANAGER .lock() .as_mut() .unwrap() - .alloc_contiguous_pages(pu, count) + .alloc_contiguous_pages(pu, count); + #[cfg(feature = "verbose")] + if let Ok(base) = res { + trace_alloc(&core::panic::Location::caller(), pu, base, count); + } + res } /// Allocates a single physical memory page. +#[cfg_attr(feature = "verbose", track_caller)] pub fn alloc_page(pu: PageUsage) -> Result { - MANAGER.lock().as_mut().unwrap().alloc_page(pu) + let res = MANAGER.lock().as_mut().unwrap().alloc_page(pu); + #[cfg(feature = "verbose")] + if let Ok(base) = res { + trace_alloc(&core::panic::Location::caller(), pu, base, 1); + } + res } /// Releases a single physical memory page back for further allocation. @@ -85,10 +134,19 @@ pub fn alloc_page(pu: PageUsage) -> Result { /// # Safety /// /// Unsafe: accepts arbitrary `page` arguments +#[cfg_attr(feature = "verbose", track_caller)] pub unsafe fn free_page(page: usize) -> Result<(), Errno> { + #[cfg(feature = "verbose")] + { + trace_free(&core::panic::Location::caller(), page); + } MANAGER.lock().as_mut().unwrap().free_page(page) } +pub fn statistics() -> PageStatistics { + MANAGER.lock().as_ref().unwrap().statistics() +} + /// # Safety /// /// Unsafe: accepts arbitrary `page` arguments From cd560e79ef4874a6614baa94b8d68af34957184f Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 20:43:48 +0200 Subject: [PATCH 03/42] refactor: merge error and libcommon into syscall --- Cargo.lock | 21 +----- Cargo.toml | 2 - error/Cargo.toml | 8 --- fs/fat32/Cargo.toml | 2 - fs/memfs/Cargo.toml | 3 +- fs/memfs/src/block.rs | 2 +- fs/memfs/src/bvec.rs | 2 +- fs/memfs/src/dir.rs | 4 +- fs/memfs/src/file.rs | 2 +- fs/memfs/src/lib.rs | 6 +- fs/memfs/src/tar.rs | 2 +- fs/vfs/Cargo.toml | 2 - fs/vfs/src/block.rs | 2 +- fs/vfs/src/char.rs | 2 +- fs/vfs/src/file.rs | 6 +- fs/vfs/src/fs.rs | 2 +- fs/vfs/src/ioctx.rs | 6 +- fs/vfs/src/node.rs | 2 +- kernel/Cargo.toml | 2 - kernel/src/arch/aarch64/boot/mod.rs | 2 +- kernel/src/arch/aarch64/irq/gic/mod.rs | 2 +- .../src/arch/aarch64/mach_orangepi3/gpio.rs | 2 +- kernel/src/arch/aarch64/mach_orangepi3/mod.rs | 2 +- kernel/src/arch/aarch64/mach_orangepi3/rtc.rs | 2 +- .../src/arch/aarch64/mach_orangepi3/uart.rs | 2 +- .../src/arch/aarch64/mach_orangepi3/wdog.rs | 2 +- kernel/src/arch/aarch64/mach_qemu/mod.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/emmc.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/irqchip.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/mailbox.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/mod.rs | 2 +- kernel/src/arch/aarch64/timer.rs | 2 +- kernel/src/dev/fdt.rs | 3 +- kernel/src/dev/gpio.rs | 2 +- kernel/src/dev/irq.rs | 2 +- kernel/src/dev/mod.rs | 2 +- kernel/src/dev/pci/mod.rs | 2 +- kernel/src/dev/pci/pcie/gpex.rs | 2 +- kernel/src/dev/rtc/pl031.rs | 2 +- kernel/src/dev/sd.rs | 2 +- kernel/src/dev/serial/mod.rs | 2 +- kernel/src/dev/serial/pl011.rs | 2 +- kernel/src/dev/timer.rs | 2 +- kernel/src/dev/tty.rs | 2 +- kernel/src/fs/devfs.rs | 2 +- kernel/src/mem/mod.rs | 70 ------------------- kernel/src/mem/phys/manager.rs | 6 +- kernel/src/mem/phys/mod.rs | 2 +- kernel/src/mem/virt/fixed.rs | 2 +- kernel/src/mem/virt/mod.rs | 2 +- kernel/src/mem/virt/table.rs | 4 +- kernel/src/proc/elf.rs | 6 +- kernel/src/proc/io.rs | 2 +- kernel/src/proc/process.rs | 2 +- kernel/src/proc/wait.rs | 2 +- kernel/src/syscall/arg.rs | 2 +- kernel/src/syscall/mod.rs | 12 ++-- libcommon/Cargo.toml | 9 --- libcommon/src/lib.rs | 49 ------------- libcommon/src/sync.rs | 0 libusr/src/io.rs | 10 +-- libusr/src/lib.rs | 3 +- syscall/Cargo.toml | 1 - error/src/lib.rs => syscall/src/error.rs | 2 - syscall/src/ioctl.rs | 3 +- syscall/src/lib.rs | 4 ++ {libusr => syscall}/src/mem.rs | 8 +++ syscall/src/path.rs | 15 ++++ syscall/src/traits.rs | 28 ++++++++ 69 files changed, 136 insertions(+), 239 deletions(-) delete mode 100644 error/Cargo.toml delete mode 100644 libcommon/Cargo.toml delete mode 100644 libcommon/src/lib.rs delete mode 100644 libcommon/src/sync.rs rename error/src/lib.rs => syscall/src/error.rs (96%) rename {libusr => syscall}/src/mem.rs (87%) create mode 100644 syscall/src/path.rs create mode 100644 syscall/src/traits.rs diff --git a/Cargo.lock b/Cargo.lock index eb4d3dd..4bb8681 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,10 +35,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6419a5c75e40011b9fe0174db3fe24006ab122fbe1b7e9cc5974b338a755c76" -[[package]] -name = "error" -version = "0.1.0" - [[package]] name = "fallible-iterator" version = "0.2.0" @@ -49,8 +45,6 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" name = "fat32" version = "0.1.0" dependencies = [ - "error", - "libcommon", "vfs", ] @@ -77,22 +71,13 @@ dependencies = [ "bitflags", "cfg-if", "cortex-a", - "error", "fdt-rs", - "libcommon", "memfs", "syscall", "tock-registers", "vfs", ] -[[package]] -name = "libcommon" -version = "0.1.0" -dependencies = [ - "error", -] - [[package]] name = "libusr" version = "0.1.0" @@ -104,8 +89,7 @@ dependencies = [ name = "memfs" version = "0.1.0" dependencies = [ - "error", - "libcommon", + "syscall", "vfs", ] @@ -206,7 +190,6 @@ name = "syscall" version = "0.1.0" dependencies = [ "bitflags", - "error", ] [[package]] @@ -238,7 +221,5 @@ dependencies = [ name = "vfs" version = "0.1.0" dependencies = [ - "error", - "libcommon", "syscall", ] diff --git a/Cargo.toml b/Cargo.toml index 183dc28..e3c8c4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,7 @@ members = [ "fs/memfs", "fs/fat32", "syscall", - "libcommon", "kernel", "libusr", "user", - "error" ] diff --git a/error/Cargo.toml b/error/Cargo.toml deleted file mode 100644 index 31b8188..0000000 --- a/error/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "error" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/fs/fat32/Cargo.toml b/fs/fat32/Cargo.toml index cee876c..595cb0a 100644 --- a/fs/fat32/Cargo.toml +++ b/fs/fat32/Cargo.toml @@ -7,5 +7,3 @@ edition = "2021" [dependencies] vfs = { path = "../vfs" } -libcommon = { path = "../../libcommon" } -error = { path = "../../error" } diff --git a/fs/memfs/Cargo.toml b/fs/memfs/Cargo.toml index 2c7d297..a2d5267 100644 --- a/fs/memfs/Cargo.toml +++ b/fs/memfs/Cargo.toml @@ -7,8 +7,7 @@ edition = "2021" [dependencies] vfs = { path = "../vfs" } -error = { path = "../../error" } -libcommon = { path = "../../libcommon" } +syscall = { path = "../../syscall" } [features] cow = [] diff --git a/fs/memfs/src/block.rs b/fs/memfs/src/block.rs index e3c9289..5e46ef4 100644 --- a/fs/memfs/src/block.rs +++ b/fs/memfs/src/block.rs @@ -1,6 +1,6 @@ use core::mem::{size_of, MaybeUninit}; use core::ops::{Deref, DerefMut}; -use error::Errno; +use syscall::error::Errno; pub const SIZE: usize = 4096; pub const ENTRY_COUNT: usize = SIZE / size_of::(); diff --git a/fs/memfs/src/bvec.rs b/fs/memfs/src/bvec.rs index f75039f..366c370 100644 --- a/fs/memfs/src/bvec.rs +++ b/fs/memfs/src/bvec.rs @@ -2,7 +2,7 @@ use crate::{block, BlockAllocator, BlockRef}; use core::cmp::min; use core::mem::MaybeUninit; use core::ops::{Index, IndexMut}; -use error::Errno; +use syscall::error::Errno; const L0_BLOCKS: usize = 32; // 128K const L1_BLOCKS: usize = 8; // 16M diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index 552a6b6..0567757 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -1,7 +1,7 @@ use crate::{BlockAllocator, Bvec, FileInode}; use alloc::boxed::Box; -use error::Errno; -use vfs::{OpenFlags, Stat, Vnode, VnodeImpl, VnodeKind, VnodeRef, IoctlCmd}; +use syscall::error::Errno; +use vfs::{IoctlCmd, OpenFlags, Stat, Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirInode { alloc: A, diff --git a/fs/memfs/src/file.rs b/fs/memfs/src/file.rs index 9c3a2b1..1bfb297 100644 --- a/fs/memfs/src/file.rs +++ b/fs/memfs/src/file.rs @@ -1,5 +1,5 @@ use crate::{BlockAllocator, Bvec}; -use error::Errno; +use syscall::error::Errno; use vfs::{OpenFlags, Stat, VnodeImpl, VnodeKind, VnodeRef, IoctlCmd}; pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> { diff --git a/fs/memfs/src/lib.rs b/fs/memfs/src/lib.rs index 22ad694..42e02d2 100644 --- a/fs/memfs/src/lib.rs +++ b/fs/memfs/src/lib.rs @@ -14,8 +14,10 @@ extern crate std; use alloc::{boxed::Box, rc::Rc}; use core::any::Any; use core::cell::{Ref, RefCell}; -use error::Errno; -use libcommon::*; +use syscall::{ + error::Errno, + path::{path_component_right, path_component_left} +}; use vfs::{BlockDevice, FileMode, Filesystem, Vnode, VnodeKind, VnodeRef}; mod block; diff --git a/fs/memfs/src/tar.rs b/fs/memfs/src/tar.rs index 0cd4450..3fe7fb3 100644 --- a/fs/memfs/src/tar.rs +++ b/fs/memfs/src/tar.rs @@ -1,4 +1,4 @@ -use error::Errno; +use syscall::error::Errno; use vfs::VnodeKind; #[repr(packed)] diff --git a/fs/vfs/Cargo.toml b/fs/vfs/Cargo.toml index dd4bb6a..e754bc3 100644 --- a/fs/vfs/Cargo.toml +++ b/fs/vfs/Cargo.toml @@ -6,6 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -error = { path = "../../error" } -libcommon = { path = "../../libcommon" } syscall = { path = "../../syscall" } diff --git a/fs/vfs/src/block.rs b/fs/vfs/src/block.rs index 01368c6..8092a62 100644 --- a/fs/vfs/src/block.rs +++ b/fs/vfs/src/block.rs @@ -1,4 +1,4 @@ -use error::Errno; +use syscall::error::Errno; /// Block device interface pub trait BlockDevice { diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index 7022076..aeebdd8 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -1,5 +1,5 @@ use crate::{OpenFlags, Stat, VnodeImpl, VnodeKind, VnodeRef, IoctlCmd}; -use error::Errno; +use syscall::error::Errno; /// Generic character device trait pub trait CharDevice { diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index 8eea546..cf30f76 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -2,8 +2,10 @@ use crate::{VnodeKind, VnodeRef}; use alloc::rc::Rc; use core::cell::RefCell; use core::cmp::min; -use error::Errno; -use libcommon::{Read, Seek, SeekDir, Write}; +use syscall::{ + traits::{Read, Seek, SeekDir, Write}, + error::Errno +}; struct NormalFile { vnode: VnodeRef, diff --git a/fs/vfs/src/fs.rs b/fs/vfs/src/fs.rs index 4b60358..dcb96b5 100644 --- a/fs/vfs/src/fs.rs +++ b/fs/vfs/src/fs.rs @@ -2,7 +2,7 @@ use crate::{BlockDevice, VnodeRef}; use alloc::rc::Rc; use core::any::Any; use core::cell::Ref; -use error::Errno; +use syscall::error::Errno; /// General filesystem interface pub trait Filesystem { diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index a736c06..5095186 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -1,6 +1,8 @@ use crate::{FileMode, FileRef, OpenFlags, VnodeKind, VnodeRef}; -use error::Errno; -use libcommon::{path_component_left, path_component_right}; +use syscall::{ + error::Errno, + path::{path_component_left, path_component_right} +}; /// I/O context structure #[derive(Clone)] diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index fb37013..e3c4608 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -2,7 +2,7 @@ use crate::{File, FileMode, FileRef, Filesystem, IoctlCmd, OpenFlags, Stat}; use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec}; use core::cell::{RefCell, RefMut}; use core::fmt; -use error::Errno; +use syscall::error::Errno; /// Convenience type alias for [Rc] pub type VnodeRef = Rc; diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 0675dec..8f4b9a8 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -10,10 +10,8 @@ name = "kernel" test = false [dependencies] -error = { path = "../error" } vfs = { path = "../fs/vfs" } memfs = { path = "../fs/memfs" } -libcommon = { path = "../libcommon" } syscall = { path = "../syscall" } cfg-if = "1.x.x" tock-registers = "0.7.x" diff --git a/kernel/src/arch/aarch64/boot/mod.rs b/kernel/src/arch/aarch64/boot/mod.rs index 580132e..898d481 100644 --- a/kernel/src/arch/aarch64/boot/mod.rs +++ b/kernel/src/arch/aarch64/boot/mod.rs @@ -11,7 +11,7 @@ use crate::dev::{ Device, }; use crate::fs::devfs; -use error::Errno; +use syscall::error::Errno; //use crate::debug::Level; use crate::mem::{ self, heap, diff --git a/kernel/src/arch/aarch64/irq/gic/mod.rs b/kernel/src/arch/aarch64/irq/gic/mod.rs index 4346f8a..b4b40a9 100644 --- a/kernel/src/arch/aarch64/irq/gic/mod.rs +++ b/kernel/src/arch/aarch64/irq/gic/mod.rs @@ -7,7 +7,7 @@ use crate::dev::{ use crate::mem::virt::{DeviceMemory, DeviceMemoryIo}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; mod gicc; use gicc::Gicc; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs b/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs index 06db644..6ff7577 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs @@ -12,7 +12,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; use tock_registers::registers::ReadWrite; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs index 2e707b0..66113c7 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs @@ -13,7 +13,7 @@ use crate::dev::{ }; use crate::fs::devfs::{self, CharDeviceType}; use crate::mem::phys; -use error::Errno; +use syscall::error::Errno; mod gpio; mod rtc; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs index 01eaf1b..5a13f5f 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs @@ -7,7 +7,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, diff --git a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs index 8fbc719..3c0bce2 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs @@ -8,7 +8,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; use tock_registers::registers::{Aliased, ReadOnly, ReadWrite}; use tock_registers::{register_bitfields, register_structs}; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs b/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs index 3bca2dd..5ae7ecd 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; use tock_registers::{ interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite, }; diff --git a/kernel/src/arch/aarch64/mach_qemu/mod.rs b/kernel/src/arch/aarch64/mach_qemu/mod.rs index 344888f..c8a2389 100644 --- a/kernel/src/arch/aarch64/mach_qemu/mod.rs +++ b/kernel/src/arch/aarch64/mach_qemu/mod.rs @@ -13,7 +13,7 @@ use crate::dev::{ }; use crate::fs::devfs::{self, CharDeviceType}; use crate::mem::phys; -use error::Errno; +use syscall::error::Errno; pub use gic::IrqNumber; diff --git a/kernel/src/arch/aarch64/mach_rpi3/emmc.rs b/kernel/src/arch/aarch64/mach_rpi3/emmc.rs index b96835a..75bc25d 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/emmc.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/emmc.rs @@ -7,7 +7,7 @@ use crate::dev::Device; use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; use tock_registers::registers::{ReadOnly, ReadWrite}; use tock_registers::{register_bitfields, register_structs}; diff --git a/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs b/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs index 0e77072..deab40a 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs @@ -7,7 +7,7 @@ use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use core::fmt; use cortex_a::registers::MPIDR_EL1; -use error::Errno; +use syscall::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; diff --git a/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs b/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs index bdfa1e1..94b9f5b 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use crate::mem::{self, virt::DeviceMemoryIo}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::registers::{ReadOnly, WriteOnly}; diff --git a/kernel/src/arch/aarch64/mach_rpi3/mod.rs b/kernel/src/arch/aarch64/mach_rpi3/mod.rs index 91cbf7c..fabb2e4 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/mod.rs @@ -5,7 +5,7 @@ use crate::dev::{ Device, }; use crate::mem::phys; -use error::Errno; +use syscall::error::Errno; pub mod irqchip; pub use irqchip::{Bcm283xIrqchip, IrqNumber}; diff --git a/kernel/src/arch/aarch64/timer.rs b/kernel/src/arch/aarch64/timer.rs index 262184f..583a93a 100644 --- a/kernel/src/arch/aarch64/timer.rs +++ b/kernel/src/arch/aarch64/timer.rs @@ -8,7 +8,7 @@ use crate::dev::{ }; use core::time::Duration; use cortex_a::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0}; -use error::Errno; +use syscall::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; /// Generic timer struct diff --git a/kernel/src/dev/fdt.rs b/kernel/src/dev/fdt.rs index f170982..d515323 100644 --- a/kernel/src/dev/fdt.rs +++ b/kernel/src/dev/fdt.rs @@ -1,12 +1,11 @@ //! Device tree facilities use crate::debug::Level; -use error::Errno; use fdt_rs::prelude::*; use fdt_rs::{ base::DevTree, index::{DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp}, }; -use libcommon::path_component_left; +use syscall::{error::Errno, path::path_component_left}; #[repr(align(16))] struct Wrap { diff --git a/kernel/src/dev/gpio.rs b/kernel/src/dev/gpio.rs index 7cf11fe..e21670f 100644 --- a/kernel/src/dev/gpio.rs +++ b/kernel/src/dev/gpio.rs @@ -1,7 +1,7 @@ //! GPIO and pin control interfaces use crate::dev::Device; -use error::Errno; +use syscall::error::Errno; /// Pin function mode pub enum PinMode { diff --git a/kernel/src/dev/irq.rs b/kernel/src/dev/irq.rs index c05e3ab..234c143 100644 --- a/kernel/src/dev/irq.rs +++ b/kernel/src/dev/irq.rs @@ -1,7 +1,7 @@ //! Interrupt controller and handler interfaces use crate::dev::Device; use core::marker::PhantomData; -use error::Errno; +use syscall::error::Errno; /// Token to indicate the local core is running in IRQ context pub struct IrqContext<'irq_context> { diff --git a/kernel/src/dev/mod.rs b/kernel/src/dev/mod.rs index b0e9dae..82c173e 100644 --- a/kernel/src/dev/mod.rs +++ b/kernel/src/dev/mod.rs @@ -1,6 +1,6 @@ //! Module for device interfaces and drivers -use error::Errno; +use syscall::error::Errno; // Device classes pub mod fdt; diff --git a/kernel/src/dev/pci/mod.rs b/kernel/src/dev/pci/mod.rs index 142c75f..cddfa7e 100644 --- a/kernel/src/dev/pci/mod.rs +++ b/kernel/src/dev/pci/mod.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use core::fmt; -use error::Errno; +use syscall::error::Errno; pub mod pcie; diff --git a/kernel/src/dev/pci/pcie/gpex.rs b/kernel/src/dev/pci/pcie/gpex.rs index ee215d2..9ea5169 100644 --- a/kernel/src/dev/pci/pcie/gpex.rs +++ b/kernel/src/dev/pci/pcie/gpex.rs @@ -6,7 +6,7 @@ use crate::dev::{ }; use crate::mem::virt::DeviceMemory; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; /// GPEX host controller struct pub struct GenericPcieHost { diff --git a/kernel/src/dev/rtc/pl031.rs b/kernel/src/dev/rtc/pl031.rs index cf6e6b6..b4eddef 100644 --- a/kernel/src/dev/rtc/pl031.rs +++ b/kernel/src/dev/rtc/pl031.rs @@ -8,7 +8,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use error::Errno; +use syscall::error::Errno; use tock_registers::{ interfaces::{ReadWriteable, Readable, Writeable}, register_bitfields, register_structs, diff --git a/kernel/src/dev/sd.rs b/kernel/src/dev/sd.rs index fe60b98..5946843 100644 --- a/kernel/src/dev/sd.rs +++ b/kernel/src/dev/sd.rs @@ -1,6 +1,6 @@ //! SD host controller interface and card operation facilities use crate::dev::Device; -use error::Errno; +use syscall::error::Errno; use vfs::BlockDevice; /// Generic SD/MMC host controller interface diff --git a/kernel/src/dev/serial/mod.rs b/kernel/src/dev/serial/mod.rs index 2f84e84..a11495e 100644 --- a/kernel/src/dev/serial/mod.rs +++ b/kernel/src/dev/serial/mod.rs @@ -1,7 +1,7 @@ //! Module for serial device drivers use crate::dev::Device; -use error::Errno; +use syscall::error::Errno; #[cfg(feature = "pl011")] pub mod pl011; diff --git a/kernel/src/dev/serial/pl011.rs b/kernel/src/dev/serial/pl011.rs index 634e078..791aa6c 100644 --- a/kernel/src/dev/serial/pl011.rs +++ b/kernel/src/dev/serial/pl011.rs @@ -11,7 +11,7 @@ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use core::fmt; -use error::Errno; +use syscall::error::Errno; use tock_registers::{ interfaces::{ReadWriteable, Readable, Writeable}, register_bitfields, register_structs, diff --git a/kernel/src/dev/timer.rs b/kernel/src/dev/timer.rs index 4494fda..14efc6b 100644 --- a/kernel/src/dev/timer.rs +++ b/kernel/src/dev/timer.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use core::time::Duration; -use error::Errno; +use syscall::error::Errno; /// Interface for generic timestamp source pub trait TimestampSource: Device { diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 6a87eba..ba1e8d6 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -2,7 +2,7 @@ use crate::dev::serial::SerialDevice; use crate::proc::wait::Wait; use crate::sync::IrqSafeSpinLock; -use error::Errno; +use syscall::error::Errno; use syscall::{ termios::{Termios, TermiosIflag, TermiosLflag, TermiosOflag}, ioctl::IoctlCmd diff --git a/kernel/src/fs/devfs.rs b/kernel/src/fs/devfs.rs index 3de2ad1..5394e9e 100644 --- a/kernel/src/fs/devfs.rs +++ b/kernel/src/fs/devfs.rs @@ -2,7 +2,7 @@ use crate::util::InitOnce; use alloc::boxed::Box; use core::sync::atomic::{AtomicUsize, Ordering}; -use error::Errno; +use syscall::error::Errno; use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef}; /// Possible character device kinds diff --git a/kernel/src/mem/mod.rs b/kernel/src/mem/mod.rs index 878494c..3f2433e 100644 --- a/kernel/src/mem/mod.rs +++ b/kernel/src/mem/mod.rs @@ -26,73 +26,3 @@ pub fn kernel_end_phys() -> usize { } unsafe { &__kernel_end as *const _ as usize - KERNEL_OFFSET } } - -/// See memcpy(3p). -/// -/// # Safety -/// -/// Unsafe: writes to arbitrary memory locations, performs no pointer -/// validation. -#[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 -} - -/// See memcmp(3p). -/// -/// # Safety -/// -/// Unsafe: performs reads from arbitrary memory locations, performs no -/// pointer validation. -#[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 -} - -/// See memmove(3p) -/// -/// # Safety -/// -/// Unsafe: writes to arbitrary memory locations, performs no pointer -/// validation. -#[no_mangle] -pub unsafe extern "C" fn memmove(dst: *mut u8, src: *mut u8, len: usize) -> *mut u8 { - if dst < src { - for i in 0..len { - *dst.add(i) = *src.add(i); - } - } else { - for i in 0..len { - *dst.add(len - (i + 1)) = *src.add(len - (i + 1)); - } - } - dst -} - -/// See memset(3p) -/// -/// # Safety -/// -/// Unsafe: writes to arbitrary memory locations, performs no pointer -/// validation. -#[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/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 0b3fdc4..1afe715 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -1,8 +1,10 @@ use super::{PageInfo, PageUsage}; -use crate::mem::{memcpy, memset, virtualize, PAGE_SIZE}; +use crate::mem::{virtualize, PAGE_SIZE}; use crate::sync::IrqSafeSpinLock; use core::mem; -use error::Errno; +use syscall::{ + error::Errno, mem::{memset, memcpy} +}; pub unsafe trait Manager { fn alloc_page(&mut self, pu: PageUsage) -> Result; diff --git a/kernel/src/mem/phys/mod.rs b/kernel/src/mem/phys/mod.rs index 4a395ac..4d95b57 100644 --- a/kernel/src/mem/phys/mod.rs +++ b/kernel/src/mem/phys/mod.rs @@ -3,7 +3,7 @@ use crate::config::{ConfigKey, CONFIG}; use crate::mem::PAGE_SIZE; use core::mem::size_of; -use error::Errno; +use syscall::error::Errno; mod manager; mod reserved; diff --git a/kernel/src/mem/virt/fixed.rs b/kernel/src/mem/virt/fixed.rs index 1327828..01cc7c6 100644 --- a/kernel/src/mem/virt/fixed.rs +++ b/kernel/src/mem/virt/fixed.rs @@ -5,7 +5,7 @@ use crate::mem::{ virt::{Entry, MapAttributes, Table}, }; use cortex_a::asm::barrier::{self, dsb, isb}; -use error::Errno; +use syscall::error::Errno; const DEVICE_MAP_OFFSET: usize = mem::KERNEL_OFFSET + (256usize << 30); diff --git a/kernel/src/mem/virt/mod.rs b/kernel/src/mem/virt/mod.rs index 97b8639..0dade9a 100644 --- a/kernel/src/mem/virt/mod.rs +++ b/kernel/src/mem/virt/mod.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::ops::Deref; use cortex_a::asm::barrier::{self, dsb, isb}; use cortex_a::registers::TTBR0_EL1; -use error::Errno; +use syscall::error::Errno; use tock_registers::interfaces::Writeable; pub mod table; diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index 3f099b8..4c4ba20 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -5,7 +5,7 @@ use crate::mem::{ phys::{self, PageUsage}, }; use core::ops::{Index, IndexMut}; -use error::Errno; +use syscall::{error::Errno, mem::memset}; /// Transparent wrapper structure representing a single /// translation table entry @@ -320,7 +320,7 @@ impl Space { } } unsafe { - mem::memset(space as *mut Space as *mut u8, 0, 4096); + memset(space as *mut Space as *mut u8, 0, 4096); } } } diff --git a/kernel/src/proc/elf.rs b/kernel/src/proc/elf.rs index 2f6c3d9..4075ac9 100644 --- a/kernel/src/proc/elf.rs +++ b/kernel/src/proc/elf.rs @@ -5,8 +5,10 @@ use crate::mem::{ virt::{MapAttributes, Space}, }; use core::mem::{size_of, MaybeUninit}; -use error::Errno; -use libcommon::{Read, Seek, SeekDir}; +use syscall::{ + error::Errno, + traits::{Read, Seek, SeekDir} +}; use vfs::FileRef; trait Elf { diff --git a/kernel/src/proc/io.rs b/kernel/src/proc/io.rs index 2267a10..2b97960 100644 --- a/kernel/src/proc/io.rs +++ b/kernel/src/proc/io.rs @@ -1,6 +1,6 @@ //! Process file descriptors and I/O context use alloc::collections::BTreeMap; -use error::Errno; +use syscall::error::Errno; use vfs::{FileRef, Ioctx}; /// Process I/O context. Contains file tables, root/cwd info etc. diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 9d2c2c1..02acc22 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -11,7 +11,7 @@ use alloc::rc::Rc; use core::cell::UnsafeCell; use core::fmt; use core::sync::atomic::{AtomicU32, Ordering}; -use error::Errno; +use syscall::error::Errno; pub use crate::arch::platform::context::{self, Context}; diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index c3f49a0..c40783c 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -6,7 +6,7 @@ use crate::proc::{self, sched::SCHED, Pid, Process}; use crate::sync::IrqSafeSpinLock; use alloc::collections::LinkedList; use core::time::Duration; -use error::Errno; +use syscall::error::Errno; /// Wait channel structure. Contains a queue of processes /// waiting for some event to happen. diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 51c46b0..9b0715c 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -2,7 +2,7 @@ use crate::mem; use core::mem::size_of; -use error::Errno; +use syscall::error::Errno; fn translate(virt: usize) -> Option { let mut res: usize; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index aa3d68a..234c6a5 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -6,13 +6,13 @@ use crate::proc::{elf, wait, Pid, Process, ProcessIo}; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; -use error::Errno; -use libcommon::{Read, Write}; use syscall::{ abi, + error::Errno, stat::{AT_EMPTY_PATH, AT_FDCWD}, + traits::{Read, Write}, }; -use vfs::{FileMode, OpenFlags, Stat, VnodeRef, IoctlCmd}; +use vfs::{FileMode, IoctlCmd, OpenFlags, Stat, VnodeRef}; pub mod arg; pub use arg::*; @@ -131,8 +131,8 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { Ok(exit) => { *status = i32::from(exit); Ok(0) - }, - _ => todo!() + } + _ => todo!(), } } abi::SYS_IOCTL => { @@ -144,7 +144,7 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?; node.ioctl(cmd, args[2], args[3]) - }, + } // Extra system calls abi::SYS_EX_DEBUG_TRACE => { diff --git a/libcommon/Cargo.toml b/libcommon/Cargo.toml deleted file mode 100644 index a49a495..0000000 --- a/libcommon/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "libcommon" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -error = { path = "../error" } diff --git a/libcommon/src/lib.rs b/libcommon/src/lib.rs deleted file mode 100644 index 961a822..0000000 --- a/libcommon/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![no_std] - -use error::Errno; - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum SeekDir { - Set, - End, - Current, -} - -pub trait Read { - fn read(&mut self, data: &mut [u8]) -> Result; -} - -pub trait Seek { - fn seek(&mut self, off: isize, whence: SeekDir) -> Result; -} - -pub trait Write { - fn write(&mut self, data: &[u8]) -> Result; -} - -pub fn path_component_left(path: &str) -> (&str, &str) { - if let Some((left, right)) = path.split_once('/') { - (left, right.trim_start_matches('/')) - } else { - (path, "") - } -} - -pub fn path_component_right(path: &str) -> (&str, &str) { - if let Some((left, right)) = path.trim_end_matches('/').rsplit_once('/') { - (left.trim_end_matches('/'), right) - } else { - ("", path) - } -} - -pub fn read_le32(src: &[u8]) -> u32 { - (src[0] as u32) | ((src[1] as u32) << 8) | ((src[2] as u32) << 16) | ((src[3] as u32) << 24) -} - -pub fn read_le16(src: &[u8]) -> u16 { - (src[0] as u16) | ((src[1] as u16) << 8) -} - -#[cfg(test)] -mod tests {} diff --git a/libcommon/src/sync.rs b/libcommon/src/sync.rs deleted file mode 100644 index e69de29..0000000 diff --git a/libusr/src/io.rs b/libusr/src/io.rs index e7b9ae7..5968513 100644 --- a/libusr/src/io.rs +++ b/libusr/src/io.rs @@ -1,13 +1,15 @@ -use crate::sys::{self, Stat}; use core::fmt; -use syscall::stat::AT_FDCWD; +use syscall::{ + calls::{sys_fstatat, sys_write}, + stat::{Stat, AT_FDCWD}, +}; // TODO populate this type pub struct Error; pub fn stat(pathname: &str) -> Result { let mut buf = Stat::default(); - let res = unsafe { sys::sys_fstatat(AT_FDCWD, pathname, &mut buf, 0) }; + let res = unsafe { sys_fstatat(AT_FDCWD, pathname, &mut buf, 0) }; if res != 0 { todo!(); } @@ -60,6 +62,6 @@ pub fn _print(fd: i32, args: fmt::Arguments) { }; writer.write_fmt(args).ok(); unsafe { - sys::sys_write(fd, &BUFFER[..writer.pos]); + sys_write(fd, &BUFFER[..writer.pos]); } } diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index ee8532b..f5e6993 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -4,12 +4,11 @@ use core::panic::PanicInfo; pub mod io; -pub mod mem; pub mod os; pub mod sys { pub use syscall::calls::*; - pub use syscall::stat::*; + pub use syscall::stat::{self, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; pub use syscall::termios; } diff --git a/syscall/Cargo.toml b/syscall/Cargo.toml index adfa386..878f881 100644 --- a/syscall/Cargo.toml +++ b/syscall/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] bitflags = "^1.3.0" -error = { path = "../error" } [features] user = [] diff --git a/error/src/lib.rs b/syscall/src/error.rs similarity index 96% rename from error/src/lib.rs rename to syscall/src/error.rs index 69a0188..3657ddb 100644 --- a/error/src/lib.rs +++ b/syscall/src/error.rs @@ -1,5 +1,3 @@ -#![no_std] - #[derive(PartialEq, Debug, Clone, Copy)] pub enum Errno { AlreadyExists, diff --git a/syscall/src/ioctl.rs b/syscall/src/ioctl.rs index 3f308d6..dd0196d 100644 --- a/syscall/src/ioctl.rs +++ b/syscall/src/ioctl.rs @@ -1,6 +1,5 @@ use core::convert::TryFrom; -use error::Errno; - +use crate::error::Errno; #[derive(Clone, Copy, Debug)] #[repr(u32)] diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 1b8eb00..8b9d9b2 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -8,6 +8,10 @@ pub mod abi; pub mod stat; pub mod ioctl; pub mod termios; +pub mod error; +pub mod path; +pub mod mem; +pub mod traits; #[cfg(feature = "user")] pub mod calls; diff --git a/libusr/src/mem.rs b/syscall/src/mem.rs similarity index 87% rename from libusr/src/mem.rs rename to syscall/src/mem.rs index 1b9f19a..021c7cc 100644 --- a/libusr/src/mem.rs +++ b/syscall/src/mem.rs @@ -1,3 +1,11 @@ +pub fn read_le32(src: &[u8]) -> u32 { + (src[0] as u32) | ((src[1] as u32) << 8) | ((src[2] as u32) << 16) | ((src[3] as u32) << 24) +} + +pub fn read_le16(src: &[u8]) -> u16 { + (src[0] as u16) | ((src[1] as u16) << 8) +} + /// See memcpy(3p). /// /// # Safety diff --git a/syscall/src/path.rs b/syscall/src/path.rs new file mode 100644 index 0000000..b64ecef --- /dev/null +++ b/syscall/src/path.rs @@ -0,0 +1,15 @@ +pub fn path_component_left(path: &str) -> (&str, &str) { + if let Some((left, right)) = path.split_once('/') { + (left, right.trim_start_matches('/')) + } else { + (path, "") + } +} + +pub fn path_component_right(path: &str) -> (&str, &str) { + if let Some((left, right)) = path.trim_end_matches('/').rsplit_once('/') { + (left.trim_end_matches('/'), right) + } else { + ("", path) + } +} diff --git a/syscall/src/traits.rs b/syscall/src/traits.rs new file mode 100644 index 0000000..c586b0d --- /dev/null +++ b/syscall/src/traits.rs @@ -0,0 +1,28 @@ +use crate::error::Errno; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SeekDir { + Set, + End, + Current, +} + +pub trait Read { + fn read(&mut self, data: &mut [u8]) -> Result; +} + +pub trait Seek { + fn seek(&mut self, off: isize, whence: SeekDir) -> Result; +} + +pub trait Write { + fn write(&mut self, data: &[u8]) -> Result; +} + +pub trait RandomRead { + fn pread(&mut self, pos: usize, data: &mut [u8]) -> Result; +} + +pub trait RandomWrite { + fn pwrite(&mut self, pos: usize, data: &[u8]) -> Result; +} From 41ffd0ddb74e06b85ebf5c6b7db69e14300dd637 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 20:45:54 +0200 Subject: [PATCH 04/42] refactor: rename syscall to libsys --- Cargo.lock | 22 +++++++++---------- Cargo.toml | 2 +- fs/memfs/Cargo.toml | 2 +- fs/memfs/src/block.rs | 2 +- fs/memfs/src/bvec.rs | 2 +- fs/memfs/src/dir.rs | 2 +- fs/memfs/src/file.rs | 2 +- fs/memfs/src/lib.rs | 2 +- fs/memfs/src/tar.rs | 2 +- fs/vfs/Cargo.toml | 2 +- fs/vfs/src/block.rs | 2 +- fs/vfs/src/char.rs | 2 +- fs/vfs/src/file.rs | 2 +- fs/vfs/src/fs.rs | 2 +- fs/vfs/src/ioctx.rs | 2 +- fs/vfs/src/lib.rs | 4 ++-- fs/vfs/src/node.rs | 2 +- kernel/Cargo.toml | 2 +- kernel/src/arch/aarch64/boot/mod.rs | 2 +- kernel/src/arch/aarch64/exception.rs | 4 ++-- kernel/src/arch/aarch64/irq/gic/mod.rs | 2 +- .../src/arch/aarch64/mach_orangepi3/gpio.rs | 2 +- kernel/src/arch/aarch64/mach_orangepi3/mod.rs | 2 +- kernel/src/arch/aarch64/mach_orangepi3/rtc.rs | 2 +- .../src/arch/aarch64/mach_orangepi3/uart.rs | 2 +- .../src/arch/aarch64/mach_orangepi3/wdog.rs | 2 +- kernel/src/arch/aarch64/mach_qemu/mod.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/emmc.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/irqchip.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/mailbox.rs | 2 +- kernel/src/arch/aarch64/mach_rpi3/mod.rs | 2 +- kernel/src/arch/aarch64/timer.rs | 2 +- kernel/src/dev/fdt.rs | 2 +- kernel/src/dev/gpio.rs | 2 +- kernel/src/dev/irq.rs | 2 +- kernel/src/dev/mod.rs | 2 +- kernel/src/dev/pci/mod.rs | 2 +- kernel/src/dev/pci/pcie/gpex.rs | 2 +- kernel/src/dev/rtc/pl031.rs | 2 +- kernel/src/dev/sd.rs | 2 +- kernel/src/dev/serial/mod.rs | 2 +- kernel/src/dev/serial/pl011.rs | 2 +- kernel/src/dev/timer.rs | 2 +- kernel/src/dev/tty.rs | 4 ++-- kernel/src/fs/devfs.rs | 2 +- kernel/src/mem/phys/manager.rs | 2 +- kernel/src/mem/phys/mod.rs | 2 +- kernel/src/mem/virt/fixed.rs | 2 +- kernel/src/mem/virt/mod.rs | 2 +- kernel/src/mem/virt/table.rs | 2 +- kernel/src/proc/elf.rs | 2 +- kernel/src/proc/io.rs | 2 +- kernel/src/proc/process.rs | 2 +- kernel/src/proc/wait.rs | 2 +- kernel/src/syscall/arg.rs | 2 +- kernel/src/syscall/mod.rs | 2 +- {syscall => libsys}/Cargo.toml | 2 +- {syscall => libsys}/src/abi.rs | 0 {syscall => libsys}/src/calls.rs | 0 {syscall => libsys}/src/error.rs | 0 {syscall => libsys}/src/ioctl.rs | 0 {syscall => libsys}/src/lib.rs | 0 {syscall => libsys}/src/mem.rs | 0 {syscall => libsys}/src/path.rs | 0 {syscall => libsys}/src/stat.rs | 0 {syscall => libsys}/src/termios.rs | 0 {syscall => libsys}/src/traits.rs | 0 libusr/Cargo.toml | 2 +- libusr/src/io.rs | 2 +- libusr/src/lib.rs | 6 ++--- libusr/src/os.rs | 2 +- 71 files changed, 76 insertions(+), 76 deletions(-) rename {syscall => libsys}/Cargo.toml (92%) rename {syscall => libsys}/src/abi.rs (100%) rename {syscall => libsys}/src/calls.rs (100%) rename {syscall => libsys}/src/error.rs (100%) rename {syscall => libsys}/src/ioctl.rs (100%) rename {syscall => libsys}/src/lib.rs (100%) rename {syscall => libsys}/src/mem.rs (100%) rename {syscall => libsys}/src/path.rs (100%) rename {syscall => libsys}/src/stat.rs (100%) rename {syscall => libsys}/src/termios.rs (100%) rename {syscall => libsys}/src/traits.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 4bb8681..dbb4da4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,24 +72,31 @@ dependencies = [ "cfg-if", "cortex-a", "fdt-rs", + "libsys", "memfs", - "syscall", "tock-registers", "vfs", ] +[[package]] +name = "libsys" +version = "0.1.0" +dependencies = [ + "bitflags", +] + [[package]] name = "libusr" version = "0.1.0" dependencies = [ - "syscall", + "libsys", ] [[package]] name = "memfs" version = "0.1.0" dependencies = [ - "syscall", + "libsys", "vfs", ] @@ -185,13 +192,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "syscall" -version = "0.1.0" -dependencies = [ - "bitflags", -] - [[package]] name = "tock-registers" version = "0.7.0" @@ -221,5 +221,5 @@ dependencies = [ name = "vfs" version = "0.1.0" dependencies = [ - "syscall", + "libsys", ] diff --git a/Cargo.toml b/Cargo.toml index e3c8c4b..3187e18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ members = [ "fs/vfs", "fs/memfs", "fs/fat32", - "syscall", + "libsys", "kernel", "libusr", "user", diff --git a/fs/memfs/Cargo.toml b/fs/memfs/Cargo.toml index a2d5267..0ee1a70 100644 --- a/fs/memfs/Cargo.toml +++ b/fs/memfs/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] vfs = { path = "../vfs" } -syscall = { path = "../../syscall" } +libsys = { path = "../../libsys" } [features] cow = [] diff --git a/fs/memfs/src/block.rs b/fs/memfs/src/block.rs index 5e46ef4..64241c9 100644 --- a/fs/memfs/src/block.rs +++ b/fs/memfs/src/block.rs @@ -1,6 +1,6 @@ use core::mem::{size_of, MaybeUninit}; use core::ops::{Deref, DerefMut}; -use syscall::error::Errno; +use libsys::error::Errno; pub const SIZE: usize = 4096; pub const ENTRY_COUNT: usize = SIZE / size_of::(); diff --git a/fs/memfs/src/bvec.rs b/fs/memfs/src/bvec.rs index 366c370..030daaa 100644 --- a/fs/memfs/src/bvec.rs +++ b/fs/memfs/src/bvec.rs @@ -2,7 +2,7 @@ use crate::{block, BlockAllocator, BlockRef}; use core::cmp::min; use core::mem::MaybeUninit; use core::ops::{Index, IndexMut}; -use syscall::error::Errno; +use libsys::error::Errno; const L0_BLOCKS: usize = 32; // 128K const L1_BLOCKS: usize = 8; // 16M diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index 0567757..4ee24e5 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -1,6 +1,6 @@ use crate::{BlockAllocator, Bvec, FileInode}; use alloc::boxed::Box; -use syscall::error::Errno; +use libsys::error::Errno; use vfs::{IoctlCmd, OpenFlags, Stat, Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirInode { diff --git a/fs/memfs/src/file.rs b/fs/memfs/src/file.rs index 1bfb297..639155b 100644 --- a/fs/memfs/src/file.rs +++ b/fs/memfs/src/file.rs @@ -1,5 +1,5 @@ use crate::{BlockAllocator, Bvec}; -use syscall::error::Errno; +use libsys::error::Errno; use vfs::{OpenFlags, Stat, VnodeImpl, VnodeKind, VnodeRef, IoctlCmd}; pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> { diff --git a/fs/memfs/src/lib.rs b/fs/memfs/src/lib.rs index 42e02d2..5529c34 100644 --- a/fs/memfs/src/lib.rs +++ b/fs/memfs/src/lib.rs @@ -14,7 +14,7 @@ extern crate std; use alloc::{boxed::Box, rc::Rc}; use core::any::Any; use core::cell::{Ref, RefCell}; -use syscall::{ +use libsys::{ error::Errno, path::{path_component_right, path_component_left} }; diff --git a/fs/memfs/src/tar.rs b/fs/memfs/src/tar.rs index 3fe7fb3..4f4984c 100644 --- a/fs/memfs/src/tar.rs +++ b/fs/memfs/src/tar.rs @@ -1,4 +1,4 @@ -use syscall::error::Errno; +use libsys::error::Errno; use vfs::VnodeKind; #[repr(packed)] diff --git a/fs/vfs/Cargo.toml b/fs/vfs/Cargo.toml index e754bc3..d05ed41 100644 --- a/fs/vfs/Cargo.toml +++ b/fs/vfs/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syscall = { path = "../../syscall" } +libsys = { path = "../../libsys" } diff --git a/fs/vfs/src/block.rs b/fs/vfs/src/block.rs index 8092a62..9e630fd 100644 --- a/fs/vfs/src/block.rs +++ b/fs/vfs/src/block.rs @@ -1,4 +1,4 @@ -use syscall::error::Errno; +use libsys::error::Errno; /// Block device interface pub trait BlockDevice { diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index aeebdd8..7eae7de 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -1,5 +1,5 @@ use crate::{OpenFlags, Stat, VnodeImpl, VnodeKind, VnodeRef, IoctlCmd}; -use syscall::error::Errno; +use libsys::error::Errno; /// Generic character device trait pub trait CharDevice { diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index cf30f76..af6bf77 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -2,7 +2,7 @@ use crate::{VnodeKind, VnodeRef}; use alloc::rc::Rc; use core::cell::RefCell; use core::cmp::min; -use syscall::{ +use libsys::{ traits::{Read, Seek, SeekDir, Write}, error::Errno }; diff --git a/fs/vfs/src/fs.rs b/fs/vfs/src/fs.rs index dcb96b5..a086b10 100644 --- a/fs/vfs/src/fs.rs +++ b/fs/vfs/src/fs.rs @@ -2,7 +2,7 @@ use crate::{BlockDevice, VnodeRef}; use alloc::rc::Rc; use core::any::Any; use core::cell::Ref; -use syscall::error::Errno; +use libsys::error::Errno; /// General filesystem interface pub trait Filesystem { diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index 5095186..2980d20 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -1,5 +1,5 @@ use crate::{FileMode, FileRef, OpenFlags, VnodeKind, VnodeRef}; -use syscall::{ +use libsys::{ error::Errno, path::{path_component_left, path_component_right} }; diff --git a/fs/vfs/src/lib.rs b/fs/vfs/src/lib.rs index d02b0f4..c8a74fe 100644 --- a/fs/vfs/src/lib.rs +++ b/fs/vfs/src/lib.rs @@ -9,8 +9,8 @@ extern crate std; extern crate alloc; -pub use syscall::stat::{FileMode, OpenFlags, Stat}; -pub use syscall::ioctl::IoctlCmd; +pub use libsys::stat::{FileMode, OpenFlags, Stat}; +pub use libsys::ioctl::IoctlCmd; mod block; pub use block::BlockDevice; diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index e3c4608..8df4eee 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -2,7 +2,7 @@ use crate::{File, FileMode, FileRef, Filesystem, IoctlCmd, OpenFlags, Stat}; use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec}; use core::cell::{RefCell, RefMut}; use core::fmt; -use syscall::error::Errno; +use libsys::error::Errno; /// Convenience type alias for [Rc] pub type VnodeRef = Rc; diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 8f4b9a8..da46004 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -12,7 +12,7 @@ test = false [dependencies] vfs = { path = "../fs/vfs" } memfs = { path = "../fs/memfs" } -syscall = { path = "../syscall" } +libsys = { path = "../libsys" } cfg-if = "1.x.x" tock-registers = "0.7.x" fdt-rs = { version = "0.x.x", default-features = false } diff --git a/kernel/src/arch/aarch64/boot/mod.rs b/kernel/src/arch/aarch64/boot/mod.rs index 898d481..0c054a2 100644 --- a/kernel/src/arch/aarch64/boot/mod.rs +++ b/kernel/src/arch/aarch64/boot/mod.rs @@ -11,7 +11,7 @@ use crate::dev::{ Device, }; use crate::fs::devfs; -use syscall::error::Errno; +use libsys::error::Errno; //use crate::debug::Level; use crate::mem::{ self, heap, diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 7be2b26..2a3e0d5 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -3,11 +3,11 @@ use crate::arch::machine; use crate::debug::Level; use crate::dev::irq::{IntController, IrqContext}; -use crate::proc::{sched, Process}; use crate::mem; +use crate::proc::{sched, Process}; use crate::syscall; -use ::syscall::abi; use cortex_a::registers::{ESR_EL1, FAR_EL1}; +use libsys::abi; use tock_registers::interfaces::Readable; /// Trapped SIMD/FP functionality diff --git a/kernel/src/arch/aarch64/irq/gic/mod.rs b/kernel/src/arch/aarch64/irq/gic/mod.rs index b4b40a9..c2c39c8 100644 --- a/kernel/src/arch/aarch64/irq/gic/mod.rs +++ b/kernel/src/arch/aarch64/irq/gic/mod.rs @@ -7,7 +7,7 @@ use crate::dev::{ use crate::mem::virt::{DeviceMemory, DeviceMemoryIo}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; mod gicc; use gicc::Gicc; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs b/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs index 6ff7577..0fb90e7 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs @@ -12,7 +12,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; use tock_registers::registers::ReadWrite; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs index 66113c7..6d1d347 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs @@ -13,7 +13,7 @@ use crate::dev::{ }; use crate::fs::devfs::{self, CharDeviceType}; use crate::mem::phys; -use syscall::error::Errno; +use libsys::error::Errno; mod gpio; mod rtc; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs index 5a13f5f..e65b85b 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs @@ -7,7 +7,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, diff --git a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs index 3c0bce2..147444f 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs @@ -8,7 +8,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; use tock_registers::registers::{Aliased, ReadOnly, ReadWrite}; use tock_registers::{register_bitfields, register_structs}; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs b/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs index 5ae7ecd..5178b9d 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::{ interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite, }; diff --git a/kernel/src/arch/aarch64/mach_qemu/mod.rs b/kernel/src/arch/aarch64/mach_qemu/mod.rs index c8a2389..fdeb445 100644 --- a/kernel/src/arch/aarch64/mach_qemu/mod.rs +++ b/kernel/src/arch/aarch64/mach_qemu/mod.rs @@ -13,7 +13,7 @@ use crate::dev::{ }; use crate::fs::devfs::{self, CharDeviceType}; use crate::mem::phys; -use syscall::error::Errno; +use libsys::error::Errno; pub use gic::IrqNumber; diff --git a/kernel/src/arch/aarch64/mach_rpi3/emmc.rs b/kernel/src/arch/aarch64/mach_rpi3/emmc.rs index 75bc25d..68119ea 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/emmc.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/emmc.rs @@ -7,7 +7,7 @@ use crate::dev::Device; use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; use tock_registers::registers::{ReadOnly, ReadWrite}; use tock_registers::{register_bitfields, register_structs}; diff --git a/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs b/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs index deab40a..dbb903f 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/irqchip.rs @@ -7,7 +7,7 @@ use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use core::fmt; use cortex_a::registers::MPIDR_EL1; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; diff --git a/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs b/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs index 94b9f5b..359b6d2 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/mailbox.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use crate::mem::{self, virt::DeviceMemoryIo}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::registers::{ReadOnly, WriteOnly}; diff --git a/kernel/src/arch/aarch64/mach_rpi3/mod.rs b/kernel/src/arch/aarch64/mach_rpi3/mod.rs index fabb2e4..a7c6d79 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/mod.rs @@ -5,7 +5,7 @@ use crate::dev::{ Device, }; use crate::mem::phys; -use syscall::error::Errno; +use libsys::error::Errno; pub mod irqchip; pub use irqchip::{Bcm283xIrqchip, IrqNumber}; diff --git a/kernel/src/arch/aarch64/timer.rs b/kernel/src/arch/aarch64/timer.rs index 583a93a..f88a682 100644 --- a/kernel/src/arch/aarch64/timer.rs +++ b/kernel/src/arch/aarch64/timer.rs @@ -8,7 +8,7 @@ use crate::dev::{ }; use core::time::Duration; use cortex_a::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0}; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::interfaces::{Readable, Writeable}; /// Generic timer struct diff --git a/kernel/src/dev/fdt.rs b/kernel/src/dev/fdt.rs index d515323..77eca43 100644 --- a/kernel/src/dev/fdt.rs +++ b/kernel/src/dev/fdt.rs @@ -5,7 +5,7 @@ use fdt_rs::{ base::DevTree, index::{DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp}, }; -use syscall::{error::Errno, path::path_component_left}; +use libsys::{error::Errno, path::path_component_left}; #[repr(align(16))] struct Wrap { diff --git a/kernel/src/dev/gpio.rs b/kernel/src/dev/gpio.rs index e21670f..d79072b 100644 --- a/kernel/src/dev/gpio.rs +++ b/kernel/src/dev/gpio.rs @@ -1,7 +1,7 @@ //! GPIO and pin control interfaces use crate::dev::Device; -use syscall::error::Errno; +use libsys::error::Errno; /// Pin function mode pub enum PinMode { diff --git a/kernel/src/dev/irq.rs b/kernel/src/dev/irq.rs index 234c143..a32476c 100644 --- a/kernel/src/dev/irq.rs +++ b/kernel/src/dev/irq.rs @@ -1,7 +1,7 @@ //! Interrupt controller and handler interfaces use crate::dev::Device; use core::marker::PhantomData; -use syscall::error::Errno; +use libsys::error::Errno; /// Token to indicate the local core is running in IRQ context pub struct IrqContext<'irq_context> { diff --git a/kernel/src/dev/mod.rs b/kernel/src/dev/mod.rs index 82c173e..fdaf7a8 100644 --- a/kernel/src/dev/mod.rs +++ b/kernel/src/dev/mod.rs @@ -1,6 +1,6 @@ //! Module for device interfaces and drivers -use syscall::error::Errno; +use libsys::error::Errno; // Device classes pub mod fdt; diff --git a/kernel/src/dev/pci/mod.rs b/kernel/src/dev/pci/mod.rs index cddfa7e..922cbb1 100644 --- a/kernel/src/dev/pci/mod.rs +++ b/kernel/src/dev/pci/mod.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use core::fmt; -use syscall::error::Errno; +use libsys::error::Errno; pub mod pcie; diff --git a/kernel/src/dev/pci/pcie/gpex.rs b/kernel/src/dev/pci/pcie/gpex.rs index 9ea5169..c988aab 100644 --- a/kernel/src/dev/pci/pcie/gpex.rs +++ b/kernel/src/dev/pci/pcie/gpex.rs @@ -6,7 +6,7 @@ use crate::dev::{ }; use crate::mem::virt::DeviceMemory; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; /// GPEX host controller struct pub struct GenericPcieHost { diff --git a/kernel/src/dev/rtc/pl031.rs b/kernel/src/dev/rtc/pl031.rs index b4eddef..429c5ca 100644 --- a/kernel/src/dev/rtc/pl031.rs +++ b/kernel/src/dev/rtc/pl031.rs @@ -8,7 +8,7 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::{ interfaces::{ReadWriteable, Readable, Writeable}, register_bitfields, register_structs, diff --git a/kernel/src/dev/sd.rs b/kernel/src/dev/sd.rs index 5946843..b5cdd04 100644 --- a/kernel/src/dev/sd.rs +++ b/kernel/src/dev/sd.rs @@ -1,6 +1,6 @@ //! SD host controller interface and card operation facilities use crate::dev::Device; -use syscall::error::Errno; +use libsys::error::Errno; use vfs::BlockDevice; /// Generic SD/MMC host controller interface diff --git a/kernel/src/dev/serial/mod.rs b/kernel/src/dev/serial/mod.rs index a11495e..ed7f120 100644 --- a/kernel/src/dev/serial/mod.rs +++ b/kernel/src/dev/serial/mod.rs @@ -1,7 +1,7 @@ //! Module for serial device drivers use crate::dev::Device; -use syscall::error::Errno; +use libsys::error::Errno; #[cfg(feature = "pl011")] pub mod pl011; diff --git a/kernel/src/dev/serial/pl011.rs b/kernel/src/dev/serial/pl011.rs index 791aa6c..27be9db 100644 --- a/kernel/src/dev/serial/pl011.rs +++ b/kernel/src/dev/serial/pl011.rs @@ -11,7 +11,7 @@ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use core::fmt; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::{ interfaces::{ReadWriteable, Readable, Writeable}, register_bitfields, register_structs, diff --git a/kernel/src/dev/timer.rs b/kernel/src/dev/timer.rs index 14efc6b..3d24525 100644 --- a/kernel/src/dev/timer.rs +++ b/kernel/src/dev/timer.rs @@ -2,7 +2,7 @@ use crate::dev::Device; use core::time::Duration; -use syscall::error::Errno; +use libsys::error::Errno; /// Interface for generic timestamp source pub trait TimestampSource: Device { diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index ba1e8d6..56d2775 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -2,8 +2,8 @@ use crate::dev::serial::SerialDevice; use crate::proc::wait::Wait; use crate::sync::IrqSafeSpinLock; -use syscall::error::Errno; -use syscall::{ +use libsys::error::Errno; +use libsys::{ termios::{Termios, TermiosIflag, TermiosLflag, TermiosOflag}, ioctl::IoctlCmd }; diff --git a/kernel/src/fs/devfs.rs b/kernel/src/fs/devfs.rs index 5394e9e..6a65421 100644 --- a/kernel/src/fs/devfs.rs +++ b/kernel/src/fs/devfs.rs @@ -2,7 +2,7 @@ use crate::util::InitOnce; use alloc::boxed::Box; use core::sync::atomic::{AtomicUsize, Ordering}; -use syscall::error::Errno; +use libsys::error::Errno; use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef}; /// Possible character device kinds diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 1afe715..a2ffbd1 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -2,7 +2,7 @@ use super::{PageInfo, PageUsage}; use crate::mem::{virtualize, PAGE_SIZE}; use crate::sync::IrqSafeSpinLock; use core::mem; -use syscall::{ +use libsys::{ error::Errno, mem::{memset, memcpy} }; diff --git a/kernel/src/mem/phys/mod.rs b/kernel/src/mem/phys/mod.rs index 4d95b57..6e1d300 100644 --- a/kernel/src/mem/phys/mod.rs +++ b/kernel/src/mem/phys/mod.rs @@ -3,7 +3,7 @@ use crate::config::{ConfigKey, CONFIG}; use crate::mem::PAGE_SIZE; use core::mem::size_of; -use syscall::error::Errno; +use libsys::error::Errno; mod manager; mod reserved; diff --git a/kernel/src/mem/virt/fixed.rs b/kernel/src/mem/virt/fixed.rs index 01cc7c6..5275576 100644 --- a/kernel/src/mem/virt/fixed.rs +++ b/kernel/src/mem/virt/fixed.rs @@ -5,7 +5,7 @@ use crate::mem::{ virt::{Entry, MapAttributes, Table}, }; use cortex_a::asm::barrier::{self, dsb, isb}; -use syscall::error::Errno; +use libsys::error::Errno; const DEVICE_MAP_OFFSET: usize = mem::KERNEL_OFFSET + (256usize << 30); diff --git a/kernel/src/mem/virt/mod.rs b/kernel/src/mem/virt/mod.rs index 0dade9a..5e879e5 100644 --- a/kernel/src/mem/virt/mod.rs +++ b/kernel/src/mem/virt/mod.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::ops::Deref; use cortex_a::asm::barrier::{self, dsb, isb}; use cortex_a::registers::TTBR0_EL1; -use syscall::error::Errno; +use libsys::error::Errno; use tock_registers::interfaces::Writeable; pub mod table; diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index 4c4ba20..d686fa7 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -5,7 +5,7 @@ use crate::mem::{ phys::{self, PageUsage}, }; use core::ops::{Index, IndexMut}; -use syscall::{error::Errno, mem::memset}; +use libsys::{error::Errno, mem::memset}; /// Transparent wrapper structure representing a single /// translation table entry diff --git a/kernel/src/proc/elf.rs b/kernel/src/proc/elf.rs index 4075ac9..cfe3125 100644 --- a/kernel/src/proc/elf.rs +++ b/kernel/src/proc/elf.rs @@ -5,7 +5,7 @@ use crate::mem::{ virt::{MapAttributes, Space}, }; use core::mem::{size_of, MaybeUninit}; -use syscall::{ +use libsys::{ error::Errno, traits::{Read, Seek, SeekDir} }; diff --git a/kernel/src/proc/io.rs b/kernel/src/proc/io.rs index 2b97960..2b44c5e 100644 --- a/kernel/src/proc/io.rs +++ b/kernel/src/proc/io.rs @@ -1,6 +1,6 @@ //! Process file descriptors and I/O context use alloc::collections::BTreeMap; -use syscall::error::Errno; +use libsys::error::Errno; use vfs::{FileRef, Ioctx}; /// Process I/O context. Contains file tables, root/cwd info etc. diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 02acc22..8a667cb 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -11,7 +11,7 @@ use alloc::rc::Rc; use core::cell::UnsafeCell; use core::fmt; use core::sync::atomic::{AtomicU32, Ordering}; -use syscall::error::Errno; +use libsys::error::Errno; pub use crate::arch::platform::context::{self, Context}; diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index c40783c..52d9d37 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -6,7 +6,7 @@ use crate::proc::{self, sched::SCHED, Pid, Process}; use crate::sync::IrqSafeSpinLock; use alloc::collections::LinkedList; use core::time::Duration; -use syscall::error::Errno; +use libsys::error::Errno; /// Wait channel structure. Contains a queue of processes /// waiting for some event to happen. diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 9b0715c..61108b8 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -2,7 +2,7 @@ use crate::mem; use core::mem::size_of; -use syscall::error::Errno; +use libsys::error::Errno; fn translate(virt: usize) -> Option { let mut res: usize; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 234c6a5..cb7f880 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -6,7 +6,7 @@ use crate::proc::{elf, wait, Pid, Process, ProcessIo}; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; -use syscall::{ +use libsys::{ abi, error::Errno, stat::{AT_EMPTY_PATH, AT_FDCWD}, diff --git a/syscall/Cargo.toml b/libsys/Cargo.toml similarity index 92% rename from syscall/Cargo.toml rename to libsys/Cargo.toml index 878f881..1524b9c 100644 --- a/syscall/Cargo.toml +++ b/libsys/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "syscall" +name = "libsys" version = "0.1.0" edition = "2021" diff --git a/syscall/src/abi.rs b/libsys/src/abi.rs similarity index 100% rename from syscall/src/abi.rs rename to libsys/src/abi.rs diff --git a/syscall/src/calls.rs b/libsys/src/calls.rs similarity index 100% rename from syscall/src/calls.rs rename to libsys/src/calls.rs diff --git a/syscall/src/error.rs b/libsys/src/error.rs similarity index 100% rename from syscall/src/error.rs rename to libsys/src/error.rs diff --git a/syscall/src/ioctl.rs b/libsys/src/ioctl.rs similarity index 100% rename from syscall/src/ioctl.rs rename to libsys/src/ioctl.rs diff --git a/syscall/src/lib.rs b/libsys/src/lib.rs similarity index 100% rename from syscall/src/lib.rs rename to libsys/src/lib.rs diff --git a/syscall/src/mem.rs b/libsys/src/mem.rs similarity index 100% rename from syscall/src/mem.rs rename to libsys/src/mem.rs diff --git a/syscall/src/path.rs b/libsys/src/path.rs similarity index 100% rename from syscall/src/path.rs rename to libsys/src/path.rs diff --git a/syscall/src/stat.rs b/libsys/src/stat.rs similarity index 100% rename from syscall/src/stat.rs rename to libsys/src/stat.rs diff --git a/syscall/src/termios.rs b/libsys/src/termios.rs similarity index 100% rename from syscall/src/termios.rs rename to libsys/src/termios.rs diff --git a/syscall/src/traits.rs b/libsys/src/traits.rs similarity index 100% rename from syscall/src/traits.rs rename to libsys/src/traits.rs diff --git a/libusr/Cargo.toml b/libusr/Cargo.toml index 26a72d1..0b91506 100644 --- a/libusr/Cargo.toml +++ b/libusr/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syscall = { path = "../syscall", features = ["user"] } +libsys = { path = "../libsys", features = ["user"] } diff --git a/libusr/src/io.rs b/libusr/src/io.rs index 5968513..c98712c 100644 --- a/libusr/src/io.rs +++ b/libusr/src/io.rs @@ -1,5 +1,5 @@ use core::fmt; -use syscall::{ +use libsys::{ calls::{sys_fstatat, sys_write}, stat::{Stat, AT_FDCWD}, }; diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index f5e6993..bff9503 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -7,9 +7,9 @@ pub mod io; pub mod os; pub mod sys { - pub use syscall::calls::*; - pub use syscall::stat::{self, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; - pub use syscall::termios; + pub use libsys::calls::*; + pub use libsys::stat::{self, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; + pub use libsys::termios; } #[link_section = ".text._start"] diff --git a/libusr/src/os.rs b/libusr/src/os.rs index 76058da..bd75771 100644 --- a/libusr/src/os.rs +++ b/libusr/src/os.rs @@ -1,7 +1,7 @@ use crate::sys; use core::fmt; use core::mem::{size_of, MaybeUninit}; -use syscall::{ioctl::IoctlCmd, termios::Termios}; +use libsys::{ioctl::IoctlCmd, termios::Termios}; pub fn get_tty_attrs(fd: u32) -> Result { let mut termios = MaybeUninit::::uninit(); From 47ef7e29fedba431934fff4806049ffc53af760c Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 21:15:12 +0200 Subject: [PATCH 05/42] feature: add derive macro for auto-CharDevice --- Cargo.lock | 17 +++++-- Cargo.toml | 7 +-- kernel/Cargo.toml | 1 + kernel/macros/Cargo.toml | 13 +++++ kernel/macros/src/lib.rs | 38 ++++++++++++++ .../src/arch/aarch64/mach_orangepi3/uart.rs | 18 +------ kernel/src/dev/serial/pl011.rs | 51 ++++++++++--------- kernel/src/main.rs | 2 + 8 files changed, 98 insertions(+), 49 deletions(-) create mode 100644 kernel/macros/Cargo.toml create mode 100644 kernel/macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index dbb4da4..8202738 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,6 +73,7 @@ dependencies = [ "cortex-a", "fdt-rs", "libsys", + "macros", "memfs", "tock-registers", "vfs", @@ -92,6 +93,14 @@ dependencies = [ "libsys", ] +[[package]] +name = "macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "memfs" version = "0.1.0" @@ -135,9 +144,9 @@ version = "0.1.0" [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] @@ -183,9 +192,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 3187e18..4ae5460 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,11 +9,12 @@ edition = "2018" [workspace] members = [ - "fs/vfs", - "fs/memfs", "fs/fat32", - "libsys", + "fs/memfs", + "fs/vfs", "kernel", + "kernel/macros", + "libsys", "libusr", "user", ] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index da46004..8af6ab4 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -17,6 +17,7 @@ cfg-if = "1.x.x" tock-registers = "0.7.x" fdt-rs = { version = "0.x.x", default-features = false } bitflags = "^1.3.0" +macros = { path = "macros" } [target.'cfg(target_arch = "aarch64")'.dependencies] cortex-a = { version = "6.x.x" } diff --git a/kernel/macros/Cargo.toml b/kernel/macros/Cargo.toml new file mode 100644 index 0000000..7894fc4 --- /dev/null +++ b/kernel/macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "macros" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +syn = "^1.0.81" +quote = "^1.0.10" diff --git a/kernel/macros/src/lib.rs b/kernel/macros/src/lib.rs new file mode 100644 index 0000000..fc36d2d --- /dev/null +++ b/kernel/macros/src/lib.rs @@ -0,0 +1,38 @@ +extern crate proc_macro; +extern crate syn; +#[macro_use] +extern crate quote; + +use proc_macro::TokenStream; +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(TtyCharDevice)] +pub fn derive_tty_char_device(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + + if !ast.generics.params.is_empty() { + panic!( + "Derived TtyCharDevice cannot have generic parameters: {:?}", + ast.ident + ); + } + let ident = ast.ident; + + quote! { + impl vfs::CharDevice for #ident { + fn read(&self, blocking: bool, data: &mut [u8]) -> Result { + assert!(blocking); + crate::dev::tty::TtyDevice::line_read(self, data) + } + fn write(&self, blocking: bool, data: &[u8]) -> Result { + assert!(blocking); + crate::dev::tty::TtyDevice::line_write(self, data) + } + fn ioctl(&self, cmd: libsys::ioctl::IoctlCmd, ptr: usize, len: usize) -> + Result + { + crate::dev::tty::TtyDevice::tty_ioctl(self, cmd, ptr, len) + } + } + }.into() +} diff --git a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs index 147444f..efa53cc 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs @@ -12,7 +12,6 @@ use libsys::error::Errno; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; use tock_registers::registers::{Aliased, ReadOnly, ReadWrite}; use tock_registers::{register_bitfields, register_structs}; -use vfs::{CharDevice, IoctlCmd}; register_bitfields! [ u32, @@ -78,6 +77,7 @@ struct UartInner { regs: DeviceMemoryIo, } +#[derive(TtyCharDevice)] pub(super) struct Uart { inner: InitOnce>, ring: CharRing<16>, @@ -123,22 +123,6 @@ impl SerialDevice for Uart { } } -impl CharDevice for Uart { - fn read(&self, blocking: bool, data: &mut [u8]) -> Result { - assert!(blocking); - self.line_read(data) - } - - fn write(&self, blocking: bool, data: &[u8]) -> Result { - assert!(blocking); - self.line_write(data) - } - - fn ioctl(&self, cmd: IoctlCmd, ptr: usize, len: usize) -> Result { - self.tty_ioctl(cmd, ptr, len) - } -} - impl TtyDevice<16> for Uart { fn ring(&self) -> &CharRing<16> { &self.ring diff --git a/kernel/src/dev/serial/pl011.rs b/kernel/src/dev/serial/pl011.rs index 27be9db..154183f 100644 --- a/kernel/src/dev/serial/pl011.rs +++ b/kernel/src/dev/serial/pl011.rs @@ -78,6 +78,7 @@ struct Pl011Inner { } /// Device struct for PL011 +#[derive(TtyCharDevice)] pub struct Pl011 { inner: InitOnce>, ring: CharRing<16>, @@ -117,16 +118,16 @@ impl Pl011Inner { } } -impl fmt::Write for Pl011Inner { - fn write_str(&mut self, s: &str) -> fmt::Result { - for &c in s.as_bytes() { - unsafe { - self.send(c); - } - } - Ok(()) - } -} +// impl fmt::Write for Pl011Inner { +// fn write_str(&mut self, s: &str) -> fmt::Result { +// for &c in s.as_bytes() { +// unsafe { +// self.send(c); +// } +// } +// Ok(()) +// } +// } impl IntSource for Pl011 { fn handle_irq(&self) -> Result<(), Errno> { @@ -168,21 +169,21 @@ impl SerialDevice for Pl011 { } } -impl CharDevice for Pl011 { - fn read(&self, blocking: bool, data: &mut [u8]) -> Result { - assert!(blocking); - self.line_read(data) - } - - fn write(&self, blocking: bool, data: &[u8]) -> Result { - assert!(blocking); - self.line_write(data) - } - - fn ioctl(&self, cmd: IoctlCmd, ptr: usize, len: usize) -> Result { - self.tty_ioctl(cmd, ptr, len) - } -} +// impl CharDevice for Pl011 { +// fn read(&self, blocking: bool, data: &mut [u8]) -> Result { +// assert!(blocking); +// self.line_read(data) +// } +// +// fn write(&self, blocking: bool, data: &[u8]) -> Result { +// assert!(blocking); +// self.line_write(data) +// } +// +// fn ioctl(&self, cmd: IoctlCmd, ptr: usize, len: usize) -> Result { +// self.tty_ioctl(cmd, ptr, len) +// } +// } impl TtyDevice<16> for Pl011 { fn ring(&self) -> &CharRing<16> { diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 3cc3a3b..277b093 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -18,6 +18,8 @@ #![no_main] #![warn(missing_docs)] +#[macro_use] +extern crate macros; #[macro_use] extern crate cfg_if; #[macro_use] From dd8033b51c42f2e43e7574a8f18d245d586cebe2 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 22:08:55 +0200 Subject: [PATCH 06/42] feature: simple macro to auto-impl VnodeImpl items --- Cargo.lock | 9 ++++ Cargo.toml | 1 + fs/macros/Cargo.toml | 13 +++++ fs/macros/src/lib.rs | 119 +++++++++++++++++++++++++++++++++++++++++++ fs/vfs/Cargo.toml | 1 + fs/vfs/src/char.rs | 25 +-------- fs/vfs/src/file.rs | 43 ++++------------ fs/vfs/src/ioctx.rs | 32 ++---------- fs/vfs/src/lib.rs | 3 ++ fs/vfs/src/node.rs | 30 ++--------- 10 files changed, 164 insertions(+), 112 deletions(-) create mode 100644 fs/macros/Cargo.toml create mode 100644 fs/macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 8202738..0958306 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,14 @@ dependencies = [ "unsafe_unwrap", ] +[[package]] +name = "fs-macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "kernel" version = "0.1.0" @@ -230,5 +238,6 @@ dependencies = [ name = "vfs" version = "0.1.0" dependencies = [ + "fs-macros", "libsys", ] diff --git a/Cargo.toml b/Cargo.toml index 4ae5460..94aff48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" [workspace] members = [ "fs/fat32", + "fs/macros", "fs/memfs", "fs/vfs", "kernel", diff --git a/fs/macros/Cargo.toml b/fs/macros/Cargo.toml new file mode 100644 index 0000000..f73f66c --- /dev/null +++ b/fs/macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "fs-macros" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +syn = { version = "^1.0.81", features = ["full"] } +quote = "^1.0.10" + +[lib] +proc-macro = true diff --git a/fs/macros/src/lib.rs b/fs/macros/src/lib.rs new file mode 100644 index 0000000..4ccd843 --- /dev/null +++ b/fs/macros/src/lib.rs @@ -0,0 +1,119 @@ +extern crate proc_macro; +extern crate syn; +#[macro_use] +extern crate quote; + +use proc_macro::TokenStream; +use quote::ToTokens; +use std::collections::HashSet; +use syn::{parse_macro_input, ImplItem, ItemImpl, Ident}; + +fn impl_inode_fn(name: &str, behavior: T) -> ImplItem { + ImplItem::Verbatim(match name { + "create" => quote! { + fn create(&mut self, _at: VnodeRef, _name: &str, kind: VnodeKind) -> Result { + #behavior + } + }, + "remove" => quote! { + fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { + #behavior + } + }, + "lookup" => quote! { + fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { + #behavior + } + }, + "stat" => quote! { + fn stat(&mut self, _at: VnodeRef, _stat: &mut Stat) -> Result<(), Errno> { + #behavior + } + }, + "truncate" => quote! { + fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { + #behavior + } + }, + "size" => quote! { + fn size(&mut self, _node: VnodeRef) -> Result { + #behavior + } + }, + "read" => quote! { + fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { + #behavior + } + }, + "write" => quote! { + fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { + #behavior + } + }, + "open" => quote! { + fn open(&mut self, _node: VnodeRef, _flags: OpenFlags) -> Result { + #behavior + } + }, + "close" => quote! { + fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { + #behavior + } + }, + "ioctl" => quote! { + fn ioctl(&mut self, _node: VnodeRef, _cmd: IoctlCmd, _ptr: usize, _len: usize) -> Result { + #behavior + } + }, + _ => panic!("TODO implement {:?}", name), + }) +} + +#[proc_macro_attribute] +pub fn auto_inode(attr: TokenStream, input: TokenStream) -> TokenStream { + let mut impl_item = parse_macro_input!(input as ItemImpl); + let mut missing = HashSet::::new(); + let behavior = if attr.is_empty() { + "unimplemented".to_string() + } else { + parse_macro_input!(attr as Ident).to_string() + }; + let behavior = match behavior.as_str() { + "unimplemented" => quote! { unimplemented!() }, + "panic" => quote! { panic!() }, + "error" => quote! { Err(libsys::error::Errno::NotImplemented) }, + _ => panic!("Unknown #[auto_inode] behavior: {:?}", behavior) + }; + + missing.insert("create".to_string()); + missing.insert("remove".to_string()); + missing.insert("lookup".to_string()); + missing.insert("open".to_string()); + missing.insert("close".to_string()); + missing.insert("truncate".to_string()); + missing.insert("read".to_string()); + missing.insert("write".to_string()); + missing.insert("stat".to_string()); + missing.insert("size".to_string()); + missing.insert("ioctl".to_string()); + + for item in &impl_item.items { + match item { + ImplItem::Method(method) => { + let name = &method.sig.ident.to_string(); + if missing.contains(name) { + missing.remove(name); + } + } + _ => panic!("Unexpected impl item"), + } + } + + for item in &missing { + impl_item + .items + .push(impl_inode_fn(item, behavior.clone())); + } + + impl_item.to_token_stream().into() +} diff --git a/fs/vfs/Cargo.toml b/fs/vfs/Cargo.toml index d05ed41..24ade6d 100644 --- a/fs/vfs/Cargo.toml +++ b/fs/vfs/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] libsys = { path = "../../libsys" } +fs-macros = { path = "../macros" } diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index 7eae7de..fa143b0 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -25,19 +25,8 @@ pub struct CharDeviceWrapper { device: &'static dyn CharDevice, } +#[auto_inode(error)] impl VnodeImpl for CharDeviceWrapper { - fn create(&mut self, _at: VnodeRef, _name: &str, _kind: VnodeKind) -> Result { - panic!(); - } - - fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { - panic!(); - } - - fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { - panic!(); - } - fn open(&mut self, _node: VnodeRef, _opts: OpenFlags) -> Result { Ok(0) } @@ -54,18 +43,6 @@ impl VnodeImpl for CharDeviceWrapper { self.device.write(true, data) } - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - panic!(); - } - - fn size(&mut self, _node: VnodeRef) -> Result { - panic!(); - } - - fn stat(&mut self, _node: VnodeRef, _stat: &mut Stat) -> Result<(), Errno> { - todo!(); - } - fn ioctl(&mut self, _node: VnodeRef, cmd: IoctlCmd, ptr: usize, len: usize) -> Result { self.device.ioctl(cmd, ptr, len) } diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index af6bf77..e7e794d 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -3,8 +3,8 @@ use alloc::rc::Rc; use core::cell::RefCell; use core::cmp::min; use libsys::{ + error::Errno, traits::{Read, Seek, SeekDir, Write}, - error::Errno }; struct NormalFile { @@ -135,11 +135,13 @@ impl Drop for File { mod tests { use super::*; use crate::{Vnode, VnodeImpl, VnodeKind, VnodeRef}; + use libsys::{stat::OpenFlags, ioctl::IoctlCmd, stat::Stat}; use alloc::boxed::Box; use alloc::rc::Rc; struct DummyInode; + #[auto_inode] impl VnodeImpl for DummyInode { fn create( &mut self, @@ -152,25 +154,17 @@ mod tests { Ok(node) } - fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { - Err(Errno::NotImplemented) - } - - fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { - todo!() - } - - fn open(&mut self, _node: VnodeRef) -> Result { + fn open(&mut self, _node: VnodeRef, _flags: OpenFlags) -> Result { Ok(0) } fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { - Err(Errno::NotImplemented) + Ok(()) } fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result { #[cfg(test)] - println!("read {}", pos); + println!("read {} at {}", data.len(), pos); let len = 123; if pos >= len { return Ok(0); @@ -185,41 +179,24 @@ mod tests { fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { Err(Errno::NotImplemented) } - - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - Err(Errno::NotImplemented) - } - - fn size(&mut self, _node: VnodeRef) -> Result { - Err(Errno::NotImplemented) - } } #[test] fn test_normal_read() { let node = Vnode::new("", VnodeKind::Regular, 0); node.set_data(Box::new(DummyInode {})); - let mut file = node.open().unwrap(); - - match &file.inner { - FileInner::Normal(inner) => { - assert!(Rc::ptr_eq(&inner.vnode, &node)); - assert_eq!(inner.pos, 0); - } - _ => panic!("Invalid file.inner"), - } - + let mut file = node.open(OpenFlags::O_RDONLY).unwrap(); let mut buf = [0u8; 4096]; - assert_eq!(file.read(&mut buf[0..32]).unwrap(), 32); + assert_eq!(file.borrow_mut().read(&mut buf[0..32]).unwrap(), 32); for i in 0..32 { assert_eq!((i & 0xFF) as u8, buf[i]); } - assert_eq!(file.read(&mut buf[0..64]).unwrap(), 64); + assert_eq!(file.borrow_mut().read(&mut buf[0..64]).unwrap(), 64); for i in 0..64 { assert_eq!(((i + 32) & 0xFF) as u8, buf[i]); } - assert_eq!(file.read(&mut buf[0..64]).unwrap(), 27); + assert_eq!(file.borrow_mut().read(&mut buf[0..64]).unwrap(), 27); for i in 0..27 { assert_eq!(((i + 96) & 0xFF) as u8, buf[i]); } diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index 2980d20..a7650d9 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -1,7 +1,7 @@ use crate::{FileMode, FileRef, OpenFlags, VnodeKind, VnodeRef}; use libsys::{ error::Errno, - path::{path_component_left, path_component_right} + path::{path_component_left, path_component_right}, }; /// I/O context structure @@ -119,9 +119,11 @@ mod tests { use super::*; use crate::{Vnode, VnodeImpl, VnodeKind}; use alloc::{boxed::Box, rc::Rc}; + use libsys::{ioctl::IoctlCmd, stat::OpenFlags, stat::Stat}; pub struct DummyInode; + #[auto_inode] impl VnodeImpl for DummyInode { fn create( &mut self, @@ -134,37 +136,9 @@ mod tests { Ok(vnode) } - fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { - todo!() - } - fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { Err(Errno::DoesNotExist) } - - fn open(&mut self, _node: VnodeRef) -> Result { - todo!() - } - - fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { - todo!() - } - - fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { - todo!() - } - - fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { - todo!() - } - - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - todo!() - } - - fn size(&mut self, _node: VnodeRef) -> Result { - todo!() - } } #[test] diff --git a/fs/vfs/src/lib.rs b/fs/vfs/src/lib.rs index c8a74fe..374731a 100644 --- a/fs/vfs/src/lib.rs +++ b/fs/vfs/src/lib.rs @@ -7,6 +7,9 @@ #[macro_use] extern crate std; +#[macro_use] +extern crate fs_macros; + extern crate alloc; pub use libsys::stat::{FileMode, OpenFlags, Stat}; diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 8df4eee..2893299 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -405,8 +405,10 @@ impl fmt::Debug for Vnode { mod tests { use super::*; + use libsys::{stat::OpenFlags, ioctl::IoctlCmd, stat::Stat}; pub struct DummyInode; + #[auto_inode] impl VnodeImpl for DummyInode { fn create( &mut self, @@ -426,30 +428,6 @@ mod tests { fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { Err(Errno::DoesNotExist) } - - fn open(&mut self, _node: VnodeRef) -> Result { - Err(Errno::NotImplemented) - } - - fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { - Err(Errno::NotImplemented) - } - - fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { - Err(Errno::NotImplemented) - } - - fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { - Err(Errno::NotImplemented) - } - - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - Err(Errno::NotImplemented) - } - - fn size(&mut self, _node: VnodeRef) -> Result { - Err(Errno::NotImplemented) - } } #[test] @@ -469,10 +447,10 @@ mod tests { root.set_data(Box::new(DummyInode {})); - let node = root.mkdir("test", FileMode::default_dir()).unwrap(); + let node = root.create("test", FileMode::default_dir(), VnodeKind::Directory).unwrap(); assert_eq!( - root.mkdir("test", FileMode::default_dir()).unwrap_err(), + root.create("test", FileMode::default_dir(), VnodeKind::Directory).unwrap_err(), Errno::AlreadyExists ); From 94c2fc3c8225e22781de7e3b1ee76d1f7fcf9611 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 22:09:55 +0200 Subject: [PATCH 07/42] refactor: rename macros -> kernel-macros --- Cargo.lock | 18 +++++++++--------- kernel/Cargo.toml | 2 +- kernel/macros/Cargo.toml | 2 +- kernel/src/main.rs | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0958306..3471e1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,13 +80,21 @@ dependencies = [ "cfg-if", "cortex-a", "fdt-rs", + "kernel-macros", "libsys", - "macros", "memfs", "tock-registers", "vfs", ] +[[package]] +name = "kernel-macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "libsys" version = "0.1.0" @@ -101,14 +109,6 @@ dependencies = [ "libsys", ] -[[package]] -name = "macros" -version = "0.1.0" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "memfs" version = "0.1.0" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 8af6ab4..eee87ea 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = "1.x.x" tock-registers = "0.7.x" fdt-rs = { version = "0.x.x", default-features = false } bitflags = "^1.3.0" -macros = { path = "macros" } +kernel-macros = { path = "macros" } [target.'cfg(target_arch = "aarch64")'.dependencies] cortex-a = { version = "6.x.x" } diff --git a/kernel/macros/Cargo.toml b/kernel/macros/Cargo.toml index 7894fc4..fed4cd7 100644 --- a/kernel/macros/Cargo.toml +++ b/kernel/macros/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "macros" +name = "kernel-macros" version = "0.1.0" edition = "2021" diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 277b093..b3f9efb 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -19,7 +19,7 @@ #![warn(missing_docs)] #[macro_use] -extern crate macros; +extern crate kernel_macros; #[macro_use] extern crate cfg_if; #[macro_use] From 7e04b11da8a4dd8ba9b9b2d570b36a6af7a62ee3 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 22:19:21 +0200 Subject: [PATCH 08/42] refactor: use auto_inode in memfs,fat32 --- Cargo.lock | 3 +++ fs/fat32/Cargo.toml | 2 ++ fs/fat32/src/data.rs | 2 +- fs/fat32/src/dir.rs | 46 +++++---------------------------- fs/fat32/src/file.rs | 40 ++++++++--------------------- fs/fat32/src/lib.rs | 9 +++++-- fs/memfs/Cargo.toml | 1 + fs/memfs/src/dir.rs | 47 +++++----------------------------- fs/memfs/src/file.rs | 36 +++++--------------------- fs/memfs/src/lib.rs | 8 ++++-- fs/vfs/src/char.rs | 8 ++++-- fs/vfs/src/ioctx.rs | 3 ++- fs/vfs/src/lib.rs | 4 +-- fs/vfs/src/node.rs | 17 ++++++++---- kernel/src/dev/serial/pl011.rs | 2 +- kernel/src/init.rs | 3 ++- kernel/src/syscall/mod.rs | 5 ++-- 17 files changed, 79 insertions(+), 157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3471e1a..a042c61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,6 +45,8 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" name = "fat32" version = "0.1.0" dependencies = [ + "fs-macros", + "libsys", "vfs", ] @@ -113,6 +115,7 @@ dependencies = [ name = "memfs" version = "0.1.0" dependencies = [ + "fs-macros", "libsys", "vfs", ] diff --git a/fs/fat32/Cargo.toml b/fs/fat32/Cargo.toml index 595cb0a..7938472 100644 --- a/fs/fat32/Cargo.toml +++ b/fs/fat32/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" [dependencies] vfs = { path = "../vfs" } +fs-macros = { path = "../macros" } +libsys = { path = "../../libsys" } diff --git a/fs/fat32/src/data.rs b/fs/fat32/src/data.rs index 469ac83..19df264 100644 --- a/fs/fat32/src/data.rs +++ b/fs/fat32/src/data.rs @@ -1,4 +1,4 @@ -use libcommon::{read_le16, read_le32}; +use libsys::mem::{read_le16, read_le32}; #[derive(Debug)] pub struct Bpb { diff --git a/fs/fat32/src/dir.rs b/fs/fat32/src/dir.rs index 4966d06..86c7547 100644 --- a/fs/fat32/src/dir.rs +++ b/fs/fat32/src/dir.rs @@ -1,7 +1,11 @@ use crate::{Bpb, FileInode}; use alloc::{borrow::ToOwned, boxed::Box, string::String}; -use error::Errno; -use libcommon::{read_le16, read_le32}; +use libsys::{ + error::Errno, + ioctl::IoctlCmd, + mem::{read_le16, read_le32}, + stat::{OpenFlags, Stat}, +}; use vfs::{BlockDevice, Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirectoryInode { @@ -26,20 +30,8 @@ pub struct Dirent { pub cluster: u32, } +#[auto_inode] impl VnodeImpl for DirectoryInode { - fn create( - &mut self, - _parent: VnodeRef, - _name: &str, - _kind: VnodeKind, - ) -> Result { - todo!() - } - - fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { - todo!() - } - fn lookup(&mut self, parent: VnodeRef, name: &str) -> Result { let fs = parent.fs().unwrap(); let dirent = { @@ -72,30 +64,6 @@ impl VnodeImpl for DirectoryInode { } Ok(vnode) } - - fn open(&mut self, _node: VnodeRef) -> Result { - todo!() - } - - fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { - todo!() - } - - fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { - todo!() - } - - fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { - todo!() - } - - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - todo!() - } - - fn size(&mut self, _node: VnodeRef) -> Result { - todo!() - } } impl Iterator for FatIterator<'_> { diff --git a/fs/fat32/src/file.rs b/fs/fat32/src/file.rs index 9d8a1f5..a0819e0 100644 --- a/fs/fat32/src/file.rs +++ b/fs/fat32/src/file.rs @@ -1,5 +1,9 @@ use crate::Bpb; -use error::Errno; +use libsys::{ + stat::{Stat, OpenFlags}, + ioctl::IoctlCmd, + error::Errno +}; use vfs::{VnodeImpl, VnodeKind, VnodeRef}; pub struct FileInode { @@ -7,27 +11,15 @@ pub struct FileInode { pub size: u32, } +#[auto_inode] impl VnodeImpl for FileInode { - fn create(&mut self, _at: VnodeRef, _name: &str, _kind: VnodeKind) -> Result { - panic!() - } - - fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { - panic!() - } - - fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result { - panic!() - } - - fn open(&mut self, _node: VnodeRef) -> Result { + fn open(&mut self, _node: VnodeRef, flags: OpenFlags) -> Result { + if flags & OpenFlags::O_ACCESS != OpenFlags::O_RDONLY { + return Err(Errno::ReadOnly); + } Ok(0) } - fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { - todo!() - } - fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result { let size = self.size as usize; if pos >= size { @@ -60,16 +52,4 @@ impl VnodeImpl for FileInode { Ok(off) } - - fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { - todo!() - } - - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - todo!() - } - - fn size(&mut self, _node: VnodeRef) -> Result { - todo!() - } } diff --git a/fs/fat32/src/lib.rs b/fs/fat32/src/lib.rs index 27e31ce..7561394 100644 --- a/fs/fat32/src/lib.rs +++ b/fs/fat32/src/lib.rs @@ -4,13 +4,18 @@ #[macro_use] extern crate std; +#[macro_use] +extern crate fs_macros; + extern crate alloc; use alloc::{boxed::Box, rc::Rc}; use core::any::Any; use core::cell::{Ref, RefCell}; -use error::Errno; -use libcommon::read_le32; +use libsys::{ + mem::read_le32, + error::Errno, +}; use vfs::{BlockDevice, Filesystem, Vnode, VnodeKind, VnodeRef}; pub mod dir; diff --git a/fs/memfs/Cargo.toml b/fs/memfs/Cargo.toml index 0ee1a70..cbb1357 100644 --- a/fs/memfs/Cargo.toml +++ b/fs/memfs/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] vfs = { path = "../vfs" } +fs-macros = { path = "../macros" } libsys = { path = "../../libsys" } [features] diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index 4ee24e5..88b8764 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -1,12 +1,17 @@ use crate::{BlockAllocator, Bvec, FileInode}; use alloc::boxed::Box; -use libsys::error::Errno; -use vfs::{IoctlCmd, OpenFlags, Stat, Vnode, VnodeImpl, VnodeKind, VnodeRef}; +use libsys::{ + error::Errno, + stat::{OpenFlags, Stat}, + ioctl::IoctlCmd +}; +use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirInode { alloc: A, } +#[auto_inode] impl VnodeImpl for DirInode { fn create( &mut self, @@ -30,44 +35,6 @@ impl VnodeImpl for DirInode { fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { Ok(()) } - - fn open(&mut self, _node: VnodeRef, _flags: OpenFlags) -> Result { - todo!() - } - - fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { - todo!() - } - - fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { - todo!() - } - - fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { - todo!() - } - - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - todo!() - } - - fn size(&mut self, _node: VnodeRef) -> Result { - todo!() - } - - fn stat(&mut self, _node: VnodeRef, _stat: &mut Stat) -> Result<(), Errno> { - todo!(); - } - - fn ioctl( - &mut self, - node: VnodeRef, - cmd: IoctlCmd, - ptr: usize, - len: usize, - ) -> Result { - todo!() - } } impl DirInode { diff --git a/fs/memfs/src/file.rs b/fs/memfs/src/file.rs index 639155b..7aab458 100644 --- a/fs/memfs/src/file.rs +++ b/fs/memfs/src/file.rs @@ -1,29 +1,17 @@ use crate::{BlockAllocator, Bvec}; -use libsys::error::Errno; -use vfs::{OpenFlags, Stat, VnodeImpl, VnodeKind, VnodeRef, IoctlCmd}; +use libsys::{ + error::Errno, + stat::{OpenFlags, Stat}, + ioctl::IoctlCmd +}; +use vfs::{VnodeImpl, VnodeKind, VnodeRef}; pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> { data: Bvec<'a, A>, } +#[auto_inode] impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { - fn create( - &mut self, - _parent: VnodeRef, - _name: &str, - _kind: VnodeKind, - ) -> Result { - panic!() - } - - fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result { - panic!() - } - - fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { - panic!() - } - fn open(&mut self, _node: VnodeRef, _mode: OpenFlags) -> Result { Ok(0) } @@ -54,16 +42,6 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { stat.mode = 0o755; Ok(()) } - - fn ioctl( - &mut self, - node: VnodeRef, - cmd: IoctlCmd, - ptr: usize, - len: usize, - ) -> Result { - todo!() - } } impl<'a, A: BlockAllocator + Copy + 'static> FileInode<'a, A> { diff --git a/fs/memfs/src/lib.rs b/fs/memfs/src/lib.rs index 5529c34..2e4a1b5 100644 --- a/fs/memfs/src/lib.rs +++ b/fs/memfs/src/lib.rs @@ -11,14 +11,18 @@ extern crate alloc; #[macro_use] extern crate std; +#[macro_use] +extern crate fs_macros; + use alloc::{boxed::Box, rc::Rc}; use core::any::Any; use core::cell::{Ref, RefCell}; use libsys::{ error::Errno, - path::{path_component_right, path_component_left} + path::{path_component_left, path_component_right}, + stat::FileMode, }; -use vfs::{BlockDevice, FileMode, Filesystem, Vnode, VnodeKind, VnodeRef}; +use vfs::{BlockDevice, Filesystem, Vnode, VnodeKind, VnodeRef}; mod block; pub use block::{BlockAllocator, BlockRef}; diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index fa143b0..a0af834 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -1,5 +1,9 @@ -use crate::{OpenFlags, Stat, VnodeImpl, VnodeKind, VnodeRef, IoctlCmd}; -use libsys::error::Errno; +use crate::{VnodeImpl, VnodeKind, VnodeRef}; +use libsys::{ + error::Errno, + stat::{OpenFlags, Stat}, + ioctl::IoctlCmd +}; /// Generic character device trait pub trait CharDevice { diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index a7650d9..3dc3e25 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -1,6 +1,7 @@ -use crate::{FileMode, FileRef, OpenFlags, VnodeKind, VnodeRef}; +use crate::{FileRef, VnodeKind, VnodeRef}; use libsys::{ error::Errno, + stat::{OpenFlags, FileMode}, path::{path_component_left, path_component_right}, }; diff --git a/fs/vfs/src/lib.rs b/fs/vfs/src/lib.rs index 374731a..81bbf7f 100644 --- a/fs/vfs/src/lib.rs +++ b/fs/vfs/src/lib.rs @@ -12,8 +12,8 @@ extern crate fs_macros; extern crate alloc; -pub use libsys::stat::{FileMode, OpenFlags, Stat}; -pub use libsys::ioctl::IoctlCmd; +// pub use libsys::stat::{FileMode, OpenFlags, Stat}; +// pub use libsys::ioctl::IoctlCmd; mod block; pub use block::BlockDevice; diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 2893299..de5ea6a 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -1,8 +1,12 @@ -use crate::{File, FileMode, FileRef, Filesystem, IoctlCmd, OpenFlags, Stat}; +use crate::{File, FileRef, Filesystem}; use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec}; use core::cell::{RefCell, RefMut}; use core::fmt; -use libsys::error::Errno; +use libsys::{ + error::Errno, + ioctl::IoctlCmd, + stat::{FileMode, OpenFlags, Stat}, +}; /// Convenience type alias for [Rc] pub type VnodeRef = Rc; @@ -405,7 +409,7 @@ impl fmt::Debug for Vnode { mod tests { use super::*; - use libsys::{stat::OpenFlags, ioctl::IoctlCmd, stat::Stat}; + use libsys::{ioctl::IoctlCmd, stat::OpenFlags, stat::Stat}; pub struct DummyInode; #[auto_inode] @@ -447,10 +451,13 @@ mod tests { root.set_data(Box::new(DummyInode {})); - let node = root.create("test", FileMode::default_dir(), VnodeKind::Directory).unwrap(); + let node = root + .create("test", FileMode::default_dir(), VnodeKind::Directory) + .unwrap(); assert_eq!( - root.create("test", FileMode::default_dir(), VnodeKind::Directory).unwrap_err(), + root.create("test", FileMode::default_dir(), VnodeKind::Directory) + .unwrap_err(), Errno::AlreadyExists ); diff --git a/kernel/src/dev/serial/pl011.rs b/kernel/src/dev/serial/pl011.rs index 154183f..7ea171d 100644 --- a/kernel/src/dev/serial/pl011.rs +++ b/kernel/src/dev/serial/pl011.rs @@ -17,7 +17,7 @@ use tock_registers::{ register_bitfields, register_structs, registers::{ReadOnly, ReadWrite, WriteOnly}, }; -use vfs::{CharDevice, IoctlCmd}; +use vfs::CharDevice; register_bitfields! { u32, diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 0b5f408..19be0bc 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -5,7 +5,8 @@ use crate::fs::{devfs, MemfsBlockAlloc}; use crate::mem; use crate::proc::{elf, Process}; use memfs::Ramfs; -use vfs::{Filesystem, Ioctx, OpenFlags}; +use libsys::stat::OpenFlags; +use vfs::{Filesystem, Ioctx}; /// Kernel init process function #[inline(never)] diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index cb7f880..9061361 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -9,10 +9,11 @@ use core::time::Duration; use libsys::{ abi, error::Errno, - stat::{AT_EMPTY_PATH, AT_FDCWD}, + ioctl::IoctlCmd, + stat::{FileMode, OpenFlags, Stat, AT_EMPTY_PATH, AT_FDCWD}, traits::{Read, Write}, }; -use vfs::{FileMode, IoctlCmd, OpenFlags, Stat, VnodeRef}; +use vfs::VnodeRef; pub mod arg; pub use arg::*; From 0a10b3c0b3be04b372f28d84e31de92d852d3f0e Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 22:27:19 +0200 Subject: [PATCH 09/42] refactor: fix non-doc warnings --- kernel/src/dev/serial/pl011.rs | 2 -- kernel/src/dev/tty.rs | 5 ++--- kernel/src/mem/phys/manager.rs | 4 +--- kernel/src/mem/virt/table.rs | 30 ++++++++++++------------------ libsys/src/ioctl.rs | 1 + 5 files changed, 16 insertions(+), 26 deletions(-) diff --git a/kernel/src/dev/serial/pl011.rs b/kernel/src/dev/serial/pl011.rs index 7ea171d..78d5215 100644 --- a/kernel/src/dev/serial/pl011.rs +++ b/kernel/src/dev/serial/pl011.rs @@ -10,14 +10,12 @@ use crate::dev::{ use crate::mem::virt::DeviceMemoryIo; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use core::fmt; use libsys::error::Errno; use tock_registers::{ interfaces::{ReadWriteable, Readable, Writeable}, register_bitfields, register_structs, registers::{ReadOnly, ReadWrite, WriteOnly}, }; -use vfs::CharDevice; register_bitfields! { u32, diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 56d2775..7985b21 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -9,7 +9,6 @@ use libsys::{ }; use core::mem::size_of; use crate::syscall::arg::validate_user_ptr_struct; -use vfs::CharDevice; #[derive(Debug)] struct CharRingInner { @@ -30,7 +29,7 @@ pub struct CharRing { pub trait TtyDevice: SerialDevice { fn ring(&self) -> &CharRing; - fn tty_ioctl(&self, cmd: IoctlCmd, ptr: usize, len: usize) -> Result { + fn tty_ioctl(&self, cmd: IoctlCmd, ptr: usize, _len: usize) -> Result { match cmd { IoctlCmd::TtyGetAttributes => { // TODO validate size @@ -132,7 +131,7 @@ pub trait TtyDevice: SerialDevice { let idx = data[..off].iter().rposition(|&ch| ch == b' ').unwrap_or(0); let len = off; - for i in idx..len { + for _ in idx..len { self.raw_write(b"\x1B[D \x1B[D").ok(); off -= 1; rem += 1; diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index a2ffbd1..9767758 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -2,9 +2,7 @@ use super::{PageInfo, PageUsage}; use crate::mem::{virtualize, PAGE_SIZE}; use crate::sync::IrqSafeSpinLock; use core::mem; -use libsys::{ - error::Errno, mem::{memset, memcpy} -}; +use libsys::{error::Errno, mem::memcpy}; pub unsafe trait Manager { fn alloc_page(&mut self, pu: PageUsage) -> Result; diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index d686fa7..e105d4b 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -227,7 +227,11 @@ impl Space { let src_phys = unsafe { entry.address_unchecked() }; if !entry.is_cow() { - warnln!("Entry is not marked as CoW: {:#x}, points to {:#x}", virt, src_phys); + warnln!( + "Entry is not marked as CoW: {:#x}, points to {:#x}", + virt, + src_phys + ); return Err(Errno::DoesNotExist); } @@ -270,7 +274,7 @@ impl Space { unsafe { asm!("tlbi vaae1, {}", in(reg) virt_addr); } - res.map(virt_addr, dst_phys, flags); + res.map(virt_addr, dst_phys, flags)?; } } } @@ -288,8 +292,7 @@ impl Space { } assert!(l0_entry.is_table()); - let l1_table = - unsafe { &mut *(mem::virtualize(l0_entry.address_unchecked()) as *mut Table) }; + let l1_table = &mut *(mem::virtualize(l0_entry.address_unchecked()) as *mut Table); for l1i in 0..512 { let l1_entry = l1_table[l1i]; @@ -297,8 +300,7 @@ impl Space { continue; } assert!(l1_entry.is_table()); - let l2_table = - unsafe { &mut *(mem::virtualize(l1_entry.address_unchecked()) as *mut Table) }; + let l2_table = &mut *(mem::virtualize(l1_entry.address_unchecked()) as *mut Table); for l2i in 0..512 { let entry = l2_table[l2i]; @@ -307,20 +309,12 @@ impl Space { } assert!(entry.is_table()); - unsafe { - phys::free_page(unsafe { entry.address_unchecked() }); - } - } - unsafe { - phys::free_page(unsafe { l1_entry.address_unchecked() }); + phys::free_page(entry.address_unchecked()).unwrap(); } + phys::free_page(l1_entry.address_unchecked()).unwrap(); } - unsafe { - phys::free_page(unsafe { l0_entry.address_unchecked() }); - } - } - unsafe { - memset(space as *mut Space as *mut u8, 0, 4096); + phys::free_page(l0_entry.address_unchecked()).unwrap(); } + memset(space as *mut Space as *mut u8, 0, 4096); } } diff --git a/libsys/src/ioctl.rs b/libsys/src/ioctl.rs index dd0196d..9b8d484 100644 --- a/libsys/src/ioctl.rs +++ b/libsys/src/ioctl.rs @@ -3,6 +3,7 @@ use crate::error::Errno; #[derive(Clone, Copy, Debug)] #[repr(u32)] +#[non_exhaustive] pub enum IoctlCmd { TtySetAttributes = 1, TtyGetAttributes = 2, From 00c368c36b97536defc368284005d7624b309b6d Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 22:46:01 +0200 Subject: [PATCH 10/42] refactor: fix clippy warnings --- Makefile | 2 +- fs/vfs/src/char.rs | 1 + fs/vfs/src/node.rs | 1 + kernel/src/dev/tty.rs | 11 +++++++++-- kernel/src/mem/phys/manager.rs | 27 ++++++++++++++------------ kernel/src/mem/phys/mod.rs | 12 ++++++++++++ kernel/src/mem/virt/table.rs | 10 ++++++++++ kernel/src/proc/process.rs | 7 +++++++ kernel/src/proc/sched.rs | 1 + libsys/src/calls.rs | 4 +++- user/src/init/main.rs | 35 +++++++++++++++++++++------------- user/src/shell/main.rs | 2 +- 12 files changed, 83 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 0414121..2ba7720 100644 --- a/Makefile +++ b/Makefile @@ -121,7 +121,7 @@ doc-open: clippy: cd kernel && cargo clippy $(CARGO_BUILD_OPTS) - cd init && cargo clippy \ + cd user && cargo clippy \ --target=../etc/$(ARCH)-osdev5.json \ -Zbuild-std=core,alloc,compiler_builtins $(CARGO_COMMON_OPTS) diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index a0af834..e74f95f 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -20,6 +20,7 @@ pub trait CharDevice { /// will immediately return an error. fn write(&self, blocking: bool, data: &[u8]) -> Result; + /// Performs a TTY control request fn ioctl(&self, cmd: IoctlCmd, ptr: usize, lim: usize) -> Result; } diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index de5ea6a..26de047 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -80,6 +80,7 @@ pub trait VnodeImpl { /// Reports the size of this filesystem object in bytes fn size(&mut self, node: VnodeRef) -> Result; + /// Performs filetype-specific request fn ioctl( &mut self, node: VnodeRef, diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 7985b21..7eec9ac 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -26,9 +26,12 @@ pub struct CharRing { inner: IrqSafeSpinLock>, } +/// Generic teletype device interface pub trait TtyDevice: SerialDevice { + /// Returns a reference to character device's ring buffer fn ring(&self) -> &CharRing; + /// Performs a TTY control request fn tty_ioctl(&self, cmd: IoctlCmd, ptr: usize, _len: usize) -> Result { match cmd { IoctlCmd::TtyGetAttributes => { @@ -46,6 +49,7 @@ pub trait TtyDevice: SerialDevice { } } + /// Processes and writes output an output byte fn line_send(&self, byte: u8) -> Result<(), Errno> { let config = self.ring().config.lock(); @@ -56,6 +60,7 @@ pub trait TtyDevice: SerialDevice { self.send(byte) } + /// Receives input bytes and processes them fn recv_byte(&self, mut byte: u8) { let ring = self.ring(); let config = ring.config.lock(); @@ -96,7 +101,7 @@ pub trait TtyDevice: SerialDevice { let ring = self.ring(); let mut config = ring.config.lock(); - if data.len() == 0 { + if data.is_empty() { return Ok(0); } @@ -104,7 +109,7 @@ pub trait TtyDevice: SerialDevice { drop(config); let byte = ring.getc()?; data[0] = byte; - return Ok(1); + Ok(1) } else { let mut rem = data.len(); let mut off = 0; @@ -164,6 +169,7 @@ pub trait TtyDevice: SerialDevice { } } + /// Processes and writes string bytes fn line_write(&self, data: &[u8]) -> Result { for &byte in data.iter() { self.line_send(byte)?; @@ -171,6 +177,7 @@ pub trait TtyDevice: SerialDevice { Ok(data.len()) } + /// Writes string bytes without any processing fn raw_write(&self, data: &[u8]) -> Result { for &byte in data.iter() { self.send(byte)?; diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 9767758..432d0db 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -97,25 +97,28 @@ unsafe impl Manager for SimpleManager { fn copy_cow_page(&mut self, src: usize) -> Result { let src_index = self.page_index(src); - let page = &mut self.pages[src_index]; - let usage = page.usage; - if usage != PageUsage::UserPrivate { - panic!("CoW not available for non-UserPrivate pages: {:?}", usage); - } + let (usage, refcount) = { + let page = &mut self.pages[src_index]; + let usage = page.usage; + if usage != PageUsage::UserPrivate { + panic!("CoW not available for non-UserPrivate pages: {:?}", usage); + } + let count = page.refcount; + if count > 1 { + page.refcount -= 1; + } + (usage, count) + }; - if page.refcount > 1 { - page.refcount -= 1; - drop(page); + if refcount == 0 { + Ok(src) + } else { let dst_index = self.alloc_single_index(usage)?; let dst = (self.base_index + dst_index) * PAGE_SIZE; unsafe { memcpy(virtualize(dst) as *mut u8, virtualize(src) as *mut u8, 4096); } Ok(dst) - } else { - assert_eq!(page.refcount, 1); - // No additional operations needed - Ok(src) } } diff --git a/kernel/src/mem/phys/mod.rs b/kernel/src/mem/phys/mod.rs index 6e1d300..cfd4dbb 100644 --- a/kernel/src/mem/phys/mod.rs +++ b/kernel/src/mem/phys/mod.rs @@ -89,6 +89,12 @@ pub unsafe fn free_page(page: usize) -> Result<(), Errno> { MANAGER.lock().as_mut().unwrap().free_page(page) } +/// Clones the source page. +/// +/// If returned address is the same as `page`, this means +/// `page`'s refcount has increased and the page is Copy-on-Write. +/// This case has to be handled accordingly +/// /// # Safety /// /// Unsafe: accepts arbitrary `page` arguments @@ -96,6 +102,12 @@ pub unsafe fn fork_page(page: usize) -> Result { MANAGER.lock().as_mut().unwrap().fork_page(page) } +/// Copies a Copy-on-Write page. If refcount is already 1, +/// page does not need to be copied and the same address is returned. +/// +/// # Safety +/// +/// Unsafe: accepts arbitrary `page` arguments pub unsafe fn copy_cow_page(page: usize) -> Result { MANAGER.lock().as_mut().unwrap().copy_cow_page(page) } diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index e105d4b..9f7abe7 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -38,6 +38,7 @@ bitflags! { /// This page is used for device-MMIO mapping and uses MAIR attribute #1 const DEVICE = 1 << 2; + /// Pages marked with this bit are Copy-on-Write const EX_COW = 1 << 55; /// UXN bit -- if set, page may not be used for instruction fetching from EL0 @@ -209,6 +210,8 @@ impl Space { } } + /// Attempts to resolve a page fault at `virt` address by copying the + /// underlying Copy-on-Write mapping (if any is present) pub fn try_cow_copy(&mut self, virt: usize) -> Result<(), Errno> { let virt = virt & !0xFFF; let l0i = virt >> 30; @@ -284,6 +287,13 @@ impl Space { Ok(res) } + /// Releases all the mappings from the address space. Frees all + /// memory pages referenced by this space as well as those used for + /// its paging tables. + /// + /// # Safety + /// + /// Unsafe: may invalidate currently active address space pub unsafe fn release(space: &mut Self) { for l0i in 0..512 { let l0_entry = space.0[l0i]; diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 8a667cb..c37b61e 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -125,6 +125,11 @@ impl Pid { self.0 } + /// Constructs [Pid] from raw [u32] value + /// + /// # Safety + /// + /// Unsafe: does not check `num` pub const unsafe fn from_raw(num: u32) -> Self { Self(num) } @@ -150,6 +155,7 @@ impl Process { SCHED.current_process() } + /// Returns process (if any) to which `pid` refers pub fn get(pid: Pid) -> Option { PROCESSES.lock().get(&pid).cloned() } @@ -168,6 +174,7 @@ impl Process { (&mut *ctx).enter() } + /// Executes a function allowing mutation of the process address space #[inline] pub fn manipulate_space Result<(), Errno>>( &self, diff --git a/kernel/src/proc/sched.rs b/kernel/src/proc/sched.rs index 333aca8..e30282a 100644 --- a/kernel/src/proc/sched.rs +++ b/kernel/src/proc/sched.rs @@ -126,6 +126,7 @@ impl Scheduler { } } +/// Returns `true` if the scheduler has been initialized pub fn is_ready() -> bool { SCHED.inner.is_initialized() } diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 8e347c6..3886a19 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -3,7 +3,6 @@ use crate::{ ioctl::IoctlCmd, stat::{FileMode, OpenFlags, Stat}, }; -use core::mem::size_of; // TODO document the syscall ABI @@ -188,6 +187,9 @@ pub unsafe fn sys_waitpid(pid: u32, status: &mut i32) -> i32 { syscall!(abi::SYS_WAITPID, argn!(pid), argp!(status as *mut i32)) as i32 } +/// # Safety +/// +/// System call #[inline(always)] pub unsafe fn sys_ioctl(fd: u32, cmd: IoctlCmd, ptr: usize, len: usize) -> isize { syscall!( diff --git a/user/src/init/main.rs b/user/src/init/main.rs index df9d5e6..59c5ed7 100644 --- a/user/src/init/main.rs +++ b/user/src/init/main.rs @@ -5,22 +5,31 @@ #[macro_use] extern crate libusr; +use core::cmp::Ordering; + #[no_mangle] fn main() -> i32 { let pid = unsafe { libusr::sys::sys_fork() }; - if pid < 0 { - eprintln!("fork() failed"); - return -1; - } else if pid == 0 { - return unsafe { libusr::sys::sys_execve("/bin/shell") }; - } else { - let mut status = 0; - let res = unsafe { libusr::sys::sys_waitpid(pid as u32, &mut status) }; - if res == 0 { - println!("Process {} exited with status {}", pid, status); - } else { - eprintln!("waitpid() failed"); + match pid.cmp(&0) { + Ordering::Less => { + eprintln!("fork() failed"); + -1 + } + Ordering::Equal => unsafe { libusr::sys::sys_execve("/bin/shell") }, + Ordering::Greater => { + let mut status = 0; + let res = unsafe { libusr::sys::sys_waitpid(pid as u32, &mut status) }; + if res == 0 { + println!("Process {} exited with status {}", pid, status); + } else { + eprintln!("waitpid() failed"); + } + + loop { + unsafe { + asm!("nop"); + } + } } } - loop {} } diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index b327102..4e6a85d 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -31,5 +31,5 @@ fn main() -> i32 { } } - return 0; + 0 } From ac13154c0e33e77b1e9eda521791529b3dfb4b49 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 11 Nov 2021 22:50:25 +0200 Subject: [PATCH 11/42] fix: proper scoping for libsys in auto_inode --- fs/macros/src/lib.rs | 44 +++++++++++++++++++++++++++++++++----------- fs/memfs/src/dir.rs | 6 +----- fs/memfs/src/file.rs | 1 - fs/vfs/src/char.rs | 14 ++++++++------ 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/fs/macros/src/lib.rs b/fs/macros/src/lib.rs index 4ccd843..9cb9ba8 100644 --- a/fs/macros/src/lib.rs +++ b/fs/macros/src/lib.rs @@ -9,59 +9,81 @@ use std::collections::HashSet; use syn::{parse_macro_input, ImplItem, ItemImpl, Ident}; fn impl_inode_fn(name: &str, behavior: T) -> ImplItem { + // TODO somehow know if current crate is vfs or not? ImplItem::Verbatim(match name { "create" => quote! { - fn create(&mut self, _at: VnodeRef, _name: &str, kind: VnodeKind) -> Result { + fn create(&mut self, _at: VnodeRef, _name: &str, kind: VnodeKind) -> + Result + { #behavior } }, "remove" => quote! { - fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { + fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), libsys::error::Errno> { #behavior } }, "lookup" => quote! { - fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { + fn lookup(&mut self, _at: VnodeRef, _name: &str) -> + Result + { #behavior } }, "stat" => quote! { - fn stat(&mut self, _at: VnodeRef, _stat: &mut Stat) -> Result<(), Errno> { + fn stat(&mut self, _at: VnodeRef, _stat: &mut libsys::stat::Stat) -> + Result<(), libsys::error::Errno> + { #behavior } }, "truncate" => quote! { - fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { + fn truncate(&mut self, _node: VnodeRef, _size: usize) -> + Result<(), libsys::error::Errno> + { #behavior } }, "size" => quote! { - fn size(&mut self, _node: VnodeRef) -> Result { + fn size(&mut self, _node: VnodeRef) -> Result { #behavior } }, "read" => quote! { - fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { + fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> + Result + { #behavior } }, "write" => quote! { - fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { + fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> + Result + { #behavior } }, "open" => quote! { - fn open(&mut self, _node: VnodeRef, _flags: OpenFlags) -> Result { + fn open(&mut self, _node: VnodeRef, _flags: libsys::stat::OpenFlags) -> + Result + { #behavior } }, "close" => quote! { - fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { + fn close(&mut self, _node: VnodeRef) -> Result<(), libsys::error::Errno> { #behavior } }, "ioctl" => quote! { - fn ioctl(&mut self, _node: VnodeRef, _cmd: IoctlCmd, _ptr: usize, _len: usize) -> Result { + fn ioctl( + &mut self, + _node: VnodeRef, + _cmd: libsys::ioctl::IoctlCmd, + _ptr: usize, + _len: usize) -> + Result + { #behavior } }, diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index 88b8764..791ceee 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -1,10 +1,6 @@ use crate::{BlockAllocator, Bvec, FileInode}; use alloc::boxed::Box; -use libsys::{ - error::Errno, - stat::{OpenFlags, Stat}, - ioctl::IoctlCmd -}; +use libsys::error::Errno; use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirInode { diff --git a/fs/memfs/src/file.rs b/fs/memfs/src/file.rs index 7aab458..1fe8068 100644 --- a/fs/memfs/src/file.rs +++ b/fs/memfs/src/file.rs @@ -2,7 +2,6 @@ use crate::{BlockAllocator, Bvec}; use libsys::{ error::Errno, stat::{OpenFlags, Stat}, - ioctl::IoctlCmd }; use vfs::{VnodeImpl, VnodeKind, VnodeRef}; diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index e74f95f..c063790 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -1,9 +1,5 @@ use crate::{VnodeImpl, VnodeKind, VnodeRef}; -use libsys::{ - error::Errno, - stat::{OpenFlags, Stat}, - ioctl::IoctlCmd -}; +use libsys::{error::Errno, ioctl::IoctlCmd, stat::OpenFlags}; /// Generic character device trait pub trait CharDevice { @@ -48,7 +44,13 @@ impl VnodeImpl for CharDeviceWrapper { self.device.write(true, data) } - fn ioctl(&mut self, _node: VnodeRef, cmd: IoctlCmd, ptr: usize, len: usize) -> Result { + fn ioctl( + &mut self, + _node: VnodeRef, + cmd: IoctlCmd, + ptr: usize, + len: usize, + ) -> Result { self.device.ioctl(cmd, ptr, len) } } From 34dbd9d9021fb7c0c802de92978815dde0c3ebfd Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 12 Nov 2021 10:26:58 +0200 Subject: [PATCH 12/42] refactor: fix all clippy warnings --- kernel/src/arch/aarch64/context.rs | 10 ++++++++-- kernel/src/arch/aarch64/exception.rs | 2 +- kernel/src/mem/phys/manager.rs | 26 ++++++++++++++------------ kernel/src/mem/phys/mod.rs | 15 +++++++++------ kernel/src/mem/virt/table.rs | 1 + kernel/src/proc/process.rs | 11 ++++++++--- kernel/src/syscall/mod.rs | 15 ++++++++------- 7 files changed, 49 insertions(+), 31 deletions(-) diff --git a/kernel/src/arch/aarch64/context.rs b/kernel/src/arch/aarch64/context.rs index aa48ac8..bf77fdc 100644 --- a/kernel/src/arch/aarch64/context.rs +++ b/kernel/src/arch/aarch64/context.rs @@ -109,8 +109,9 @@ impl Context { } } - pub fn user_empty() -> Self { - let mut stack = Stack::new(8); + /// Constructs an uninitialized thread context + pub fn empty() -> Self { + let stack = Stack::new(8); Self { k_sp: stack.sp, stack_base: stack.bp, @@ -118,6 +119,11 @@ impl Context { } } + /// Sets up a context for signal entry + /// + /// # Safety + /// + /// Unsafe: may clobber an already active context pub unsafe fn setup_signal_entry(&mut self, entry: usize, arg: usize, ttbr0: usize, ustack: usize) { let mut stack = Stack::from_base_size(self.stack_base, self.stack_page_count); diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index d7ac3c9..5117ea4 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -92,7 +92,7 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { if far < mem::KERNEL_OFFSET && sched::is_ready() { let proc = Process::current(); - if let Err(e) = proc.manipulate_space(|space| space.try_cow_copy(far)) { + if proc.manipulate_space(|space| space.try_cow_copy(far)).is_err() { // Kill program dump_data_abort(Level::Error, esr, far as u64); proc.enter_signal(Signal::SegmentationFault); diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 7e229a6..b82f552 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -122,21 +122,23 @@ unsafe impl Manager for SimpleManager { Err(Errno::OutOfMemory) } fn free_page(&mut self, addr: usize) -> Result<(), Errno> { - let index = self.page_index(addr); - let page = &mut self.pages[index]; + let usage = { + let index = self.page_index(addr); + let page = &mut self.pages[index]; - let usage = page.usage; - assert!(page.usage != PageUsage::Reserved && page.usage != PageUsage::Available); + let usage = page.usage; + assert!(page.usage != PageUsage::Reserved && page.usage != PageUsage::Available); - if page.refcount > 1 { - page.refcount -= 1; - } else { - assert_eq!(page.refcount, 1); - page.usage = PageUsage::Available; - page.refcount = 0; - } + if page.refcount > 1 { + page.refcount -= 1; + } else { + assert_eq!(page.refcount, 1); + page.usage = PageUsage::Available; + page.refcount = 0; + } - drop(page); + usage + }; self.update_stats_free(usage, 1); Ok(()) diff --git a/kernel/src/mem/phys/mod.rs b/kernel/src/mem/phys/mod.rs index 172fb05..f90b072 100644 --- a/kernel/src/mem/phys/mod.rs +++ b/kernel/src/mem/phys/mod.rs @@ -32,14 +32,16 @@ pub enum PageUsage { Filesystem, } +/// Represents counts of allocated/available pages +#[allow(missing_docs)] #[derive(Clone, Debug)] pub struct PageStatistics { - available: usize, - kernel: usize, - kernel_heap: usize, - paging: usize, - user_private: usize, - filesystem: usize, + pub available: usize, + pub kernel: usize, + pub kernel_heap: usize, + pub paging: usize, + pub user_private: usize, + pub filesystem: usize, } /// Data structure representing a single physical memory page @@ -143,6 +145,7 @@ pub unsafe fn free_page(page: usize) -> Result<(), Errno> { MANAGER.lock().as_mut().unwrap().free_page(page) } +/// Returns current statistics for page allocation pub fn statistics() -> PageStatistics { MANAGER.lock().as_ref().unwrap().statistics() } diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index 09c13a2..e49d5db 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -328,6 +328,7 @@ impl Space { memset(space as *mut Space as *mut u8, 0, 4096); } + /// Returns the physical address of this structure pub fn address_phys(&mut self) -> usize { (self as *mut _ as usize) - mem::KERNEL_OFFSET } diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index c8e5bb3..23c782a 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -165,8 +165,9 @@ impl Process { PROCESSES.lock().get(&pid).cloned() } + /// Sets a pending signal for a process pub fn set_signal(&self, signal: Signal) { - let mut lock = self.inner.lock(); + let lock = self.inner.lock(); match lock.state { State::Running => { @@ -187,6 +188,7 @@ impl Process { } } + /// Switches current thread back from signal handler pub fn return_from_signal(&self) { if self.signal_pending.load(Ordering::Acquire) == 0 { panic!("TODO handle cases when returning from no signal"); @@ -203,6 +205,7 @@ impl Process { } } + /// Switches current thread to a signal handler pub fn enter_signal(&self, signal: Signal) { if self .signal_pending @@ -243,6 +246,7 @@ impl Process { } } + /// Sets up values needed for signal entry pub fn setup_signal_context(&self, entry: usize, stack: usize) { let mut lock = self.inner.lock(); lock.signal_entry = entry; @@ -270,6 +274,7 @@ impl Process { f(self.inner.lock().space.as_mut().unwrap()) } + #[allow(clippy::mut_from_ref)] fn current_context(&self) -> &mut Context { if self.signal_pending.load(Ordering::Acquire) != 0 { unsafe { &mut *self.signal_ctx.get() } @@ -339,7 +344,7 @@ impl Process { let id = Pid::new_kernel(); let res = Rc::new(Self { ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), - signal_ctx: UnsafeCell::new(Context::user_empty()), + signal_ctx: UnsafeCell::new(Context::empty()), io: IrqSafeSpinLock::new(ProcessIo::new()), exit_wait: Wait::new(), signal_state: AtomicU32::new(0), @@ -372,7 +377,7 @@ impl Process { let dst = Rc::new(Self { ctx: UnsafeCell::new(Context::fork(frame, dst_ttbr0)), - signal_ctx: UnsafeCell::new(Context::user_empty()), + signal_ctx: UnsafeCell::new(Context::empty()), io: IrqSafeSpinLock::new(src_io.fork()?), exit_wait: Wait::new(), signal_state: AtomicU32::new(0), diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 160cba5..a32a8be 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -6,11 +6,12 @@ use crate::proc::{elf, wait, Pid, Process, ProcessIo}; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; +use core::cmp::Ordering; use libsys::{ abi, - signal::Signal, error::Errno, ioctl::IoctlCmd, + signal::Signal, stat::{FileMode, OpenFlags, Stat, AT_EMPTY_PATH, AT_FDCWD}, traits::{Read, Write}, }; @@ -183,12 +184,12 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { abi::SYS_EX_KILL => { let pid = args[0] as i32; let signal = Signal::try_from(args[1] as u32)?; - let proc = if pid > 0 { - Process::get(unsafe { Pid::from_raw(pid as u32) }).ok_or(Errno::DoesNotExist)? - } else if pid == 0 { - Process::current() - } else { - todo!() + let proc = match pid.cmp(&0) { + Ordering::Greater => { + Process::get(unsafe { Pid::from_raw(pid as u32) }).ok_or(Errno::DoesNotExist)? + } + Ordering::Equal => Process::current(), + Ordering::Less => todo!(), }; proc.set_signal(signal); Ok(0) From 496f14d39123daa481da2afc4a40c3d02ba2707d Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 12 Nov 2021 16:00:13 +0200 Subject: [PATCH 13/42] feature: simple select() --- fs/macros/src/lib.rs | 8 ++++ fs/vfs/src/char.rs | 6 +++ fs/vfs/src/file.rs | 7 ++++ fs/vfs/src/node.rs | 10 +++++ kernel/macros/src/lib.rs | 6 ++- kernel/src/dev/tty.rs | 54 ++++++++++++++++++++++---- kernel/src/proc/wait.rs | 53 ++++++++++++++++++++++++- kernel/src/syscall/arg.rs | 12 +++++- kernel/src/syscall/mod.rs | 20 +++++++++- libsys/src/abi.rs | 1 + libsys/src/calls.rs | 18 ++++++++- libsys/src/stat.rs | 81 +++++++++++++++++++++++++++++++++++++++ user/src/shell/main.rs | 28 +++++++++++--- 13 files changed, 283 insertions(+), 21 deletions(-) diff --git a/fs/macros/src/lib.rs b/fs/macros/src/lib.rs index 9cb9ba8..dde1281 100644 --- a/fs/macros/src/lib.rs +++ b/fs/macros/src/lib.rs @@ -87,6 +87,13 @@ fn impl_inode_fn(name: &str, behavior: T) -> ImplItem { #behavior } }, + "is_ready" => quote! { + fn is_ready(&mut self, _node: VnodeRef, _write: bool) -> + Result + { + #behavior + } + }, _ => panic!("TODO implement {:?}", name), }) } @@ -118,6 +125,7 @@ pub fn auto_inode(attr: TokenStream, input: TokenStream) -> TokenStream { missing.insert("stat".to_string()); missing.insert("size".to_string()); missing.insert("ioctl".to_string()); + missing.insert("is_ready".to_string()); for item in &impl_item.items { match item { diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index c063790..1901bd5 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -18,6 +18,8 @@ pub trait CharDevice { /// Performs a TTY control request fn ioctl(&self, cmd: IoctlCmd, ptr: usize, lim: usize) -> Result; + + fn is_ready(&self, write: bool) -> Result; } /// Wrapper struct to attach [VnodeImpl] implementation @@ -44,6 +46,10 @@ impl VnodeImpl for CharDeviceWrapper { self.device.write(true, data) } + fn is_ready(&mut self, _node: VnodeRef, write: bool) -> Result { + self.device.is_ready(write) + } + fn ioctl( &mut self, _node: VnodeRef, diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index e7e794d..cd63be4 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -118,6 +118,13 @@ impl File { pub fn is_cloexec(&self) -> bool { self.flags & Self::CLOEXEC != 0 } + + pub fn is_ready(&self, write: bool) -> Result { + match &self.inner { + FileInner::Normal(inner) => inner.vnode.is_ready(write), + _ => todo!(), + } + } } impl Drop for File { diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 26de047..ad86b2f 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -80,6 +80,8 @@ pub trait VnodeImpl { /// Reports the size of this filesystem object in bytes fn size(&mut self, node: VnodeRef) -> Result; + fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result; + /// Performs filetype-specific request fn ioctl( &mut self, @@ -398,6 +400,14 @@ impl Vnode { Err(Errno::NotImplemented) } } + + pub fn is_ready(self: &VnodeRef, write: bool) -> Result { + if let Some(ref mut data) = *self.data() { + data.is_ready(self.clone(), write) + } else { + Err(Errno::NotImplemented) + } + } } impl fmt::Debug for Vnode { diff --git a/kernel/macros/src/lib.rs b/kernel/macros/src/lib.rs index fc36d2d..6235eb5 100644 --- a/kernel/macros/src/lib.rs +++ b/kernel/macros/src/lib.rs @@ -33,6 +33,10 @@ pub fn derive_tty_char_device(input: TokenStream) -> TokenStream { { crate::dev::tty::TtyDevice::tty_ioctl(self, cmd, ptr, len) } + fn is_ready(&self, write: bool) -> Result { + crate::dev::tty::TtyDevice::is_ready(self, write) + } } - }.into() + } + .into() } diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 7e1cb00..5d1b464 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -1,6 +1,6 @@ //! Teletype (TTY) device facilities use crate::dev::serial::SerialDevice; -use crate::proc::wait::Wait; +use crate::proc::wait::{Wait, WAIT_SELECT}; use crate::sync::IrqSafeSpinLock; use libsys::error::Errno; use libsys::{ @@ -31,6 +31,17 @@ pub trait TtyDevice: SerialDevice { /// Returns a reference to character device's ring buffer fn ring(&self) -> &CharRing; + fn is_ready(&self, write: bool) -> Result { + let ring = self.ring(); + let config = ring.config.lock(); + + if write { + todo!() + } else { + Ok(ring.is_readable(config.lflag.contains(TermiosLflag::ICANON))) + } + } + /// Performs a TTY control request fn tty_ioctl(&self, cmd: IoctlCmd, ptr: usize, _len: usize) -> Result { match cmd { @@ -234,6 +245,36 @@ impl CharRing { } } + pub fn is_readable(&self, canonical: bool) -> bool { + let inner = self.inner.lock(); + if canonical { + // TODO optimize this somehow? + let mut rd = inner.rd; + let mut count = 0usize; + loop { + let readable = if rd <= inner.wr { + (inner.wr - rd) > 0 + } else { + (inner.wr + (N - rd)) > 0 + }; + + if !readable { + break; + } + + if inner.data[rd] == b'\n' { + count += 1; + } + + rd = (rd + 1) % N; + } + + count != 0 || inner.flags != 0 + } else { + inner.is_readable() || inner.flags != 0 + } + } + /// Performs a blocking read of a single byte from the buffer pub fn getc(&self) -> Result { let mut lock = self.inner.lock(); @@ -246,15 +287,10 @@ impl CharRing { break; } } - if lock.flags != 0 { - if lock.flags & (1 << 0) != 0 { - lock.flags &= !(1 << 0); - return Err(Errno::EndOfFile); - } - todo!(); - } let byte = lock.read_unchecked(); + drop(lock); self.wait_write.wakeup_one(); + WAIT_SELECT.wakeup_all(); Ok(byte) } @@ -265,7 +301,9 @@ impl CharRing { todo!() } lock.write_unchecked(ch); + drop(lock); self.wait_read.wakeup_one(); + WAIT_SELECT.wakeup_all(); Ok(()) } } diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index 52d9d37..a945b97 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -2,11 +2,11 @@ use crate::arch::machine; use crate::dev::timer::TimestampSource; -use crate::proc::{self, sched::SCHED, Pid, Process}; +use crate::proc::{self, sched::SCHED, Pid, Process, ProcessRef}; use crate::sync::IrqSafeSpinLock; use alloc::collections::LinkedList; use core::time::Duration; -use libsys::error::Errno; +use libsys::{error::Errno, stat::FdSet}; /// Wait channel structure. Contains a queue of processes /// waiting for some event to happen. @@ -20,6 +20,7 @@ struct Timeout { } static TICK_LIST: IrqSafeSpinLock> = IrqSafeSpinLock::new(LinkedList::new()); +pub static WAIT_SELECT: Wait = Wait::new(); /// Checks for any timed out wait channels and interrupts them pub fn tick() { @@ -54,6 +55,54 @@ pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> { } } +pub fn select( + proc: ProcessRef, + n: u32, + mut rfds: Option<&mut FdSet>, + mut wfds: Option<&mut FdSet>, + timeout: Option, +) -> Result { + // TODO support wfds + if wfds.is_some() || rfds.is_none() { + todo!(); + } + let read = rfds.as_deref().map(FdSet::clone); + let write = wfds.as_deref().map(FdSet::clone); + rfds.as_deref_mut().map(FdSet::reset); + wfds.as_deref_mut().map(FdSet::reset); + + let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap()); + let mut io = proc.io.lock(); + + loop { + if let Some(read) = &read { + for fd in read.iter() { + let file = io.file(fd as usize)?; + if file.borrow().is_ready(false)? { + rfds.as_mut().unwrap().set(fd); + return Ok(1); + } + } + } + if let Some(write) = &write { + for fd in write.iter() { + let file = io.file(fd as usize)?; + if file.borrow().is_ready(true)? { + wfds.as_mut().unwrap().set(fd); + return Ok(1); + } + } + } + + // Suspend + match WAIT_SELECT.wait(deadline) { + Err(Errno::TimedOut) => return Ok(0), + Err(e) => return Err(e), + Ok(_) => {} + } + } +} + impl Wait { /// Constructs a new wait channel pub const fn new() -> Self { diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 61108b8..72a377d 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -18,8 +18,16 @@ fn translate(virt: usize) -> Option { /// Unwraps a slim structure pointer pub fn validate_user_ptr_struct<'a, T>(base: usize) -> Result<&'a mut T, Errno> { - let bytes = validate_user_ptr(base, size_of::())?; - Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) + validate_user_ptr_struct_option(base).and_then(|e| e.ok_or(Errno::InvalidArgument)) +} + +pub fn validate_user_ptr_struct_option<'a, T>(base: usize) -> Result, Errno> { + if base == 0 { + Ok(None) + } else { + let bytes = validate_user_ptr(base, size_of::())?; + Ok(Some(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })) + } } /// Unwraps an user buffer reference diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index a32a8be..5e69e4c 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -3,16 +3,16 @@ use crate::arch::platform::exception::ExceptionFrame; use crate::debug::Level; use crate::proc::{elf, wait, Pid, Process, ProcessIo}; +use core::cmp::Ordering; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; -use core::cmp::Ordering; use libsys::{ abi, error::Errno, ioctl::IoctlCmd, signal::Signal, - stat::{FileMode, OpenFlags, Stat, AT_EMPTY_PATH, AT_FDCWD}, + stat::{FdSet, FileMode, OpenFlags, Stat, AT_EMPTY_PATH, AT_FDCWD}, traits::{Read, Write}, }; use vfs::VnodeRef; @@ -194,6 +194,22 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { proc.set_signal(signal); Ok(0) } + + abi::SYS_SELECT => { + let n = args[0] as u32; + let rfds = validate_user_ptr_struct_option::(args[1])?; + let wfds = validate_user_ptr_struct_option::(args[2])?; + let timeout = if args[3] == 0 { + None + } else { + Some(Duration::from_nanos(args[3] as u64)) + }; + + let proc = Process::current(); + let fd = wait::select(proc, n, rfds, wfds, timeout)?; + Ok(fd as usize) + } + _ => { let proc = Process::current(); errorln!("Undefined system call: {}", num); diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index b14c321..5035906 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -15,3 +15,4 @@ pub const SYS_FORK: usize = 7; pub const SYS_EXECVE: usize = 8; pub const SYS_WAITPID: usize = 9; pub const SYS_IOCTL: usize = 10; +pub const SYS_SELECT: usize = 11; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 3b50be1..a4cd887 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -2,7 +2,7 @@ use crate::abi; use crate::{ ioctl::IoctlCmd, signal::Signal, - stat::{FileMode, OpenFlags, Stat}, + stat::{FdSet, FileMode, OpenFlags, Stat}, }; // TODO document the syscall ABI @@ -217,3 +217,19 @@ pub unsafe fn sys_ex_sigreturn() -> ! { pub unsafe fn sys_ex_kill(pid: u32, signum: Signal) -> i32 { syscall!(abi::SYS_EX_KILL, argn!(pid), argn!(signum as u32)) as i32 } + +#[inline(always)] +pub unsafe fn sys_select( + n: u32, + read_fds: Option<&mut FdSet>, + write_fds: Option<&mut FdSet>, + timeout: u64, +) -> i32 { + syscall!( + abi::SYS_SELECT, + argn!(n), + argp!(read_fds.map(|e| e as *mut _).unwrap_or(core::ptr::null_mut())), + argp!(write_fds.map(|e| e as *mut _).unwrap_or(core::ptr::null_mut())), + argn!(timeout) + ) as i32 +} diff --git a/libsys/src/stat.rs b/libsys/src/stat.rs index 733f77f..d7d3c69 100644 --- a/libsys/src/stat.rs +++ b/libsys/src/stat.rs @@ -1,3 +1,5 @@ +use core::fmt; + pub const AT_FDCWD: i32 = -2; pub const AT_EMPTY_PATH: u32 = 1 << 16; @@ -32,6 +34,16 @@ bitflags! { } } +#[derive(Clone, Default)] +pub struct FdSet { + bits: [u64; 2] +} + +struct FdSetIter<'a> { + idx: u32, + set: &'a FdSet +} + #[derive(Clone, Copy, Debug, Default)] #[repr(C)] pub struct Stat { @@ -40,6 +52,75 @@ pub struct Stat { pub blksize: u32, } +impl FdSet { + pub const fn empty() -> Self { + Self { bits: [0; 2] } + } + + #[inline] + pub fn reset(&mut self) { + self.bits.fill(0); + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.bits.iter().find(|&&x| x != 0).is_some() + } + + #[inline] + pub fn set(&mut self, fd: u32) { + self.bits[(fd as usize) / 64] |= 1 << (fd % 64); + } + + #[inline] + pub fn clear(&mut self, fd: u32) { + self.bits[(fd as usize) / 64] &= !(1 << (fd % 64)); + } + + #[inline] + pub fn is_set(&self, fd: u32) -> bool { + self.bits[(fd as usize) / 64] & (1 << (fd % 64)) != 0 + } + + pub fn iter(&self) -> impl Iterator + '_ { + FdSetIter { + idx: 0, + set: self + } + } +} + +impl Iterator for FdSetIter<'_> { + type Item = u32; + + fn next(&mut self) -> Option { + while self.idx < 128 { + if self.set.is_set(self.idx) { + let res = self.idx; + self.idx += 1; + return Some(res); + } + self.idx += 1; + } + None + } +} + +impl fmt::Debug for FdSet { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "FdSet {{ ")?; + let mut count = 0; + for fd in self.iter() { + if count != 0 { + write!(f, ", ")?; + } + write!(f, "{}", fd)?; + count += 1; + } + write!(f, " }}") + } +} + impl FileMode { /// Returns default permission set for directories pub const fn default_dir() -> Self { diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 7d6290e..8df7e49 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -5,19 +5,37 @@ extern crate libusr; use libusr::sys::Signal; +use libusr::sys::stat::FdSet; fn readline(fd: i32, buf: &mut [u8]) -> Result<&str, ()> { - let count = unsafe { libusr::sys::sys_read(fd, buf) }; - if count >= 0 { - core::str::from_utf8(&buf[..count as usize]).map_err(|_| ()) - } else { - Err(()) + // select() just for test + loop { + let mut rfds = FdSet::empty(); + rfds.set(fd as u32); + let res = unsafe { libusr::sys::sys_select(fd as u32 + 1, Some(&mut rfds), None, 1_000_000_000) }; + if res < 0 { + return Err(()); + } + if res == 0 { + continue; + } + if !rfds.is_set(fd as u32) { + panic!(); + } + + let count = unsafe { libusr::sys::sys_read(fd, buf) }; + if count >= 0 { + return core::str::from_utf8(&buf[..count as usize]).map_err(|_| ()); + } else { + return Err(()); + } } } #[no_mangle] fn main() -> i32 { let mut buf = [0; 512]; + loop { print!("> "); let line = readline(libusr::sys::STDIN_FILENO, &mut buf).unwrap(); From fe1b39db3340de163ebe3a7c59aaee41b113273f Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 12 Nov 2021 18:45:56 +0200 Subject: [PATCH 14/42] fix: treat EOF as "data is available" in select() --- kernel/src/dev/tty.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 5d1b464..43f94bc 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -33,12 +33,10 @@ pub trait TtyDevice: SerialDevice { fn is_ready(&self, write: bool) -> Result { let ring = self.ring(); - let config = ring.config.lock(); - if write { todo!() } else { - Ok(ring.is_readable(config.lflag.contains(TermiosLflag::ICANON))) + Ok(ring.is_readable()) } } @@ -245,9 +243,10 @@ impl CharRing { } } - pub fn is_readable(&self, canonical: bool) -> bool { + pub fn is_readable(&self) -> bool { let inner = self.inner.lock(); - if canonical { + let config = self.config.lock(); + if config.lflag.contains(TermiosLflag::ICANON) { // TODO optimize this somehow? let mut rd = inner.rd; let mut count = 0usize; @@ -262,7 +261,8 @@ impl CharRing { break; } - if inner.data[rd] == b'\n' { + let byte = inner.data[rd]; + if byte == b'\n' || byte == config.chars.eof { count += 1; } From 0f48379e1aa3e0e0593411ba58e0ffff5567fda2 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 12 Nov 2021 19:44:10 +0200 Subject: [PATCH 15/42] refactor: better ABI for SignalDestination passing --- kernel/src/proc/mod.rs | 3 +- kernel/src/proc/process.rs | 134 ++++++++----------------------------- kernel/src/proc/wait.rs | 4 +- kernel/src/syscall/mod.rs | 21 +++--- libsys/src/calls.rs | 6 +- libsys/src/lib.rs | 13 ++-- libsys/src/proc.rs | 116 ++++++++++++++++++++++++++++++++ libsys/src/signal.rs | 34 ++++++++++ libusr/src/lib.rs | 2 +- user/src/shell/main.rs | 4 +- 10 files changed, 205 insertions(+), 132 deletions(-) create mode 100644 libsys/src/proc.rs diff --git a/kernel/src/proc/mod.rs b/kernel/src/proc/mod.rs index 42f084f..4ddc628 100644 --- a/kernel/src/proc/mod.rs +++ b/kernel/src/proc/mod.rs @@ -3,10 +3,11 @@ use crate::init; use crate::sync::IrqSafeSpinLock; use alloc::collections::BTreeMap; +use libsys::proc::Pid; pub mod elf; pub mod process; -pub use process::{Pid, Process, ProcessRef, State as ProcessState}; +pub use process::{Process, ProcessRef, State as ProcessState}; pub mod io; pub use io::ProcessIo; diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 23c782a..88d0c04 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -11,23 +11,13 @@ use alloc::rc::Rc; use core::cell::UnsafeCell; use core::fmt; use core::sync::atomic::{AtomicU32, Ordering}; -use libsys::{error::Errno, signal::Signal}; +use libsys::{error::Errno, signal::Signal, proc::{ExitCode, Pid}}; pub use crate::arch::platform::context::{self, Context}; /// Wrapper type for a process struct reference pub type ProcessRef = Rc; -/// Wrapper type for process exit code -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] -#[repr(transparent)] -pub struct ExitCode(i32); - -/// Wrapper type for process ID -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] -#[repr(transparent)] -pub struct Pid(u32); - /// List of possible process states #[derive(Clone, Copy, Debug, PartialEq)] pub enum State { @@ -64,93 +54,6 @@ pub struct Process { pub io: IrqSafeSpinLock, } -impl From for ExitCode { - fn from(f: i32) -> Self { - Self(f) - } -} - -impl From<()> for ExitCode { - fn from(_: ()) -> Self { - Self(0) - } -} - -impl From for i32 { - fn from(f: ExitCode) -> Self { - f.0 - } -} - -impl Pid { - /// Kernel idle process always has PID of zero - pub const IDLE: Self = Self(Self::KERNEL_BIT); - - const KERNEL_BIT: u32 = 1 << 31; - - /// Constructs an instance of user-space PID - pub const fn user(id: u32) -> Self { - assert!(id < 256, "PID is too high"); - Self(id) - } - - /// Allocates a new kernel-space PID - pub fn new_kernel() -> Self { - static LAST: AtomicU32 = AtomicU32::new(0); - let id = LAST.fetch_add(1, Ordering::Relaxed); - assert!(id & Self::KERNEL_BIT == 0, "Out of kernel PIDs"); - Self(id | Self::KERNEL_BIT) - } - - /// Allocates a new user-space PID. - /// - /// First user PID is #1. - pub fn new_user() -> Self { - static LAST: AtomicU32 = AtomicU32::new(1); - let id = LAST.fetch_add(1, Ordering::Relaxed); - assert!(id < 256, "Out of user PIDs"); - Self(id) - } - - /// Returns `true` if this PID belongs to a kernel process - pub fn is_kernel(self) -> bool { - self.0 & Self::KERNEL_BIT != 0 - } - - /// Returns address space ID of a user-space process. - /// - /// Panics if called on kernel process PID. - pub fn asid(self) -> u8 { - assert!(!self.is_kernel()); - self.0 as u8 - } - - /// Returns bit value of this pid - pub const fn value(self) -> u32 { - self.0 - } - - /// Constructs [Pid] from raw [u32] value - /// - /// # Safety - /// - /// Unsafe: does not check `num` - pub const unsafe fn from_raw(num: u32) -> Self { - Self(num) - } -} - -impl fmt::Display for Pid { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Pid(#{}{})", - if self.is_kernel() { "K" } else { "U" }, - self.0 & !Self::KERNEL_BIT - ) - } -} - impl Process { const USTACK_VIRT_TOP: usize = 0x100000000; const USTACK_PAGES: usize = 4; @@ -341,7 +244,7 @@ impl Process { /// Creates a new kernel process pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result { - let id = Pid::new_kernel(); + let id = new_kernel_pid(); let res = Rc::new(Self { ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), signal_ctx: UnsafeCell::new(Context::empty()), @@ -359,7 +262,7 @@ impl Process { state: State::Ready, }), }); - debugln!("New kernel process: {}", id); + debugln!("New kernel process: {:?}", id); assert!(PROCESSES.lock().insert(id, res.clone()).is_none()); Ok(res) } @@ -370,7 +273,7 @@ impl Process { let src_io = self.io.lock(); let mut src_inner = self.inner.lock(); - let dst_id = Pid::new_user(); + let dst_id = new_user_pid(); let dst_space = src_inner.space.as_mut().unwrap().fork()?; let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET; let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48); @@ -392,7 +295,7 @@ impl Process { wait_flag: false, }), }); - debugln!("Process {} forked into {}", src_inner.id, dst_id); + debugln!("Process {:?} forked into {:?}", src_inner.id, dst_id); assert!(PROCESSES.lock().insert(dst_id, dst).is_none()); SCHED.enqueue(dst_id); @@ -405,7 +308,7 @@ impl Process { let drop = { let mut lock = self.inner.lock(); let drop = lock.state == State::Running; - infoln!("Process {} is exiting: {:?}", lock.id, status); + infoln!("Process {:?} is exiting: {:?}", lock.id, status); assert!(lock.exit.is_none()); lock.exit = Some(status); lock.state = State::Finished; @@ -450,7 +353,7 @@ impl Process { if let Some(r) = proc.collect() { // TODO drop the process struct itself PROCESSES.lock().remove(&proc.id()); - debugln!("pid {} has {} refs", proc.id(), Rc::strong_count(&proc)); + debugln!("pid {:?} has {} refs", proc.id(), Rc::strong_count(&proc)); return Ok(r); } @@ -477,9 +380,9 @@ impl Process { proc_lock.remove(&old_pid).is_some(), "Failed to downgrade kernel process (remove kernel pid)" ); - lock.id = Pid::new_user(); + lock.id = new_user_pid(); debugln!( - "Process downgrades from kernel to user: {} -> {}", + "Process downgrades from kernel to user: {:?} -> {:?}", old_pid, lock.id ); @@ -541,6 +444,23 @@ impl Process { impl Drop for Process { fn drop(&mut self) { - debugln!("Dropping process {}", self.id()); + debugln!("Dropping process {:?}", self.id()); } } + +/// Allocates a new kernel-space PID +pub fn new_kernel_pid() -> Pid { + static LAST: AtomicU32 = AtomicU32::new(0); + let id = LAST.fetch_add(1, Ordering::Relaxed); + Pid::kernel(id) +} + +/// Allocates a new user-space PID. +/// +/// First user PID is #1. +pub fn new_user_pid() -> Pid { + static LAST: AtomicU32 = AtomicU32::new(1); + let id = LAST.fetch_add(1, Ordering::Relaxed); + assert!(id < 256, "Out of user PIDs"); + Pid::user(id) +} diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index a945b97..59e06b2 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -2,11 +2,11 @@ use crate::arch::machine; use crate::dev::timer::TimestampSource; -use crate::proc::{self, sched::SCHED, Pid, Process, ProcessRef}; +use crate::proc::{self, sched::SCHED, Process, ProcessRef}; use crate::sync::IrqSafeSpinLock; use alloc::collections::LinkedList; use core::time::Duration; -use libsys::{error::Errno, stat::FdSet}; +use libsys::{error::Errno, stat::FdSet, proc::Pid}; /// Wait channel structure. Contains a queue of processes /// waiting for some event to happen. diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 5e69e4c..b42d196 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -2,7 +2,7 @@ use crate::arch::platform::exception::ExceptionFrame; use crate::debug::Level; -use crate::proc::{elf, wait, Pid, Process, ProcessIo}; +use crate::proc::{elf, wait, Process, ProcessIo}; use core::cmp::Ordering; use core::mem::size_of; use core::ops::DerefMut; @@ -11,7 +11,8 @@ use libsys::{ abi, error::Errno, ioctl::IoctlCmd, - signal::Signal, + proc::Pid, + signal::{Signal, SignalDestination}, stat::{FdSet, FileMode, OpenFlags, Stat, AT_EMPTY_PATH, AT_FDCWD}, traits::{Read, Write}, }; @@ -182,16 +183,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { panic!("This code won't run"); } abi::SYS_EX_KILL => { - let pid = args[0] as i32; + let target = SignalDestination::from(args[0] as isize); let signal = Signal::try_from(args[1] as u32)?; - let proc = match pid.cmp(&0) { - Ordering::Greater => { - Process::get(unsafe { Pid::from_raw(pid as u32) }).ok_or(Errno::DoesNotExist)? - } - Ordering::Equal => Process::current(), - Ordering::Less => todo!(), + + match target { + SignalDestination::This => Process::current().set_signal(signal), + SignalDestination::Process(pid) => Process::get(pid) + .ok_or(Errno::DoesNotExist)? + .set_signal(signal), + _ => todo!(), }; - proc.set_signal(signal); Ok(0) } diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index a4cd887..8ea597f 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -1,7 +1,7 @@ use crate::abi; use crate::{ ioctl::IoctlCmd, - signal::Signal, + signal::{Signal, SignalDestination}, stat::{FdSet, FileMode, OpenFlags, Stat}, }; @@ -214,8 +214,8 @@ pub unsafe fn sys_ex_sigreturn() -> ! { } #[inline(always)] -pub unsafe fn sys_ex_kill(pid: u32, signum: Signal) -> i32 { - syscall!(abi::SYS_EX_KILL, argn!(pid), argn!(signum as u32)) as i32 +pub unsafe fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> i32 { + syscall!(abi::SYS_EX_KILL, argn!(isize::from(pid)), argn!(signum as u32)) as i32 } #[inline(always)] diff --git a/libsys/src/lib.rs b/libsys/src/lib.rs index c6a4034..71f984e 100644 --- a/libsys/src/lib.rs +++ b/libsys/src/lib.rs @@ -1,17 +1,18 @@ -#![feature(asm)] +#![feature(asm, const_panic)] #![no_std] #[macro_use] extern crate bitflags; pub mod abi; -pub mod stat; -pub mod ioctl; -pub mod termios; -pub mod signal; pub mod error; -pub mod path; +pub mod ioctl; pub mod mem; +pub mod path; +pub mod proc; +pub mod signal; +pub mod stat; +pub mod termios; pub mod traits; #[cfg(feature = "user")] diff --git a/libsys/src/proc.rs b/libsys/src/proc.rs new file mode 100644 index 0000000..e63b6dc --- /dev/null +++ b/libsys/src/proc.rs @@ -0,0 +1,116 @@ +use crate::error::Errno; +use core::convert::TryFrom; +use core::fmt; + +/// Wrapper type for process exit code +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct ExitCode(i32); + +/// Wrapper type for process ID +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] +#[repr(transparent)] +pub struct Pid(u32); + +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct Pgid(u32); + +impl From for ExitCode { + fn from(f: i32) -> Self { + Self(f) + } +} + +impl From<()> for ExitCode { + fn from(_: ()) -> Self { + Self(0) + } +} + +impl From for i32 { + fn from(f: ExitCode) -> Self { + f.0 + } +} + +impl Pid { + /// Kernel idle process always has PID of zero + pub const IDLE: Self = Self(Self::KERNEL_BIT); + + const KERNEL_BIT: u32 = 1 << 31; + + /// Constructs an instance of user-space PID + pub const fn user(id: u32) -> Self { + assert!(id < 256, "PID is too high"); + Self(id) + } + + /// Constructs an instance of kernel-space PID + pub const fn kernel(id: u32) -> Self { + assert!(id & Self::KERNEL_BIT == 0, "PID is too high"); + Self(id | Self::KERNEL_BIT) + } + + /// Returns `true` if this PID belongs to a kernel process + pub fn is_kernel(self) -> bool { + self.0 & Self::KERNEL_BIT != 0 + } + + /// Returns address space ID of a user-space process. + /// + /// Panics if called on kernel process PID. + pub fn asid(self) -> u8 { + assert!(!self.is_kernel()); + self.0 as u8 + } + + /// Returns bit value of this pid + pub const fn value(self) -> u32 { + self.0 + } + + /// Constructs [Pid] from raw [u32] value + /// + /// # Safety + /// + /// Unsafe: does not check `num` + pub const unsafe fn from_raw(num: u32) -> Self { + Self(num) + } +} + +impl fmt::Debug for Pid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Pid(#{}{})", + if self.is_kernel() { "K" } else { "U" }, + self.0 & !Self::KERNEL_BIT + ) + } +} + +impl TryFrom for Pgid { + type Error = Errno; + + fn try_from(pid: Pid) -> Result { + if pid.is_kernel() { + Err(Errno::InvalidArgument) + } else { + Ok(Pgid(pid.0)) + } + } +} + +impl From for Pgid { + fn from(p: u32) -> Pgid { + Self(p) + } +} + +impl From for u32 { + fn from(p: Pgid) -> u32 { + p.0 + } +} diff --git a/libsys/src/signal.rs b/libsys/src/signal.rs index e17d1c1..6d2dc3c 100644 --- a/libsys/src/signal.rs +++ b/libsys/src/signal.rs @@ -1,4 +1,5 @@ use crate::error::Errno; +use crate::proc::{Pid, Pgid}; #[derive(Clone, Copy, PartialEq, Debug)] #[repr(u32)] @@ -11,6 +12,39 @@ pub enum Signal { InvalidSystemCall = 31 } +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum SignalDestination { + Group(Pgid), + Process(Pid), + All, + This +} + +impl From for SignalDestination { + fn from(num: isize) -> Self { + if num > 0 { + Self::Process(Pid::user(num as u32)) + } else if num == 0 { + Self::This + } else if num == -1 { + Self::All + } else { + Self::Group(Pgid::from((-num) as u32)) + } + } +} + +impl From for isize { + fn from(p: SignalDestination) -> isize { + match p { + SignalDestination::Process(pid) => pid.value() as isize, + SignalDestination::Group(pgid) => -(u32::from(pgid) as isize), + SignalDestination::This => 0, + SignalDestination::All => -1 + } + } +} + impl TryFrom for Signal { type Error = Errno; diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index 6f78ba2..01c383a 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -7,7 +7,7 @@ pub mod io; pub mod os; pub mod sys { - pub use libsys::signal::Signal; + pub use libsys::signal::{Signal, SignalDestination}; pub use libsys::termios; pub use libsys::calls::*; pub use libsys::stat::{self, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 8df7e49..08f1c8e 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -4,7 +4,7 @@ #[macro_use] extern crate libusr; -use libusr::sys::Signal; +use libusr::sys::{Signal, SignalDestination}; use libusr::sys::stat::FdSet; fn readline(fd: i32, buf: &mut [u8]) -> Result<&str, ()> { @@ -48,7 +48,7 @@ fn main() -> i32 { if line == "test" { unsafe { - libusr::sys::sys_ex_kill(0, Signal::Interrupt); + libusr::sys::sys_ex_kill(SignalDestination::This, Signal::Interrupt); } trace!("Returned from signal"); continue; From a6952329260ee026ffdaaae121ecdb9a2ac9384b Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sat, 13 Nov 2021 12:58:51 +0200 Subject: [PATCH 16/42] feature: add FileDescriptor type --- kernel/src/init.rs | 8 ++-- kernel/src/proc/io.rs | 19 +++++----- kernel/src/proc/process.rs | 1 - kernel/src/proc/wait.rs | 7 ++-- kernel/src/syscall/mod.rs | 41 ++++++++++---------- libsys/src/calls.rs | 52 ++++++++++++++++--------- libsys/src/stat.rs | 77 +++++++++++++++++++++++++++----------- libusr/src/io.rs | 10 ++--- libusr/src/lib.rs | 2 +- libusr/src/os.rs | 6 +-- user/src/shell/main.rs | 14 ++++--- 11 files changed, 144 insertions(+), 93 deletions(-) diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 19be0bc..9744253 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -4,8 +4,8 @@ use crate::config::{ConfigKey, CONFIG}; use crate::fs::{devfs, MemfsBlockAlloc}; use crate::mem; use crate::proc::{elf, Process}; +use libsys::stat::{FileDescriptor, OpenFlags}; use memfs::Ramfs; -use libsys::stat::OpenFlags; use vfs::{Filesystem, Ioctx}; /// Kernel init process function @@ -51,9 +51,9 @@ pub extern "C" fn init_fn(_arg: usize) -> ! { let stdout = tty_node.open(OpenFlags::O_WRONLY).unwrap(); let stderr = stdout.clone(); - io.set_file(0, stdin).unwrap(); - io.set_file(1, stdout).unwrap(); - io.set_file(2, stderr).unwrap(); + io.set_file(FileDescriptor::STDIN, stdin).unwrap(); + io.set_file(FileDescriptor::STDOUT, stdout).unwrap(); + io.set_file(FileDescriptor::STDERR, stderr).unwrap(); } drop(cfg); diff --git a/kernel/src/proc/io.rs b/kernel/src/proc/io.rs index 2b44c5e..f60301a 100644 --- a/kernel/src/proc/io.rs +++ b/kernel/src/proc/io.rs @@ -1,12 +1,12 @@ //! Process file descriptors and I/O context use alloc::collections::BTreeMap; -use libsys::error::Errno; +use libsys::{error::Errno, stat::FileDescriptor}; use vfs::{FileRef, Ioctx}; /// Process I/O context. Contains file tables, root/cwd info etc. pub struct ProcessIo { ioctx: Option, - files: BTreeMap, + files: BTreeMap, } impl ProcessIo { @@ -22,8 +22,8 @@ impl ProcessIo { } /// Returns [File] struct referred to by file descriptor `idx` - pub fn file(&mut self, idx: usize) -> Result { - self.files.get(&idx).cloned().ok_or(Errno::InvalidFile) + pub fn file(&mut self, fd: FileDescriptor) -> Result { + self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile) } /// Returns [Ioctx] structure reference of this I/O context @@ -32,19 +32,19 @@ impl ProcessIo { } /// Allocates a file descriptor and associates a [File] struct with it - pub fn place_file(&mut self, file: FileRef) -> Result { + pub fn place_file(&mut self, file: FileRef) -> Result { for idx in 0..64 { if self.files.get(&idx).is_none() { self.files.insert(idx, file); - return Ok(idx); + return Ok(FileDescriptor::from(idx)); } } Err(Errno::TooManyDescriptors) } /// Performs [File] close and releases its associated file descriptor `idx` - pub fn close_file(&mut self, idx: usize) -> Result<(), Errno> { - let res = self.files.remove(&idx); + pub fn close_file(&mut self, idx: FileDescriptor) -> Result<(), Errno> { + let res = self.files.remove(&u32::from(idx)); assert!(res.is_some()); Ok(()) } @@ -59,7 +59,8 @@ impl ProcessIo { /// Assigns a descriptor number to an open file. If the number is not available, /// returns [Errno::AlreadyExists]. - pub fn set_file(&mut self, idx: usize, file: FileRef) -> Result<(), Errno> { + pub fn set_file(&mut self, idx: FileDescriptor, file: FileRef) -> Result<(), Errno> { + let idx = u32::from(idx); if self.files.get(&idx).is_none() { self.files.insert(idx, file); Ok(()) diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 88d0c04..e511943 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -9,7 +9,6 @@ use crate::proc::{wait::Wait, ProcessIo, PROCESSES, SCHED}; use crate::sync::IrqSafeSpinLock; use alloc::rc::Rc; use core::cell::UnsafeCell; -use core::fmt; use core::sync::atomic::{AtomicU32, Ordering}; use libsys::{error::Errno, signal::Signal, proc::{ExitCode, Pid}}; diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index 59e06b2..1869e70 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -57,11 +57,10 @@ pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> { pub fn select( proc: ProcessRef, - n: u32, mut rfds: Option<&mut FdSet>, mut wfds: Option<&mut FdSet>, timeout: Option, -) -> Result { +) -> Result { // TODO support wfds if wfds.is_some() || rfds.is_none() { todo!(); @@ -77,7 +76,7 @@ pub fn select( loop { if let Some(read) = &read { for fd in read.iter() { - let file = io.file(fd as usize)?; + let file = io.file(fd)?; if file.borrow().is_ready(false)? { rfds.as_mut().unwrap().set(fd); return Ok(1); @@ -86,7 +85,7 @@ pub fn select( } if let Some(write) = &write { for fd in write.iter() { - let file = io.file(fd as usize)?; + let file = io.file(fd)?; if file.borrow().is_ready(true)? { wfds.as_mut().unwrap().set(fd); return Ok(1); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index b42d196..5e6edbc 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -3,7 +3,6 @@ use crate::arch::platform::exception::ExceptionFrame; use crate::debug::Level; use crate::proc::{elf, wait, Process, ProcessIo}; -use core::cmp::Ordering; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; @@ -13,7 +12,7 @@ use libsys::{ ioctl::IoctlCmd, proc::Pid, signal::{Signal, SignalDestination}, - stat::{FdSet, FileMode, OpenFlags, Stat, AT_EMPTY_PATH, AT_FDCWD}, + stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH}, traits::{Read, Write}, }; use vfs::VnodeRef; @@ -34,11 +33,11 @@ pub unsafe fn sys_fork(regs: &mut ExceptionFrame) -> Result { fn find_at_node>( io: &mut T, - at_fd: usize, + at_fd: Option, filename: &str, empty_path: bool, ) -> Result { - let at = if at_fd as i32 != AT_FDCWD { + let at = if let Some(at_fd) = at_fd { io.file(at_fd)?.borrow().node() } else { None @@ -62,7 +61,7 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { // I/O system calls abi::SYS_OPENAT => { - let at_fd = args[0]; + let at_fd = FileDescriptor::from_i32(args[0] as i32)?; let path = validate_user_str(args[1], args[2])?; let mode = FileMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; let opts = OpenFlags::from_bits(args[4] as u32).ok_or(Errno::InvalidArgument)?; @@ -70,31 +69,33 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { let proc = Process::current(); let mut io = proc.io.lock(); - let at = if at_fd as i32 == AT_FDCWD { - None + let at = if let Some(fd) = at_fd { + io.file(fd)?.borrow().node() } else { - io.file(at_fd)?.borrow().node() + None }; let file = io.ioctx().open(at, path, mode, opts)?; - io.place_file(file) + Ok(u32::from(io.place_file(file)?) as usize) } abi::SYS_READ => { let proc = Process::current(); + let fd = FileDescriptor::from(args[0] as u32); let mut io = proc.io.lock(); let buf = validate_user_ptr(args[1], args[2])?; - io.file(args[0])?.borrow_mut().read(buf) + io.file(fd)?.borrow_mut().read(buf) } abi::SYS_WRITE => { let proc = Process::current(); + let fd = FileDescriptor::from(args[0] as u32); let mut io = proc.io.lock(); let buf = validate_user_ptr(args[1], args[2])?; - io.file(args[0])?.borrow_mut().write(buf) + io.file(fd)?.borrow_mut().write(buf) } abi::SYS_FSTATAT => { - let at_fd = args[0]; + let at_fd = FileDescriptor::from_i32(args[0] as i32)?; let filename = validate_user_str(args[1], args[2])?; let buf = validate_user_ptr_struct::(args[3])?; let flags = args[4] as u32; @@ -107,7 +108,7 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { abi::SYS_CLOSE => { let proc = Process::current(); let mut io = proc.io.lock(); - let fd = args[0]; + let fd = FileDescriptor::from(args[0] as u32); io.close_file(fd)?; Ok(0) @@ -140,7 +141,7 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { } } abi::SYS_IOCTL => { - let fd = args[0]; + let fd = FileDescriptor::from(args[0] as u32); let cmd = IoctlCmd::try_from(args[1] as u32)?; let proc = Process::current(); @@ -197,18 +198,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { } abi::SYS_SELECT => { - let n = args[0] as u32; - let rfds = validate_user_ptr_struct_option::(args[1])?; - let wfds = validate_user_ptr_struct_option::(args[2])?; - let timeout = if args[3] == 0 { + let rfds = validate_user_ptr_struct_option::(args[0])?; + let wfds = validate_user_ptr_struct_option::(args[1])?; + let timeout = if args[2] == 0 { None } else { - Some(Duration::from_nanos(args[3] as u64)) + Some(Duration::from_nanos(args[2] as u64)) }; let proc = Process::current(); - let fd = wait::select(proc, n, rfds, wfds, timeout)?; - Ok(fd as usize) + wait::select(proc, rfds, wfds, timeout) } _ => { diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 8ea597f..e2bd7b0 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -2,7 +2,7 @@ use crate::abi; use crate::{ ioctl::IoctlCmd, signal::{Signal, SignalDestination}, - stat::{FdSet, FileMode, OpenFlags, Stat}, + stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, }; // TODO document the syscall ABI @@ -80,8 +80,8 @@ pub unsafe fn sys_exit(status: i32) -> ! { /// /// System call #[inline(always)] -pub unsafe fn sys_close(fd: i32) -> i32 { - syscall!(abi::SYS_CLOSE, argn!(fd)) as i32 +pub unsafe fn sys_close(fd: FileDescriptor) -> i32 { + syscall!(abi::SYS_CLOSE, argn!(u32::from(fd))) as i32 } /// # Safety @@ -108,10 +108,15 @@ pub unsafe fn sys_ex_debug_trace(msg: &[u8]) -> usize { /// /// System call #[inline(always)] -pub unsafe fn sys_openat(at: i32, pathname: &str, mode: FileMode, flags: OpenFlags) -> i32 { +pub unsafe fn sys_openat( + at: Option, + pathname: &str, + mode: FileMode, + flags: OpenFlags, +) -> i32 { syscall!( abi::SYS_OPENAT, - argn!(at), + argn!(FileDescriptor::into_i32(at)), argp!(pathname.as_ptr()), argn!(pathname.len()), argn!(mode.bits()), @@ -123,10 +128,10 @@ pub unsafe fn sys_openat(at: i32, pathname: &str, mode: FileMode, flags: OpenFla /// /// System call #[inline(always)] -pub unsafe fn sys_read(fd: i32, data: &mut [u8]) -> isize { +pub unsafe fn sys_read(fd: FileDescriptor, data: &mut [u8]) -> isize { syscall!( abi::SYS_READ, - argn!(fd), + argn!(u32::from(fd)), argp!(data.as_mut_ptr()), argn!(data.len()) ) as isize @@ -136,10 +141,10 @@ pub unsafe fn sys_read(fd: i32, data: &mut [u8]) -> isize { /// /// System call #[inline(always)] -pub unsafe fn sys_write(fd: i32, data: &[u8]) -> isize { +pub unsafe fn sys_write(fd: FileDescriptor, data: &[u8]) -> isize { syscall!( abi::SYS_WRITE, - argn!(fd), + argn!(u32::from(fd)), argp!(data.as_ptr()), argn!(data.len()) ) as isize @@ -149,10 +154,15 @@ pub unsafe fn sys_write(fd: i32, data: &[u8]) -> isize { /// /// System call #[inline(always)] -pub unsafe fn sys_fstatat(at: i32, pathname: &str, statbuf: &mut Stat, flags: u32) -> i32 { +pub unsafe fn sys_fstatat( + at: Option, + pathname: &str, + statbuf: &mut Stat, + flags: u32, +) -> i32 { syscall!( abi::SYS_FSTATAT, - argn!(at), + argn!(FileDescriptor::into_i32(at)), argp!(pathname.as_ptr()), argn!(pathname.len()), argp!(statbuf as *mut Stat), @@ -192,10 +202,10 @@ pub unsafe fn sys_waitpid(pid: u32, status: &mut i32) -> i32 { /// /// System call #[inline(always)] -pub unsafe fn sys_ioctl(fd: u32, cmd: IoctlCmd, ptr: usize, len: usize) -> isize { +pub unsafe fn sys_ioctl(fd: FileDescriptor, cmd: IoctlCmd, ptr: usize, len: usize) -> isize { syscall!( abi::SYS_IOCTL, - argn!(fd), + argn!(u32::from(fd)), argn!(cmd), argn!(ptr), argn!(len) @@ -215,21 +225,27 @@ pub unsafe fn sys_ex_sigreturn() -> ! { #[inline(always)] pub unsafe fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> i32 { - syscall!(abi::SYS_EX_KILL, argn!(isize::from(pid)), argn!(signum as u32)) as i32 + syscall!( + abi::SYS_EX_KILL, + argn!(isize::from(pid)), + argn!(signum as u32) + ) as i32 } #[inline(always)] pub unsafe fn sys_select( - n: u32, read_fds: Option<&mut FdSet>, write_fds: Option<&mut FdSet>, timeout: u64, ) -> i32 { syscall!( abi::SYS_SELECT, - argn!(n), - argp!(read_fds.map(|e| e as *mut _).unwrap_or(core::ptr::null_mut())), - argp!(write_fds.map(|e| e as *mut _).unwrap_or(core::ptr::null_mut())), + argp!(read_fds + .map(|e| e as *mut _) + .unwrap_or(core::ptr::null_mut())), + argp!(write_fds + .map(|e| e as *mut _) + .unwrap_or(core::ptr::null_mut())), argn!(timeout) ) as i32 } diff --git a/libsys/src/stat.rs b/libsys/src/stat.rs index d7d3c69..f1d0e73 100644 --- a/libsys/src/stat.rs +++ b/libsys/src/stat.rs @@ -1,12 +1,9 @@ use core::fmt; +use crate::error::Errno; -pub const AT_FDCWD: i32 = -2; +const AT_FDCWD: i32 = -2; pub const AT_EMPTY_PATH: u32 = 1 << 16; -pub const STDIN_FILENO: i32 = 0; -pub const STDOUT_FILENO: i32 = 1; -pub const STDERR_FILENO: i32 = 2; - bitflags! { pub struct OpenFlags: u32 { const O_RDONLY = 1; @@ -39,6 +36,10 @@ pub struct FdSet { bits: [u64; 2] } +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub struct FileDescriptor(u32); + struct FdSetIter<'a> { idx: u32, set: &'a FdSet @@ -64,25 +65,25 @@ impl FdSet { #[inline] pub fn is_empty(&self) -> bool { - self.bits.iter().find(|&&x| x != 0).is_some() + self.bits.iter().any(|&x| x != 0) } #[inline] - pub fn set(&mut self, fd: u32) { - self.bits[(fd as usize) / 64] |= 1 << (fd % 64); + pub fn set(&mut self, fd: FileDescriptor) { + self.bits[(fd.0 as usize) / 64] |= 1 << (fd.0 % 64); } #[inline] - pub fn clear(&mut self, fd: u32) { - self.bits[(fd as usize) / 64] &= !(1 << (fd % 64)); + pub fn clear(&mut self, fd: FileDescriptor) { + self.bits[(fd.0 as usize) / 64] &= !(1 << (fd.0 % 64)); } #[inline] - pub fn is_set(&self, fd: u32) -> bool { - self.bits[(fd as usize) / 64] & (1 << (fd % 64)) != 0 + pub fn is_set(&self, fd: FileDescriptor) -> bool { + self.bits[(fd.0 as usize) / 64] & (1 << (fd.0 % 64)) != 0 } - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { FdSetIter { idx: 0, set: self @@ -91,14 +92,14 @@ impl FdSet { } impl Iterator for FdSetIter<'_> { - type Item = u32; + type Item = FileDescriptor; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { while self.idx < 128 { - if self.set.is_set(self.idx) { + if self.set.is_set(FileDescriptor(self.idx)) { let res = self.idx; self.idx += 1; - return Some(res); + return Some(FileDescriptor::from(res)); } self.idx += 1; } @@ -109,13 +110,11 @@ impl Iterator for FdSetIter<'_> { impl fmt::Debug for FdSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "FdSet {{ ")?; - let mut count = 0; - for fd in self.iter() { + for (count, fd) in self.iter().enumerate() { if count != 0 { write!(f, ", ")?; } - write!(f, "{}", fd)?; - count += 1; + write!(f, "{:?}", fd)?; } write!(f, " }}") } @@ -132,3 +131,39 @@ impl FileMode { unsafe { Self::from_bits_unchecked(0o644) } } } + +impl FileDescriptor { + pub const STDIN: Self = Self(0); + pub const STDOUT: Self = Self(1); + pub const STDERR: Self = Self(2); + + pub fn from_i32(u: i32) -> Result, Errno> { + if u >= 0 { + Ok(Some(Self(u as u32))) + } else if u == AT_FDCWD { + Ok(None) + } else { + Err(Errno::InvalidArgument) + } + } + + pub fn into_i32(u: Option) -> i32 { + if let Some(u) = u { + u.0 as i32 + } else { + AT_FDCWD + } + } +} + +impl From for FileDescriptor { + fn from(u: u32) -> Self { + Self(u) + } +} + +impl From for u32 { + fn from(u: FileDescriptor) -> u32 { + u.0 + } +} diff --git a/libusr/src/io.rs b/libusr/src/io.rs index c98712c..650fcaa 100644 --- a/libusr/src/io.rs +++ b/libusr/src/io.rs @@ -1,7 +1,7 @@ use core::fmt; use libsys::{ calls::{sys_fstatat, sys_write}, - stat::{Stat, AT_FDCWD}, + stat::{Stat, FileDescriptor}, }; // TODO populate this type @@ -9,7 +9,7 @@ pub struct Error; pub fn stat(pathname: &str) -> Result { let mut buf = Stat::default(); - let res = unsafe { sys_fstatat(AT_FDCWD, pathname, &mut buf, 0) }; + let res = unsafe { sys_fstatat(None, pathname, &mut buf, 0) }; if res != 0 { todo!(); } @@ -20,7 +20,7 @@ pub fn stat(pathname: &str) -> Result { #[macro_export] macro_rules! print { - ($($args:tt)+) => ($crate::io::_print($crate::sys::STDOUT_FILENO, format_args!($($args)+))) + ($($args:tt)+) => ($crate::io::_print($crate::sys::FileDescriptor::STDOUT, format_args!($($args)+))) } #[macro_export] @@ -30,7 +30,7 @@ macro_rules! println { #[macro_export] macro_rules! eprint { - ($($args:tt)+) => ($crate::io::_print($crate::sys::STDERR_FILENO, format_args!($($args)+))) + ($($args:tt)+) => ($crate::io::_print($crate::sys::FileDescriptor::STDERR, format_args!($($args)+))) } #[macro_export] @@ -53,7 +53,7 @@ impl fmt::Write for BufferWriter<'_> { } } -pub fn _print(fd: i32, args: fmt::Arguments) { +pub fn _print(fd: FileDescriptor, args: fmt::Arguments) { use core::fmt::Write; static mut BUFFER: [u8; 4096] = [0; 4096]; let mut writer = BufferWriter { diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index 01c383a..6199930 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -10,7 +10,7 @@ pub mod sys { pub use libsys::signal::{Signal, SignalDestination}; pub use libsys::termios; pub use libsys::calls::*; - pub use libsys::stat::{self, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; + pub use libsys::stat::{self, FileDescriptor}; } #[inline(never)] diff --git a/libusr/src/os.rs b/libusr/src/os.rs index bd75771..76bb6ab 100644 --- a/libusr/src/os.rs +++ b/libusr/src/os.rs @@ -1,9 +1,9 @@ use crate::sys; use core::fmt; use core::mem::{size_of, MaybeUninit}; -use libsys::{ioctl::IoctlCmd, termios::Termios}; +use libsys::{ioctl::IoctlCmd, stat::FileDescriptor, termios::Termios}; -pub fn get_tty_attrs(fd: u32) -> Result { +pub fn get_tty_attrs(fd: FileDescriptor) -> Result { let mut termios = MaybeUninit::::uninit(); let res = unsafe { sys::sys_ioctl( @@ -19,7 +19,7 @@ pub fn get_tty_attrs(fd: u32) -> Result { Ok(unsafe { termios.assume_init() }) } -pub fn set_tty_attrs(fd: u32, attrs: &Termios) -> Result<(), &'static str> { +pub fn set_tty_attrs(fd: FileDescriptor, attrs: &Termios) -> Result<(), &'static str> { let res = unsafe { sys::sys_ioctl( fd, diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 08f1c8e..02e796c 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -4,22 +4,24 @@ #[macro_use] extern crate libusr; +use libusr::sys::stat::{FdSet, FileDescriptor}; use libusr::sys::{Signal, SignalDestination}; -use libusr::sys::stat::FdSet; -fn readline(fd: i32, buf: &mut [u8]) -> Result<&str, ()> { +fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, ()> { // select() just for test loop { let mut rfds = FdSet::empty(); - rfds.set(fd as u32); - let res = unsafe { libusr::sys::sys_select(fd as u32 + 1, Some(&mut rfds), None, 1_000_000_000) }; + rfds.set(fd); + let res = unsafe { + libusr::sys::sys_select(Some(&mut rfds), None, 1_000_000_000) + }; if res < 0 { return Err(()); } if res == 0 { continue; } - if !rfds.is_set(fd as u32) { + if !rfds.is_set(fd) { panic!(); } @@ -38,7 +40,7 @@ fn main() -> i32 { loop { print!("> "); - let line = readline(libusr::sys::STDIN_FILENO, &mut buf).unwrap(); + let line = readline(FileDescriptor::STDIN, &mut buf).unwrap(); if line.is_empty() { break; } From 1f204e1d4c2b92410702663dcd44af7f2fa2023d Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sat, 13 Nov 2021 15:44:55 +0200 Subject: [PATCH 17/42] refactor: better syscall result handling --- kernel/src/arch/aarch64/exception.rs | 13 +- kernel/src/mem/phys/manager.rs | 3 +- libsys/src/calls.rs | 225 ++++++++++++++++----------- libsys/src/error.rs | 31 ++++ libusr/src/file.rs | 12 ++ libusr/src/io.rs | 6 +- libusr/src/lib.rs | 8 +- libusr/src/os.rs | 34 ++-- user/src/init/main.rs | 33 ++-- user/src/shell/main.rs | 13 +- 10 files changed, 222 insertions(+), 156 deletions(-) create mode 100644 libusr/src/file.rs diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 5117ea4..1304e0a 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -6,8 +6,8 @@ use crate::dev::irq::{IntController, IrqContext}; use crate::mem; use crate::proc::{sched, Process}; use crate::syscall; -use libsys::{abi, signal::Signal}; use cortex_a::registers::{ESR_EL1, FAR_EL1}; +use libsys::{abi, signal::Signal}; use tock_registers::interfaces::Readable; /// Trapped SIMD/FP functionality @@ -92,7 +92,10 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { if far < mem::KERNEL_OFFSET && sched::is_ready() { let proc = Process::current(); - if proc.manipulate_space(|space| space.try_cow_copy(far)).is_err() { + if proc + .manipulate_space(|space| space.try_cow_copy(far)) + .is_err() + { // Kill program dump_data_abort(Level::Error, esr, far as u64); proc.enter_signal(Signal::SegmentationFault); @@ -117,8 +120,7 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { match syscall::sys_fork(exc) { Ok(pid) => exc.x[0] = pid.value() as usize, Err(err) => { - warnln!("fork() syscall failed: {:?}", err); - exc.x[0] = usize::MAX; + exc.x[0] = err.to_negative_isize() as usize; } } return; @@ -127,8 +129,7 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { match syscall::syscall(exc.x[8], &exc.x[..6]) { Ok(val) => exc.x[0] = val, Err(err) => { - warnln!("syscall {} failed: {:?}", exc.x[8], err); - exc.x[0] = usize::MAX + exc.x[0] = err.to_negative_isize() as usize; } } } diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index b82f552..4ad8b48 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -139,7 +139,8 @@ unsafe impl Manager for SimpleManager { usage }; - self.update_stats_free(usage, 1); + // FIXME + // self.update_stats_free(usage, 1); Ok(()) } diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index e2bd7b0..b2ece93 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -1,6 +1,8 @@ use crate::abi; use crate::{ + error::Errno, ioctl::IoctlCmd, + proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, }; @@ -71,8 +73,10 @@ macro_rules! argp { /// /// System call #[inline(always)] -pub unsafe fn sys_exit(status: i32) -> ! { - syscall!(abi::SYS_EXIT, argn!(status)); +pub fn sys_exit(code: ExitCode) -> ! { + unsafe { + syscall!(abi::SYS_EXIT, argn!(i32::from(code))); + } unreachable!(); } @@ -80,172 +84,209 @@ pub unsafe fn sys_exit(status: i32) -> ! { /// /// System call #[inline(always)] -pub unsafe fn sys_close(fd: FileDescriptor) -> i32 { - syscall!(abi::SYS_CLOSE, argn!(u32::from(fd))) as i32 +pub fn sys_close(fd: FileDescriptor) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { syscall!(abi::SYS_CLOSE, argn!(u32::from(fd))) }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_ex_nanosleep(ns: u64, rem: &mut [u64; 2]) -> i32 { - syscall!(abi::SYS_EX_NANOSLEEP, argn!(ns), argp!(rem.as_mut_ptr())) as i32 +pub fn sys_ex_nanosleep(ns: u64, rem: &mut [u64; 2]) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!(abi::SYS_EX_NANOSLEEP, argn!(ns), argp!(rem.as_mut_ptr())) + }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_ex_debug_trace(msg: &[u8]) -> usize { - syscall!( - abi::SYS_EX_DEBUG_TRACE, - argp!(msg.as_ptr()), - argn!(msg.len()) - ) +pub fn sys_ex_debug_trace(msg: &[u8]) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + abi::SYS_EX_DEBUG_TRACE, + argp!(msg.as_ptr()), + argn!(msg.len()) + ) + }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_openat( +pub fn sys_openat( at: Option, pathname: &str, mode: FileMode, flags: OpenFlags, -) -> i32 { - syscall!( - abi::SYS_OPENAT, - argn!(FileDescriptor::into_i32(at)), - argp!(pathname.as_ptr()), - argn!(pathname.len()), - argn!(mode.bits()), - argn!(flags.bits()) - ) as i32 +) -> Result { + Errno::from_syscall(unsafe { + syscall!( + abi::SYS_OPENAT, + argn!(FileDescriptor::into_i32(at)), + argp!(pathname.as_ptr()), + argn!(pathname.len()), + argn!(mode.bits()), + argn!(flags.bits()) + ) + }) + .map(|e| FileDescriptor::from(e as u32)) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_read(fd: FileDescriptor, data: &mut [u8]) -> isize { - syscall!( - abi::SYS_READ, - argn!(u32::from(fd)), - argp!(data.as_mut_ptr()), - argn!(data.len()) - ) as isize +pub fn sys_read(fd: FileDescriptor, data: &mut [u8]) -> Result { + Errno::from_syscall(unsafe { + syscall!( + abi::SYS_READ, + argn!(u32::from(fd)), + argp!(data.as_mut_ptr()), + argn!(data.len()) + ) + }) +} + +#[inline(always)] +pub fn sys_write(fd: FileDescriptor, data: &[u8]) -> Result { + Errno::from_syscall(unsafe { + syscall!( + abi::SYS_WRITE, + argn!(u32::from(fd)), + argp!(data.as_ptr()), + argn!(data.len()) + ) + }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_write(fd: FileDescriptor, data: &[u8]) -> isize { - syscall!( - abi::SYS_WRITE, - argn!(u32::from(fd)), - argp!(data.as_ptr()), - argn!(data.len()) - ) as isize -} - -/// # Safety -/// -/// System call -#[inline(always)] -pub unsafe fn sys_fstatat( +pub fn sys_fstatat( at: Option, pathname: &str, statbuf: &mut Stat, flags: u32, -) -> i32 { - syscall!( - abi::SYS_FSTATAT, - argn!(FileDescriptor::into_i32(at)), - argp!(pathname.as_ptr()), - argn!(pathname.len()), - argp!(statbuf as *mut Stat), - argn!(flags) - ) as i32 +) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + abi::SYS_FSTATAT, + argn!(FileDescriptor::into_i32(at)), + argp!(pathname.as_ptr()), + argn!(pathname.len()), + argp!(statbuf as *mut Stat), + argn!(flags) + ) + }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_fork() -> i32 { - syscall!(abi::SYS_FORK) as i32 +pub fn sys_fork() -> Result, Errno> { + Errno::from_syscall(unsafe { syscall!(abi::SYS_FORK) }).map(|res| { + if res != 0 { + Some(unsafe { Pid::from_raw(res as u32) }) + } else { + None + } + }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_execve(pathname: &str) -> i32 { - syscall!( - abi::SYS_EXECVE, - argp!(pathname.as_ptr()), - argn!(pathname.len()) - ) as i32 +pub fn sys_execve(pathname: &str) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + abi::SYS_EXECVE, + argp!(pathname.as_ptr()), + argn!(pathname.len()) + ) + }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_waitpid(pid: u32, status: &mut i32) -> i32 { - syscall!(abi::SYS_WAITPID, argn!(pid), argp!(status as *mut i32)) as i32 +pub fn sys_waitpid(pid: Pid, status: &mut i32) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + abi::SYS_WAITPID, + argn!(pid.value()), + argp!(status as *mut i32) + ) + }) } /// # Safety /// /// System call #[inline(always)] -pub unsafe fn sys_ioctl(fd: FileDescriptor, cmd: IoctlCmd, ptr: usize, len: usize) -> isize { - syscall!( - abi::SYS_IOCTL, - argn!(u32::from(fd)), - argn!(cmd), - argn!(ptr), - argn!(len) - ) as isize +pub fn sys_ioctl( + fd: FileDescriptor, + cmd: IoctlCmd, + ptr: usize, + len: usize, +) -> Result { + Errno::from_syscall(unsafe { + syscall!( + abi::SYS_IOCTL, + argn!(u32::from(fd)), + argn!(cmd), + argn!(ptr), + argn!(len) + ) + }) } #[inline(always)] -pub unsafe fn sys_ex_signal(entry: usize, stack: usize) { - syscall!(abi::SYS_EX_SIGNAL, argn!(entry), argn!(stack)); +pub fn sys_ex_signal(entry: usize, stack: usize) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { syscall!(abi::SYS_EX_SIGNAL, argn!(entry), argn!(stack)) }) } #[inline(always)] -pub unsafe fn sys_ex_sigreturn() -> ! { - syscall!(abi::SYS_EX_SIGRETURN); +pub fn sys_ex_sigreturn() -> ! { + unsafe { + syscall!(abi::SYS_EX_SIGRETURN); + } unreachable!(); } #[inline(always)] -pub unsafe fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> i32 { - syscall!( - abi::SYS_EX_KILL, - argn!(isize::from(pid)), - argn!(signum as u32) - ) as i32 +pub fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + abi::SYS_EX_KILL, + argn!(isize::from(pid)), + argn!(signum as u32) + ) + }) } #[inline(always)] -pub unsafe fn sys_select( +pub fn sys_select( read_fds: Option<&mut FdSet>, write_fds: Option<&mut FdSet>, timeout: u64, -) -> i32 { - syscall!( - abi::SYS_SELECT, - argp!(read_fds - .map(|e| e as *mut _) - .unwrap_or(core::ptr::null_mut())), - argp!(write_fds - .map(|e| e as *mut _) - .unwrap_or(core::ptr::null_mut())), - argn!(timeout) - ) as i32 +) -> Result { + Errno::from_syscall(unsafe { + syscall!( + abi::SYS_SELECT, + argp!(read_fds + .map(|e| e as *mut _) + .unwrap_or(core::ptr::null_mut())), + argp!(write_fds + .map(|e| e as *mut _) + .unwrap_or(core::ptr::null_mut())), + argn!(timeout) + ) + }) } diff --git a/libsys/src/error.rs b/libsys/src/error.rs index 3657ddb..3f42bf4 100644 --- a/libsys/src/error.rs +++ b/libsys/src/error.rs @@ -1,4 +1,5 @@ #[derive(PartialEq, Debug, Clone, Copy)] +#[repr(u32)] pub enum Errno { AlreadyExists, BadExecutable, @@ -19,3 +20,33 @@ pub enum Errno { TooManyDescriptors, WouldBlock, } + +impl Errno { + pub const fn to_negative_isize(self) -> isize { + -(self as isize) + } + + pub fn from_syscall(u: usize) -> Result { + let i = u as isize; + if i < 0 { + Err(Self::from((-i) as usize)) + } else { + Ok(u) + } + } + + pub fn from_syscall_unit(u: usize) -> Result<(), Self> { + let i = u as isize; + if i < 0 { + Err(Self::from((-i) as usize)) + } else { + Ok(()) + } + } +} + +impl From for Errno { + fn from(u: usize) -> Errno { + todo!() + } +} diff --git a/libusr/src/file.rs b/libusr/src/file.rs new file mode 100644 index 0000000..d90eff7 --- /dev/null +++ b/libusr/src/file.rs @@ -0,0 +1,12 @@ +use libsys::stat::FileDescriptor; +use crate::io; + +pub struct File { + fd: FileDescriptor +} + +impl File { + pub fn open(path: &str) -> Result { + todo!() + } +} diff --git a/libusr/src/io.rs b/libusr/src/io.rs index 650fcaa..2cbb407 100644 --- a/libusr/src/io.rs +++ b/libusr/src/io.rs @@ -9,10 +9,8 @@ pub struct Error; pub fn stat(pathname: &str) -> Result { let mut buf = Stat::default(); - let res = unsafe { sys_fstatat(None, pathname, &mut buf, 0) }; - if res != 0 { - todo!(); - } + // TODO error handling + let res = unsafe { sys_fstatat(None, pathname, &mut buf, 0).unwrap() }; Ok(buf) } diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index 6199930..18c547b 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -2,9 +2,11 @@ #![no_std] use core::panic::PanicInfo; +use libsys::proc::ExitCode; pub mod io; pub mod os; +pub mod file; pub mod sys { pub use libsys::signal::{Signal, SignalDestination}; @@ -33,7 +35,7 @@ extern "C" fn _start(_arg: usize) -> ! { SIGNAL_STACK[0] = 1; sys::sys_ex_signal(_signal_handler as usize, SIGNAL_STACK.as_ptr() as usize + 4096); - sys::sys_exit(main()); + sys::sys_exit(ExitCode::from(main())); } } @@ -41,7 +43,5 @@ extern "C" fn _start(_arg: usize) -> ! { fn panic_handler(pi: &PanicInfo) -> ! { // TODO formatted messages trace!("Panic ocurred: {}", pi); - unsafe { - sys::sys_exit(-1); - } + sys::sys_exit(ExitCode::from(-1)); } diff --git a/libusr/src/os.rs b/libusr/src/os.rs index 76bb6ab..00c00ab 100644 --- a/libusr/src/os.rs +++ b/libusr/src/os.rs @@ -5,30 +5,28 @@ use libsys::{ioctl::IoctlCmd, stat::FileDescriptor, termios::Termios}; pub fn get_tty_attrs(fd: FileDescriptor) -> Result { let mut termios = MaybeUninit::::uninit(); - let res = unsafe { - sys::sys_ioctl( - fd, - IoctlCmd::TtyGetAttributes, - termios.as_mut_ptr() as usize, - size_of::(), - ) - }; - if res != size_of::() as isize { + let res = sys::sys_ioctl( + fd, + IoctlCmd::TtyGetAttributes, + termios.as_mut_ptr() as usize, + size_of::(), + ) + .unwrap(); + if res != size_of::() { return Err("Failed"); } Ok(unsafe { termios.assume_init() }) } pub fn set_tty_attrs(fd: FileDescriptor, attrs: &Termios) -> Result<(), &'static str> { - let res = unsafe { - sys::sys_ioctl( - fd, - IoctlCmd::TtySetAttributes, - attrs as *const _ as usize, - size_of::(), - ) - }; - if res != size_of::() as isize { + let res = sys::sys_ioctl( + fd, + IoctlCmd::TtySetAttributes, + attrs as *const _ as usize, + size_of::(), + ) + .unwrap(); + if res != size_of::() { return Err("Failed"); } Ok(()) diff --git a/user/src/init/main.rs b/user/src/init/main.rs index 59c5ed7..f033d6d 100644 --- a/user/src/init/main.rs +++ b/user/src/init/main.rs @@ -5,31 +5,22 @@ #[macro_use] extern crate libusr; -use core::cmp::Ordering; - #[no_mangle] fn main() -> i32 { - let pid = unsafe { libusr::sys::sys_fork() }; - match pid.cmp(&0) { - Ordering::Less => { - eprintln!("fork() failed"); - -1 - } - Ordering::Equal => unsafe { libusr::sys::sys_execve("/bin/shell") }, - Ordering::Greater => { - let mut status = 0; - let res = unsafe { libusr::sys::sys_waitpid(pid as u32, &mut status) }; - if res == 0 { - println!("Process {} exited with status {}", pid, status); - } else { - eprintln!("waitpid() failed"); - } + let pid = libusr::sys::sys_fork().unwrap(); - loop { - unsafe { - asm!("nop"); - } + if let Some(pid) = pid { + let mut status = 0; + libusr::sys::sys_waitpid(pid, &mut status).unwrap(); + println!("Process {:?} exited with status {}", pid, status); + + loop { + unsafe { + asm!("nop"); } } + } else { + libusr::sys::sys_execve("/bin/shell").unwrap(); + loop {} } } diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 02e796c..fbf27f2 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -13,11 +13,8 @@ fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, ()> { let mut rfds = FdSet::empty(); rfds.set(fd); let res = unsafe { - libusr::sys::sys_select(Some(&mut rfds), None, 1_000_000_000) + libusr::sys::sys_select(Some(&mut rfds), None, 1_000_000_000).unwrap() }; - if res < 0 { - return Err(()); - } if res == 0 { continue; } @@ -25,12 +22,8 @@ fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, ()> { panic!(); } - let count = unsafe { libusr::sys::sys_read(fd, buf) }; - if count >= 0 { - return core::str::from_utf8(&buf[..count as usize]).map_err(|_| ()); - } else { - return Err(()); - } + let count = unsafe { libusr::sys::sys_read(fd, buf).unwrap() }; + return core::str::from_utf8(&buf[..count as usize]).map_err(|_| ()); } } From 6bb4f38edcb4365817f8401a9a75e7047ad58908 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 16 Nov 2021 14:34:14 +0200 Subject: [PATCH 18/42] feature: Stdin/Stdout/Stderr structs --- Cargo.lock | 16 +++++ libusr/Cargo.toml | 1 + libusr/src/file.rs | 20 ++++++- libusr/src/io.rs | 65 -------------------- libusr/src/io/error.rs | 35 +++++++++++ libusr/src/io/mod.rs | 32 ++++++++++ libusr/src/io/stdio.rs | 130 ++++++++++++++++++++++++++++++++++++++++ libusr/src/io/writer.rs | 26 ++++++++ libusr/src/lib.rs | 33 +++++----- libusr/src/os.rs | 33 +--------- libusr/src/sync.rs | 54 +++++++++++++++++ libusr/src/sys/mod.rs | 39 ++++++++++++ user/src/shell/main.rs | 48 +++------------ 13 files changed, 376 insertions(+), 156 deletions(-) delete mode 100644 libusr/src/io.rs create mode 100644 libusr/src/io/error.rs create mode 100644 libusr/src/io/mod.rs create mode 100644 libusr/src/io/stdio.rs create mode 100644 libusr/src/io/writer.rs create mode 100644 libusr/src/sync.rs create mode 100644 libusr/src/sys/mod.rs diff --git a/Cargo.lock b/Cargo.lock index a042c61..0567f66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,6 +97,15 @@ dependencies = [ "syn", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + [[package]] name = "libsys" version = "0.1.0" @@ -108,6 +117,7 @@ dependencies = [ name = "libusr" version = "0.1.0" dependencies = [ + "lazy_static", "libsys", ] @@ -195,6 +205,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/libusr/Cargo.toml b/libusr/Cargo.toml index 0b91506..feb52ee 100644 --- a/libusr/Cargo.toml +++ b/libusr/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] libsys = { path = "../libsys", features = ["user"] } +lazy_static = { version = "^1.4.0", features = ["spin_no_std"] } diff --git a/libusr/src/file.rs b/libusr/src/file.rs index d90eff7..80e7727 100644 --- a/libusr/src/file.rs +++ b/libusr/src/file.rs @@ -1,12 +1,26 @@ +use crate::io::{AsRawFd, Error}; +use crate::os; +use crate::trace; use libsys::stat::FileDescriptor; -use crate::io; pub struct File { - fd: FileDescriptor + fd: FileDescriptor, } impl File { - pub fn open(path: &str) -> Result { + pub fn open(path: &str) -> Result { todo!() } } + +impl AsRawFd for File { + fn as_raw_fd(&self) -> FileDescriptor { + self.fd + } +} + +impl Drop for File { + fn drop(&mut self) { + todo!(); + } +} diff --git a/libusr/src/io.rs b/libusr/src/io.rs deleted file mode 100644 index 2cbb407..0000000 --- a/libusr/src/io.rs +++ /dev/null @@ -1,65 +0,0 @@ -use core::fmt; -use libsys::{ - calls::{sys_fstatat, sys_write}, - stat::{Stat, FileDescriptor}, -}; - -// TODO populate this type -pub struct Error; - -pub fn stat(pathname: &str) -> Result { - let mut buf = Stat::default(); - // TODO error handling - let res = unsafe { sys_fstatat(None, pathname, &mut buf, 0).unwrap() }; - Ok(buf) -} - -// print!/println! group - -#[macro_export] -macro_rules! print { - ($($args:tt)+) => ($crate::io::_print($crate::sys::FileDescriptor::STDOUT, format_args!($($args)+))) -} - -#[macro_export] -macro_rules! println { - ($($args:tt)+) => (print!("{}\n", format_args!($($args)+))) -} - -#[macro_export] -macro_rules! eprint { - ($($args:tt)+) => ($crate::io::_print($crate::sys::FileDescriptor::STDERR, format_args!($($args)+))) -} - -#[macro_export] -macro_rules! eprintln { - ($($args:tt)+) => (eprint!("{}\n", 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 _print(fd: FileDescriptor, 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(); - unsafe { - sys_write(fd, &BUFFER[..writer.pos]); - } -} diff --git a/libusr/src/io/error.rs b/libusr/src/io/error.rs new file mode 100644 index 0000000..9818834 --- /dev/null +++ b/libusr/src/io/error.rs @@ -0,0 +1,35 @@ +use libsys::error::Errno; + +#[derive(Debug)] +pub struct Error { + repr: Repr, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum ErrorKind { + NotFound, + PermissionDenied, + InvalidData, +} + +#[derive(Debug)] +enum Repr { + Os(Errno), + Simple(ErrorKind), +} + +impl Error { + pub const fn new(kind: ErrorKind) -> Self { + Self { + repr: Repr::Simple(kind), + } + } +} + +impl From for Error { + fn from(e: Errno) -> Self { + Self { + repr: Repr::Os(e) + } + } +} diff --git a/libusr/src/io/mod.rs b/libusr/src/io/mod.rs new file mode 100644 index 0000000..ac29239 --- /dev/null +++ b/libusr/src/io/mod.rs @@ -0,0 +1,32 @@ +use libsys::{ + calls::sys_fstatat, + stat::{FileDescriptor, Stat}, +}; +use core::fmt; + +mod error; +pub use error::{Error, ErrorKind}; +mod writer; +pub use writer::{_print}; +mod stdio; +pub use stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; + +pub trait Read { + fn read(&mut self, bytes: &mut [u8]) -> Result; +} + +pub trait Write { + fn write(&mut self, bytes: &[u8]) -> Result; + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error>; +} + +pub trait AsRawFd { + fn as_raw_fd(&self) -> FileDescriptor; +} + +pub fn stat(pathname: &str) -> Result { + let mut buf = Stat::default(); + // TODO error handling + let res = sys_fstatat(None, pathname, &mut buf, 0).unwrap(); + Ok(buf) +} diff --git a/libusr/src/io/stdio.rs b/libusr/src/io/stdio.rs new file mode 100644 index 0000000..de7fc99 --- /dev/null +++ b/libusr/src/io/stdio.rs @@ -0,0 +1,130 @@ +use libsys::{ + stat::FileDescriptor, + calls::{sys_read, sys_write} +}; +use crate::io::{Read, Write, Error}; +use crate::sync::{Mutex, MutexGuard}; +use core::fmt; + +struct InputInner { + fd: FileDescriptor +} +struct OutputInner { + fd: FileDescriptor +} + +pub struct StdinLock<'a> { + lock: MutexGuard<'a, InputInner> +} + +pub struct StdoutLock<'a> { + lock: MutexGuard<'a, OutputInner> +} + +pub struct StderrLock<'a> { + lock: MutexGuard<'a, OutputInner> +} + +pub struct Stdin { + inner: &'static Mutex, +} + +pub struct Stdout { + inner: &'static Mutex +} + +pub struct Stderr { + inner: &'static Mutex +} + +// STDIN + +impl Read for InputInner { + fn read(&mut self, bytes: &mut [u8]) -> Result { + sys_read(self.fd, bytes).map_err(Error::from) + } +} + +impl Read for Stdin { + fn read(&mut self, bytes: &mut [u8]) -> Result { + self.inner.lock().read(bytes) + } +} + +// STDOUT/STDERR + +impl fmt::Write for OutputInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write(s.as_bytes()).map(|_| ()).map_err(|_| todo!()) + } +} + +impl Write for OutputInner { + fn write(&mut self, bytes: &[u8]) -> Result { + sys_write(self.fd, bytes).map_err(Error::from) + } + + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error> { + fmt::Write::write_fmt(self, args).map_err(|_| todo!()) + } +} + +impl Write for Stdout { + fn write(&mut self, bytes: &[u8]) -> Result { + self.inner.lock().write(bytes) + } + + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error> { + self.inner.lock().write_fmt(args) + } +} + +impl Write for Stderr { + fn write(&mut self, bytes: &[u8]) -> Result { + self.inner.lock().write(bytes) + } + + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error> { + self.inner.lock().write_fmt(args) + } +} + +impl Stdout { + pub fn lock(&self) -> StdoutLock { + StdoutLock { + lock: self.inner.lock() + } + } +} + +impl Stderr { + pub fn lock(&self) -> StderrLock { + StderrLock { + lock: self.inner.lock() + } + } +} + +lazy_static! { + static ref STDIN: Mutex = Mutex::new(InputInner { + fd: FileDescriptor::STDIN + }); + static ref STDOUT: Mutex = Mutex::new(OutputInner { + fd: FileDescriptor::STDOUT + }); + static ref STDERR: Mutex = Mutex::new(OutputInner { + fd: FileDescriptor::STDOUT + }); +} + +pub fn stdin() -> Stdin { + Stdin { inner: &STDIN } +} + +pub fn stdout() -> Stdout { + Stdout { inner: &STDOUT } +} + +pub fn stderr() -> Stderr { + Stderr { inner: &STDERR } +} diff --git a/libusr/src/io/writer.rs b/libusr/src/io/writer.rs new file mode 100644 index 0000000..30ed6d8 --- /dev/null +++ b/libusr/src/io/writer.rs @@ -0,0 +1,26 @@ +use core::fmt; +use crate::io::{self, Write}; + +#[macro_export] +macro_rules! print { + ($($args:tt)+) => ($crate::io::_print($crate::io::stdout, format_args!($($args)+))) +} + +#[macro_export] +macro_rules! println { + ($($args:tt)+) => (print!("{}\n", format_args!($($args)+))) +} + +#[macro_export] +macro_rules! eprint { + ($($args:tt)+) => ($crate::io::_print($crate::io::stderr, format_args!($($args)+))) +} + +#[macro_export] +macro_rules! eprintln { + ($($args:tt)+) => (eprint!("{}\n", format_args!($($args)+))) +} + +pub fn _print(out: fn() -> T, args: fmt::Arguments) { + out().write_fmt(args).expect("stdout/stderr write failed"); +} diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index 18c547b..f85f49a 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -4,23 +4,19 @@ use core::panic::PanicInfo; use libsys::proc::ExitCode; +#[macro_use] +extern crate lazy_static; + +pub mod file; pub mod io; pub mod os; -pub mod file; - -pub mod sys { - pub use libsys::signal::{Signal, SignalDestination}; - pub use libsys::termios; - pub use libsys::calls::*; - pub use libsys::stat::{self, FileDescriptor}; -} +pub mod sys; +pub mod sync; #[inline(never)] extern "C" fn _signal_handler(arg: sys::Signal) -> ! { trace!("Entered signal handler: arg={:?}", arg); - unsafe { - sys::sys_ex_sigreturn(); - } + sys::sys_ex_sigreturn(); } static mut SIGNAL_STACK: [u8; 4096] = [0; 4096]; @@ -31,17 +27,22 @@ extern "C" fn _start(_arg: usize) -> ! { extern "Rust" { fn main() -> i32; } - unsafe { - SIGNAL_STACK[0] = 1; - sys::sys_ex_signal(_signal_handler as usize, SIGNAL_STACK.as_ptr() as usize + 4096); - sys::sys_exit(ExitCode::from(main())); + unsafe { + sys::sys_ex_signal( + _signal_handler as usize, + SIGNAL_STACK.as_ptr() as usize + 4096, + ) + .unwrap(); } + + let res = unsafe { main() }; + sys::sys_exit(ExitCode::from(res)); } #[panic_handler] fn panic_handler(pi: &PanicInfo) -> ! { - // TODO formatted messages + // TODO print to stdout/stderr (if available) trace!("Panic ocurred: {}", pi); sys::sys_exit(ExitCode::from(-1)); } diff --git a/libusr/src/os.rs b/libusr/src/os.rs index 00c00ab..85a385a 100644 --- a/libusr/src/os.rs +++ b/libusr/src/os.rs @@ -3,35 +3,6 @@ use core::fmt; use core::mem::{size_of, MaybeUninit}; use libsys::{ioctl::IoctlCmd, stat::FileDescriptor, termios::Termios}; -pub fn get_tty_attrs(fd: FileDescriptor) -> Result { - let mut termios = MaybeUninit::::uninit(); - let res = sys::sys_ioctl( - fd, - IoctlCmd::TtyGetAttributes, - termios.as_mut_ptr() as usize, - size_of::(), - ) - .unwrap(); - if res != size_of::() { - return Err("Failed"); - } - Ok(unsafe { termios.assume_init() }) -} - -pub fn set_tty_attrs(fd: FileDescriptor, attrs: &Termios) -> Result<(), &'static str> { - let res = sys::sys_ioctl( - fd, - IoctlCmd::TtySetAttributes, - attrs as *const _ as usize, - size_of::(), - ) - .unwrap(); - if res != size_of::() { - return Err("Failed"); - } - Ok(()) -} - #[macro_export] macro_rules! trace { ($($args:tt)+) => ($crate::os::_trace(format_args!($($args)+))) @@ -60,7 +31,5 @@ pub fn _trace(args: fmt::Arguments) { pos: 0, }; writer.write_fmt(args).ok(); - unsafe { - sys::sys_ex_debug_trace(&BUFFER[..writer.pos]); - } + sys::sys_ex_debug_trace(unsafe { &BUFFER[..writer.pos] }).ok(); } diff --git a/libusr/src/sync.rs b/libusr/src/sync.rs new file mode 100644 index 0000000..e04b5c9 --- /dev/null +++ b/libusr/src/sync.rs @@ -0,0 +1,54 @@ +use core::cell::UnsafeCell; +use core::ops::{Deref, DerefMut}; +use crate::sys::RawMutex; + +pub struct Mutex { + inner: RawMutex, + data: UnsafeCell +} + +pub struct MutexGuard<'a, T> { + data: &'a mut T, + lock: &'a RawMutex, +} + +impl Mutex { + pub fn new(t: T) -> Self { + Self { + inner: RawMutex::new(), + data: UnsafeCell::new(t) + } + } + + pub fn lock(&self) -> MutexGuard<'_, T> { + unsafe { + self.inner.lock(); + MutexGuard { + data: (&mut *self.data.get()), + lock: &self.inner + } + } + } +} + +impl<'a, T> Drop for MutexGuard<'a, T> { + fn drop(&mut self) { + unsafe { self.lock.release(); } + } +} + +impl<'a, T> Deref for MutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + self.data + } +} + +impl<'a, T> DerefMut for MutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + self.data + } +} + +unsafe impl Sync for Mutex {} diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs new file mode 100644 index 0000000..af55f54 --- /dev/null +++ b/libusr/src/sys/mod.rs @@ -0,0 +1,39 @@ +pub use libsys::signal::{Signal, SignalDestination}; +pub use libsys::termios; +pub use libsys::calls::*; +pub use libsys::stat::{self, FileDescriptor}; + +use core::sync::atomic::{Ordering, AtomicBool}; + +// TODO replace with a proper mutex impl +pub(crate) struct RawMutex { + inner: AtomicBool +} + +impl RawMutex { + pub const fn new() -> Self { + Self { inner: AtomicBool::new(false) } + } + + #[inline] + unsafe fn try_lock(&self) -> bool { + self.inner.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_ok() + } + + #[inline] + unsafe fn is_locked(&self) -> bool { + self.inner.load(Ordering::Acquire) + } + + #[inline] + pub unsafe fn lock(&self) { + while !self.try_lock() { + asm!("nop"); + } + } + + #[inline] + pub unsafe fn release(&self) { + self.inner.store(false, Ordering::Release); + } +} diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index fbf27f2..d6044a1 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -4,54 +4,22 @@ #[macro_use] extern crate libusr; -use libusr::sys::stat::{FdSet, FileDescriptor}; -use libusr::sys::{Signal, SignalDestination}; - -fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, ()> { - // select() just for test - loop { - let mut rfds = FdSet::empty(); - rfds.set(fd); - let res = unsafe { - libusr::sys::sys_select(Some(&mut rfds), None, 1_000_000_000).unwrap() - }; - if res == 0 { - continue; - } - if !rfds.is_set(fd) { - panic!(); - } - - let count = unsafe { libusr::sys::sys_read(fd, buf).unwrap() }; - return core::str::from_utf8(&buf[..count as usize]).map_err(|_| ()); - } -} +use libusr::io::{self, Read}; #[no_mangle] fn main() -> i32 { let mut buf = [0; 512]; + let mut stdin = io::stdin(); + + eprintln!("stderr test"); loop { - print!("> "); - let line = readline(FileDescriptor::STDIN, &mut buf).unwrap(); - if line.is_empty() { - break; - } - let line = line.trim_end_matches('\n'); - - println!(":: {:?}", line); - - if line == "test" { - unsafe { - libusr::sys::sys_ex_kill(SignalDestination::This, Signal::Interrupt); - } - trace!("Returned from signal"); - continue; - } - - if line == "quit" || line == "exit" { + let count = stdin.read(&mut buf).unwrap(); + if count == 0 { break; } + let line = core::str::from_utf8(&buf[..count]).unwrap(); + println!("{:?}", line); } 0 From adb95ac52ed772f7b3d12665ae596546ea6a462a Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 17 Nov 2021 13:05:51 +0200 Subject: [PATCH 19/42] feature: add threads (WIP) --- Cargo.lock | 1 + kernel/src/arch/aarch64/exception.rs | 12 +- kernel/src/init.rs | 2 +- kernel/src/proc/mod.rs | 10 +- kernel/src/proc/process.rs | 424 +++++++++++---------------- kernel/src/proc/sched.rs | 62 ++-- kernel/src/proc/thread.rs | 325 ++++++++++++++++++++ kernel/src/proc/wait.rs | 134 +++++---- kernel/src/syscall/mod.rs | 33 ++- libsys/src/abi.rs | 2 + libsys/src/calls.rs | 26 ++ libsys/src/error.rs | 2 +- libusr/src/lib.rs | 9 +- libusr/src/sys/mod.rs | 3 +- user/Cargo.toml | 1 + user/src/shell/main.rs | 67 ++++- 16 files changed, 746 insertions(+), 367 deletions(-) create mode 100644 kernel/src/proc/thread.rs diff --git a/Cargo.lock b/Cargo.lock index 0567f66..03e4c5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,6 +250,7 @@ checksum = "1230ec65f13e0f9b28d789da20d2d419511893ea9dac2c1f4ef67b8b14e5da80" name = "user" version = "0.1.0" dependencies = [ + "lazy_static", "libusr", ] diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 1304e0a..d25cc60 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -4,7 +4,7 @@ use crate::arch::machine; use crate::debug::Level; use crate::dev::irq::{IntController, IrqContext}; use crate::mem; -use crate::proc::{sched, Process}; +use crate::proc::{sched, Thread, Process}; use crate::syscall; use cortex_a::registers::{ESR_EL1, FAR_EL1}; use libsys::{abi, signal::Signal}; @@ -90,7 +90,8 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { let far = FAR_EL1.get() as usize; if far < mem::KERNEL_OFFSET && sched::is_ready() { - let proc = Process::current(); + let thread = Thread::current(); + let proc = thread.owner().unwrap(); if proc .manipulate_space(|space| space.try_cow_copy(far)) @@ -98,7 +99,7 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { { // Kill program dump_data_abort(Level::Error, esr, far as u64); - proc.enter_signal(Signal::SegmentationFault); + proc.enter_fault_signal(thread, Signal::SegmentationFault); } unsafe { @@ -138,6 +139,11 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { _ => {} } + if sched::is_ready() { + let thread = Thread::current(); + errorln!("Unhandled exception in thread {}, {:?}", thread.id(), thread.owner().map(|e| e.id())); + } + errorln!( "Unhandled exception at ELR={:#018x}, ESR={:#010x}", exc.elr_el1, diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 9744253..53aea9f 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -3,7 +3,7 @@ use crate::config::{ConfigKey, CONFIG}; use crate::fs::{devfs, MemfsBlockAlloc}; use crate::mem; -use crate::proc::{elf, Process}; +use crate::proc::{wait, elf, Process}; use libsys::stat::{FileDescriptor, OpenFlags}; use memfs::Ramfs; use vfs::{Filesystem, Ioctx}; diff --git a/kernel/src/proc/mod.rs b/kernel/src/proc/mod.rs index 4ddc628..1c77633 100644 --- a/kernel/src/proc/mod.rs +++ b/kernel/src/proc/mod.rs @@ -6,8 +6,11 @@ use alloc::collections::BTreeMap; use libsys::proc::Pid; pub mod elf; +pub mod thread; +pub use thread::{Thread, ThreadRef, State as ThreadState}; +pub(self) use thread::Context; pub mod process; -pub use process::{Process, ProcessRef, State as ProcessState}; +pub use process::{Process, ProcessRef, ProcessState}; pub mod io; pub use io::ProcessIo; @@ -52,6 +55,9 @@ pub fn process(id: Pid) -> ProcessRef { pub(self) static PROCESSES: IrqSafeSpinLock> = IrqSafeSpinLock::new(BTreeMap::new()); +pub(self) static THREADS: IrqSafeSpinLock> = + IrqSafeSpinLock::new(BTreeMap::new()); + /// Sets up initial process and enters it. /// /// See [Scheduler::enter] @@ -61,6 +67,6 @@ pub(self) static PROCESSES: IrqSafeSpinLock> = /// Unsafe: May only be called once. pub unsafe fn enter() -> ! { SCHED.init(); - SCHED.enqueue(Process::new_kernel(init::init_fn, 0).unwrap().id()); + Process::new_kernel(init::init_fn, 0).unwrap().enqueue(); SCHED.enter(); } diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index e511943..7506853 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -5,50 +5,45 @@ use crate::mem::{ phys::{self, PageUsage}, virt::{MapAttributes, Space}, }; -use crate::proc::{wait::Wait, ProcessIo, PROCESSES, SCHED}; -use crate::sync::IrqSafeSpinLock; -use alloc::rc::Rc; +use crate::proc::{ + wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED, THREADS, +}; +use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard}; +use alloc::{rc::Rc, vec::Vec}; use core::cell::UnsafeCell; use core::sync::atomic::{AtomicU32, Ordering}; -use libsys::{error::Errno, signal::Signal, proc::{ExitCode, Pid}}; - -pub use crate::arch::platform::context::{self, Context}; +use libsys::{ + error::Errno, + proc::{ExitCode, Pid}, + signal::Signal, +}; /// Wrapper type for a process struct reference pub type ProcessRef = Rc; /// List of possible process states #[derive(Clone, Copy, Debug, PartialEq)] -pub enum State { - /// Process is ready to be executed and/or is scheduled for it - Ready, - /// Process is currently running or is in system call/interrupt handler - Running, +pub enum ProcessState { + /// Process is alive + Active, /// Process has finished execution and is waiting to be reaped Finished, - /// Process is waiting for some external event - Waiting, } struct ProcessInner { space: Option<&'static mut Space>, - state: State, + state: ProcessState, id: Pid, - wait_flag: bool, exit: Option, - signal_entry: usize, - signal_stack: usize, + threads: Vec, } /// Structure describing an operating system process #[allow(dead_code)] pub struct Process { - ctx: UnsafeCell, - signal_ctx: UnsafeCell, inner: IrqSafeSpinLock, exit_wait: Wait, signal_state: AtomicU32, - signal_pending: AtomicU32, /// Process I/O context pub io: IrqSafeSpinLock, } @@ -57,9 +52,53 @@ impl Process { const USTACK_VIRT_TOP: usize = 0x100000000; const USTACK_PAGES: usize = 4; - /// Returns currently executing process + #[inline] + pub fn id(&self) -> Pid { + self.inner.lock().id + } + + #[inline] pub fn current() -> ProcessRef { - SCHED.current_process() + Thread::current().owner().unwrap() + } + + #[inline] + pub fn manipulate_space(&self, f: F) -> Result<(), Errno> + where + F: FnOnce(&mut Space) -> Result<(), Errno>, + { + f(self.inner.lock().space.as_mut().unwrap()) + } + + pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result { + let id = new_kernel_pid(); + let thread = Thread::new_kernel(Some(id), entry, arg)?; + let mut inner = ProcessInner { + threads: Vec::new(), + id, + exit: None, + space: None, + state: ProcessState::Active, + }; + inner.threads.push(thread.id()); + + let res = Rc::new(Self { + exit_wait: Wait::new(), + io: IrqSafeSpinLock::new(ProcessIo::new()), + signal_state: AtomicU32::new(0), + inner: IrqSafeSpinLock::new(inner), + }); + debugln!("New kernel process: {:?}", id); + let prev = PROCESSES.lock().insert(id, res.clone()); + assert!(prev.is_none()); + Ok(res) + } + + pub fn enqueue(&self) { + let inner = self.inner.lock(); + for &tid in inner.threads.iter() { + SCHED.enqueue(tid); + } } /// Returns process (if any) to which `pid` refers @@ -69,201 +108,55 @@ impl Process { /// Sets a pending signal for a process pub fn set_signal(&self, signal: Signal) { - let lock = self.inner.lock(); + let mut lock = self.inner.lock(); + let main_thread = Thread::get(lock.threads[0]).unwrap(); - match lock.state { - State::Running => { - drop(lock); - self.enter_signal(signal); + // TODO check that `signal` is not a fault signal + // it is illegal to call this function with + // fault signals + + match main_thread.state() { + ThreadState::Running => { + Process::enter_signal_on(lock, main_thread, signal); } - State::Waiting => { + ThreadState::Waiting => { // TODO abort whatever the process is waiting for todo!() } - State::Ready => { + ThreadState::Ready => { todo!() } - State::Finished => { + ThreadState::Finished => { // TODO report error back todo!() } } } - /// Switches current thread back from signal handler - pub fn return_from_signal(&self) { - if self.signal_pending.load(Ordering::Acquire) == 0 { - panic!("TODO handle cases when returning from no signal"); - } - self.signal_pending.store(0, Ordering::Release); - - let src_ctx = self.signal_ctx.get(); - let dst_ctx = self.ctx.get(); - - assert_eq!(self.inner.lock().state, State::Running); - - unsafe { - (&mut *src_ctx).switch(&mut *dst_ctx); - } + fn enter_signal_on(mut inner: IrqSafeSpinLockGuard, thread: ThreadRef, signal: Signal) { + let ttbr0 = + inner.space.as_mut().unwrap().address_phys() | ((inner.id.asid() as usize) << 48); + drop(inner); + thread.enter_signal(signal, ttbr0); } - /// Switches current thread to a signal handler - pub fn enter_signal(&self, signal: Signal) { - if self - .signal_pending - .compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed) - .is_err() - { - panic!("Already handling a signal (maybe handle this case)"); - } + pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) { + let lock = self.inner.lock(); + Process::enter_signal_on(lock, thread, signal); + } + pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result { let mut lock = self.inner.lock(); - let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; - let dst_id = lock.id; - let dst_space_phys = lock.space.as_mut().unwrap().address_phys(); - let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48); + let space_phys = lock.space.as_mut().unwrap().address_phys(); + let ttbr0 = space_phys | ((lock.id.asid() as usize) << 48); - debugln!( - "Signal entry: pc={:#x}, sp={:#x}, ttbr0={:#x}", - lock.signal_entry, - lock.signal_stack, - dst_ttbr0 - ); - assert_eq!(lock.state, State::Running); + let thread = Thread::new_user(lock.id, entry, stack, arg, ttbr0)?; + let tid = thread.id(); + lock.threads.push(tid); + SCHED.enqueue(tid); - unsafe { - signal_ctx.setup_signal_entry( - lock.signal_entry, - signal as usize, - dst_ttbr0, - lock.signal_stack, - ); - } - let src_ctx = self.ctx.get(); - drop(lock); - - unsafe { - (&mut *src_ctx).switch(signal_ctx); - } - } - - /// Sets up values needed for signal entry - pub fn setup_signal_context(&self, entry: usize, stack: usize) { - let mut lock = self.inner.lock(); - lock.signal_entry = entry; - lock.signal_stack = stack; - } - - /// Schedules an initial thread for execution - /// - /// # Safety - /// - /// Unsafe: only allowed to be called once, repeated calls - /// will generate undefined behavior - pub unsafe fn enter(proc: ProcessRef) -> ! { - // FIXME use some global lock to guarantee atomicity of thread entry? - proc.inner.lock().state = State::Running; - proc.current_context().enter() - } - - /// Executes a function allowing mutation of the process address space - #[inline] - pub fn manipulate_space Result<(), Errno>>( - &self, - f: F, - ) -> Result<(), Errno> { - f(self.inner.lock().space.as_mut().unwrap()) - } - - #[allow(clippy::mut_from_ref)] - fn current_context(&self) -> &mut Context { - if self.signal_pending.load(Ordering::Acquire) != 0 { - unsafe { &mut *self.signal_ctx.get() } - } else { - unsafe { &mut *self.ctx.get() } - } - } - - /// Schedules a next thread for execution - /// - /// # Safety - /// - /// Unsafe: - /// - /// * Does not ensure src and dst threads are not the same thread - /// * Does not ensure src is actually current context - pub unsafe fn switch(src: ProcessRef, dst: ProcessRef, discard: bool) { - { - let mut src_lock = src.inner.lock(); - let mut dst_lock = dst.inner.lock(); - - if !discard { - assert_eq!(src_lock.state, State::Running); - src_lock.state = State::Ready; - } - assert!(dst_lock.state == State::Ready || dst_lock.state == State::Waiting); - dst_lock.state = State::Running; - } - - let src_ctx = src.current_context(); - let dst_ctx = dst.current_context(); - - (&mut *src_ctx).switch(&mut *dst_ctx); - } - - /// Suspends current process with a "waiting" status - pub fn enter_wait(&self) { - let drop = { - let mut lock = self.inner.lock(); - let drop = lock.state == State::Running; - lock.state = State::Waiting; - SCHED.dequeue(lock.id); - drop - }; - if drop { - SCHED.switch(true); - } - } - - /// Changes process wait condition status - pub fn set_wait_flag(&self, v: bool) { - self.inner.lock().wait_flag = v; - } - - /// Returns `true` if process wait condition has not been reached - pub fn wait_flag(&self) -> bool { - self.inner.lock().wait_flag - } - - /// Returns the process ID - pub fn id(&self) -> Pid { - self.inner.lock().id - } - - /// Creates a new kernel process - pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result { - let id = new_kernel_pid(); - let res = Rc::new(Self { - ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), - signal_ctx: UnsafeCell::new(Context::empty()), - io: IrqSafeSpinLock::new(ProcessIo::new()), - exit_wait: Wait::new(), - signal_state: AtomicU32::new(0), - signal_pending: AtomicU32::new(0), - inner: IrqSafeSpinLock::new(ProcessInner { - signal_entry: 0, - signal_stack: 0, - id, - exit: None, - space: None, - wait_flag: false, - state: State::Ready, - }), - }); - debugln!("New kernel process: {:?}", id); - assert!(PROCESSES.lock().insert(id, res.clone()).is_none()); - Ok(res) + Ok(tid) } /// Creates a "fork" of the process, cloning its address space and @@ -277,63 +170,73 @@ impl Process { let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET; let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48); + let mut threads = Vec::new(); + let tid = Thread::fork(Some(dst_id), frame, dst_ttbr0)?.id(); + threads.push(tid); + let dst = Rc::new(Self { - ctx: UnsafeCell::new(Context::fork(frame, dst_ttbr0)), - signal_ctx: UnsafeCell::new(Context::empty()), - io: IrqSafeSpinLock::new(src_io.fork()?), exit_wait: Wait::new(), + io: IrqSafeSpinLock::new(src_io.fork()?), signal_state: AtomicU32::new(0), - signal_pending: AtomicU32::new(0), inner: IrqSafeSpinLock::new(ProcessInner { - signal_entry: 0, - signal_stack: 0, - id: dst_id, + threads, exit: None, space: Some(dst_space), - state: State::Ready, - wait_flag: false, + state: ProcessState::Active, + id: dst_id, }), }); + debugln!("Process {:?} forked into {:?}", src_inner.id, dst_id); assert!(PROCESSES.lock().insert(dst_id, dst).is_none()); - SCHED.enqueue(dst_id); + + SCHED.enqueue(tid); Ok(dst_id) } + // TODO a way to terminate a single thread? /// Terminates a process. - pub fn exit>(&self, status: I) { - let status = status.into(); - let drop = { - let mut lock = self.inner.lock(); - let drop = lock.state == State::Running; - infoln!("Process {:?} is exiting: {:?}", lock.id, status); - assert!(lock.exit.is_none()); - lock.exit = Some(status); - lock.state = State::Finished; - - if let Some(space) = lock.space.take() { - unsafe { - Space::release(space); - asm!("tlbi aside1, {}", in(reg) ((lock.id.asid() as usize) << 48)); - } - } - - self.io.lock().handle_exit(); - - SCHED.dequeue(lock.id); - drop - }; - self.exit_wait.wakeup_all(); - if drop { - SCHED.switch(true); - panic!("This code should never run"); + pub fn exit>(status: I) { + unsafe { + asm!("msr daifclr, #0xF"); } + let status = status.into(); + let thread = Thread::current(); + let process = thread.owner().unwrap(); + let mut lock = process.inner.lock(); + + infoln!("Process {:?} is exiting: {:?}", lock.id, status); + assert!(lock.exit.is_none()); + lock.exit = Some(status); + lock.state = ProcessState::Finished; + + for &tid in lock.threads.iter() { + debugln!("Dequeue {:?}", tid); + Thread::get(tid).unwrap().terminate(); + SCHED.dequeue(tid); + } + SCHED.debug(); + + if let Some(space) = lock.space.take() { + unsafe { + Space::release(space); + asm!("tlbi aside1, {}", in(reg) ((lock.id.asid() as usize) << 48)); + } + } + + process.io.lock().handle_exit(); + + drop(lock); + + process.exit_wait.wakeup_all(); + SCHED.switch(true); + panic!("This code should never run"); } fn collect(&self) -> Option { let lock = self.inner.lock(); - if lock.state == State::Finished { + if lock.state == ProcessState::Finished { lock.exit } else { None @@ -370,33 +273,36 @@ impl Process { asm!("msr daifset, #2"); } - let proc = SCHED.current_process(); - let mut lock = proc.inner.lock(); - if lock.id.is_kernel() { - let mut proc_lock = PROCESSES.lock(); - let old_pid = lock.id; - assert!( - proc_lock.remove(&old_pid).is_some(), - "Failed to downgrade kernel process (remove kernel pid)" - ); - lock.id = new_user_pid(); - debugln!( - "Process downgrades from kernel to user: {:?} -> {:?}", - old_pid, - lock.id - ); - assert!(proc_lock.insert(lock.id, proc.clone()).is_none()); - unsafe { - SCHED.hack_current_pid(lock.id); - } + let proc = Process::current(); + let mut process_lock = proc.inner.lock(); + + if process_lock.threads.len() != 1 { + todo!(); + } + + let thread = Thread::get(process_lock.threads[0]).unwrap(); + + if process_lock.id.is_kernel() { + let mut processes = PROCESSES.lock(); + let old_pid = process_lock.id; + let new_pid = new_user_pid(); + debugln!("Downgrading process {:?} -> {:?}", old_pid, new_pid); + + let r = processes.remove(&old_pid); + assert!(r.is_some()); + process_lock.id = new_pid; + let r = processes.insert(new_pid, proc.clone()); + assert!(r.is_none()); } else { // Invalidate user ASID - let input = (lock.id.asid() as usize) << 48; + let input = (process_lock.id.asid() as usize) << 48; unsafe { asm!("tlbi aside1, {}", in(reg) input); } } + thread.set_owner(process_lock.id); + proc.io.lock().handle_cloexec(); let new_space = Space::alloc_empty()?; @@ -419,22 +325,20 @@ impl Process { debugln!("Will now enter at {:#x}", entry); // TODO drop old address space - lock.space = Some(new_space); + process_lock.space = Some(new_space); unsafe { // TODO drop old context - let ctx = proc.ctx.get(); + let ctx = thread.ctx.get(); ctx.write(Context::user( entry, arg, - new_space_phys | ((lock.id.asid() as usize) << 48), + new_space_phys | ((process_lock.id.asid() as usize) << 48), Self::USTACK_VIRT_TOP, )); - assert_eq!(lock.state, State::Running); - - drop(lock); + drop(process_lock); (*ctx).enter(); } diff --git a/kernel/src/proc/sched.rs b/kernel/src/proc/sched.rs index e30282a..28f002e 100644 --- a/kernel/src/proc/sched.rs +++ b/kernel/src/proc/sched.rs @@ -1,13 +1,13 @@ //! -use crate::proc::{Pid, Process, ProcessRef, PROCESSES}; +use crate::proc::{Pid, Process, ProcessRef, Thread, ThreadRef, PROCESSES, THREADS}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use alloc::{collections::VecDeque, rc::Rc}; struct SchedulerInner { - queue: VecDeque, - idle: Option, - current: Option, + queue: VecDeque, + idle: Option, + current: Option, } /// Process scheduler state and queues @@ -23,7 +23,7 @@ impl SchedulerInner { current: None, }; - this.idle = Some(Process::new_kernel(idle_fn, 0).unwrap().id()); + this.idle = Some(Thread::new_kernel(None, idle_fn, 0).unwrap().id()); this } @@ -39,13 +39,21 @@ impl Scheduler { } /// Schedules a thread for execution - pub fn enqueue(&self, pid: Pid) { - self.inner.get().lock().queue.push_back(pid); + pub fn enqueue(&self, tid: u32) { + self.inner.get().lock().queue.push_back(tid); } - /// Removes given `pid` from execution queue - pub fn dequeue(&self, pid: Pid) { - self.inner.get().lock().queue.retain(|&p| p != pid) + /// Removes given `tid` from execution queue + pub fn dequeue(&self, tid: u32) { + self.inner.get().lock().queue.retain(|&p| p != tid) + } + + pub fn debug(&self) { + let lock = self.inner.get().lock(); + debugln!("Scheduler queue:"); + for &tid in lock.queue.iter() { + debugln!("TID: {:?}", tid); + } } /// Performs initial process entry. @@ -63,11 +71,11 @@ impl Scheduler { }; inner.current = Some(id); - PROCESSES.lock().get(&id).unwrap().clone() + THREADS.lock().get(&id).unwrap().clone() }; asm!("msr daifset, #2"); - Process::enter(thread) + Thread::enter(thread) } /// This hack is required to be called from execve() when downgrading current @@ -76,8 +84,14 @@ impl Scheduler { /// # Safety /// /// Unsafe: only allowed to be called from Process::execve() - pub unsafe fn hack_current_pid(&self, new: Pid) { - self.inner.get().lock().current = Some(new); + pub unsafe fn hack_current_tid(&self, old: u32, new: u32) { + let mut lock = self.inner.get().lock(); + match lock.current { + Some(t) if t == old => { + lock.current = Some(new); + } + _ => {} + } } /// Switches to the next task scheduled for execution. If there're @@ -87,7 +101,7 @@ impl Scheduler { let mut inner = self.inner.get().lock(); let current = inner.current.unwrap(); - if !discard && current != Pid::IDLE { + if !discard && current != 0 { // Put the process into the back of the queue inner.queue.push_back(current); } @@ -100,7 +114,7 @@ impl Scheduler { inner.current = Some(next); let (from, to) = { - let lock = PROCESSES.lock(); + let lock = THREADS.lock(); ( lock.get(¤t).unwrap().clone(), lock.get(&next).unwrap().clone(), @@ -113,17 +127,23 @@ impl Scheduler { if !Rc::ptr_eq(&from, &to) { unsafe { asm!("msr daifset, #2"); - Process::switch(from, to, discard); + Thread::switch(from, to, discard); } } } - /// Returns a Rc-reference to currently running process - pub fn current_process(&self) -> ProcessRef { + pub fn current_thread(&self) -> ThreadRef { let inner = self.inner.get().lock(); - let current = inner.current.unwrap(); - PROCESSES.lock().get(¤t).unwrap().clone() + let id = inner.current.unwrap(); + THREADS.lock().get(&id).unwrap().clone() } + + // /// Returns a Rc-reference to currently running process + // pub fn current_process(&self) -> ProcessRef { + // let inner = self.inner.get().lock(); + // let current = inner.current.unwrap(); + // PROCESSES.lock().get(¤t).unwrap().clone() + // } } /// Returns `true` if the scheduler has been initialized diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs new file mode 100644 index 0000000..a8b0a2d --- /dev/null +++ b/kernel/src/proc/thread.rs @@ -0,0 +1,325 @@ +use crate::arch::aarch64::exception::ExceptionFrame; +use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS}; +use crate::sync::IrqSafeSpinLock; +use alloc::{rc::Rc, vec::Vec}; +use core::cell::UnsafeCell; +use core::sync::atomic::{AtomicU32, Ordering}; +use libsys::{error::Errno, proc::Pid, signal::Signal}; + +pub use crate::arch::platform::context::{self, Context}; + +pub type ThreadRef = Rc; + +/// List of possible process states +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum State { + /// Process is ready to be executed and/or is scheduled for it + Ready, + /// Process is currently running or is in system call/interrupt handler + Running, + /// Process has finished execution and is waiting to be reaped + Finished, + /// Process is waiting for some external event + Waiting, +} + +struct ThreadInner { + id: u32, + state: State, + owner: Option, + pending_wait: Option<&'static Wait>, + wait_flag: bool, + signal_entry: usize, + signal_stack: usize, +} + +pub struct Thread { + inner: IrqSafeSpinLock, + pub(super) ctx: UnsafeCell, + signal_ctx: UnsafeCell, + signal_pending: AtomicU32, +} + +impl Thread { + #[inline] + pub fn current() -> ThreadRef { + SCHED.current_thread() + } + + #[inline] + pub fn get(tid: u32) -> Option { + THREADS.lock().get(&tid).cloned() + } + + #[inline] + pub fn owner(&self) -> Option { + self.inner.lock().owner.and_then(Process::get) + } + + /// Creates a new kernel process + pub fn new_kernel( + owner: Option, + entry: extern "C" fn(usize) -> !, + arg: usize, + ) -> Result { + let id = new_tid(); + + let res = Rc::new(Self { + ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), + signal_ctx: UnsafeCell::new(Context::empty()), + signal_pending: AtomicU32::new(0), + inner: IrqSafeSpinLock::new(ThreadInner { + signal_entry: 0, + signal_stack: 0, + id, + owner, + pending_wait: None, + wait_flag: false, + state: State::Ready, + }), + }); + debugln!("New kernel thread: {:?}", id); + assert!(THREADS.lock().insert(id, res.clone()).is_none()); + Ok(res) + } + + /// Creates a new userspace process + pub fn new_user( + owner: Pid, + entry: usize, + stack: usize, + arg: usize, + ttbr0: usize, + ) -> Result { + let id = new_tid(); + + let res = Rc::new(Self { + ctx: UnsafeCell::new(Context::user(entry, arg, ttbr0, stack)), + signal_ctx: UnsafeCell::new(Context::empty()), + signal_pending: AtomicU32::new(0), + inner: IrqSafeSpinLock::new(ThreadInner { + signal_entry: 0, + signal_stack: 0, + id, + owner: Some(owner), + pending_wait: None, + wait_flag: false, + state: State::Ready, + }), + }); + debugln!("New userspace thread: {:?}", id); + assert!(THREADS.lock().insert(id, res.clone()).is_none()); + Ok(res) + } + + pub fn fork( + owner: Option, + frame: &ExceptionFrame, + ttbr0: usize, + ) -> Result { + let id = new_tid(); + + let res = Rc::new(Self { + ctx: UnsafeCell::new(Context::fork(frame, ttbr0)), + signal_ctx: UnsafeCell::new(Context::empty()), + signal_pending: AtomicU32::new(0), + inner: IrqSafeSpinLock::new(ThreadInner { + signal_entry: 0, + signal_stack: 0, + id, + owner, + pending_wait: None, + wait_flag: false, + state: State::Ready, + }), + }); + debugln!("Forked new user thread: {:?}", id); + assert!(THREADS.lock().insert(id, res.clone()).is_none()); + Ok(res) + } + + #[inline] + pub fn id(&self) -> u32 { + self.inner.lock().id + } + + /// Schedules an initial thread for execution + /// + /// # Safety + /// + /// Unsafe: only allowed to be called once, repeated calls + /// will generate undefined behavior + pub unsafe fn enter(thread: ThreadRef) -> ! { + // FIXME use some global lock to guarantee atomicity of thread entry? + thread.inner.lock().state = State::Running; + thread.current_context().enter() + } + + /// Schedules a next thread for execution + /// + /// # Safety + /// + /// Unsafe: + /// + /// * Does not ensure src and dst threads are not the same thread + /// * Does not ensure src is actually current context + pub unsafe fn switch(src: ThreadRef, dst: ThreadRef, discard: bool) { + { + let mut src_lock = src.inner.lock(); + let mut dst_lock = dst.inner.lock(); + + if !discard { + assert_eq!(src_lock.state, State::Running); + src_lock.state = State::Ready; + } + assert!(dst_lock.state == State::Ready || dst_lock.state == State::Waiting); + dst_lock.state = State::Running; + } + + let src_ctx = src.current_context(); + let dst_ctx = dst.current_context(); + + (&mut *src_ctx).switch(&mut *dst_ctx); + } + + #[allow(clippy::mut_from_ref)] + fn current_context(&self) -> &mut Context { + if self.signal_pending.load(Ordering::Acquire) != 0 { + unsafe { &mut *self.signal_ctx.get() } + } else { + unsafe { &mut *self.ctx.get() } + } + } + + /// Suspends current process with a "waiting" status + pub fn enter_wait(&self) { + let drop = { + let mut lock = self.inner.lock(); + let drop = lock.state == State::Running; + lock.state = State::Waiting; + SCHED.dequeue(lock.id); + drop + }; + if drop { + SCHED.switch(true); + } + } + + /// Changes process wait condition status + pub fn setup_wait(&self, wait: *const Wait) { + let mut lock = self.inner.lock(); + // FIXME this is not cool + lock.pending_wait = Some(unsafe { &*wait }); + lock.wait_flag = true; + } + + pub fn set_wait_reached(&self) { + let mut lock = self.inner.lock(); + lock.wait_flag = false; + } + + pub fn reset_wait(&self) { + let mut lock = self.inner.lock(); + lock.pending_wait = None; + } + + /// Returns `true` if process wait condition has not been reached + pub fn wait_flag(&self) -> bool { + self.inner.lock().wait_flag + } + + /// Switches current thread back from signal handler + pub fn return_from_signal(&self) { + if self.signal_pending.load(Ordering::Acquire) == 0 { + panic!("TODO handle cases when returning from no signal"); + } + self.signal_pending.store(0, Ordering::Release); + + let src_ctx = self.signal_ctx.get(); + let dst_ctx = self.ctx.get(); + + assert_eq!(self.inner.lock().state, State::Running); + + unsafe { + (&mut *src_ctx).switch(&mut *dst_ctx); + } + } + + #[inline] + pub fn state(&self) -> State { + self.inner.lock().state + } + + pub fn set_owner(&self, pid: Pid) { + self.inner.lock().owner = Some(pid); + } + + /// Sets up values needed for signal entry + pub fn set_signal_entry(&self, entry: usize, stack: usize) { + let mut lock = self.inner.lock(); + lock.signal_entry = entry; + lock.signal_stack = stack; + } + + /// Switches process main thread to a signal handler + pub fn enter_signal(&self, signal: Signal, ttbr0: usize) { + if self + .signal_pending + .compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed) + .is_err() + { + panic!("Already handling a signal (maybe handle this case)"); + } + + let mut lock = self.inner.lock(); + if lock.signal_entry == 0 || lock.signal_stack == 0 { + todo!(); + } + + let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; + let src_ctx = self.ctx.get(); + + debugln!( + "Signal entry: tid={}, pc={:#x}, sp={:#x}, ttbr0={:#x}", + lock.id, + lock.signal_entry, + lock.signal_stack, + ttbr0 + ); + assert_eq!(lock.state, State::Running); + + unsafe { + signal_ctx.setup_signal_entry(lock.signal_entry, signal as usize, ttbr0, lock.signal_stack); + } + + drop(lock); + + unsafe { + (&mut *src_ctx).switch(signal_ctx); + } + } + + pub fn terminate(&self) { + let mut lock = self.inner.lock(); + lock.state = State::Finished; + let tid = lock.id; + let wait = lock.pending_wait.take(); + drop(lock); + if let Some(wait) = wait { + wait.abort(tid); + } + } +} + +impl Drop for Thread { + fn drop(&mut self) { + debugln!("Dropping process {:?}", self.id()); + } +} + +pub fn new_tid() -> u32 { + static LAST: AtomicU32 = AtomicU32::new(1); + let id = LAST.fetch_add(1, Ordering::Relaxed); + assert!(id < 256, "Out of user TIDs"); + id +} diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index 1869e70..2d21c8e 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -2,7 +2,7 @@ use crate::arch::machine; use crate::dev::timer::TimestampSource; -use crate::proc::{self, sched::SCHED, Process, ProcessRef}; +use crate::proc::{self, sched::SCHED, Process, Thread, ThreadRef}; use crate::sync::IrqSafeSpinLock; use alloc::collections::LinkedList; use core::time::Duration; @@ -11,11 +11,11 @@ use libsys::{error::Errno, stat::FdSet, proc::Pid}; /// Wait channel structure. Contains a queue of processes /// waiting for some event to happen. pub struct Wait { - queue: IrqSafeSpinLock>, + queue: IrqSafeSpinLock>, } struct Timeout { - pid: Pid, + tid: u32, deadline: Duration, } @@ -30,9 +30,9 @@ pub fn tick() { while let Some(item) = cursor.current() { if time > item.deadline { - let pid = item.pid; + let tid = item.tid; cursor.remove_current(); - SCHED.enqueue(pid); + SCHED.enqueue(tid); } else { cursor.move_next(); } @@ -56,50 +56,51 @@ pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> { } pub fn select( - proc: ProcessRef, + thread: ThreadRef, mut rfds: Option<&mut FdSet>, mut wfds: Option<&mut FdSet>, timeout: Option, ) -> Result { - // TODO support wfds - if wfds.is_some() || rfds.is_none() { - todo!(); - } - let read = rfds.as_deref().map(FdSet::clone); - let write = wfds.as_deref().map(FdSet::clone); - rfds.as_deref_mut().map(FdSet::reset); - wfds.as_deref_mut().map(FdSet::reset); + todo!(); + // // TODO support wfds + // if wfds.is_some() || rfds.is_none() { + // todo!(); + // } + // let read = rfds.as_deref().map(FdSet::clone); + // let write = wfds.as_deref().map(FdSet::clone); + // rfds.as_deref_mut().map(FdSet::reset); + // wfds.as_deref_mut().map(FdSet::reset); - let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap()); - let mut io = proc.io.lock(); + // let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap()); + // let mut io = proc.io.lock(); - loop { - if let Some(read) = &read { - for fd in read.iter() { - let file = io.file(fd)?; - if file.borrow().is_ready(false)? { - rfds.as_mut().unwrap().set(fd); - return Ok(1); - } - } - } - if let Some(write) = &write { - for fd in write.iter() { - let file = io.file(fd)?; - if file.borrow().is_ready(true)? { - wfds.as_mut().unwrap().set(fd); - return Ok(1); - } - } - } + // loop { + // if let Some(read) = &read { + // for fd in read.iter() { + // let file = io.file(fd)?; + // if file.borrow().is_ready(false)? { + // rfds.as_mut().unwrap().set(fd); + // return Ok(1); + // } + // } + // } + // if let Some(write) = &write { + // for fd in write.iter() { + // let file = io.file(fd)?; + // if file.borrow().is_ready(true)? { + // wfds.as_mut().unwrap().set(fd); + // return Ok(1); + // } + // } + // } - // Suspend - match WAIT_SELECT.wait(deadline) { - Err(Errno::TimedOut) => return Ok(0), - Err(e) => return Err(e), - Ok(_) => {} - } - } + // // Suspend + // match WAIT_SELECT.wait(deadline) { + // Err(Errno::TimedOut) => return Ok(0), + // Err(e) => return Err(e), + // Ok(_) => {} + // } + // } } impl Wait { @@ -115,12 +116,12 @@ impl Wait { let mut queue = self.queue.lock(); let mut count = 0; while limit != 0 && !queue.is_empty() { - let pid = queue.pop_front(); - if let Some(pid) = pid { + let tid = queue.pop_front(); + if let Some(tid) = tid { let mut tick_lock = TICK_LIST.lock(); let mut cursor = tick_lock.cursor_front_mut(); while let Some(item) = cursor.current() { - if pid == item.pid { + if tid == item.tid { cursor.remove_current(); break; } else { @@ -129,8 +130,8 @@ impl Wait { } drop(tick_lock); - proc::process(pid).set_wait_flag(false); - SCHED.enqueue(pid); + Thread::get(tid).unwrap().set_wait_reached(); + SCHED.enqueue(tid); } limit -= 1; @@ -149,29 +150,54 @@ impl Wait { self.wakeup_some(1); } + pub fn abort(&self, tid: u32) { + let mut queue = self.queue.lock(); + let mut tick_lock = TICK_LIST.lock(); + let mut cursor = tick_lock.cursor_front_mut(); + while let Some(item) = cursor.current() { + if tid == item.tid { + cursor.remove_current(); + break; + } else { + cursor.move_next(); + } + } + + let mut cursor = queue.cursor_front_mut(); + while let Some(item) = cursor.current() { + if tid == *item { + cursor.remove_current(); + break; + } else { + cursor.move_next(); + } + } + } + /// Suspends current process until event is signalled or /// (optional) deadline is reached pub fn wait(&self, deadline: Option) -> Result<(), Errno> { - let proc = Process::current(); + let thread = Thread::current(); //let deadline = timeout.map(|t| machine::local_timer().timestamp().unwrap() + t); let mut queue_lock = self.queue.lock(); - queue_lock.push_back(proc.id()); - proc.set_wait_flag(true); + queue_lock.push_back(thread.id()); + thread.setup_wait(self); + if let Some(deadline) = deadline { TICK_LIST.lock().push_back(Timeout { - pid: proc.id(), + tid: thread.id(), deadline, }); } loop { - if !proc.wait_flag() { + if !thread.wait_flag() { return Ok(()); } drop(queue_lock); - proc.enter_wait(); + thread.enter_wait(); queue_lock = self.queue.lock(); if let Some(deadline) = deadline { @@ -179,7 +205,7 @@ impl Wait { let mut cursor = queue_lock.cursor_front_mut(); while let Some(&mut item) = cursor.current() { - if proc.id() == item { + if thread.id() == item { cursor.remove_current(); break; } else { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 5e6edbc..c58c416 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -2,7 +2,7 @@ use crate::arch::platform::exception::ExceptionFrame; use crate::debug::Level; -use crate::proc::{elf, wait, Process, ProcessIo}; +use crate::proc::{self, elf, wait, Process, ProcessIo, Thread}; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; @@ -55,7 +55,7 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { match num { // Process management system calls abi::SYS_EXIT => { - Process::current().exit(args[0] as i32); + Process::exit(args[0] as i32); unreachable!(); } @@ -174,13 +174,11 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { res.map(|_| 0) } abi::SYS_EX_SIGNAL => { - let proc = Process::current(); - proc.setup_signal_context(args[0], args[1]); + Thread::current().set_signal_entry(args[0], args[1]); Ok(0) } abi::SYS_EX_SIGRETURN => { - let proc = Process::current(); - proc.return_from_signal(); + Thread::current().return_from_signal(); panic!("This code won't run"); } abi::SYS_EX_KILL => { @@ -196,6 +194,19 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { }; Ok(0) } + abi::SYS_EX_CLONE => { + let entry = args[0]; + let stack = args[1]; + let arg = args[2]; + + Process::current() + .new_user_thread(entry, stack, arg) + .map(|e| e as usize) + } + abi::SYS_EX_YIELD => { + proc::switch(); + Ok(0) + }, abi::SYS_SELECT => { let rfds = validate_user_ptr_struct_option::(args[0])?; @@ -206,15 +217,15 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { Some(Duration::from_nanos(args[2] as u64)) }; - let proc = Process::current(); - wait::select(proc, rfds, wfds, timeout) + wait::select(Thread::current(), rfds, wfds, timeout) } _ => { - let proc = Process::current(); + let thread = Thread::current(); + let proc = thread.owner().unwrap(); errorln!("Undefined system call: {}", num); - proc.enter_signal(Signal::InvalidSystemCall); - todo!() + proc.enter_fault_signal(thread, Signal::InvalidSystemCall); + Err(Errno::InvalidArgument) } } } diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 5035906..4f1ff3d 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -4,6 +4,8 @@ pub const SYS_EX_NANOSLEEP: usize = 129; pub const SYS_EX_SIGNAL: usize = 130; pub const SYS_EX_SIGRETURN: usize = 131; pub const SYS_EX_KILL: usize = 132; +pub const SYS_EX_CLONE: usize = 133; +pub const SYS_EX_YIELD: usize = 134; pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index b2ece93..e506be4 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -271,6 +271,32 @@ pub fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> Result<(), Errno> }) } +#[inline(always)] +pub fn sys_ex_clone(entry: usize, stack: usize, arg: usize) -> Result { + Errno::from_syscall(unsafe { + syscall!( + abi::SYS_EX_CLONE, + argn!(entry), + argn!(stack), + argn!(arg) + ) + }) +} + +#[inline(always)] +pub fn sys_ex_yield() { + unsafe { + syscall!(abi::SYS_EX_YIELD); + } +} + +#[inline(always)] +pub fn sys_ex_undefined() { + unsafe { + syscall!(0); + } +} + #[inline(always)] pub fn sys_select( read_fds: Option<&mut FdSet>, diff --git a/libsys/src/error.rs b/libsys/src/error.rs index 3f42bf4..450358f 100644 --- a/libsys/src/error.rs +++ b/libsys/src/error.rs @@ -47,6 +47,6 @@ impl Errno { impl From for Errno { fn from(u: usize) -> Errno { - todo!() + unsafe { core::mem::transmute(u as u32) } } } diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index f85f49a..b973998 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -13,9 +13,16 @@ pub mod os; pub mod sys; pub mod sync; +use sys::Signal; + #[inline(never)] -extern "C" fn _signal_handler(arg: sys::Signal) -> ! { +extern "C" fn _signal_handler(arg: Signal) -> ! { trace!("Entered signal handler: arg={:?}", arg); + match arg { + Signal::Interrupt | Signal::SegmentationFault => + loop {}, + _ => todo!() + } sys::sys_ex_sigreturn(); } diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs index af55f54..749c809 100644 --- a/libusr/src/sys/mod.rs +++ b/libusr/src/sys/mod.rs @@ -1,4 +1,5 @@ pub use libsys::signal::{Signal, SignalDestination}; +pub use libsys::proc::ExitCode; pub use libsys::termios; pub use libsys::calls::*; pub use libsys::stat::{self, FileDescriptor}; @@ -28,7 +29,7 @@ impl RawMutex { #[inline] pub unsafe fn lock(&self) { while !self.try_lock() { - asm!("nop"); + sys_ex_yield(); } } diff --git a/user/Cargo.toml b/user/Cargo.toml index 2b8da15..9196443 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -15,3 +15,4 @@ path = "src/shell/main.rs" [dependencies] libusr = { path = "../libusr" } +lazy_static = { version = "*", features = ["spin_no_std"] } diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index d6044a1..970ba36 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -3,24 +3,67 @@ #[macro_use] extern crate libusr; +#[macro_use] +extern crate lazy_static; use libusr::io::{self, Read}; +use libusr::sys::{Signal, SignalDestination}; +use libusr::sync::Mutex; + +static mut THREAD_STACK: [u8; 8192] = [0; 8192]; +static mut THREAD_SIGNAL_STACK: [u8; 8192] = [0; 8192]; +lazy_static! { + static ref MUTEX: Mutex<()> = Mutex::new(()); +} + +fn sleep(ns: u64) { + let mut rem = [0; 2]; + libusr::sys::sys_ex_nanosleep(ns, &mut rem).unwrap(); +} + +fn fn0_signal(arg: Signal) { + trace!("fn0_signal"); + unsafe { + libusr::sys::sys_exit(libusr::sys::ExitCode::from(0)); + } +} + +fn fn0(_arg: usize) { + unsafe { + libusr::sys::sys_ex_signal(fn0_signal as usize, THREAD_SIGNAL_STACK.as_mut_ptr().add(8192) as usize); + } + + unsafe { + core::ptr::read_volatile(0x1234 as *const u32); + } + loop {} + //loop { + // sleep(100_000_000); + // println!("Tick from B"); + // { + // let lock = MUTEX.lock(); + // sleep(1_000_000_000); + // } + //} +} + +fn do_fault() { + unsafe { + core::ptr::read_volatile(0x1238 as *const u32); + } +} #[no_mangle] fn main() -> i32 { - let mut buf = [0; 512]; - let mut stdin = io::stdin(); - - eprintln!("stderr test"); - - loop { - let count = stdin.read(&mut buf).unwrap(); - if count == 0 { - break; - } - let line = core::str::from_utf8(&buf[..count]).unwrap(); - println!("{:?}", line); + unsafe { + libusr::sys::sys_ex_clone(fn0 as usize, THREAD_STACK.as_mut_ptr().add(8192) as usize, 0); } + sleep(1_000_000_000); + + do_fault(); + + loop {} + 0 } From d582a9b58bf210792a1319652e793a2607fd3b08 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 19 Nov 2021 16:14:13 +0200 Subject: [PATCH 20/42] feature: spawn for closures --- kernel/src/proc/process.rs | 32 ++++++++++++++++ kernel/src/syscall/mod.rs | 4 ++ libsys/src/abi.rs | 1 + libsys/src/calls.rs | 8 ++++ libusr/src/allocator.rs | 36 ++++++++++++++++++ libusr/src/lib.rs | 6 ++- libusr/src/thread.rs | 77 ++++++++++++++++++++++++++++++++++++++ user/src/shell/main.rs | 51 ++++--------------------- 8 files changed, 171 insertions(+), 44 deletions(-) create mode 100644 libusr/src/allocator.rs create mode 100644 libusr/src/thread.rs diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 7506853..27fac7a 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -234,6 +234,38 @@ impl Process { panic!("This code should never run"); } + pub fn exit_thread(thread: ThreadRef) { + let switch = { + let switch = thread.state() == ThreadState::Running; + let process = thread.owner().unwrap(); + let mut lock = process.inner.lock(); + let tid = thread.id(); + + if lock.threads.len() == 1 { + // TODO call Process::exit instead? + todo!(); + } + + lock.threads.retain(|&e| e != tid); + + thread.terminate(); + SCHED.dequeue(tid); + debugln!("Thread {} terminated", tid); + + switch + }; + + if switch { + // TODO retain thread ID in process "finished" list and + // drop it when process finishes + SCHED.switch(true); + panic!("This code should not run"); + } else { + // Can drop this thread: it's not running + todo!(); + } + } + fn collect(&self) -> Option { let lock = self.inner.lock(); if lock.state == ProcessState::Finished { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c58c416..e3d2818 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -58,6 +58,10 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { Process::exit(args[0] as i32); unreachable!(); } + abi::SYS_EX_THREAD_EXIT => { + Process::exit_thread(Thread::current()); + unreachable!(); + }, // I/O system calls abi::SYS_OPENAT => { diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 4f1ff3d..ff16f06 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -6,6 +6,7 @@ pub const SYS_EX_SIGRETURN: usize = 131; pub const SYS_EX_KILL: usize = 132; pub const SYS_EX_CLONE: usize = 133; pub const SYS_EX_YIELD: usize = 134; +pub const SYS_EX_THREAD_EXIT: usize = 135; pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index e506be4..ebbe22a 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -283,6 +283,14 @@ pub fn sys_ex_clone(entry: usize, stack: usize, arg: usize) -> Result ! { + unsafe { + syscall!(abi::SYS_EX_THREAD_EXIT, argn!(i32::from(status))); + } + unreachable!(); +} + #[inline(always)] pub fn sys_ex_yield() { unsafe { diff --git a/libusr/src/allocator.rs b/libusr/src/allocator.rs new file mode 100644 index 0000000..7976520 --- /dev/null +++ b/libusr/src/allocator.rs @@ -0,0 +1,36 @@ +use core::alloc::{Layout, GlobalAlloc}; +use core::sync::atomic::{AtomicUsize, Ordering}; +use libsys::mem::memset; + +use crate::trace; + +struct Allocator; + +static mut ALLOC_DATA: [u8; 65536] = [0; 65536]; +static ALLOC_PTR: AtomicUsize = AtomicUsize::new(0); + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + assert!(layout.align() < 16); + let res = ALLOC_PTR.fetch_add((layout.size() + 15) & !15, Ordering::SeqCst); + if res > 65536 { + panic!("Out of memory"); + } + trace!("alloc({:?}) = {:p}", layout, &ALLOC_DATA[res]); + let res = &mut ALLOC_DATA[res] as *mut _; + memset(res, 0, layout.size()); + res + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + trace!("free({:p}, {:?})", ptr, layout); + } +} + +#[alloc_error_handler] +fn alloc_error_handler(_layout: Layout) -> ! { + loop {} +} + +#[global_allocator] +static ALLOC: Allocator = Allocator; diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index b973998..e14a47f 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -7,16 +7,20 @@ use libsys::proc::ExitCode; #[macro_use] extern crate lazy_static; +extern crate alloc; + +mod allocator; pub mod file; pub mod io; pub mod os; pub mod sys; pub mod sync; +pub mod thread; use sys::Signal; #[inline(never)] -extern "C" fn _signal_handler(arg: Signal) -> ! { +pub(crate) extern "C" fn _signal_handler(arg: Signal) -> ! { trace!("Entered signal handler: arg={:?}", arg); match arg { Signal::Interrupt | Signal::SegmentationFault => diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs new file mode 100644 index 0000000..4792275 --- /dev/null +++ b/libusr/src/thread.rs @@ -0,0 +1,77 @@ +use alloc::boxed::Box; +use alloc::vec; +use core::cell::UnsafeCell; +use core::marker::PhantomData; +use libsys::{ + calls::{sys_ex_clone, sys_ex_thread_exit, sys_ex_signal}, + error::Errno, + proc::ExitCode, +}; + +use crate::trace; + +struct NativeData +where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, +{ + closure: F, + stack: usize, +} + +pub struct JoinHandle { + native: u32, + _pd: PhantomData, +} + +pub fn spawn(f: F) -> JoinHandle +where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, +{ + let stack = vec![0u8; 8192].leak(); + + #[inline(never)] + extern "C" fn thread_entry(data: *mut NativeData) -> ! + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + let (stack, len) = { + // Setup signal handling + let mut signal_stack = vec![0u8; 8192]; + + unsafe { + sys_ex_signal( + crate::_signal_handler as usize, + signal_stack.as_mut_ptr() as usize + signal_stack.len(), + ) + .unwrap(); + } + + let data: Box> = unsafe { Box::from_raw(data) }; + + let res = (data.closure)(); + + (data.stack, 8192) + }; + + // TODO free stack + sys_ex_thread_exit(ExitCode::from(0)); + } + + let native = unsafe { + let stack = stack.as_mut_ptr() as usize + stack.len(); + let data: *mut NativeData = Box::into_raw(Box::new(NativeData { closure: f, stack })); + + sys_ex_clone(thread_entry:: as usize, stack, data as usize).unwrap() as u32 + }; + + JoinHandle { + native, + _pd: PhantomData, + } +} diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 970ba36..1c32add 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -6,62 +6,27 @@ extern crate libusr; #[macro_use] extern crate lazy_static; +use libusr::thread; use libusr::io::{self, Read}; use libusr::sys::{Signal, SignalDestination}; use libusr::sync::Mutex; -static mut THREAD_STACK: [u8; 8192] = [0; 8192]; -static mut THREAD_SIGNAL_STACK: [u8; 8192] = [0; 8192]; -lazy_static! { - static ref MUTEX: Mutex<()> = Mutex::new(()); -} - fn sleep(ns: u64) { let mut rem = [0; 2]; libusr::sys::sys_ex_nanosleep(ns, &mut rem).unwrap(); } -fn fn0_signal(arg: Signal) { - trace!("fn0_signal"); - unsafe { - libusr::sys::sys_exit(libusr::sys::ExitCode::from(0)); - } -} - -fn fn0(_arg: usize) { - unsafe { - libusr::sys::sys_ex_signal(fn0_signal as usize, THREAD_SIGNAL_STACK.as_mut_ptr().add(8192) as usize); - } - - unsafe { - core::ptr::read_volatile(0x1234 as *const u32); - } - loop {} - //loop { - // sleep(100_000_000); - // println!("Tick from B"); - // { - // let lock = MUTEX.lock(); - // sleep(1_000_000_000); - // } - //} -} - -fn do_fault() { - unsafe { - core::ptr::read_volatile(0x1238 as *const u32); - } -} - #[no_mangle] fn main() -> i32 { - unsafe { - libusr::sys::sys_ex_clone(fn0 as usize, THREAD_STACK.as_mut_ptr().add(8192) as usize, 0); - } - + let value = 1234; + let thread = thread::spawn(move || { + trace!("Closure is alive: {}", value); + sleep(2_000_000_000); + trace!("Closure will now exit"); + }); sleep(1_000_000_000); - do_fault(); + trace!("???"); loop {} From 87c13d392030688cd00e5062ce0f36af39868e77 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 19 Nov 2021 16:38:38 +0200 Subject: [PATCH 21/42] feature: thread join() with exit value --- kernel/src/proc/thread.rs | 22 ++++++++++++++++++++++ kernel/src/syscall/mod.rs | 10 ++++++++++ libsys/src/abi.rs | 1 + libsys/src/calls.rs | 13 +++++++------ libusr/src/lib.rs | 1 + libusr/src/thread.rs | 38 +++++++++++++++++++++++++++----------- user/src/shell/main.rs | 4 +++- 7 files changed, 71 insertions(+), 18 deletions(-) diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index a8b0a2d..2c7d786 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -35,6 +35,7 @@ struct ThreadInner { pub struct Thread { inner: IrqSafeSpinLock, + exit_wait: Wait, pub(super) ctx: UnsafeCell, signal_ctx: UnsafeCell, signal_pending: AtomicU32, @@ -68,6 +69,7 @@ impl Thread { ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), + exit_wait: Wait::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -97,6 +99,7 @@ impl Thread { ctx: UnsafeCell::new(Context::user(entry, arg, ttbr0, stack)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), + exit_wait: Wait::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -123,6 +126,7 @@ impl Thread { ctx: UnsafeCell::new(Context::fork(frame, ttbr0)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), + exit_wait: Wait::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -213,6 +217,23 @@ impl Thread { lock.wait_flag = true; } + pub fn waittid(tid: u32) -> Result<(), Errno> { + loop { + let thread = THREADS + .lock() + .get(&tid) + .cloned() + .ok_or(Errno::DoesNotExist)?; + + if thread.state() == State::Finished { + // TODO remove thread from its parent? + return Ok(()); + } + + thread.exit_wait.wait(None)?; + } + } + pub fn set_wait_reached(&self) { let mut lock = self.inner.lock(); lock.wait_flag = false; @@ -308,6 +329,7 @@ impl Thread { if let Some(wait) = wait { wait.abort(tid); } + self.exit_wait.wakeup_all(); } } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index e3d2818..9a5f701 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -144,6 +144,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { _ => todo!(), } } + abi::SYS_EX_THREAD_WAIT => { + let tid = args[0] as u32; + + match Thread::waittid(tid) { + Ok(_) => { + Ok(0) + }, + _ => todo!(), + } + }, abi::SYS_IOCTL => { let fd = FileDescriptor::from(args[0] as u32); let cmd = IoctlCmd::try_from(args[1] as u32)?; diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index ff16f06..e5183b8 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -7,6 +7,7 @@ pub const SYS_EX_KILL: usize = 132; pub const SYS_EX_CLONE: usize = 133; pub const SYS_EX_YIELD: usize = 134; pub const SYS_EX_THREAD_EXIT: usize = 135; +pub const SYS_EX_THREAD_WAIT: usize = 136; pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index ebbe22a..96de914 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -274,12 +274,7 @@ pub fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> Result<(), Errno> #[inline(always)] pub fn sys_ex_clone(entry: usize, stack: usize, arg: usize) -> Result { Errno::from_syscall(unsafe { - syscall!( - abi::SYS_EX_CLONE, - argn!(entry), - argn!(stack), - argn!(arg) - ) + syscall!(abi::SYS_EX_CLONE, argn!(entry), argn!(stack), argn!(arg)) }) } @@ -291,6 +286,12 @@ pub fn sys_ex_thread_exit(status: ExitCode) -> ! { unreachable!(); } +#[inline(always)] +pub fn sys_ex_thread_wait(tid: u32) -> Result { + Errno::from_syscall(unsafe { syscall!(abi::SYS_EX_THREAD_WAIT, argn!(tid)) }) + .map(|_| ExitCode::from(0)) +} + #[inline(always)] pub fn sys_ex_yield() { unsafe { diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index e14a47f..c967fb3 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -53,6 +53,7 @@ extern "C" fn _start(_arg: usize) -> ! { #[panic_handler] fn panic_handler(pi: &PanicInfo) -> ! { + // TODO handle non-main thread panics // TODO print to stdout/stderr (if available) trace!("Panic ocurred: {}", pi); sys::sys_exit(ExitCode::from(-1)); diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs index 4792275..f521ce0 100644 --- a/libusr/src/thread.rs +++ b/libusr/src/thread.rs @@ -1,9 +1,8 @@ -use alloc::boxed::Box; -use alloc::vec; +use alloc::{boxed::Box, sync::Arc, vec}; use core::cell::UnsafeCell; -use core::marker::PhantomData; +use core::mem::MaybeUninit; use libsys::{ - calls::{sys_ex_clone, sys_ex_thread_exit, sys_ex_signal}, + calls::{sys_ex_clone, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait}, error::Errno, proc::ExitCode, }; @@ -17,12 +16,24 @@ where T: Send + 'static, { closure: F, + result: Arc>>, stack: usize, } pub struct JoinHandle { native: u32, - _pd: PhantomData, + result: Arc>>, +} + +impl JoinHandle { + pub fn join(self) -> Result { + sys_ex_thread_wait(self.native).unwrap(); + if let Ok(result) = Arc::try_unwrap(self.result) { + Ok(unsafe { result.into_inner().assume_init() }) + } else { + Err(()) + } + } } pub fn spawn(f: F) -> JoinHandle @@ -32,6 +43,7 @@ where T: Send + 'static, { let stack = vec![0u8; 8192].leak(); + let result = Arc::new(UnsafeCell::new(MaybeUninit::uninit())); #[inline(never)] extern "C" fn thread_entry(data: *mut NativeData) -> ! @@ -53,9 +65,12 @@ where } let data: Box> = unsafe { Box::from_raw(data) }; - let res = (data.closure)(); + unsafe { + (&mut *data.result.get()).write(res); + } + (data.stack, 8192) }; @@ -65,13 +80,14 @@ where let native = unsafe { let stack = stack.as_mut_ptr() as usize + stack.len(); - let data: *mut NativeData = Box::into_raw(Box::new(NativeData { closure: f, stack })); + let data: *mut NativeData = Box::into_raw(Box::new(NativeData { + closure: f, + stack, + result: result.clone(), + })); sys_ex_clone(thread_entry:: as usize, stack, data as usize).unwrap() as u32 }; - JoinHandle { - native, - _pd: PhantomData, - } + JoinHandle { native, result } } diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 1c32add..2c5f85f 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -23,12 +23,14 @@ fn main() -> i32 { trace!("Closure is alive: {}", value); sleep(2_000_000_000); trace!("Closure will now exit"); + + value - 100 }); sleep(1_000_000_000); trace!("???"); - loop {} + trace!("Thread joined: {:?}", thread.join()); 0 } From 6eac5287a206a4ac1ebe7f25d6308fe3663e66d1 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sat, 20 Nov 2021 13:54:06 +0200 Subject: [PATCH 22/42] feature: shell exec --- Makefile | 1 + fs/memfs/src/lib.rs | 13 +++++--- fs/memfs/src/tar.rs | 6 +++- fs/vfs/src/node.rs | 43 ++++++++++++++++++++++++-- kernel/src/proc/process.rs | 4 ++- kernel/src/proc/thread.rs | 6 ++-- kernel/src/syscall/mod.rs | 14 ++++++++- libsys/src/abi.rs | 1 + libsys/src/calls.rs | 21 ++++++++++++- libsys/src/error.rs | 1 + libsys/src/stat.rs | 9 ++++++ libusr/src/sys/mod.rs | 3 +- user/Cargo.toml | 4 +++ user/src/fuzzy/main.rs | 10 ++++++ user/src/shell/main.rs | 62 ++++++++++++++++++++++++++------------ 15 files changed, 164 insertions(+), 34 deletions(-) create mode 100644 user/src/fuzzy/main.rs diff --git a/Makefile b/Makefile index d0d3afa..bbfd889 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,7 @@ initrd: mkdir -p $(O)/rootfs/bin cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin + cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"` ifeq ($(MACH),orangepi3) $(MKIMAGE) \ diff --git a/fs/memfs/src/lib.rs b/fs/memfs/src/lib.rs index 2e4a1b5..04be460 100644 --- a/fs/memfs/src/lib.rs +++ b/fs/memfs/src/lib.rs @@ -29,7 +29,7 @@ pub use block::{BlockAllocator, BlockRef}; mod bvec; use bvec::Bvec; mod tar; -use tar::TarIterator; +use tar::{TarIterator, Tar}; mod file; use file::FileInode; mod dir; @@ -67,8 +67,10 @@ impl Ramfs { Ok(res) } - fn create_node_initial(self: Rc, name: &str, kind: VnodeKind) -> VnodeRef { + fn create_node_initial(self: Rc, name: &str, tar: &Tar) -> VnodeRef { + let kind = tar.node_kind(); let node = Vnode::new(name, kind, Vnode::SEEKABLE); + node.props_mut().mode = tar.mode(); node.set_fs(self.clone()); match kind { VnodeKind::Directory => node.set_data(Box::new(DirInode::new(self.alloc))), @@ -111,7 +113,10 @@ impl Ramfs { } unsafe fn load_tar(self: Rc, base: *const u8, size: usize) -> Result { - let root = self.clone().create_node_initial("", VnodeKind::Directory); + let root = Vnode::new("", VnodeKind::Directory, Vnode::SEEKABLE); + root.set_fs(self.clone()); + root.set_data(Box::new(DirInode::new(self.alloc))); + root.props_mut().mode = FileMode::default_dir(); // 1. Create all the paths in TAR for block in TarIterator::new(base, base.add(size)) { @@ -120,7 +125,7 @@ impl Ramfs { let parent = self.clone().make_path(root.clone(), dirname, true)?; let node = self .clone() - .create_node_initial(basename, block.node_kind()); + .create_node_initial(basename, block); assert_eq!(node.kind(), block.node_kind()); parent.attach(node); } diff --git a/fs/memfs/src/tar.rs b/fs/memfs/src/tar.rs index 4f4984c..2211f65 100644 --- a/fs/memfs/src/tar.rs +++ b/fs/memfs/src/tar.rs @@ -1,4 +1,4 @@ -use libsys::error::Errno; +use libsys::{error::Errno, stat::FileMode}; use vfs::VnodeKind; #[repr(packed)] @@ -81,6 +81,10 @@ impl Tar { } } + pub fn mode(&self) -> FileMode { + FileMode::from_bits(from_octal(&self.mode) as u32).unwrap() + } + pub fn data(&self) -> &[u8] { unsafe { core::slice::from_raw_parts( diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index ad86b2f..8ff2185 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -1,11 +1,11 @@ -use crate::{File, FileRef, Filesystem}; +use crate::{Ioctx, File, FileRef, Filesystem}; use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec}; use core::cell::{RefCell, RefMut}; use core::fmt; use libsys::{ error::Errno, ioctl::IoctlCmd, - stat::{FileMode, OpenFlags, Stat}, + stat::{AccessMode, FileMode, OpenFlags, Stat}, }; /// Convenience type alias for [Rc] @@ -31,7 +31,7 @@ pub(crate) struct TreeNode { /// File property cache struct pub struct VnodeProps { - mode: FileMode, + pub mode: FileMode, } /// Virtual filesystem node struct, generalizes access to @@ -122,6 +122,11 @@ impl Vnode { &self.name } + /// Returns a borrowed reference to cached file properties + pub fn props_mut(&self) -> RefMut { + self.props.borrow_mut() + } + /// Sets an associated [VnodeImpl] for the [Vnode] pub fn set_data(&self, data: Box) { *self.data.borrow_mut() = Some(data); @@ -408,6 +413,38 @@ impl Vnode { Err(Errno::NotImplemented) } } + + pub fn check_access(&self, ioctx: &Ioctx, access: AccessMode) -> Result<(), Errno> { + let props = self.props.borrow(); + let mode = props.mode; + + if access.contains(AccessMode::F_OK) { + if access.intersects(AccessMode::R_OK | AccessMode::W_OK | AccessMode::X_OK) { + return Err(Errno::InvalidArgument); + } + return Ok(()); + } else { + if access.contains(AccessMode::F_OK) { + return Err(Errno::InvalidArgument); + } + + // Check user + if access.contains(AccessMode::R_OK) && !mode.contains(FileMode::USER_READ) { + return Err(Errno::PermissionDenied); + } + if access.contains(AccessMode::W_OK) && !mode.contains(FileMode::USER_WRITE) { + return Err(Errno::PermissionDenied); + } + if access.contains(AccessMode::X_OK) && !mode.contains(FileMode::USER_EXEC) { + return Err(Errno::PermissionDenied); + } + + // TODO check group + // TODO check other + + return Ok(()); + } + } } impl fmt::Debug for Vnode { diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 27fac7a..b24f58f 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -243,7 +243,9 @@ impl Process { if lock.threads.len() == 1 { // TODO call Process::exit instead? - todo!(); + drop(lock); + Process::exit(ExitCode::from(0)); + panic!(); } lock.threads.retain(|&e| e != tid); diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index 2c7d786..d848c19 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -283,7 +283,7 @@ impl Thread { } /// Switches process main thread to a signal handler - pub fn enter_signal(&self, signal: Signal, ttbr0: usize) { + pub fn enter_signal(self: ThreadRef, signal: Signal, ttbr0: usize) { if self .signal_pending .compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed) @@ -294,7 +294,9 @@ impl Thread { let mut lock = self.inner.lock(); if lock.signal_entry == 0 || lock.signal_stack == 0 { - todo!(); + drop(lock); + Process::exit_thread(self); + panic!(); } let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 9a5f701..b870833 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -12,7 +12,7 @@ use libsys::{ ioctl::IoctlCmd, proc::Pid, signal::{Signal, SignalDestination}, - stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH}, + stat::{FdSet, AccessMode, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH}, traits::{Read, Write}, }; use vfs::VnodeRef; @@ -233,6 +233,18 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { wait::select(Thread::current(), rfds, wfds, timeout) } + abi::SYS_FACCESSAT => { + let at_fd = FileDescriptor::from_i32(args[0] as i32)?; + let path = validate_user_str(args[1], args[2])?; + let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; + let flags = args[4] as u32; + + let proc = Process::current(); + let mut io = proc.io.lock(); + + find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?; + Ok(0) + }, _ => { let thread = Thread::current(); diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index e5183b8..16ef3d7 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -20,3 +20,4 @@ pub const SYS_EXECVE: usize = 8; pub const SYS_WAITPID: usize = 9; pub const SYS_IOCTL: usize = 10; pub const SYS_SELECT: usize = 11; +pub const SYS_FACCESSAT: usize = 12; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 96de914..af430f6 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -4,7 +4,7 @@ use crate::{ ioctl::IoctlCmd, proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, - stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, + stat::{AccessMode, FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, }; // TODO document the syscall ABI @@ -325,3 +325,22 @@ pub fn sys_select( ) }) } + +#[inline(always)] +pub fn sys_faccessat( + fd: Option, + name: &str, + mode: AccessMode, + flags: u32, +) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + abi::SYS_FACCESSAT, + argn!(FileDescriptor::into_i32(fd)), + argp!(name.as_ptr()), + argn!(name.len()), + argn!(mode.bits()), + argn!(flags) + ) + }) +} diff --git a/libsys/src/error.rs b/libsys/src/error.rs index 450358f..1788d38 100644 --- a/libsys/src/error.rs +++ b/libsys/src/error.rs @@ -15,6 +15,7 @@ pub enum Errno { NotADirectory, NotImplemented, OutOfMemory, + PermissionDenied, ReadOnly, TimedOut, TooManyDescriptors, diff --git a/libsys/src/stat.rs b/libsys/src/stat.rs index f1d0e73..a59be78 100644 --- a/libsys/src/stat.rs +++ b/libsys/src/stat.rs @@ -31,6 +31,15 @@ bitflags! { } } +bitflags! { + pub struct AccessMode: u32 { + const R_OK = 1 << 0; + const W_OK = 1 << 1; + const X_OK = 1 << 2; + const F_OK = 1 << 3; + } +} + #[derive(Clone, Default)] pub struct FdSet { bits: [u64; 2] diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs index 749c809..09c2212 100644 --- a/libusr/src/sys/mod.rs +++ b/libusr/src/sys/mod.rs @@ -2,7 +2,8 @@ pub use libsys::signal::{Signal, SignalDestination}; pub use libsys::proc::ExitCode; pub use libsys::termios; pub use libsys::calls::*; -pub use libsys::stat::{self, FileDescriptor}; +pub use libsys::stat::{self, AccessMode, FileDescriptor}; +pub use libsys::error::Errno; use core::sync::atomic::{Ordering, AtomicBool}; diff --git a/user/Cargo.toml b/user/Cargo.toml index 9196443..8cb69ab 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -13,6 +13,10 @@ path = "src/init/main.rs" name = "shell" path = "src/shell/main.rs" +[[bin]] +name = "fuzzy" +path = "src/fuzzy/main.rs" + [dependencies] libusr = { path = "../libusr" } lazy_static = { version = "*", features = ["spin_no_std"] } diff --git a/user/src/fuzzy/main.rs b/user/src/fuzzy/main.rs new file mode 100644 index 0000000..974561f --- /dev/null +++ b/user/src/fuzzy/main.rs @@ -0,0 +1,10 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate libusr; + +#[no_mangle] +fn main() -> i32 { + 0 +} diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 2c5f85f..4425bd5 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -3,34 +3,56 @@ #[macro_use] extern crate libusr; -#[macro_use] -extern crate lazy_static; +extern crate alloc; -use libusr::thread; +use alloc::borrow::ToOwned; +use libusr::sys::{sys_faccessat, sys_exit, sys_execve, sys_waitpid, sys_fork, ExitCode, Errno, AccessMode}; use libusr::io::{self, Read}; -use libusr::sys::{Signal, SignalDestination}; -use libusr::sync::Mutex; -fn sleep(ns: u64) { - let mut rem = [0; 2]; - libusr::sys::sys_ex_nanosleep(ns, &mut rem).unwrap(); +fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result, io::Error> { + let size = f.read(bytes)?; + Ok(if size == 0 { + None + } else { + Some(core::str::from_utf8(&bytes[..size]).unwrap().trim_end_matches('\n')) + }) +} + +fn execvp(cmd: &str) -> ! { + sys_execve(&("/bin/".to_owned() + cmd)); + sys_exit(ExitCode::from(-1)); +} + +fn execute(line: &str) -> Result { + let mut words = line.split(' '); + let cmd = words.next().unwrap(); + + if let Some(pid) = sys_fork()? { + let mut status = 0; + sys_waitpid(pid, &mut status)?; + Ok(ExitCode::from(status)) + } else { + execvp(cmd); + } } #[no_mangle] fn main() -> i32 { - let value = 1234; - let thread = thread::spawn(move || { - trace!("Closure is alive: {}", value); - sleep(2_000_000_000); - trace!("Closure will now exit"); + let mut buf = [0; 256]; + let mut stdin = io::stdin(); - value - 100 - }); - sleep(1_000_000_000); - - trace!("???"); - - trace!("Thread joined: {:?}", thread.join()); + loop { + print!("> "); + let line = readline(&mut stdin, &mut buf).unwrap(); + if line.is_none() { + break; + } + let line = line.unwrap().trim_start_matches(' '); + if line.is_empty() { + continue; + } + execute(line); + } 0 } From 7c622a78f81102942a75c77047cd43f79c14de3e Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sat, 20 Nov 2021 15:46:38 +0200 Subject: [PATCH 23/42] feature: thread::current() using tpidr_el0 --- kernel/src/arch/aarch64/context.S | 27 ++--------- kernel/src/arch/aarch64/context.rs | 30 ++++++------ kernel/src/proc/process.rs | 11 ++--- kernel/src/proc/thread.rs | 12 +++-- kernel/src/syscall/mod.rs | 9 ++-- libsys/src/abi.rs | 2 + libsys/src/calls.rs | 9 +++- libusr/src/lib.rs | 26 ++--------- libusr/src/signal.rs | 13 ++++++ libusr/src/thread.rs | 75 +++++++++++++++++++++++------- user/src/init/main.rs | 2 +- user/src/shell/main.rs | 2 +- 12 files changed, 127 insertions(+), 91 deletions(-) create mode 100644 libusr/src/signal.rs diff --git a/kernel/src/arch/aarch64/context.S b/kernel/src/arch/aarch64/context.S index b022526..71858c5 100644 --- a/kernel/src/arch/aarch64/context.S +++ b/kernel/src/arch/aarch64/context.S @@ -32,27 +32,6 @@ __aa64_ctx_enter_kernel: eret __aa64_ctx_enter_from_fork: - // stack.push(frame.x[18]); - // stack.push(frame.x[17]); - // stack.push(frame.x[16]); - // stack.push(frame.x[15]); - // stack.push(frame.x[14]); - // stack.push(frame.x[13]); - // stack.push(frame.x[12]); - // stack.push(frame.x[11]); - // stack.push(frame.x[10]); - // stack.push(frame.x[9]); - // stack.push(frame.x[8]); - // stack.push(frame.x[7]); - // stack.push(frame.x[6]); - // stack.push(frame.x[5]); - // stack.push(frame.x[4]); - // stack.push(frame.x[3]); - // stack.push(frame.x[2]); - // stack.push(frame.x[1]); - - // stack.push(frame.elr_el1 as usize); - // stack.push(frame.sp_el0 as usize); ldp x0, x1, [sp, #16 * 0] msr sp_el0, x0 msr elr_el1, x1 @@ -82,7 +61,8 @@ __aa64_ctx_switch: stp x27, x28, [sp, #16 * 4] stp x29, x30, [sp, #16 * 5] mrs x19, TTBR0_EL1 - stp x19, xzr, [sp, #16 * 6] + mrs x20, TPIDR_EL0 + stp x19, x20, [sp, #16 * 6] mov x19, sp str x19, [x1] @@ -90,8 +70,9 @@ __aa64_ctx_switch_to: ldr x0, [x0] mov sp, x0 - ldp x19, xzr, [sp, #16 * 6] + ldp x19, x20, [sp, #16 * 6] msr TTBR0_EL1, x19 + msr TPIDR_EL0, x20 ldp x19, x20, [sp, #16 * 0] ldp x21, x22, [sp, #16 * 1] ldp x23, x24, [sp, #16 * 2] diff --git a/kernel/src/arch/aarch64/context.rs b/kernel/src/arch/aarch64/context.rs index bf77fdc..d639758 100644 --- a/kernel/src/arch/aarch64/context.rs +++ b/kernel/src/arch/aarch64/context.rs @@ -67,7 +67,7 @@ impl Context { stack.push(frame.sp_el0 as usize); // Setup common - stack.push(0); + stack.push(0); // tpidr_el0 stack.push(ttbr0); stack.push(__aa64_ctx_enter_from_fork as usize); // x30/lr stack.push(frame.x[29]); // x29 @@ -96,7 +96,7 @@ impl Context { stack.push(entry); stack.push(arg); - stack.push(/* ttbr0 */ 0); + stack.push(0); stack.push(ustack); stack.setup_common(__aa64_ctx_enter_user as usize, ttbr0); @@ -176,20 +176,20 @@ impl Stack { } pub fn setup_common(&mut self, entry: usize, ttbr: usize) { - self.push(0); + self.push(0); // tpidr_el0 self.push(ttbr); - self.push(entry); // x30/lr - self.push(0); // x29 - self.push(0); // x28 - self.push(0); // x27 - self.push(0); // x26 - self.push(0); // x25 - self.push(0); // x24 - self.push(0); // x23 - self.push(0); // x22 - self.push(0); // x21 - self.push(0); // x20 - self.push(0); // x19 + self.push(entry); // x30/lr + self.push(0); // x29 + self.push(0); // x28 + self.push(0); // x27 + self.push(0); // x26 + self.push(0); // x25 + self.push(0); // x24 + self.push(0); // x23 + self.push(0); // x22 + self.push(0); // x21 + self.push(0); // x20 + self.push(0); // x19 } pub fn push(&mut self, value: usize) { diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index b24f58f..06bbed6 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -197,11 +197,10 @@ impl Process { // TODO a way to terminate a single thread? /// Terminates a process. - pub fn exit>(status: I) { + pub fn exit(status: ExitCode) { unsafe { asm!("msr daifclr, #0xF"); } - let status = status.into(); let thread = Thread::current(); let process = thread.owner().unwrap(); let mut lock = process.inner.lock(); @@ -213,7 +212,7 @@ impl Process { for &tid in lock.threads.iter() { debugln!("Dequeue {:?}", tid); - Thread::get(tid).unwrap().terminate(); + Thread::get(tid).unwrap().terminate(status); SCHED.dequeue(tid); } SCHED.debug(); @@ -234,7 +233,7 @@ impl Process { panic!("This code should never run"); } - pub fn exit_thread(thread: ThreadRef) { + pub fn exit_thread(thread: ThreadRef, status: ExitCode) { let switch = { let switch = thread.state() == ThreadState::Running; let process = thread.owner().unwrap(); @@ -244,13 +243,13 @@ impl Process { if lock.threads.len() == 1 { // TODO call Process::exit instead? drop(lock); - Process::exit(ExitCode::from(0)); + Process::exit(status); panic!(); } lock.threads.retain(|&e| e != tid); - thread.terminate(); + thread.terminate(status); SCHED.dequeue(tid); debugln!("Thread {} terminated", tid); diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index d848c19..3e4ed85 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -1,10 +1,11 @@ use crate::arch::aarch64::exception::ExceptionFrame; use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS}; use crate::sync::IrqSafeSpinLock; +use crate::util::InitOnce; use alloc::{rc::Rc, vec::Vec}; use core::cell::UnsafeCell; use core::sync::atomic::{AtomicU32, Ordering}; -use libsys::{error::Errno, proc::Pid, signal::Signal}; +use libsys::{error::Errno, proc::{Pid, ExitCode}, signal::Signal}; pub use crate::arch::platform::context::{self, Context}; @@ -36,6 +37,7 @@ struct ThreadInner { pub struct Thread { inner: IrqSafeSpinLock, exit_wait: Wait, + exit_status: InitOnce, pub(super) ctx: UnsafeCell, signal_ctx: UnsafeCell, signal_pending: AtomicU32, @@ -70,6 +72,7 @@ impl Thread { signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), exit_wait: Wait::new(), + exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -100,6 +103,7 @@ impl Thread { signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), exit_wait: Wait::new(), + exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -127,6 +131,7 @@ impl Thread { signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), exit_wait: Wait::new(), + exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -295,7 +300,7 @@ impl Thread { let mut lock = self.inner.lock(); if lock.signal_entry == 0 || lock.signal_stack == 0 { drop(lock); - Process::exit_thread(self); + Process::exit_thread(self, ExitCode::from(-1)); panic!(); } @@ -322,7 +327,7 @@ impl Thread { } } - pub fn terminate(&self) { + pub fn terminate(&self, status: ExitCode) { let mut lock = self.inner.lock(); lock.state = State::Finished; let tid = lock.id; @@ -331,6 +336,7 @@ impl Thread { if let Some(wait) = wait { wait.abort(tid); } + self.exit_status.init(status); self.exit_wait.wakeup_all(); } } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index b870833..2c0892f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -10,7 +10,7 @@ use libsys::{ abi, error::Errno, ioctl::IoctlCmd, - proc::Pid, + proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, stat::{FdSet, AccessMode, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH}, traits::{Read, Write}, @@ -55,13 +55,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { match num { // Process management system calls abi::SYS_EXIT => { - Process::exit(args[0] as i32); + Process::exit(ExitCode::from(args[0] as i32)); unreachable!(); } abi::SYS_EX_THREAD_EXIT => { - Process::exit_thread(Thread::current()); + Process::exit_thread(Thread::current(), ExitCode::from(args[0] as i32)); unreachable!(); }, + abi::SYS_EX_GETTID => { + Ok(Thread::current().id() as usize) + }, // I/O system calls abi::SYS_OPENAT => { diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 16ef3d7..056563e 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -8,6 +8,7 @@ pub const SYS_EX_CLONE: usize = 133; pub const SYS_EX_YIELD: usize = 134; pub const SYS_EX_THREAD_EXIT: usize = 135; pub const SYS_EX_THREAD_WAIT: usize = 136; +pub const SYS_EX_GETTID: usize = 137; pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; @@ -21,3 +22,4 @@ pub const SYS_WAITPID: usize = 9; pub const SYS_IOCTL: usize = 10; pub const SYS_SELECT: usize = 11; pub const SYS_FACCESSAT: usize = 12; +// pub const SYS_GETPID: usize = 13; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index af430f6..8f09427 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -188,7 +188,7 @@ pub fn sys_fstatat( /// /// System call #[inline(always)] -pub fn sys_fork() -> Result, Errno> { +pub unsafe fn sys_fork() -> Result, Errno> { Errno::from_syscall(unsafe { syscall!(abi::SYS_FORK) }).map(|res| { if res != 0 { Some(unsafe { Pid::from_raw(res as u32) }) @@ -344,3 +344,10 @@ pub fn sys_faccessat( ) }) } + +#[inline(always)] +pub fn sys_ex_gettid() -> u32 { + unsafe { + syscall!(abi::SYS_EX_GETTID) as u32 + } +} diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index c967fb3..f13a1e9 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -16,21 +16,8 @@ pub mod os; pub mod sys; pub mod sync; pub mod thread; +pub mod signal; -use sys::Signal; - -#[inline(never)] -pub(crate) extern "C" fn _signal_handler(arg: Signal) -> ! { - trace!("Entered signal handler: arg={:?}", arg); - match arg { - Signal::Interrupt | Signal::SegmentationFault => - loop {}, - _ => todo!() - } - sys::sys_ex_sigreturn(); -} - -static mut SIGNAL_STACK: [u8; 4096] = [0; 4096]; #[link_section = ".text._start"] #[no_mangle] @@ -40,11 +27,7 @@ extern "C" fn _start(_arg: usize) -> ! { } unsafe { - sys::sys_ex_signal( - _signal_handler as usize, - SIGNAL_STACK.as_ptr() as usize + 4096, - ) - .unwrap(); + thread::init_main(); } let res = unsafe { main() }; @@ -53,8 +36,9 @@ extern "C" fn _start(_arg: usize) -> ! { #[panic_handler] fn panic_handler(pi: &PanicInfo) -> ! { - // TODO handle non-main thread panics + // TODO unwind to send panic argument back to parent thread // TODO print to stdout/stderr (if available) - trace!("Panic ocurred: {}", pi); + let thread = thread::current(); + trace!("{:?} panicked: {:?}", thread, pi); sys::sys_exit(ExitCode::from(-1)); } diff --git a/libusr/src/signal.rs b/libusr/src/signal.rs new file mode 100644 index 0000000..f9d8787 --- /dev/null +++ b/libusr/src/signal.rs @@ -0,0 +1,13 @@ +use libsys::{calls::sys_ex_sigreturn, signal::Signal}; +use crate::trace; + +#[inline(never)] +pub(crate) extern "C" fn signal_handler(arg: Signal) -> ! { + trace!("Entered signal handler: arg={:?}", arg); + match arg { + Signal::Interrupt | Signal::SegmentationFault => + loop {}, + _ => todo!() + } + sys_ex_sigreturn(); +} diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs index f521ce0..f08848f 100644 --- a/libusr/src/thread.rs +++ b/libusr/src/thread.rs @@ -2,12 +2,14 @@ use alloc::{boxed::Box, sync::Arc, vec}; use core::cell::UnsafeCell; use core::mem::MaybeUninit; use libsys::{ - calls::{sys_ex_clone, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait}, + calls::{sys_ex_clone, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait, sys_ex_gettid}, error::Errno, proc::ExitCode, }; - -use crate::trace; +use core::sync::atomic::{AtomicU32, Ordering}; +use core::any::Any; +use crate::{trace, signal}; +use core::fmt; struct NativeData where @@ -16,26 +18,69 @@ where T: Send + 'static, { closure: F, - result: Arc>>, + result: ThreadPacket, stack: usize, } +#[derive(Clone)] +pub struct Thread { + id: u32 +} + +pub type ThreadResult = Result>; +pub type ThreadPacket = Arc>>>; + pub struct JoinHandle { native: u32, - result: Arc>>, + result: ThreadPacket +} + +impl Thread { + pub const fn id(&self) -> u32 { + self.id + } +} + +impl fmt::Debug for Thread { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Thread").field("id", &self.id).finish_non_exhaustive() + } } impl JoinHandle { - pub fn join(self) -> Result { + pub fn join(self) -> ThreadResult { sys_ex_thread_wait(self.native).unwrap(); - if let Ok(result) = Arc::try_unwrap(self.result) { - Ok(unsafe { result.into_inner().assume_init() }) - } else { - Err(()) - } + unsafe { Arc::try_unwrap(self.result).unwrap().into_inner().assume_init() } } } +unsafe fn init_common(signal_stack_pointer: *mut u8) { + let tid = sys_ex_gettid(); + asm!("msr tpidr_el0, {}", in(reg) tid); + + // thread::current() should be valid at this point + + sys_ex_signal( + signal::signal_handler as usize, + signal_stack_pointer as usize + ) + .unwrap(); +} + +pub(crate) unsafe fn init_main() { + static mut SIGNAL_STACK: [u8; 4096] = [0; 4096]; + init_common(SIGNAL_STACK.as_mut_ptr().add(SIGNAL_STACK.len())) +} + +pub fn current() -> Thread { + let mut id: u32; + unsafe { + asm!("mrs {}, tpidr_el0", out(reg) id); + } + + Thread { id } +} + pub fn spawn(f: F) -> JoinHandle where F: FnOnce() -> T, @@ -57,18 +102,14 @@ where let mut signal_stack = vec![0u8; 8192]; unsafe { - sys_ex_signal( - crate::_signal_handler as usize, - signal_stack.as_mut_ptr() as usize + signal_stack.len(), - ) - .unwrap(); + init_common(signal_stack.as_mut_ptr().add(signal_stack.len())); } let data: Box> = unsafe { Box::from_raw(data) }; let res = (data.closure)(); unsafe { - (&mut *data.result.get()).write(res); + (&mut *data.result.get()).write(Ok(res)); } (data.stack, 8192) diff --git a/user/src/init/main.rs b/user/src/init/main.rs index f033d6d..02bebcc 100644 --- a/user/src/init/main.rs +++ b/user/src/init/main.rs @@ -7,7 +7,7 @@ extern crate libusr; #[no_mangle] fn main() -> i32 { - let pid = libusr::sys::sys_fork().unwrap(); + let pid = unsafe { libusr::sys::sys_fork().unwrap() }; if let Some(pid) = pid { let mut status = 0; diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 4425bd5..64ea822 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -27,7 +27,7 @@ fn execute(line: &str) -> Result { let mut words = line.split(' '); let cmd = words.next().unwrap(); - if let Some(pid) = sys_fork()? { + if let Some(pid) = unsafe { sys_fork()? } { let mut status = 0; sys_waitpid(pid, &mut status)?; Ok(ExitCode::from(status)) From 3121cc9ba928bc3c9c7510c7a77fb3a7bf3c6218 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 21 Nov 2021 11:44:33 +0200 Subject: [PATCH 24/42] feature: fuzzy --- fs/memfs/src/dir.rs | 6 +- kernel/src/syscall/mod.rs | 7 ++- libsys/src/abi.rs | 1 + libsys/src/calls.rs | 9 +++ libusr/src/signal.rs | 36 +++++++++-- libusr/src/sys/mod.rs | 1 + libusr/src/thread.rs | 8 ++- user/src/fuzzy/main.rs | 126 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 184 insertions(+), 10 deletions(-) diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index 791ceee..5766e1a 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -1,6 +1,6 @@ use crate::{BlockAllocator, Bvec, FileInode}; use alloc::boxed::Box; -use libsys::error::Errno; +use libsys::{error::Errno, stat::Stat}; use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirInode { @@ -31,6 +31,10 @@ impl VnodeImpl for DirInode { fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { Ok(()) } + + fn stat(&mut self, _at: VnodeRef, _stat: &mut Stat) -> Result<(), Errno> { + Ok(()) + } } impl DirInode { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 2c0892f..055ce08 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1,8 +1,9 @@ //! System call implementation -use crate::arch::platform::exception::ExceptionFrame; +use crate::arch::{machine, platform::exception::ExceptionFrame}; use crate::debug::Level; use crate::proc::{self, elf, wait, Process, ProcessIo, Thread}; +use crate::dev::timer::TimestampSource; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; @@ -248,6 +249,10 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?; Ok(0) }, + abi::SYS_EX_GETCPUTIME => { + let time = machine::local_timer().timestamp()?; + Ok(time.as_nanos() as usize) + } _ => { let thread = Thread::current(); diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 056563e..67dcbe4 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -9,6 +9,7 @@ pub const SYS_EX_YIELD: usize = 134; pub const SYS_EX_THREAD_EXIT: usize = 135; pub const SYS_EX_THREAD_WAIT: usize = 136; pub const SYS_EX_GETTID: usize = 137; +pub const SYS_EX_GETCPUTIME: usize = 138; pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 8f09427..48bce17 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -6,9 +6,11 @@ use crate::{ signal::{Signal, SignalDestination}, stat::{AccessMode, FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, }; +use core::time::Duration; // TODO document the syscall ABI +// TODO move this to libusr macro_rules! syscall { ($num:expr) => {{ let mut res: usize; @@ -247,6 +249,13 @@ pub fn sys_ioctl( }) } +#[inline(always)] +pub fn sys_ex_getcputime() -> Result { + Errno::from_syscall(unsafe { + syscall!(abi::SYS_EX_GETCPUTIME) + }).map(|e| Duration::from_nanos(e as u64)) +} + #[inline(always)] pub fn sys_ex_signal(entry: usize, stack: usize) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!(abi::SYS_EX_SIGNAL, argn!(entry), argn!(stack)) }) diff --git a/libusr/src/signal.rs b/libusr/src/signal.rs index f9d8787..e6fd5a0 100644 --- a/libusr/src/signal.rs +++ b/libusr/src/signal.rs @@ -1,13 +1,37 @@ -use libsys::{calls::sys_ex_sigreturn, signal::Signal}; -use crate::trace; +use libsys::{calls::{sys_exit, sys_ex_sigreturn}, signal::Signal, proc::ExitCode}; +use crate::{trace, thread}; + +#[derive(Clone, Copy)] +pub enum SignalHandler { + Func(fn(Signal) -> ()), + Ignore, + Terminate +} + +// TODO per-thread signal handler table +static mut SIGNAL_HANDLERS: [SignalHandler; 32] = [SignalHandler::Terminate; 32]; + +pub fn set_handler(sig: Signal, handler: SignalHandler) -> SignalHandler { + unsafe { + let old = SIGNAL_HANDLERS[sig as usize]; + SIGNAL_HANDLERS[sig as usize] = handler; + old + } +} #[inline(never)] pub(crate) extern "C" fn signal_handler(arg: Signal) -> ! { + // TODO tpidr_el0 is invalidated when entering signal context trace!("Entered signal handler: arg={:?}", arg); - match arg { - Signal::Interrupt | Signal::SegmentationFault => - loop {}, - _ => todo!() + let no = arg as usize; + if no >= 32 { + panic!("Undefined signal number: {}", no); } + match unsafe { SIGNAL_HANDLERS[no] } { + SignalHandler::Func(f) => f(arg), + SignalHandler::Ignore => (), + SignalHandler::Terminate => sys_exit(ExitCode::from(-1)), + } + sys_ex_sigreturn(); } diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs index 09c2212..8a6ab86 100644 --- a/libusr/src/sys/mod.rs +++ b/libusr/src/sys/mod.rs @@ -1,6 +1,7 @@ pub use libsys::signal::{Signal, SignalDestination}; pub use libsys::proc::ExitCode; pub use libsys::termios; +pub use libsys::abi; pub use libsys::calls::*; pub use libsys::stat::{self, AccessMode, FileDescriptor}; pub use libsys::error::Errno; diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs index f08848f..71df64e 100644 --- a/libusr/src/thread.rs +++ b/libusr/src/thread.rs @@ -68,8 +68,12 @@ unsafe fn init_common(signal_stack_pointer: *mut u8) { } pub(crate) unsafe fn init_main() { - static mut SIGNAL_STACK: [u8; 4096] = [0; 4096]; - init_common(SIGNAL_STACK.as_mut_ptr().add(SIGNAL_STACK.len())) + #[repr(align(16))] + struct StackWrapper { + data: [u8; 8192] + } + static mut STACK: StackWrapper = StackWrapper { data: [0; 8192] }; + init_common(STACK.data.as_mut_ptr().add(8192)) } pub fn current() -> Thread { diff --git a/user/src/fuzzy/main.rs b/user/src/fuzzy/main.rs index 974561f..c87864f 100644 --- a/user/src/fuzzy/main.rs +++ b/user/src/fuzzy/main.rs @@ -1,10 +1,136 @@ +#![feature(asm)] #![no_std] #![no_main] #[macro_use] extern crate libusr; +use libusr::sys::{abi, stat::Stat, Signal}; +use libusr::signal::{self, SignalHandler}; + +static mut STATE: u64 = 0; + +macro_rules! syscall { + ($num:expr) => {{ + let mut res: usize; + asm!("svc #0", out("x0") res, in("x8") $num, options(nostack)); + res + }}; + ($num:expr, $a0:expr) => {{ + let mut res: usize = $a0; + asm!("svc #0", + inout("x0") res, + in("x8") $num, options(nostack)); + res + }}; + ($num:expr, $a0:expr, $a1:expr) => {{ + let mut res: usize = $a0; + asm!("svc #0", + inout("x0") res, in("x1") $a1, + in("x8") $num, options(nostack)); + res + }}; + ($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{ + let mut res: usize = $a0; + asm!("svc #0", + inout("x0") res, in("x1") $a1, in("x2") $a2, + in("x8") $num, options(nostack)); + res + }}; + ($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{ + let mut res: usize = $a0; + asm!("svc #0", + inout("x0") res, in("x1") $a1, in("x2") $a2, + in("x3") $a3, in("x8") $num, options(nostack)); + res + }}; + ($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{ + let mut res: usize = $a0; + asm!("svc #0", + inout("x0") res, in("x1") $a1, in("x2") $a2, + in("x3") $a3, in("x4") $a4, in("x8") $num, options(nostack)); + res + }}; +} + +/// Integer/size argument +macro_rules! argn { + ($a:expr) => { + $a as usize + }; +} +/// Pointer/base argument +macro_rules! argp { + ($a:expr) => { + $a as usize + }; +} + +fn random_set_seed(seed: u64) { + unsafe { STATE = seed; } +} + +fn random_u64() -> u64 { + let mut x = unsafe { STATE }; + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; + unsafe { + STATE = x; + } + x +} + +fn random_ascii_char() -> u8 { + ((random_u64() % (0x7F - 0x20)) as u8) + 0x20 +} + +fn random_str_range(buf: &mut [u8], min: usize, max: usize) -> &str { + let max = core::cmp::min(buf.len(), max); + assert!(max > min); + let len = ((random_u64() as usize) % (max - min)) + min; + for c in buf[..len].iter_mut() { + *c = random_ascii_char(); + } + core::str::from_utf8(&buf[..len]).unwrap() +} + +fn random_str(buf: &mut [u8]) -> &str { + random_str_range(buf, 0, buf.len()) +} + +fn random_bytes(buf: &mut [u8]) { + for byte in buf.iter_mut() { + *byte = (random_u64() & 0xFF) as u8; + } +} + #[no_mangle] fn main() -> i32 { + let seed = libusr::sys::sys_ex_getcputime().unwrap().as_nanos() as u64 / 13; + trace!("Using seed: {:#x}", seed); + random_set_seed(seed); + + let mut buf = [0; 256]; + + // Test sys_ex_getcputime() + let mut prev_time = libusr::sys::sys_ex_getcputime().unwrap().as_nanos(); + for _ in 0..100000 { + let t = libusr::sys::sys_ex_getcputime().unwrap().as_nanos(); + assert!(t >= prev_time); + } + + // Test non-utf8 input fed into syscalls expecting strings + // let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore); + for _ in 0..10000 { + random_bytes(&mut buf); + let mut stat = Stat::default(); + + unsafe { + syscall!(abi::SYS_FSTATAT, (-2i32) as usize, buf.as_mut_ptr() as usize, buf.len(), (&mut stat) as *mut _ as usize); + } + } + // signal::set_handler(Signal::InvalidSystemCall, old_signal); + 0 } From bf1a215730d1c2c40b0b4f7939b7df7433ade2d1 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 21 Nov 2021 12:26:11 +0200 Subject: [PATCH 25/42] feature: better ABI for system call numbers --- Cargo.lock | 12 ++ kernel/src/arch/aarch64/exception.rs | 32 ++-- kernel/src/syscall/mod.rs | 223 +++++++++++++-------------- libsys/Cargo.toml | 1 + libsys/src/abi.rs | 57 ++++--- libsys/src/calls.rs | 67 ++++---- user/src/fuzzy/main.rs | 6 +- user/src/shell/main.rs | 10 ++ 8 files changed, 218 insertions(+), 190 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03e4c5b..ef237f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,17 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6419a5c75e40011b9fe0174db3fe24006ab122fbe1b7e9cc5974b338a755c76" +[[package]] +name = "enum-repr" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad30c9c0fa1aaf1ae5010dab11f1117b15d35faf62cda4bbbc53b9987950f18" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -111,6 +122,7 @@ name = "libsys" version = "0.1.0" dependencies = [ "bitflags", + "enum-repr", ] [[package]] diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index d25cc60..21085dc 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -7,7 +7,7 @@ use crate::mem; use crate::proc::{sched, Thread, Process}; use crate::syscall; use cortex_a::registers::{ESR_EL1, FAR_EL1}; -use libsys::{abi, signal::Signal}; +use libsys::{abi::SystemCall, signal::Signal}; use tock_registers::interfaces::Readable; /// Trapped SIMD/FP functionality @@ -116,24 +116,30 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { dump_data_abort(Level::Error, esr, far as u64); } EC_SVC_AA64 => { - unsafe { - if exc.x[8] == abi::SYS_FORK { - match syscall::sys_fork(exc) { - Ok(pid) => exc.x[0] = pid.value() as usize, - Err(err) => { - exc.x[0] = err.to_negative_isize() as usize; - } - } - return; - } + let num = SystemCall::from_repr(exc.x[8]); + if num.is_none() { + todo!(); + return; + } + let num = num.unwrap(); - match syscall::syscall(exc.x[8], &exc.x[..6]) { - Ok(val) => exc.x[0] = val, + if num == SystemCall::Fork { + match unsafe { syscall::sys_fork(exc) } { + Ok(pid) => exc.x[0] = pid.value() as usize, Err(err) => { exc.x[0] = err.to_negative_isize() as usize; } } + return; } + + match syscall::syscall(num, &exc.x[..6]) { + Ok(val) => exc.x[0] = val, + Err(err) => { + exc.x[0] = err.to_negative_isize() as usize; + } + } + return; } _ => {} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 055ce08..fe4b483 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -8,7 +8,7 @@ use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; use libsys::{ - abi, + abi::SystemCall, error::Errno, ioctl::IoctlCmd, proc::{ExitCode, Pid}, @@ -52,23 +52,26 @@ fn find_at_node>( } /// Main system call dispatcher function -pub fn syscall(num: usize, args: &[usize]) -> Result { +pub fn syscall(num: SystemCall, args: &[usize]) -> Result { match num { - // Process management system calls - abi::SYS_EXIT => { - Process::exit(ExitCode::from(args[0] as i32)); - unreachable!(); - } - abi::SYS_EX_THREAD_EXIT => { - Process::exit_thread(Thread::current(), ExitCode::from(args[0] as i32)); - unreachable!(); - }, - abi::SYS_EX_GETTID => { - Ok(Thread::current().id() as usize) - }, + // I/O + SystemCall::Read => { + let proc = Process::current(); + let fd = FileDescriptor::from(args[0] as u32); + let mut io = proc.io.lock(); + let buf = validate_user_ptr(args[1], args[2])?; - // I/O system calls - abi::SYS_OPENAT => { + io.file(fd)?.borrow_mut().read(buf) + }, + SystemCall::Write => { + let proc = Process::current(); + let fd = FileDescriptor::from(args[0] as u32); + let mut io = proc.io.lock(); + let buf = validate_user_ptr(args[1], args[2])?; + + io.file(fd)?.borrow_mut().write(buf) + }, + SystemCall::Open => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; let path = validate_user_str(args[1], args[2])?; let mode = FileMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; @@ -85,24 +88,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { let file = io.ioctx().open(at, path, mode, opts)?; Ok(u32::from(io.place_file(file)?) as usize) - } - abi::SYS_READ => { + }, + SystemCall::Close => { let proc = Process::current(); - let fd = FileDescriptor::from(args[0] as u32); let mut io = proc.io.lock(); - let buf = validate_user_ptr(args[1], args[2])?; - - io.file(fd)?.borrow_mut().read(buf) - } - abi::SYS_WRITE => { - let proc = Process::current(); let fd = FileDescriptor::from(args[0] as u32); - let mut io = proc.io.lock(); - let buf = validate_user_ptr(args[1], args[2])?; - io.file(fd)?.borrow_mut().write(buf) - } - abi::SYS_FSTATAT => { + io.close_file(fd)?; + Ok(0) + }, + SystemCall::FileStatus => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; let filename = validate_user_str(args[1], args[2])?; let buf = validate_user_ptr_struct::(args[3])?; @@ -112,16 +107,52 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { let mut io = proc.io.lock(); find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat(buf)?; Ok(0) - } - abi::SYS_CLOSE => { + }, + SystemCall::Ioctl => { + let fd = FileDescriptor::from(args[0] as u32); + let cmd = IoctlCmd::try_from(args[1] as u32)?; + let proc = Process::current(); let mut io = proc.io.lock(); - let fd = FileDescriptor::from(args[0] as u32); - io.close_file(fd)?; + let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?; + node.ioctl(cmd, args[2], args[3]) + }, + SystemCall::Select => { + let rfds = validate_user_ptr_struct_option::(args[0])?; + let wfds = validate_user_ptr_struct_option::(args[1])?; + let timeout = if args[2] == 0 { + None + } else { + Some(Duration::from_nanos(args[2] as u64)) + }; + + wait::select(Thread::current(), rfds, wfds, timeout) + }, + SystemCall::Access => { + let at_fd = FileDescriptor::from_i32(args[0] as i32)?; + let path = validate_user_str(args[1], args[2])?; + let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; + let flags = args[4] as u32; + + let proc = Process::current(); + let mut io = proc.io.lock(); + + find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?; Ok(0) - } - abi::SYS_EXECVE => { + }, + + // Process + SystemCall::Clone => { + let entry = args[0]; + let stack = args[1]; + let arg = args[2]; + + Process::current() + .new_user_thread(entry, stack, arg) + .map(|e| e as usize) + }, + SystemCall::Exec => { let node = { let proc = Process::current(); let mut io = proc.io.lock(); @@ -134,8 +165,20 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { let file = node.open(OpenFlags::O_RDONLY)?; Process::execve(|space| elf::load_elf(space, file), 0).unwrap(); panic!(); - } - abi::SYS_WAITPID => { + }, + SystemCall::Exit => { + let status = ExitCode::from(args[0] as i32); + let flags = args[1]; + + if flags & (1 << 0) != 0 { + Process::exit_thread(Thread::current(), status); + } else { + Process::exit(status); + } + + unreachable!(); + }, + SystemCall::WaitPid => { // TODO special "pid" values let pid = unsafe { Pid::from_raw(args[0] as u32) }; let status = validate_user_ptr_struct::(args[1])?; @@ -147,8 +190,8 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { } _ => todo!(), } - } - abi::SYS_EX_THREAD_WAIT => { + }, + SystemCall::WaitTid => { let tid = args[0] as u32; match Thread::waittid(tid) { @@ -158,28 +201,9 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { _ => todo!(), } }, - abi::SYS_IOCTL => { - let fd = FileDescriptor::from(args[0] as u32); - let cmd = IoctlCmd::try_from(args[1] as u32)?; - - let proc = Process::current(); - let mut io = proc.io.lock(); - - let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?; - node.ioctl(cmd, args[2], args[3]) - } - - // Extra system calls - abi::SYS_EX_DEBUG_TRACE => { - let buf = validate_user_ptr(args[0], args[1])?; - print!(Level::Debug, "[trace] "); - for &byte in buf.iter() { - print!(Level::Debug, "{}", byte as char); - } - println!(Level::Debug, ""); - Ok(args[1]) - } - abi::SYS_EX_NANOSLEEP => { + SystemCall::GetPid => todo!(), + SystemCall::GetTid => Ok(Thread::current().id() as usize), + SystemCall::Sleep => { let rem_buf = validate_user_ptr_null(args[1], size_of::() * 2)?; let mut rem = Duration::new(0, 0); let res = wait::sleep(Duration::from_nanos(args[0] as u64), &mut rem); @@ -190,16 +214,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { } } res.map(|_| 0) - } - abi::SYS_EX_SIGNAL => { + }, + SystemCall::SetSignalEntry => { Thread::current().set_signal_entry(args[0], args[1]); Ok(0) - } - abi::SYS_EX_SIGRETURN => { + }, + SystemCall::SignalReturn => { Thread::current().return_from_signal(); - panic!("This code won't run"); - } - abi::SYS_EX_KILL => { + unreachable!(); + }, + SystemCall::SendSignal => { let target = SignalDestination::from(args[0] as isize); let signal = Signal::try_from(args[1] as u32)?; @@ -211,55 +235,30 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { _ => todo!(), }; Ok(0) - } - abi::SYS_EX_CLONE => { - let entry = args[0]; - let stack = args[1]; - let arg = args[2]; - - Process::current() - .new_user_thread(entry, stack, arg) - .map(|e| e as usize) - } - abi::SYS_EX_YIELD => { + }, + SystemCall::Yield => { proc::switch(); Ok(0) }, - abi::SYS_SELECT => { - let rfds = validate_user_ptr_struct_option::(args[0])?; - let wfds = validate_user_ptr_struct_option::(args[1])?; - let timeout = if args[2] == 0 { - None - } else { - Some(Duration::from_nanos(args[2] as u64)) - }; - - wait::select(Thread::current(), rfds, wfds, timeout) - } - abi::SYS_FACCESSAT => { - let at_fd = FileDescriptor::from_i32(args[0] as i32)?; - let path = validate_user_str(args[1], args[2])?; - let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; - let flags = args[4] as u32; - - let proc = Process::current(); - let mut io = proc.io.lock(); - - find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?; - Ok(0) - }, - abi::SYS_EX_GETCPUTIME => { + // System + SystemCall::GetCpuTime => { let time = machine::local_timer().timestamp()?; Ok(time.as_nanos() as usize) - } + }, - _ => { - let thread = Thread::current(); - let proc = thread.owner().unwrap(); - errorln!("Undefined system call: {}", num); - proc.enter_fault_signal(thread, Signal::InvalidSystemCall); - Err(Errno::InvalidArgument) - } + // Debugging + SystemCall::DebugTrace => { + let buf = validate_user_ptr(args[0], args[1])?; + print!(Level::Debug, "[trace] "); + for &byte in buf.iter() { + print!(Level::Debug, "{}", byte as char); + } + println!(Level::Debug, ""); + Ok(args[1]) + }, + + // Handled elsewhere + SystemCall::Fork => unreachable!() } } diff --git a/libsys/Cargo.toml b/libsys/Cargo.toml index 1524b9c..f2a50f4 100644 --- a/libsys/Cargo.toml +++ b/libsys/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] bitflags = "^1.3.0" +enum-repr = "^0.2.6" [features] user = [] diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 67dcbe4..59c9b36 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -1,26 +1,33 @@ -pub const SYS_EX_DEBUG_TRACE: usize = 128; -pub const SYS_EX_NANOSLEEP: usize = 129; +use enum_repr::EnumRepr; -pub const SYS_EX_SIGNAL: usize = 130; -pub const SYS_EX_SIGRETURN: usize = 131; -pub const SYS_EX_KILL: usize = 132; -pub const SYS_EX_CLONE: usize = 133; -pub const SYS_EX_YIELD: usize = 134; -pub const SYS_EX_THREAD_EXIT: usize = 135; -pub const SYS_EX_THREAD_WAIT: usize = 136; -pub const SYS_EX_GETTID: usize = 137; -pub const SYS_EX_GETCPUTIME: usize = 138; - -pub const SYS_EXIT: usize = 1; -pub const SYS_READ: usize = 2; -pub const SYS_WRITE: usize = 3; -pub const SYS_OPENAT: usize = 4; -pub const SYS_FSTATAT: usize = 5; -pub const SYS_CLOSE: usize = 6; -pub const SYS_FORK: usize = 7; -pub const SYS_EXECVE: usize = 8; -pub const SYS_WAITPID: usize = 9; -pub const SYS_IOCTL: usize = 10; -pub const SYS_SELECT: usize = 11; -pub const SYS_FACCESSAT: usize = 12; -// pub const SYS_GETPID: usize = 13; +#[EnumRepr(type = "usize")] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum SystemCall { + // I/O + Read = 1, + Write = 2, + Open = 3, + Close = 4, + FileStatus = 5, + Ioctl = 6, + Select = 7, + Access = 8, + // Process manipulation + Fork = 32, + Clone = 33, + Exec = 34, + Exit = 35, + WaitPid = 36, + WaitTid = 37, + GetPid = 38, + GetTid = 39, + Sleep = 40, + SetSignalEntry = 41, + SignalReturn = 42, + SendSignal = 43, + Yield = 44, + // System + GetCpuTime = 64, + // Debugging + DebugTrace = 128 +} diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 48bce17..20acb26 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -1,4 +1,4 @@ -use crate::abi; +use crate::abi::SystemCall; use crate::{ error::Errno, ioctl::IoctlCmd, @@ -14,42 +14,42 @@ use core::time::Duration; macro_rules! syscall { ($num:expr) => {{ let mut res: usize; - asm!("svc #0", out("x0") res, in("x8") $num, options(nostack)); + asm!("svc #0", out("x0") res, in("x8") $num.repr(), options(nostack)); res }}; ($num:expr, $a0:expr) => {{ let mut res: usize = $a0; asm!("svc #0", inout("x0") res, - in("x8") $num, options(nostack)); + in("x8") $num.repr(), options(nostack)); res }}; ($num:expr, $a0:expr, $a1:expr) => {{ let mut res: usize = $a0; asm!("svc #0", inout("x0") res, in("x1") $a1, - in("x8") $num, options(nostack)); + in("x8") $num.repr(), options(nostack)); res }}; ($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{ let mut res: usize = $a0; asm!("svc #0", inout("x0") res, in("x1") $a1, in("x2") $a2, - in("x8") $num, options(nostack)); + in("x8") $num.repr(), options(nostack)); res }}; ($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{ let mut res: usize = $a0; asm!("svc #0", inout("x0") res, in("x1") $a1, in("x2") $a2, - in("x3") $a3, in("x8") $num, options(nostack)); + in("x3") $a3, in("x8") $num.repr(), options(nostack)); res }}; ($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{ let mut res: usize = $a0; asm!("svc #0", inout("x0") res, in("x1") $a1, in("x2") $a2, - in("x3") $a3, in("x4") $a4, in("x8") $num, options(nostack)); + in("x3") $a3, in("x4") $a4, in("x8") $num.repr(), options(nostack)); res }}; } @@ -77,7 +77,7 @@ macro_rules! argp { #[inline(always)] pub fn sys_exit(code: ExitCode) -> ! { unsafe { - syscall!(abi::SYS_EXIT, argn!(i32::from(code))); + syscall!(SystemCall::Exit, argn!(i32::from(code)), argn!(0)); } unreachable!(); } @@ -87,7 +87,7 @@ pub fn sys_exit(code: ExitCode) -> ! { /// System call #[inline(always)] pub fn sys_close(fd: FileDescriptor) -> Result<(), Errno> { - Errno::from_syscall_unit(unsafe { syscall!(abi::SYS_CLOSE, argn!(u32::from(fd))) }) + Errno::from_syscall_unit(unsafe { syscall!(SystemCall::Close, argn!(u32::from(fd))) }) } /// # Safety @@ -96,7 +96,7 @@ pub fn sys_close(fd: FileDescriptor) -> Result<(), Errno> { #[inline(always)] pub fn sys_ex_nanosleep(ns: u64, rem: &mut [u64; 2]) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { - syscall!(abi::SYS_EX_NANOSLEEP, argn!(ns), argp!(rem.as_mut_ptr())) + syscall!(SystemCall::Sleep, argn!(ns), argp!(rem.as_mut_ptr())) }) } @@ -107,7 +107,7 @@ pub fn sys_ex_nanosleep(ns: u64, rem: &mut [u64; 2]) -> Result<(), Errno> { pub fn sys_ex_debug_trace(msg: &[u8]) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( - abi::SYS_EX_DEBUG_TRACE, + SystemCall::DebugTrace, argp!(msg.as_ptr()), argn!(msg.len()) ) @@ -126,7 +126,7 @@ pub fn sys_openat( ) -> Result { Errno::from_syscall(unsafe { syscall!( - abi::SYS_OPENAT, + SystemCall::Open, argn!(FileDescriptor::into_i32(at)), argp!(pathname.as_ptr()), argn!(pathname.len()), @@ -144,7 +144,7 @@ pub fn sys_openat( pub fn sys_read(fd: FileDescriptor, data: &mut [u8]) -> Result { Errno::from_syscall(unsafe { syscall!( - abi::SYS_READ, + SystemCall::Read, argn!(u32::from(fd)), argp!(data.as_mut_ptr()), argn!(data.len()) @@ -156,7 +156,7 @@ pub fn sys_read(fd: FileDescriptor, data: &mut [u8]) -> Result { pub fn sys_write(fd: FileDescriptor, data: &[u8]) -> Result { Errno::from_syscall(unsafe { syscall!( - abi::SYS_WRITE, + SystemCall::Write, argn!(u32::from(fd)), argp!(data.as_ptr()), argn!(data.len()) @@ -176,7 +176,7 @@ pub fn sys_fstatat( ) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( - abi::SYS_FSTATAT, + SystemCall::FileStatus, argn!(FileDescriptor::into_i32(at)), argp!(pathname.as_ptr()), argn!(pathname.len()), @@ -191,7 +191,7 @@ pub fn sys_fstatat( /// System call #[inline(always)] pub unsafe fn sys_fork() -> Result, Errno> { - Errno::from_syscall(unsafe { syscall!(abi::SYS_FORK) }).map(|res| { + Errno::from_syscall(unsafe { syscall!(SystemCall::Fork) }).map(|res| { if res != 0 { Some(unsafe { Pid::from_raw(res as u32) }) } else { @@ -207,7 +207,7 @@ pub unsafe fn sys_fork() -> Result, Errno> { pub fn sys_execve(pathname: &str) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( - abi::SYS_EXECVE, + SystemCall::Exec, argp!(pathname.as_ptr()), argn!(pathname.len()) ) @@ -221,7 +221,7 @@ pub fn sys_execve(pathname: &str) -> Result<(), Errno> { pub fn sys_waitpid(pid: Pid, status: &mut i32) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( - abi::SYS_WAITPID, + SystemCall::WaitPid, argn!(pid.value()), argp!(status as *mut i32) ) @@ -240,7 +240,7 @@ pub fn sys_ioctl( ) -> Result { Errno::from_syscall(unsafe { syscall!( - abi::SYS_IOCTL, + SystemCall::Ioctl, argn!(u32::from(fd)), argn!(cmd), argn!(ptr), @@ -252,19 +252,19 @@ pub fn sys_ioctl( #[inline(always)] pub fn sys_ex_getcputime() -> Result { Errno::from_syscall(unsafe { - syscall!(abi::SYS_EX_GETCPUTIME) + syscall!(SystemCall::GetCpuTime) }).map(|e| Duration::from_nanos(e as u64)) } #[inline(always)] pub fn sys_ex_signal(entry: usize, stack: usize) -> Result<(), Errno> { - Errno::from_syscall_unit(unsafe { syscall!(abi::SYS_EX_SIGNAL, argn!(entry), argn!(stack)) }) + Errno::from_syscall_unit(unsafe { syscall!(SystemCall::SetSignalEntry, argn!(entry), argn!(stack)) }) } #[inline(always)] pub fn sys_ex_sigreturn() -> ! { unsafe { - syscall!(abi::SYS_EX_SIGRETURN); + syscall!(SystemCall::SignalReturn); } unreachable!(); } @@ -273,7 +273,7 @@ pub fn sys_ex_sigreturn() -> ! { pub fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( - abi::SYS_EX_KILL, + SystemCall::SendSignal, argn!(isize::from(pid)), argn!(signum as u32) ) @@ -283,35 +283,28 @@ pub fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> Result<(), Errno> #[inline(always)] pub fn sys_ex_clone(entry: usize, stack: usize, arg: usize) -> Result { Errno::from_syscall(unsafe { - syscall!(abi::SYS_EX_CLONE, argn!(entry), argn!(stack), argn!(arg)) + syscall!(SystemCall::Clone, argn!(entry), argn!(stack), argn!(arg)) }) } #[inline(always)] pub fn sys_ex_thread_exit(status: ExitCode) -> ! { unsafe { - syscall!(abi::SYS_EX_THREAD_EXIT, argn!(i32::from(status))); + syscall!(SystemCall::Exit, argn!(i32::from(status)), argn!(1)); } unreachable!(); } #[inline(always)] pub fn sys_ex_thread_wait(tid: u32) -> Result { - Errno::from_syscall(unsafe { syscall!(abi::SYS_EX_THREAD_WAIT, argn!(tid)) }) + Errno::from_syscall(unsafe { syscall!(SystemCall::WaitTid, argn!(tid)) }) .map(|_| ExitCode::from(0)) } #[inline(always)] pub fn sys_ex_yield() { unsafe { - syscall!(abi::SYS_EX_YIELD); - } -} - -#[inline(always)] -pub fn sys_ex_undefined() { - unsafe { - syscall!(0); + syscall!(SystemCall::Yield); } } @@ -323,7 +316,7 @@ pub fn sys_select( ) -> Result { Errno::from_syscall(unsafe { syscall!( - abi::SYS_SELECT, + SystemCall::Select, argp!(read_fds .map(|e| e as *mut _) .unwrap_or(core::ptr::null_mut())), @@ -344,7 +337,7 @@ pub fn sys_faccessat( ) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( - abi::SYS_FACCESSAT, + SystemCall::Access, argn!(FileDescriptor::into_i32(fd)), argp!(name.as_ptr()), argn!(name.len()), @@ -357,6 +350,6 @@ pub fn sys_faccessat( #[inline(always)] pub fn sys_ex_gettid() -> u32 { unsafe { - syscall!(abi::SYS_EX_GETTID) as u32 + syscall!(SystemCall::GetTid) as u32 } } diff --git a/user/src/fuzzy/main.rs b/user/src/fuzzy/main.rs index c87864f..8cde8fa 100644 --- a/user/src/fuzzy/main.rs +++ b/user/src/fuzzy/main.rs @@ -5,7 +5,7 @@ #[macro_use] extern crate libusr; -use libusr::sys::{abi, stat::Stat, Signal}; +use libusr::sys::{abi::SystemCall, stat::Stat, Signal}; use libusr::signal::{self, SignalHandler}; static mut STATE: u64 = 0; @@ -122,12 +122,12 @@ fn main() -> i32 { // Test non-utf8 input fed into syscalls expecting strings // let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore); - for _ in 0..10000 { + for _ in 0..100 { random_bytes(&mut buf); let mut stat = Stat::default(); unsafe { - syscall!(abi::SYS_FSTATAT, (-2i32) as usize, buf.as_mut_ptr() as usize, buf.len(), (&mut stat) as *mut _ as usize); + syscall!(SystemCall::FileStatus.repr(), (-2i32) as usize, buf.as_mut_ptr() as usize, buf.len(), (&mut stat) as *mut _ as usize); } } // signal::set_handler(Signal::InvalidSystemCall, old_signal); diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 64ea822..f0a32e7 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -41,6 +41,16 @@ fn main() -> i32 { let mut buf = [0; 256]; let mut stdin = io::stdin(); + let delay = libusr::thread::spawn(|| { + let mut t = [0; 2]; + libusr::sys::sys_ex_nanosleep(1_000_000_000, &mut t); + }); + + delay.join(); + + libusr::signal::set_handler(libusr::sys::Signal::Interrupt, libusr::signal::SignalHandler::Ignore); + libusr::sys::sys_ex_kill(libusr::sys::SignalDestination::This, libusr::sys::Signal::Interrupt); + loop { print!("> "); let line = readline(&mut stdin, &mut buf).unwrap(); From 1820009deef89e052f64f9523a6ff870d68e8a3f Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 21 Nov 2021 12:36:20 +0200 Subject: [PATCH 26/42] feature: "aggressive" syscall memory checking --- kernel/Cargo.toml | 2 ++ kernel/src/syscall/arg.rs | 70 +++++++++++---------------------------- 2 files changed, 22 insertions(+), 50 deletions(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index eee87ea..f5b3402 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -23,9 +23,11 @@ kernel-macros = { path = "macros" } cortex-a = { version = "6.x.x" } [features] +default = ["aggressive_syscall"] pl011 = [] pl031 = [] verbose = [] +aggressive_syscall = [] mach_qemu = ["pl011", "pl031"] mach_orangepi3 = [] diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 72a377d..caedd58 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -4,6 +4,24 @@ use crate::mem; use core::mem::size_of; use libsys::error::Errno; +// TODO _mut() versions checking whether pages are actually writable + +macro_rules! invalid_memory { + ($($args:tt)+) => { + warnln!($($args)+); + #[cfg(feature = "aggressive_syscall")] + { + use libsys::signal::Signal; + use crate::proc::Thread; + + let thread = Thread::current(); + let proc = thread.owner().unwrap(); + proc.enter_fault_signal(thread, Signal::SegmentationFault); + } + return Err(Errno::InvalidArgument); + } +} + fn translate(virt: usize) -> Option { let mut res: usize; unsafe { @@ -33,23 +51,21 @@ pub fn validate_user_ptr_struct_option<'a, T>(base: usize) -> Result(base: usize, len: usize) -> Result<&'a mut [u8], Errno> { if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET { - warnln!( + invalid_memory!( "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!( + invalid_memory!( "User region refers to unmapped memory: base={:#x}, len={:#x} (page {:#x})", base, len, i * mem::PAGE_SIZE ); - return Err(Errno::InvalidArgument); } } @@ -77,49 +93,3 @@ pub fn validate_user_str<'a>(base: usize, len: usize) -> Result<&'a str, Errno> Errno::InvalidArgument }) } -// if base > mem::KERNEL_OFFSET { -// warnln!("User string refers to kernel memory: base={:#x}", base); -// return Err(Errno::InvalidArgument); -// } -// -// let base_ptr = base as *const u8; -// let mut len = 0; -// let mut page_valid = false; -// loop { -// if len == limit { -// warnln!("User string exceeded limit: base={:#x}", base); -// return Err(Errno::InvalidArgument); -// } -// -// if (base + len) % mem::PAGE_SIZE == 0 { -// page_valid = false; -// } -// -// if !page_valid && translate((base + len) & !0xFFF).is_none() { -// warnln!( -// "User string refers to unmapped memory: base={:#x}, off={:#x}", -// base, -// len -// ); -// return Err(Errno::InvalidArgument); -// } -// -// page_valid = true; -// -// let byte = unsafe { *base_ptr.add(len) }; -// if byte == 0 { -// break; -// } -// -// len += 1; -// } -// -// let slice = unsafe { core::slice::from_raw_parts(base_ptr, len) }; -// core::str::from_utf8(slice).map_err(|_| { -// warnln!( -// "User string contains invalid UTF-8 characters: base={:#x}", -// base -// ); -// Errno::InvalidArgument -// }) -// } From 7c809f3b116d06764b1026bec131a0e89f88a3d4 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 21 Nov 2021 14:01:48 +0200 Subject: [PATCH 27/42] feature: extended user pointer validation --- kernel/src/arch/aarch64/exception.rs | 3 +- kernel/src/dev/tty.rs | 6 +- kernel/src/mem/virt/table.rs | 15 +++-- kernel/src/syscall/arg.rs | 90 +++++++++++++++++++++------- kernel/src/syscall/mod.rs | 31 +++++----- user/src/shell/main.rs | 10 ---- 6 files changed, 97 insertions(+), 58 deletions(-) diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 21085dc..5be036d 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -88,8 +88,9 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { match err_code { EC_DATA_ABORT_EL0 | EC_DATA_ABORT_ELX => { let far = FAR_EL1.get() as usize; + let iss = esr & 0x1FFFFFF; - if far < mem::KERNEL_OFFSET && sched::is_ready() { + if iss & (1 << 6) != 0 && far < mem::KERNEL_OFFSET && sched::is_ready() { let thread = Thread::current(); let proc = thread.owner().unwrap(); diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 43f94bc..4ab8da4 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -8,7 +8,7 @@ use libsys::{ ioctl::IoctlCmd }; use core::mem::size_of; -use crate::syscall::arg::validate_user_ptr_struct; +use crate::syscall::arg; #[derive(Debug)] struct CharRingInner { @@ -45,12 +45,12 @@ pub trait TtyDevice: SerialDevice { match cmd { IoctlCmd::TtyGetAttributes => { // TODO validate size - let res = validate_user_ptr_struct::(ptr)?; + let res = arg::struct_mut::(ptr)?; *res = self.ring().config.lock().clone(); Ok(size_of::()) }, IoctlCmd::TtySetAttributes => { - let src = validate_user_ptr_struct::(ptr)?; + let src = arg::struct_ref::(ptr)?; *self.ring().config.lock() = src.clone(); Ok(size_of::()) }, diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index e49d5db..12985a0 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -271,12 +271,17 @@ impl Space { todo!(); // res.map(virt_addr, dst_phys, flags)?; } else { - // TODO only apply CoW to writable pages - flags |= MapAttributes::AP_BOTH_READONLY | MapAttributes::EX_COW; - l2_table[l2i].set_cow(); - unsafe { - asm!("tlbi vaae1, {}", in(reg) virt_addr); + let writable = flags & MapAttributes::AP_BOTH_READONLY == MapAttributes::AP_BOTH_READWRITE; + + if writable { + flags |= MapAttributes::AP_BOTH_READONLY | MapAttributes::EX_COW; + l2_table[l2i].set_cow(); + + unsafe { + asm!("tlbi vaae1, {}", in(reg) virt_addr); + } } + res.map(virt_addr, dst_phys, flags)?; } } diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index caedd58..952a9e5 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -1,6 +1,7 @@ //! System call argument ABI helpers use crate::mem; +use core::alloc::Layout; use core::mem::size_of; use libsys::error::Errno; @@ -22,34 +23,62 @@ macro_rules! invalid_memory { } } -fn translate(virt: usize) -> Option { +#[inline(always)] +fn is_el0_accessible(virt: usize, write: bool) -> bool { 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 + if write { + asm!("at s1e0w, {}; mrs {}, par_el1", in(reg) virt, out(reg) res); + } else { + asm!("at s1e0r, {}; mrs {}, par_el1", in(reg) virt, out(reg) res); + } } + res & 1 == 0 } -/// Unwraps a slim structure pointer -pub fn validate_user_ptr_struct<'a, T>(base: usize) -> Result<&'a mut T, Errno> { - validate_user_ptr_struct_option(base).and_then(|e| e.ok_or(Errno::InvalidArgument)) +pub fn struct_ref<'a, T>(base: usize) -> Result<&'a T, Errno> { + let layout = Layout::new::(); + if base % layout.align() != 0 { + invalid_memory!( + "Structure pointer is misaligned: base={:#x}, expected {:?}", + base, + layout + ); + } + let bytes = buf_ref(base, layout.size())?; + Ok(unsafe { &*(bytes.as_ptr() as *const T) }) } -pub fn validate_user_ptr_struct_option<'a, T>(base: usize) -> Result, Errno> { +pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> { + let layout = Layout::new::(); + if base % layout.align() != 0 { + invalid_memory!( + "Structure pointer is misaligned: base={:#x}, expected {:?}", + base, + layout + ); + } + let bytes = buf_mut(base, layout.size())?; + Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) +} + +pub fn option_struct_ref<'a, T>(base: usize) -> Result, Errno> { if base == 0 { Ok(None) } else { - let bytes = validate_user_ptr(base, size_of::())?; - Ok(Some(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })) + struct_ref(base).map(Some) } } -/// Unwraps an user buffer reference -pub fn validate_user_ptr<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Errno> { +pub fn option_struct_mut<'a, T>(base: usize) -> Result, Errno> { + if base == 0 { + Ok(None) + } else { + struct_mut(base).map(Some) + } +} + +fn validate_ptr(base: usize, len: usize, writable: bool) -> Result<(), Errno> { if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET { invalid_memory!( "User region refers to kernel memory: base={:#x}, len={:#x}", @@ -59,9 +88,9 @@ pub fn validate_user_ptr<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Er } for i in (base / mem::PAGE_SIZE)..((base + len + mem::PAGE_SIZE - 1) / mem::PAGE_SIZE) { - if translate(i * mem::PAGE_SIZE).is_none() { + if !is_el0_accessible(i * mem::PAGE_SIZE, writable) { invalid_memory!( - "User region refers to unmapped memory: base={:#x}, len={:#x} (page {:#x})", + "User region refers to inaccessible/unmapped memory: base={:#x}, len={:#x} (page {:#x})", base, len, i * mem::PAGE_SIZE @@ -69,21 +98,38 @@ pub fn validate_user_ptr<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Er } } + Ok(()) +} + +pub fn buf_ref<'a>(base: usize, len: usize) -> Result<&'a [u8], Errno> { + validate_ptr(base, len, false)?; + Ok(unsafe { core::slice::from_raw_parts(base as *const u8, len) }) +} + +pub fn buf_mut<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Errno> { + validate_ptr(base, len, true)?; Ok(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, len) }) } -/// Unwraps a nullable user buffer reference -pub fn validate_user_ptr_null<'a>(base: usize, len: usize) -> Result, Errno> { +pub fn option_buf_ref<'a>(base: usize, len: usize) -> Result, Errno> { if base == 0 { Ok(None) } else { - validate_user_ptr(base, len).map(Some) + buf_ref(base, len).map(Some) + } +} + +pub fn option_buf_mut<'a>(base: usize, len: usize) -> Result, Errno> { + if base == 0 { + Ok(None) + } else { + buf_mut(base, len).map(Some) } } /// Unwraps user string argument -pub fn validate_user_str<'a>(base: usize, len: usize) -> Result<&'a str, Errno> { - let bytes = validate_user_ptr(base, len)?; +pub fn str_ref<'a>(base: usize, len: usize) -> Result<&'a str, Errno> { + let bytes = buf_ref(base, len)?; core::str::from_utf8(bytes).map_err(|_| { warnln!( "User string contains invalid UTF-8 characters: base={:#x}, len={:#x}", diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index fe4b483..520547e 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -19,7 +19,6 @@ use libsys::{ use vfs::VnodeRef; pub mod arg; -pub use arg::*; /// Creates a "fork" process from current one using its register frame. /// See [Process::fork()]. @@ -59,7 +58,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let proc = Process::current(); let fd = FileDescriptor::from(args[0] as u32); let mut io = proc.io.lock(); - let buf = validate_user_ptr(args[1], args[2])?; + let buf = arg::buf_mut(args[1], args[2])?; io.file(fd)?.borrow_mut().read(buf) }, @@ -67,13 +66,13 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let proc = Process::current(); let fd = FileDescriptor::from(args[0] as u32); let mut io = proc.io.lock(); - let buf = validate_user_ptr(args[1], args[2])?; + let buf = arg::buf_ref(args[1], args[2])?; io.file(fd)?.borrow_mut().write(buf) }, SystemCall::Open => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; - let path = validate_user_str(args[1], args[2])?; + let path = arg::str_ref(args[1], args[2])?; let mode = FileMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; let opts = OpenFlags::from_bits(args[4] as u32).ok_or(Errno::InvalidArgument)?; @@ -99,8 +98,8 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { }, SystemCall::FileStatus => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; - let filename = validate_user_str(args[1], args[2])?; - let buf = validate_user_ptr_struct::(args[3])?; + let filename = arg::str_ref(args[1], args[2])?; + let buf = arg::struct_mut::(args[3])?; let flags = args[4] as u32; let proc = Process::current(); @@ -119,8 +118,8 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { node.ioctl(cmd, args[2], args[3]) }, SystemCall::Select => { - let rfds = validate_user_ptr_struct_option::(args[0])?; - let wfds = validate_user_ptr_struct_option::(args[1])?; + let rfds = arg::option_struct_mut::(args[0])?; + let wfds = arg::option_struct_mut::(args[1])?; let timeout = if args[2] == 0 { None } else { @@ -131,7 +130,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { }, SystemCall::Access => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; - let path = validate_user_str(args[1], args[2])?; + let path = arg::str_ref(args[1], args[2])?; let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; let flags = args[4] as u32; @@ -156,14 +155,14 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let node = { let proc = Process::current(); let mut io = proc.io.lock(); - let filename = validate_user_str(args[0], args[1])?; + let filename = arg::str_ref(args[0], args[1])?; // TODO argv, envp array passing ABI? let node = io.ioctx().find(None, filename, true)?; drop(io); node }; let file = node.open(OpenFlags::O_RDONLY)?; - Process::execve(|space| elf::load_elf(space, file), 0).unwrap(); + Process::execve(move |space| elf::load_elf(space, file), 0).unwrap(); panic!(); }, SystemCall::Exit => { @@ -181,7 +180,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { SystemCall::WaitPid => { // TODO special "pid" values let pid = unsafe { Pid::from_raw(args[0] as u32) }; - let status = validate_user_ptr_struct::(args[1])?; + let status = arg::struct_mut::(args[1])?; match Process::waitpid(pid) { Ok(exit) => { @@ -204,7 +203,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { SystemCall::GetPid => todo!(), SystemCall::GetTid => Ok(Thread::current().id() as usize), SystemCall::Sleep => { - let rem_buf = validate_user_ptr_null(args[1], size_of::() * 2)?; + let rem_buf = arg::option_buf_ref(args[1], size_of::() * 2)?; let mut rem = Duration::new(0, 0); let res = wait::sleep(Duration::from_nanos(args[0] as u64), &mut rem); if res == Err(Errno::Interrupt) { @@ -249,11 +248,9 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { // Debugging SystemCall::DebugTrace => { - let buf = validate_user_ptr(args[0], args[1])?; + let buf = arg::str_ref(args[0], args[1])?; print!(Level::Debug, "[trace] "); - for &byte in buf.iter() { - print!(Level::Debug, "{}", byte as char); - } + print!(Level::Debug, "{}", buf); println!(Level::Debug, ""); Ok(args[1]) }, diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index f0a32e7..64ea822 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -41,16 +41,6 @@ fn main() -> i32 { let mut buf = [0; 256]; let mut stdin = io::stdin(); - let delay = libusr::thread::spawn(|| { - let mut t = [0; 2]; - libusr::sys::sys_ex_nanosleep(1_000_000_000, &mut t); - }); - - delay.join(); - - libusr::signal::set_handler(libusr::sys::Signal::Interrupt, libusr::signal::SignalHandler::Ignore); - libusr::sys::sys_ex_kill(libusr::sys::SignalDestination::This, libusr::sys::Signal::Interrupt); - loop { print!("> "); let line = readline(&mut stdin, &mut buf).unwrap(); From da36ecef13e1a894f90fd10203c5e9510a610cec Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 22 Nov 2021 12:00:57 +0200 Subject: [PATCH 28/42] fix: ptr validation did not work for CoW pages --- kernel/src/syscall/arg.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 952a9e5..58d3d1f 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -4,6 +4,7 @@ use crate::mem; use core::alloc::Layout; use core::mem::size_of; use libsys::error::Errno; +use crate::proc::Process; // TODO _mut() versions checking whether pages are actually writable @@ -78,7 +79,7 @@ pub fn option_struct_mut<'a, T>(base: usize) -> Result, Errno> } } -fn validate_ptr(base: usize, len: usize, writable: bool) -> Result<(), Errno> { +fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> { if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET { invalid_memory!( "User region refers to kernel memory: base={:#x}, len={:#x}", @@ -87,13 +88,31 @@ fn validate_ptr(base: usize, len: usize, writable: bool) -> Result<(), Errno> { ); } + let process = Process::current(); + for i in (base / mem::PAGE_SIZE)..((base + len + mem::PAGE_SIZE - 1) / mem::PAGE_SIZE) { - if !is_el0_accessible(i * mem::PAGE_SIZE, writable) { + if !is_el0_accessible(i * mem::PAGE_SIZE, write) { + // It's possible a CoW page hasn't yet been cloned when trying + // a write access + let res = if write { + process.manipulate_space(|space| { + space.try_cow_copy(i * mem::PAGE_SIZE) + }) + } else { + todo!(); + Err(Errno::DoesNotExist) + }; + + if res.is_ok() { + continue; + } + invalid_memory!( - "User region refers to inaccessible/unmapped memory: base={:#x}, len={:#x} (page {:#x})", + "User region refers to inaccessible/unmapped memory: base={:#x}, len={:#x} (page {:#x}, write={})", base, len, - i * mem::PAGE_SIZE + i * mem::PAGE_SIZE, + write ); } } From 4cfa1f295859d87f50419dae223fd54fdfcf7aec Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 22 Nov 2021 14:02:29 +0200 Subject: [PATCH 29/42] feature: faster single-page alloc --- kernel/src/mem/phys/manager.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 4ad8b48..74ce890 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -17,6 +17,7 @@ pub struct SimpleManager { pages: &'static mut [PageInfo], stats: PageStatistics, base_index: usize, + last_index: usize, } impl SimpleManager { pub(super) unsafe fn initialize(base: usize, at: usize, count: usize) -> Self { @@ -34,6 +35,7 @@ impl SimpleManager { } Self { base_index: base / PAGE_SIZE, + last_index: 0, stats: PageStatistics { available: 0, kernel: 0, @@ -57,11 +59,21 @@ impl SimpleManager { } fn alloc_single_index(&mut self, pu: PageUsage) -> Result { - for index in 0..self.pages.len() { + for index in self.last_index..self.pages.len() { let page = &mut self.pages[index]; if page.usage == PageUsage::Available { page.usage = pu; page.refcount = 1; + self.last_index = index; + return Ok(index); + } + } + for index in 0..self.last_index { + let page = &mut self.pages[index]; + if page.usage == PageUsage::Available { + page.usage = pu; + page.refcount = 1; + self.last_index = index; return Ok(index); } } @@ -135,6 +147,8 @@ unsafe impl Manager for SimpleManager { assert_eq!(page.refcount, 1); page.usage = PageUsage::Available; page.refcount = 0; + + self.last_index = index; } usage From fabf4e8d3f428b134dcfd3db9592f26cf459420f Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 22 Nov 2021 15:42:43 +0200 Subject: [PATCH 30/42] refactor: fix non-doc warnings --- fs/vfs/src/node.rs | 2 +- kernel/src/arch/aarch64/exception.rs | 3 +- kernel/src/init.rs | 2 +- kernel/src/mem/phys/manager.rs | 50 ++++++++--------- kernel/src/proc/process.rs | 11 ++-- kernel/src/proc/sched.rs | 2 +- kernel/src/proc/thread.rs | 17 ++++-- kernel/src/proc/wait.rs | 77 +++++++++++++------------- kernel/src/syscall/arg.rs | 3 +- libsys/src/calls.rs | 2 +- libusr/src/file.rs | 4 +- libusr/src/io/error.rs | 1 + libusr/src/io/mod.rs | 2 +- libusr/src/io/stdio.rs | 80 +++++++++++++++------------- libusr/src/io/writer.rs | 2 +- libusr/src/os.rs | 2 - libusr/src/signal.rs | 10 ++-- libusr/src/sys/mod.rs | 5 -- libusr/src/thread.rs | 43 ++++++++------- user/src/fuzzy/main.rs | 9 ++-- user/src/shell/main.rs | 6 +-- 21 files changed, 175 insertions(+), 158 deletions(-) diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 8ff2185..1e066b9 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -414,7 +414,7 @@ impl Vnode { } } - pub fn check_access(&self, ioctx: &Ioctx, access: AccessMode) -> Result<(), Errno> { + pub fn check_access(&self, _ioctx: &Ioctx, access: AccessMode) -> Result<(), Errno> { let props = self.props.borrow(); let mode = props.mode; diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 5be036d..ff9a74e 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -4,7 +4,7 @@ use crate::arch::machine; use crate::debug::Level; use crate::dev::irq::{IntController, IrqContext}; use crate::mem; -use crate::proc::{sched, Thread, Process}; +use crate::proc::{sched, Thread}; use crate::syscall; use cortex_a::registers::{ESR_EL1, FAR_EL1}; use libsys::{abi::SystemCall, signal::Signal}; @@ -120,7 +120,6 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { let num = SystemCall::from_repr(exc.x[8]); if num.is_none() { todo!(); - return; } let num = num.unwrap(); diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 53aea9f..9744253 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -3,7 +3,7 @@ use crate::config::{ConfigKey, CONFIG}; use crate::fs::{devfs, MemfsBlockAlloc}; use crate::mem; -use crate::proc::{wait, elf, Process}; +use crate::proc::{elf, Process}; use libsys::stat::{FileDescriptor, OpenFlags}; use memfs::Ramfs; use vfs::{Filesystem, Ioctx}; diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 74ce890..de4ba15 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -93,18 +93,18 @@ impl SimpleManager { self.stats.available -= count; } - fn update_stats_free(&mut self, pu: PageUsage, count: usize) { - let field = match pu { - PageUsage::Kernel => &mut self.stats.kernel, - PageUsage::KernelHeap => &mut self.stats.kernel_heap, - PageUsage::Paging => &mut self.stats.paging, - PageUsage::UserPrivate => &mut self.stats.user_private, - PageUsage::Filesystem => &mut self.stats.filesystem, - _ => panic!("TODO {:?}", pu), - }; - *field -= count; - self.stats.available += count; - } + // fn update_stats_free(&mut self, pu: PageUsage, count: usize) { + // let field = match pu { + // PageUsage::Kernel => &mut self.stats.kernel, + // PageUsage::KernelHeap => &mut self.stats.kernel_heap, + // PageUsage::Paging => &mut self.stats.paging, + // PageUsage::UserPrivate => &mut self.stats.user_private, + // PageUsage::Filesystem => &mut self.stats.filesystem, + // _ => panic!("TODO {:?}", pu), + // }; + // *field -= count; + // self.stats.available += count; + // } } unsafe impl Manager for SimpleManager { fn alloc_page(&mut self, pu: PageUsage) -> Result { @@ -134,25 +134,21 @@ unsafe impl Manager for SimpleManager { Err(Errno::OutOfMemory) } fn free_page(&mut self, addr: usize) -> Result<(), Errno> { - let usage = { - let index = self.page_index(addr); - let page = &mut self.pages[index]; + let index = self.page_index(addr); + let page = &mut self.pages[index]; - let usage = page.usage; - assert!(page.usage != PageUsage::Reserved && page.usage != PageUsage::Available); + assert!(page.usage != PageUsage::Reserved && page.usage != PageUsage::Available); - if page.refcount > 1 { - page.refcount -= 1; - } else { - assert_eq!(page.refcount, 1); - page.usage = PageUsage::Available; - page.refcount = 0; + if page.refcount > 1 { + page.refcount -= 1; + } else { + assert_eq!(page.refcount, 1); + page.usage = PageUsage::Available; + page.refcount = 0; - self.last_index = index; - } + self.last_index = index; + } - usage - }; // FIXME // self.update_stats_free(usage, 1); diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 06bbed6..e11f518 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -6,11 +6,10 @@ use crate::mem::{ virt::{MapAttributes, Space}, }; use crate::proc::{ - wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED, THREADS, + wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED, }; use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard}; use alloc::{rc::Rc, vec::Vec}; -use core::cell::UnsafeCell; use core::sync::atomic::{AtomicU32, Ordering}; use libsys::{ error::Errno, @@ -108,7 +107,7 @@ impl Process { /// Sets a pending signal for a process pub fn set_signal(&self, signal: Signal) { - let mut lock = self.inner.lock(); + let lock = self.inner.lock(); let main_thread = Thread::get(lock.threads[0]).unwrap(); // TODO check that `signal` is not a fault signal @@ -133,7 +132,11 @@ impl Process { } } - fn enter_signal_on(mut inner: IrqSafeSpinLockGuard, thread: ThreadRef, signal: Signal) { + fn enter_signal_on( + mut inner: IrqSafeSpinLockGuard, + thread: ThreadRef, + signal: Signal, + ) { let ttbr0 = inner.space.as_mut().unwrap().address_phys() | ((inner.id.asid() as usize) << 48); drop(inner); diff --git a/kernel/src/proc/sched.rs b/kernel/src/proc/sched.rs index 28f002e..ccdc751 100644 --- a/kernel/src/proc/sched.rs +++ b/kernel/src/proc/sched.rs @@ -1,5 +1,5 @@ //! -use crate::proc::{Pid, Process, ProcessRef, Thread, ThreadRef, PROCESSES, THREADS}; +use crate::proc::{Thread, ThreadRef, THREADS}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use alloc::{collections::VecDeque, rc::Rc}; diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index 3e4ed85..7c23763 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -2,10 +2,14 @@ use crate::arch::aarch64::exception::ExceptionFrame; use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; -use alloc::{rc::Rc, vec::Vec}; +use alloc::rc::Rc; use core::cell::UnsafeCell; use core::sync::atomic::{AtomicU32, Ordering}; -use libsys::{error::Errno, proc::{Pid, ExitCode}, signal::Signal}; +use libsys::{ + error::Errno, + proc::{ExitCode, Pid}, + signal::Signal, +}; pub use crate::arch::platform::context::{self, Context}; @@ -297,7 +301,7 @@ impl Thread { panic!("Already handling a signal (maybe handle this case)"); } - let mut lock = self.inner.lock(); + let lock = self.inner.lock(); if lock.signal_entry == 0 || lock.signal_stack == 0 { drop(lock); Process::exit_thread(self, ExitCode::from(-1)); @@ -317,7 +321,12 @@ impl Thread { assert_eq!(lock.state, State::Running); unsafe { - signal_ctx.setup_signal_entry(lock.signal_entry, signal as usize, ttbr0, lock.signal_stack); + signal_ctx.setup_signal_entry( + lock.signal_entry, + signal as usize, + ttbr0, + lock.signal_stack, + ); } drop(lock); diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index 2d21c8e..5885275 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -2,11 +2,11 @@ use crate::arch::machine; use crate::dev::timer::TimestampSource; -use crate::proc::{self, sched::SCHED, Process, Thread, ThreadRef}; +use crate::proc::{sched::SCHED, Thread, ThreadRef}; use crate::sync::IrqSafeSpinLock; use alloc::collections::LinkedList; use core::time::Duration; -use libsys::{error::Errno, stat::FdSet, proc::Pid}; +use libsys::{error::Errno, stat::FdSet}; /// Wait channel structure. Contains a queue of processes /// waiting for some event to happen. @@ -61,46 +61,45 @@ pub fn select( mut wfds: Option<&mut FdSet>, timeout: Option, ) -> Result { - todo!(); - // // TODO support wfds - // if wfds.is_some() || rfds.is_none() { - // todo!(); - // } - // let read = rfds.as_deref().map(FdSet::clone); - // let write = wfds.as_deref().map(FdSet::clone); - // rfds.as_deref_mut().map(FdSet::reset); - // wfds.as_deref_mut().map(FdSet::reset); + if wfds.is_none() && rfds.is_none() { + todo!(); + } + let read = rfds.as_deref().map(FdSet::clone); + let write = wfds.as_deref().map(FdSet::clone); + rfds.as_deref_mut().map(FdSet::reset); + wfds.as_deref_mut().map(FdSet::reset); - // let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap()); - // let mut io = proc.io.lock(); + let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap()); + let proc = thread.owner().unwrap(); + let mut io = proc.io.lock(); - // loop { - // if let Some(read) = &read { - // for fd in read.iter() { - // let file = io.file(fd)?; - // if file.borrow().is_ready(false)? { - // rfds.as_mut().unwrap().set(fd); - // return Ok(1); - // } - // } - // } - // if let Some(write) = &write { - // for fd in write.iter() { - // let file = io.file(fd)?; - // if file.borrow().is_ready(true)? { - // wfds.as_mut().unwrap().set(fd); - // return Ok(1); - // } - // } - // } + loop { + if let Some(read) = &read { + for fd in read.iter() { + let file = io.file(fd)?; + if file.borrow().is_ready(false)? { + rfds.as_mut().unwrap().set(fd); + return Ok(1); + } + } + } + if let Some(write) = &write { + for fd in write.iter() { + let file = io.file(fd)?; + if file.borrow().is_ready(true)? { + wfds.as_mut().unwrap().set(fd); + return Ok(1); + } + } + } - // // Suspend - // match WAIT_SELECT.wait(deadline) { - // Err(Errno::TimedOut) => return Ok(0), - // Err(e) => return Err(e), - // Ok(_) => {} - // } - // } + // Suspend + match WAIT_SELECT.wait(deadline) { + Err(Errno::TimedOut) => return Ok(0), + Err(e) => return Err(e), + Ok(_) => {} + } + } } impl Wait { diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 58d3d1f..937ec98 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -2,7 +2,6 @@ use crate::mem; use core::alloc::Layout; -use core::mem::size_of; use libsys::error::Errno; use crate::proc::Process; @@ -100,7 +99,7 @@ fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> { }) } else { todo!(); - Err(Errno::DoesNotExist) + // Err(Errno::DoesNotExist) }; if res.is_ok() { diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 20acb26..b5e13e7 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -191,7 +191,7 @@ pub fn sys_fstatat( /// System call #[inline(always)] pub unsafe fn sys_fork() -> Result, Errno> { - Errno::from_syscall(unsafe { syscall!(SystemCall::Fork) }).map(|res| { + Errno::from_syscall(syscall!(SystemCall::Fork)).map(|res| { if res != 0 { Some(unsafe { Pid::from_raw(res as u32) }) } else { diff --git a/libusr/src/file.rs b/libusr/src/file.rs index 80e7727..7603252 100644 --- a/libusr/src/file.rs +++ b/libusr/src/file.rs @@ -1,6 +1,4 @@ use crate::io::{AsRawFd, Error}; -use crate::os; -use crate::trace; use libsys::stat::FileDescriptor; pub struct File { @@ -8,7 +6,7 @@ pub struct File { } impl File { - pub fn open(path: &str) -> Result { + pub fn open(_path: &str) -> Result { todo!() } } diff --git a/libusr/src/io/error.rs b/libusr/src/io/error.rs index 9818834..64b570a 100644 --- a/libusr/src/io/error.rs +++ b/libusr/src/io/error.rs @@ -2,6 +2,7 @@ use libsys::error::Errno; #[derive(Debug)] pub struct Error { + #[allow(dead_code)] repr: Repr, } diff --git a/libusr/src/io/mod.rs b/libusr/src/io/mod.rs index ac29239..f4c9ee3 100644 --- a/libusr/src/io/mod.rs +++ b/libusr/src/io/mod.rs @@ -27,6 +27,6 @@ pub trait AsRawFd { pub fn stat(pathname: &str) -> Result { let mut buf = Stat::default(); // TODO error handling - let res = sys_fstatat(None, pathname, &mut buf, 0).unwrap(); + sys_fstatat(None, pathname, &mut buf, 0).unwrap(); Ok(buf) } diff --git a/libusr/src/io/stdio.rs b/libusr/src/io/stdio.rs index de7fc99..17f8afe 100644 --- a/libusr/src/io/stdio.rs +++ b/libusr/src/io/stdio.rs @@ -1,40 +1,40 @@ -use libsys::{ - stat::FileDescriptor, - calls::{sys_read, sys_write} -}; -use crate::io::{Read, Write, Error}; -use crate::sync::{Mutex, MutexGuard}; +use crate::io::{Error, Read, Write}; +use crate::sync::Mutex; use core::fmt; +use libsys::{ + calls::{sys_read, sys_write}, + stat::FileDescriptor, +}; struct InputInner { - fd: FileDescriptor + fd: FileDescriptor, } struct OutputInner { - fd: FileDescriptor + fd: FileDescriptor, } -pub struct StdinLock<'a> { - lock: MutexGuard<'a, InputInner> -} - -pub struct StdoutLock<'a> { - lock: MutexGuard<'a, OutputInner> -} - -pub struct StderrLock<'a> { - lock: MutexGuard<'a, OutputInner> -} +//pub struct StdinLock<'a> { +// lock: MutexGuard<'a, InputInner> +//} +// +//pub struct StdoutLock<'a> { +// lock: MutexGuard<'a, OutputInner> +//} +// +//pub struct StderrLock<'a> { +// lock: MutexGuard<'a, OutputInner> +//} pub struct Stdin { inner: &'static Mutex, } pub struct Stdout { - inner: &'static Mutex + inner: &'static Mutex, } pub struct Stderr { - inner: &'static Mutex + inner: &'static Mutex, } // STDIN @@ -51,6 +51,14 @@ impl Read for Stdin { } } +// impl Stdin { +// pub fn lock(&self) -> StdinLock { +// StdinLock { +// lock: self.inner.lock() +// } +// } +// } + // STDOUT/STDERR impl fmt::Write for OutputInner { @@ -89,21 +97,21 @@ impl Write for Stderr { } } -impl Stdout { - pub fn lock(&self) -> StdoutLock { - StdoutLock { - lock: self.inner.lock() - } - } -} - -impl Stderr { - pub fn lock(&self) -> StderrLock { - StderrLock { - lock: self.inner.lock() - } - } -} +// impl Stdout { +// pub fn lock(&self) -> StdoutLock { +// StdoutLock { +// lock: self.inner.lock() +// } +// } +// } +// +// impl Stderr { +// pub fn lock(&self) -> StderrLock { +// StderrLock { +// lock: self.inner.lock() +// } +// } +// } lazy_static! { static ref STDIN: Mutex = Mutex::new(InputInner { diff --git a/libusr/src/io/writer.rs b/libusr/src/io/writer.rs index 30ed6d8..9ddcc08 100644 --- a/libusr/src/io/writer.rs +++ b/libusr/src/io/writer.rs @@ -1,5 +1,5 @@ use core::fmt; -use crate::io::{self, Write}; +use crate::io::Write; #[macro_export] macro_rules! print { diff --git a/libusr/src/os.rs b/libusr/src/os.rs index 85a385a..f7d0f10 100644 --- a/libusr/src/os.rs +++ b/libusr/src/os.rs @@ -1,7 +1,5 @@ use crate::sys; use core::fmt; -use core::mem::{size_of, MaybeUninit}; -use libsys::{ioctl::IoctlCmd, stat::FileDescriptor, termios::Termios}; #[macro_export] macro_rules! trace { diff --git a/libusr/src/signal.rs b/libusr/src/signal.rs index e6fd5a0..f34793c 100644 --- a/libusr/src/signal.rs +++ b/libusr/src/signal.rs @@ -1,11 +1,15 @@ -use libsys::{calls::{sys_exit, sys_ex_sigreturn}, signal::Signal, proc::ExitCode}; -use crate::{trace, thread}; +use crate::trace; +use libsys::{ + calls::{sys_ex_sigreturn, sys_exit}, + proc::ExitCode, + signal::Signal, +}; #[derive(Clone, Copy)] pub enum SignalHandler { Func(fn(Signal) -> ()), Ignore, - Terminate + Terminate, } // TODO per-thread signal handler table diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs index 8a6ab86..9b43f6b 100644 --- a/libusr/src/sys/mod.rs +++ b/libusr/src/sys/mod.rs @@ -23,11 +23,6 @@ impl RawMutex { self.inner.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_ok() } - #[inline] - unsafe fn is_locked(&self) -> bool { - self.inner.load(Ordering::Acquire) - } - #[inline] pub unsafe fn lock(&self) { while !self.try_lock() { diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs index 71df64e..266c11a 100644 --- a/libusr/src/thread.rs +++ b/libusr/src/thread.rs @@ -1,15 +1,13 @@ +use crate::signal; use alloc::{boxed::Box, sync::Arc, vec}; +use core::any::Any; use core::cell::UnsafeCell; +use core::fmt; use core::mem::MaybeUninit; use libsys::{ - calls::{sys_ex_clone, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait, sys_ex_gettid}, - error::Errno, + calls::{sys_ex_clone, sys_ex_gettid, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait}, proc::ExitCode, }; -use core::sync::atomic::{AtomicU32, Ordering}; -use core::any::Any; -use crate::{trace, signal}; -use core::fmt; struct NativeData where @@ -24,7 +22,7 @@ where #[derive(Clone)] pub struct Thread { - id: u32 + id: u32, } pub type ThreadResult = Result>; @@ -32,7 +30,7 @@ pub type ThreadPacket = Arc>>>; pub struct JoinHandle { native: u32, - result: ThreadPacket + result: ThreadPacket, } impl Thread { @@ -43,26 +41,33 @@ impl Thread { impl fmt::Debug for Thread { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Thread").field("id", &self.id).finish_non_exhaustive() + f.debug_struct("Thread") + .field("id", &self.id) + .finish_non_exhaustive() } } impl JoinHandle { pub fn join(self) -> ThreadResult { sys_ex_thread_wait(self.native).unwrap(); - unsafe { Arc::try_unwrap(self.result).unwrap().into_inner().assume_init() } + unsafe { + Arc::try_unwrap(self.result) + .unwrap() + .into_inner() + .assume_init() + } } } unsafe fn init_common(signal_stack_pointer: *mut u8) { - let tid = sys_ex_gettid(); - asm!("msr tpidr_el0, {}", in(reg) tid); + let tid = sys_ex_gettid() as u64; + asm!("msr tpidr_el0, {:x}", in(reg) tid); // thread::current() should be valid at this point sys_ex_signal( signal::signal_handler as usize, - signal_stack_pointer as usize + signal_stack_pointer as usize, ) .unwrap(); } @@ -70,19 +75,19 @@ unsafe fn init_common(signal_stack_pointer: *mut u8) { pub(crate) unsafe fn init_main() { #[repr(align(16))] struct StackWrapper { - data: [u8; 8192] + data: [u8; 8192], } static mut STACK: StackWrapper = StackWrapper { data: [0; 8192] }; init_common(STACK.data.as_mut_ptr().add(8192)) } pub fn current() -> Thread { - let mut id: u32; + let mut id: u64; unsafe { - asm!("mrs {}, tpidr_el0", out(reg) id); + asm!("mrs {:x}, tpidr_el0", out(reg) id); } - Thread { id } + Thread { id: id as u32 } } pub fn spawn(f: F) -> JoinHandle @@ -101,7 +106,7 @@ where F: Send + 'static, T: Send + 'static, { - let (stack, len) = { + let (_stack, _len) = { // Setup signal handling let mut signal_stack = vec![0u8; 8192]; @@ -123,7 +128,7 @@ where sys_ex_thread_exit(ExitCode::from(0)); } - let native = unsafe { + let native = { let stack = stack.as_mut_ptr() as usize + stack.len(); let data: *mut NativeData = Box::into_raw(Box::new(NativeData { closure: f, diff --git a/user/src/fuzzy/main.rs b/user/src/fuzzy/main.rs index 8cde8fa..cfc7d4e 100644 --- a/user/src/fuzzy/main.rs +++ b/user/src/fuzzy/main.rs @@ -2,11 +2,13 @@ #![no_std] #![no_main] +#![allow(unused_macros)] +#![allow(dead_code)] + #[macro_use] extern crate libusr; -use libusr::sys::{abi::SystemCall, stat::Stat, Signal}; -use libusr::signal::{self, SignalHandler}; +use libusr::sys::{abi::SystemCall, stat::Stat}; static mut STATE: u64 = 0; @@ -115,9 +117,10 @@ fn main() -> i32 { // Test sys_ex_getcputime() let mut prev_time = libusr::sys::sys_ex_getcputime().unwrap().as_nanos(); - for _ in 0..100000 { + for _ in 0..1000 { let t = libusr::sys::sys_ex_getcputime().unwrap().as_nanos(); assert!(t >= prev_time); + prev_time = t; } // Test non-utf8 input fed into syscalls expecting strings diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 64ea822..b2a835e 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -6,7 +6,7 @@ extern crate libusr; extern crate alloc; use alloc::borrow::ToOwned; -use libusr::sys::{sys_faccessat, sys_exit, sys_execve, sys_waitpid, sys_fork, ExitCode, Errno, AccessMode}; +use libusr::sys::{sys_exit, sys_execve, sys_waitpid, sys_fork, ExitCode, Errno}; use libusr::io::{self, Read}; fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result, io::Error> { @@ -19,7 +19,7 @@ fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result ! { - sys_execve(&("/bin/".to_owned() + cmd)); + sys_execve(&("/bin/".to_owned() + cmd)).unwrap(); sys_exit(ExitCode::from(-1)); } @@ -52,7 +52,7 @@ fn main() -> i32 { continue; } - execute(line); + execute(line).ok(); } 0 } From 349418ed3685dd217245c3f17c54031e7337ca6d Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 23 Nov 2021 09:32:27 +0200 Subject: [PATCH 31/42] feature: print elr on unresolved data aborts --- kernel/src/arch/aarch64/exception.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index ff9a74e..e9cf661 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -99,6 +99,7 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { .is_err() { // Kill program + errorln!("Data abort from {:#x}", exc.elr_el1); dump_data_abort(Level::Error, esr, far as u64); proc.enter_fault_signal(thread, Signal::SegmentationFault); } @@ -114,6 +115,7 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { } errorln!("Unresolved data abort"); + errorln!("Data abort from {:#x}", exc.elr_el1); dump_data_abort(Level::Error, esr, far as u64); } EC_SVC_AA64 => { From a7d89158cb3ff0e9ebeb2cc03db4fdb098cccd73 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 23 Nov 2021 14:16:37 +0200 Subject: [PATCH 32/42] feature: Ctrl+C signal to foreground pgid --- kernel/src/arch/aarch64/exception.rs | 6 +- kernel/src/arch/aarch64/irq/gic/mod.rs | 6 +- kernel/src/dev/tty.rs | 28 +++++++- kernel/src/init.rs | 1 + kernel/src/proc/io.rs | 13 +++- kernel/src/proc/process.rs | 94 ++++++++++++++++---------- kernel/src/proc/thread.rs | 62 +++++++++++------ kernel/src/proc/wait.rs | 82 +++++++++++++--------- kernel/src/syscall/mod.rs | 69 ++++++++++++++++++- libsys/src/abi.rs | 5 ++ libsys/src/calls.rs | 30 ++++++-- libsys/src/ioctl.rs | 2 + libusr/src/io/mod.rs | 14 +++- libusr/src/sys/mod.rs | 2 +- user/src/fuzzy/main.rs | 2 +- user/src/shell/main.rs | 46 ++++++++++--- 16 files changed, 340 insertions(+), 122 deletions(-) diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index e9cf661..7ba09f0 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -149,7 +149,11 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { if sched::is_ready() { let thread = Thread::current(); - errorln!("Unhandled exception in thread {}, {:?}", thread.id(), thread.owner().map(|e| e.id())); + errorln!( + "Unhandled exception in thread {}, {:?}", + thread.id(), + thread.owner().map(|e| e.id()) + ); } errorln!( diff --git a/kernel/src/arch/aarch64/irq/gic/mod.rs b/kernel/src/arch/aarch64/irq/gic/mod.rs index c2c39c8..c5366f9 100644 --- a/kernel/src/arch/aarch64/irq/gic/mod.rs +++ b/kernel/src/arch/aarch64/irq/gic/mod.rs @@ -86,9 +86,7 @@ impl IntController for Gic { return; } - if self.scheduler_irq.0 == irq_number { - gicc.clear_irq(irq_number as u32, ic); - } + gicc.clear_irq(irq_number as u32, ic); { let table = self.table.lock(); @@ -100,8 +98,6 @@ impl IntController for Gic { } } } - - gicc.clear_irq(irq_number as u32, ic); } fn register_handler( diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 4ab8da4..b826644 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -1,10 +1,12 @@ //! Teletype (TTY) device facilities use crate::dev::serial::SerialDevice; -use crate::proc::wait::{Wait, WAIT_SELECT}; +use crate::proc::{Process, wait::{Wait, WAIT_SELECT}}; use crate::sync::IrqSafeSpinLock; use libsys::error::Errno; use libsys::{ termios::{Termios, TermiosIflag, TermiosLflag, TermiosOflag}, + proc::Pid, + signal::Signal, ioctl::IoctlCmd }; use core::mem::size_of; @@ -16,6 +18,7 @@ struct CharRingInner { wr: usize, data: [u8; N], flags: u8, + fg_pgid: Option, } /// Ring buffer for TTYs @@ -54,6 +57,11 @@ pub trait TtyDevice: SerialDevice { *self.ring().config.lock() = src.clone(); Ok(size_of::()) }, + IoctlCmd::TtySetPgrp => { + let src = arg::struct_ref::(ptr)?; + self.ring().inner.lock().fg_pgid = Some(unsafe { Pid::from_raw(*src) }); + Ok(0) + }, _ => Err(Errno::InvalidArgument) } } @@ -110,6 +118,19 @@ pub trait TtyDevice: SerialDevice { } } + if byte == 0x3 && config.lflag.contains(TermiosLflag::ISIG) { + drop(config); + let pgid = ring.inner.lock().fg_pgid; + if let Some(pgid) = pgid { + // TODO send to pgid + let proc = Process::get(pgid); + if let Some(proc) = proc { + proc.set_signal(Signal::Interrupt); + } + } + return; + } + self.ring().putc(byte, false).ok(); } @@ -232,14 +253,15 @@ impl CharRing { pub const fn new() -> Self { Self { inner: IrqSafeSpinLock::new(CharRingInner { + fg_pgid: None, rd: 0, wr: 0, data: [0; N], flags: 0, }), config: IrqSafeSpinLock::new(Termios::new()), - wait_read: Wait::new(), - wait_write: Wait::new(), + wait_read: Wait::new("tty_read"), + wait_write: Wait::new("tty_write"), } } diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 9744253..f390019 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -54,6 +54,7 @@ pub extern "C" fn init_fn(_arg: usize) -> ! { io.set_file(FileDescriptor::STDIN, stdin).unwrap(); io.set_file(FileDescriptor::STDOUT, stdout).unwrap(); io.set_file(FileDescriptor::STDERR, stderr).unwrap(); + io.set_ctty(tty_node); } drop(cfg); diff --git a/kernel/src/proc/io.rs b/kernel/src/proc/io.rs index f60301a..c42f60f 100644 --- a/kernel/src/proc/io.rs +++ b/kernel/src/proc/io.rs @@ -1,12 +1,13 @@ //! Process file descriptors and I/O context use alloc::collections::BTreeMap; use libsys::{error::Errno, stat::FileDescriptor}; -use vfs::{FileRef, Ioctx}; +use vfs::{FileRef, Ioctx, VnodeRef, VnodeKind}; /// Process I/O context. Contains file tables, root/cwd info etc. pub struct ProcessIo { ioctx: Option, files: BTreeMap, + ctty: Option, } impl ProcessIo { @@ -21,6 +22,15 @@ impl ProcessIo { Ok(dst) } + pub fn set_ctty(&mut self, node: VnodeRef) { + assert_eq!(node.kind(), VnodeKind::Char); + self.ctty = Some(node); + } + + pub fn ctty(&mut self) -> Option { + self.ctty.clone() + } + /// Returns [File] struct referred to by file descriptor `idx` pub fn file(&mut self, fd: FileDescriptor) -> Result { self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile) @@ -54,6 +64,7 @@ impl ProcessIo { Self { files: BTreeMap::new(), ioctx: None, + ctty: None, } } diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index e11f518..af18b48 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -16,6 +16,7 @@ use libsys::{ proc::{ExitCode, Pid}, signal::Signal, }; +use vfs::{VnodeRef, VnodeKind}; /// Wrapper type for a process struct reference pub type ProcessRef = Rc; @@ -33,6 +34,9 @@ struct ProcessInner { space: Option<&'static mut Space>, state: ProcessState, id: Pid, + pgid: Pid, + ppid: Option, + sid: Pid, exit: Option, threads: Vec, } @@ -56,6 +60,25 @@ impl Process { self.inner.lock().id } + #[inline] + pub fn sid(&self) -> Pid { + self.inner.lock().sid + } + + #[inline] + pub fn pgid(&self) -> Pid { + self.inner.lock().pgid + } + + #[inline] + pub fn ppid(&self) -> Option { + self.inner.lock().ppid + } + + pub fn set_pgid(&self, pgid: Pid) { + self.inner.lock().pgid = pgid; + } + #[inline] pub fn current() -> ProcessRef { Thread::current().owner().unwrap() @@ -75,6 +98,9 @@ impl Process { let mut inner = ProcessInner { threads: Vec::new(), id, + pgid: id, + ppid: None, + sid: id, exit: None, space: None, state: ProcessState::Active, @@ -82,7 +108,7 @@ impl Process { inner.threads.push(thread.id()); let res = Rc::new(Self { - exit_wait: Wait::new(), + exit_wait: Wait::new("process_exit"), io: IrqSafeSpinLock::new(ProcessIo::new()), signal_state: AtomicU32::new(0), inner: IrqSafeSpinLock::new(inner), @@ -107,8 +133,11 @@ impl Process { /// Sets a pending signal for a process pub fn set_signal(&self, signal: Signal) { - let lock = self.inner.lock(); + let mut lock = self.inner.lock(); + let ttbr0 = + lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48); let main_thread = Thread::get(lock.threads[0]).unwrap(); + drop(lock); // TODO check that `signal` is not a fault signal // it is illegal to call this function with @@ -116,14 +145,15 @@ impl Process { match main_thread.state() { ThreadState::Running => { - Process::enter_signal_on(lock, main_thread, signal); + main_thread.enter_signal(signal, ttbr0); } ThreadState::Waiting => { - // TODO abort whatever the process is waiting for - todo!() + main_thread.clone().setup_signal(signal, ttbr0); + main_thread.interrupt_wait(true); } ThreadState::Ready => { - todo!() + main_thread.clone().setup_signal(signal, ttbr0); + main_thread.interrupt_wait(false); } ThreadState::Finished => { // TODO report error back @@ -132,20 +162,11 @@ impl Process { } } - fn enter_signal_on( - mut inner: IrqSafeSpinLockGuard, - thread: ThreadRef, - signal: Signal, - ) { - let ttbr0 = - inner.space.as_mut().unwrap().address_phys() | ((inner.id.asid() as usize) << 48); - drop(inner); - thread.enter_signal(signal, ttbr0); - } - pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) { - let lock = self.inner.lock(); - Process::enter_signal_on(lock, thread, signal); + let mut lock = self.inner.lock(); + let ttbr0 = + lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48); + thread.enter_signal(signal, ttbr0); } pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result { @@ -178,7 +199,7 @@ impl Process { threads.push(tid); let dst = Rc::new(Self { - exit_wait: Wait::new(), + exit_wait: Wait::new("process_exit"), io: IrqSafeSpinLock::new(src_io.fork()?), signal_state: AtomicU32::new(0), inner: IrqSafeSpinLock::new(ProcessInner { @@ -187,6 +208,9 @@ impl Process { space: Some(dst_space), state: ProcessState::Active, id: dst_id, + pgid: src_inner.pgid, + ppid: Some(src_inner.id), + sid: src_inner.sid }), }); @@ -198,15 +222,11 @@ impl Process { Ok(dst_id) } - // TODO a way to terminate a single thread? /// Terminates a process. - pub fn exit(status: ExitCode) { - unsafe { - asm!("msr daifclr, #0xF"); - } + pub fn exit(self: ProcessRef, status: ExitCode) { let thread = Thread::current(); - let process = thread.owner().unwrap(); - let mut lock = process.inner.lock(); + let mut lock = self.inner.lock(); + let is_running = thread.owner_id().map(|e| e == lock.id).unwrap_or(false); infoln!("Process {:?} is exiting: {:?}", lock.id, status); assert!(lock.exit.is_none()); @@ -214,11 +234,9 @@ impl Process { lock.state = ProcessState::Finished; for &tid in lock.threads.iter() { - debugln!("Dequeue {:?}", tid); Thread::get(tid).unwrap().terminate(status); SCHED.dequeue(tid); } - SCHED.debug(); if let Some(space) = lock.space.take() { unsafe { @@ -227,13 +245,16 @@ impl Process { } } - process.io.lock().handle_exit(); + self.io.lock().handle_exit(); drop(lock); - process.exit_wait.wakeup_all(); - SCHED.switch(true); - panic!("This code should never run"); + self.exit_wait.wakeup_all(); + + if is_running { + SCHED.switch(true); + panic!("This code should never run"); + } } pub fn exit_thread(thread: ThreadRef, status: ExitCode) { @@ -246,8 +267,8 @@ impl Process { if lock.threads.len() == 1 { // TODO call Process::exit instead? drop(lock); - Process::exit(status); - panic!(); + process.exit(status); + return; } lock.threads.retain(|&e| e != tid); @@ -291,7 +312,6 @@ impl Process { if let Some(r) = proc.collect() { // TODO drop the process struct itself PROCESSES.lock().remove(&proc.id()); - debugln!("pid {:?} has {} refs", proc.id(), Rc::strong_count(&proc)); return Ok(r); } @@ -327,6 +347,8 @@ impl Process { let r = processes.remove(&old_pid); assert!(r.is_some()); process_lock.id = new_pid; + process_lock.pgid = new_pid; + process_lock.sid = new_pid; let r = processes.insert(new_pid, proc.clone()); assert!(r.is_none()); } else { diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index 7c23763..fb653e6 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -1,5 +1,5 @@ use crate::arch::aarch64::exception::ExceptionFrame; -use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS}; +use crate::proc::{wait::{Wait, WaitStatus}, Process, ProcessRef, SCHED, THREADS}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use alloc::rc::Rc; @@ -33,7 +33,7 @@ struct ThreadInner { state: State, owner: Option, pending_wait: Option<&'static Wait>, - wait_flag: bool, + wait_status: WaitStatus, signal_entry: usize, signal_stack: usize, } @@ -63,6 +63,10 @@ impl Thread { self.inner.lock().owner.and_then(Process::get) } + pub fn owner_id(&self) -> Option { + self.inner.lock().owner + } + /// Creates a new kernel process pub fn new_kernel( owner: Option, @@ -75,7 +79,7 @@ impl Thread { ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), - exit_wait: Wait::new(), + exit_wait: Wait::new("thread_exit"), exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, @@ -83,7 +87,7 @@ impl Thread { id, owner, pending_wait: None, - wait_flag: false, + wait_status: WaitStatus::Done, state: State::Ready, }), }); @@ -106,7 +110,7 @@ impl Thread { ctx: UnsafeCell::new(Context::user(entry, arg, ttbr0, stack)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), - exit_wait: Wait::new(), + exit_wait: Wait::new("thread_exit"), exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, @@ -114,7 +118,7 @@ impl Thread { id, owner: Some(owner), pending_wait: None, - wait_flag: false, + wait_status: WaitStatus::Done, state: State::Ready, }), }); @@ -134,7 +138,7 @@ impl Thread { ctx: UnsafeCell::new(Context::fork(frame, ttbr0)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), - exit_wait: Wait::new(), + exit_wait: Wait::new("thread_exit"), exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, @@ -142,7 +146,7 @@ impl Thread { id, owner, pending_wait: None, - wait_flag: false, + wait_status: WaitStatus::Done, state: State::Ready, }), }); @@ -185,7 +189,7 @@ impl Thread { assert_eq!(src_lock.state, State::Running); src_lock.state = State::Ready; } - assert!(dst_lock.state == State::Ready || dst_lock.state == State::Waiting); + // assert!(dst_lock.state == State::Ready || dst_lock.state == State::Waiting); dst_lock.state = State::Running; } @@ -223,7 +227,7 @@ impl Thread { let mut lock = self.inner.lock(); // FIXME this is not cool lock.pending_wait = Some(unsafe { &*wait }); - lock.wait_flag = true; + lock.wait_status = WaitStatus::Pending; } pub fn waittid(tid: u32) -> Result<(), Errno> { @@ -243,19 +247,19 @@ impl Thread { } } - pub fn set_wait_reached(&self) { + pub fn set_wait_status(&self, status: WaitStatus) { let mut lock = self.inner.lock(); - lock.wait_flag = false; + lock.wait_status = status; } pub fn reset_wait(&self) { let mut lock = self.inner.lock(); lock.pending_wait = None; + lock.wait_status = WaitStatus::Done; } - /// Returns `true` if process wait condition has not been reached - pub fn wait_flag(&self) -> bool { - self.inner.lock().wait_flag + pub fn wait_status(&self) -> WaitStatus { + self.inner.lock().wait_status } /// Switches current thread back from signal handler @@ -291,8 +295,7 @@ impl Thread { lock.signal_stack = stack; } - /// Switches process main thread to a signal handler - pub fn enter_signal(self: ThreadRef, signal: Signal, ttbr0: usize) { + pub fn setup_signal(self: ThreadRef, signal: Signal, ttbr0: usize) { if self .signal_pending .compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed) @@ -305,7 +308,7 @@ impl Thread { if lock.signal_entry == 0 || lock.signal_stack == 0 { drop(lock); Process::exit_thread(self, ExitCode::from(-1)); - panic!(); + return; } let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; @@ -318,7 +321,6 @@ impl Thread { lock.signal_stack, ttbr0 ); - assert_eq!(lock.state, State::Running); unsafe { signal_ctx.setup_signal_entry( @@ -329,13 +331,31 @@ impl Thread { ); } - drop(lock); + } + + /// Switches process main thread to a signal handler + pub fn enter_signal(self: ThreadRef, signal: Signal, ttbr0: usize) { + let src_ctx = self.ctx.get(); + let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; + + assert_eq!(self.state(), State::Running); + self.setup_signal(signal, ttbr0); unsafe { (&mut *src_ctx).switch(signal_ctx); } } + pub fn interrupt_wait(&self, enqueue: bool) { + let mut lock = self.inner.lock(); + let tid = lock.id; + let wait = lock.pending_wait.take(); + drop(lock); + if let Some(wait) = wait { + wait.abort(tid, enqueue); + } + } + pub fn terminate(&self, status: ExitCode) { let mut lock = self.inner.lock(); lock.state = State::Finished; @@ -343,7 +363,7 @@ impl Thread { let wait = lock.pending_wait.take(); drop(lock); if let Some(wait) = wait { - wait.abort(tid); + wait.abort(tid, false); } self.exit_status.init(status); self.exit_wait.wakeup_all(); diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index 5885275..de19bd2 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -12,6 +12,14 @@ use libsys::{error::Errno, stat::FdSet}; /// waiting for some event to happen. pub struct Wait { queue: IrqSafeSpinLock>, + name: &'static str +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum WaitStatus { + Pending, + Interrupted, + Done, } struct Timeout { @@ -20,7 +28,7 @@ struct Timeout { } static TICK_LIST: IrqSafeSpinLock> = IrqSafeSpinLock::new(LinkedList::new()); -pub static WAIT_SELECT: Wait = Wait::new(); +pub static WAIT_SELECT: Wait = Wait::new("select"); /// Checks for any timed out wait channels and interrupts them pub fn tick() { @@ -42,7 +50,7 @@ pub fn tick() { /// Suspends current process for given duration pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> { // Dummy wait descriptor which will never receive notifications - static SLEEP_NOTIFY: Wait = Wait::new(); + static SLEEP_NOTIFY: Wait = Wait::new("sleep"); let deadline = machine::local_timer().timestamp()? + timeout; match SLEEP_NOTIFY.wait(Some(deadline)) { Err(Errno::Interrupt) => { @@ -104,9 +112,39 @@ pub fn select( impl Wait { /// Constructs a new wait channel - pub const fn new() -> Self { + pub const fn new(name: &'static str) -> Self { Self { queue: IrqSafeSpinLock::new(LinkedList::new()), + name + } + } + + pub fn abort(&self, tid: u32, enqueue: bool) { + let mut queue = self.queue.lock(); + let mut tick_lock = TICK_LIST.lock(); + let mut cursor = tick_lock.cursor_front_mut(); + while let Some(item) = cursor.current() { + if tid == item.tid { + cursor.remove_current(); + break; + } else { + cursor.move_next(); + } + } + + let mut cursor = queue.cursor_front_mut(); + while let Some(item) = cursor.current() { + if tid == *item { + cursor.remove_current(); + let thread = Thread::get(tid).unwrap(); + thread.set_wait_status(WaitStatus::Interrupted); + if enqueue { + SCHED.enqueue(tid); + } + break; + } else { + cursor.move_next(); + } } } @@ -129,7 +167,7 @@ impl Wait { } drop(tick_lock); - Thread::get(tid).unwrap().set_wait_reached(); + Thread::get(tid).unwrap().set_wait_status(WaitStatus::Done); SCHED.enqueue(tid); } @@ -149,30 +187,6 @@ impl Wait { self.wakeup_some(1); } - pub fn abort(&self, tid: u32) { - let mut queue = self.queue.lock(); - let mut tick_lock = TICK_LIST.lock(); - let mut cursor = tick_lock.cursor_front_mut(); - while let Some(item) = cursor.current() { - if tid == item.tid { - cursor.remove_current(); - break; - } else { - cursor.move_next(); - } - } - - let mut cursor = queue.cursor_front_mut(); - while let Some(item) = cursor.current() { - if tid == *item { - cursor.remove_current(); - break; - } else { - cursor.move_next(); - } - } - } - /// Suspends current process until event is signalled or /// (optional) deadline is reached pub fn wait(&self, deadline: Option) -> Result<(), Errno> { @@ -191,9 +205,15 @@ impl Wait { } loop { - if !thread.wait_flag() { - return Ok(()); - } + match thread.wait_status() { + WaitStatus::Pending => {} + WaitStatus::Done => { + return Ok(()); + } + WaitStatus::Interrupted => { + return Err(Errno::Interrupt); + } + }; drop(queue_lock); thread.enter_wait(); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 520547e..c3b8f45 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -52,6 +52,7 @@ fn find_at_node>( /// Main system call dispatcher function pub fn syscall(num: SystemCall, args: &[usize]) -> Result { + // debugln!("syscall {:?}", num); match num { // I/O SystemCall::Read => { @@ -172,7 +173,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { if flags & (1 << 0) != 0 { Process::exit_thread(Thread::current(), status); } else { - Process::exit(status); + Process::current().exit(status); } unreachable!(); @@ -187,7 +188,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { *status = i32::from(exit); Ok(0) } - _ => todo!(), + e => e.map(|e| i32::from(e) as usize), } }, SystemCall::WaitTid => { @@ -200,7 +201,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { _ => todo!(), } }, - SystemCall::GetPid => todo!(), + SystemCall::GetPid => Ok(Process::current().id().value() as usize), SystemCall::GetTid => Ok(Thread::current().id() as usize), SystemCall::Sleep => { let rem_buf = arg::option_buf_ref(args[1], size_of::() * 2)?; @@ -239,6 +240,68 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { proc::switch(); Ok(0) }, + SystemCall::GetSid => { + // TODO handle kernel processes here? + let pid = args[0] as u32; + let current = Process::current(); + let proc = if pid == 0 { + current + } else { + let pid = unsafe { Pid::from_raw(pid) }; + let proc = Process::get(pid).ok_or(Errno::DoesNotExist)?; + if proc.sid() != current.sid() { + return Err(Errno::PermissionDenied) + } + proc + }; + + Ok(proc.sid().value() as usize) + }, + SystemCall::GetPgid => { + // TODO handle kernel processes here? + let pid = args[0] as u32; + let current = Process::current(); + let proc = if pid == 0 { + current + } else { + let pid = unsafe { Pid::from_raw(pid) }; + Process::get(pid).ok_or(Errno::DoesNotExist)? + }; + + Ok(proc.pgid().value() as usize) + }, + SystemCall::GetPpid => { + Ok(Process::current().ppid().unwrap().value() as usize) + }, + SystemCall::SetSid => { + let proc = Process::current(); + let mut io = proc.io.lock(); + + if let Some(ctty) = io.ctty() { + todo!(); + } + + todo!(); + }, + SystemCall::SetPgid => { + let pid = args[0] as u32; + let pgid = args[1] as u32; + + let current = Process::current(); + let proc = if pid == 0 { + current + } else { + todo!() + }; + + if pgid == 0 { + proc.set_pgid(proc.id()); + } else { + todo!(); + } + + Ok(proc.pgid().value() as usize) + }, // System SystemCall::GetCpuTime => { diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 59c9b36..fad27ff 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -26,6 +26,11 @@ pub enum SystemCall { SignalReturn = 42, SendSignal = 43, Yield = 44, + GetSid = 45, + GetPgid = 46, + GetPpid = 47, + SetSid = 48, + SetPgid = 49, // System GetCpuTime = 64, // Debugging diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index b5e13e7..98fdb53 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -251,14 +251,15 @@ pub fn sys_ioctl( #[inline(always)] pub fn sys_ex_getcputime() -> Result { - Errno::from_syscall(unsafe { - syscall!(SystemCall::GetCpuTime) - }).map(|e| Duration::from_nanos(e as u64)) + Errno::from_syscall(unsafe { syscall!(SystemCall::GetCpuTime) }) + .map(|e| Duration::from_nanos(e as u64)) } #[inline(always)] pub fn sys_ex_signal(entry: usize, stack: usize) -> Result<(), Errno> { - Errno::from_syscall_unit(unsafe { syscall!(SystemCall::SetSignalEntry, argn!(entry), argn!(stack)) }) + Errno::from_syscall_unit(unsafe { + syscall!(SystemCall::SetSignalEntry, argn!(entry), argn!(stack)) + }) } #[inline(always)] @@ -349,7 +350,22 @@ pub fn sys_faccessat( #[inline(always)] pub fn sys_ex_gettid() -> u32 { - unsafe { - syscall!(SystemCall::GetTid) as u32 - } + unsafe { syscall!(SystemCall::GetTid) as u32 } } + +#[inline(always)] +pub fn sys_getpid() -> Pid { + unsafe { Pid::from_raw(syscall!(SystemCall::GetPid) as u32) } +} + +#[inline(always)] +pub fn sys_getpgid(pid: Pid) -> Result { + Errno::from_syscall(unsafe { syscall!(SystemCall::GetPgid, argn!(pid.value())) }) + .map(|e| unsafe { Pid::from_raw(e as u32) }) +} + +#[inline(always)] +pub fn sys_setpgid(pid: Pid, pgid: Pid) -> Result { + Errno::from_syscall(unsafe { syscall!(SystemCall::SetPgid, argn!(pid.value()), argn!(pgid.value())) }).map(|e| unsafe { Pid::from_raw(e as u32) }) +} + diff --git a/libsys/src/ioctl.rs b/libsys/src/ioctl.rs index 9b8d484..91cb058 100644 --- a/libsys/src/ioctl.rs +++ b/libsys/src/ioctl.rs @@ -7,6 +7,7 @@ use crate::error::Errno; pub enum IoctlCmd { TtySetAttributes = 1, TtyGetAttributes = 2, + TtySetPgrp = 3, } impl TryFrom for IoctlCmd { @@ -17,6 +18,7 @@ impl TryFrom for IoctlCmd { match u { 1 => Ok(Self::TtySetAttributes), 2 => Ok(Self::TtyGetAttributes), + 3 => Ok(Self::TtySetPgrp), _ => Err(Errno::InvalidArgument) } } diff --git a/libusr/src/io/mod.rs b/libusr/src/io/mod.rs index f4c9ee3..6e2bf5f 100644 --- a/libusr/src/io/mod.rs +++ b/libusr/src/io/mod.rs @@ -1,7 +1,11 @@ use libsys::{ - calls::sys_fstatat, + calls::{sys_fstatat, sys_ioctl}, stat::{FileDescriptor, Stat}, + ioctl::IoctlCmd, + error::Errno, + proc::Pid }; +use core::mem::size_of; use core::fmt; mod error; @@ -24,6 +28,14 @@ pub trait AsRawFd { fn as_raw_fd(&self) -> FileDescriptor; } +pub fn tcgetpgrp(fd: FileDescriptor) -> Result { + todo!() +} + +pub fn tcsetpgrp(fd: FileDescriptor, pgid: Pid) -> Result<(), Errno> { + sys_ioctl(fd, IoctlCmd::TtySetPgrp, &pgid as *const _ as usize, size_of::()).map(|_| ()) +} + pub fn stat(pathname: &str) -> Result { let mut buf = Stat::default(); // TODO error handling diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs index 9b43f6b..e6727f4 100644 --- a/libusr/src/sys/mod.rs +++ b/libusr/src/sys/mod.rs @@ -1,5 +1,5 @@ pub use libsys::signal::{Signal, SignalDestination}; -pub use libsys::proc::ExitCode; +pub use libsys::proc::{self, ExitCode}; pub use libsys::termios; pub use libsys::abi; pub use libsys::calls::*; diff --git a/user/src/fuzzy/main.rs b/user/src/fuzzy/main.rs index cfc7d4e..6b06d79 100644 --- a/user/src/fuzzy/main.rs +++ b/user/src/fuzzy/main.rs @@ -125,7 +125,7 @@ fn main() -> i32 { // Test non-utf8 input fed into syscalls expecting strings // let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore); - for _ in 0..100 { + for _ in 0..10000 { random_bytes(&mut buf); let mut stat = Stat::default(); diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index b2a835e..054c443 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -6,19 +6,29 @@ extern crate libusr; extern crate alloc; use alloc::borrow::ToOwned; -use libusr::sys::{sys_exit, sys_execve, sys_waitpid, sys_fork, ExitCode, Errno}; use libusr::io::{self, Read}; +use libusr::signal::{self, SignalHandler}; +use libusr::sys::{ + proc::Pid, sys_execve, sys_setpgid, sys_exit, sys_fork, sys_getpgid, sys_waitpid, Errno, ExitCode, + FileDescriptor, Signal, +}; fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result, io::Error> { let size = f.read(bytes)?; Ok(if size == 0 { None } else { - Some(core::str::from_utf8(&bytes[..size]).unwrap().trim_end_matches('\n')) + Some( + core::str::from_utf8(&bytes[..size]) + .unwrap() + .trim_end_matches('\n'), + ) }) } fn execvp(cmd: &str) -> ! { + let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap(); + io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); sys_execve(&("/bin/".to_owned() + cmd)).unwrap(); sys_exit(ExitCode::from(-1)); } @@ -30,6 +40,8 @@ fn execute(line: &str) -> Result { if let Some(pid) = unsafe { sys_fork()? } { let mut status = 0; sys_waitpid(pid, &mut status)?; + let pgid = sys_getpgid(unsafe { Pid::from_raw(0) }).unwrap(); + io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); Ok(ExitCode::from(status)) } else { execvp(cmd); @@ -41,18 +53,30 @@ fn main() -> i32 { let mut buf = [0; 256]; let mut stdin = io::stdin(); + signal::set_handler(Signal::Interrupt, SignalHandler::Ignore); + let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap(); + io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); + loop { print!("> "); - let line = readline(&mut stdin, &mut buf).unwrap(); - if line.is_none() { - break; - } - let line = line.unwrap().trim_start_matches(' '); - if line.is_empty() { - continue; - } + match readline(&mut stdin, &mut buf) { + Ok(line) => { + if line.is_none() { + break; + } + let line = line.unwrap().trim_start_matches(' '); + if line.is_empty() { + continue; + } - execute(line).ok(); + execute(line).ok(); + }, + Err(_) => { + println!("Interrupt!"); + continue; + }, + _ => panic!() + } } 0 } From 564d10e1be466b4e794773d0a7637c8494caf8d3 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 23 Nov 2021 17:55:58 +0200 Subject: [PATCH 33/42] feature: simple ls(1p) --- Makefile | 1 + fs/macros/src/lib.rs | 13 +++++ fs/memfs/src/dir.rs | 13 +++-- fs/memfs/src/file.rs | 5 +- fs/memfs/src/lib.rs | 4 +- fs/memfs/src/tar.rs | 7 ++- fs/vfs/src/file.rs | 60 ++++++++++++++++++++++- fs/vfs/src/node.rs | 100 ++++++++++++++++++++++++++++++-------- kernel/src/syscall/arg.rs | 13 +++++ kernel/src/syscall/mod.rs | 83 ++++++++++++++++--------------- libsys/src/abi.rs | 1 + libsys/src/calls.rs | 18 ++++++- libsys/src/stat.rs | 95 +++++++++++++++++++++++++++++++----- user/Cargo.toml | 4 ++ user/src/ls/main.rs | 45 +++++++++++++++++ 15 files changed, 380 insertions(+), 82 deletions(-) create mode 100644 user/src/ls/main.rs diff --git a/Makefile b/Makefile index bbfd889..b73183a 100644 --- a/Makefile +++ b/Makefile @@ -96,6 +96,7 @@ initrd: cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin + cp target/$(ARCH)-osdev5/$(PROFILE)/ls $(O)/rootfs/bin cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"` ifeq ($(MACH),orangepi3) $(MKIMAGE) \ diff --git a/fs/macros/src/lib.rs b/fs/macros/src/lib.rs index dde1281..c3c4c84 100644 --- a/fs/macros/src/lib.rs +++ b/fs/macros/src/lib.rs @@ -94,6 +94,18 @@ fn impl_inode_fn(name: &str, behavior: T) -> ImplItem { #behavior } }, + "readdir" => quote! { + fn readdir( + &mut self, + _node: VnodeRef, + _pos: usize, + _entries: &mut [libsys::stat::DirectoryEntry] + ) -> + Result + { + #behavior + } + }, _ => panic!("TODO implement {:?}", name), }) } @@ -126,6 +138,7 @@ pub fn auto_inode(attr: TokenStream, input: TokenStream) -> TokenStream { missing.insert("size".to_string()); missing.insert("ioctl".to_string()); missing.insert("is_ready".to_string()); + missing.insert("readdir".to_string()); for item in &impl_item.items { match item { diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index 5766e1a..fc1caea 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -1,6 +1,9 @@ use crate::{BlockAllocator, Bvec, FileInode}; use alloc::boxed::Box; -use libsys::{error::Errno, stat::Stat}; +use libsys::{ + error::Errno, + stat::{DirectoryEntry, OpenFlags, Stat}, +}; use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirInode { @@ -15,7 +18,7 @@ impl VnodeImpl for DirInode { name: &str, kind: VnodeKind, ) -> Result { - let vnode = Vnode::new(name, kind, Vnode::SEEKABLE); + let vnode = Vnode::new(name, kind, Vnode::SEEKABLE | Vnode::CACHE_READDIR); match kind { VnodeKind::Directory => vnode.set_data(Box::new(DirInode { alloc: self.alloc })), VnodeKind::Regular => vnode.set_data(Box::new(FileInode::new(Bvec::new(self.alloc)))), @@ -32,7 +35,11 @@ impl VnodeImpl for DirInode { Ok(()) } - fn stat(&mut self, _at: VnodeRef, _stat: &mut Stat) -> Result<(), Errno> { + fn stat(&mut self, node: VnodeRef, stat: &mut Stat) -> Result<(), Errno> { + let props = node.props(); + stat.size = 0; + stat.blksize = 4096; + stat.mode = props.mode; Ok(()) } } diff --git a/fs/memfs/src/file.rs b/fs/memfs/src/file.rs index 1fe8068..13d31b6 100644 --- a/fs/memfs/src/file.rs +++ b/fs/memfs/src/file.rs @@ -35,10 +35,11 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { Ok(self.data.size()) } - fn stat(&mut self, _node: VnodeRef, stat: &mut Stat) -> Result<(), Errno> { + fn stat(&mut self, node: VnodeRef, stat: &mut Stat) -> Result<(), Errno> { + let props = node.props(); stat.size = self.data.size() as u64; stat.blksize = 4096; - stat.mode = 0o755; + stat.mode = props.mode; Ok(()) } } diff --git a/fs/memfs/src/lib.rs b/fs/memfs/src/lib.rs index 04be460..7e9e83c 100644 --- a/fs/memfs/src/lib.rs +++ b/fs/memfs/src/lib.rs @@ -69,7 +69,7 @@ impl Ramfs { fn create_node_initial(self: Rc, name: &str, tar: &Tar) -> VnodeRef { let kind = tar.node_kind(); - let node = Vnode::new(name, kind, Vnode::SEEKABLE); + let node = Vnode::new(name, kind, Vnode::SEEKABLE | Vnode::CACHE_READDIR); node.props_mut().mode = tar.mode(); node.set_fs(self.clone()); match kind { @@ -113,7 +113,7 @@ impl Ramfs { } unsafe fn load_tar(self: Rc, base: *const u8, size: usize) -> Result { - let root = Vnode::new("", VnodeKind::Directory, Vnode::SEEKABLE); + let root = Vnode::new("", VnodeKind::Directory, Vnode::SEEKABLE | Vnode::CACHE_READDIR); root.set_fs(self.clone()); root.set_data(Box::new(DirInode::new(self.alloc))); root.props_mut().mode = FileMode::default_dir(); diff --git a/fs/memfs/src/tar.rs b/fs/memfs/src/tar.rs index 2211f65..5326a2f 100644 --- a/fs/memfs/src/tar.rs +++ b/fs/memfs/src/tar.rs @@ -82,7 +82,12 @@ impl Tar { } pub fn mode(&self) -> FileMode { - FileMode::from_bits(from_octal(&self.mode) as u32).unwrap() + let t = match self.node_kind() { + VnodeKind::Regular => FileMode::S_IFREG, + VnodeKind::Directory => FileMode::S_IFDIR, + _ => todo!() + }; + FileMode::from_bits(from_octal(&self.mode) as u32).unwrap() | t } pub fn data(&self) -> &[u8] { diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index cd63be4..4c267b6 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -1,9 +1,10 @@ -use crate::{VnodeKind, VnodeRef}; +use crate::{VnodeKind, VnodeRef, Vnode}; use alloc::rc::Rc; use core::cell::RefCell; use core::cmp::min; use libsys::{ error::Errno, + stat::DirectoryEntry, traits::{Read, Seek, SeekDir, Write}, }; @@ -97,6 +98,9 @@ impl File { /// File has to be closed on execve() calls pub const CLOEXEC: u32 = 1 << 2; + pub const POS_CACHE_DOT: usize = usize::MAX - 1; + pub const POS_CACHE_DOT_DOT: usize = usize::MAX; + /// Constructs a new file handle for a regular file pub fn normal(vnode: VnodeRef, pos: usize, flags: u32) -> FileRef { Rc::new(RefCell::new(Self { @@ -125,6 +129,60 @@ impl File { _ => todo!(), } } + + fn cache_readdir(inner: &mut NormalFile, entries: &mut [DirectoryEntry]) -> Result { + let mut count = entries.len(); + let mut offset = 0usize; + + if inner.pos == Self::POS_CACHE_DOT { + if count == 0 { + return Ok(offset); + } + + entries[offset] = DirectoryEntry::from_str("."); + inner.pos = Self::POS_CACHE_DOT_DOT; + + offset += 1; + count -= 1; + } + + if inner.pos == Self::POS_CACHE_DOT_DOT { + if count == 0 { + return Ok(offset); + } + + entries[offset] = DirectoryEntry::from_str(".."); + inner.pos = 0; + + offset += 1; + count -= 1; + } + + if count == 0 { + return Ok(offset); + } + + let count = inner.vnode.for_each_entry(inner.pos, count, |i, e| { + entries[offset + i] = DirectoryEntry::from_str(e.name()); + }); + inner.pos += count; + Ok(offset + count) + } + + pub fn readdir(&mut self, entries: &mut [DirectoryEntry]) -> Result { + match &mut self.inner { + FileInner::Normal(inner) => { + assert_eq!(inner.vnode.kind(), VnodeKind::Directory); + + if inner.vnode.flags() & Vnode::CACHE_READDIR != 0 { + Self::cache_readdir(inner, entries) + } else { + todo!(); + } + }, + _ => todo!(), + } + } } impl Drop for File { diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 1e066b9..d21b058 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -1,11 +1,11 @@ -use crate::{Ioctx, File, FileRef, Filesystem}; +use crate::{File, FileRef, Filesystem, Ioctx}; use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec}; -use core::cell::{RefCell, RefMut}; +use core::cell::{RefCell, RefMut, Ref}; use core::fmt; use libsys::{ error::Errno, ioctl::IoctlCmd, - stat::{AccessMode, FileMode, OpenFlags, Stat}, + stat::{AccessMode, DirectoryEntry, FileMode, OpenFlags, Stat}, }; /// Convenience type alias for [Rc] @@ -74,6 +74,13 @@ pub trait VnodeImpl { /// Resizes the file storage if necessary. fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result; + fn readdir( + &mut self, + node: VnodeRef, + pos: usize, + data: &mut [DirectoryEntry], + ) -> Result; + /// Retrieves file status fn stat(&mut self, node: VnodeRef, stat: &mut Stat) -> Result<(), Errno>; @@ -97,6 +104,8 @@ impl Vnode { /// be seeked to arbitrary offsets pub const SEEKABLE: u32 = 1 << 0; + pub const CACHE_READDIR: u32 = 1 << 1; + /// Constructs a new [Vnode], wrapping it in [Rc]. The resulting node /// then needs to have [Vnode::set_data()] called on it to be usable. pub fn new(name: &str, kind: VnodeKind, flags: u32) -> VnodeRef { @@ -127,6 +136,11 @@ impl Vnode { self.props.borrow_mut() } + /// Returns a borrowed reference to cached file properties + pub fn props(&self) -> Ref { + self.props.borrow() + } + /// Sets an associated [VnodeImpl] for the [Vnode] pub fn set_data(&self, data: Box) { *self.data.borrow_mut() = Some(data); @@ -163,6 +177,11 @@ impl Vnode { self.kind } + #[inline(always)] + pub const fn flags(&self) -> u32 { + self.flags + } + // Tree operations /// Attaches `child` vnode to `self` in in-memory tree. NOTE: does not @@ -235,6 +254,29 @@ impl Vnode { .cloned() } + pub(crate) fn for_each_entry( + &self, + offset: usize, + limit: usize, + mut f: F, + ) -> usize { + assert!(self.is_directory()); + let mut count = 0; + for (index, item) in self + .tree + .borrow() + .children + .iter() + .skip(offset) + .take(limit) + .enumerate() + { + f(index, item); + count += 1; + } + count + } + /// Looks up a child `name` in `self`. Will first try looking up a cached /// vnode and will load it from disk if it's missing. pub fn lookup_or_load(self: &VnodeRef, name: &str) -> Result { @@ -308,35 +350,55 @@ impl Vnode { /// Opens a vnode for access pub fn open(self: &VnodeRef, flags: OpenFlags) -> Result { - if self.kind == VnodeKind::Directory { - return Err(Errno::IsADirectory); + let mut open_flags = 0; + if flags.contains(OpenFlags::O_DIRECTORY) { + if self.kind != VnodeKind::Directory { + return Err(Errno::NotADirectory); + } + if flags & OpenFlags::O_ACCESS != OpenFlags::O_RDONLY { + return Err(Errno::IsADirectory); + } + + open_flags = File::READ; + } else { + if self.kind == VnodeKind::Directory { + return Err(Errno::IsADirectory); + } + + match flags & OpenFlags::O_ACCESS { + OpenFlags::O_RDONLY => open_flags |= File::READ, + OpenFlags::O_WRONLY => open_flags |= File::WRITE, + OpenFlags::O_RDWR => open_flags |= File::READ | File::WRITE, + _ => unimplemented!(), + } } - let mut open_flags = 0; - match flags & OpenFlags::O_ACCESS { - OpenFlags::O_RDONLY => open_flags |= File::READ, - OpenFlags::O_WRONLY => open_flags |= File::WRITE, - OpenFlags::O_RDWR => open_flags |= File::READ | File::WRITE, - _ => unimplemented!(), - } if flags.contains(OpenFlags::O_CLOEXEC) { open_flags |= File::CLOEXEC; } - if let Some(ref mut data) = *self.data() { - let pos = data.open(self.clone(), flags)?; - Ok(File::normal(self.clone(), pos, open_flags)) + if self.kind == VnodeKind::Directory && self.flags & Vnode::CACHE_READDIR != 0 { + Ok(File::normal(self.clone(), File::POS_CACHE_DOT, open_flags)) } else { - Err(Errno::NotImplemented) + if let Some(ref mut data) = *self.data() { + let pos = data.open(self.clone(), flags)?; + Ok(File::normal(self.clone(), pos, open_flags)) + } else { + Err(Errno::NotImplemented) + } } } /// Closes a vnode pub fn close(self: &VnodeRef) -> Result<(), Errno> { - if let Some(ref mut data) = *self.data() { - data.close(self.clone()) + if self.kind == VnodeKind::Directory && self.flags & Vnode::CACHE_READDIR != 0 { + Ok(()) } else { - Err(Errno::NotImplemented) + if let Some(ref mut data) = *self.data() { + data.close(self.clone()) + } else { + Err(Errno::NotImplemented) + } } } diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 937ec98..c64075d 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -62,6 +62,19 @@ pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> { Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) } +pub fn struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<&'a mut [T], Errno> { + let layout = Layout::array::(count).unwrap(); + if base % layout.align() != 0 { + invalid_memory!( + "Structure pointer is misaligned: base={:#x}, expected {:?}", + base, + layout + ); + } + let bytes = buf_mut(base, layout.size())?; + Ok(unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, count) }) +} + pub fn option_struct_ref<'a, T>(base: usize) -> Result, Errno> { if base == 0 { Ok(None) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c3b8f45..1896f48 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -2,8 +2,8 @@ use crate::arch::{machine, platform::exception::ExceptionFrame}; use crate::debug::Level; -use crate::proc::{self, elf, wait, Process, ProcessIo, Thread}; use crate::dev::timer::TimestampSource; +use crate::proc::{self, elf, wait, Process, ProcessIo, Thread}; use core::mem::size_of; use core::ops::DerefMut; use core::time::Duration; @@ -13,7 +13,9 @@ use libsys::{ ioctl::IoctlCmd, proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, - stat::{FdSet, AccessMode, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH}, + stat::{ + AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH, + }, traits::{Read, Write}, }; use vfs::VnodeRef; @@ -62,7 +64,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let buf = arg::buf_mut(args[1], args[2])?; io.file(fd)?.borrow_mut().read(buf) - }, + } SystemCall::Write => { let proc = Process::current(); let fd = FileDescriptor::from(args[0] as u32); @@ -70,7 +72,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let buf = arg::buf_ref(args[1], args[2])?; io.file(fd)?.borrow_mut().write(buf) - }, + } SystemCall::Open => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; let path = arg::str_ref(args[1], args[2])?; @@ -88,7 +90,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let file = io.ioctx().open(at, path, mode, opts)?; Ok(u32::from(io.place_file(file)?) as usize) - }, + } SystemCall::Close => { let proc = Process::current(); let mut io = proc.io.lock(); @@ -96,7 +98,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { io.close_file(fd)?; Ok(0) - }, + } SystemCall::FileStatus => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; let filename = arg::str_ref(args[1], args[2])?; @@ -107,7 +109,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let mut io = proc.io.lock(); find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat(buf)?; Ok(0) - }, + } SystemCall::Ioctl => { let fd = FileDescriptor::from(args[0] as u32); let cmd = IoctlCmd::try_from(args[1] as u32)?; @@ -117,7 +119,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let node = io.file(fd)?.borrow().node().ok_or(Errno::InvalidFile)?; node.ioctl(cmd, args[2], args[3]) - }, + } SystemCall::Select => { let rfds = arg::option_struct_mut::(args[0])?; let wfds = arg::option_struct_mut::(args[1])?; @@ -128,7 +130,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { }; wait::select(Thread::current(), rfds, wfds, timeout) - }, + } SystemCall::Access => { let at_fd = FileDescriptor::from_i32(args[0] as i32)?; let path = arg::str_ref(args[1], args[2])?; @@ -138,9 +140,18 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let proc = Process::current(); let mut io = proc.io.lock(); - find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?; + find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)? + .check_access(io.ioctx(), mode)?; Ok(0) - }, + } + SystemCall::ReadDirectory => { + let proc = Process::current(); + let fd = FileDescriptor::from(args[0] as u32); + let mut io = proc.io.lock(); + let buf = arg::struct_buf_mut::(args[1], args[2])?; + + io.file(fd)?.borrow_mut().readdir(buf) + } // Process SystemCall::Clone => { @@ -151,7 +162,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { Process::current() .new_user_thread(entry, stack, arg) .map(|e| e as usize) - }, + } SystemCall::Exec => { let node = { let proc = Process::current(); @@ -165,7 +176,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let file = node.open(OpenFlags::O_RDONLY)?; Process::execve(move |space| elf::load_elf(space, file), 0).unwrap(); panic!(); - }, + } SystemCall::Exit => { let status = ExitCode::from(args[0] as i32); let flags = args[1]; @@ -177,7 +188,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { } unreachable!(); - }, + } SystemCall::WaitPid => { // TODO special "pid" values let pid = unsafe { Pid::from_raw(args[0] as u32) }; @@ -190,17 +201,15 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { } e => e.map(|e| i32::from(e) as usize), } - }, + } SystemCall::WaitTid => { let tid = args[0] as u32; match Thread::waittid(tid) { - Ok(_) => { - Ok(0) - }, + Ok(_) => Ok(0), _ => todo!(), } - }, + } SystemCall::GetPid => Ok(Process::current().id().value() as usize), SystemCall::GetTid => Ok(Thread::current().id() as usize), SystemCall::Sleep => { @@ -214,15 +223,15 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { } } res.map(|_| 0) - }, + } SystemCall::SetSignalEntry => { Thread::current().set_signal_entry(args[0], args[1]); Ok(0) - }, + } SystemCall::SignalReturn => { Thread::current().return_from_signal(); unreachable!(); - }, + } SystemCall::SendSignal => { let target = SignalDestination::from(args[0] as isize); let signal = Signal::try_from(args[1] as u32)?; @@ -235,11 +244,11 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { _ => todo!(), }; Ok(0) - }, + } SystemCall::Yield => { proc::switch(); Ok(0) - }, + } SystemCall::GetSid => { // TODO handle kernel processes here? let pid = args[0] as u32; @@ -250,13 +259,13 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let pid = unsafe { Pid::from_raw(pid) }; let proc = Process::get(pid).ok_or(Errno::DoesNotExist)?; if proc.sid() != current.sid() { - return Err(Errno::PermissionDenied) + return Err(Errno::PermissionDenied); } proc }; Ok(proc.sid().value() as usize) - }, + } SystemCall::GetPgid => { // TODO handle kernel processes here? let pid = args[0] as u32; @@ -269,10 +278,8 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { }; Ok(proc.pgid().value() as usize) - }, - SystemCall::GetPpid => { - Ok(Process::current().ppid().unwrap().value() as usize) - }, + } + SystemCall::GetPpid => Ok(Process::current().ppid().unwrap().value() as usize), SystemCall::SetSid => { let proc = Process::current(); let mut io = proc.io.lock(); @@ -282,17 +289,13 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { } todo!(); - }, + } SystemCall::SetPgid => { let pid = args[0] as u32; let pgid = args[1] as u32; let current = Process::current(); - let proc = if pid == 0 { - current - } else { - todo!() - }; + let proc = if pid == 0 { current } else { todo!() }; if pgid == 0 { proc.set_pgid(proc.id()); @@ -301,13 +304,13 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { } Ok(proc.pgid().value() as usize) - }, + } // System SystemCall::GetCpuTime => { let time = machine::local_timer().timestamp()?; Ok(time.as_nanos() as usize) - }, + } // Debugging SystemCall::DebugTrace => { @@ -316,9 +319,9 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { print!(Level::Debug, "{}", buf); println!(Level::Debug, ""); Ok(args[1]) - }, + } // Handled elsewhere - SystemCall::Fork => unreachable!() + SystemCall::Fork => unreachable!(), } } diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index fad27ff..7fb3eb4 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -12,6 +12,7 @@ pub enum SystemCall { Ioctl = 6, Select = 7, Access = 8, + ReadDirectory = 9, // Process manipulation Fork = 32, Clone = 33, diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 98fdb53..aae3c28 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -4,7 +4,7 @@ use crate::{ ioctl::IoctlCmd, proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, - stat::{AccessMode, FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, + stat::{AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, }; use core::time::Duration; @@ -366,6 +366,20 @@ pub fn sys_getpgid(pid: Pid) -> Result { #[inline(always)] pub fn sys_setpgid(pid: Pid, pgid: Pid) -> Result { - Errno::from_syscall(unsafe { syscall!(SystemCall::SetPgid, argn!(pid.value()), argn!(pgid.value())) }).map(|e| unsafe { Pid::from_raw(e as u32) }) + Errno::from_syscall(unsafe { + syscall!(SystemCall::SetPgid, argn!(pid.value()), argn!(pgid.value())) + }) + .map(|e| unsafe { Pid::from_raw(e as u32) }) } +#[inline(always)] +pub fn sys_readdir(fd: FileDescriptor, buf: &mut [DirectoryEntry]) -> Result { + Errno::from_syscall(unsafe { + syscall!( + SystemCall::ReadDirectory, + argn!(u32::from(fd)), + argp!(buf.as_mut_ptr()), + argn!(buf.len()) + ) + }) +} diff --git a/libsys/src/stat.rs b/libsys/src/stat.rs index a59be78..7ba0ecb 100644 --- a/libsys/src/stat.rs +++ b/libsys/src/stat.rs @@ -1,5 +1,5 @@ -use core::fmt; use crate::error::Errno; +use core::fmt; const AT_FDCWD: i32 = -2; pub const AT_EMPTY_PATH: u32 = 1 << 16; @@ -14,11 +14,16 @@ bitflags! { const O_CREAT = 1 << 4; const O_EXEC = 1 << 5; const O_CLOEXEC = 1 << 6; + const O_DIRECTORY = 1 << 7; } } bitflags! { pub struct FileMode: u32 { + const FILE_TYPE = 0xF << 12; + const S_IFREG = 0x8 << 12; + const S_IFDIR = 0x4 << 12; + const USER_READ = 1 << 8; const USER_WRITE = 1 << 7; const USER_EXEC = 1 << 6; @@ -42,26 +47,57 @@ bitflags! { #[derive(Clone, Default)] pub struct FdSet { - bits: [u64; 2] + bits: [u64; 2], } #[derive(Clone, Copy, Debug)] #[repr(transparent)] pub struct FileDescriptor(u32); +#[derive(Clone, Copy)] +pub struct DirectoryEntry { + name: [u8; 64], +} + struct FdSetIter<'a> { idx: u32, - set: &'a FdSet + set: &'a FdSet, } #[derive(Clone, Copy, Debug, Default)] #[repr(C)] pub struct Stat { - pub mode: u32, + pub mode: FileMode, pub size: u64, pub blksize: u32, } +impl DirectoryEntry { + pub const fn empty() -> Self { + Self { name: [0; 64] } + } + + pub fn from_str(i: &str) -> DirectoryEntry { + let mut res = DirectoryEntry { name: [0; 64] }; + let bytes = i.as_bytes(); + res.name[..bytes.len()].copy_from_slice(bytes); + res + } + + pub fn as_str(&self) -> &str { + let zero = self.name.iter().position(|&c| c == 0).unwrap(); + core::str::from_utf8(&self.name[..zero]).unwrap() + } +} + +impl fmt::Debug for DirectoryEntry { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("DirectoryEntry") + .field("name", &self.as_str()) + .finish() + } +} + impl FdSet { pub const fn empty() -> Self { Self { bits: [0; 2] } @@ -93,10 +129,7 @@ impl FdSet { } pub fn iter(&self) -> impl Iterator + '_ { - FdSetIter { - idx: 0, - set: self - } + FdSetIter { idx: 0, set: self } } } @@ -131,13 +164,51 @@ impl fmt::Debug for FdSet { impl FileMode { /// Returns default permission set for directories - pub const fn default_dir() -> Self { - unsafe { Self::from_bits_unchecked(0o755) } + pub fn default_dir() -> Self { + unsafe { Self::from_bits_unchecked(0o755) | Self::S_IFDIR } } /// Returns default permission set for regular files - pub const fn default_reg() -> Self { - unsafe { Self::from_bits_unchecked(0o644) } + pub fn default_reg() -> Self { + unsafe { Self::from_bits_unchecked(0o644) | Self::S_IFREG } + } +} + +fn choose(q: bool, a: T, b: T) -> T { + if q { a } else { b } +} + +impl Default for FileMode { + fn default() -> Self { + unsafe { Self::from_bits_unchecked(0) } + } +} + +impl fmt::Display for FileMode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}{}{}{}{}{}{}{}{}{}", + // File type + match *self & Self::FILE_TYPE { + Self::S_IFDIR => 'd', + Self::S_IFREG => '-', + _ => '?' + }, + // User + choose(self.contains(Self::USER_READ), 'r', '-'), + choose(self.contains(Self::USER_WRITE), 'w', '-'), + choose(self.contains(Self::USER_EXEC), 'x', '-'), + // Group + choose(self.contains(Self::GROUP_READ), 'r', '-'), + choose(self.contains(Self::GROUP_WRITE), 'w', '-'), + choose(self.contains(Self::GROUP_EXEC), 'x', '-'), + // Other + choose(self.contains(Self::OTHER_READ), 'r', '-'), + choose(self.contains(Self::OTHER_WRITE), 'w', '-'), + choose(self.contains(Self::OTHER_EXEC), 'x', '-'), + ); + Ok(()) } } diff --git a/user/Cargo.toml b/user/Cargo.toml index 8cb69ab..91af3a7 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -17,6 +17,10 @@ path = "src/shell/main.rs" name = "fuzzy" path = "src/fuzzy/main.rs" +[[bin]] +name = "ls" +path = "src/ls/main.rs" + [dependencies] libusr = { path = "../libusr" } lazy_static = { version = "*", features = ["spin_no_std"] } diff --git a/user/src/ls/main.rs b/user/src/ls/main.rs new file mode 100644 index 0000000..91d8ebb --- /dev/null +++ b/user/src/ls/main.rs @@ -0,0 +1,45 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate libusr; +#[macro_use] +extern crate alloc; + +use libusr::sys::{sys_readdir, sys_openat, sys_close, sys_fstatat, stat::{FileMode, OpenFlags, DirectoryEntry, Stat}}; +use alloc::{string::String, borrow::ToOwned}; + +#[no_mangle] +fn main() -> i32 { + let mut buffer = [DirectoryEntry::empty(); 16]; + let mut stat = Stat::default(); + let mut data = vec![]; + + let fd = sys_openat(None, "/", FileMode::default_dir(), OpenFlags::O_DIRECTORY | OpenFlags::O_RDONLY).unwrap(); + + loop { + let count = sys_readdir(fd, &mut buffer).unwrap(); + if count == 0 { + break; + } + + buffer.iter().take(count).for_each(|e| data.push(e.as_str().to_owned())); + } + + data.sort(); + + data.iter().for_each(|item| { + let stat = sys_fstatat(Some(fd), item, &mut stat, 0).map(|_| &stat); + if let Ok(stat) = stat { + print!("{} ", stat.mode); + } else { + print!("?????????? "); + } + println!("{}", item); + }); + + sys_close(fd).unwrap(); + + + 0 +} From 7f939543fe9abb219b5e9370ceefe8823e1bf1f8 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 23 Nov 2021 18:01:48 +0200 Subject: [PATCH 34/42] refactor: make Vnode::stat() return Stat --- fs/macros/src/lib.rs | 4 ++-- fs/memfs/src/dir.rs | 11 ++++++----- fs/memfs/src/file.rs | 11 ++++++----- fs/vfs/src/node.rs | 6 +++--- kernel/src/syscall/mod.rs | 3 ++- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/fs/macros/src/lib.rs b/fs/macros/src/lib.rs index c3c4c84..91d79e9 100644 --- a/fs/macros/src/lib.rs +++ b/fs/macros/src/lib.rs @@ -31,8 +31,8 @@ fn impl_inode_fn(name: &str, behavior: T) -> ImplItem { } }, "stat" => quote! { - fn stat(&mut self, _at: VnodeRef, _stat: &mut libsys::stat::Stat) -> - Result<(), libsys::error::Errno> + fn stat(&mut self, _at: VnodeRef) -> + Result { #behavior } diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index fc1caea..2dbca3c 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -35,12 +35,13 @@ impl VnodeImpl for DirInode { Ok(()) } - fn stat(&mut self, node: VnodeRef, stat: &mut Stat) -> Result<(), Errno> { + fn stat(&mut self, node: VnodeRef) -> Result { let props = node.props(); - stat.size = 0; - stat.blksize = 4096; - stat.mode = props.mode; - Ok(()) + Ok(Stat { + size: 0, + blksize: 4096, + mode: props.mode + }) } } diff --git a/fs/memfs/src/file.rs b/fs/memfs/src/file.rs index 13d31b6..c3b8e8d 100644 --- a/fs/memfs/src/file.rs +++ b/fs/memfs/src/file.rs @@ -35,12 +35,13 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { Ok(self.data.size()) } - fn stat(&mut self, node: VnodeRef, stat: &mut Stat) -> Result<(), Errno> { + fn stat(&mut self, node: VnodeRef) -> Result { let props = node.props(); - stat.size = self.data.size() as u64; - stat.blksize = 4096; - stat.mode = props.mode; - Ok(()) + Ok(Stat { + size: self.data.size() as u64, + blksize: 4096, + mode: props.mode + }) } } diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index d21b058..62ae21b 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -82,7 +82,7 @@ pub trait VnodeImpl { ) -> Result; /// Retrieves file status - fn stat(&mut self, node: VnodeRef, stat: &mut Stat) -> Result<(), Errno>; + fn stat(&mut self, node: VnodeRef) -> Result; /// Reports the size of this filesystem object in bytes fn size(&mut self, node: VnodeRef) -> Result; @@ -451,9 +451,9 @@ impl Vnode { } /// Reports file status - pub fn stat(self: &VnodeRef, stat: &mut Stat) -> Result<(), Errno> { + pub fn stat(self: &VnodeRef) -> Result { if let Some(ref mut data) = *self.data() { - data.stat(self.clone(), stat) + data.stat(self.clone()) } else { Err(Errno::NotImplemented) } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 1896f48..557e3f0 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -107,7 +107,8 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let proc = Process::current(); let mut io = proc.io.lock(); - find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat(buf)?; + let stat = find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat()?; + *buf = stat; Ok(0) } SystemCall::Ioctl => { From 47b67fa93cf31f5bd13dc270a5870ac60e441edf Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 24 Nov 2021 15:16:34 +0200 Subject: [PATCH 35/42] feature: passing args to execve() --- kernel/src/init.rs | 2 +- kernel/src/mem/virt/table.rs | 17 ++++++ kernel/src/proc/process.rs | 112 ++++++++++++++++++++++++++++++----- kernel/src/syscall/arg.rs | 18 +++++- kernel/src/syscall/mod.rs | 10 +++- libsys/src/calls.rs | 6 +- libsys/src/lib.rs | 8 +++ libsys/src/mem.rs | 2 +- libusr/src/env.rs | 21 +++++++ libusr/src/lib.rs | 11 ++-- user/src/init/main.rs | 2 +- user/src/ls/main.rs | 52 ++++++++++++---- user/src/shell/main.rs | 20 +++---- 13 files changed, 228 insertions(+), 53 deletions(-) create mode 100644 libusr/src/env.rs diff --git a/kernel/src/init.rs b/kernel/src/init.rs index f390019..2c876c0 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -59,6 +59,6 @@ pub extern "C" fn init_fn(_arg: usize) -> ! { drop(cfg); - Process::execve(|space| elf::load_elf(space, file), 0).unwrap(); + Process::execve(|space| elf::load_elf(space, file), &["/init"]).unwrap(); panic!("Unreachable"); } diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index 12985a0..cabeb5f 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -210,6 +210,23 @@ impl Space { } } + // TODO extract attributes + pub fn translate(&mut self, virt: usize) -> Result { + let l0i = virt >> 30; + let l1i = (virt >> 21) & 0x1FF; + let l2i = (virt >> 12) & 0x1FF; + + let l1_table = self.0.next_level_table(l0i).ok_or(Errno::DoesNotExist)?; + let l2_table = l1_table.next_level_table(l1i).ok_or(Errno::DoesNotExist)?; + + let entry = l2_table[l2i]; + if entry.is_present() { + Ok(unsafe { entry.address_unchecked() }) + } else { + Err(Errno::DoesNotExist) + } + } + /// Attempts to resolve a page fault at `virt` address by copying the /// underlying Copy-on-Write mapping (if any is present) pub fn try_cow_copy(&mut self, virt: usize) -> Result<(), Errno> { diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index af18b48..154d20d 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -10,13 +10,16 @@ use crate::proc::{ }; use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard}; use alloc::{rc::Rc, vec::Vec}; +use core::alloc::Layout; use core::sync::atomic::{AtomicU32, Ordering}; use libsys::{ error::Errno, proc::{ExitCode, Pid}, signal::Signal, + mem::memcpy, + ProgramArgs, }; -use vfs::{VnodeRef, VnodeKind}; +use vfs::{VnodeKind, VnodeRef}; /// Wrapper type for a process struct reference pub type ProcessRef = Rc; @@ -134,8 +137,7 @@ impl Process { /// Sets a pending signal for a process pub fn set_signal(&self, signal: Signal) { let mut lock = self.inner.lock(); - let ttbr0 = - lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48); + let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48); let main_thread = Thread::get(lock.threads[0]).unwrap(); drop(lock); @@ -164,8 +166,7 @@ impl Process { pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) { let mut lock = self.inner.lock(); - let ttbr0 = - lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48); + let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48); thread.enter_signal(signal, ttbr0); } @@ -210,7 +211,7 @@ impl Process { id: dst_id, pgid: src_inner.pgid, ppid: Some(src_inner.id), - sid: src_inner.sid + sid: src_inner.sid, }), }); @@ -319,10 +320,96 @@ impl Process { } } + fn write_paged(space: &mut Space, dst: usize, src: T) -> Result<(), Errno> { + let size = core::mem::size_of::(); + if (size + (dst % 4096)) > 4096 { + todo!("Object crossed page boundary"); + } + + let page_virt = dst & !4095; + let page_phys = if let Ok(phys) = space.translate(dst) { + phys + } else { + let page = phys::alloc_page(PageUsage::UserPrivate)?; + let flags = MapAttributes::SH_OUTER | + MapAttributes::NOT_GLOBAL | + MapAttributes::UXN | + MapAttributes::PXN | + MapAttributes::AP_BOTH_READONLY; + space.map(page_virt, page, flags)?; + page + }; + + unsafe { + core::ptr::write((mem::virtualize(page_phys) + (dst % 4096)) as *mut T, src); + } + Ok(()) + } + + fn write_paged_bytes(space: &mut Space, dst: usize, src: &[u8]) -> Result<(), Errno> { + if (src.len() + (dst % 4096)) > 4096 { + todo!("Object crossed page boundary"); + } + let page_virt = dst & !4095; + let page_phys = if let Ok(phys) = space.translate(dst) { + phys + } else { + let page = phys::alloc_page(PageUsage::UserPrivate)?; + let flags = MapAttributes::SH_OUTER | + MapAttributes::NOT_GLOBAL | + MapAttributes::UXN | + MapAttributes::PXN | + MapAttributes::AP_BOTH_READONLY; + space.map(page_virt, page, flags)?; + page + }; + + unsafe { + memcpy((mem::virtualize(page_phys) + (dst % 4096)) as *mut u8, src.as_ptr(), src.len()); + } + Ok(()) + } + + fn store_arguments(space: &mut Space, argv: &[&str]) -> Result { + let mut offset = 0usize; + // TODO vmalloc? + let base = 0x60000000; + + // 1. Store program argument string bytes + for arg in argv.iter() { + Self::write_paged_bytes(space, base + offset, arg.as_bytes())?; + offset += arg.len(); + } + // Align + offset = (offset + 15) & !15; + let argv_offset = offset; + + // 2. Store arg pointers + let mut data_offset = 0usize; + for arg in argv.iter() { + // XXX this is really unsafe and I am not really sure ABI will stay like this XXX + Self::write_paged(space, base + offset + 0, base + data_offset)?; + Self::write_paged(space, base + offset + 8, arg.len())?; + offset += 16; + data_offset += arg.len(); + } + + // 3. Store ProgramArgs + let data = ProgramArgs { + argc: argv.len(), + argv: base + argv_offset, + storage: base, + size: offset + core::mem::size_of::() + }; + Self::write_paged(space, base + offset, data)?; + + Ok(base + offset) + } + /// Loads a new program into current process address space pub fn execve Result>( loader: F, - arg: usize, + argv: &[&str], ) -> Result<(), Errno> { unsafe { // Run with interrupts disabled @@ -351,12 +438,6 @@ impl Process { process_lock.sid = new_pid; let r = processes.insert(new_pid, proc.clone()); assert!(r.is_none()); - } else { - // Invalidate user ASID - let input = (process_lock.id.asid() as usize) << 48; - unsafe { - asm!("tlbi aside1, {}", in(reg) input); - } } thread.set_owner(process_lock.id); @@ -380,6 +461,7 @@ impl Process { } let entry = loader(new_space)?; + let arg = Self::store_arguments(new_space, argv)?; debugln!("Will now enter at {:#x}", entry); // TODO drop old address space @@ -388,11 +470,13 @@ impl Process { unsafe { // TODO drop old context let ctx = thread.ctx.get(); + let asid = (process_lock.id.asid() as usize) << 48; + asm!("tlbi aside1, {}", in(reg) asid); ctx.write(Context::user( entry, arg, - new_space_phys | ((process_lock.id.asid() as usize) << 48), + new_space_phys | asid, Self::USTACK_VIRT_TOP, )); diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index c64075d..629ec96 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -62,6 +62,19 @@ pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> { Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) } +pub fn struct_buf_ref<'a, T>(base: usize, count: usize) -> Result<&'a [T], Errno> { + let layout = Layout::array::(count).unwrap(); + if base % layout.align() != 0 { + invalid_memory!( + "Structure pointer is misaligned: base={:#x}, expected {:?}", + base, + layout + ); + } + let bytes = buf_ref(base, layout.size())?; + Ok(unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *const T, count) }) +} + pub fn struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<&'a mut [T], Errno> { let layout = Layout::array::(count).unwrap(); if base % layout.align() != 0 { @@ -91,7 +104,7 @@ pub fn option_struct_mut<'a, T>(base: usize) -> Result, Errno> } } -fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> { +pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> { if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET { invalid_memory!( "User region refers to kernel memory: base={:#x}, len={:#x}", @@ -111,8 +124,7 @@ fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> { space.try_cow_copy(i * mem::PAGE_SIZE) }) } else { - todo!(); - // Err(Errno::DoesNotExist) + Err(Errno::DoesNotExist) }; if res.is_ok() { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 557e3f0..8cdac5b 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -54,7 +54,6 @@ fn find_at_node>( /// Main system call dispatcher function pub fn syscall(num: SystemCall, args: &[usize]) -> Result { - // debugln!("syscall {:?}", num); match num { // I/O SystemCall::Read => { @@ -165,17 +164,22 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { .map(|e| e as usize) } SystemCall::Exec => { + let filename = arg::str_ref(args[0], args[1])?; + let argv = arg::struct_buf_ref::<&str>(args[2], args[3])?; + // Validate each argument as well + for item in argv.iter() { + arg::validate_ptr(item.as_ptr() as usize, item.len(), false)?; + } let node = { let proc = Process::current(); let mut io = proc.io.lock(); - let filename = arg::str_ref(args[0], args[1])?; // TODO argv, envp array passing ABI? let node = io.ioctx().find(None, filename, true)?; drop(io); node }; let file = node.open(OpenFlags::O_RDONLY)?; - Process::execve(move |space| elf::load_elf(space, file), 0).unwrap(); + Process::execve(move |space| elf::load_elf(space, file), argv).unwrap(); panic!(); } SystemCall::Exit => { diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index aae3c28..7405fc1 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -204,12 +204,14 @@ pub unsafe fn sys_fork() -> Result, Errno> { /// /// System call #[inline(always)] -pub fn sys_execve(pathname: &str) -> Result<(), Errno> { +pub fn sys_execve(pathname: &str, argv: &[&str]) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( SystemCall::Exec, argp!(pathname.as_ptr()), - argn!(pathname.len()) + argn!(pathname.len()), + argp!(argv.as_ptr()), + argn!(argv.len()) ) }) } diff --git a/libsys/src/lib.rs b/libsys/src/lib.rs index 71f984e..8c4e278 100644 --- a/libsys/src/lib.rs +++ b/libsys/src/lib.rs @@ -15,6 +15,14 @@ pub mod stat; pub mod termios; pub mod traits; +#[derive(Debug)] +pub struct ProgramArgs { + pub argv: usize, + pub argc: usize, + pub storage: usize, + pub size: usize +} + #[cfg(feature = "user")] pub mod calls; #[cfg(feature = "user")] diff --git a/libsys/src/mem.rs b/libsys/src/mem.rs index 021c7cc..64a33c6 100644 --- a/libsys/src/mem.rs +++ b/libsys/src/mem.rs @@ -13,7 +13,7 @@ pub fn read_le16(src: &[u8]) -> u16 { /// Unsafe: writes to arbitrary memory locations, performs no pointer /// validation. #[no_mangle] -pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *mut u8, mut len: usize) -> *mut u8 { +pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *const u8, mut len: usize) -> *mut u8 { while len != 0 { len -= 1; *dst.add(len) = *src.add(len); diff --git a/libusr/src/env.rs b/libusr/src/env.rs new file mode 100644 index 0000000..42a0226 --- /dev/null +++ b/libusr/src/env.rs @@ -0,0 +1,21 @@ +use libsys::ProgramArgs; +use alloc::vec::Vec; +use crate::trace; + +static mut PROGRAM_ARGS: Vec<&'static str> = Vec::new(); + +pub fn args() -> &'static [&'static str] { + unsafe { &PROGRAM_ARGS } +} + +pub(crate) unsafe fn setup_env(arg: &ProgramArgs) { + for i in 0..arg.argc { + let base = core::ptr::read((arg.argv + i * 16 + 0) as *const *const u8); + let len = core::ptr::read((arg.argv + i * 16 + 8) as *const usize); + + let string = core::str::from_utf8(core::slice::from_raw_parts(base, len)).unwrap(); + PROGRAM_ARGS.push(string); + } + + trace!("args = {:?}", PROGRAM_ARGS); +} diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index f13a1e9..4474625 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -1,15 +1,16 @@ #![feature(asm, alloc_error_handler)] #![no_std] -use core::panic::PanicInfo; -use libsys::proc::ExitCode; - #[macro_use] extern crate lazy_static; extern crate alloc; +use core::panic::PanicInfo; +use libsys::{ProgramArgs, proc::ExitCode}; + mod allocator; +pub mod env; pub mod file; pub mod io; pub mod os; @@ -18,16 +19,16 @@ pub mod sync; pub mod thread; pub mod signal; - #[link_section = ".text._start"] #[no_mangle] -extern "C" fn _start(_arg: usize) -> ! { +extern "C" fn _start(arg: &'static ProgramArgs) -> ! { extern "Rust" { fn main() -> i32; } unsafe { thread::init_main(); + env::setup_env(arg); } let res = unsafe { main() }; diff --git a/user/src/init/main.rs b/user/src/init/main.rs index 02bebcc..2161d0f 100644 --- a/user/src/init/main.rs +++ b/user/src/init/main.rs @@ -20,7 +20,7 @@ fn main() -> i32 { } } } else { - libusr::sys::sys_execve("/bin/shell").unwrap(); + libusr::sys::sys_execve("/bin/shell", &["/bin/shell"]).unwrap(); loop {} } } diff --git a/user/src/ls/main.rs b/user/src/ls/main.rs index 91d8ebb..d50f795 100644 --- a/user/src/ls/main.rs +++ b/user/src/ls/main.rs @@ -6,24 +6,33 @@ extern crate libusr; #[macro_use] extern crate alloc; -use libusr::sys::{sys_readdir, sys_openat, sys_close, sys_fstatat, stat::{FileMode, OpenFlags, DirectoryEntry, Stat}}; -use alloc::{string::String, borrow::ToOwned}; +use alloc::{borrow::ToOwned, string::String}; +use libusr::sys::{ + stat::{DirectoryEntry, FileMode, OpenFlags, Stat}, + sys_close, sys_fstatat, sys_openat, sys_readdir, Errno, +}; -#[no_mangle] -fn main() -> i32 { - let mut buffer = [DirectoryEntry::empty(); 16]; +fn list_directory(path: &str) -> Result<(), Errno> { + let mut buffer = [DirectoryEntry::empty(); 8]; let mut stat = Stat::default(); let mut data = vec![]; - let fd = sys_openat(None, "/", FileMode::default_dir(), OpenFlags::O_DIRECTORY | OpenFlags::O_RDONLY).unwrap(); + let fd = sys_openat( + None, + path, + FileMode::default_dir(), + OpenFlags::O_DIRECTORY | OpenFlags::O_RDONLY, + )?; loop { - let count = sys_readdir(fd, &mut buffer).unwrap(); + let count = sys_readdir(fd, &mut buffer)?; if count == 0 { break; } - buffer.iter().take(count).for_each(|e| data.push(e.as_str().to_owned())); + buffer.iter().take(count).for_each(|e| { + data.push(e.as_str().to_owned()); + }); } data.sort(); @@ -38,8 +47,27 @@ fn main() -> i32 { println!("{}", item); }); - sys_close(fd).unwrap(); - - - 0 + sys_close(fd) +} + +#[no_mangle] +fn main() -> i32 { + let args = libusr::env::args(); + let mut res = 0; + + if args.len() == 1 { + if let Err(e) = list_directory(".") { + eprintln!("{}: {:?}", ".", e); + res = -1; + } + } else { + for arg in &args[1..] { + if let Err(e) = list_directory(arg) { + eprintln!("{}: {:?}", arg, e); + res = -1; + } + } + } + + res } diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 054c443..9d7f410 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -5,7 +5,7 @@ extern crate libusr; extern crate alloc; -use alloc::borrow::ToOwned; +use alloc::{borrow::ToOwned, vec::Vec}; use libusr::io::{self, Read}; use libusr::signal::{self, SignalHandler}; use libusr::sys::{ @@ -26,16 +26,10 @@ fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result ! { - let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap(); - io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); - sys_execve(&("/bin/".to_owned() + cmd)).unwrap(); - sys_exit(ExitCode::from(-1)); -} - fn execute(line: &str) -> Result { - let mut words = line.split(' '); - let cmd = words.next().unwrap(); + // TODO proper arg handling + let args: Vec<&str> = line.split(' ').collect(); + let cmd = args[0]; if let Some(pid) = unsafe { sys_fork()? } { let mut status = 0; @@ -44,7 +38,11 @@ fn execute(line: &str) -> Result { io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); Ok(ExitCode::from(status)) } else { - execvp(cmd); + let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap(); + io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); + let filename = "/bin/".to_owned() + cmd; + sys_execve(&filename, &args).unwrap(); + sys_exit(ExitCode::from(-1)); } } From 61a92920c298e44465c57e45dcd4c1868c311a06 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 25 Nov 2021 12:02:25 +0200 Subject: [PATCH 36/42] feature: trace! levels --- kernel/src/debug.rs | 15 ++++++++++++++- kernel/src/syscall/mod.rs | 10 ++++++---- libsys/src/calls.rs | 4 +++- libsys/src/debug.rs | 10 ++++++++++ libsys/src/lib.rs | 1 + libusr/src/allocator.rs | 6 +++--- libusr/src/env.rs | 4 ++-- libusr/src/lib.rs | 4 ++-- libusr/src/os.rs | 13 ++++++++++--- libusr/src/signal.rs | 3 ++- libusr/src/sys/mod.rs | 1 + user/src/fuzzy/main.rs | 2 +- user/src/shell/main.rs | 9 +++++++-- 13 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 libsys/src/debug.rs diff --git a/kernel/src/debug.rs b/kernel/src/debug.rs index 067eefe..d75bab0 100644 --- a/kernel/src/debug.rs +++ b/kernel/src/debug.rs @@ -12,6 +12,7 @@ //! * [errorln!] use crate::dev::serial::SerialDevice; +use libsys::debug::TraceLevel; use core::fmt; /// Kernel logging levels @@ -27,6 +28,18 @@ pub enum Level { Error, } +impl From for Level { + #[inline(always)] + fn from(l: TraceLevel) -> Self { + match l { + TraceLevel::Debug => Self::Debug, + TraceLevel::Info => Self::Info, + TraceLevel::Warn => Self::Warn, + TraceLevel::Error => Self::Error, + } + } +} + struct SerialOutput { inner: &'static T, } @@ -101,7 +114,7 @@ macro_rules! errorln { } #[doc(hidden)] -pub fn _debug(_level: Level, args: fmt::Arguments) { +pub fn _debug(level: Level, args: fmt::Arguments) { use crate::arch::machine; use fmt::Write; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 8cdac5b..762d909 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -9,6 +9,7 @@ use core::ops::DerefMut; use core::time::Duration; use libsys::{ abi::SystemCall, + debug::TraceLevel, error::Errno, ioctl::IoctlCmd, proc::{ExitCode, Pid}, @@ -319,10 +320,11 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { // Debugging SystemCall::DebugTrace => { - let buf = arg::str_ref(args[0], args[1])?; - print!(Level::Debug, "[trace] "); - print!(Level::Debug, "{}", buf); - println!(Level::Debug, ""); + let level = TraceLevel::from_repr(args[0]).map(Level::from).ok_or(Errno::InvalidArgument)?; + let buf = arg::str_ref(args[1], args[2])?; + let thread = Thread::current(); + let proc = thread.owner().unwrap(); + println!(level, "[trace {:?}:{}] {}", proc.id(), thread.id(), buf); Ok(args[1]) } diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 7405fc1..d78abb6 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -1,6 +1,7 @@ use crate::abi::SystemCall; use crate::{ error::Errno, + debug::TraceLevel, ioctl::IoctlCmd, proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, @@ -104,10 +105,11 @@ pub fn sys_ex_nanosleep(ns: u64, rem: &mut [u64; 2]) -> Result<(), Errno> { /// /// System call #[inline(always)] -pub fn sys_ex_debug_trace(msg: &[u8]) -> Result<(), Errno> { +pub fn sys_ex_debug_trace(level: TraceLevel, msg: &[u8]) -> Result<(), Errno> { Errno::from_syscall_unit(unsafe { syscall!( SystemCall::DebugTrace, + argn!(level.repr()), argp!(msg.as_ptr()), argn!(msg.len()) ) diff --git a/libsys/src/debug.rs b/libsys/src/debug.rs new file mode 100644 index 0000000..cafc5d9 --- /dev/null +++ b/libsys/src/debug.rs @@ -0,0 +1,10 @@ +use enum_repr::EnumRepr; + +#[EnumRepr(type = "usize")] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum TraceLevel { + Debug = 1, + Info = 2, + Warn = 3, + Error = 4, +} diff --git a/libsys/src/lib.rs b/libsys/src/lib.rs index 8c4e278..ddafbff 100644 --- a/libsys/src/lib.rs +++ b/libsys/src/lib.rs @@ -5,6 +5,7 @@ extern crate bitflags; pub mod abi; +pub mod debug; pub mod error; pub mod ioctl; pub mod mem; diff --git a/libusr/src/allocator.rs b/libusr/src/allocator.rs index 7976520..c803689 100644 --- a/libusr/src/allocator.rs +++ b/libusr/src/allocator.rs @@ -1,6 +1,6 @@ use core::alloc::{Layout, GlobalAlloc}; use core::sync::atomic::{AtomicUsize, Ordering}; -use libsys::mem::memset; +use libsys::{debug::TraceLevel, mem::memset}; use crate::trace; @@ -16,14 +16,14 @@ unsafe impl GlobalAlloc for Allocator { if res > 65536 { panic!("Out of memory"); } - trace!("alloc({:?}) = {:p}", layout, &ALLOC_DATA[res]); + trace!(TraceLevel::Debug, "alloc({:?}) = {:p}", layout, &ALLOC_DATA[res]); let res = &mut ALLOC_DATA[res] as *mut _; memset(res, 0, layout.size()); res } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - trace!("free({:p}, {:?})", ptr, layout); + trace!(TraceLevel::Debug, "free({:p}, {:?})", ptr, layout); } } diff --git a/libusr/src/env.rs b/libusr/src/env.rs index 42a0226..ce81bc6 100644 --- a/libusr/src/env.rs +++ b/libusr/src/env.rs @@ -1,4 +1,4 @@ -use libsys::ProgramArgs; +use libsys::{debug::TraceLevel, ProgramArgs}; use alloc::vec::Vec; use crate::trace; @@ -17,5 +17,5 @@ pub(crate) unsafe fn setup_env(arg: &ProgramArgs) { PROGRAM_ARGS.push(string); } - trace!("args = {:?}", PROGRAM_ARGS); + trace!(TraceLevel::Debug, "args = {:?}", PROGRAM_ARGS); } diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index 4474625..7386805 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -7,7 +7,7 @@ extern crate lazy_static; extern crate alloc; use core::panic::PanicInfo; -use libsys::{ProgramArgs, proc::ExitCode}; +use libsys::{debug::TraceLevel, ProgramArgs, proc::ExitCode}; mod allocator; pub mod env; @@ -40,6 +40,6 @@ fn panic_handler(pi: &PanicInfo) -> ! { // TODO unwind to send panic argument back to parent thread // TODO print to stdout/stderr (if available) let thread = thread::current(); - trace!("{:?} panicked: {:?}", thread, pi); + trace!(TraceLevel::Error, "{:?} panicked: {:?}", thread, pi); sys::sys_exit(ExitCode::from(-1)); } diff --git a/libusr/src/os.rs b/libusr/src/os.rs index f7d0f10..3c9a592 100644 --- a/libusr/src/os.rs +++ b/libusr/src/os.rs @@ -1,9 +1,16 @@ +use libsys::debug::TraceLevel; use crate::sys; use core::fmt; #[macro_export] macro_rules! trace { - ($($args:tt)+) => ($crate::os::_trace(format_args!($($args)+))) + ($level:expr, $($args:tt)+) => ($crate::os::_trace($level, format_args!($($args)+))) +} + + +#[macro_export] +macro_rules! trace_debug { + ($($args:tt)+) => ($crate::os::_trace($crate::sys::debug::TraceLevel::Debug, format_args!($($args)+))) } struct BufferWriter<'a> { @@ -21,7 +28,7 @@ impl fmt::Write for BufferWriter<'_> { } } -pub fn _trace(args: fmt::Arguments) { +pub fn _trace(level: TraceLevel, args: fmt::Arguments) { use core::fmt::Write; static mut BUFFER: [u8; 4096] = [0; 4096]; let mut writer = BufferWriter { @@ -29,5 +36,5 @@ pub fn _trace(args: fmt::Arguments) { pos: 0, }; writer.write_fmt(args).ok(); - sys::sys_ex_debug_trace(unsafe { &BUFFER[..writer.pos] }).ok(); + sys::sys_ex_debug_trace(level, unsafe { &BUFFER[..writer.pos] }).ok(); } diff --git a/libusr/src/signal.rs b/libusr/src/signal.rs index f34793c..8417122 100644 --- a/libusr/src/signal.rs +++ b/libusr/src/signal.rs @@ -1,5 +1,6 @@ use crate::trace; use libsys::{ + debug::TraceLevel, calls::{sys_ex_sigreturn, sys_exit}, proc::ExitCode, signal::Signal, @@ -26,7 +27,7 @@ pub fn set_handler(sig: Signal, handler: SignalHandler) -> SignalHandler { #[inline(never)] pub(crate) extern "C" fn signal_handler(arg: Signal) -> ! { // TODO tpidr_el0 is invalidated when entering signal context - trace!("Entered signal handler: arg={:?}", arg); + trace!(TraceLevel::Debug, "Entered signal handler: arg={:?}", arg); let no = arg as usize; if no >= 32 { panic!("Undefined signal number: {}", no); diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs index e6727f4..06ac158 100644 --- a/libusr/src/sys/mod.rs +++ b/libusr/src/sys/mod.rs @@ -5,6 +5,7 @@ pub use libsys::abi; pub use libsys::calls::*; pub use libsys::stat::{self, AccessMode, FileDescriptor}; pub use libsys::error::Errno; +pub use libsys::debug; use core::sync::atomic::{Ordering, AtomicBool}; diff --git a/user/src/fuzzy/main.rs b/user/src/fuzzy/main.rs index 6b06d79..36a2629 100644 --- a/user/src/fuzzy/main.rs +++ b/user/src/fuzzy/main.rs @@ -110,7 +110,7 @@ fn random_bytes(buf: &mut [u8]) { #[no_mangle] fn main() -> i32 { let seed = libusr::sys::sys_ex_getcputime().unwrap().as_nanos() as u64 / 13; - trace!("Using seed: {:#x}", seed); + println!("Using seed: {:#x}", seed); random_set_seed(seed); let mut buf = [0; 256]; diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 9d7f410..5ecfa12 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -10,6 +10,7 @@ use libusr::io::{self, Read}; use libusr::signal::{self, SignalHandler}; use libusr::sys::{ proc::Pid, sys_execve, sys_setpgid, sys_exit, sys_fork, sys_getpgid, sys_waitpid, Errno, ExitCode, + sys_faccessat, AccessMode, FileDescriptor, Signal, }; @@ -31,6 +32,9 @@ fn execute(line: &str) -> Result { let args: Vec<&str> = line.split(' ').collect(); let cmd = args[0]; + let filename = "/bin/".to_owned() + cmd; + sys_faccessat(None, &filename, AccessMode::X_OK, 0)?; + if let Some(pid) = unsafe { sys_fork()? } { let mut status = 0; sys_waitpid(pid, &mut status)?; @@ -40,7 +44,6 @@ fn execute(line: &str) -> Result { } else { let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap(); io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); - let filename = "/bin/".to_owned() + cmd; sys_execve(&filename, &args).unwrap(); sys_exit(ExitCode::from(-1)); } @@ -67,7 +70,9 @@ fn main() -> i32 { continue; } - execute(line).ok(); + if let Err(e) = execute(line) { + eprintln!("{}: {:?}", line.split(' ').next().unwrap(), e); + } }, Err(_) => { println!("Interrupt!"); From ed51f233eecd52d582466d65320bb07d61fc51b0 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 28 Nov 2021 00:47:45 +0200 Subject: [PATCH 37/42] fix: memcmp() was comparing in reverse lmao --- libsys/src/mem.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libsys/src/mem.rs b/libsys/src/mem.rs index 64a33c6..b67d35e 100644 --- a/libsys/src/mem.rs +++ b/libsys/src/mem.rs @@ -28,15 +28,16 @@ pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *const u8, mut len: usize) -> /// Unsafe: performs reads from arbitrary memory locations, performs no /// pointer validation. #[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) { +pub unsafe extern "C" fn memcmp(a: *mut u8, b: *mut u8, len: usize) -> isize { + let mut off = 0; + while off != len { + if *a.add(off) < *b.add(off) { return -1; } - if *a.add(len) > *b.add(len) { + if *a.add(off) > *b.add(off) { return 1; } + off += 1; } 0 } From a7a0c8bf2c9f828c6b29ac7f842ab60acf78d314 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 28 Nov 2021 11:46:55 +0200 Subject: [PATCH 38/42] feature: login program --- Cargo.lock | 1 + Makefile | 4 +- fs/vfs/src/ioctx.rs | 22 +++++- fs/vfs/src/node.rs | 10 ++- kernel/src/fs/devfs.rs | 9 ++- kernel/src/fs/mod.rs | 12 +++ kernel/src/init.rs | 4 +- kernel/src/proc/io.rs | 53 ++++++++++++- kernel/src/proc/process.rs | 4 + kernel/src/syscall/mod.rs | 73 +++++++++++++++++- libsys/src/abi.rs | 8 ++ libsys/src/calls.rs | 68 ++++++++++++++++- libsys/src/stat.rs | 67 ++++++++++++++++ user/Cargo.toml | 5 ++ user/src/init/main.rs | 13 +++- user/src/login/main.rs | 151 +++++++++++++++++++++++++++++++++++++ user/src/shell/main.rs | 41 ++++++++-- 17 files changed, 522 insertions(+), 23 deletions(-) create mode 100644 user/src/login/main.rs diff --git a/Cargo.lock b/Cargo.lock index ef237f1..486e6d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,7 @@ name = "user" version = "0.1.0" dependencies = [ "lazy_static", + "libsys", "libusr", ] diff --git a/Makefile b/Makefile index b73183a..ba8bb46 100644 --- a/Makefile +++ b/Makefile @@ -92,11 +92,13 @@ initrd: --target=../etc/$(ARCH)-osdev5.json \ -Z build-std=core,alloc,compiler_builtins \ $(CARGO_COMMON_OPTS) - mkdir -p $(O)/rootfs/bin + mkdir -p $(O)/rootfs/bin $(O)/rootfs/sbin $(O)/rootfs/dev + touch $(O)/rootfs/dev/.do_no_remove cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin cp target/$(ARCH)-osdev5/$(PROFILE)/ls $(O)/rootfs/bin + cp target/$(ARCH)-osdev5/$(PROFILE)/login $(O)/rootfs/sbin cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"` ifeq ($(MACH),orangepi3) $(MKIMAGE) \ diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index 3dc3e25..c4d498d 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -1,8 +1,8 @@ use crate::{FileRef, VnodeKind, VnodeRef}; use libsys::{ error::Errno, - stat::{OpenFlags, FileMode}, path::{path_component_left, path_component_right}, + stat::{FileMode, GroupId, OpenFlags, UserId}, }; /// I/O context structure @@ -10,13 +10,17 @@ use libsys::{ pub struct Ioctx { root: VnodeRef, cwd: VnodeRef, + pub uid: UserId, + pub gid: GroupId, } impl Ioctx { /// Creates a new I/O context with given root node - pub fn new(root: VnodeRef) -> Self { + pub fn new(root: VnodeRef, uid: UserId, gid: GroupId) -> Self { Self { cwd: root.clone(), + uid, + gid, root, } } @@ -41,6 +45,11 @@ impl Ioctx { } } + while let Some(target) = at.target() { + assert!(at.kind() == VnodeKind::Directory); + at = target; + } + if element.is_empty() && rest.is_empty() { return Ok(at); } @@ -113,6 +122,15 @@ impl Ioctx { node.open(opts) } + + pub fn chdir(&mut self, path: &str) -> Result<(), Errno> { + let node = self.find(None, path, true)?; + if !node.is_directory() { + return Err(Errno::NotADirectory); + } + self.cwd = node; + Ok(()) + } } #[cfg(test)] diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 62ae21b..816add0 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -105,6 +105,7 @@ impl Vnode { pub const SEEKABLE: u32 = 1 << 0; pub const CACHE_READDIR: u32 = 1 << 1; + pub const CACHE_STAT: u32 = 1 << 2; /// Constructs a new [Vnode], wrapping it in [Rc]. The resulting node /// then needs to have [Vnode::set_data()] called on it to be usable. @@ -452,7 +453,14 @@ impl Vnode { /// Reports file status pub fn stat(self: &VnodeRef) -> Result { - if let Some(ref mut data) = *self.data() { + if self.flags & Self::CACHE_STAT != 0 { + let props = self.props(); + Ok(Stat { + blksize: 0, + size: 0, + mode: props.mode + }) + } else if let Some(ref mut data) = *self.data() { data.stat(self.clone()) } else { Err(Errno::NotImplemented) diff --git a/kernel/src/fs/devfs.rs b/kernel/src/fs/devfs.rs index 6a65421..3cb59c7 100644 --- a/kernel/src/fs/devfs.rs +++ b/kernel/src/fs/devfs.rs @@ -2,7 +2,7 @@ use crate::util::InitOnce; use alloc::boxed::Box; use core::sync::atomic::{AtomicUsize, Ordering}; -use libsys::error::Errno; +use libsys::{stat::FileMode, error::Errno}; use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef}; /// Possible character device kinds @@ -16,7 +16,9 @@ static DEVFS_ROOT: InitOnce = InitOnce::new(); /// Initializes devfs pub fn init() { - DEVFS_ROOT.init(Vnode::new("", VnodeKind::Directory, 0)); + let node = Vnode::new("", VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT); + node.props_mut().mode = FileMode::default_dir(); + DEVFS_ROOT.init(node); } /// Returns devfs root node reference @@ -27,7 +29,8 @@ pub fn root() -> &'static VnodeRef { fn _add_char_device(dev: &'static dyn CharDevice, name: &str) -> Result<(), Errno> { infoln!("Add char device: {}", name); - let node = Vnode::new(name, VnodeKind::Char, 0); + let node = Vnode::new(name, VnodeKind::Char, Vnode::CACHE_STAT); + node.props_mut().mode = FileMode::from_bits(0o600).unwrap() | FileMode::S_IFCHR; node.set_data(Box::new(CharDeviceWrapper::new(dev))); DEVFS_ROOT.get().attach(node); diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 2773a42..299a08d 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -3,6 +3,8 @@ use crate::mem::{ self, phys::{self, PageUsage}, }; +use libsys::{error::Errno, stat::MountOptions}; +use vfs::VnodeRef; use memfs::BlockAllocator; pub mod devfs; @@ -25,3 +27,13 @@ unsafe impl BlockAllocator for MemfsBlockAlloc { phys::free_page(phys).unwrap(); } } + +pub fn create_filesystem(options: &MountOptions) -> Result { + let fs_name = options.fs.unwrap(); + + if fs_name == "devfs" { + Ok(devfs::root().clone()) + } else { + todo!(); + } +} diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 2c876c0..db7789f 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -4,7 +4,7 @@ use crate::config::{ConfigKey, CONFIG}; use crate::fs::{devfs, MemfsBlockAlloc}; use crate::mem; use crate::proc::{elf, Process}; -use libsys::stat::{FileDescriptor, OpenFlags}; +use libsys::stat::{FileDescriptor, OpenFlags, UserId, GroupId}; use memfs::Ramfs; use vfs::{Filesystem, Ioctx}; @@ -29,7 +29,7 @@ pub extern "C" fn init_fn(_arg: usize) -> ! { unsafe { Ramfs::open(initrd_start as *mut u8, initrd_size, MemfsBlockAlloc {}).unwrap() }; let root = fs.root().unwrap(); - let ioctx = Ioctx::new(root); + let ioctx = Ioctx::new(root, UserId::root(), GroupId::root()); let node = ioctx.find(None, "/init", true).unwrap(); let file = node.open(OpenFlags::O_RDONLY | OpenFlags::O_EXEC).unwrap(); diff --git a/kernel/src/proc/io.rs b/kernel/src/proc/io.rs index c42f60f..5e4ee77 100644 --- a/kernel/src/proc/io.rs +++ b/kernel/src/proc/io.rs @@ -1,6 +1,6 @@ //! Process file descriptors and I/O context use alloc::collections::BTreeMap; -use libsys::{error::Errno, stat::FileDescriptor}; +use libsys::{error::Errno, stat::{FileDescriptor, UserId, GroupId}}; use vfs::{FileRef, Ioctx, VnodeRef, VnodeKind}; /// Process I/O context. Contains file tables, root/cwd info etc. @@ -31,6 +31,57 @@ impl ProcessIo { self.ctty.clone() } + #[inline(always)] + pub fn uid(&self) -> UserId { + self.ioctx.as_ref().unwrap().uid + } + + #[inline(always)] + pub fn gid(&self) -> GroupId { + self.ioctx.as_ref().unwrap().gid + } + + #[inline(always)] + pub fn set_uid(&mut self, uid: UserId) -> Result<(), Errno> { + let old_uid = self.uid(); + if old_uid == uid { + Ok(()) + } else if !old_uid.is_root() { + Err(Errno::PermissionDenied) + } else { + self.ioctx.as_mut().unwrap().uid = uid; + Ok(()) + } + } + + #[inline(always)] + pub fn set_gid(&mut self, gid: GroupId) -> Result<(), Errno> { + let old_gid = self.gid(); + if old_gid == gid { + Ok(()) + } else if !old_gid.is_root() { + Err(Errno::PermissionDenied) + } else { + self.ioctx.as_mut().unwrap().gid = gid; + Ok(()) + } + } + + pub fn duplicate_file(&mut self, src: FileDescriptor, dst: Option) -> Result { + let file_ref = self.file(src)?; + if let Some(dst) = dst { + let idx = u32::from(dst); + if self.files.get(&idx).is_some() { + return Err(Errno::AlreadyExists); + } + + self.files.insert(idx, file_ref); + Ok(dst) + } else { + self.place_file(file_ref) + } + } + /// Returns [File] struct referred to by file descriptor `idx` pub fn file(&mut self, fd: FileDescriptor) -> Result { self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile) diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 154d20d..e437b4e 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -82,6 +82,10 @@ impl Process { self.inner.lock().pgid = pgid; } + pub fn set_sid(&self, sid: Pid) { + self.inner.lock().sid = sid; + } + #[inline] pub fn current() -> ProcessRef { Thread::current().owner().unwrap() diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 762d909..7da0597 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -3,6 +3,7 @@ use crate::arch::{machine, platform::exception::ExceptionFrame}; use crate::debug::Level; use crate::dev::timer::TimestampSource; +use crate::fs::create_filesystem; use crate::proc::{self, elf, wait, Process, ProcessIo, Thread}; use core::mem::size_of; use core::ops::DerefMut; @@ -15,7 +16,8 @@ use libsys::{ proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, stat::{ - AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH, + AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions, + OpenFlags, Stat, UserId, AT_EMPTY_PATH, }, traits::{Read, Write}, }; @@ -107,7 +109,8 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let proc = Process::current(); let mut io = proc.io.lock(); - let stat = find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat()?; + let stat = + find_at_node(&mut io, at_fd, filename, flags & AT_EMPTY_PATH != 0)?.stat()?; *buf = stat; Ok(0) } @@ -153,6 +156,48 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { io.file(fd)?.borrow_mut().readdir(buf) } + SystemCall::GetUserId => { + let proc = Process::current(); + let uid = proc.io.lock().uid(); + Ok(u32::from(uid) as usize) + } + SystemCall::GetGroupId => { + let proc = Process::current(); + let gid = proc.io.lock().gid(); + Ok(u32::from(gid) as usize) + } + SystemCall::DuplicateFd => { + let src = FileDescriptor::from(args[0] as u32); + let dst = FileDescriptor::from_i32(args[1] as i32)?; + + let proc = Process::current(); + let mut io = proc.io.lock(); + + let res = io.duplicate_file(src, dst)?; + + Ok(u32::from(res) as usize) + } + SystemCall::SetUserId => { + let uid = UserId::from(args[0] as u32); + let proc = Process::current(); + proc.io.lock().set_uid(uid)?; + Ok(0) + } + SystemCall::SetGroupId => { + let gid = GroupId::from(args[0] as u32); + let proc = Process::current(); + proc.io.lock().set_gid(gid)?; + Ok(0) + } + SystemCall::SetCurrentDirectory => { + let path = arg::str_ref(args[0], args[1])?; + let proc = Process::current(); + proc.io.lock().ioctx().chdir(path)?; + Ok(0) + } + SystemCall::GetCurrentDirectory => { + todo!() + } // Process SystemCall::Clone => { @@ -294,7 +339,9 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { todo!(); } - todo!(); + let id = proc.id(); + proc.set_sid(id); + Ok(id.value() as usize) } SystemCall::SetPgid => { let pid = args[0] as u32; @@ -317,10 +364,28 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let time = machine::local_timer().timestamp()?; Ok(time.as_nanos() as usize) } + SystemCall::Mount => { + let target = arg::str_ref(args[0], args[1])?; + let options = arg::struct_ref::(args[2])?; + + let proc = Process::current(); + let mut io = proc.io.lock(); + + debugln!("mount(target={:?}, options={:#x?})", target, options); + + let target_node = io.ioctx().find(None, target, true)?; + let root = create_filesystem(options)?; + + target_node.mount(root)?; + + Ok(0) + } // Debugging SystemCall::DebugTrace => { - let level = TraceLevel::from_repr(args[0]).map(Level::from).ok_or(Errno::InvalidArgument)?; + let level = TraceLevel::from_repr(args[0]) + .map(Level::from) + .ok_or(Errno::InvalidArgument)?; let buf = arg::str_ref(args[1], args[2])?; let thread = Thread::current(); let proc = thread.owner().unwrap(); diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 7fb3eb4..6d5c5dc 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -13,6 +13,13 @@ pub enum SystemCall { Select = 7, Access = 8, ReadDirectory = 9, + GetUserId = 10, + GetGroupId = 11, + DuplicateFd = 12, + SetUserId = 13, + SetGroupId = 14, + SetCurrentDirectory = 15, + GetCurrentDirectory = 16, // Process manipulation Fork = 32, Clone = 33, @@ -34,6 +41,7 @@ pub enum SystemCall { SetPgid = 49, // System GetCpuTime = 64, + Mount = 65, // Debugging DebugTrace = 128 } diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index d78abb6..d93b0b2 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -1,11 +1,14 @@ use crate::abi::SystemCall; use crate::{ - error::Errno, debug::TraceLevel, + error::Errno, ioctl::IoctlCmd, proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, - stat::{AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, + stat::{ + AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions, + OpenFlags, Stat, UserId, + }, }; use core::time::Duration; @@ -387,3 +390,64 @@ pub fn sys_readdir(fd: FileDescriptor, buf: &mut [DirectoryEntry]) -> Result UserId { + UserId::from(unsafe { syscall!(SystemCall::GetUserId) as u32 }) +} + +#[inline(always)] +pub fn sys_getgid() -> GroupId { + GroupId::from(unsafe { syscall!(SystemCall::GetGroupId) as u32 }) +} + +#[inline(always)] +pub fn sys_setsid() -> Result { + Errno::from_syscall(unsafe { syscall!(SystemCall::SetSid) }) + .map(|e| unsafe { Pid::from_raw(e as u32) }) +} + +#[inline(always)] +pub fn sys_mount(target: &str, options: &MountOptions) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + SystemCall::Mount, + argp!(target.as_ptr()), + argn!(target.len()), + argp!(options as *const _) + ) + }) +} + +#[inline(always)] +pub fn sys_dup(src: FileDescriptor, dst: Option) -> Result { + Errno::from_syscall(unsafe { + syscall!( + SystemCall::DuplicateFd, + argn!(u32::from(src)), + argn!(FileDescriptor::into_i32(dst)) + ) + }) + .map(|e| FileDescriptor::from(e as u32)) +} + +#[inline(always)] +pub fn sys_setuid(uid: UserId) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { syscall!(SystemCall::SetUserId, u32::from(uid) as usize) }) +} + +#[inline(always)] +pub fn sys_setgid(gid: GroupId) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { syscall!(SystemCall::SetGroupId, u32::from(gid) as usize) }) +} + +#[inline(always)] +pub fn sys_chdir(path: &str) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { + syscall!( + SystemCall::SetCurrentDirectory, + argp!(path.as_ptr()), + argn!(path.len()) + ) + }) +} diff --git a/libsys/src/stat.rs b/libsys/src/stat.rs index 7ba0ecb..188f46b 100644 --- a/libsys/src/stat.rs +++ b/libsys/src/stat.rs @@ -1,3 +1,4 @@ +// TODO split up this file use crate::error::Errno; use core::fmt; @@ -15,6 +16,7 @@ bitflags! { const O_EXEC = 1 << 5; const O_CLOEXEC = 1 << 6; const O_DIRECTORY = 1 << 7; + const O_CTTY = 1 << 8; } } @@ -23,6 +25,7 @@ bitflags! { const FILE_TYPE = 0xF << 12; const S_IFREG = 0x8 << 12; const S_IFDIR = 0x4 << 12; + const S_IFCHR = 0x2 << 12; const USER_READ = 1 << 8; const USER_WRITE = 1 << 7; @@ -45,6 +48,69 @@ bitflags! { } } +#[derive(Clone, Debug)] +pub struct MountOptions<'a> { + pub device: Option<&'a str>, + pub fs: Option<&'a str>, + // TODO flags etc. +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct UserId(u32); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct GroupId(u32); + +impl UserId { + pub const fn root() -> Self { + Self(0) + } + + pub const fn is_root(self) -> bool { + self.0 == 0 + } +} + +impl From for UserId { + #[inline(always)] + fn from(v: u32) -> Self { + Self(v) + } +} + +impl From for u32 { + #[inline(always)] + fn from(v: UserId) -> u32 { + v.0 + } +} + +impl GroupId { + pub const fn root() -> Self { + Self(0) + } + + pub const fn is_root(self) -> bool { + self.0 == 0 + } +} + +impl From for GroupId { + #[inline(always)] + fn from(v: u32) -> Self { + Self(v) + } +} + +impl From for u32 { + #[inline(always)] + fn from(v: GroupId) -> u32 { + v.0 + } +} + #[derive(Clone, Default)] pub struct FdSet { bits: [u64; 2], @@ -191,6 +257,7 @@ impl fmt::Display for FileMode { "{}{}{}{}{}{}{}{}{}{}", // File type match *self & Self::FILE_TYPE { + Self::S_IFCHR => 'c', Self::S_IFDIR => 'd', Self::S_IFREG => '-', _ => '?' diff --git a/user/Cargo.toml b/user/Cargo.toml index 91af3a7..cb483a7 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -21,6 +21,11 @@ path = "src/fuzzy/main.rs" name = "ls" path = "src/ls/main.rs" +[[bin]] +name = "login" +path = "src/login/main.rs" + [dependencies] libusr = { path = "../libusr" } +libsys = { path = "../libsys" } lazy_static = { version = "*", features = ["spin_no_std"] } diff --git a/user/src/init/main.rs b/user/src/init/main.rs index 2161d0f..f75daca 100644 --- a/user/src/init/main.rs +++ b/user/src/init/main.rs @@ -5,8 +5,19 @@ #[macro_use] extern crate libusr; +use libusr::sys::{stat::MountOptions, sys_execve, sys_fork, sys_mount, sys_waitpid}; + #[no_mangle] fn main() -> i32 { + sys_mount( + "/dev", + &MountOptions { + device: None, + fs: Some("devfs"), + }, + ) + .expect("Failed to mount devfs"); + let pid = unsafe { libusr::sys::sys_fork().unwrap() }; if let Some(pid) = pid { @@ -20,7 +31,7 @@ fn main() -> i32 { } } } else { - libusr::sys::sys_execve("/bin/shell", &["/bin/shell"]).unwrap(); + libusr::sys::sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap(); loop {} } } diff --git a/user/src/login/main.rs b/user/src/login/main.rs new file mode 100644 index 0000000..63d172e --- /dev/null +++ b/user/src/login/main.rs @@ -0,0 +1,151 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate libusr; +#[macro_use] +extern crate alloc; + +use libsys::{ + calls::{ + sys_close, sys_dup, sys_fork, sys_getgid, sys_getpgid, sys_getuid, sys_ioctl, sys_openat, + sys_read, sys_setgid, sys_setpgid, sys_setsid, sys_setuid, sys_waitpid, sys_execve + }, + error::Errno, + ioctl::IoctlCmd, + proc::Pid, + stat::{FileDescriptor, FileMode, GroupId, OpenFlags, UserId}, + termios::{Termios, TermiosLflag}, +}; +use libusr::{env, io}; + +struct HiddenInput { + fd: FileDescriptor, + termios: Termios, +} + +impl HiddenInput { + fn open(fd: FileDescriptor) -> Result { + use core::mem::{size_of, MaybeUninit}; + let mut termios: MaybeUninit = MaybeUninit::uninit(); + sys_ioctl( + fd, + IoctlCmd::TtyGetAttributes, + termios.as_mut_ptr() as usize, + size_of::(), + )?; + let termios = unsafe { termios.assume_init() }; + + let mut new_termios = termios.clone(); + new_termios.lflag &= !(TermiosLflag::ECHO | TermiosLflag::ECHOK | TermiosLflag::ECHOE); + sys_ioctl( + fd, + IoctlCmd::TtySetAttributes, + &new_termios as *const _ as usize, + size_of::(), + )?; + + Ok(Self { fd, termios }) + } + + fn readline<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a str, Errno> { + readline(self.fd, buf) + } +} + +impl Drop for HiddenInput { + fn drop(&mut self) { + use core::mem::size_of; + sys_ioctl( + self.fd, + IoctlCmd::TtySetAttributes, + &self.termios as *const _ as usize, + size_of::(), + ) + .ok(); + } +} + +fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, Errno> { + let len = sys_read(fd, buf)?; + + if len == 0 { + Ok("") + } else { + Ok(core::str::from_utf8(&buf[..len - 1]).unwrap()) + } +} + +fn login_as(uid: UserId, gid: GroupId, shell: &str) -> Result<(), Errno> { + if let Some(pid) = unsafe { sys_fork() }? { + let mut status = 0; + sys_waitpid(pid, &mut status).ok(); + let pgid = sys_getpgid(unsafe { Pid::from_raw(0) }).unwrap(); + io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); + Ok(()) + } else { + sys_setuid(uid).expect("setuid failed"); + sys_setgid(gid).expect("setgid failed"); + let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap(); + io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap(); + sys_execve(shell, &[shell]).expect("execve() failed"); + panic!(); + } +} + +// TODO baud rate and misc port settings +#[no_mangle] +fn main() -> i32 { + if !sys_getuid().is_root() { + panic!("This program must be run as root"); + } + + let args = env::args(); + if args.len() != 2 { + panic!("Usage: {} TTY", args[0]); + } + + sys_setsid().expect("setsid() failed"); + + // Close controlling terminal + // NOTE this will invalidate rust-side Stdin, Stdout, Stderr + // until replacement is re-opened using the specified TTY + sys_close(FileDescriptor::STDERR).unwrap(); + sys_close(FileDescriptor::STDOUT).unwrap(); + sys_close(FileDescriptor::STDIN).unwrap(); + + sys_openat( + None, + args[1], + FileMode::default_reg(), + OpenFlags::O_RDONLY | OpenFlags::O_CTTY, + ) + .expect("Failed to open stdin"); + sys_openat( + None, + args[1], + FileMode::default_reg(), + OpenFlags::O_WRONLY | OpenFlags::O_CTTY, + ) + .expect("Failed to open stdout"); + sys_dup(FileDescriptor::STDOUT, Some(FileDescriptor::STDERR)).expect("Failed to open stderr"); + + let mut user_buf = [0; 128]; + let mut password_buf = [0; 128]; + loop { + print!("login: "); + let username = readline(FileDescriptor::STDIN, &mut user_buf).expect("Login read failed"); + print!("password: "); + let password = { + let mut input = HiddenInput::open(FileDescriptor::STDIN).unwrap(); + input.readline(&mut password_buf) + } + .expect("Password read failed"); + + if username == "root" && password == "toor" { + login_as(UserId::from(0), GroupId::from(0), "/bin/shell"); + } + } + + 0 +} diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 5ecfa12..18d3e15 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -9,11 +9,34 @@ use alloc::{borrow::ToOwned, vec::Vec}; use libusr::io::{self, Read}; use libusr::signal::{self, SignalHandler}; use libusr::sys::{ - proc::Pid, sys_execve, sys_setpgid, sys_exit, sys_fork, sys_getpgid, sys_waitpid, Errno, ExitCode, - sys_faccessat, AccessMode, - FileDescriptor, Signal, + proc::Pid, sys_chdir, sys_execve, sys_exit, sys_faccessat, sys_fork, sys_getpgid, sys_setpgid, + sys_waitpid, AccessMode, Errno, ExitCode, FileDescriptor, Signal, }; +struct Builtin { + func: fn(&[&str]) -> ExitCode, + name: &'static str, +} + +fn cmd_cd(args: &[&str]) -> ExitCode { + if args.len() != 2 { + eprintln!("Usage: cd DIR"); + ExitCode::from(-1) + } else { + if let Err(err) = sys_chdir(args[1]) { + eprintln!("{}: {:?}", args[1], err); + ExitCode::from(-1) + } else { + ExitCode::from(0) + } + } +} + +static BUILTINS: [Builtin; 1] = [Builtin { + name: "cd", + func: cmd_cd, +}]; + fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result, io::Error> { let size = f.read(bytes)?; Ok(if size == 0 { @@ -32,6 +55,12 @@ fn execute(line: &str) -> Result { let args: Vec<&str> = line.split(' ').collect(); let cmd = args[0]; + for item in BUILTINS.iter() { + if item.name == cmd { + return Ok((item.func)(&args)); + } + } + let filename = "/bin/".to_owned() + cmd; sys_faccessat(None, &filename, AccessMode::X_OK, 0)?; @@ -73,12 +102,12 @@ fn main() -> i32 { if let Err(e) = execute(line) { eprintln!("{}: {:?}", line.split(' ').next().unwrap(), e); } - }, + } Err(_) => { println!("Interrupt!"); continue; - }, - _ => panic!() + } + _ => panic!(), } } 0 From cd71ee25ab9ba93543cf467623c49b8c3bf465f5 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 28 Nov 2021 11:50:59 +0200 Subject: [PATCH 39/42] refactor: better user dir structure --- user/Cargo.toml | 8 ++++---- user/src/{fuzzy/main.rs => bin/fuzzy.rs} | 0 user/src/{ls/main.rs => bin/ls.rs} | 0 user/src/{shell/main.rs => bin/shell.rs} | 0 user/src/{login/main.rs => sbin/login.rs} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename user/src/{fuzzy/main.rs => bin/fuzzy.rs} (100%) rename user/src/{ls/main.rs => bin/ls.rs} (100%) rename user/src/{shell/main.rs => bin/shell.rs} (100%) rename user/src/{login/main.rs => sbin/login.rs} (100%) diff --git a/user/Cargo.toml b/user/Cargo.toml index cb483a7..2c41d63 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -11,19 +11,19 @@ path = "src/init/main.rs" [[bin]] name = "shell" -path = "src/shell/main.rs" +path = "src/bin/shell.rs" [[bin]] name = "fuzzy" -path = "src/fuzzy/main.rs" +path = "src/bin/fuzzy.rs" [[bin]] name = "ls" -path = "src/ls/main.rs" +path = "src/bin/ls.rs" [[bin]] name = "login" -path = "src/login/main.rs" +path = "src/sbin/login.rs" [dependencies] libusr = { path = "../libusr" } diff --git a/user/src/fuzzy/main.rs b/user/src/bin/fuzzy.rs similarity index 100% rename from user/src/fuzzy/main.rs rename to user/src/bin/fuzzy.rs diff --git a/user/src/ls/main.rs b/user/src/bin/ls.rs similarity index 100% rename from user/src/ls/main.rs rename to user/src/bin/ls.rs diff --git a/user/src/shell/main.rs b/user/src/bin/shell.rs similarity index 100% rename from user/src/shell/main.rs rename to user/src/bin/shell.rs diff --git a/user/src/login/main.rs b/user/src/sbin/login.rs similarity index 100% rename from user/src/login/main.rs rename to user/src/sbin/login.rs From 3ed41501cb643527d737fe45645d43036a6e932e Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 28 Nov 2021 12:24:17 +0200 Subject: [PATCH 40/42] feature: cat and hexd --- Makefile | 2 ++ libusr/src/file.rs | 21 +++++++++---- user/Cargo.toml | 8 +++++ user/src/bin/cat.rs | 48 ++++++++++++++++++++++++++++++ user/src/bin/hexd.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 user/src/bin/cat.rs create mode 100644 user/src/bin/hexd.rs diff --git a/Makefile b/Makefile index ba8bb46..5622ef9 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,8 @@ initrd: cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin cp target/$(ARCH)-osdev5/$(PROFILE)/ls $(O)/rootfs/bin + cp target/$(ARCH)-osdev5/$(PROFILE)/cat $(O)/rootfs/bin + cp target/$(ARCH)-osdev5/$(PROFILE)/hexd $(O)/rootfs/bin cp target/$(ARCH)-osdev5/$(PROFILE)/login $(O)/rootfs/sbin cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"` ifeq ($(MACH),orangepi3) diff --git a/libusr/src/file.rs b/libusr/src/file.rs index 7603252..6c1855e 100644 --- a/libusr/src/file.rs +++ b/libusr/src/file.rs @@ -1,13 +1,18 @@ -use crate::io::{AsRawFd, Error}; -use libsys::stat::FileDescriptor; +use crate::io::{AsRawFd, Error, Read, Write}; +use libsys::{ + calls::{sys_openat, sys_read, sys_close}, + stat::{FileDescriptor, FileMode, OpenFlags}, +}; pub struct File { fd: FileDescriptor, } impl File { - pub fn open(_path: &str) -> Result { - todo!() + pub fn open(path: &str) -> Result { + let fd = sys_openat(None, path, FileMode::default_reg(), OpenFlags::O_RDONLY) + .map_err(Error::from)?; + Ok(File { fd }) } } @@ -19,6 +24,12 @@ impl AsRawFd for File { impl Drop for File { fn drop(&mut self) { - todo!(); + sys_close(self.fd).ok(); + } +} + +impl Read for File { + fn read(&mut self, bytes: &mut [u8]) -> Result { + sys_read(self.fd, bytes).map_err(Error::from) } } diff --git a/user/Cargo.toml b/user/Cargo.toml index 2c41d63..910a7e6 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -21,6 +21,14 @@ path = "src/bin/fuzzy.rs" name = "ls" path = "src/bin/ls.rs" +[[bin]] +name = "cat" +path = "src/bin/cat.rs" + +[[bin]] +name = "hexd" +path = "src/bin/hexd.rs" + [[bin]] name = "login" path = "src/sbin/login.rs" diff --git a/user/src/bin/cat.rs b/user/src/bin/cat.rs new file mode 100644 index 0000000..24e2592 --- /dev/null +++ b/user/src/bin/cat.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate libusr; +#[macro_use] +extern crate alloc; + +use libusr::io::{self, Read, Write}; +use libusr::file::File; + +fn do_cat(mut fd: F) -> Result<(), io::Error> { + let mut buf = [0; 4096]; + let mut out = io::stdout(); + + loop { + let count = fd.read(&mut buf)?; + if count == 0 { + break; + } + + out.write(&buf[..count]); + } + + Ok(()) +} + +#[no_mangle] +fn main() -> i32 { + let args = libusr::env::args(); + let mut res = 0; + + if args.len() == 1 { + if let Err(e) = do_cat(io::stdin()) { + eprintln!("{}: {:?}", ".", e); + res = -1; + } + } else { + for arg in &args[1..] { + if let Err(e) = File::open(arg).map(do_cat) { + eprintln!("{}: {:?}", arg, e); + res = -1; + } + } + } + + res +} diff --git a/user/src/bin/hexd.rs b/user/src/bin/hexd.rs new file mode 100644 index 0000000..0a2b1cd --- /dev/null +++ b/user/src/bin/hexd.rs @@ -0,0 +1,71 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate libusr; +#[macro_use] +extern crate alloc; + +use libusr::io::{self, Read, Write}; +use libusr::file::File; + +fn line_print(off: usize, line: &[u8]) { + print!("{:08x}: ", off); + for i in 0..16 { + if i < line.len() { + print!("{:02x}", line[i]); + } else { + print!(" "); + } + if i % 2 != 0 { + print!(" "); + } + } + print!("| "); + for &b in line.iter() { + if b.is_ascii() && !b.is_ascii_control() { + print!("{}", b as char); + } else { + print!("."); + } + } + println!(""); +} + +fn do_hexd(mut fd: F) -> Result<(), io::Error> { + let mut buf = [0; 16]; + let mut off = 0; + loop { + let count = fd.read(&mut buf)?; + if count == 0 { + break; + } + + line_print(off, &buf[..count]); + off += count; + } + + Ok(()) +} + +#[no_mangle] +fn main() -> i32 { + let args = libusr::env::args(); + let mut res = 0; + + if args.len() == 1 { + if let Err(e) = do_hexd(io::stdin()) { + eprintln!("{}: {:?}", ".", e); + res = -1; + } + } else { + for arg in &args[1..] { + if let Err(e) = File::open(arg).map(do_hexd) { + eprintln!("{}: {:?}", arg, e); + res = -1; + } + } + } + + res +} From 4c3374de36dc919f8ad0b25362e563f6bd5c0d7f Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 29 Nov 2021 16:57:21 +0200 Subject: [PATCH 41/42] feature: MapMemory and UnmapMemory system calls --- Cargo.lock | 12 +- kernel/src/mem/virt/table.rs | 66 ++++++++- kernel/src/proc/process.rs | 6 +- kernel/src/syscall/mod.rs | 53 +++++++- libsys/src/abi.rs | 4 + libsys/src/calls.rs | 25 +++- libsys/src/proc.rs | 18 +++ libusr/Cargo.toml | 1 + libusr/src/allocator.rs | 254 +++++++++++++++++++++++++++++++++-- libusr/src/lib.rs | 1 + 10 files changed, 420 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 486e6d3..1cf773c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,7 +69,7 @@ checksum = "99a40cabc11c8258822a593f5c51f2d9f4923e715ca9e2a0630cf77ae15f390b" dependencies = [ "endian-type-rs", "fallible-iterator", - "memoffset", + "memoffset 0.5.6", "num-derive", "num-traits", "rustc_version", @@ -131,6 +131,7 @@ version = "0.1.0" dependencies = [ "lazy_static", "libsys", + "memoffset 0.6.4", ] [[package]] @@ -151,6 +152,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + [[package]] name = "num-derive" version = "0.3.3" diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index cabeb5f..64a4c4d 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -264,6 +264,66 @@ impl Space { Ok(()) } + pub fn allocate( + &mut self, + start: usize, + end: usize, + len: usize, + flags: MapAttributes, + usage: PageUsage, + ) -> Result { + 'l0: for page in (start..end).step_by(0x1000) { + for i in 0..len { + if self.translate(page + i * 0x1000).is_ok() { + continue 'l0; + } + } + + for i in 0..len { + let phys = phys::alloc_page(usage).unwrap(); + self.map(page + i * 0x1000, phys, flags).unwrap(); + } + return Ok(page); + } + Err(Errno::OutOfMemory) + } + + pub fn unmap_single(&mut self, page: usize) -> Result<(), Errno> { + let l0i = page >> 30; + let l1i = (page >> 21) & 0x1FF; + let l2i = (page >> 12) & 0x1FF; + + let l1_table = self.0.next_level_table(l0i).ok_or(Errno::DoesNotExist)?; + let l2_table = l1_table.next_level_table(l1i).ok_or(Errno::DoesNotExist)?; + + let entry = l2_table[l2i]; + + if !entry.is_present() { + return Err(Errno::DoesNotExist); + } + + let phys = unsafe { entry.address_unchecked() }; + unsafe { + phys::free_page(phys); + } + l2_table[l2i] = Entry::invalid(); + + unsafe { + asm!("tlbi vaae1, {}", in(reg) page); + } + + // TODO release paging structure memory + + Ok(()) + } + + pub fn free(&mut self, start: usize, len: usize) -> Result<(), Errno> { + for i in 0..len { + self.unmap_single(start + i * 0x1000)?; + } + Ok(()) + } + /// Performs a copy of the address space, cloning data owned by it pub fn fork(&mut self) -> Result<&'static mut Self, Errno> { let res = Self::alloc_empty()?; @@ -288,10 +348,12 @@ impl Space { todo!(); // res.map(virt_addr, dst_phys, flags)?; } else { - let writable = flags & MapAttributes::AP_BOTH_READONLY == MapAttributes::AP_BOTH_READWRITE; + let writable = flags & MapAttributes::AP_BOTH_READONLY + == MapAttributes::AP_BOTH_READWRITE; if writable { - flags |= MapAttributes::AP_BOTH_READONLY | MapAttributes::EX_COW; + flags |= + MapAttributes::AP_BOTH_READONLY | MapAttributes::EX_COW; l2_table[l2i].set_cow(); unsafe { diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index e437b4e..7c90cd2 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -92,9 +92,9 @@ impl Process { } #[inline] - pub fn manipulate_space(&self, f: F) -> Result<(), Errno> + pub fn manipulate_space(&self, f: F) -> R where - F: FnOnce(&mut Space) -> Result<(), Errno>, + F: FnOnce(&mut Space) -> R, { f(self.inner.lock().space.as_mut().unwrap()) } @@ -250,6 +250,8 @@ impl Process { } } + // TODO when exiting from signal handler interrupting an IO operation + // deadlock is achieved self.io.lock().handle_exit(); drop(lock); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 7da0597..fb00db9 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1,6 +1,7 @@ //! System call implementation use crate::arch::{machine, platform::exception::ExceptionFrame}; +use crate::mem::{virt::MapAttributes, phys::PageUsage}; use crate::debug::Level; use crate::dev::timer::TimestampSource; use crate::fs::create_filesystem; @@ -13,7 +14,7 @@ use libsys::{ debug::TraceLevel, error::Errno, ioctl::IoctlCmd, - proc::{ExitCode, Pid}, + proc::{ExitCode, Pid, MemoryAccess, MemoryMap}, signal::{Signal, SignalDestination}, stat::{ AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions, @@ -198,6 +199,56 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { SystemCall::GetCurrentDirectory => { todo!() } + SystemCall::Seek => { + todo!() + } + SystemCall::MapMemory => { + let len = args[1]; + if len == 0 || (len & 0xFFF) != 0 { + return Err(Errno::InvalidArgument); + } + let acc = MemoryAccess::from_bits(args[2] as u32).ok_or(Errno::InvalidArgument)?; + let flags = MemoryAccess::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; + + let mut attrs = MapAttributes::NOT_GLOBAL | MapAttributes::SH_OUTER | MapAttributes::PXN; + if !acc.contains(MemoryAccess::READ) { + return Err(Errno::NotImplemented); + } + if acc.contains(MemoryAccess::WRITE) { + if acc.contains(MemoryAccess::EXEC) { + return Err(Errno::PermissionDenied); + } + attrs |= MapAttributes::AP_BOTH_READWRITE; + } else { + attrs |= MapAttributes::AP_BOTH_READONLY; + } + if !acc.contains(MemoryAccess::EXEC) { + attrs |= MapAttributes::UXN; + } + + // TODO don't ignore flags + let usage = PageUsage::UserPrivate; + + let proc = Process::current(); + + proc.manipulate_space(move |space| { + space.allocate(0x100000000, 0xF00000000, len / 4096, attrs, usage) + }) + } + SystemCall::UnmapMemory => { + let addr = args[0]; + let len = args[1]; + + if addr == 0 || len == 0 || addr & 0xFFF != 0 || len & 0xFFF != 0 { + return Err(Errno::InvalidArgument); + } + + let proc = Process::current(); + proc.manipulate_space(move |space| { + space.free(addr, len / 4096) + })?; + Ok(0) + } // Process SystemCall::Clone => { diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 6d5c5dc..1a758d0 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -20,6 +20,10 @@ pub enum SystemCall { SetGroupId = 14, SetCurrentDirectory = 15, GetCurrentDirectory = 16, + Seek = 17, + MapMemory = 18, + UnmapMemory = 19, + // Process manipulation Fork = 32, Clone = 33, diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index d93b0b2..1e18b4a 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -3,7 +3,7 @@ use crate::{ debug::TraceLevel, error::Errno, ioctl::IoctlCmd, - proc::{ExitCode, Pid}, + proc::{ExitCode, MemoryAccess, MemoryMap, Pid}, signal::{Signal, SignalDestination}, stat::{ AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions, @@ -451,3 +451,26 @@ pub fn sys_chdir(path: &str) -> Result<(), Errno> { ) }) } + +#[inline(always)] +pub fn sys_mmap( + hint: usize, + len: usize, + acc: MemoryAccess, + flags: MemoryMap, +) -> Result { + Errno::from_syscall(unsafe { + syscall!( + SystemCall::MapMemory, + argn!(hint), + argn!(len), + argn!(acc.bits()), + argn!(flags.bits()) + ) + }) +} + +#[inline(always)] +pub unsafe fn sys_munmap(addr: usize, len: usize) -> Result<(), Errno> { + Errno::from_syscall_unit(unsafe { syscall!(SystemCall::UnmapMemory, argn!(addr), argn!(len)) }) +} diff --git a/libsys/src/proc.rs b/libsys/src/proc.rs index e63b6dc..fe76473 100644 --- a/libsys/src/proc.rs +++ b/libsys/src/proc.rs @@ -16,6 +16,24 @@ pub struct Pid(u32); #[repr(transparent)] pub struct Pgid(u32); +bitflags! { + pub struct MemoryAccess: u32 { + const READ = 1 << 0; + const WRITE = 1 << 1; + const EXEC = 1 << 2; + } +} + +bitflags! { + pub struct MemoryMap: u32 { + const BACKEND = 0x3 << 0; + const ANONYMOUS = 1 << 0; + + const SHARING = 0x3 << 2; + const PRIVATE = 1 << 2; + } +} + impl From for ExitCode { fn from(f: i32) -> Self { Self(f) diff --git a/libusr/Cargo.toml b/libusr/Cargo.toml index feb52ee..0299b4e 100644 --- a/libusr/Cargo.toml +++ b/libusr/Cargo.toml @@ -8,3 +8,4 @@ edition = "2021" [dependencies] libsys = { path = "../libsys", features = ["user"] } lazy_static = { version = "^1.4.0", features = ["spin_no_std"] } +memoffset = "^0.6.4" diff --git a/libusr/src/allocator.rs b/libusr/src/allocator.rs index c803689..353c78a 100644 --- a/libusr/src/allocator.rs +++ b/libusr/src/allocator.rs @@ -1,29 +1,251 @@ -use core::alloc::{Layout, GlobalAlloc}; +use core::alloc::{GlobalAlloc, Layout}; +use core::mem::{size_of, MaybeUninit}; +use core::ptr::null_mut; use core::sync::atomic::{AtomicUsize, Ordering}; -use libsys::{debug::TraceLevel, mem::memset}; +use libsys::{ + calls::{sys_mmap, sys_munmap}, + debug::TraceLevel, + error::Errno, + mem::memset, + proc::{MemoryAccess, MemoryMap}, +}; +use memoffset::offset_of; -use crate::trace; +use crate::trace_debug; struct Allocator; -static mut ALLOC_DATA: [u8; 65536] = [0; 65536]; -static ALLOC_PTR: AtomicUsize = AtomicUsize::new(0); +const BLOCK_MAGIC: u32 = 0xBADB10C0; +const BLOCK_MAGIC_MASK: u32 = 0xFFFFFFF0; +const BLOCK_ALLOC: u32 = 1 << 0; +const SMALL_ZONE_ELEM: usize = 256; +const SMALL_ZONE_SIZE: usize = 6 * 0x1000; +const MID_ZONE_ELEM: usize = 2048; +const MID_ZONE_SIZE: usize = 24 * 0x1000; +const LARGE_ZONE_ELEM: usize = 8192; +const LARGE_ZONE_SIZE: usize = 48 * 0x1000; + +struct ZoneList { + prev: *mut ZoneList, + next: *mut ZoneList, +} + +#[repr(C)] +struct Zone { + size: usize, + list: ZoneList, +} + +#[repr(C)] +struct Block { + prev: *mut Block, + next: *mut Block, + flags: u32, + size: u32, +} + +static mut SMALL_ZONE_LIST: MaybeUninit = MaybeUninit::uninit(); +static mut MID_ZONE_LIST: MaybeUninit = MaybeUninit::uninit(); +static mut LARGE_ZONE_LIST: MaybeUninit = MaybeUninit::uninit(); + +impl ZoneList { + fn init(&mut self) { + self.prev = self; + self.next = self; + } + + unsafe fn init_uninit(list: &mut MaybeUninit) { + list.assume_init_mut().init() + } + + fn add(&mut self, new: *mut ZoneList) { + let new = unsafe { &mut *new }; + let next = unsafe { &mut *self.next }; + + next.prev = new; + new.next = next; + new.prev = self; + self.next = new; + } + + fn del(&mut self) { + let prev = unsafe { &mut *self.prev }; + let next = unsafe { &mut *self.next }; + + next.prev = prev; + prev.next = next; + } +} + +impl Zone { + fn alloc(size: usize) -> Result<*mut Self, Errno> { + let pages = sys_mmap( + 0, + size, + MemoryAccess::READ | MemoryAccess::WRITE, + MemoryMap::ANONYMOUS | MemoryMap::PRIVATE, + )?; + trace_debug!("Zone::alloc({}) => {:#x}", size, pages); + + let zone_ptr = pages as *mut Zone; + let head_ptr = (pages + size_of::()) as *mut Block; + + let zone = unsafe { &mut *zone_ptr }; + let head = unsafe { &mut *head_ptr }; + zone.list.init(); + zone.size = size - size_of::(); + + head.size = (size - (size_of::() + size_of::())) as u32; + head.flags = BLOCK_MAGIC; + head.prev = null_mut(); + head.next = null_mut(); + + Ok(zone) + } + + unsafe fn free(zone: *mut Self) { + trace_debug!("Zone::free({:p})", zone); + sys_munmap(zone as usize, (&*zone).size + size_of::()) + .expect("Failed to unmap heap pages"); + } + + fn get(item: *mut ZoneList) -> *mut Zone { + ((item as usize) - offset_of!(Zone, list)) as *mut Zone + } +} + +unsafe fn zone_alloc(zone: &mut Zone, size: usize) -> *mut u8 { + assert_eq!(size & 15, 0); + + let mut begin = ((zone as *mut _ as usize) + size_of::()) as *mut Block; + + let mut block = begin; + while !block.is_null() { + let block_ref = &mut *block; + if block_ref.flags & BLOCK_ALLOC != 0 { + block = block_ref.next; + continue; + } + + if size == block_ref.size as usize { + block_ref.flags |= BLOCK_ALLOC; + let ptr = block.add(1) as *mut u8; + // TODO fill with zeros + return ptr; + } else if block_ref.size as usize >= size + size_of::() { + let cur_next = block_ref.next; + let cur_next_ref = &mut *cur_next; + let new_block = ((block as usize) + size_of::() + size) as *mut Block; + let new_block_ref = &mut *new_block; + + if !cur_next.is_null() { + cur_next_ref.prev = new_block; + } + new_block_ref.next = cur_next; + new_block_ref.prev = block; + new_block_ref.size = ((block_ref.size as usize) - size_of::() - size) as u32; + new_block_ref.flags = BLOCK_MAGIC; + block_ref.next = new_block; + block_ref.size = size as u32; + block_ref.flags |= BLOCK_ALLOC; + + let ptr = block.add(1) as *mut u8; + // TODO fill with zeros + return ptr; + } + + block = block_ref.next; + } + + null_mut() +} + +unsafe fn alloc_from(list: &mut ZoneList, zone_size: usize, size: usize) -> *mut u8 { + loop { + let mut zone = list.next; + while zone != list { + let ptr = zone_alloc(&mut *Zone::get(zone), size); + if !ptr.is_null() { + return ptr; + } + } + + let zone = match Zone::alloc(zone_size) { + Ok(zone) => zone, + Err(e) => { + trace_debug!("Zone alloc failed: {:?}", e); + return null_mut(); + } + }; + list.add(&mut (&mut *zone).list); + } +} unsafe impl GlobalAlloc for Allocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { assert!(layout.align() < 16); - let res = ALLOC_PTR.fetch_add((layout.size() + 15) & !15, Ordering::SeqCst); - if res > 65536 { - panic!("Out of memory"); + let size = (layout.size() + 15) & !15; + trace_debug!("alloc({:?})", layout); + if size <= SMALL_ZONE_ELEM { + alloc_from(SMALL_ZONE_LIST.assume_init_mut(), SMALL_ZONE_SIZE, size) + } else if size <= MID_ZONE_ELEM { + alloc_from(MID_ZONE_LIST.assume_init_mut(), MID_ZONE_SIZE, size) + } else if size <= LARGE_ZONE_ELEM { + alloc_from(LARGE_ZONE_LIST.assume_init_mut(), LARGE_ZONE_SIZE, size) + } else { + todo!(); } - trace!(TraceLevel::Debug, "alloc({:?}) = {:p}", layout, &ALLOC_DATA[res]); - let res = &mut ALLOC_DATA[res] as *mut _; - memset(res, 0, layout.size()); - res } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - trace!(TraceLevel::Debug, "free({:p}, {:?})", ptr, layout); + trace_debug!("free({:p}, {:?})", ptr, layout); + assert!(!ptr.is_null()); + let mut block = ptr.sub(size_of::()) as *mut Block; + let mut block_ref = &mut *block; + + if block_ref.flags & BLOCK_MAGIC_MASK != BLOCK_MAGIC { + panic!("Heap block is malformed: block={:p}, ptr={:p}", block, ptr); + } + if block_ref.flags & BLOCK_ALLOC == 0 { + panic!( + "Double free error in heap: block={:p}, ptr={:p}", + block, ptr + ); + } + + block_ref.flags &= !BLOCK_ALLOC; + let prev = block_ref.prev; + let next = block_ref.next; + let prev_ref = &mut *prev; + let next_ref = &mut *next; + + if !prev.is_null() && prev_ref.flags & BLOCK_ALLOC == 0 { + block_ref.flags = 0; + prev_ref.next = next; + if !next.is_null() { + next_ref.prev = prev; + } + prev_ref.size += (block_ref.size as usize + size_of::()) as u32; + + block = prev; + block_ref = &mut *block; + } + + if !next.is_null() && next_ref.flags & BLOCK_ALLOC == 0 { + next_ref.flags = 0; + if !next_ref.next.is_null() { + (&mut *(next_ref.next)).prev = block; + } + block_ref.next = next_ref.next; + block_ref.size += (next_ref.size as usize + size_of::()) as u32; + } + + if block_ref.prev.is_null() && block_ref.next.is_null() { + let zone = (block as usize - size_of::()) as *mut Zone; + assert_eq!((zone as usize) & 0xFFF, 0); + (&mut *zone).list.del(); + Zone::free(zone); + } } } @@ -34,3 +256,9 @@ fn alloc_error_handler(_layout: Layout) -> ! { #[global_allocator] static ALLOC: Allocator = Allocator; + +pub unsafe fn init() { + ZoneList::init_uninit(&mut SMALL_ZONE_LIST); + ZoneList::init_uninit(&mut MID_ZONE_LIST); + ZoneList::init_uninit(&mut LARGE_ZONE_LIST); +} diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index 7386805..cc52cd4 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -27,6 +27,7 @@ extern "C" fn _start(arg: &'static ProgramArgs) -> ! { } unsafe { + allocator::init(); thread::init_main(); env::setup_env(arg); } From 4ffbb8c1158254a09bc320f2a7c9dcf331418fe7 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 30 Nov 2021 09:55:13 +0200 Subject: [PATCH 42/42] refactor: fix warnings --- fs/memfs/src/dir.rs | 7 +--- fs/vfs/src/char.rs | 1 + fs/vfs/src/file.rs | 4 ++ fs/vfs/src/ioctx.rs | 3 ++ fs/vfs/src/node.rs | 8 ++++ kernel/src/arch/aarch64/irq/gic/mod.rs | 4 +- kernel/src/arch/aarch64/mach_qemu/mod.rs | 2 +- kernel/src/debug.rs | 2 +- kernel/src/dev/tty.rs | 2 + kernel/src/fs/mod.rs | 1 + kernel/src/mem/virt/table.rs | 10 ++++- kernel/src/proc/io.rs | 7 ++++ kernel/src/proc/mod.rs | 25 ------------ kernel/src/proc/process.rs | 48 ++++++++++++++++-------- kernel/src/proc/sched.rs | 9 +---- kernel/src/proc/thread.rs | 28 ++++++++++++-- kernel/src/proc/wait.rs | 10 +++++ kernel/src/syscall/arg.rs | 12 ++++++ kernel/src/syscall/mod.rs | 6 +-- libsys/src/calls.rs | 2 +- libsys/src/stat.rs | 3 +- libusr/src/allocator.rs | 6 +-- libusr/src/file.rs | 2 +- libusr/src/io/mod.rs | 2 +- user/src/bin/cat.rs | 4 +- user/src/bin/hexd.rs | 4 +- user/src/bin/ls.rs | 2 +- user/src/bin/shell.rs | 1 - user/src/init/main.rs | 8 ++-- user/src/sbin/login.rs | 8 +--- 30 files changed, 137 insertions(+), 94 deletions(-) diff --git a/fs/memfs/src/dir.rs b/fs/memfs/src/dir.rs index 2dbca3c..b87e1d6 100644 --- a/fs/memfs/src/dir.rs +++ b/fs/memfs/src/dir.rs @@ -1,9 +1,6 @@ use crate::{BlockAllocator, Bvec, FileInode}; use alloc::boxed::Box; -use libsys::{ - error::Errno, - stat::{DirectoryEntry, OpenFlags, Stat}, -}; +use libsys::{error::Errno, stat::Stat}; use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef}; pub struct DirInode { @@ -40,7 +37,7 @@ impl VnodeImpl for DirInode { Ok(Stat { size: 0, blksize: 4096, - mode: props.mode + mode: props.mode, }) } } diff --git a/fs/vfs/src/char.rs b/fs/vfs/src/char.rs index 1901bd5..b4d2fe4 100644 --- a/fs/vfs/src/char.rs +++ b/fs/vfs/src/char.rs @@ -19,6 +19,7 @@ pub trait CharDevice { /// Performs a TTY control request fn ioctl(&self, cmd: IoctlCmd, ptr: usize, lim: usize) -> Result; + /// Returns `true` if the device is ready for an operation fn is_ready(&self, write: bool) -> Result; } diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index 4c267b6..a9da4a6 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -98,7 +98,9 @@ impl File { /// File has to be closed on execve() calls pub const CLOEXEC: u32 = 1 << 2; + /// Special position for cache-readdir: "." entry pub const POS_CACHE_DOT: usize = usize::MAX - 1; + /// Special position for cache-readdir: ".." entry pub const POS_CACHE_DOT_DOT: usize = usize::MAX; /// Constructs a new file handle for a regular file @@ -123,6 +125,7 @@ impl File { self.flags & Self::CLOEXEC != 0 } + /// Returns `true` if the file is ready for an operation pub fn is_ready(&self, write: bool) -> Result { match &self.inner { FileInner::Normal(inner) => inner.vnode.is_ready(write), @@ -169,6 +172,7 @@ impl File { Ok(offset + count) } + /// Reads directory entries into the target buffer pub fn readdir(&mut self, entries: &mut [DirectoryEntry]) -> Result { match &mut self.inner { FileInner::Normal(inner) => { diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index c4d498d..f55b3c7 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -10,7 +10,9 @@ use libsys::{ pub struct Ioctx { root: VnodeRef, cwd: VnodeRef, + /// Process user ID pub uid: UserId, + /// Process group ID pub gid: GroupId, } @@ -123,6 +125,7 @@ impl Ioctx { node.open(opts) } + /// Changes current working directory of the process pub fn chdir(&mut self, path: &str) -> Result<(), Errno> { let node = self.find(None, path, true)?; if !node.is_directory() { diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index 816add0..0e87b37 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -31,6 +31,7 @@ pub(crate) struct TreeNode { /// File property cache struct pub struct VnodeProps { + /// Node permissions and type pub mode: FileMode, } @@ -74,6 +75,7 @@ pub trait VnodeImpl { /// Resizes the file storage if necessary. fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result; + /// Read directory entries into target buffer fn readdir( &mut self, node: VnodeRef, @@ -87,6 +89,7 @@ pub trait VnodeImpl { /// Reports the size of this filesystem object in bytes fn size(&mut self, node: VnodeRef) -> Result; + /// Returns `true` if node is ready for an operation fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result; /// Performs filetype-specific request @@ -104,7 +107,9 @@ impl Vnode { /// be seeked to arbitrary offsets pub const SEEKABLE: u32 = 1 << 0; + /// If set, readdir() uses only in-memory node tree pub const CACHE_READDIR: u32 = 1 << 1; + /// If set, stat() uses only in-memory stat data pub const CACHE_STAT: u32 = 1 << 2; /// Constructs a new [Vnode], wrapping it in [Rc]. The resulting node @@ -178,6 +183,7 @@ impl Vnode { self.kind } + /// Returns flags of the vnode #[inline(always)] pub const fn flags(&self) -> u32 { self.flags @@ -476,6 +482,7 @@ impl Vnode { } } + /// Returns `true` if the node is ready for operation pub fn is_ready(self: &VnodeRef, write: bool) -> Result { if let Some(ref mut data) = *self.data() { data.is_ready(self.clone(), write) @@ -484,6 +491,7 @@ impl Vnode { } } + /// Checks if given [Ioctx] has `access` permissions to the vnode pub fn check_access(&self, _ioctx: &Ioctx, access: AccessMode) -> Result<(), Errno> { let props = self.props.borrow(); let mode = props.mode; diff --git a/kernel/src/arch/aarch64/irq/gic/mod.rs b/kernel/src/arch/aarch64/irq/gic/mod.rs index c5366f9..e2f8b5a 100644 --- a/kernel/src/arch/aarch64/irq/gic/mod.rs +++ b/kernel/src/arch/aarch64/irq/gic/mod.rs @@ -28,7 +28,6 @@ pub struct Gic { gicd: InitOnce, gicd_base: usize, gicc_base: usize, - scheduler_irq: IrqNumber, table: IrqSafeSpinLock<[Option<&'static (dyn IntSource + Sync)>; MAX_IRQ]>, } @@ -124,13 +123,12 @@ impl Gic { /// # Safety /// /// Does not perform `gicd_base` and `gicc_base` validation. - pub const unsafe fn new(gicd_base: usize, gicc_base: usize, scheduler_irq: IrqNumber) -> Self { + pub const unsafe fn new(gicd_base: usize, gicc_base: usize) -> Self { Self { gicc: InitOnce::new(), gicd: InitOnce::new(), gicd_base, gicc_base, - scheduler_irq, table: IrqSafeSpinLock::new([None; MAX_IRQ]), } } diff --git a/kernel/src/arch/aarch64/mach_qemu/mod.rs b/kernel/src/arch/aarch64/mach_qemu/mod.rs index fdeb445..d85c6bf 100644 --- a/kernel/src/arch/aarch64/mach_qemu/mod.rs +++ b/kernel/src/arch/aarch64/mach_qemu/mod.rs @@ -78,6 +78,6 @@ pub fn intc() -> &'static impl IntController { static UART0: Pl011 = unsafe { Pl011::new(UART0_BASE, UART0_IRQ) }; static RTC: Pl031 = unsafe { Pl031::new(RTC_BASE, RTC_IRQ) }; -static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE, LOCAL_TIMER_IRQ) }; +static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE) }; static PCIE: GenericPcieHost = unsafe { GenericPcieHost::new(ECAM_BASE, 8) }; static LOCAL_TIMER: GenericTimer = GenericTimer::new(LOCAL_TIMER_IRQ); diff --git a/kernel/src/debug.rs b/kernel/src/debug.rs index d75bab0..fb85ea2 100644 --- a/kernel/src/debug.rs +++ b/kernel/src/debug.rs @@ -114,7 +114,7 @@ macro_rules! errorln { } #[doc(hidden)] -pub fn _debug(level: Level, args: fmt::Arguments) { +pub fn _debug(_level: Level, args: fmt::Arguments) { use crate::arch::machine; use fmt::Write; diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index b826644..2d9300f 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -34,6 +34,7 @@ pub trait TtyDevice: SerialDevice { /// Returns a reference to character device's ring buffer fn ring(&self) -> &CharRing; + /// Returns `true` if the TTY is ready for an operation fn is_ready(&self, write: bool) -> Result { let ring = self.ring(); if write { @@ -265,6 +266,7 @@ impl CharRing { } } + /// Returns `true` if a character/line is available for reception pub fn is_readable(&self) -> bool { let inner = self.inner.lock(); let config = self.config.lock(); diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 299a08d..acfa1b8 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -28,6 +28,7 @@ unsafe impl BlockAllocator for MemfsBlockAlloc { } } +/// Creates a filesystem instance based on `options` pub fn create_filesystem(options: &MountOptions) -> Result { let fs_name = options.fs.unwrap(); diff --git a/kernel/src/mem/virt/table.rs b/kernel/src/mem/virt/table.rs index 64a4c4d..8ec0d4b 100644 --- a/kernel/src/mem/virt/table.rs +++ b/kernel/src/mem/virt/table.rs @@ -210,6 +210,9 @@ impl Space { } } + /// Translates a virtual address into a corresponding physical one. + /// + /// Only works for 4K pages atm. // TODO extract attributes pub fn translate(&mut self, virt: usize) -> Result { let l0i = virt >> 30; @@ -264,6 +267,8 @@ impl Space { Ok(()) } + /// Allocates a contiguous region from the address space and maps + /// physical pages to it pub fn allocate( &mut self, start: usize, @@ -288,6 +293,8 @@ impl Space { Err(Errno::OutOfMemory) } + /// Removes a single 4K page mapping from the table and + /// releases the underlying physical memory pub fn unmap_single(&mut self, page: usize) -> Result<(), Errno> { let l0i = page >> 30; let l1i = (page >> 21) & 0x1FF; @@ -304,7 +311,7 @@ impl Space { let phys = unsafe { entry.address_unchecked() }; unsafe { - phys::free_page(phys); + phys::free_page(phys)?; } l2_table[l2i] = Entry::invalid(); @@ -317,6 +324,7 @@ impl Space { Ok(()) } + /// Releases a range of virtual pages and their corresponding physical pages pub fn free(&mut self, start: usize, len: usize) -> Result<(), Errno> { for i in 0..len { self.unmap_single(start + i * 0x1000)?; diff --git a/kernel/src/proc/io.rs b/kernel/src/proc/io.rs index 5e4ee77..c7ff1f9 100644 --- a/kernel/src/proc/io.rs +++ b/kernel/src/proc/io.rs @@ -22,25 +22,30 @@ impl ProcessIo { Ok(dst) } + /// Sets controlling terminal for the process pub fn set_ctty(&mut self, node: VnodeRef) { assert_eq!(node.kind(), VnodeKind::Char); self.ctty = Some(node); } + /// Returns current controlling terminal of the process pub fn ctty(&mut self) -> Option { self.ctty.clone() } + /// Returns user ID of the process #[inline(always)] pub fn uid(&self) -> UserId { self.ioctx.as_ref().unwrap().uid } + /// Returns group ID of the process #[inline(always)] pub fn gid(&self) -> GroupId { self.ioctx.as_ref().unwrap().gid } + /// Changes (if permitted) user ID of the process #[inline(always)] pub fn set_uid(&mut self, uid: UserId) -> Result<(), Errno> { let old_uid = self.uid(); @@ -54,6 +59,7 @@ impl ProcessIo { } } + /// Changes (if permitted) group ID of the process #[inline(always)] pub fn set_gid(&mut self, gid: GroupId) -> Result<(), Errno> { let old_gid = self.gid(); @@ -67,6 +73,7 @@ impl ProcessIo { } } + /// Clones a file descriptor into an available slot or, if specified, requested one pub fn duplicate_file(&mut self, src: FileDescriptor, dst: Option) -> Result { let file_ref = self.file(src)?; if let Some(dst) = dst { diff --git a/kernel/src/proc/mod.rs b/kernel/src/proc/mod.rs index 1c77633..e6ed03d 100644 --- a/kernel/src/proc/mod.rs +++ b/kernel/src/proc/mod.rs @@ -20,25 +20,6 @@ pub mod sched; pub use sched::Scheduler; pub(self) use sched::SCHED; -// macro_rules! spawn { -// (fn ($dst_arg:ident : usize) $body:block, $src_arg:expr) => {{ -// #[inline(never)] -// extern "C" fn __inner_func($dst_arg : usize) -> ! { -// let __res = $body; -// { -// #![allow(unreachable_code)] -// SCHED.current_process().exit(__res); -// panic!(); -// } -// } -// -// let __proc = $crate::proc::Process::new_kernel(__inner_func, $src_arg).unwrap(); -// $crate::proc::SCHED.enqueue(__proc.id()); -// }}; -// -// (fn () $body:block) => (spawn!(fn (_arg: usize) $body, 0usize)) -// } - /// Performs a task switch. /// /// See [Scheduler::switch] @@ -46,12 +27,6 @@ pub fn switch() { SCHED.switch(false); } -/// -pub fn process(id: Pid) -> ProcessRef { - PROCESSES.lock().get(&id).unwrap().clone() -} - -/// Global list of all processes in the system pub(self) static PROCESSES: IrqSafeSpinLock> = IrqSafeSpinLock::new(BTreeMap::new()); diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 7c90cd2..6e9b8d6 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -8,18 +8,16 @@ use crate::mem::{ use crate::proc::{ wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED, }; -use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard}; +use crate::sync::IrqSafeSpinLock; use alloc::{rc::Rc, vec::Vec}; -use core::alloc::Layout; use core::sync::atomic::{AtomicU32, Ordering}; use libsys::{ error::Errno, + mem::memcpy, proc::{ExitCode, Pid}, signal::Signal, - mem::memcpy, ProgramArgs, }; -use vfs::{VnodeKind, VnodeRef}; /// Wrapper type for a process struct reference pub type ProcessRef = Rc; @@ -58,39 +56,47 @@ impl Process { const USTACK_VIRT_TOP: usize = 0x100000000; const USTACK_PAGES: usize = 4; + /// Returns the process ID #[inline] pub fn id(&self) -> Pid { self.inner.lock().id } + /// Returns the process session ID #[inline] pub fn sid(&self) -> Pid { self.inner.lock().sid } + /// Returns parent's [Pid] #[inline] pub fn pgid(&self) -> Pid { self.inner.lock().pgid } + /// Returns parent's [Pid] #[inline] pub fn ppid(&self) -> Option { self.inner.lock().ppid } + /// Sets a new group id for the process pub fn set_pgid(&self, pgid: Pid) { self.inner.lock().pgid = pgid; } + /// Sets a new session id for the process pub fn set_sid(&self, sid: Pid) { self.inner.lock().sid = sid; } + /// Returns [Rc]-reference to current process #[inline] pub fn current() -> ProcessRef { Thread::current().owner().unwrap() } + /// Executes a closure performing manipulations on the process address space #[inline] pub fn manipulate_space(&self, f: F) -> R where @@ -99,6 +105,7 @@ impl Process { f(self.inner.lock().space.as_mut().unwrap()) } + /// Creates a new kernel process pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result { let id = new_kernel_pid(); let thread = Thread::new_kernel(Some(id), entry, arg)?; @@ -126,6 +133,7 @@ impl Process { Ok(res) } + /// Adds all of the process threads to scheduler queue pub fn enqueue(&self) { let inner = self.inner.lock(); for &tid in inner.threads.iter() { @@ -168,12 +176,14 @@ impl Process { } } + /// Immediately delivers a signal to requested thread pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) { let mut lock = self.inner.lock(); let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48); thread.enter_signal(signal, ttbr0); } + /// Crates a new thread in the process pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result { let mut lock = self.inner.lock(); @@ -264,6 +274,8 @@ impl Process { } } + /// Terminates a thread of the process. If the thread is the only + /// one remaining, process itself is exited (see [Process::exit]) pub fn exit_thread(thread: ThreadRef, status: ExitCode) { let switch = { let switch = thread.state() == ThreadState::Running; @@ -337,11 +349,11 @@ impl Process { phys } else { let page = phys::alloc_page(PageUsage::UserPrivate)?; - let flags = MapAttributes::SH_OUTER | - MapAttributes::NOT_GLOBAL | - MapAttributes::UXN | - MapAttributes::PXN | - MapAttributes::AP_BOTH_READONLY; + let flags = MapAttributes::SH_OUTER + | MapAttributes::NOT_GLOBAL + | MapAttributes::UXN + | MapAttributes::PXN + | MapAttributes::AP_BOTH_READONLY; space.map(page_virt, page, flags)?; page }; @@ -361,17 +373,21 @@ impl Process { phys } else { let page = phys::alloc_page(PageUsage::UserPrivate)?; - let flags = MapAttributes::SH_OUTER | - MapAttributes::NOT_GLOBAL | - MapAttributes::UXN | - MapAttributes::PXN | - MapAttributes::AP_BOTH_READONLY; + let flags = MapAttributes::SH_OUTER + | MapAttributes::NOT_GLOBAL + | MapAttributes::UXN + | MapAttributes::PXN + | MapAttributes::AP_BOTH_READONLY; space.map(page_virt, page, flags)?; page }; unsafe { - memcpy((mem::virtualize(page_phys) + (dst % 4096)) as *mut u8, src.as_ptr(), src.len()); + memcpy( + (mem::virtualize(page_phys) + (dst % 4096)) as *mut u8, + src.as_ptr(), + src.len(), + ); } Ok(()) } @@ -405,7 +421,7 @@ impl Process { argc: argv.len(), argv: base + argv_offset, storage: base, - size: offset + core::mem::size_of::() + size: offset + core::mem::size_of::(), }; Self::write_paged(space, base + offset, data)?; diff --git a/kernel/src/proc/sched.rs b/kernel/src/proc/sched.rs index ccdc751..cfff932 100644 --- a/kernel/src/proc/sched.rs +++ b/kernel/src/proc/sched.rs @@ -48,14 +48,6 @@ impl Scheduler { self.inner.get().lock().queue.retain(|&p| p != tid) } - pub fn debug(&self) { - let lock = self.inner.get().lock(); - debugln!("Scheduler queue:"); - for &tid in lock.queue.iter() { - debugln!("TID: {:?}", tid); - } - } - /// Performs initial process entry. /// /// # Safety @@ -132,6 +124,7 @@ impl Scheduler { } } + /// Returns a [Rc]-reference to currently running Thread pub fn current_thread(&self) -> ThreadRef { let inner = self.inner.get().lock(); let id = inner.current.unwrap(); diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index fb653e6..4e1b06a 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -1,5 +1,10 @@ +//! Facilities for controlling threads - smallest units of +//! execution in the operating system use crate::arch::aarch64::exception::ExceptionFrame; -use crate::proc::{wait::{Wait, WaitStatus}, Process, ProcessRef, SCHED, THREADS}; +use crate::proc::{ + wait::{Wait, WaitStatus}, + Process, ProcessRef, SCHED, THREADS, +}; use crate::sync::IrqSafeSpinLock; use crate::util::InitOnce; use alloc::rc::Rc; @@ -13,6 +18,7 @@ use libsys::{ pub use crate::arch::platform::context::{self, Context}; +/// Convenience wrapper for [Thread] references pub type ThreadRef = Rc; /// List of possible process states @@ -38,6 +44,7 @@ struct ThreadInner { signal_stack: usize, } +/// Thread control data pub struct Thread { inner: IrqSafeSpinLock, exit_wait: Wait, @@ -48,21 +55,25 @@ pub struct Thread { } impl Thread { + /// Returns currently active thread [Rc]-reference #[inline] pub fn current() -> ThreadRef { SCHED.current_thread() } + /// Returns a reference to thread `tid`, if it exists #[inline] pub fn get(tid: u32) -> Option { THREADS.lock().get(&tid).cloned() } + /// Returns the owner process #[inline] pub fn owner(&self) -> Option { self.inner.lock().owner.and_then(Process::get) } + /// Returns [Pid] of the owner process pub fn owner_id(&self) -> Option { self.inner.lock().owner } @@ -127,6 +138,7 @@ impl Thread { Ok(res) } + /// Creates a fork thread cloning `frame` context pub fn fork( owner: Option, frame: &ExceptionFrame, @@ -155,6 +167,7 @@ impl Thread { Ok(res) } + /// Returns the thread ID #[inline] pub fn id(&self) -> u32 { self.inner.lock().id @@ -230,6 +243,7 @@ impl Thread { lock.wait_status = WaitStatus::Pending; } + /// Suspends current thread until thread `tid` terminates pub fn waittid(tid: u32) -> Result<(), Errno> { loop { let thread = THREADS @@ -247,17 +261,20 @@ impl Thread { } } + /// Updates pending wait status pub fn set_wait_status(&self, status: WaitStatus) { let mut lock = self.inner.lock(); lock.wait_status = status; } + /// Resets wait channel back to initial state pub fn reset_wait(&self) { let mut lock = self.inner.lock(); lock.pending_wait = None; lock.wait_status = WaitStatus::Done; } + /// Returns status of the thread's pending wait pub fn wait_status(&self) -> WaitStatus { self.inner.lock().wait_status } @@ -279,11 +296,13 @@ impl Thread { } } + /// Returns the thread state #[inline] pub fn state(&self) -> State { self.inner.lock().state } + /// Sets the thread's owner process ID pub fn set_owner(&self, pid: Pid) { self.inner.lock().owner = Some(pid); } @@ -295,6 +314,7 @@ impl Thread { lock.signal_stack = stack; } + /// Sets up a context for signal handler pub fn setup_signal(self: ThreadRef, signal: Signal, ttbr0: usize) { if self .signal_pending @@ -312,7 +332,6 @@ impl Thread { } let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; - let src_ctx = self.ctx.get(); debugln!( "Signal entry: tid={}, pc={:#x}, sp={:#x}, ttbr0={:#x}", @@ -330,7 +349,6 @@ impl Thread { lock.signal_stack, ); } - } /// Switches process main thread to a signal handler @@ -346,6 +364,7 @@ impl Thread { } } + /// Interrupts pending wait (from signal routines) pub fn interrupt_wait(&self, enqueue: bool) { let mut lock = self.inner.lock(); let tid = lock.id; @@ -356,6 +375,8 @@ impl Thread { } } + /// Cleans up any resources of the thread and aborts + /// pending wait, if any pub fn terminate(&self, status: ExitCode) { let mut lock = self.inner.lock(); lock.state = State::Finished; @@ -376,6 +397,7 @@ impl Drop for Thread { } } +/// Allocates a new thread ID pub fn new_tid() -> u32 { static LAST: AtomicU32 = AtomicU32::new(1); let id = LAST.fetch_add(1, Ordering::Relaxed); diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index de19bd2..8b5dce1 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -12,13 +12,18 @@ use libsys::{error::Errno, stat::FdSet}; /// waiting for some event to happen. pub struct Wait { queue: IrqSafeSpinLock>, + #[allow(dead_code)] name: &'static str } +/// Status of a (possibly) pending wait #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum WaitStatus { + /// In progress Pending, + /// Wait was interrupted by a signal Interrupted, + /// Channel reported data available Done, } @@ -28,6 +33,8 @@ struct Timeout { } static TICK_LIST: IrqSafeSpinLock> = IrqSafeSpinLock::new(LinkedList::new()); +/// Global wait channel for blocking on select. Gets notified +/// of ANY I/O operations available, so not very efficient. pub static WAIT_SELECT: Wait = Wait::new("select"); /// Checks for any timed out wait channels and interrupts them @@ -63,6 +70,8 @@ pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> { } } +/// Suspends current process until some file descriptor +/// signals data available pub fn select( thread: ThreadRef, mut rfds: Option<&mut FdSet>, @@ -119,6 +128,7 @@ impl Wait { } } + /// Interrupt wait pending on the channel pub fn abort(&self, tid: u32, enqueue: bool) { let mut queue = self.queue.lock(); let mut tick_lock = TICK_LIST.lock(); diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index 629ec96..88a4eae 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -36,6 +36,7 @@ fn is_el0_accessible(virt: usize, write: bool) -> bool { res & 1 == 0 } +/// Checks given argument and interprets it as a `T` reference pub fn struct_ref<'a, T>(base: usize) -> Result<&'a T, Errno> { let layout = Layout::new::(); if base % layout.align() != 0 { @@ -49,6 +50,7 @@ pub fn struct_ref<'a, T>(base: usize) -> Result<&'a T, Errno> { Ok(unsafe { &*(bytes.as_ptr() as *const T) }) } +/// Checks given argument and interprets it as a `T` mutable reference pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> { let layout = Layout::new::(); if base % layout.align() != 0 { @@ -62,6 +64,7 @@ pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> { Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) } +/// Checks given argument and interprets it as a `T` array buffer of size `count` pub fn struct_buf_ref<'a, T>(base: usize, count: usize) -> Result<&'a [T], Errno> { let layout = Layout::array::(count).unwrap(); if base % layout.align() != 0 { @@ -75,6 +78,7 @@ pub fn struct_buf_ref<'a, T>(base: usize, count: usize) -> Result<&'a [T], Errno Ok(unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *const T, count) }) } +/// Checks given argument and interprets it as a `T` array buffer of size `count` pub fn struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<&'a mut [T], Errno> { let layout = Layout::array::(count).unwrap(); if base % layout.align() != 0 { @@ -88,6 +92,7 @@ pub fn struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<&'a mut [T], E Ok(unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, count) }) } +/// Checks given argument and interprets it as a `Option<&'a T>` pub fn option_struct_ref<'a, T>(base: usize) -> Result, Errno> { if base == 0 { Ok(None) @@ -96,6 +101,7 @@ pub fn option_struct_ref<'a, T>(base: usize) -> Result, Errno> { } } +/// Checks given argument and interprets it as a `Option<&'a mut T>` pub fn option_struct_mut<'a, T>(base: usize) -> Result, Errno> { if base == 0 { Ok(None) @@ -104,6 +110,8 @@ pub fn option_struct_mut<'a, T>(base: usize) -> Result, Errno> } } +/// Validates that the argument pointer is accessible for requested operation +/// for current process pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> { if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET { invalid_memory!( @@ -144,16 +152,19 @@ pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> { Ok(()) } +/// Checks given argument and interprets it as a byte buffer pub fn buf_ref<'a>(base: usize, len: usize) -> Result<&'a [u8], Errno> { validate_ptr(base, len, false)?; Ok(unsafe { core::slice::from_raw_parts(base as *const u8, len) }) } +/// Checks given argument and interprets it as a mutable byte buffer pub fn buf_mut<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Errno> { validate_ptr(base, len, true)?; Ok(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, len) }) } +/// Checks possibly NULL given argument and interprets it as a byte buffer pub fn option_buf_ref<'a>(base: usize, len: usize) -> Result, Errno> { if base == 0 { Ok(None) @@ -162,6 +173,7 @@ pub fn option_buf_ref<'a>(base: usize, len: usize) -> Result, E } } +/// Checks possibly NULL given argument and interprets it as a mutable byte buffer pub fn option_buf_mut<'a>(base: usize, len: usize) -> Result, Errno> { if base == 0 { Ok(None) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index fb00db9..d566fcc 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -14,7 +14,7 @@ use libsys::{ debug::TraceLevel, error::Errno, ioctl::IoctlCmd, - proc::{ExitCode, Pid, MemoryAccess, MemoryMap}, + proc::{ExitCode, Pid, MemoryAccess}, signal::{Signal, SignalDestination}, stat::{ AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions, @@ -208,7 +208,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { return Err(Errno::InvalidArgument); } let acc = MemoryAccess::from_bits(args[2] as u32).ok_or(Errno::InvalidArgument)?; - let flags = MemoryAccess::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; + let _flags = MemoryAccess::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?; let mut attrs = MapAttributes::NOT_GLOBAL | MapAttributes::SH_OUTER | MapAttributes::PXN; if !acc.contains(MemoryAccess::READ) { @@ -386,7 +386,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { let proc = Process::current(); let mut io = proc.io.lock(); - if let Some(ctty) = io.ctty() { + if let Some(_ctty) = io.ctty() { todo!(); } diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index 1e18b4a..d0ba0bb 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -472,5 +472,5 @@ pub fn sys_mmap( #[inline(always)] pub unsafe fn sys_munmap(addr: usize, len: usize) -> Result<(), Errno> { - Errno::from_syscall_unit(unsafe { syscall!(SystemCall::UnmapMemory, argn!(addr), argn!(len)) }) + Errno::from_syscall_unit(syscall!(SystemCall::UnmapMemory, argn!(addr), argn!(len))) } diff --git a/libsys/src/stat.rs b/libsys/src/stat.rs index 188f46b..8cc3ac8 100644 --- a/libsys/src/stat.rs +++ b/libsys/src/stat.rs @@ -274,8 +274,7 @@ impl fmt::Display for FileMode { choose(self.contains(Self::OTHER_READ), 'r', '-'), choose(self.contains(Self::OTHER_WRITE), 'w', '-'), choose(self.contains(Self::OTHER_EXEC), 'x', '-'), - ); - Ok(()) + ) } } diff --git a/libusr/src/allocator.rs b/libusr/src/allocator.rs index 353c78a..7f4f65a 100644 --- a/libusr/src/allocator.rs +++ b/libusr/src/allocator.rs @@ -1,12 +1,9 @@ use core::alloc::{GlobalAlloc, Layout}; use core::mem::{size_of, MaybeUninit}; use core::ptr::null_mut; -use core::sync::atomic::{AtomicUsize, Ordering}; use libsys::{ calls::{sys_mmap, sys_munmap}, - debug::TraceLevel, error::Errno, - mem::memset, proc::{MemoryAccess, MemoryMap}, }; use memoffset::offset_of; @@ -117,7 +114,7 @@ impl Zone { unsafe fn zone_alloc(zone: &mut Zone, size: usize) -> *mut u8 { assert_eq!(size & 15, 0); - let mut begin = ((zone as *mut _ as usize) + size_of::()) as *mut Block; + let begin = ((zone as *mut _ as usize) + size_of::()) as *mut Block; let mut block = begin; while !block.is_null() { @@ -168,6 +165,7 @@ unsafe fn alloc_from(list: &mut ZoneList, zone_size: usize, size: usize) -> *mut if !ptr.is_null() { return ptr; } + zone = (&mut *zone).next; } let zone = match Zone::alloc(zone_size) { diff --git a/libusr/src/file.rs b/libusr/src/file.rs index 6c1855e..ef161d3 100644 --- a/libusr/src/file.rs +++ b/libusr/src/file.rs @@ -1,4 +1,4 @@ -use crate::io::{AsRawFd, Error, Read, Write}; +use crate::io::{AsRawFd, Error, Read}; use libsys::{ calls::{sys_openat, sys_read, sys_close}, stat::{FileDescriptor, FileMode, OpenFlags}, diff --git a/libusr/src/io/mod.rs b/libusr/src/io/mod.rs index 6e2bf5f..d0c97d5 100644 --- a/libusr/src/io/mod.rs +++ b/libusr/src/io/mod.rs @@ -28,7 +28,7 @@ pub trait AsRawFd { fn as_raw_fd(&self) -> FileDescriptor; } -pub fn tcgetpgrp(fd: FileDescriptor) -> Result { +pub fn tcgetpgrp(_fd: FileDescriptor) -> Result { todo!() } diff --git a/user/src/bin/cat.rs b/user/src/bin/cat.rs index 24e2592..6360799 100644 --- a/user/src/bin/cat.rs +++ b/user/src/bin/cat.rs @@ -3,8 +3,6 @@ #[macro_use] extern crate libusr; -#[macro_use] -extern crate alloc; use libusr::io::{self, Read, Write}; use libusr::file::File; @@ -19,7 +17,7 @@ fn do_cat(mut fd: F) -> Result<(), io::Error> { break; } - out.write(&buf[..count]); + out.write(&buf[..count])?; } Ok(()) diff --git a/user/src/bin/hexd.rs b/user/src/bin/hexd.rs index 0a2b1cd..536463c 100644 --- a/user/src/bin/hexd.rs +++ b/user/src/bin/hexd.rs @@ -3,10 +3,8 @@ #[macro_use] extern crate libusr; -#[macro_use] -extern crate alloc; -use libusr::io::{self, Read, Write}; +use libusr::io::{self, Read}; use libusr::file::File; fn line_print(off: usize, line: &[u8]) { diff --git a/user/src/bin/ls.rs b/user/src/bin/ls.rs index d50f795..ef35207 100644 --- a/user/src/bin/ls.rs +++ b/user/src/bin/ls.rs @@ -6,7 +6,7 @@ extern crate libusr; #[macro_use] extern crate alloc; -use alloc::{borrow::ToOwned, string::String}; +use alloc::borrow::ToOwned; use libusr::sys::{ stat::{DirectoryEntry, FileMode, OpenFlags, Stat}, sys_close, sys_fstatat, sys_openat, sys_readdir, Errno, diff --git a/user/src/bin/shell.rs b/user/src/bin/shell.rs index 18d3e15..ecd6319 100644 --- a/user/src/bin/shell.rs +++ b/user/src/bin/shell.rs @@ -107,7 +107,6 @@ fn main() -> i32 { println!("Interrupt!"); continue; } - _ => panic!(), } } 0 diff --git a/user/src/init/main.rs b/user/src/init/main.rs index f75daca..b7b1448 100644 --- a/user/src/init/main.rs +++ b/user/src/init/main.rs @@ -18,11 +18,9 @@ fn main() -> i32 { ) .expect("Failed to mount devfs"); - let pid = unsafe { libusr::sys::sys_fork().unwrap() }; - - if let Some(pid) = pid { + if let Some(pid) = unsafe { sys_fork().unwrap() } { let mut status = 0; - libusr::sys::sys_waitpid(pid, &mut status).unwrap(); + sys_waitpid(pid, &mut status).unwrap(); println!("Process {:?} exited with status {}", pid, status); loop { @@ -31,7 +29,7 @@ fn main() -> i32 { } } } else { - libusr::sys::sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap(); + sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap(); loop {} } } diff --git a/user/src/sbin/login.rs b/user/src/sbin/login.rs index 63d172e..3de22b2 100644 --- a/user/src/sbin/login.rs +++ b/user/src/sbin/login.rs @@ -3,8 +3,6 @@ #[macro_use] extern crate libusr; -#[macro_use] -extern crate alloc; use libsys::{ calls::{ @@ -96,7 +94,7 @@ fn login_as(uid: UserId, gid: GroupId, shell: &str) -> Result<(), Errno> { // TODO baud rate and misc port settings #[no_mangle] fn main() -> i32 { - if !sys_getuid().is_root() { + if !sys_getuid().is_root() || !sys_getgid().is_root() { panic!("This program must be run as root"); } @@ -143,9 +141,7 @@ fn main() -> i32 { .expect("Password read failed"); if username == "root" && password == "toor" { - login_as(UserId::from(0), GroupId::from(0), "/bin/shell"); + login_as(UserId::from(0), GroupId::from(0), "/bin/shell").unwrap(); } } - - 0 }