parent
5bffce787b
commit
1541282ad7
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "example"
|
||||
version = "0.1.0"
|
||||
authors = ["WangRunji <wangrunji0408@163.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
linked_list_allocator = "0.6"
|
||||
blog_os = { git = "https://github.com/phil-opp/blog_os.git" }
|
||||
rcore-thread = { path = ".." }
|
||||
|
||||
[package.metadata.bootimage]
|
||||
default-target = "x86_64-blog_os.json"
|
||||
run-command = ["qemu-system-x86_64",
|
||||
"-drive", "format=raw,file={}",
|
||||
"-serial", "mon:stdio",
|
||||
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
|
||||
]
|
@ -0,0 +1,5 @@
|
||||
# Example of `rcore-thread` crate
|
||||
|
||||
```bash
|
||||
bootimage run --release
|
||||
```
|
@ -0,0 +1,199 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(asm)]
|
||||
#![feature(alloc)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(panic_info_message)]
|
||||
#![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 = Box::new(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!("I'm thread {}! yield...", tid);
|
||||
thread::yield_now();
|
||||
serial_println!("I'm thread {}! exit...", tid);
|
||||
});
|
||||
thread::spawn(|| {
|
||||
let tid = processor().tid();
|
||||
serial_println!("I'm thread {}! yield...", tid);
|
||||
thread::yield_now();
|
||||
serial_println!("I'm thread {}! 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" )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) -> ! {
|
||||
let location = info.location().unwrap();
|
||||
let message = info.message().unwrap();
|
||||
serial_println!("\nPANIC @ {}\n\t{}", location, message);
|
||||
|
||||
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");
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "-mmx,-sse,+soft-float"
|
||||
}
|
Loading…
Reference in new issue