lib.rs 6.57 KB
Newer Older
ticki's avatar
ticki committed
1 2
//! # The Redox OS Kernel, version 2
//!
3
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
ticki's avatar
ticki committed
4 5
//! provides Unix-like syscalls for primarily Rust applications

6
//#![deny(warnings)]
7 8 9 10 11 12 13 14
#![cfg_attr(feature = "clippy", allow(if_same_then_else))]
#![cfg_attr(feature = "clippy", allow(inline_always))]
#![cfg_attr(feature = "clippy", allow(many_single_char_names))]
#![cfg_attr(feature = "clippy", allow(module_inception))]
#![cfg_attr(feature = "clippy", allow(new_without_default))]
#![cfg_attr(feature = "clippy", allow(not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "clippy", allow(or_fun_call))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
Jeremy Soller's avatar
Jeremy Soller committed
15
#![feature(alloc)]
Jeremy Soller's avatar
Jeremy Soller committed
16
#![feature(allocator_api)]
17
#![feature(asm)]
Jeremy Soller's avatar
Jeremy Soller committed
18
#![feature(collections)]
19
#![feature(concat_idents)]
20
#![feature(const_atomic_usize_new)]
Jeremy Soller's avatar
Jeremy Soller committed
21
#![feature(const_fn)]
22
#![feature(const_max_value)]
Jeremy Soller's avatar
Jeremy Soller committed
23
#![feature(const_size_of)]
Jeremy Soller's avatar
Jeremy Soller committed
24
#![feature(core_intrinsics)]
Jeremy Soller's avatar
Jeremy Soller committed
25
#![feature(global_allocator)]
26
#![feature(integer_atomics)]
Jeremy Soller's avatar
Jeremy Soller committed
27 28
#![feature(lang_items)]
#![feature(naked_functions)]
29
#![feature(never_type)]
Jeremy Soller's avatar
Jeremy Soller committed
30
#![feature(panic_implementation)]
Jeremy Soller's avatar
Jeremy Soller committed
31
#![feature(ptr_internals)]
32
#![feature(thread_local)]
Jeremy Soller's avatar
Jeremy Soller committed
33
#![feature(unique)]
ticki's avatar
ticki committed
34 35
#![no_std]

Jeremy Soller's avatar
Jeremy Soller committed
36
pub extern crate x86;
ticki's avatar
ticki committed
37

Jeremy Soller's avatar
Jeremy Soller committed
38
#[macro_use]
Nagy Tibor's avatar
Nagy Tibor committed
39
extern crate alloc;
Jeremy Soller's avatar
Jeremy Soller committed
40

Jeremy Soller's avatar
Jeremy Soller committed
41
#[macro_use]
Jeremy Soller's avatar
Jeremy Soller committed
42
extern crate bitflags;
43
extern crate goblin;
44
extern crate linked_list_allocator;
Jeremy Soller's avatar
Jeremy Soller committed
45
extern crate spin;
46
#[cfg(feature = "slab")]
47
extern crate slab_allocator;
Jeremy Soller's avatar
Jeremy Soller committed
48

Jeremy Soller's avatar
Jeremy Soller committed
49
use alloc::arc::Arc;
50
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
Jeremy Soller's avatar
Jeremy Soller committed
51 52
use spin::Mutex;

Jeremy Soller's avatar
Jeremy Soller committed
53
use scheme::{FileHandle, SchemeNamespace};
54

Jeremy Soller's avatar
Jeremy Soller committed
55 56
pub use consts::*;

57 58 59
#[macro_use]
/// Shared data structures
pub mod common;
60

61
/// Architecture-dependent stuff
Jeremy Soller's avatar
Jeremy Soller committed
62
#[macro_use]
63 64
pub mod arch;
pub use arch::*;
Jeremy Soller's avatar
Jeremy Soller committed
65 66 67 68

/// Constants like memory locations
pub mod consts;

69 70 71
/// Heap allocators
pub mod allocator;

Jeremy Soller's avatar
Jeremy Soller committed
72
/// ACPI table parsing
Jeremy Soller's avatar
Jeremy Soller committed
73
#[cfg(feature = "acpi")]
Jeremy Soller's avatar
Jeremy Soller committed
74 75
mod acpi;

Jeremy Soller's avatar
Jeremy Soller committed
76 77 78
/// Context management
pub mod context;

79 80 81
/// Architecture-independent devices
pub mod devices;

82
/// ELF file parsing
Jeremy Soller's avatar
Jeremy Soller committed
83
#[cfg(not(feature="doc"))]
84 85
pub mod elf;

Jeremy Soller's avatar
Jeremy Soller committed
86 87 88
/// Event handling
pub mod event;

Jeremy Soller's avatar
Jeremy Soller committed
89 90 91
/// External functions
pub mod externs;

Jeremy Soller's avatar
Jeremy Soller committed
92 93 94 95
/// Memory management
pub mod memory;

/// Panic
Jeremy Soller's avatar
Jeremy Soller committed
96
#[cfg(not(any(feature="doc", test)))]
Jeremy Soller's avatar
Jeremy Soller committed
97 98
pub mod panic;

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

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

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

Jeremy Soller's avatar
Jeremy Soller committed
108 109 110
/// Time
pub mod time;

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

Jeremy Soller's avatar
Jeremy Soller committed
115
#[global_allocator]
116
static ALLOCATOR: allocator::Allocator = allocator::Allocator;
Jeremy Soller's avatar
Jeremy Soller committed
117

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

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

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

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

Jeremy Soller's avatar
Jeremy Soller committed
137 138
/// 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
139
pub extern fn userspace_init() {
Jeremy Soller's avatar
Jeremy Soller committed
140
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));
141

142 143 144
    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));
Jeremy Soller's avatar
Jeremy Soller committed
145

Jeremy Soller's avatar
Jeremy Soller committed
146
    syscall::exec(b"/bin/init", &[]).expect("failed to execute init");
Jeremy Soller's avatar
Jeremy Soller committed
147

148
    panic!("init returned");
Jeremy Soller's avatar
Jeremy Soller committed
149 150
}

Jeremy Soller's avatar
Jeremy Soller committed
151
/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
Jeremy Soller's avatar
Jeremy Soller committed
152
pub fn kmain(cpus: usize, env: &[u8]) -> ! {
153
    CPU_ID.store(0, Ordering::SeqCst);
154
    CPU_COUNT.store(cpus, Ordering::SeqCst);
155

156 157
    context::init();

158
    let pid = syscall::getpid();
159
    println!("BSP: {:?} {}", pid, cpus);
Jeremy Soller's avatar
Jeremy Soller committed
160
    println!("Env: {:?}", ::core::str::from_utf8(env));
161

162 163 164
    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
Jeremy Soller's avatar
Jeremy Soller committed
165 166
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
167
            context.status = context::Status::Runnable;
Jeremy Soller's avatar
Jeremy Soller committed
168 169 170 171 172 173 174 175 176 177 178 179 180

            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()))
                        );
                    }
                }
            }
181 182 183 184 185
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }
Jeremy Soller's avatar
Jeremy Soller committed
186

Jeremy Soller's avatar
Jeremy Soller committed
187
    loop {
Jeremy Soller's avatar
Jeremy Soller committed
188
        unsafe {
189
            interrupt::disable();
190 191 192 193 194
            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();
Jeremy Soller's avatar
Jeremy Soller committed
195
            }
Jeremy Soller's avatar
Jeremy Soller committed
196
        }
197 198 199
    }
}

Jeremy Soller's avatar
Jeremy Soller committed
200
/// This is the main kernel entry point for secondary CPUs
bjorn3's avatar
bjorn3 committed
201
#[allow(unreachable_code, unused_variables)]
Jeremy Soller's avatar
Jeremy Soller committed
202 203
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);
Jeremy Soller's avatar
Jeremy Soller committed
204

Jeremy Soller's avatar
Jeremy Soller committed
205
    if cfg!(feature = "multi_core") {
bjorn3's avatar
bjorn3 committed
206 207 208 209 210 211 212 213
        context::init();

        let pid = syscall::getpid();
        println!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
214 215 216 217 218
                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();
bjorn3's avatar
bjorn3 committed
219
                }
Jeremy Soller's avatar
Jeremy Soller committed
220 221
            }
        }
Jeremy Soller's avatar
Jeremy Soller committed
222 223
    } else {
        println!("AP {}: Disabled", id);
bjorn3's avatar
bjorn3 committed
224

Jeremy Soller's avatar
Jeremy Soller committed
225 226 227 228 229 230 231
        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
ticki's avatar
ticki committed
232
}
Jeremy Soller's avatar
Jeremy Soller committed
233 234 235 236 237 238 239 240 241 242 243 244 245 246

/// 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()) });
        }
    }
    syscall::exit(signal & 0x7F);
}