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:
parent
25d459f389
commit
64b3716c92
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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" )
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user