From 1541282ad76c41be80e92e4d3ebe50c4b890db12 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 24 Jan 2019 22:39:52 +0800 Subject: [PATCH] add example for 'thread' crate --- crate/thread/example/Cargo.toml | 19 +++ crate/thread/example/README.md | 5 + crate/thread/example/src/main.rs | 199 +++++++++++++++++++++++ crate/thread/example/x86_64-blog_os.json | 15 ++ 4 files changed, 238 insertions(+) create mode 100644 crate/thread/example/Cargo.toml create mode 100644 crate/thread/example/README.md create mode 100644 crate/thread/example/src/main.rs create mode 100644 crate/thread/example/x86_64-blog_os.json diff --git a/crate/thread/example/Cargo.toml b/crate/thread/example/Cargo.toml new file mode 100644 index 0000000..0ecc867 --- /dev/null +++ b/crate/thread/example/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["WangRunji "] +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" +] \ No newline at end of file diff --git a/crate/thread/example/README.md b/crate/thread/example/README.md new file mode 100644 index 0000000..2b14623 --- /dev/null +++ b/crate/thread/example/README.md @@ -0,0 +1,5 @@ +# Example of `rcore-thread` crate + +```bash +bootimage run --release +``` \ No newline at end of file diff --git a/crate/thread/example/src/main.rs b/crate/thread/example/src/main.rs new file mode 100644 index 0000000..2c7ada9 --- /dev/null +++ b/crate/thread/example/src/main.rs @@ -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 { + Box::new(core::mem::uninitialized()) + } + fn new(entry: extern fn(usize) -> !, arg0: usize) -> Box { + let mut thread = unsafe { Thread::init() }; + let rsp = thread.stack.as_ptr() as usize + STACK_SIZE - core::mem::size_of::(); + // 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 { + 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"); +} \ No newline at end of file diff --git a/crate/thread/example/x86_64-blog_os.json b/crate/thread/example/x86_64-blog_os.json new file mode 100644 index 0000000..7d2110d --- /dev/null +++ b/crate/thread/example/x86_64-blog_os.json @@ -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" +}