From 15b029de3687fdbbe62efc018e339f9b2937f933 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 22 Feb 2022 19:49:05 +0100 Subject: [PATCH] Fix everything all the way to booting to desktop. --- Cargo.toml | 4 +- src/arch/x86_64/consts.rs | 43 +------------------ src/context/context.rs | 9 +++- src/context/signal.rs | 6 +-- src/scheme/proc.rs | 18 ++++++++ src/syscall/driver.rs | 87 ++++++++++++++++++--------------------- src/syscall/mod.rs | 16 +++++-- src/syscall/process.rs | 45 +++++++++++--------- 8 files changed, 110 insertions(+), 118 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2bd3aa7e17..82ead039eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,9 @@ raw-cpuid = "10.2.0" x86 = { version = "0.47.0", default-features = false } [features] -default = ["acpi", "multi_core", "graphical_debug", "serial_debug"] +# TODO: Fix multicore +#default = ["acpi", "multi_core", "graphical_debug", "serial_debug"] +default = ["acpi", "graphical_debug", "serial_debug"] acpi = [] doc = [] graphical_debug = [] diff --git a/src/arch/x86_64/consts.rs b/src/arch/x86_64/consts.rs index b7b7ccbcb3..33432e8259 100644 --- a/src/arch/x86_64/consts.rs +++ b/src/arch/x86_64/consts.rs @@ -37,47 +37,8 @@ /// Offset to user image pub const USER_OFFSET: usize = 0; - pub const USER_PML4: usize = (USER_OFFSET & PML4_MASK)/PML4_SIZE; - - /// Offset to user arguments - pub const USER_ARG_OFFSET: usize = USER_OFFSET + PML4_SIZE/2; - - /// Offset to user grants - pub const USER_GRANT_OFFSET: usize = USER_OFFSET + PML4_SIZE; - pub const USER_GRANT_PML4: usize = (USER_GRANT_OFFSET & PML4_MASK)/PML4_SIZE; - - /// Offset to user stack - pub const USER_STACK_OFFSET: usize = USER_GRANT_OFFSET + PML4_SIZE; - pub const USER_STACK_PML4: usize = (USER_STACK_OFFSET & PML4_MASK)/PML4_SIZE; - /// Size of user stack - pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB - - /// Offset to user sigstack - pub const USER_SIGSTACK_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; - pub const USER_SIGSTACK_PML4: usize = (USER_SIGSTACK_OFFSET & PML4_MASK)/PML4_SIZE; - /// Size of user sigstack - pub const USER_SIGSTACK_SIZE: usize = 256 * 1024; // 256 KB - - /// Offset to user temporary image (used when cloning) - pub const USER_TMP_OFFSET: usize = USER_SIGSTACK_OFFSET + PML4_SIZE; - pub const USER_TMP_PML4: usize = (USER_TMP_OFFSET & PML4_MASK)/PML4_SIZE; - - /// Offset to user temporary heap (used when cloning) - pub const USER_TMP_HEAP_OFFSET: usize = USER_TMP_OFFSET + PML4_SIZE; - pub const USER_TMP_HEAP_PML4: usize = (USER_TMP_HEAP_OFFSET & PML4_MASK)/PML4_SIZE; - - /// Offset to user temporary page for grants - pub const USER_TMP_GRANT_OFFSET: usize = USER_TMP_HEAP_OFFSET + PML4_SIZE; - pub const USER_TMP_GRANT_PML4: usize = (USER_TMP_GRANT_OFFSET & PML4_MASK)/PML4_SIZE; - - /// Offset to user temporary stack (used when cloning) - pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_GRANT_OFFSET + PML4_SIZE; - pub const USER_TMP_STACK_PML4: usize = (USER_TMP_STACK_OFFSET & PML4_MASK)/PML4_SIZE; - - /// Offset to user temporary sigstack (used when cloning) - pub const USER_TMP_SIGSTACK_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; - pub const USER_TMP_SIGSTACK_PML4: usize = (USER_TMP_SIGSTACK_OFFSET & PML4_MASK)/PML4_SIZE; /// Offset for usage in other temporary pages - pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_SIGSTACK_OFFSET + PML4_SIZE; + // TODO: Currently used for ptrace but should be removed or replaced with a kernel address. + pub const USER_TMP_MISC_OFFSET: usize = USER_OFFSET + PML4_SIZE; pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK)/PML4_SIZE; diff --git a/src/context/context.rs b/src/context/context.rs index 71a21d054e..614318a248 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -244,7 +244,11 @@ pub struct Context { /// A somewhat hacky way to initially stop a context when creating /// a new instance of the proc: scheme, entirely separate from /// signals or any other way to restart a process. - pub ptrace_stop: bool + pub ptrace_stop: bool, + /// A pointer to the signal stack. If this is unset, none of the sigactions can be anything + /// else than SIG_DFL, otherwise signals will not be delivered. Userspace is responsible for + /// setting this. + pub sigstack: Option, } // Necessary because GlobalAlloc::dealloc requires the layout to be the same, and therefore Box @@ -345,7 +349,8 @@ impl Context { 0 ); 128])), regs: None, - ptrace_stop: false + ptrace_stop: false, + sigstack: None, }) } diff --git a/src/context/signal.rs b/src/context/signal.rs index ae6b2529e0..7b19831e73 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -13,12 +13,12 @@ pub fn is_user_handled(handler: Option) -> bool { } pub extern "C" fn signal_handler(sig: usize) { - let (action, restorer) = { + let ((action, restorer), sigstack) = { let contexts = contexts(); let context_lock = contexts.current().expect("context::signal_handler not inside of context"); let context = context_lock.read(); let actions = context.actions.read(); - actions[sig] + (actions[sig], context.sigstack) }; let handler = action.sa_handler.map(|ptr| ptr as usize).unwrap_or(0); @@ -115,7 +115,7 @@ pub extern "C" fn signal_handler(sig: usize) { }; unsafe { - let mut sp = crate::USER_SIGSTACK_OFFSET + crate::USER_SIGSTACK_SIZE - 256; + let mut sp = sigstack.expect("sigaction was set while sigstack was not") - 256; sp = (sp / 16) * 16; diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 5b66dcb3c1..cb2fc9215c 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -23,6 +23,7 @@ use alloc::{ }; use core::{ cmp, + convert::TryFrom, mem, slice, str, @@ -102,6 +103,7 @@ enum Operation { Trace, Static(&'static str), Name, + Sigstack, } impl Operation { fn needs_child_process(self) -> bool { @@ -111,6 +113,7 @@ impl Operation { Self::Trace => true, Self::Static(_) => false, Self::Name => false, + Self::Sigstack => false, } } } @@ -251,6 +254,7 @@ impl Scheme for ProcScheme { Some("trace") => Operation::Trace, Some("exe") => Operation::Static("exe"), Some("name") => Operation::Name, + Some("sigstack") => Operation::Sigstack, _ => return Err(Error::new(EINVAL)) }; @@ -529,6 +533,13 @@ impl Scheme for ProcScheme { Ok(to_copy) } } + Operation::Sigstack => match context::contexts().current().ok_or(Error::new(ESRCH))?.read().sigstack.unwrap_or(!0).to_ne_bytes() { + sigstack => { + let to_copy = cmp::min(buf.len(), sigstack.len()); + buf[..to_copy].copy_from_slice(&sigstack[..to_copy]); + Ok(to_copy) + } + } } } @@ -719,6 +730,12 @@ impl Scheme for ProcScheme { *context::contexts().current().ok_or(Error::new(ESRCH))?.read().name.write() = utf8; Ok(buf.len()) } + Operation::Sigstack => { + let bytes = <[u8; mem::size_of::()]>::try_from(buf).map_err(|_| Error::new(EINVAL))?; + let sigstack = usize::from_ne_bytes(bytes); + context::contexts().current().ok_or(Error::new(ESRCH))?.write().sigstack = (sigstack != !0).then(|| sigstack); + Ok(buf.len()) + } } } @@ -757,6 +774,7 @@ impl Scheme for ProcScheme { Operation::Trace => "trace", Operation::Static(path) => path, Operation::Name => "name", + Operation::Sigstack => "sigstack", }); let len = cmp::min(path.len(), buf.len()); diff --git a/src/syscall/driver.rs b/src/syscall/driver.rs index 1e64e1bb4e..f1fc77f2e8 100644 --- a/src/syscall/driver.rs +++ b/src/syscall/driver.rs @@ -1,9 +1,9 @@ use crate::interrupt::InterruptStack; -use crate::memory::{allocate_frames_complex, deallocate_frames, Frame}; +use crate::memory::{allocate_frames_complex, deallocate_frames, Frame, PAGE_SIZE}; use crate::paging::{ActivePageTable, PageFlags, PhysicalAddress, VirtualAddress}; use crate::paging::entry::EntryFlags; use crate::context; -use crate::context::memory::{Grant, Region}; +use crate::context::memory::{DANGLING, Grant, Region}; use crate::syscall::error::{Error, EFAULT, EINVAL, ENOMEM, EPERM, ESRCH, Result}; use crate::syscall::flag::{PhysallocFlags, PartialAllocStrategy, PhysmapFlags, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE}; @@ -71,56 +71,47 @@ pub fn physfree(physical_address: usize, size: usize) -> Result { } //TODO: verify exlusive access to physical memory +// TODO: Replace this completely with something such as `memory:physical`. Mmapping at offset +// `physaddr` to `address` (optional) will map that physical address. We would have to find out +// some way to pass flags such as WRITE_COMBINE/NO_CACHE however. pub fn inner_physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result { //TODO: Abstract with other grant creation if size == 0 { - Ok(0) - } else { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - - let mut grants = context.grants.write(); - - let from_address = (physical_address/4096) * 4096; - let offset = physical_address - from_address; - let full_size = ((offset + size + 4095)/4096) * 4096; - let mut to_address = crate::USER_GRANT_OFFSET; - - let mut page_flags = PageFlags::new().user(true); - if flags.contains(PHYSMAP_WRITE) { - page_flags = page_flags.write(true); - } - if flags.contains(PHYSMAP_WRITE_COMBINE) { - page_flags = page_flags.custom_flag(EntryFlags::HUGE_PAGE.bits(), true); - } - #[cfg(target_arch = "x86_64")] // TODO: AARCH64 - if flags.contains(PHYSMAP_NO_CACHE) { - page_flags = page_flags.custom_flag(EntryFlags::NO_CACHE.bits(), true); - } - - // TODO: Make this faster than Sonic himself by using le superpowers of BTreeSet - - for grant in grants.iter() { - let start = grant.start_address().data(); - if to_address + full_size < start { - break; - } - - let pages = (grant.size() + 4095) / 4096; - let end = start + pages * 4096; - to_address = end; - } - - grants.insert(Grant::physmap( - PhysicalAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - page_flags - )); - - Ok(to_address + offset) + return Ok(DANGLING); } + if size % PAGE_SIZE != 0 || physical_address % PAGE_SIZE != 0 { + return Err(Error::new(EINVAL)); + } + // TODO: Enforce size being a multiple of the page size, fail otherwise. + + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + + let mut grants = context.grants.write(); + + let dst_address = grants.find_free(size).ok_or(Error::new(ENOMEM))?; + + let mut page_flags = PageFlags::new().user(true); + if flags.contains(PHYSMAP_WRITE) { + page_flags = page_flags.write(true); + } + if flags.contains(PHYSMAP_WRITE_COMBINE) { + page_flags = page_flags.custom_flag(EntryFlags::HUGE_PAGE.bits(), true); + } + #[cfg(target_arch = "x86_64")] // TODO: AARCH64 + if flags.contains(PHYSMAP_NO_CACHE) { + page_flags = page_flags.custom_flag(EntryFlags::NO_CACHE.bits(), true); + } + + grants.insert(Grant::physmap( + PhysicalAddress::new(physical_address), + dst_address.start_address(), + size, + page_flags, + )); + + Ok(dst_address.start_address().data()) } pub fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result { enforce_root()?; diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index d85a19b7c3..0f9f440877 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -25,8 +25,8 @@ pub use self::process::*; pub use self::time::*; pub use self::validate::*; -use self::data::{ExecMemRange, Map, SigAction, Stat, TimeSpec}; -use self::error::{Error, Result, ENOSYS}; +use self::data::{CloneInfo, ExecMemRange, Map, SigAction, Stat, TimeSpec}; +use self::error::{Error, Result, ENOSYS, EINVAL}; use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags}; use self::number::*; @@ -134,6 +134,13 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u SYS_CLONE => { let b = CloneFlags::from_bits_truncate(b); + let info = if b.contains(CloneFlags::CLONE_VM) { + if d < core::mem::size_of::() { + return Err(Error::new(EINVAL)); + } + Some(&validate_slice(c as *const CloneInfo, 1)?[0]) + } else { None }; + #[cfg(not(target_arch = "x86_64"))] { //TODO: CLONE_STACK @@ -144,10 +151,11 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u #[cfg(target_arch = "x86_64")] { let old_rsp = stack.iret.rsp; + // TODO: Unify CLONE_STACK and CLONE_VM. if b.contains(flag::CLONE_STACK) { - stack.iret.rsp = c; + stack.iret.rsp = info.as_ref().ok_or(Error::new(EINVAL))?.target_stack; } - let ret = clone(b, bp).map(ContextId::into); + let ret = clone(b, bp, info).map(ContextId::into); stack.iret.rsp = old_rsp; ret } diff --git a/src/syscall/process.rs b/src/syscall/process.rs index a6e670f41e..3df81647e9 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -27,7 +27,7 @@ use crate::paging::{ActivePageTable, InactivePageTable, Page, PageFlags, RmmA, T use crate::{ptrace, syscall}; use crate::scheme::FileHandle; use crate::start::usermode; -use crate::syscall::data::{ExecMemRange, SigAction, Stat}; +use crate::syscall::data::{CloneInfo, ExecMemRange, SigAction, Stat}; use crate::syscall::error::*; use crate::syscall::flag::{wifcontinued, wifstopped, AT_ENTRY, AT_NULL, AT_PHDR, AT_PHENT, AT_PHNUM, CloneFlags, CLONE_FILES, CLONE_FS, CLONE_SIGHAND, CLONE_STACK, CLONE_VFORK, CLONE_VM, @@ -37,7 +37,7 @@ use crate::syscall::flag::{wifcontinued, wifstopped, AT_ENTRY, AT_NULL, AT_PHDR, use crate::syscall::ptrace_event; use crate::syscall::validate::{validate_slice, validate_slice_mut}; -pub fn clone(flags: CloneFlags, stack_base: usize) -> Result { +pub fn clone(flags: CloneFlags, stack_base: usize, info: Option<&CloneInfo>) -> Result { let ppid; let pid; { @@ -61,6 +61,7 @@ pub fn clone(flags: CloneFlags, stack_base: usize) -> Result { let cwd; let files; let actions; + let old_sigstack; // Copy from old process { @@ -78,6 +79,7 @@ pub fn clone(flags: CloneFlags, stack_base: usize) -> Result { ens = context.ens; sigmask = context.sigmask; umask = context.umask; + old_sigstack = context.sigstack; // Uncomment to disable threads on different CPUs //TODO: fix memory allocation races when this is removed @@ -360,6 +362,12 @@ pub fn clone(flags: CloneFlags, stack_base: usize) -> Result { context.files = files; context.actions = actions; + + if flags.contains(CLONE_VM) { + context.sigstack = info.and_then(|info| (info.target_sigstack != !0).then(|| info.target_sigstack)); + } else { + context.sigstack = old_sigstack; + } } } @@ -747,24 +755,23 @@ pub fn setpgid(pid: ContextId, pgid: ContextId) -> Result { } pub fn sigaction(sig: usize, act_opt: Option<&SigAction>, oldact_opt: Option<&mut SigAction>, restorer: usize) -> Result { - if sig > 0 && sig <= 0x7F { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - let mut actions = context.actions.write(); - - if let Some(oldact) = oldact_opt { - *oldact = actions[sig].0; - } - - if let Some(act) = act_opt { - actions[sig] = (*act, restorer); - } - - Ok(0) - } else { - Err(Error::new(EINVAL)) + if sig == 0 || sig > 0x7F { + return Err(Error::new(EINVAL)); } + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let mut actions = context.actions.write(); + + if let Some(oldact) = oldact_opt { + *oldact = actions[sig].0; + } + + if let Some(act) = act_opt { + actions[sig] = (*act, restorer); + } + + Ok(0) } pub fn sigprocmask(how: usize, mask_opt: Option<&[u64; 2]>, oldmask_opt: Option<&mut [u64; 2]>) -> Result {