diff --git a/kernel/src/arch/aarch64/context.rs b/kernel/src/arch/aarch64/context.rs deleted file mode 100644 index 4ca8b56..0000000 --- a/kernel/src/arch/aarch64/context.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Trapframe and context definitions for aarch64. - -/// TODO -#[repr(C)] -#[derive(Debug)] -pub struct TrapFrame { - // TODO -} - -///TODO -#[derive(Debug)] -pub struct Context { - // TODO -} - -impl Context { - /// TODO - #[inline(never)] - pub unsafe extern fn switch(&mut self, target: &mut Self) { - unimplemented!() - } - - /// TODO - pub unsafe fn null() -> Self { - unimplemented!() - } - - /// TODO - pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, cr3: usize) -> Self { - unimplemented!() - } - - /// TODO - pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize) -> Self { - unimplemented!() - } - - /// TODO - pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { - unimplemented!() - } -} - -#[inline(always)] -pub unsafe fn enable() { - unimplemented!() -} - -#[inline(always)] -pub unsafe fn disable() { - unimplemented!() -} - -#[inline(always)] -pub unsafe fn disable_and_store() -> usize { - unimplemented!() -} - -#[inline(always)] -pub unsafe fn restore(flags: usize) { - unimplemented!() -} diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs new file mode 100644 index 0000000..06a9bd5 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -0,0 +1,60 @@ +//! TrapFrame and context definitions for aarch64. + +#[repr(C)] +#[derive(Default, Debug, Copy, Clone)] +pub struct TrapFrame { + pub elr: u64, + pub spsr: u64, + pub sp: u64, + pub tpidr: u64, + // pub q0to31: [u128; 32], // disable SIMD/FP registers + pub x1to29: [u64; 29], + pub __reserved: u64, + pub x30: u64, // lr + pub x0: u64, +} + +///TODO +#[derive(Debug)] +pub struct Context { + // TODO +} + +impl Context { + /// TODO + #[inline(never)] + pub unsafe extern "C" fn switch(&mut self, target: &mut Self) { + unimplemented!() + } + + /// TODO + pub unsafe fn null() -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_kernel_thread( + entry: extern "C" fn(usize) -> !, + arg: usize, + kstack_top: usize, + cr3: usize, + ) -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_user_thread( + entry_addr: usize, + ustack_top: usize, + kstack_top: usize, + is32: bool, + cr3: usize, + ) -> Self { + unimplemented!() + } + + /// TODO + pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { + unimplemented!() + } +} diff --git a/kernel/src/arch/aarch64/interrupt/handler.rs b/kernel/src/arch/aarch64/interrupt/handler.rs new file mode 100644 index 0000000..371d4d1 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/handler.rs @@ -0,0 +1,67 @@ +//! Trap handler + +use super::context::TrapFrame; +use super::syndrome::Syndrome; + +global_asm!(include_str!("trap.S")); +global_asm!(include_str!("vector.S")); + +#[repr(u16)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum Kind { + Synchronous = 0, + Irq = 1, + Fiq = 2, + SError = 3, +} + +#[repr(u16)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum Source { + CurrentSpEl0 = 0, + CurrentSpElx = 1, + LowerAArch64 = 2, + LowerAArch32 = 3, +} + +#[repr(C)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub struct Info { + source: Source, + kind: Kind, +} + +/// This function is called when an exception occurs. The `info` parameter +/// specifies the source and kind of exception that has occurred. The `esr` is +/// the value of the exception syndrome register. Finally, `tf` is a pointer to +/// the trap frame for the exception. +#[no_mangle] +pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) { + let syndrome = Syndrome::from(esr); + trace!("Interrupt: {:?} from: {:?}", syndrome, info); + match info.kind { + Kind::Synchronous => { + // syndrome is only valid with sync + match syndrome { + Syndrome::Brk(brk) => handle_break(brk, tf), + Syndrome::Svc(syscall) => handle_syscall(syscall, tf), + _ => ::trap::error(tf), + } + } + Kind::Irq => { + // TODO + } + _ => ::trap::error(tf), + } + ::trap::before_return(); + trace!("Interrupt end"); +} + +fn handle_break(num: u16, tf: &mut TrapFrame) { + tf.elr += 4; // Skip the current brk instruction +} + +fn handle_syscall(num: u16, tf: &mut TrapFrame) { + // svc instruction has been skipped in syscall + println!("syscall {}", num); +} diff --git a/kernel/src/arch/aarch64/interrupt.rs b/kernel/src/arch/aarch64/interrupt/mod.rs similarity index 70% rename from kernel/src/arch/aarch64/interrupt.rs rename to kernel/src/arch/aarch64/interrupt/mod.rs index 1566afd..5181cb5 100644 --- a/kernel/src/arch/aarch64/interrupt.rs +++ b/kernel/src/arch/aarch64/interrupt/mod.rs @@ -1,14 +1,20 @@ -//! Interrupt handler implementation on raspi3. +//! Interrupt and exception for aarch64. -pub use self::context::*; - -#[path = "context.rs"] +mod handler; mod context; +mod syndrome; -/// Initialize the trap to enable the interrupt. +pub use self::context::*; +pub use self::handler::*; + +/// Set the exception vector address pub fn init() { - // TODO - // info!("interrupt: init end"); + unsafe { + asm!( + "adr x0, __vectors; + msr vbar_el1, x0" + ); + } } /// Enable the interrupt. diff --git a/kernel/src/arch/aarch64/interrupt/syndrome.rs b/kernel/src/arch/aarch64/interrupt/syndrome.rs new file mode 100644 index 0000000..d466a5d --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/syndrome.rs @@ -0,0 +1,108 @@ +//! Exception syndrome from ESR + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum Fault { + AddressSize, + Translation, + AccessFlag, + Permission, + Alignment, + TlbConflict, + Other(u8), +} + +impl From for Fault { + fn from(val: u32) -> Fault { + use self::Fault::*; + + // IFSC or DFSC bits (ref: D10.2.39, Page 2457~2464). + match val & 0b111100 { + 0b000000 => AddressSize, + 0b000100 => Translation, + 0b001000 => AccessFlag, + 0b001100 => Permission, + 0b100000 => Alignment, + 0b110000 => TlbConflict, + _ => Other((val & 0b111111) as u8), + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum Syndrome { + Unknown, + WfiWfe, + McrMrc, + McrrMrrc, + LdcStc, + SimdFp, + Vmrs, + Mrrc, + IllegalExecutionState, + Svc(u16), + Hvc(u16), + Smc(u16), + MsrMrsSystem, + InstructionAbort { kind: Fault, level: u8 }, + PCAlignmentFault, + DataAbort { kind: Fault, level: u8 }, + SpAlignmentFault, + TrappedFpu, + SError, + Breakpoint, + Step, + Watchpoint, + Brk(u16), + Other(u32), +} + +/// Converts a raw syndrome value (ESR) into a `Syndrome` (ref: D1.10.4, D10.2.39). +impl From for Syndrome { + fn from(esr: u32) -> Syndrome { + use self::Syndrome::*; + + let ec = esr >> 26; + let iss = esr & 0xFFFFFF; + + match ec { + 0b000000 => Unknown, + 0b000001 => WfiWfe, + 0b000011 => McrMrc, + 0b000100 => McrrMrrc, + 0b000101 => McrMrc, + 0b000110 => LdcStc, + 0b000111 => SimdFp, + 0b001000 => Vmrs, + 0b001100 => Mrrc, + 0b001110 => IllegalExecutionState, + 0b010001 => Svc((iss & 0xFFFF) as u16), + 0b010010 => Hvc((iss & 0xFFFF) as u16), + 0b010011 => Smc((iss & 0xFFFF) as u16), + 0b010101 => Svc((iss & 0xFFFF) as u16), + 0b010110 => Hvc((iss & 0xFFFF) as u16), + 0b010111 => Smc((iss & 0xFFFF) as u16), + 0b011000 => MsrMrsSystem, + 0b100000 | 0b100001 => InstructionAbort { + kind: Fault::from(iss), + level: (iss & 0b11) as u8, + }, + 0b100010 => PCAlignmentFault, + 0b100100 | 0b100101 => DataAbort { + kind: Fault::from(iss), + level: (iss & 0b11) as u8, + }, + 0b100110 => SpAlignmentFault, + 0b101000 => TrappedFpu, + 0b101100 => TrappedFpu, + 0b101111 => SError, + 0b110000 => Breakpoint, + 0b110001 => Breakpoint, + 0b110010 => Step, + 0b110011 => Step, + 0b110100 => Watchpoint, + 0b110101 => Watchpoint, + 0b111100 => Brk((iss & 0xFFFF) as u16), + other => Other(other), + } + } +} diff --git a/kernel/src/arch/aarch64/interrupt/trap.S b/kernel/src/arch/aarch64/interrupt/trap.S new file mode 100644 index 0000000..fb51110 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/trap.S @@ -0,0 +1,103 @@ +.section .text + +.macro SAVE_ALL + # lr, x0 is saved in HANDLER + str x29, [sp, #-16]! + stp x27, x28, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x19, x20, [sp, #-16]! + stp x17, x18, [sp, #-16]! + stp x15, x16, [sp, #-16]! + stp x13, x14, [sp, #-16]! + stp x11, x12, [sp, #-16]! + stp x9, x10, [sp, #-16]! + stp x7, x8, [sp, #-16]! + stp x5, x6, [sp, #-16]! + stp x3, x4, [sp, #-16]! + stp x1, x2, [sp, #-16]! + + # stp q30, q31, [sp, #-32]! + # stp q28, q29, [sp, #-32]! + # stp q26, q27, [sp, #-32]! + # stp q24, q25, [sp, #-32]! + # stp q22, q23, [sp, #-32]! + # stp q20, q21, [sp, #-32]! + # stp q18, q19, [sp, #-32]! + # stp q16, q17, [sp, #-32]! + # stp q14, q15, [sp, #-32]! + # stp q12, q13, [sp, #-32]! + # stp q10, q11, [sp, #-32]! + # stp q8, q9, [sp, #-32]! + # stp q6, q7, [sp, #-32]! + # stp q4, q5, [sp, #-32]! + # stp q2, q3, [sp, #-32]! + # stp q0, q1, [sp, #-32]! + + mrs x2, tpidr_el0 + mrs x1, sp_el0 + stp x1, x2, [sp, #-16]! + + mrs x2, spsr_el1 + mrs x1, elr_el1 + stp x1, x2, [sp, #-16]! +.endm + +.macro RESTORE_ALL + ldp x1, x2, [sp], #16 + msr elr_el1, x1 + msr spsr_el1, x2 + + ldp x1, x2, [sp], #16 + msr sp_el0, x1 + msr tpidr_el0, x2 + + # ldp q0, q1, [sp], #32 + # ldp q2, q3, [sp], #32 + # ldp q4, q5, [sp], #32 + # ldp q6, q7, [sp], #32 + # ldp q8, q9, [sp], #32 + # ldp q10, q11, [sp], #32 + # ldp q12, q13, [sp], #32 + # ldp q14, q15, [sp], #32 + # ldp q16, q17, [sp], #32 + # ldp q18, q19, [sp], #32 + # ldp q20, q21, [sp], #32 + # ldp q22, q23, [sp], #32 + # ldp q24, q25, [sp], #32 + # ldp q26, q27, [sp], #32 + # ldp q28, q29, [sp], #32 + # ldp q30, q31, [sp], #32 + + ldp x1, x2, [sp], #16 + ldp x3, x4, [sp], #16 + ldp x5, x6, [sp], #16 + ldp x7, x8, [sp], #16 + ldp x9, x10, [sp], #16 + ldp x11, x12, [sp], #16 + ldp x13, x14, [sp], #16 + ldp x15, x16, [sp], #16 + ldp x17, x18, [sp], #16 + ldp x19, x20, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x27, x28, [sp], #16 + ldr x29, [sp], #16 + ldp lr, x0, [sp], #16 +.endm + +.global __alltraps +__alltraps: + SAVE_ALL + + # x0 is set in HANDLER + mrs x1, esr_el1 + mov x2, sp + bl rust_trap + +.global trap_ret +trap_ret: + RESTORE_ALL + eret diff --git a/kernel/src/arch/aarch64/interrupt/vector.S b/kernel/src/arch/aarch64/interrupt/vector.S new file mode 100644 index 0000000..3a749f9 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupt/vector.S @@ -0,0 +1,29 @@ +.section .text + +.macro HANDLER source kind + .align 7 + stp lr, x0, [sp, #-16]! + mov x0, #\source + movk x0, #\kind, lsl #16 + b __alltraps +.endm + +.global __vectors +.align 11 +__vectors: + HANDLER 0 0 + HANDLER 0 1 + HANDLER 0 2 + HANDLER 0 3 + HANDLER 1 0 + HANDLER 1 1 + HANDLER 1 2 + HANDLER 1 3 + HANDLER 2 0 + HANDLER 2 1 + HANDLER 2 2 + HANDLER 2 3 + HANDLER 3 0 + HANDLER 3 1 + HANDLER 3 2 + HANDLER 3 3 diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index f668a25..8353324 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -19,6 +19,7 @@ pub extern "C" fn rust_main() -> ! { // First init log mod, so that we can print log info. // FIXME // ::logging::init(); + interrupt::init(); super::fs::show_logo(); @@ -30,6 +31,14 @@ pub extern "C" fn rust_main() -> ! { '\u{7f}' => { print!("\u{7f}"); } + 'b' => unsafe { + println!("brk 233"); + asm!("brk 233"); + }, + 'c' => unsafe { + println!("svc 666"); + asm!("svc 666"); + }, ' '...'\u{7e}' => { print!("{}", c); }