Merge remote-tracking branch 'origin/relibc'
This commit is contained in:
@@ -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<X86IdtEntry> = DescriptorTablePointer {
|
||||
limit: 0,
|
||||
@@ -68,9 +69,11 @@ 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[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);
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
use core::sync::atomic::Ordering;
|
||||
use x86::shared::tlb;
|
||||
|
||||
use context;
|
||||
use device::local_apic::LOCAL_APIC;
|
||||
use super::irq::PIT_TICKS;
|
||||
|
||||
interrupt!(ipi, {
|
||||
interrupt!(wakeup, {
|
||||
LOCAL_APIC.eoi();
|
||||
});
|
||||
|
||||
interrupt!(tlb, {
|
||||
LOCAL_APIC.eoi();
|
||||
|
||||
tlb::flush_all();
|
||||
});
|
||||
|
||||
interrupt!(switch, {
|
||||
LOCAL_APIC.eoi();
|
||||
|
||||
let _ = context::switch();
|
||||
});
|
||||
|
||||
interrupt!(pit, {
|
||||
LOCAL_APIC.eoi();
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -39,11 +40,6 @@ 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);
|
||||
}
|
||||
|
||||
// Saves CPU time by not sending IRQ event irq_trigger(0);
|
||||
|
||||
const PIT_RATE: u64 = 2_250_286;
|
||||
@@ -57,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();
|
||||
|
||||
|
||||
29
src/arch/x86_64/ipi.rs
Normal file
29
src/arch/x86_64/ipi.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum IpiKind {
|
||||
Wakeup = 0x40,
|
||||
Tlb = 0x41,
|
||||
Switch = 0x42,
|
||||
Pit = 0x43,
|
||||
}
|
||||
|
||||
#[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) };
|
||||
}
|
||||
@@ -20,6 +20,9 @@ pub mod idt;
|
||||
/// Interrupt instructions
|
||||
pub mod interrupt;
|
||||
|
||||
/// Inter-processor interrupts
|
||||
pub mod ipi;
|
||||
|
||||
/// Paging
|
||||
pub mod paging;
|
||||
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -150,8 +150,6 @@ pub struct Context {
|
||||
pub name: Arc<Mutex<Box<[u8]>>>,
|
||||
/// The current working directory
|
||||
pub cwd: Arc<Mutex<Vec<u8>>>,
|
||||
/// The process environment
|
||||
pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
|
||||
/// The open files in the scheme
|
||||
pub files: Arc<Mutex<Vec<Option<FileDescriptor>>>>,
|
||||
/// 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 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};
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -24,10 +24,6 @@ impl EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dup(&self, other: &EventQueue) {
|
||||
panic!("EventQeuue::dup");
|
||||
}
|
||||
|
||||
pub fn read(&self, events: &mut [Event]) -> Result<usize> {
|
||||
Ok(self.queue.receive_into(events, true))
|
||||
}
|
||||
|
||||
36
src/lib.rs
36
src/lib.rs
@@ -45,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};
|
||||
|
||||
@@ -133,24 +132,40 @@ 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 path = b"/bin/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));
|
||||
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(path, syscall::flag::O_RDONLY).expect("failed to open init");
|
||||
|
||||
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_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice()).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);
|
||||
unsafe { INIT_ENV = env };
|
||||
|
||||
//Initialize the first context, stored in kernel/src/context/mod.rs
|
||||
context::init();
|
||||
@@ -165,19 +180,6 @@ pub fn kmain(cpus: usize, env: &[u8]) -> ! {
|
||||
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);
|
||||
|
||||
@@ -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<Mutex<Vec<u8>>>,
|
||||
mode: u16,
|
||||
seek: usize
|
||||
}
|
||||
|
||||
pub struct EnvScheme {
|
||||
next_id: AtomicUsize,
|
||||
handles: RwLock<BTreeMap<usize, Handle>>
|
||||
}
|
||||
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
|
||||
}
|
||||
|
||||
fn unlink(&self, path: &[u8], _uid: u32, _gid: u32) -> Result<usize> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,27 +16,6 @@ impl Scheme for EventScheme {
|
||||
Ok(id.into())
|
||||
}
|
||||
|
||||
fn dup(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||
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<usize> {
|
||||
let id = EventQueueId::from(id);
|
||||
|
||||
|
||||
@@ -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::new()))).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();
|
||||
|
||||
@@ -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,
|
||||
@@ -191,13 +186,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::<Vec<Option<&str>>>()
|
||||
}),
|
||||
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 +213,6 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
|
||||
).collect::<Vec<Option<&str>>>()
|
||||
})
|
||||
),
|
||||
SYS_EXIT => format!(
|
||||
"exit({})",
|
||||
b
|
||||
),
|
||||
SYS_FUTEX => format!(
|
||||
"futex({:#X} [{:?}], {}, {}, {}, {})",
|
||||
b,
|
||||
|
||||
@@ -371,11 +371,6 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Register events for file
|
||||
pub fn fevent(fd: FileHandle, flags: usize) -> Result<usize> {
|
||||
Err(Error::new(ENOSYS))
|
||||
}
|
||||
|
||||
pub fn frename(fd: FileHandle, path: &[u8]) -> Result<usize> {
|
||||
let file = {
|
||||
let contexts = context::contexts();
|
||||
|
||||
@@ -63,7 +63,7 @@ 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),
|
||||
_ => file_op(a, fd, c, d)
|
||||
@@ -98,7 +98,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(),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use alloc::arc::Arc;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::{BTreeMap, Vec};
|
||||
use core::alloc::{Alloc, GlobalAlloc, Layout};
|
||||
use core::{intrinsics, mem, str};
|
||||
use alloc::vec::Vec;
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::{intrinsics, mem};
|
||||
use core::ops::DerefMut;
|
||||
use spin::Mutex;
|
||||
|
||||
@@ -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};
|
||||
@@ -86,7 +87,6 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
let grants;
|
||||
let name;
|
||||
let cwd;
|
||||
let env;
|
||||
let files;
|
||||
let actions;
|
||||
|
||||
@@ -265,16 +265,6 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
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,14 +472,15 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
|
||||
context.cwd = cwd;
|
||||
|
||||
context.env = env;
|
||||
|
||||
context.files = files;
|
||||
|
||||
context.actions = actions;
|
||||
}
|
||||
}
|
||||
|
||||
// Race to pick up the new process!
|
||||
ipi(IpiKind::Switch, IpiTarget::Other);
|
||||
|
||||
let _ = unsafe { context::switch() };
|
||||
|
||||
Ok(pid)
|
||||
@@ -540,12 +531,12 @@ impl Drop for ExecFile {
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_noreturn(
|
||||
canonical: Box<[u8]>,
|
||||
fn fexec_noreturn(
|
||||
setuid: Option<u32>,
|
||||
setgid: Option<u32>,
|
||||
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 +548,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);
|
||||
|
||||
@@ -686,17 +679,24 @@ fn exec_noreturn(
|
||||
context.tls = Some(tls);
|
||||
}
|
||||
|
||||
// Push arguments
|
||||
let mut arg_size = 0;
|
||||
for arg in args.iter().rev() {
|
||||
sp -= mem::size_of::<usize>();
|
||||
unsafe { *(sp as *mut usize) = ::USER_ARG_OFFSET + arg_size; }
|
||||
sp -= mem::size_of::<usize>();
|
||||
unsafe { *(sp as *mut usize) = arg.len(); }
|
||||
|
||||
arg_size += arg.len();
|
||||
// Push arguments and variables
|
||||
for iter in &[&vars, &args] {
|
||||
// Push null-terminator
|
||||
sp -= mem::size_of::<usize>();
|
||||
unsafe { *(sp as *mut usize) = 0; }
|
||||
|
||||
// Push content
|
||||
for arg in iter.iter().rev() {
|
||||
sp -= mem::size_of::<usize>();
|
||||
unsafe { *(sp as *mut usize) = ::USER_ARG_OFFSET + arg_size; }
|
||||
|
||||
arg_size += arg.len() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Push arguments length
|
||||
sp -= mem::size_of::<usize>();
|
||||
unsafe { *(sp as *mut usize) = args.len(); }
|
||||
|
||||
@@ -709,14 +709,18 @@ 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,
|
||||
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);
|
||||
@@ -744,7 +748,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 {
|
||||
@@ -774,25 +778,19 @@ fn exec_noreturn(
|
||||
unsafe { usermode(entry, sp, 0); }
|
||||
}
|
||||
|
||||
pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
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 (uid, gid, mut canonical) = {
|
||||
pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>) -> Result<usize> {
|
||||
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<u8>;
|
||||
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)?;
|
||||
@@ -817,34 +815,37 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
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::<Vec<_>>().into_boxed_slice())
|
||||
.collect::<Vec<_>>();
|
||||
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::<Vec<_>>().into_boxed_slice())
|
||||
// .collect::<Vec<_>>();
|
||||
// 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
|
||||
@@ -869,7 +870,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
// 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));
|
||||
}
|
||||
|
||||
@@ -892,19 +893,35 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
}
|
||||
},
|
||||
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);
|
||||
|
||||
// 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());
|
||||
fexec_noreturn(setuid, setgid, data.into_boxed_slice(), args, vars);
|
||||
}
|
||||
|
||||
pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
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) -> ! {
|
||||
@@ -929,7 +946,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();
|
||||
}
|
||||
@@ -1048,7 +1065,7 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
|
||||
(context.ruid, context.euid, context.pgid)
|
||||
};
|
||||
|
||||
if sig >= 0 && sig < 0x7F {
|
||||
if sig < 0x7F {
|
||||
let mut found = 0;
|
||||
let mut sent = 0;
|
||||
|
||||
|
||||
2
syscall
2
syscall
Submodule syscall updated: 0ab552da9a...85598a1c33
Reference in New Issue
Block a user