diff --git a/nucleus/src/arch/aarch64/traps.rs b/nucleus/src/arch/aarch64/traps.rs index 86f7d33..d198330 100644 --- a/nucleus/src/arch/aarch64/traps.rs +++ b/nucleus/src/arch/aarch64/traps.rs @@ -55,6 +55,7 @@ use { barrier, regs::{RegisterReadOnly, RegisterReadWrite, ESR_EL1, FAR_EL1, VBAR_EL1}, }, + register::{register_bitfields, LocalRegisterCopy}, snafu::Snafu, }; @@ -151,6 +152,152 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { endless_sleep() } +fn cause_to_string(cause: u64) -> &'static str { + if cause == ESR_EL1::EC::DataAbortCurrentEL.read(ESR_EL1::EC) { + "Data Alignment Check" + } else { + "Unknown" + } +} + +register_bitfields! { + u64, + /// ISS structure for Data Abort exceptions + ISS_DA [ + /// Instruction Syndrome Valid. Indicates whether the syndrome information in ISS[23:14] is valid. + /// (This includes SAS, SSE, SRT, SF, and AR) + ISV OFFSET(24) NUMBITS(1) [], + SAS OFFSET(22) NUMBITS(2) [ + Byte = 0b00, + Halfword = 0b01, + Word = 0b10, + DoubleWord = 0b11 + ], + SSE OFFSET(21) NUMBITS(1) [], + SRT OFFSET(16) NUMBITS(5) [], + SF OFFSET(15) NUMBITS(1) [], + AR OFFSET(14) NUMBITS(1) [], + VNCR OFFSET(13) NUMBITS(1) [], + SET OFFSET(11) NUMBITS(2) [ + UER = 0b00, // Recoverable state + UC = 0b10, // Uncontainable + UEO = 0b11 // Restartable state + ], + FNV OFFSET(10) NUMBITS(1) [], + EA OFFSET(9) NUMBITS(1) [], + CM OFFSET(8) NUMBITS(1) [], + S1PTW OFFSET(7) NUMBITS(1) [], + WNR OFFSET(6) NUMBITS(1) [], + DFSC OFFSET(0) NUMBITS(6) [ + /// Address size fault, level 0 of translation or translation table base register. + AddressSizeTL0 = 0b000000, + /// Address size fault, level 1. + AddressSizeTL1 = 0b000001, + ///Address size fault, level 2. + AddressSizeTL2 = 0b000010, + /// Address size fault, level 3. + AddressSizeTL3 = 0b000011, + /// Translation fault, level 0. + TranslationFaultTL0 = 0b000100, + /// Translation fault, level 1. + TranslationFaultTL1 = 0b000101, + /// Translation fault, level 2. + TranslationFaultTL2 = 0b000110, + /// Translation fault, level 3. + TranslationFaultTL3 = 0b000111, + /// Access flag fault, level 1. + AccessFaultTL1 = 0b001001, + /// Access flag fault, level 2. + AccessFaultTL2 = 0b001010, + /// Access flag fault, level 3. + AccessFaultTL3 = 0b001011, + /// Permission fault, level 1. + PermissionFaultTL1 = 0b001101, + /// Permission fault, level 2. + PermissionFaultTL2 = 0b001110, + /// Permission fault, level 3. + PermissionFaultTL3 = 0b001111, + /// Synchronous External abort, not on translation table walk or hardware update of translation table. + SyncExternalAbort = 0b010000, + /// Synchronous Tag Check Fault. + /// (When FEAT_MTE is implemented) + SyncTagCheckFault = 0b010001, + /// Synchronous External abort on translation table walk or hardware update of translation table, level 0. + SyncAbortOnTranslationTL0 = 0b010100, + /// Synchronous External abort on translation table walk or hardware update of translation table, level 1. + SyncAbortOnTranslationTL1 = 0b010101, + /// Synchronous External abort on translation table walk or hardware update of translation table, level 2. + SyncAbortOnTranslationTL2 = 0b010110, + /// Synchronous External abort on translation table walk or hardware update of translation table, level 3. + SyncAbortOnTranslationTL3 = 0b010111, + /// Synchronous parity or ECC error on memory access, not on translation table walk. + /// (When FEAT_RAS is not implemented) + SyncParityError = 0b011000, + /// Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 0. + /// (When FEAT_RAS is not implemented) + SyncParityErrorOnTranslationTL0 = 0b011100, + /// Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 1. + /// (When FEAT_RAS is not implemented) + SyncParityErrorOnTranslationTL1 = 0b011101, + /// Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 2. + /// (When FEAT_RAS is not implemented) + SyncParityErrorOnTranslationTL2 = 0b011110, + /// Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 3. + /// (When FEAT_RAS is not implemented) + SyncParityErrorOnTranslationTL3 = 0b011111, + /// Alignment fault. + AlignmentFault = 0b100001, + /// TLB conflict abort. + TlbConflictAbort = 0b110000, + /// Unsupported atomic hardware update fault. + /// (When FEAT_HAFDBS is implemented) + UnsupportedAtomicUpdate = 0b110001, + /// IMPLEMENTATION DEFINED fault (Lockdown). + Lockdown = 0b110100, + /// IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access). + UnsupportedAccess = 0b110101 + ] + ] +} + +type IssForDataAbort = LocalRegisterCopy; + +fn iss_dfsc_to_string(iss: IssForDataAbort) -> &'static str { + match iss.read_as_enum(ISS_DA::DFSC) { + Some(ISS_DA::DFSC::Value::AddressSizeTL0) => "Address size fault, level 0 of translation or translation table base register", + Some(ISS_DA::DFSC::Value::AddressSizeTL1) => "Address size fault, level 1", + Some(ISS_DA::DFSC::Value::AddressSizeTL2) => "Address size fault, level 2", + Some(ISS_DA::DFSC::Value::AddressSizeTL3) => "Address size fault, level 3", + Some(ISS_DA::DFSC::Value::TranslationFaultTL0) => "Translation fault, level 0", + Some(ISS_DA::DFSC::Value::TranslationFaultTL1) => "Translation fault, level 1", + Some(ISS_DA::DFSC::Value::TranslationFaultTL2) => "Translation fault, level 2", + Some(ISS_DA::DFSC::Value::TranslationFaultTL3) => "Translation fault, level 3", + Some(ISS_DA::DFSC::Value::AccessFaultTL1) => "Access flag fault, level 1", + Some(ISS_DA::DFSC::Value::AccessFaultTL2) => "Access flag fault, level 2", + Some(ISS_DA::DFSC::Value::AccessFaultTL3) => "Access flag fault, level 3", + Some(ISS_DA::DFSC::Value::PermissionFaultTL1) => "Permission fault, level 1", + Some(ISS_DA::DFSC::Value::PermissionFaultTL2) => "Permission fault, level 2", + Some(ISS_DA::DFSC::Value::PermissionFaultTL3) => "Permission fault, level 3", + Some(ISS_DA::DFSC::Value::SyncExternalAbort) => "Synchronous External abort, not on translation table walk or hardware update of translation table", + Some(ISS_DA::DFSC::Value::SyncTagCheckFault) => "Synchronous Tag Check Fault", + Some(ISS_DA::DFSC::Value::SyncAbortOnTranslationTL0) => "Synchronous External abort on translation table walk or hardware update of translation table, level 0", + Some(ISS_DA::DFSC::Value::SyncAbortOnTranslationTL1) => "Synchronous External abort on translation table walk or hardware update of translation table, level 1", + Some(ISS_DA::DFSC::Value::SyncAbortOnTranslationTL2) => "Synchronous External abort on translation table walk or hardware update of translation table, level 2", + Some(ISS_DA::DFSC::Value::SyncAbortOnTranslationTL3) => "Synchronous External abort on translation table walk or hardware update of translation table, level 3", + Some(ISS_DA::DFSC::Value::SyncParityError) => "Synchronous parity or ECC error on memory access, not on translation table walk", + Some(ISS_DA::DFSC::Value::SyncParityErrorOnTranslationTL0) => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 0", + Some(ISS_DA::DFSC::Value::SyncParityErrorOnTranslationTL1) => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 1", + Some(ISS_DA::DFSC::Value::SyncParityErrorOnTranslationTL2) => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 2", + Some(ISS_DA::DFSC::Value::SyncParityErrorOnTranslationTL3) => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 3", + Some(ISS_DA::DFSC::Value::AlignmentFault) => "Alignment fault", + Some(ISS_DA::DFSC::Value::TlbConflictAbort) => "TLB conflict abort", + Some(ISS_DA::DFSC::Value::UnsupportedAtomicUpdate) => "Unsupported atomic hardware update fault", + Some(ISS_DA::DFSC::Value::Lockdown) => "Lockdown (IMPLEMENTATION DEFINED fault)", + Some(ISS_DA::DFSC::Value::UnsupportedAccess) => "Unsupported Exclusive or Atomic access (IMPLEMENTATION DEFINED fault)", + _ => "Unknown", + } +} + // 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); @@ -163,12 +310,62 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { /// Not for production use! fn synchronous_common(e: &mut ExceptionContext) { println!(" ESR_EL1: {:#010x} (syndrome)", ESR_EL1.get()); - println!(" EC: {:#06b} (cause)", ESR_EL1.read(ESR_EL1::EC)); - println!(" FAR_EL1: {:#016x} (location)", FAR_EL1.get()); - println!(" ELR_EL1: {:#010x}", e.elr_el1); + let cause = ESR_EL1.read(ESR_EL1::EC); + println!( + " EC: {:#06b} (cause) -- {}", + cause, + cause_to_string(cause) + ); + + // Print more details about Data Alignment Check + if cause == ESR_EL1::EC::DataAbortCurrentEL.read(ESR_EL1::EC) { + let iss = ESR_EL1.read(ESR_EL1::ISS); + let iss = IssForDataAbort::new(iss); + if iss.is_set(ISS_DA::ISV) { + println!( + " Access size: {} bytes ({}signed) to {}{}", + 2u64.pow(iss.read(ISS_DA::SAS) as u32), + if iss.is_set(ISS_DA::SSE) { "" } else { "un" }, + if iss.is_set(ISS_DA::SF) { "x" } else { "r" }, + iss.read(ISS_DA::SRT) + ); + println!( + " Acq/Rel semantics: {}present", + if iss.is_set(ISS_DA::AR) { "" } else { "not " } + ); + } + // data abort specific encoding + println!( + " {} address {:#016x} ({}valid)", + if iss.is_set(ISS_DA::WNR) { + "Writing to" + } else { + "Reading from" + }, + FAR_EL1.get(), + if iss.is_set(ISS_DA::FNV) { "not " } else { "" } + ); + println!(" Specific fault: {}", iss_dfsc_to_string(iss)); + } else { + println!(" FAR_EL1: {:#016x} (location)", FAR_EL1.get()); + println!(" Stack: {:#016x}", e.spsr_el1); + println!(" ELR_EL1: {:#010x}", e.elr_el1); + } + + println!(" x00: 0000000000000000 x01: {:016x}", e.gpr.x[0]); + + for index in 0..15 { + println!( + " x{:02}: {:016x} x{:02}: {:016x}", + index * 2 + 2, + e.gpr.x[index * 2 + 1], + index * 2 + 3, + e.gpr.x[index * 2 + 2] + ); + } println!( - " Incrementing ELR_EL1 by 4 now to continue with the first \ + " Incrementing ELR_EL1 by 4 to continue with the first \ instruction after the exception!" );