Skip to content
Snippets Groups Projects
lib.rs 4.58 KiB
Newer Older
//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86_64 systems and
//! provides Unix-like syscalls for primarily Rust applications

Jeremy Soller's avatar
Jeremy Soller committed
#![feature(alloc)]
Jeremy Soller's avatar
Jeremy Soller committed
#![feature(arc_counts)]
#![feature(asm)]
Jeremy Soller's avatar
Jeremy Soller committed
#![feature(collections)]
#![feature(const_fn)]
Jeremy Soller's avatar
Jeremy Soller committed
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
Jeremy Soller's avatar
Jeremy Soller committed
#![feature(heap_api)]
#![feature(never_type)]
#![feature(thread_local)]
#![no_std]

Jeremy Soller's avatar
Jeremy Soller committed
/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
Jeremy Soller's avatar
Jeremy Soller committed
extern crate arch_test as arch;

Jeremy Soller's avatar
Jeremy Soller committed
/// Architecture specific items (ARM)
#[cfg(all(not(test), target_arch = "arm"))]
#[macro_use]
extern crate arch_arm as arch;

Jeremy Soller's avatar
Jeremy Soller committed
/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;
Jeremy Soller's avatar
Jeremy Soller committed
extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use scheme::FileHandle;
#[macro_export]
/// Shared data structures
pub mod common;
/// Context management
pub mod context;

/// ELF file parsing
pub mod elf;

Jeremy Soller's avatar
Jeremy Soller committed
/// Schemes, filesystem handlers
pub mod scheme;

Jeremy Soller's avatar
Jeremy Soller committed
/// Synchronization primitives
pub mod sync;

Jeremy Soller's avatar
Jeremy Soller committed
/// Syscall handlers
pub mod syscall;

Jeremy Soller's avatar
Jeremy Soller committed
/// Tests
#[cfg(test)]
pub mod tests;

Jeremy Soller's avatar
Jeremy Soller committed
/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

Jeremy Soller's avatar
Jeremy Soller committed
/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

Jeremy Soller's avatar
Jeremy Soller committed
/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

Jeremy Soller's avatar
Jeremy Soller committed
/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

Jeremy Soller's avatar
Jeremy Soller committed
/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
Jeremy Soller's avatar
Jeremy Soller committed
pub extern fn userspace_init() {
Jeremy Soller's avatar
Jeremy Soller committed
    assert_eq!(syscall::chdir(b"initfs:bin"), Ok(0));
    assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", 0).map(FileHandle::into), Ok(2));
    syscall::exec(b"initfs:bin/init", &[]).expect("failed to execute initfs:init");
Jeremy Soller's avatar
Jeremy Soller committed

    panic!("initfs:init returned")
Jeremy Soller's avatar
Jeremy Soller committed
/// 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());
Jeremy Soller's avatar
Jeremy Soller committed
    {
        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()) });
        }
    }
    syscall::exit(signal & 0x7F);
Jeremy Soller's avatar
Jeremy Soller committed
}

Jeremy Soller's avatar
Jeremy Soller committed
/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
#[no_mangle]
    context::init();

    let pid = syscall::getpid();
    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }
    loop {
Jeremy Soller's avatar
Jeremy Soller committed
        unsafe {
Jeremy Soller's avatar
Jeremy Soller committed
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
Jeremy Soller's avatar
Jeremy Soller committed
                interrupt::enable_and_halt();
            }
Jeremy Soller's avatar
Jeremy Soller committed
        }
Jeremy Soller's avatar
Jeremy Soller committed
/// This is the main kernel entry point for secondary CPUs
pub extern fn kmain_ap(id: usize) {
    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);
    // Disable APs for now
    loop {
        unsafe { interrupt::enable_and_halt(); }
    }
Jeremy Soller's avatar
Jeremy Soller committed
        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();
            }
        }