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