diff --git a/kernel/src/arch/mipsel/boot/context.S b/kernel/src/arch/mipsel/boot/context.S index 534ede5..d81e961 100644 --- a/kernel/src/arch/mipsel/boot/context.S +++ b/kernel/src/arch/mipsel/boot/context.S @@ -7,22 +7,23 @@ .globl switch_context .extern _root_page_table_ptr .extern _cur_kstack_ptr +.extern _cur_tls switch_context: // save from's registers addi sp, sp, (-4*14) sw sp, 0(a0) sw ra, 0(sp) - sw s0, 2*4(sp) - sw s1, 3*4(sp) - sw s2, 4*4(sp) - sw s3, 5*4(sp) - sw s4, 6*4(sp) - sw s5, 7*4(sp) - sw s6, 8*4(sp) - sw s7, 9*4(sp) - sw s8, 10*4(sp) - sw gp, 11*4(sp) + sw s0, 4*4(sp) + sw s1, 5*4(sp) + sw s2, 6*4(sp) + sw s3, 7*4(sp) + sw s4, 8*4(sp) + sw s5, 9*4(sp) + sw s6, 10*4(sp) + sw s7, 11*4(sp) + sw s8, 12*4(sp) + sw gp, 13*4(sp) // sw ra, 12*4(sp) // sw sp, 13*4(sp) @@ -31,27 +32,34 @@ switch_context: lw s1, 0(s0) sw s1, 4(sp) + // save TLS + la s2, _cur_tls + lw s1, 0(s2) + sw s1, 2*4(sp) + // restore to's registers lw sp, 0(a1) + + // restore page table address lw s1, 4(sp) sw s1, 0(s0) - // restore kstack ptr - // la s0, _cur_kstack_ptr - // addi s1, sp, 4 * 14 - // sw s1, 0(s0) + // restore TLS + lw s1, 2*4(sp) + sw s1, 0(s2) + mtc0 s1, $4, 2 // cp0.user_local lw ra, 0(sp) - lw s0, 2*4(sp) - lw s1, 3*4(sp) - lw s2, 4*4(sp) - lw s3, 5*4(sp) - lw s4, 6*4(sp) - lw s5, 7*4(sp) - lw s6, 8*4(sp) - lw s7, 9*4(sp) - lw s8, 10*4(sp) - lw gp, 11*4(sp) + lw s0, 4*4(sp) + lw s1, 5*4(sp) + lw s2, 6*4(sp) + lw s3, 7*4(sp) + lw s4, 8*4(sp) + lw s5, 9*4(sp) + lw s6, 10*4(sp) + lw s7, 11*4(sp) + lw s8, 12*4(sp) + lw gp, 13*4(sp) addi sp, sp, (4*14) sw zero, 0(a1) diff --git a/kernel/src/arch/mipsel/boot/trap.S b/kernel/src/arch/mipsel/boot/trap.S index 2d40343..44d48d2 100644 --- a/kernel/src/arch/mipsel/boot/trap.S +++ b/kernel/src/arch/mipsel/boot/trap.S @@ -177,3 +177,6 @@ _root_page_table_ptr: .global _cur_kstack_ptr _cur_kstack_ptr: .space 4 # 4bytes + .global _cur_tls +_cur_tls: + .space 4 # 4bytes diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index e5e2053..eec9bde 100644 --- a/kernel/src/arch/mipsel/context.rs +++ b/kernel/src/arch/mipsel/context.rs @@ -130,17 +130,21 @@ struct ContextData { ra: usize, /// Page table token satp: usize, - /// Callee-saved registers + /// s[0] = TLS + /// s[1] = reserved + /// s[2..11] = Callee-saved registers s: [usize; 12], } impl ContextData { - fn new(satp: usize) -> Self { - ContextData { + fn new(satp: usize, tls: usize) -> Self { + let mut context = ContextData { ra: trap_return as usize, - satp, + satp: satp, ..ContextData::default() - } + }; + context.s[0] = tls; + context } } @@ -191,7 +195,7 @@ impl Context { ); InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, 0), tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), } .push_at(kstack_top) @@ -215,7 +219,7 @@ impl Context { ); InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, 0), tf: TrapFrame::new_user_thread(entry_addr, ustack_top), } .push_at(kstack_top) @@ -228,7 +232,7 @@ impl Context { /// All the other registers are same as the original. pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self { InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, 0), tf: { let mut tf = tf.clone(); // fork function's ret value, the new process is 0 @@ -254,11 +258,10 @@ impl Context { tls: usize, ) -> Self { InitStack { - context: ContextData::new(satp), + context: ContextData::new(satp, tls), tf: { let mut tf = tf.clone(); tf.sp = ustack_top; // sp - tf.v1 = tls; tf.v0 = 0; // return value tf }, diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index bc60547..5ae84dd 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -70,6 +70,14 @@ pub extern "C" fn rust_trap(tf: &mut TrapFrame) { E::TLBModification => page_fault(tf), E::TLBLoadMiss => page_fault(tf), E::TLBStoreMiss => page_fault(tf), + E::ReservedInstruction => { + if !reserved_inst(tf) { + error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); + crate::trap::error(tf) + } else { + tf.epc = tf.epc + 4; + } + } _ => { error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); crate::trap::error(tf) @@ -149,6 +157,78 @@ fn syscall(tf: &mut TrapFrame) { } } +fn set_trapframe_register(rt: usize, val: usize, tf: &mut TrapFrame) { + match rt { + 1 => tf.at = val, + 2 => tf.v0 = val, + 3 => tf.v1 = val, + 4 => tf.a0 = val, + 5 => tf.a1 = val, + 6 => tf.a2 = val, + 7 => tf.a3 = val, + 8 => tf.t0 = val, + 9 => tf.t1 = val, + 10 => tf.t2 = val, + 11 => tf.t3 = val, + 12 => tf.t4 = val, + 13 => tf.t5 = val, + 14 => tf.t6 = val, + 15 => tf.t7 = val, + 16 => tf.s0 = val, + 17 => tf.s1 = val, + 18 => tf.s2 = val, + 19 => tf.s3 = val, + 20 => tf.s4 = val, + 21 => tf.s5 = val, + 22 => tf.s6 = val, + 23 => tf.s7 = val, + 24 => tf.t8 = val, + 25 => tf.t9 = val, + 26 => tf.k0 = val, + 27 => tf.k1 = val, + 28 => tf.gp = val, + 29 => tf.sp = val, + 30 => tf.fp = val, + 31 => tf.ra = val, + _ => { + error!("Unknown register {:?} ", rt); + crate::trap::error(tf) + } + } +} + +fn reserved_inst(tf: &mut TrapFrame) -> bool { + let inst = unsafe { + *(tf.epc as *const usize) + }; + + let opcode = inst >> 26; + let rt = (inst >> 16) & 0b11111; + let rd = (inst >> 11) & 0b11111; + let sel = (inst >> 6) & 0b111; + let format = inst & 0b111111; + + if opcode == 0b011111 && format == 0b111011 { + // RDHWR + if rd == 29 && sel == 0 { + info!("Read TLS by rdhdr"); + extern "C" { + fn _cur_tls(); + } + + let tls = unsafe { + *(_cur_tls as *const usize) + }; + set_trapframe_register(rt, tls, tf); + return true; + } else { + return false; + } + } + + false +} + fn page_fault(tf: &mut TrapFrame) { // TODO: set access/dirty bit let addr = tf.vaddr; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 0787d83..11558d3 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -288,8 +288,15 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { let x86_64_ret = x86_64_syscall(id, args, tf); #[cfg(not(target_arch = "x86_64"))] let x86_64_ret = None; + + #[cfg(target_arch = "mips")] + let mips_ret = mips_syscall(id, args, tf); + #[cfg(not(target_arch = "mips"))] + let mips_ret = None; if let Some(ret) = x86_64_ret { ret + } else if let Some(ret) = mips_ret { + ret } else { error!("unknown syscall id: {}, args: {:x?}", id, args); crate::trap::error(tf); @@ -309,6 +316,27 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { } } +#[cfg(target_arch = "mips")] +fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { + let ret = match id { + SYS_SET_THREAD_AREA => { + extern "C" { + fn _cur_tls(); + } + + unsafe { + asm!("mtc0 $0, $$4, 2": :"r"(args[0])); + *(_cur_tls as *mut usize) = args[0]; + } + Ok(0) + } + _ => { + return None; + } + }; + Some(ret) +} + #[cfg(target_arch = "x86_64")] fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { let ret = match id {