1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-23 00:16:17 +04:00

HUGE: Impl switch() like ucore/xv6.

This commit is contained in:
WangRunji 2018-05-22 23:48:39 +08:00
parent 25d459f389
commit 64b3716c92
8 changed files with 149 additions and 42 deletions

View File

@ -19,12 +19,15 @@ __alltraps:
push r15
mov rdi, rsp
; extern fn rust_trap(rsp) -> rsp
extern rust_trap
call rust_trap
mov rsp, rax
global trap_ret
trap_ret:
mov rdi, rsp
extern set_return_rsp
call set_return_rsp
pop r15
pop r14

View File

@ -24,7 +24,8 @@
use super::TrapFrame;
#[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) -> usize {
pub extern fn rust_trap(tf: &mut TrapFrame) {
trace!("Interrupt: {:#x}", tf.trap_num);
// Dispatch
match tf.trap_num as u8 {
T_BRKPT => breakpoint(),
@ -53,15 +54,8 @@ pub extern fn rust_trap(tf: &mut TrapFrame) -> usize {
_ => panic!("Unhandled interrupt {:x}", tf.trap_num),
}
let mut rsp = tf as *const _ as usize;
use process::PROCESSOR;
PROCESSOR.try().unwrap().lock().schedule(&mut rsp);
// Set return rsp if to user
let tf = unsafe { &*(rsp as *const TrapFrame) };
set_return_rsp(tf);
rsp
PROCESSOR.try().unwrap().lock().schedule();
}
fn breakpoint() {
@ -144,13 +138,19 @@ fn syscall32(tf: &mut TrapFrame) {
fn error(tf: &TrapFrame) {
use process::PROCESSOR;
let mut processor = PROCESSOR.try().unwrap().lock();
let pid = processor.current_pid();
error!("Process {} error:\n{:#x?}", pid, tf);
processor.exit(pid, 0x100); // TODO: Exit code for error
if let Some(processor) = PROCESSOR.try() {
let mut processor = processor.lock();
let pid = processor.current_pid();
error!("Process {} error:\n{:#x?}", pid, tf);
processor.exit(pid, 0x100); // TODO: Exit code for error
} else {
error!("Exception {:#x} when processor not inited\n{:#x?}", tf.trap_num, tf);
loop {}
}
}
fn set_return_rsp(tf: &TrapFrame) {
#[no_mangle]
pub extern fn set_return_rsp(tf: &TrapFrame) {
use arch::gdt::Cpu;
use core::mem::size_of;
if tf.cs & 0x3 == 3 {

View File

@ -5,8 +5,8 @@ pub mod consts;
mod handler;
mod trapframe;
pub use self::trapframe::TrapFrame;
pub use self::handler::rust_trap;
pub use self::trapframe::*;
pub use self::handler::*;
#[inline(always)]
pub unsafe fn enable() {

View File

@ -1,4 +1,5 @@
#[derive(Debug, Clone, Default)]
#[repr(C)]
pub struct TrapFrame {
// Pushed by __alltraps at 'trap.asm'
pub r15: usize,
@ -34,7 +35,7 @@ pub struct TrapFrame {
/// 用于在内核栈中构造新线程的中断帧
impl TrapFrame {
pub fn new_kernel_thread(entry: extern fn(), rsp: usize) -> Self {
fn new_kernel_thread(entry: extern fn() -> !, rsp: usize) -> Self {
use arch::gdt;
let mut tf = TrapFrame::default();
tf.cs = gdt::KCODE_SELECTOR.0 as usize;
@ -44,7 +45,7 @@ impl TrapFrame {
tf.rflags = 0x282;
tf
}
pub fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
use arch::gdt;
let mut tf = TrapFrame::default();
tf.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize;
@ -54,4 +55,109 @@ impl TrapFrame {
tf.rflags = 0x282;
tf
}
}
#[derive(Debug, Default)]
#[repr(C)]
struct Context {
r15: usize,
r14: usize,
r13: usize,
r12: usize,
rbp: usize,
rbx: usize,
rip: usize,
}
impl Context {
fn new() -> Self {
let mut context = Context::default();
context.rip = forkret as usize;
context
}
}
/// 新线程的内核栈初始内容
#[derive(Debug)]
#[repr(C)]
pub struct InitStack {
context: Context,
trapret: usize,
tf: TrapFrame,
}
impl InitStack {
pub fn new_kernel_thread(entry: extern fn() -> !, rsp: usize) -> Self {
InitStack {
context: Context::new(),
trapret: trap_ret as usize,
tf: TrapFrame::new_kernel_thread(entry, rsp),
}
}
pub fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
InitStack {
context: Context::new(),
trapret: trap_ret as usize,
tf: TrapFrame::new_user_thread(entry_addr, rsp, is32),
}
}
pub fn new_fork(tf: &TrapFrame) -> Self {
InitStack {
context: Context::new(),
trapret: trap_ret as usize,
tf: {
let mut tf = tf.clone();
tf.rax = 0;
tf
},
}
}
}
extern {
fn trap_ret();
}
/// The entry point of new thread
extern fn forkret() {
debug!("forkret");
// Will return to `trapret`
}
/// Switch to another kernel thread.
///
/// Defined in `trap.asm`.
///
/// Push all callee-saved registers at the current kernel stack.
/// Store current rsp at `from_rsp`. Switch kernel stack to `to_rsp`.
/// Pop all callee-saved registers, then return to the target.
#[naked]
pub unsafe extern fn switch(from_rsp: &mut usize, to_rsp: usize) {
asm!(
"
// push rip (by caller)
// Save old callee-save registers
push rbx
push rbp
push r12
push r13
push r14
push r15
// Switch stacks
mov [rdi], rsp // rdi = from_rsp
mov rsp, rsi // rsi = to_rsp
// Save old callee-save registers
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
// pop rip
ret"
: : : : "intel" "volatile" )
}

View File

@ -59,6 +59,7 @@ mod arch;
#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
arch::cpu::init();
arch::idt::init();
io::init();
// ATTENTION: we have a very small stack and no guard page
@ -70,7 +71,6 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
let mut memory_controller = memory::init(boot_info);
arch::gdt::init();
arch::idt::init();
test!(cow);
test!(global_allocator);
@ -127,7 +127,7 @@ pub extern "C" fn other_main() -> ! {
loop {}
}
pub use arch::interrupt::rust_trap;
pub use arch::interrupt::{rust_trap, set_return_rsp};
use linked_list_allocator::LockedHeap;

View File

@ -2,7 +2,6 @@ use memory::MemoryController;
use spin::{Once, Mutex};
use core::slice;
use alloc::String;
use arch::interrupt::TrapFrame;
use self::process::*;
pub use self::processor::*;
@ -26,7 +25,7 @@ pub fn init(mut mc: MemoryController) {
pub static PROCESSOR: Once<Mutex<Processor>> = Once::new();
pub static MC: Once<Mutex<MemoryController>> = Once::new();
extern fn idle_thread() {
extern fn idle_thread() -> ! {
loop {
println!("idle ...");
let mut i = 0;

View File

@ -3,6 +3,7 @@ use memory::{self, Stack, InactivePageTable};
use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2};
use core::slice;
use alloc::{rc::Rc, String};
use arch::interrupt::*;
#[derive(Debug)]
pub struct Process {
@ -34,10 +35,10 @@ pub enum Status {
impl Process {
/// Make a new kernel thread
pub fn new(name: &str, entry: extern fn(), mc: &mut MemoryController) -> Self {
pub fn new(name: &str, entry: extern fn() -> !, mc: &mut MemoryController) -> Self {
let kstack = mc.alloc_stack(7).unwrap();
let tf = TrapFrame::new_kernel_thread(entry, kstack.top());
let rsp = kstack.push_at_top(tf);
let data = InitStack::new_kernel_thread(entry, kstack.top());
let rsp = kstack.push_at_top(data);
Process {
pid: 0,
@ -124,7 +125,7 @@ impl Process {
// Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap();
let tf = TrapFrame::new_user_thread(entry_addr, user_stack_top - 8, is32);
let tf = InitStack::new_user_thread(entry_addr, user_stack_top - 8, is32);
let rsp = kstack.push_at_top(tf);
trace!("rsp = {:#x}", rsp);
@ -165,9 +166,8 @@ impl Process {
// Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap();
let mut tf = tf.clone();
tf.rax = 0; // sys_fork return 0 for child
let rsp = kstack.push_at_top(tf);
let data = InitStack::new_fork(tf);
let rsp = kstack.push_at_top(data);
Process {
pid: 0,

View File

@ -4,6 +4,7 @@ use super::process::*;
use core::cell::RefCell;
use core::fmt::{Debug, Formatter, Error};
use util::{EventHub, GetMut2};
use arch::interrupt::*;
pub struct Processor {
procs: BTreeMap<Pid, Process>,
@ -81,12 +82,12 @@ impl Processor {
/// Called every interrupt end
/// Do schedule ONLY IF current status != Running
pub fn schedule(&mut self, rsp: &mut usize) {
pub fn schedule(&mut self) {
if self.current().status == Status::Running {
return;
}
let pid = self.next.take().unwrap_or_else(|| self.find_next());
self.switch_to(pid, rsp);
self.switch_to(pid);
}
fn find_next(&self) -> Pid {
@ -99,10 +100,9 @@ impl Processor {
/// Switch process to `pid`, switch page table if necessary.
/// Store `rsp` and point it to target kernel stack.
/// The current status must be set before, and not be `Running`.
fn switch_to(&mut self, pid: Pid, rsp: &mut usize) {
fn switch_to(&mut self, pid: Pid) {
// for debug print
let pid0 = self.current_pid;
let rsp0 = *rsp;
if pid == self.current_pid {
return;
@ -111,14 +111,9 @@ impl Processor {
let (from, to) = self.procs.get_mut2(pid0, pid);
// set `from`
assert_ne!(from.status, Status::Running);
from.rsp = *rsp;
// set `to`
assert_eq!(to.status, Status::Ready);
to.status = Status::Running;
*rsp = to.rsp;
// switch page table
if from.is_user || to.is_user {
@ -139,7 +134,11 @@ impl Processor {
unsafe { *(addr as *mut usize) = value; }
}
info!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp);
info!("Processor: switch from {} to {}\n rsp: ??? -> {:#x}", pid0, pid, to.rsp);
unsafe {
super::PROCESSOR.try().unwrap().force_unlock();
switch(&mut from.rsp, to.rsp);
}
}
fn get(&self, pid: Pid) -> &Process {