Can switch between `init` and `idle` process

master
WangRunji 7 years ago
parent 4f18f70e19
commit 0553d3374d

@ -15,7 +15,7 @@ interrupt_error_p!(double_fault, stack, {
loop {}
});
interrupt_stack_p!(page_fault, stack, {
interrupt_error_p!(page_fault, stack, {
use x86_64::registers::control_regs::cr2;
println!("\nEXCEPTION: Page Fault\nAddress: {:#x}", cr2());
stack.dump();
@ -62,7 +62,7 @@ use spin::Mutex;
// FIXME: Deadlock
//static TICK: Mutex<usize> = Mutex::new(0);
interrupt_stack_p!(timer, stack, {
interrupt_switch!(timer, rsp, {
// let mut tick = TICK.lock();
// *tick += 1;
// let tick = *tick;
@ -71,9 +71,8 @@ interrupt_stack_p!(timer, stack, {
if tick % 100 == 0 {
println!("\nInterupt: Timer\ntick = {}", tick);
use process;
// process::schedule(stack);
process::schedule(rsp);
}
stack.dump();
ack(IRQ_TIMER);
});

@ -317,6 +317,45 @@ impl Debug for InterruptStackP {
}
}
#[macro_export]
macro_rules! interrupt_switch {
($name:ident, $rsp: ident, $func:block) => {
#[naked]
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($rsp: &mut usize) {
$func
}
// Push scratch registers
scratch_push!();
preserved_push!();
fs_push!();
// Get reference to stack variables
let mut rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Map kernel
// $crate::arch::x86_64::pti::map();
// Call inner rust function
inner(&mut rsp);
asm!("" : : "{rsp}"(rsp) : : "intel", "volatile");
// Unmap kernel
// $crate::arch::x86_64::pti::unmap();
// Pop scratch registers and return
fs_pop!();
preserved_pop!();
scratch_pop!();
iret!();
}
};
}
#[macro_export]
macro_rules! interrupt_stack_p {
($name:ident, $stack: ident, $func:block) => {

@ -35,6 +35,9 @@ fn print_in_color(args: fmt::Arguments, color: Color) {
// writer.set_color(color);
// writer.write_fmt(args).unwrap();
// }
// TODO: 解决死锁问题
// 若进程在持有锁时被中断,中断处理程序请求输出,就会死锁
unsafe{ COM1.force_unlock(); }
COM1.lock().write_fmt(args).unwrap();
}

@ -80,19 +80,27 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
// arch::smp::start_other_cores(&acpi, &mut memory_controller);
process::init(&mut memory_controller);
// FIXME: 在用户模式下触发时钟中断导致GPF
// unsafe{ arch::interrupt::enable(); }
unsafe{ arch::interrupt::enable(); }
unsafe{
use arch::syscall;
syscall::switch_to_user();
println!("Now in user mode");
// loop{}
syscall::switch_to_kernel();
println!("Now in kernel mode");
// 在用户模式下触发时钟中断会导致GPF
// (可能是由于没有合理分离栈)
no_interrupt!({
syscall::switch_to_user();
println!("Now in user mode");
syscall::switch_to_kernel();
println!("Now in kernel mode");
});
}
loop{}
loop{
println!("init ...");
let mut i = 0;
while i < 1 << 22 {
i += 1;
}
}
test_end!();
unreachable!();

@ -6,29 +6,37 @@ use spin::{Once, Mutex};
///
/// ## 必须实现的特性
///
/// * Clone: 用于对栈中TrapFrame的替换
/// * Debug: 用于Debug输出
use arch::interrupt::TrapFrame;
pub fn init(mc: &mut MemoryController) {
PROCESSOR.call_once(|| {Mutex::new(Processor::new(mc))});
PROCESSOR.call_once(|| {Mutex::new({
let mut processor = Processor::new(mc);
let initproc = Process::new_init(mc);
let idleproc = Process::new("idle", idle_thread, mc);
processor.add(initproc);
processor.add(idleproc);
processor
})});
}
static PROCESSOR: Once<Mutex<Processor>> = Once::new();
/// Called by timer handler in arch
pub fn schedule(trap_frame: &mut TrapFrame) {
PROCESSOR.try().unwrap().lock().schedule(trap_frame);
/// 设置rsp指向接下来要执行线程的 内核栈顶
/// 之后中断处理例程会重置rsp恢复对应线程的上下文
pub fn schedule(rsp: &mut usize) {
PROCESSOR.try().unwrap().lock().schedule(rsp);
}
#[derive(Debug)]
pub struct Process {
pid: Pid,
name: String,
name: &'static str,
kstack: Stack,
// page_table: Box<PageTable>,
status: Status,
trap_frame: TrapFrame,
rsp: usize,
}
#[derive(Debug)]
@ -45,33 +53,10 @@ type Pid = usize;
impl Processor {
fn new(mc: &mut MemoryController) -> Self {
let mut processor = Processor {
Processor {
procs: BTreeMap::<Pid, Box<Process>>::new(),
current_pid: 0,
};
let initproc = Box::new(Process{
pid: 0,
name: String::from("initproc"),
kstack: mc.kernel_stack.take().unwrap(),
status: Status::Running,
trap_frame: TrapFrame::default(),
});
let idleproc = Box::new(Process{
pid: 1,
name: String::from("idleproc"),
kstack: mc.alloc_stack(7).unwrap(),
status: Status::Ready,
trap_frame: {
let mut tf = TrapFrame::default();
tf.iret.cs = 8;
tf.iret.rip = idle_thread as usize;
tf.iret.rflags = 0x282;
tf
},
});
processor.procs.insert(0, initproc);
processor.procs.insert(1, idleproc);
processor
}
}
fn alloc_pid(&self) -> Pid {
let mut next: Pid = 0;
@ -84,31 +69,88 @@ impl Processor {
}
return next;
}
fn schedule(&mut self, trap_frame: &mut TrapFrame) {
self.switch(1, trap_frame);
fn add(&mut self, mut process: Box<Process>) {
let pid = self.alloc_pid();
process.pid = pid;
self.procs.insert(pid, process);
}
fn schedule(&mut self, rsp: &mut usize) {
let pid = self.find_next();
self.switch_to(pid, rsp);
}
fn find_next(&self) -> Pid {
*self.procs.keys()
.find(|&&i| i > self.current_pid)
.unwrap_or(self.procs.keys().nth(0).unwrap())
}
fn switch(&mut self, pid: Pid, trap_frame: &mut TrapFrame) {
fn switch_to(&mut self, pid: Pid, rsp: &mut usize) {
// for debug print
let pid0 = self.current_pid;
let rsp0 = *rsp;
if pid == self.current_pid {
return;
}
{
let current = self.procs.get_mut(&self.current_pid).unwrap();
current.status = Status::Ready;
current.rsp = *rsp;
}
{
let process = self.procs.get_mut(&pid).unwrap();
*trap_frame = process.trap_frame.clone();
process.status = Status::Running;
*rsp = process.rsp;
// TODO switch page table
}
self.current_pid = pid;
debug!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp);
}
}
impl Process {
/// Make a new kernel thread
fn new(name: &'static str, entry: extern fn(), mc: &mut MemoryController) -> Box<Self> {
let kstack = mc.alloc_stack(7).unwrap();
let rsp = unsafe{ (kstack.top() as *mut TrapFrame).offset(-1) } as usize;
let mut tf = unsafe{ &mut *(rsp as *mut TrapFrame) };
// TODO: move to arch
*tf = TrapFrame::default();
tf.iret.cs = 8;
tf.iret.rip = entry as usize;
tf.iret.ss = 24;
tf.iret.rsp = kstack.top();
tf.iret.rflags = 0x282;
Box::new(Process {
pid: 0,
name,
kstack,
status: Status::Ready,
rsp,
})
}
/// Make the first kernel thread `initproc`
/// Should be called only once
fn new_init(mc: &mut MemoryController) -> Box<Self> {
assert_has_not_been_called!();
Box::new(Process {
pid: 0,
name: "init",
kstack: mc.kernel_stack.take().unwrap(),
status: Status::Running,
rsp: 0, // will be set at first schedule
})
}
}
extern fn idle_thread() {
loop {
println!("idle ...");
for i in 0 .. 1 << 20 {
let mut i = 0;
while i < 1 << 22 {
i += 1;
}
}
}
Loading…
Cancel
Save