You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
5.0 KiB
204 lines
5.0 KiB
#![no_std]
|
|
#![no_main]
|
|
#![feature(asm)]
|
|
#![feature(alloc)]
|
|
#![feature(naked_functions)]
|
|
#![feature(lang_items)]
|
|
|
|
extern crate alloc;
|
|
|
|
use core::alloc::Layout;
|
|
use core::panic::PanicInfo;
|
|
use alloc::{boxed::Box, sync::Arc};
|
|
|
|
use blog_os::{exit_qemu, gdt, interrupts::init_idt, serial_println};
|
|
use linked_list_allocator::LockedHeap;
|
|
use rcore_thread::{*, std_thread as thread};
|
|
|
|
const STACK_SIZE: usize = 0x2000;
|
|
const HEAP_SIZE: usize = 0x100000;
|
|
const MAX_CPU_NUM: usize = 1;
|
|
const MAX_PROC_NUM: usize = 32;
|
|
|
|
|
|
/// The entry of the kernel
|
|
#[no_mangle]
|
|
pub extern "C" fn _start() -> ! {
|
|
// init x86
|
|
gdt::init();
|
|
init_idt();
|
|
// init log
|
|
init_log();
|
|
// init heap
|
|
unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); }
|
|
// init processor
|
|
let scheduler = scheduler::RRScheduler::new(5);
|
|
let thread_pool = Arc::new(ThreadPool::new(scheduler, MAX_PROC_NUM));
|
|
unsafe { processor().init(0, Thread::init(), thread_pool); }
|
|
// init threads
|
|
thread::spawn(|| {
|
|
let tid = processor().tid();
|
|
serial_println!("[{}] yield", tid);
|
|
thread::yield_now();
|
|
serial_println!("[{}] spawn", tid);
|
|
let t2 = thread::spawn(|| {
|
|
let tid = processor().tid();
|
|
serial_println!("[{}] yield", tid);
|
|
thread::yield_now();
|
|
serial_println!("[{}] return 8", tid);
|
|
8
|
|
});
|
|
serial_println!("[{}] join", tid);
|
|
let ret = t2.join();
|
|
serial_println!("[{}] get {:?}", tid, ret);
|
|
serial_println!("[{}] exit", tid);
|
|
});
|
|
// run threads
|
|
processor().run();
|
|
}
|
|
|
|
fn init_log() {
|
|
use log::*;
|
|
struct SimpleLogger;
|
|
impl Log for SimpleLogger {
|
|
fn enabled(&self, _metadata: &Metadata) -> bool {
|
|
true
|
|
}
|
|
fn log(&self, record: &Record) {
|
|
serial_println!("[{:>5}] {}", record.level(), record.args());
|
|
}
|
|
fn flush(&self) {}
|
|
}
|
|
static LOGGER: SimpleLogger = SimpleLogger;
|
|
set_logger(&LOGGER).unwrap();
|
|
set_max_level(LevelFilter::Trace);
|
|
}
|
|
|
|
/// The context of a thread.
|
|
///
|
|
/// When a thread yield, its context will be stored at its stack.
|
|
#[derive(Debug, Default)]
|
|
#[repr(C)]
|
|
struct ContextData {
|
|
rdi: usize, // arg0
|
|
r15: usize,
|
|
r14: usize,
|
|
r13: usize,
|
|
r12: usize,
|
|
rbp: usize,
|
|
rbx: usize,
|
|
rip: usize,
|
|
}
|
|
|
|
impl ContextData {
|
|
fn new(entry: extern fn(usize) -> !, arg0: usize) -> Self {
|
|
ContextData {
|
|
rip: entry as usize,
|
|
rdi: arg0,
|
|
..ContextData::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
struct Thread {
|
|
rsp: usize,
|
|
stack: [u8; STACK_SIZE],
|
|
}
|
|
|
|
impl Thread {
|
|
unsafe fn init() -> Box<Self> {
|
|
Box::new(core::mem::uninitialized())
|
|
}
|
|
fn new(entry: extern fn(usize) -> !, arg0: usize) -> Box<Self> {
|
|
let mut thread = unsafe { Thread::init() };
|
|
let rsp = thread.stack.as_ptr() as usize + STACK_SIZE - core::mem::size_of::<ContextData>();
|
|
// push a Context at stack top
|
|
let init_context = ContextData::new(entry, arg0);
|
|
unsafe { (rsp as *mut ContextData).write(init_context); }
|
|
thread.rsp = rsp;
|
|
thread
|
|
}
|
|
}
|
|
|
|
/// Implement `switch_to` for a thread
|
|
impl Context for Thread {
|
|
/// Switch to another thread.
|
|
unsafe fn switch_to(&mut self, target: &mut Context) {
|
|
let (to, _): (*mut Thread, usize) = core::mem::transmute(target);
|
|
inner(self, to);
|
|
|
|
#[naked]
|
|
#[inline(never)]
|
|
unsafe extern "C" fn inner(_from: *mut Thread, _to: *mut Thread) {
|
|
asm!(
|
|
"
|
|
// push rip (by caller)
|
|
|
|
// Save self callee-save registers
|
|
push rbx
|
|
push rbp
|
|
push r12
|
|
push r13
|
|
push r14
|
|
push r15
|
|
push rdi
|
|
|
|
// Switch stacks
|
|
mov [rdi], rsp // *rdi = from_rsp
|
|
mov rsp, [rsi] // *rsi = to_rsp
|
|
|
|
// Restore target callee-save registers
|
|
pop rdi
|
|
pop r15
|
|
pop r14
|
|
pop r13
|
|
pop r12
|
|
pop rbp
|
|
pop rbx
|
|
|
|
// pop rip
|
|
ret"
|
|
: : : : "intel" "volatile" )
|
|
}
|
|
}
|
|
|
|
fn set_tid(&mut self, _tid: usize) {
|
|
}
|
|
}
|
|
|
|
/// Define global `Processor` for each core.
|
|
static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new()];
|
|
|
|
/// Now we only have one core.
|
|
fn cpu_id() -> usize { 0 }
|
|
|
|
/// Implement dependency for `rcore_thread::std_thread`
|
|
#[no_mangle]
|
|
pub fn processor() -> &'static Processor {
|
|
&PROCESSORS[cpu_id()]
|
|
}
|
|
|
|
/// Implement dependency for `rcore_thread::std_thread`
|
|
#[no_mangle]
|
|
pub fn new_kernel_context(entry: extern fn(usize) -> !, arg0: usize) -> Box<Context> {
|
|
Thread::new(entry, arg0)
|
|
}
|
|
|
|
#[panic_handler]
|
|
fn panic(info: &PanicInfo) -> ! {
|
|
serial_println!("\n{}", info);
|
|
|
|
unsafe { exit_qemu(); }
|
|
loop {}
|
|
}
|
|
|
|
#[global_allocator]
|
|
static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty();
|
|
|
|
static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
|
|
|
|
#[lang = "oom"]
|
|
fn oom(_: Layout) -> ! {
|
|
panic!("out of memory");
|
|
} |