diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index a96b1bd..586ace7 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -3,6 +3,7 @@ mod boot; mod memory; pub mod mmu; +pub mod traps; pub use self::memory::{PhysicalAddress, VirtualAddress}; pub use mmu::*; diff --git a/src/arch/aarch64/traps.rs b/src/arch/aarch64/traps.rs index 262a57b..7ffcf24 100644 --- a/src/arch/aarch64/traps.rs +++ b/src/arch/aarch64/traps.rs @@ -1,39 +1,41 @@ // Interrupt handling - // The base address is given by VBAR_ELn and each entry has a defined offset from this // base address. Each table has 16 entries, with each entry being 128 bytes (32 instructions) // in size. The table effectively consists of 4 sets of 4 entries. -VBAR_EL1, VBAR_EL2, VBAR_EL3 +// Minimal implementation to help catch MMU traps +// Reads ESR_ELx to understand why trap was taken. -CurrentEL with SP0: +0x0 +// VBAR_EL1, VBAR_EL2, VBAR_EL3 - Synchronous - IRQ/vIRQ - FIQ - SError/vSError +// CurrentEL with SP0: +0x0 -CurrentEL with SPx: +0x200 +// Synchronous +// IRQ/vIRQ +// FIQ +// SError/vSError - Synchronous - IRQ/vIRQ - FIQ - SError/vSError +// CurrentEL with SPx: +0x200 -Lower EL using AArch64: +0x400 +// Synchronous +// IRQ/vIRQ +// FIQ +// SError/vSError - Synchronous - IRQ/vIRQ - FIQ - SError/vSError +// Lower EL using AArch64: +0x400 -Lower EL using AArch32: +0x600 +// Synchronous +// IRQ/vIRQ +// FIQ +// SError/vSError - Synchronous - IRQ/vIRQ - FIQ - SError/vSError +// Lower EL using AArch32: +0x600 + +// Synchronous +// IRQ/vIRQ +// FIQ +// SError/vSError // When the processor takes an exception to AArch64 execution state, // all of the PSTATE interrupt masks is set automatically. This means @@ -41,4 +43,79 @@ Lower EL using AArch32: +0x600 // nested exceptions, for example, to allow a higher priority interrupt // to interrupt the handling of a lower priority source, then software needs // to explicitly re-enable interrupts +use cortex_a::{barrier, regs}; +use register::cpu::RegisterReadWrite; +global_asm!(include_str!("vectors.S")); + +pub unsafe fn set_vbar_el1_checked(vec_base_addr: u64) -> bool { + if vec_base_addr.trailing_zeros() < 11 { + false + } else { + regs::VBAR_EL1.set(vec_base_addr); + + // Force VBAR update to complete before next instruction. + barrier::isb(barrier::SY); + + true + } +} + +#[repr(C)] +pub struct GPR { + x: [u64; 31], +} + +#[repr(C)] +pub struct ExceptionContext { + // General Purpose Registers + gpr: GPR, + spsr_el1: u64, + elr_el1: u64, +} + +/// The default exception, invoked for every exception type unless the handler +/// is overwritten. +#[no_mangle] +unsafe extern "C" fn default_exception_handler() { + // println!("Unexpected exception. Halting CPU."); + + loop { + cortex_a::asm::wfe() + } +} + +// To implement an exception handler, overwrite it by defining the respective +// function below. +// Don't forget the #[no_mangle] attribute. +// +// unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext); +// unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext); +// unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext); + +// unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext); +// unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext); +// unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext); + +// unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext); +// unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext); +// unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext); + +// unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext); +// unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext); +// unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext); + +#[no_mangle] +unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { + // println!("[!] A synchronous exception happened."); + // println!(" ELR_EL1: {:#010X}", e.elr_el1); + // println!( + // " Incrementing ELR_EL1 by 4 now to continue with the first \ + // instruction after the exception!" + // ); + + e.elr_el1 += 4; + + // println!(" ELR_EL1 modified: {:#010X}", e.elr_el1); + // println!(" Returning from exception...\n"); +} diff --git a/src/arch/aarch64/vectors.S b/src/arch/aarch64/vectors.S new file mode 100644 index 0000000..b2f294c --- /dev/null +++ b/src/arch/aarch64/vectors.S @@ -0,0 +1,113 @@ +// +// MIT License +// +// Copyright (c) 2018-2019 Andre Richter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +.macro SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE handler +.balign 0x80 + + sub sp, sp, #16 * 17 + + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + + mrs x1, SPSR_EL1 + mrs x2, ELR_EL1 + + stp x30, x1, [sp, #16 * 15] + str x2, [sp, #16 * 16] + + mov x0, sp + bl \handler + b __restore_context +.endm + +.macro FIQ_DUMMY +.balign 0x80 +1: wfe + b 1b +.endm + +// The vector definitions +.section .vectors, "ax" +.global __exception_vectors_start +__exception_vectors_start: + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_synchronous // 0x000 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_irq // 0x080 + FIQ_DUMMY // 0x100 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_serror // 0x180 + + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_synchronous // 0x200 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_irq // 0x280 + FIQ_DUMMY // 0x300 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_serror // 0x380 + + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_synchronous // 0x400 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_irq // 0x480 + FIQ_DUMMY // 0x500 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_serror // 0x580 + + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_synchronous // 0x600 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_irq // 0x680 + FIQ_DUMMY // 0x700 + SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_serror // 0x780 + +.global __restore_context +__restore_context: + ldr x19, [sp, #16 * 16] + ldp x30, x20, [sp, #16 * 15] + + msr ELR_EL1, x19 + msr SPSR_EL1, x20 + + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + + add sp, sp, #16 * 17 + + eret