lib.rs 6.57 KB
Newer Older
1 2
//! # The Redox OS Kernel, version 2
//!
3
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
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))]
15
#![deny(unreachable_patterns)]
Jeremy Soller's avatar
Jeremy Soller committed
16
#![feature(alloc)]
17
#![feature(allocator_api)]
18
#![feature(asm)]
19
#![feature(concat_idents)]
20
#![feature(const_fn)]
Jeremy Soller's avatar
Jeremy Soller committed
21
#![feature(core_intrinsics)]
22
#![feature(integer_atomics)]
Jeremy Soller's avatar
Jeremy Soller committed
23 24
#![feature(lang_items)]
#![feature(naked_functions)]
25
#![feature(never_type)]
Jeremy Soller's avatar
Jeremy Soller committed
26
#![feature(ptr_internals)]
27
#![feature(thread_local)]
28 29
#![no_std]

Jeremy Soller's avatar
Jeremy Soller committed
30
pub extern crate x86;
31

Jeremy Soller's avatar
Jeremy Soller committed
32
#[macro_use]
Nagy Tibor's avatar
Nagy Tibor committed
33
extern crate alloc;
Jeremy Soller's avatar
Jeremy Soller committed
34

Jeremy Soller's avatar
Jeremy Soller committed
35
#[macro_use]
36
extern crate bitflags;
37
extern crate goblin;
38
extern crate linked_list_allocator;
39
extern crate rustc_demangle;
40
extern crate spin;
41
#[cfg(feature = "slab")]
42
extern crate slab_allocator;
43

44
use alloc::vec::Vec;
Jeremy Soller's avatar
Jeremy Soller committed
45
use core::sync::atomic::{AtomicUsize, Ordering};
46

jD91mZM2's avatar
jD91mZM2 committed
47
use crate::scheme::{FileHandle, SchemeNamespace};
48

jD91mZM2's avatar
jD91mZM2 committed
49
pub use crate::consts::*;
Jeremy Soller's avatar
Jeremy Soller committed
50

51 52 53
#[macro_use]
/// Shared data structures
pub mod common;
54

55
/// Architecture-dependent stuff
Jeremy Soller's avatar
Jeremy Soller committed
56
#[macro_use]
57
pub mod arch;
jD91mZM2's avatar
jD91mZM2 committed
58
pub use crate::arch::*;
Jeremy Soller's avatar
Jeremy Soller committed
59 60 61 62

/// Constants like memory locations
pub mod consts;

63 64 65
/// Heap allocators
pub mod allocator;

Jeremy Soller's avatar
Jeremy Soller committed
66
/// ACPI table parsing
Jeremy Soller's avatar
Jeremy Soller committed
67
#[cfg(feature = "acpi")]
Jeremy Soller's avatar
Jeremy Soller committed
68 69
mod acpi;

70 71 72
/// Context management
pub mod context;

73 74 75
/// Architecture-independent devices
pub mod devices;

76
/// ELF file parsing
Jeremy Soller's avatar
Jeremy Soller committed
77
#[cfg(not(feature="doc"))]
78 79
pub mod elf;

Jeremy Soller's avatar
Jeremy Soller committed
80 81 82
/// Event handling
pub mod event;

Jeremy Soller's avatar
Jeremy Soller committed
83 84 85
/// External functions
pub mod externs;

86 87 88
/// Logging
pub mod log;

Jeremy Soller's avatar
Jeremy Soller committed
89 90 91 92
/// Memory management
pub mod memory;

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

96 97 98
/// Process tracing
pub mod ptrace;

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;

115
#[global_allocator]
116
static ALLOCATOR: allocator::Allocator = allocator::Allocator;
117

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

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
Jeremy Soller's avatar
Jeremy Soller committed
129
static CPU_COUNT : AtomicUsize = AtomicUsize::new(0);
130

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)
}

137 138
static mut INIT_ENV: &[u8] = &[];

Jeremy Soller's avatar
Jeremy Soller committed
139 140
/// 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
141
pub extern fn userspace_init() {
Jeremy Soller's avatar
Jeremy Soller committed
142
    let path = b"initfs:/bin/init";
143 144
    let env = unsafe { INIT_ENV };

Jeremy Soller's avatar
Jeremy Soller committed
145
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));
146

147 148 149
    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));
150

Jeremy Soller's avatar
Jeremy Soller committed
151
    let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init");
152

Jeremy Soller's avatar
Jeremy Soller committed
153 154 155 156 157
    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') {
158 159 160
        if ! var.is_empty() {
            vars.push(var.to_vec().into_boxed_slice());
        }
161 162
    }

163
    syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None).expect("failed to execute init");
Jeremy Soller's avatar
Jeremy Soller committed
164

165
    panic!("init returned");
166 167
}

Jeremy Soller's avatar
Jeremy Soller committed
168
/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
169
pub fn kmain(cpus: usize, env: &'static [u8]) -> ! {
170
    CPU_ID.store(0, Ordering::SeqCst);
171
    CPU_COUNT.store(cpus, Ordering::SeqCst);
Jeremy Soller's avatar
Jeremy Soller committed
172
    unsafe { INIT_ENV = env };
173

174
    //Initialize the first context, stored in kernel/src/context/mod.rs
175 176
    context::init();

177
    let pid = syscall::getpid();
178
    println!("BSP: {:?} {}", pid, cpus);
179
    println!("Env: {:?}", ::core::str::from_utf8(env));
180

181 182 183
    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
Jeremy Soller's avatar
Jeremy Soller committed
184 185
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
186
            context.status = context::Status::Runnable;
187 188 189 190 191
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }
192

193
    loop {
Jeremy Soller's avatar
Jeremy Soller committed
194
        unsafe {
195
            interrupt::disable();
196 197 198 199 200
            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
201
            }
Jeremy Soller's avatar
Jeremy Soller committed
202
        }
203 204 205
    }
}

Jeremy Soller's avatar
Jeremy Soller committed
206
/// This is the main kernel entry point for secondary CPUs
207
#[allow(unreachable_code, unused_variables)]
208 209
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);
210

211
    if cfg!(feature = "multi_core") {
212 213 214 215 216 217 218 219
        context::init();

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

        loop {
            unsafe {
                interrupt::disable();
220 221 222 223 224
                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();
225
                }
Jeremy Soller's avatar
Jeremy Soller committed
226 227
            }
        }
228 229
    } else {
        println!("AP {}: Disabled", id);
230

231 232 233 234 235 236 237
        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
238
}
Jeremy Soller's avatar
Jeremy Soller committed
239 240 241 242 243 244 245 246 247 248 249 250 251 252

/// 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);
}