* Fire up multiple processors

* Use IPIs to wake up secondary processors

* Much better exception information

* Modifications to show more information on fault

* WIP: Use real libstd

* Add TLS (not complete)

* Add random function, export getpid, cleanup

* Do not spin APs until new context

* Update rust

* Update rust

* Use rd/wrfsbase

* Implement TLS

* Implement compiler builtins and update rust

* Update rust

* Back to Redox libstd

* Update rust
This commit is contained in:
Jeremy Soller 2016-10-31 10:49:00 -06:00 committed by GitHub
parent 25dc44b348
commit 149b0297a4
54 changed files with 1121 additions and 380 deletions

View file

@ -5,7 +5,7 @@ use spin::Mutex;
use arch;
use context::file::File;
use context::memory::{Grant, Memory, SharedMemory};
use context::memory::{Grant, Memory, SharedMemory, Tls};
use syscall::data::Event;
use sync::{WaitCondition, WaitQueue};
@ -36,7 +36,7 @@ pub struct Context {
/// Context running or not
pub running: bool,
/// CPU ID, if locked
pub cpuid: Option<usize>,
pub cpu_id: Option<usize>,
/// Context is halting parent
pub vfork: bool,
/// Context is being waited on
@ -55,6 +55,8 @@ pub struct Context {
pub heap: Option<SharedMemory>,
/// User stack
pub stack: Option<Memory>,
/// User Tls
pub tls: Option<Tls>,
/// User grants
pub grants: Arc<Mutex<Vec<Grant>>>,
/// The name of the context
@ -81,7 +83,7 @@ impl Context {
egid: 0,
status: Status::Blocked,
running: false,
cpuid: None,
cpu_id: None,
vfork: false,
waitpid: Arc::new(WaitCondition::new()),
wake: None,
@ -91,6 +93,7 @@ impl Context {
image: Vec::new(),
heap: None,
stack: None,
tls: None,
grants: Arc::new(Mutex::new(Vec::new())),
name: Arc::new(Mutex::new(Vec::new())),
cwd: Arc::new(Mutex::new(Vec::new())),
@ -153,6 +156,13 @@ impl Context {
pub fn unblock(&mut self) -> bool {
if self.status == Status::Blocked {
self.status = Status::Runnable;
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 { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) };
}
}
true
} else {
false

View file

@ -332,3 +332,10 @@ impl Drop for Memory {
self.unmap(true);
}
}
#[derive(Debug)]
pub struct Tls {
pub master: VirtualAddress,
pub file_size: usize,
pub mem: Memory
}

View file

@ -50,7 +50,7 @@ pub fn init() {
context.kfx = Some(fx);
context.status = Status::Runnable;
context.running = true;
context.cpuid = Some(::cpu_id());
context.cpu_id = Some(::cpu_id());
CONTEXT_ID.store(context.id, Ordering::SeqCst);
}

View file

@ -16,27 +16,34 @@ pub unsafe fn switch() -> bool {
arch::interrupt::pause();
}
let cpu_id = ::cpu_id();
let from_ptr;
let mut to_ptr = 0 as *mut Context;
{
let contexts = contexts();
{
let context_lock = contexts.current().expect("context::switch: Not inside of context");
let context_lock = contexts.current().expect("context::switch: not inside of context");
let mut context = context_lock.write();
from_ptr = context.deref_mut() as *mut Context;
}
let check_context = |context: &mut Context| -> bool {
if context.cpuid == None || context.cpuid == Some(::cpu_id()) {
if context.status == Status::Blocked && context.wake.is_some() {
let wake = context.wake.expect("context::switch: wake not set");
if context.cpu_id == None && cpu_id == 0 {
context.cpu_id = Some(cpu_id);
println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock()));
}
let current = arch::time::monotonic();
if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) {
context.unblock();
}
if context.status == Status::Blocked && context.wake.is_some() {
let wake = context.wake.expect("context::switch: wake not set");
let current = arch::time::monotonic();
if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) {
context.unblock();
}
}
if context.cpu_id == Some(cpu_id) {
if context.status == Status::Runnable && ! context.running {
return true;
}
@ -74,8 +81,6 @@ pub unsafe fn switch() -> bool {
return false;
}
// println!("{}: Switch {} to {}", ::cpu_id(), (&*from_ptr).id, (&*to_ptr).id);
(&mut *from_ptr).running = false;
(&mut *to_ptr).running = true;
if let Some(ref stack) = (*to_ptr).kstack {
@ -83,6 +88,9 @@ pub unsafe fn switch() -> bool {
}
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
// Unset global lock before switch, as arch is only usable by the current CPU at this time
arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
true

View file

@ -152,6 +152,19 @@ pub extern fn userspace_init() {
panic!("initfs:init returned")
}
/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
println!("SIGNAL {}, CPU {}, PID {}", signal, cpu_id(), context::context_id());
{
let contexts = context::contexts();
if let Some(context_lock) = contexts.current() {
let context = context_lock.read();
println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
}
}
}
#[no_mangle]
pub extern fn kmain(cpus: usize) {
CPU_ID.store(0, Ordering::SeqCst);
@ -195,6 +208,14 @@ pub extern fn kmain_ap(id: usize) {
println!("AP {}: {:?}", id, pid);
loop {
unsafe { interrupt::enable_and_halt() }
unsafe {
interrupt::disable();
if context::switch() {
interrupt::enable_and_nop();
} else {
// Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
interrupt::enable_and_halt();
}
}
}
}

View file

@ -5,12 +5,13 @@ use context;
use syscall::error::Result;
pub fn resource() -> Result<Vec<u8>> {
let mut string = format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n",
let mut string = format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n",
"PID",
"PPID",
"UID",
"GID",
"STAT",
"CPU",
"MEM",
"NAME");
{
@ -18,6 +19,35 @@ pub fn resource() -> Result<Vec<u8>> {
for (_id, context_lock) in contexts.iter() {
let context = context_lock.read();
let mut stat_string = String::new();
if context.stack.is_some() {
stat_string.push('U');
} else {
stat_string.push('K');
}
match context.status {
context::Status::Runnable => {
stat_string.push('R');
},
context::Status::Blocked => if context.wake.is_some() {
stat_string.push('S');
} else {
stat_string.push('B');
},
context::Status::Exited(_status) => {
stat_string.push('Z');
}
}
if context.running {
stat_string.push('+');
}
let cpu_string = if let Some(cpu_id) = context.cpu_id {
format!("{}", cpu_id)
} else {
format!("?")
};
let mut memory = 0;
if let Some(ref kfx) = context.kstack {
memory += kfx.len();
@ -49,38 +79,16 @@ pub fn resource() -> Result<Vec<u8>> {
format!("{} B", memory)
};
let mut stat_string = String::new();
if context.stack.is_some() {
stat_string.push('U');
} else {
stat_string.push('K');
}
match context.status {
context::Status::Runnable => {
stat_string.push('R');
},
context::Status::Blocked => if context.wake.is_some() {
stat_string.push('S');
} else {
stat_string.push('B');
},
context::Status::Exited(_status) => {
stat_string.push('Z');
}
}
if context.running {
stat_string.push('+');
}
let name_bytes = context.name.lock();
let name = str::from_utf8(&name_bytes).unwrap_or("");
string.push_str(&format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n",
string.push_str(&format!("{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{}\n",
context.id,
context.ppid,
context.euid,
context.egid,
stat_string,
cpu_string,
memory_string,
name));
}

View file

@ -62,6 +62,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
let rgid;
let euid;
let egid;
let mut cpu_id = None;
let arch;
let vfork;
let mut kfx_option = None;
@ -70,6 +71,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
let mut image = vec![];
let mut heap_option = None;
let mut stack_option = None;
let mut tls_option = None;
let grants;
let name;
let cwd;
@ -88,6 +90,10 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
euid = context.euid;
egid = context.egid;
if flags & CLONE_VM == CLONE_VM {
cpu_id = context.cpu_id;
}
arch = context.arch.clone();
if let Some(ref fx) = context.kfx {
@ -181,6 +187,29 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
stack_option = Some(new_stack);
}
if let Some(ref tls) = context.tls {
let mut new_tls = context::memory::Tls {
master: tls.master,
file_size: tls.file_size,
mem: context::memory::Memory::new(
VirtualAddress::new(arch::USER_TMP_TLS_OFFSET),
tls.mem.size(),
entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE,
true,
false
)
};
unsafe {
arch::externs::memcpy(new_tls.mem.start_address().get() as *mut u8,
tls.master.get() as *const u8,
tls.file_size);
}
new_tls.mem.remap(tls.mem.flags(), true);
tls_option = Some(new_tls);
}
if flags & CLONE_VM == CLONE_VM {
grants = context.grants.clone();
} else {
@ -277,6 +306,8 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
context.euid = euid;
context.egid = egid;
context.cpu_id = cpu_id;
context.status = context::Status::Runnable;
context.vfork = vfork;
@ -393,6 +424,12 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
context.stack = Some(stack);
}
// Setup user TLS
if let Some(mut tls) = tls_option {
tls.mem.move_to(VirtualAddress::new(arch::USER_TLS_OFFSET), &mut new_table, &mut temporary_page, true);
context.tls = Some(tls);
}
context.name = name;
context.cwd = cwd;
@ -411,6 +448,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
let entry;
let mut sp = arch::USER_STACK_OFFSET + arch::USER_STACK_SIZE - 256;
let fs = arch::USER_STACK_OFFSET;
{
let mut args = Vec::new();
@ -466,11 +504,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
// Set name
context.name = Arc::new(Mutex::new(canonical));
// Unmap previous image and stack
// Unmap previous image, heap, grants, stack, and tls
context.image.clear();
drop(context.heap.take());
drop(context.stack.take());
context.grants = Arc::new(Mutex::new(Vec::new()));
drop(context.stack.take());
drop(context.tls.take());
if stat.st_mode & syscall::flag::MODE_SETUID == syscall::flag::MODE_SETUID {
context.euid = stat.st_uid;
@ -481,6 +520,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
}
// Map and copy new segments
let mut tls_option = None;
for segment in elf.segments() {
if segment.p_type == program_header::PT_LOAD {
let mut memory = context::memory::Memory::new(
@ -514,6 +554,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
memory.remap(flags, true);
context.image.push(memory.to_shared());
} else if segment.p_type == program_header::PT_TLS {
tls_option = Some((
VirtualAddress::new(segment.p_vaddr as usize),
segment.p_filesz as usize,
segment.p_memsz as usize
));
}
}
@ -535,6 +581,35 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
true
));
// Map TLS
if let Some((master, file_size, size)) = tls_option {
let tls = context::memory::Tls {
master: master,
file_size: file_size,
mem: context::memory::Memory::new(
VirtualAddress::new(arch::USER_TLS_OFFSET),
size,
entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE,
true,
true
)
};
unsafe {
// Copy file data
memcpy(tls.mem.start_address().get() as *mut u8,
master.get() as *const u8,
file_size);
}
// Set TLS pointer
//TODO: Do not use stack to store TLS pointer, use a TCB structure instead
unsafe { *(arch::USER_STACK_OFFSET as *mut usize) = tls.mem.start_address().get() + size; }
context.tls = Some(tls);
}
// Push arguments
let mut arg_size = 0;
for arg in args.iter().rev() {
sp -= mem::size_of::<usize>();
@ -597,7 +672,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
}
// Go to usermode
unsafe { usermode(entry, sp); }
unsafe { usermode(entry, sp, fs); }
}
pub fn exit(status: usize) -> ! {
@ -897,6 +972,7 @@ pub fn virttophys(virtual_address: usize) -> Result<usize> {
pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
loop {
let mut exited = false;
let mut running;
let waitpid;
{
let contexts = context::contexts();
@ -909,10 +985,23 @@ pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
}
exited = true;
}
running = context.running;
waitpid = context.waitpid.clone();
}
if exited {
// Spin until not running
while running {
{
let contexts = context::contexts();
let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
running = context.running;
}
arch::interrupt::pause();
}
let mut contexts = context::contexts_mut();
return contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid));
} else if flags & WNOHANG == WNOHANG {