From b86672b81e9e431b31231620c1a79e4424d422d4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 3 Jul 2018 19:42:23 -0600 Subject: [PATCH 01/14] Support for relibc --- src/syscall/process.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 297f645..0126115 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -691,10 +691,8 @@ fn exec_noreturn( for arg in args.iter().rev() { sp -= mem::size_of::(); unsafe { *(sp as *mut usize) = ::USER_ARG_OFFSET + arg_size; } - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = arg.len(); } - arg_size += arg.len(); + arg_size += arg.len() + 1; } sp -= mem::size_of::(); @@ -715,8 +713,12 @@ fn exec_noreturn( (::USER_ARG_OFFSET + arg_offset) as *mut u8, arg.len()); } - arg_offset += arg.len(); + + unsafe { + *((::USER_ARG_OFFSET + arg_offset) as *mut u8) = 0; + } + arg_offset += 1; } memory.remap(EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE); From c7b3765d6f3aed4bae9cab0cbb10b5b6262148ff Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Aug 2018 11:14:32 -0600 Subject: [PATCH 02/14] Remove execve, replace with fexec --- src/lib.rs | 3 +- src/syscall/debug.rs | 27 ++++++++---- src/syscall/mod.rs | 2 +- src/syscall/process.rs | 95 ++++++++++++++++++++++++------------------ syscall | 2 +- 5 files changed, 76 insertions(+), 53 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c3caf85..f0ce729 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,7 +143,8 @@ pub extern fn userspace_init() { assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1)); assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2)); - syscall::exec(b"/bin/init", &[]).expect("failed to execute init"); + let fd = syscall::open(b"/bin/init", syscall::flag::O_RDONLY).expect("failed to open init"); + syscall::fexec(fd, &[], &[]).expect("failed to execute init"); panic!("init returned"); } diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index 06474a1..d126f2e 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -191,13 +191,26 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - "clone({})", b ), + SYS_EXIT => format!( + "exit({})", + b + ), //TODO: Cleanup, do not allocate - SYS_EXECVE => format!( - "execve({:?}, {:?})", - validate_slice(b as *const u8, c).map(ByteStr), + SYS_FEXEC => format!( + "fexec({}, {:?}, {:?})", + b, validate_slice( - d as *const [usize; 2], - e + c as *const [usize; 2], + d + ).map(|slice| { + slice.iter().map(|a| + validate_slice(a[0] as *const u8, a[1]).ok() + .and_then(|s| ::core::str::from_utf8(s).ok()) + ).collect::>>() + }), + validate_slice( + e as *const [usize; 2], + f ).map(|slice| { slice.iter().map(|a| validate_slice(a[0] as *const u8, a[1]).ok() @@ -205,10 +218,6 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - ).collect::>>() }) ), - SYS_EXIT => format!( - "exit({})", - b - ), SYS_FUTEX => format!( "futex({:#X} [{:?}], {}, {}, {}, {})", b, diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index f06f1de..6ebcbac 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -64,6 +64,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into), SYS_FCNTL => fcntl(fd, c, d), SYS_FEVENT => fevent(fd, c), + SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?), SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?), SYS_FUNMAP => funmap(b), _ => file_op(a, fd, c, d) @@ -98,7 +99,6 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u SYS_KILL => kill(ContextId::from(b), c), SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into), SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?), - SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), SYS_IOPL => iopl(b, stack), SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?), SYS_GETEGID => getegid(), diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 0126115..8b012aa 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -2,7 +2,7 @@ use alloc::arc::Arc; use alloc::boxed::Box; use alloc::{BTreeMap, Vec}; use core::alloc::{Alloc, GlobalAlloc, Layout}; -use core::{intrinsics, mem, str}; +use core::{intrinsics, mem}; use core::ops::DerefMut; use spin::Mutex; @@ -541,11 +541,11 @@ impl Drop for ExecFile { } fn exec_noreturn( - canonical: Box<[u8]>, setuid: Option, setgid: Option, data: Box<[u8]>, - args: Box<[Box<[u8]>]> + args: Box<[Box<[u8]>]>, + vars: Box<[Box<[u8]>]> ) -> ! { let entry; let mut sp = ::USER_STACK_OFFSET + ::USER_STACK_SIZE - 256; @@ -557,7 +557,9 @@ fn exec_noreturn( let mut context = context_lock.write(); // Set name - context.name = Arc::new(Mutex::new(canonical)); + if let Some(name) = args.get(0) { + context.name = Arc::new(Mutex::new(name.clone())); + } empty(&mut context, false); @@ -776,7 +778,7 @@ fn exec_noreturn( unsafe { usermode(entry, sp, 0); } } -pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { +pub fn fexec(mut fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result { let mut args = Vec::new(); for arg_ptr in arg_ptrs { let arg = validate_slice(arg_ptr[0] as *const u8, arg_ptr[1])?; @@ -784,17 +786,25 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { args.push(arg.to_vec().into_boxed_slice()); } - let (uid, gid, mut canonical) = { + let mut vars = Vec::new(); + for var_ptr in var_ptrs { + let var = validate_slice(var_ptr[0] as *const u8, var_ptr[1])?; + // Argument must be moved into kernel space before exec unmaps all memory + vars.push(var.to_vec().into_boxed_slice()); + } + + let (uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - (context.euid, context.egid, context.canonicalize(path)) + (context.euid, context.egid) }; let mut stat: Stat; let mut data: Vec; - loop { - let file = ExecFile(syscall::open(&canonical, syscall::flag::O_RDONLY)?); + //loop + { + let file = ExecFile(fd); stat = Stat::default(); syscall::file_op_mut_slice(syscall::number::SYS_FSTAT, file.0, &mut stat)?; @@ -819,34 +829,37 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { syscall::file_op_mut_slice(syscall::number::SYS_READ, file.0, &mut data)?; drop(file); - if data.starts_with(b"#!") { - if let Some(line) = data[2..].split(|&b| b == b'\n').next() { - // Strip whitespace - let line = &line[line.iter().position(|&b| b != b' ') - .unwrap_or(0)..]; - let executable = line.split(|x| *x == b' ').next().unwrap_or(b""); - let mut parts = line.split(|x| *x == b' ') - .map(|x| x.iter().cloned().collect::>().into_boxed_slice()) - .collect::>(); - if ! args.is_empty() { - args.remove(0); - } - parts.push(path.to_vec().into_boxed_slice()); - parts.extend(args.iter().cloned()); - args = parts; - canonical = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.canonicalize(executable) - }; - } else { - println!("invalid script {}", unsafe { str::from_utf8_unchecked(path) }); - return Err(Error::new(ENOEXEC)); - } - } else { - break; - } + // TODO: Move to userspace + // if data.starts_with(b"#!") { + // if let Some(line) = data[2..].split(|&b| b == b'\n').next() { + // // Strip whitespace + // let line = &line[line.iter().position(|&b| b != b' ') + // .unwrap_or(0)..]; + // let executable = line.split(|x| *x == b' ').next().unwrap_or(b""); + // let mut parts = line.split(|x| *x == b' ') + // .map(|x| x.iter().cloned().collect::>().into_boxed_slice()) + // .collect::>(); + // if ! args.is_empty() { + // args.remove(0); + // } + // parts.push(path.to_vec().into_boxed_slice()); + // parts.extend(args.iter().cloned()); + // args = parts; + // let canonical = { + // let contexts = context::contexts(); + // let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + // let context = context_lock.read(); + // context.canonicalize(executable) + // }; + // + // fd = syscall::open(&canonical, syscall::flag::O_RDONLY)?; + // } else { + // println!("invalid script {}", unsafe { str::from_utf8_unchecked(path) }); + // return Err(Error::new(ENOEXEC)); + // } + // } else { + // break; + // } } // Set UID and GID are determined after resolving any hashbangs @@ -871,7 +884,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { // argument pointer array and potential padding // // A limit of 4095 would mean a stack of (4095 + 1) * 8 * 2 = 65536, or 64KB - if args.len() > 4095 { + if (args.len() + vars.len()) > 4095 { return Err(Error::new(E2BIG)); } @@ -894,19 +907,19 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { } }, Err(err) => { - println!("exec: failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err); + println!("fexec: failed to execute {}: {}", fd.into(), err); return Err(Error::new(ENOEXEC)); } } // Drop so that usage is not allowed after unmapping context - drop(path); drop(arg_ptrs); + drop(var_ptrs); // This is the point of no return, quite literaly. Any checks for validity need // to be done before, and appropriate errors returned. Otherwise, we have nothing // to return to. - exec_noreturn(canonical.into_boxed_slice(), setuid, setgid, data.into_boxed_slice(), args.into_boxed_slice()); + exec_noreturn(setuid, setgid, data.into_boxed_slice(), args.into_boxed_slice(), vars.into_boxed_slice()); } pub fn exit(status: usize) -> ! { diff --git a/syscall b/syscall index 0ab552d..66e34ae 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 0ab552da9a9587b360b5d9991ed9921300e5667b +Subproject commit 66e34aea2ee48e55a023861595064df26f8573b9 From fe90664e33f7077bc8c47d7a267fe14547bba105 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Aug 2018 11:18:45 -0600 Subject: [PATCH 03/14] Copy variables to USER_ARG_OFFSET --- src/syscall/process.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 8b012aa..4e709fb 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -688,9 +688,9 @@ fn exec_noreturn( context.tls = Some(tls); } - // Push arguments + // Push arguments and variables let mut arg_size = 0; - for arg in args.iter().rev() { + for arg in vars.iter().rev().chain(args.iter().rev()) { sp -= mem::size_of::(); unsafe { *(sp as *mut usize) = ::USER_ARG_OFFSET + arg_size; } @@ -709,7 +709,7 @@ fn exec_noreturn( ); let mut arg_offset = 0; - for arg in args.iter().rev() { + for arg in vars.iter().rev().chain(args.iter().rev()) { unsafe { intrinsics::copy(arg.as_ptr(), (::USER_ARG_OFFSET + arg_offset) as *mut u8, From 30e68f917ee4db1fa20688e2df3176daf3457f57 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Aug 2018 11:34:32 -0600 Subject: [PATCH 04/14] Remove env scheme and env field on context, fix all warnings --- src/arch/x86_64/paging/mod.rs | 4 +- src/context/context.rs | 5 +- src/context/list.rs | 2 +- src/context/mod.rs | 4 +- src/elf.rs | 2 - src/event.rs | 4 - src/lib.rs | 35 +++-- src/scheme/env.rs | 237 ---------------------------------- src/scheme/event.rs | 21 --- src/scheme/mod.rs | 5 - src/syscall/debug.rs | 5 - src/syscall/fs.rs | 5 - src/syscall/mod.rs | 1 - src/syscall/process.rs | 25 +--- 14 files changed, 29 insertions(+), 326 deletions(-) delete mode 100644 src/scheme/env.rs diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index b2fb446..395be8a 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -126,7 +126,7 @@ pub unsafe fn init(cpu_id: usize, kernel_start: usize, kernel_end: usize, stack_ let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); let result = mapper.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::GLOBAL | EntryFlags::NO_EXECUTE | EntryFlags::WRITABLE); // The flush can be ignored as this is not the active table. See later active_table.switch - unsafe { result.ignore(); } + /* unsafe */ { result.ignore(); } } } @@ -168,7 +168,7 @@ pub unsafe fn init(cpu_id: usize, kernel_start: usize, kernel_end: usize, stack_ let page = Page::containing_address(VirtualAddress::new(virt_addr)); let result = mapper.map_to(page, frame, flags); // The flush can be ignored as this is not the active table. See later active_table.switch - unsafe { result.ignore(); } + /* unsafe */ { result.ignore(); } } } diff --git a/src/context/context.rs b/src/context/context.rs index adf5345..0e4c87c 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -1,6 +1,6 @@ use alloc::arc::Arc; use alloc::boxed::Box; -use alloc::{BTreeMap, Vec, VecDeque}; +use alloc::{Vec, VecDeque}; use core::cmp::Ordering; use core::mem; use spin::Mutex; @@ -150,8 +150,6 @@ pub struct Context { pub name: Arc>>, /// The current working directory pub cwd: Arc>>, - /// The process environment - pub env: Arc, Arc>>>>>, /// The open files in the scheme pub files: Arc>>>, /// Singal actions @@ -191,7 +189,6 @@ impl Context { grants: Arc::new(Mutex::new(Vec::new())), name: Arc::new(Mutex::new(Vec::new().into_boxed_slice())), cwd: Arc::new(Mutex::new(Vec::new())), - env: Arc::new(Mutex::new(BTreeMap::new())), files: Arc::new(Mutex::new(Vec::new())), actions: Arc::new(Mutex::new(vec![( SigAction { diff --git a/src/context/list.rs b/src/context/list.rs index bbc8e28..d55ee95 100644 --- a/src/context/list.rs +++ b/src/context/list.rs @@ -1,7 +1,7 @@ use alloc::arc::Arc; use alloc::boxed::Box; use alloc::BTreeMap; -use core::alloc::{Alloc, GlobalAlloc, Layout}; +use core::alloc::{GlobalAlloc, Layout}; use core::mem; use core::sync::atomic::Ordering; use paging; diff --git a/src/context/mod.rs b/src/context/mod.rs index c1e0d19..931ac17 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -1,8 +1,8 @@ //! # Context management -//! +//! //! For resources on contexts, please consult [wikipedia](https://en.wikipedia.org/wiki/Context_switch) and [osdev](https://wiki.osdev.org/Context_Switching) use alloc::boxed::Box; -use core::alloc::{Alloc, GlobalAlloc, Layout}; +use core::alloc::{GlobalAlloc, Layout}; use core::sync::atomic::Ordering; use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; diff --git a/src/elf.rs b/src/elf.rs index 966ba55..eddd841 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -61,7 +61,6 @@ impl<'a> Elf<'a> { if let Some(symtab) = symtab_opt { Some(ElfSymbols { data: self.data, - header: self.header, symtab: symtab, i: 0 }) @@ -128,7 +127,6 @@ impl<'a> Iterator for ElfSegments<'a> { pub struct ElfSymbols<'a> { data: &'a [u8], - header: &'a header::Header, symtab: &'a section_header::SectionHeader, i: usize } diff --git a/src/event.rs b/src/event.rs index cbf7c78..06d7cb2 100644 --- a/src/event.rs +++ b/src/event.rs @@ -24,10 +24,6 @@ impl EventQueue { } } - pub fn dup(&self, other: &EventQueue) { - panic!("EventQeuue::dup"); - } - pub fn read(&self, events: &mut [Event]) -> Result { Ok(self.queue.receive_into(events, true)) } diff --git a/src/lib.rs b/src/lib.rs index f0ce729..1083532 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,6 @@ #![feature(const_max_value)] #![feature(const_size_of)] #![feature(core_intrinsics)] -#![feature(global_allocator)] #![feature(integer_atomics)] #![feature(lang_items)] #![feature(naked_functions)] @@ -46,9 +45,8 @@ extern crate spin; #[cfg(feature = "slab")] extern crate slab_allocator; -use alloc::arc::Arc; +use alloc::vec::Vec; use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use spin::Mutex; use scheme::{FileHandle, SchemeNamespace}; @@ -134,9 +132,13 @@ pub fn cpu_count() -> usize { CPU_COUNT.load(Ordering::Relaxed) } +static mut INIT_ENV: &[u8] = &[]; + /// Initialize userspace by running the initfs:bin/init process /// This function will also set the CWD to initfs:bin and open debug: as stdio pub extern fn userspace_init() { + let env = unsafe { INIT_ENV }; + assert_eq!(syscall::chdir(b"initfs:"), Ok(0)); assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0)); @@ -144,13 +146,22 @@ pub extern fn userspace_init() { assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2)); let fd = syscall::open(b"/bin/init", syscall::flag::O_RDONLY).expect("failed to open init"); - syscall::fexec(fd, &[], &[]).expect("failed to execute init"); + + let mut env_ptrs = Vec::new(); + for line in env.split(|b| *b == b'\n') { + env_ptrs.push([ + line.as_ptr() as usize, + line.len(), + ]); + } + + syscall::fexec(fd, &[], &env_ptrs).expect("failed to execute init"); panic!("init returned"); } /// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this -pub fn kmain(cpus: usize, env: &[u8]) -> ! { +pub fn kmain(cpus: usize, env: &'static [u8]) -> ! { CPU_ID.store(0, Ordering::SeqCst); CPU_COUNT.store(cpus, Ordering::SeqCst); @@ -161,25 +172,13 @@ pub fn kmain(cpus: usize, env: &[u8]) -> ! { println!("BSP: {:?} {}", pid, cpus); println!("Env: {:?}", ::core::str::from_utf8(env)); + unsafe { INIT_ENV = env }; match context::contexts_mut().spawn(userspace_init) { Ok(context_lock) => { let mut context = context_lock.write(); context.rns = SchemeNamespace::from(1); context.ens = SchemeNamespace::from(1); context.status = context::Status::Runnable; - - let mut context_env = context.env.lock(); - for line in env.split(|b| *b == b'\n') { - let mut parts = line.splitn(2, |b| *b == b'='); - if let Some(name) = parts.next() { - if let Some(data) = parts.next() { - context_env.insert( - name.to_vec().into_boxed_slice(), - Arc::new(Mutex::new(data.to_vec())) - ); - } - } - } }, Err(err) => { panic!("failed to spawn userspace_init: {:?}", err); diff --git a/src/scheme/env.rs b/src/scheme/env.rs deleted file mode 100644 index 3c359dd..0000000 --- a/src/scheme/env.rs +++ /dev/null @@ -1,237 +0,0 @@ -use alloc::arc::Arc; -use alloc::{BTreeMap, Vec}; -use core::{cmp, str}; -use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::{Mutex, RwLock}; - -use context; -use syscall::data::Stat; -use syscall::error::*; -use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END, O_CREAT}; -use syscall::scheme::Scheme; - -#[derive(Clone)] -struct Handle { - data: Arc>>, - mode: u16, - seek: usize -} - -pub struct EnvScheme { - next_id: AtomicUsize, - handles: RwLock> -} - -impl EnvScheme { - pub fn new() -> EnvScheme { - EnvScheme { - next_id: AtomicUsize::new(0), - handles: RwLock::new(BTreeMap::new()) - } - } -} - -impl Scheme for EnvScheme { - fn open(&self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { - let path = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); - - let env_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.env.clone() - }; - - if path.is_empty() { - let mut list = Vec::new(); - { - let env = env_lock.lock(); - for entry in env.iter() { - if ! list.is_empty() { - list.push(b'\n'); - } - list.extend_from_slice(&entry.0); - list.push(b'='); - list.extend_from_slice(&entry.1.lock()); - } - } - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - data: Arc::new(Mutex::new(list)), - mode: MODE_FILE, - seek: 0 - }); - - Ok(id) - } else { - let data = { - let mut env = env_lock.lock(); - if env.contains_key(path.as_bytes()) { - env[path.as_bytes()].clone() - } else if flags & O_CREAT == O_CREAT { - let name = path.as_bytes().to_vec().into_boxed_slice(); - let data = Arc::new(Mutex::new(Vec::new())); - env.insert(name, data.clone()); - data - } else { - return Err(Error::new(ENOENT)); - } - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - data: data, - mode: MODE_FILE, - seek: 0 - }); - - Ok(id) - } - } - - fn dup(&self, id: usize, buf: &[u8]) -> Result { - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let new_handle = { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, new_handle); - - Ok(id) - } - - fn read(&self, id: usize, buffer: &mut [u8]) -> Result { - let mut handles = self.handles.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let data = handle.data.lock(); - - let mut i = 0; - while i < buffer.len() && handle.seek < data.len() { - buffer[i] = data[handle.seek]; - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn write(&self, id: usize, buffer: &[u8]) -> Result { - let mut handles = self.handles.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut data = handle.data.lock(); - - let mut i = 0; - while i < buffer.len() && handle.seek < data.len() { - data[handle.seek] = buffer[i]; - i += 1; - handle.seek += 1; - } - - while i < buffer.len() { - data.push(buffer[i]); - i += 1; - handle.seek += 1; - } - - Ok(i) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let len = handle.data.lock().len(); - handle.seek = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.seek as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(handle.seek) - } - - fn fcntl(&self, id: usize, _cmd: usize, _arg: usize) -> Result { - let handles = self.handles.read(); - let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles = self.handles.read(); - let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - //TODO: Get env name - let scheme_path = b"env:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(i) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_mode = handle.mode; - stat.st_size = handle.data.lock().len() as u64; - - Ok(0) - } - - fn fsync(&self, id: usize) -> Result { - let handles = self.handles.read(); - let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn ftruncate(&self, id: usize, len: usize) -> Result { - let handles = self.handles.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut data = handle.data.lock(); - if len < data.len() { - data.truncate(len) - } else { - while len > data.len() { - data.push(0); - } - } - - Ok(0) - } - - fn close(&self, id: usize) -> Result { - self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } - - fn unlink(&self, path: &[u8], _uid: u32, _gid: u32) -> Result { - let env_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.env.clone() - }; - - let mut env = env_lock.lock(); - - if let Some(_) = env.remove(path) { - Ok(0) - } else { - Err(Error::new(ENOENT)) - } - } -} diff --git a/src/scheme/event.rs b/src/scheme/event.rs index 6efee8b..85b81eb 100644 --- a/src/scheme/event.rs +++ b/src/scheme/event.rs @@ -16,27 +16,6 @@ impl Scheme for EventScheme { Ok(id.into()) } - fn dup(&self, id: usize, buf: &[u8]) -> Result { - let id = EventQueueId::from(id); - - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let old_queue = { - let handles = queues(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let new_id = next_queue_id(); - let new_queue = Arc::new(EventQueue::new(new_id)); - queues_mut().insert(new_id, new_queue.clone()); - new_queue.dup(&old_queue); - - Ok(new_id.into()) - } - fn read(&self, id: usize, buf: &mut [u8]) -> Result { let id = EventQueueId::from(id); diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index d54d655..8f22b98 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -17,7 +17,6 @@ use syscall::scheme::Scheme; use self::debug::DebugScheme; use self::event::EventScheme; -use self::env::EnvScheme; use self::initfs::InitFsScheme; use self::irq::IrqScheme; use self::memory::MemoryScheme; @@ -32,9 +31,6 @@ pub mod debug; /// `event:` - allows reading of `Event`s which are registered using `fevent` pub mod event; -/// `env:` - access and modify environmental variables -pub mod env; - /// `initfs:` - a readonly filesystem used for initializing the system pub mod initfs; @@ -119,7 +115,6 @@ impl SchemeList { self.insert(ns, Box::new(*b""), |scheme_id| Arc::new(Box::new(RootScheme::new(ns, scheme_id)))).unwrap(); self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme))).unwrap(); - self.insert(ns, Box::new(*b"env"), |_| Arc::new(Box::new(EnvScheme::new()))).unwrap(); self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap(); self.insert(ns, Box::new(*b"sys"), |_| Arc::new(Box::new(SysScheme::new()))).unwrap(); self.insert(ns, Box::new(*b"time"), |scheme_id| Arc::new(Box::new(TimeScheme::new(scheme_id)))).unwrap(); diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index d126f2e..d5ad809 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -129,11 +129,6 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - c, d ), - SYS_FEVENT => format!( - "fevent({}, {:#X})", - b, - c - ), SYS_FMAP => format!( "fmap({}, {:#X}, {})", b, diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index cf2e7e7..6629133 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -371,11 +371,6 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result { } } -/// Register events for file -pub fn fevent(fd: FileHandle, flags: usize) -> Result { - Err(Error::new(ENOSYS)) -} - pub fn frename(fd: FileHandle, path: &[u8]) -> Result { let file = { let contexts = context::contexts(); diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index 6ebcbac..37a1a10 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -63,7 +63,6 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into), SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into), SYS_FCNTL => fcntl(fd, c, d), - SYS_FEVENT => fevent(fd, c), SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?), SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?), SYS_FUNMAP => funmap(b), diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 4e709fb..3fe5df7 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -1,7 +1,7 @@ use alloc::arc::Arc; use alloc::boxed::Box; -use alloc::{BTreeMap, Vec}; -use core::alloc::{Alloc, GlobalAlloc, Layout}; +use alloc::vec::Vec; +use core::alloc::{GlobalAlloc, Layout}; use core::{intrinsics, mem}; use core::ops::DerefMut; use spin::Mutex; @@ -86,7 +86,6 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { let grants; let name; let cwd; - let env; let files; let actions; @@ -265,16 +264,6 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { cwd = Arc::new(Mutex::new(context.cwd.lock().clone())); } - if flags & CLONE_VM == CLONE_VM { - env = Arc::clone(&context.env); - } else { - let mut new_env = BTreeMap::new(); - for item in context.env.lock().iter() { - new_env.insert(item.0.clone(), Arc::new(Mutex::new(item.1.lock().clone()))); - } - env = Arc::new(Mutex::new(new_env)); - } - if flags & CLONE_FILES == CLONE_FILES { files = Arc::clone(&context.files); } else { @@ -482,8 +471,6 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { context.cwd = cwd; - context.env = env; - context.files = files; context.actions = actions; @@ -748,7 +735,7 @@ fn exec_noreturn( (vfork, context.ppid, files) }; - for (fd, file_option) in files.lock().iter_mut().enumerate() { + for (_fd, file_option) in files.lock().iter_mut().enumerate() { let mut cloexec = false; if let Some(ref file) = *file_option { if file.cloexec { @@ -778,7 +765,7 @@ fn exec_noreturn( unsafe { usermode(entry, sp, 0); } } -pub fn fexec(mut fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result { +pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result { let mut args = Vec::new(); for arg_ptr in arg_ptrs { let arg = validate_slice(arg_ptr[0] as *const u8, arg_ptr[1])?; @@ -944,7 +931,7 @@ pub fn exit(status: usize) -> ! { }; // Files must be closed while context is valid so that messages can be passed - for (fd, file_option) in close_files.drain(..).enumerate() { + for (_fd, file_option) in close_files.drain(..).enumerate() { if let Some(file) = file_option { let _ = file.close(); } @@ -1063,7 +1050,7 @@ pub fn kill(pid: ContextId, sig: usize) -> Result { (context.ruid, context.euid, context.pgid) }; - if sig >= 0 && sig < 0x7F { + if sig < 0x7F { let mut found = 0; let mut sent = 0; From 23f4c76ebbd9186f5464a37bb97650e1cc36b774 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Aug 2018 11:51:58 -0600 Subject: [PATCH 05/14] Fixes for launching init --- src/lib.rs | 19 +++++++++--------- src/syscall/process.rs | 44 ++++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1083532..6e7bfdb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,6 +137,7 @@ static mut INIT_ENV: &[u8] = &[]; /// Initialize userspace by running the initfs:bin/init process /// This function will also set the CWD to initfs:bin and open debug: as stdio pub extern fn userspace_init() { + let path = b"/bin/init"; let env = unsafe { INIT_ENV }; assert_eq!(syscall::chdir(b"initfs:"), Ok(0)); @@ -145,17 +146,17 @@ pub extern fn userspace_init() { assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1)); assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2)); - let fd = syscall::open(b"/bin/init", syscall::flag::O_RDONLY).expect("failed to open init"); + let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init"); - let mut env_ptrs = Vec::new(); - for line in env.split(|b| *b == b'\n') { - env_ptrs.push([ - line.as_ptr() as usize, - line.len(), - ]); + let mut args = Vec::new(); + args.push(path.to_vec().into_boxed_slice()); + + let mut vars = Vec::new(); + for var in env.split(|b| *b == b'\n') { + vars.push(var.to_vec().into_boxed_slice()); } - syscall::fexec(fd, &[], &env_ptrs).expect("failed to execute init"); + syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice()).expect("failed to execute init"); panic!("init returned"); } @@ -164,6 +165,7 @@ pub extern fn userspace_init() { pub fn kmain(cpus: usize, env: &'static [u8]) -> ! { CPU_ID.store(0, Ordering::SeqCst); CPU_COUNT.store(cpus, Ordering::SeqCst); + unsafe { INIT_ENV = env }; //Initialize the first context, stored in kernel/src/context/mod.rs context::init(); @@ -172,7 +174,6 @@ pub fn kmain(cpus: usize, env: &'static [u8]) -> ! { println!("BSP: {:?} {}", pid, cpus); println!("Env: {:?}", ::core::str::from_utf8(env)); - unsafe { INIT_ENV = env }; match context::contexts_mut().spawn(userspace_init) { Ok(context_lock) => { let mut context = context_lock.write(); diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 3fe5df7..0f8878f 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -527,7 +527,7 @@ impl Drop for ExecFile { } } -fn exec_noreturn( +fn fexec_noreturn( setuid: Option, setgid: Option, data: Box<[u8]>, @@ -765,21 +765,7 @@ fn exec_noreturn( unsafe { usermode(entry, sp, 0); } } -pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result { - let mut args = Vec::new(); - for arg_ptr in arg_ptrs { - let arg = validate_slice(arg_ptr[0] as *const u8, arg_ptr[1])?; - // Argument must be moved into kernel space before exec unmaps all memory - args.push(arg.to_vec().into_boxed_slice()); - } - - let mut vars = Vec::new(); - for var_ptr in var_ptrs { - let var = validate_slice(var_ptr[0] as *const u8, var_ptr[1])?; - // Argument must be moved into kernel space before exec unmaps all memory - vars.push(var.to_vec().into_boxed_slice()); - } - +pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>) -> Result { let (uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; @@ -899,14 +885,30 @@ pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) - } } - // Drop so that usage is not allowed after unmapping context - drop(arg_ptrs); - drop(var_ptrs); - // This is the point of no return, quite literaly. Any checks for validity need // to be done before, and appropriate errors returned. Otherwise, we have nothing // to return to. - exec_noreturn(setuid, setgid, data.into_boxed_slice(), args.into_boxed_slice(), vars.into_boxed_slice()); + fexec_noreturn(setuid, setgid, data.into_boxed_slice(), args, vars); +} + +pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result { + let mut args = Vec::new(); + for arg_ptr in arg_ptrs { + let arg = validate_slice(arg_ptr[0] as *const u8, arg_ptr[1])?; + // Argument must be moved into kernel space before exec unmaps all memory + args.push(arg.to_vec().into_boxed_slice()); + } + drop(arg_ptrs); + + let mut vars = Vec::new(); + for var_ptr in var_ptrs { + let var = validate_slice(var_ptr[0] as *const u8, var_ptr[1])?; + // Argument must be moved into kernel space before exec unmaps all memory + vars.push(var.to_vec().into_boxed_slice()); + } + drop(var_ptrs); + + fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice()) } pub fn exit(status: usize) -> ! { From 69766ce3b938417a0f182ce6e3314f79e5946151 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Aug 2018 16:47:48 -0600 Subject: [PATCH 06/14] Update syscall --- syscall | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syscall b/syscall index 66e34ae..739aef4 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 66e34aea2ee48e55a023861595064df26f8573b9 +Subproject commit 739aef47b8e6b300874945c3c33bb9550414b5b8 From 1718d28d393d9aa289dcd54a401656d32ab6b7de Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 12 Aug 2018 08:30:12 -0600 Subject: [PATCH 07/14] Push null pointer to indicate end of environment --- src/syscall/process.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 0f8878f..32af87a 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -675,6 +675,10 @@ fn fexec_noreturn( context.tls = Some(tls); } + // Push end of variables + sp -= mem::size_of::(); + unsafe { *(sp as *mut usize) = 0; } + // Push arguments and variables let mut arg_size = 0; for arg in vars.iter().rev().chain(args.iter().rev()) { @@ -684,6 +688,7 @@ fn fexec_noreturn( arg_size += arg.len() + 1; } + // Push arguments length sp -= mem::size_of::(); unsafe { *(sp as *mut usize) = args.len(); } From 1d817fa41dd931263dcfc97a4edc1246743b5dd5 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 13 Aug 2018 11:45:13 +0200 Subject: [PATCH 08/14] Push null after argv --- src/syscall/process.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 32af87a..5596e8f 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -675,17 +675,21 @@ fn fexec_noreturn( context.tls = Some(tls); } - // Push end of variables - sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = 0; } + let mut arg_size = 0; // Push arguments and variables - let mut arg_size = 0; - for arg in vars.iter().rev().chain(args.iter().rev()) { + for iter in &[&vars, &args] { + // Push null-terminator sp -= mem::size_of::(); - unsafe { *(sp as *mut usize) = ::USER_ARG_OFFSET + arg_size; } + unsafe { *(sp as *mut usize) = 0; } - arg_size += arg.len() + 1; + // Push content + for arg in iter.iter().rev() { + sp -= mem::size_of::(); + unsafe { *(sp as *mut usize) = ::USER_ARG_OFFSET + arg_size; } + + arg_size += arg.len() + 1; + } } // Push arguments length From 7a978678681bf06c49eaa2181918e321e7ed6832 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Sep 2018 10:40:55 -0600 Subject: [PATCH 09/14] Make multi-core support the default Make IPIs less architecture specific --- Cargo.toml | 2 +- src/arch/x86_64/idt.rs | 7 ++++--- src/arch/x86_64/interrupt/ipi.rs | 6 +++++- src/arch/x86_64/interrupt/irq.rs | 7 +++---- src/arch/x86_64/ipi.rs | 28 ++++++++++++++++++++++++++++ src/arch/x86_64/mod.rs | 3 +++ src/arch/x86_64/paging/mod.rs | 1 + src/context/context.rs | 17 ++++++++--------- 8 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 src/arch/x86_64/ipi.rs diff --git a/Cargo.toml b/Cargo.toml index 03debdd..3f5878e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ version = "0.9.0" default-features = false [features] -default = [] +default = ["acpi", "multi_core"] acpi = [] doc = [] graphical_debug = [] diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index 1317ba6..1a04789 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -68,9 +68,10 @@ pub unsafe fn init_paging() { IDT[46].set_func(irq::ata1); IDT[47].set_func(irq::ata2); - // Set IPI handler (null) - IDT[0x40].set_func(ipi::ipi); - IDT[0x41].set_func(ipi::pit); + // Set IPI handlers + IDT[0x40].set_func(ipi::wakeup); + IDT[0x41].set_func(ipi::tlb); + IDT[0x42].set_func(ipi::pit); // Set syscall function IDT[0x80].set_func(syscall::syscall); diff --git a/src/arch/x86_64/interrupt/ipi.rs b/src/arch/x86_64/interrupt/ipi.rs index 2f7177c..a0ad189 100644 --- a/src/arch/x86_64/interrupt/ipi.rs +++ b/src/arch/x86_64/interrupt/ipi.rs @@ -4,7 +4,7 @@ use context; use device::local_apic::LOCAL_APIC; use super::irq::PIT_TICKS; -interrupt!(ipi, { +interrupt!(wakeup, { LOCAL_APIC.eoi(); }); @@ -15,3 +15,7 @@ interrupt!(pit, { let _ = context::switch(); } }); + +interrupt!(tlb, { + LOCAL_APIC.eoi(); +}); diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index 4031ed1..19a47c3 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -2,8 +2,9 @@ use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use context; use context::timeout; -use device::{local_apic, pic}; +use device::pic; use device::serial::{COM1, COM2}; +use ipi::{ipi, IpiKind, IpiTarget}; use time; //resets to 0 in context::switch() @@ -40,9 +41,7 @@ pub unsafe fn acknowledge(irq: usize) { interrupt!(pit, { // Wake up other CPUs - if cfg!(feature = "multi_core") { - local_apic::LOCAL_APIC.set_icr(3 << 18 | 1 << 14 | 0x41); - } + ipi(IpiKind::Pit, IpiTarget::Other); // Saves CPU time by not sending IRQ event irq_trigger(0); diff --git a/src/arch/x86_64/ipi.rs b/src/arch/x86_64/ipi.rs new file mode 100644 index 0000000..021fc82 --- /dev/null +++ b/src/arch/x86_64/ipi.rs @@ -0,0 +1,28 @@ +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum IpiKind { + Wakeup = 0x40, + Tlb = 0x41, + Pit = 0x42, +} + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum IpiTarget { + Current = 1, + All = 2, + Other = 3, +} + +#[cfg(not(feature = "multi_core"))] +#[inline(always)] +pub fn ipi(_kind: IpiKind, _target: IpiTarget) {} + +#[cfg(feature = "multi_core")] +#[inline(always)] +pub fn ipi(kind: IpiKind, target: IpiTarget) { + use device::local_apic::LOCAL_APIC; + + let icr = (target as u64) << 18 | 1 << 14 | (kind as u64); + unsafe { LOCAL_APIC.set_icr(icr) }; +} diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index b7857d2..715bcad 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -20,6 +20,9 @@ pub mod idt; /// Interrupt instructions pub mod interrupt; +/// Inter-processor interrupts +pub mod ipi; + /// Paging pub mod paging; diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index 395be8a..4f60fa8 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -5,6 +5,7 @@ use core::{mem, ptr}; use core::ops::{Deref, DerefMut}; use x86::shared::{control_regs, msr, tlb}; +use ipi::{ipi, IpiKind, IpiTarget}; use memory::{allocate_frames, Frame}; use self::entry::EntryFlags; diff --git a/src/context/context.rs b/src/context/context.rs index 0e4c87c..cc8037a 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -8,7 +8,7 @@ use spin::Mutex; use context::arch; use context::file::FileDescriptor; use context::memory::{Grant, Memory, SharedMemory, Tls}; -use device; +use ipi::{ipi, IpiKind, IpiTarget}; use scheme::{SchemeNamespace, FileHandle}; use syscall::data::SigAction; use syscall::flag::SIG_DFL; @@ -284,15 +284,14 @@ impl Context { pub fn unblock(&mut self) -> bool { if self.status == Status::Blocked { self.status = Status::Runnable; - if cfg!(feature = "multi_core") { - if let Some(cpu_id) = self.cpu_id { - if cpu_id != ::cpu_id() { - // Send IPI if not on current CPU - // TODO: Make this more architecture independent - unsafe { device::local_apic::LOCAL_APIC.set_icr(3 << 18 | 1 << 14 | 0x40) }; - } - } + + if let Some(cpu_id) = self.cpu_id { + if cpu_id != ::cpu_id() { + // Send IPI if not on current CPU + ipi(IpiKind::Wakeup, IpiTarget::Other); + } } + true } else { false From 0d510a4f744817303cd7043b1cf250796880a1f1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Sep 2018 11:44:34 -0600 Subject: [PATCH 10/14] Remove multi-core and acpi again --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3f5878e..03debdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ version = "0.9.0" default-features = false [features] -default = ["acpi", "multi_core"] +default = [] acpi = [] doc = [] graphical_debug = [] From e867326df10d9108036539f1b6ef08f6ffdef375 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 25 Sep 2018 18:01:38 -0600 Subject: [PATCH 11/14] Attempt to schedule other processors more often by waking them up with a context switch when a process is created --- src/arch/x86_64/idt.rs | 8 +++++--- src/arch/x86_64/interrupt/ipi.rs | 15 +++++++++++---- src/arch/x86_64/ipi.rs | 3 ++- src/syscall/process.rs | 4 ++++ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index 1a04789..d60fe5c 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -3,6 +3,7 @@ use x86::current::irq::IdtEntry as X86IdtEntry; use x86::shared::dtables::{self, DescriptorTablePointer}; use interrupt::*; +use ipi::IpiKind; pub static mut INIT_IDTR: DescriptorTablePointer = DescriptorTablePointer { limit: 0, @@ -69,9 +70,10 @@ pub unsafe fn init_paging() { IDT[47].set_func(irq::ata2); // Set IPI handlers - IDT[0x40].set_func(ipi::wakeup); - IDT[0x41].set_func(ipi::tlb); - IDT[0x42].set_func(ipi::pit); + IDT[IpiKind::Wakeup as usize].set_func(ipi::wakeup); + IDT[IpiKind::Switch as usize].set_func(ipi::switch); + IDT[IpiKind::Tlb as usize].set_func(ipi::tlb); + IDT[IpiKind::Pit as usize].set_func(ipi::pit); // Set syscall function IDT[0x80].set_func(syscall::syscall); diff --git a/src/arch/x86_64/interrupt/ipi.rs b/src/arch/x86_64/interrupt/ipi.rs index a0ad189..bc370e9 100644 --- a/src/arch/x86_64/interrupt/ipi.rs +++ b/src/arch/x86_64/interrupt/ipi.rs @@ -8,6 +8,17 @@ interrupt!(wakeup, { LOCAL_APIC.eoi(); }); +interrupt!(tlb, { + LOCAL_APIC.eoi(); + //TODO +}); + +interrupt!(switch, { + LOCAL_APIC.eoi(); + + let _ = context::switch(); +}); + interrupt!(pit, { LOCAL_APIC.eoi(); @@ -15,7 +26,3 @@ interrupt!(pit, { let _ = context::switch(); } }); - -interrupt!(tlb, { - LOCAL_APIC.eoi(); -}); diff --git a/src/arch/x86_64/ipi.rs b/src/arch/x86_64/ipi.rs index 021fc82..97996dc 100644 --- a/src/arch/x86_64/ipi.rs +++ b/src/arch/x86_64/ipi.rs @@ -3,7 +3,8 @@ pub enum IpiKind { Wakeup = 0x40, Tlb = 0x41, - Pit = 0x42, + Switch = 0x42, + Pit = 0x43, } #[derive(Clone, Copy, Debug)] diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 5596e8f..813bff3 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -17,6 +17,7 @@ use context::{ContextId, WaitpidKey}; use context::file::FileDescriptor; #[cfg(not(feature="doc"))] use elf::{self, program_header}; +use ipi::{ipi, IpiKind, IpiTarget}; use scheme::FileHandle; use syscall; use syscall::data::{SigAction, Stat}; @@ -477,6 +478,9 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { } } + // Race to pick up the new process! + ipi(IpiKind::Switch, IpiTarget::Other); + let _ = unsafe { context::switch() }; Ok(pid) From f5fcbc12b8c426b5a9794cc75ba6770cfbc4f735 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 25 Sep 2018 18:05:10 -0600 Subject: [PATCH 12/14] Move ipi for pit to after EOI --- src/arch/x86_64/interrupt/irq.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index 19a47c3..17adbd0 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -40,9 +40,6 @@ pub unsafe fn acknowledge(irq: usize) { } interrupt!(pit, { - // Wake up other CPUs - ipi(IpiKind::Pit, IpiTarget::Other); - // Saves CPU time by not sending IRQ event irq_trigger(0); const PIT_RATE: u64 = 2_250_286; @@ -56,6 +53,9 @@ interrupt!(pit, { pic::MASTER.ack(); + // Wake up other CPUs + ipi(IpiKind::Pit, IpiTarget::Other); + // Any better way of doing this? timeout::trigger(); From b08fa102777849e0c97b0292815bf12f58f0ceaa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 25 Sep 2018 20:57:59 -0600 Subject: [PATCH 13/14] Implement tlb IPI --- src/arch/x86_64/interrupt/ipi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/arch/x86_64/interrupt/ipi.rs b/src/arch/x86_64/interrupt/ipi.rs index bc370e9..a8e3d11 100644 --- a/src/arch/x86_64/interrupt/ipi.rs +++ b/src/arch/x86_64/interrupt/ipi.rs @@ -1,4 +1,5 @@ use core::sync::atomic::Ordering; +use x86::shared::tlb; use context; use device::local_apic::LOCAL_APIC; @@ -10,7 +11,8 @@ interrupt!(wakeup, { interrupt!(tlb, { LOCAL_APIC.eoi(); - //TODO + + tlb::flush_all(); }); interrupt!(switch, { From 3b1bf1bac1aa21eed53c3465d7b1a470f5922396 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 25 Sep 2018 20:58:24 -0600 Subject: [PATCH 14/14] Call TLB IPI when mapping grants --- src/arch/x86_64/paging/mod.rs | 1 - src/context/memory.rs | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index 4f60fa8..395be8a 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -5,7 +5,6 @@ use core::{mem, ptr}; use core::ops::{Deref, DerefMut}; use x86::shared::{control_regs, msr, tlb}; -use ipi::{ipi, IpiKind, IpiTarget}; use memory::{allocate_frames, Frame}; use self::entry::EntryFlags; diff --git a/src/context/memory.rs b/src/context/memory.rs index f9fe8c0..61c08fc 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -3,6 +3,7 @@ use alloc::VecDeque; use core::intrinsics; use spin::Mutex; +use ipi::{ipi, IpiKind, IpiTarget}; use memory::Frame; use paging::{ActivePageTable, InactivePageTable, Page, PageIter, PhysicalAddress, VirtualAddress}; use paging::entry::EntryFlags; @@ -64,6 +65,8 @@ impl Grant { } }); + ipi(IpiKind::Tlb, IpiTarget::Other); + Grant { start: to, size: size, @@ -118,6 +121,8 @@ impl Grant { } }); + ipi(IpiKind::Tlb, IpiTarget::Other); + self.mapped = false; } }