Commit 9570de21 authored by Jeremy Soller's avatar Jeremy Soller

Merge remote-tracking branch 'origin/relibc'

parents 22aa5f48 3b1bf1ba
......@@ -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);
......
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();
......
#[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(); }
}
}
......
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![(
SigAction {
......@@ -287,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
......
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;
......
......@@ -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;
}
}
......
//! # 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};
......
......@@ -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))
}
......
......@@ -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);
......
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)?),