1 // Copyright 2023, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! Helper functions and structs for exception handlers. 16 17 use crate::{ 18 console, eprintln, 19 memory::{page_4kb_of, MemoryTrackerError}, 20 read_sysreg, 21 }; 22 use aarch64_paging::paging::VirtualAddress; 23 use core::fmt; 24 25 const UART_PAGE: usize = page_4kb_of(console::BASE_ADDRESS); 26 27 /// Represents an error that can occur while handling an exception. 28 #[derive(Debug)] 29 pub enum HandleExceptionError { 30 /// The page table is unavailable. 31 PageTableUnavailable, 32 /// The page table has not been initialized. 33 PageTableNotInitialized, 34 /// An internal error occurred in the memory tracker. 35 InternalError(MemoryTrackerError), 36 /// An unknown exception occurred. 37 UnknownException, 38 } 39 40 impl From<MemoryTrackerError> for HandleExceptionError { from(other: MemoryTrackerError) -> Self41 fn from(other: MemoryTrackerError) -> Self { 42 Self::InternalError(other) 43 } 44 } 45 46 impl fmt::Display for HandleExceptionError { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 match self { 49 Self::PageTableUnavailable => write!(f, "Page table is not available."), 50 Self::PageTableNotInitialized => write!(f, "Page table is not initialized."), 51 Self::InternalError(e) => write!(f, "Error while updating page table: {e}"), 52 Self::UnknownException => write!(f, "An unknown exception occurred, not handled."), 53 } 54 } 55 } 56 57 /// Represents the possible types of exception syndrome register (ESR) values. 58 #[derive(Debug, PartialEq, Copy, Clone)] 59 pub enum Esr { 60 /// Data abort due to translation fault. 61 DataAbortTranslationFault, 62 /// Data abort due to permission fault. 63 DataAbortPermissionFault, 64 /// Data abort due to a synchronous external abort. 65 DataAbortSyncExternalAbort, 66 /// An unknown ESR value. 67 Unknown(usize), 68 } 69 70 impl Esr { 71 const EXT_DABT_32BIT: usize = 0x96000010; 72 const TRANSL_FAULT_BASE_32BIT: usize = 0x96000004; 73 const TRANSL_FAULT_ISS_MASK_32BIT: usize = !0x143; 74 const PERM_FAULT_BASE_32BIT: usize = 0x9600004C; 75 const PERM_FAULT_ISS_MASK_32BIT: usize = !0x103; 76 } 77 78 impl From<usize> for Esr { from(esr: usize) -> Self79 fn from(esr: usize) -> Self { 80 if esr == Self::EXT_DABT_32BIT { 81 Self::DataAbortSyncExternalAbort 82 } else if esr & Self::TRANSL_FAULT_ISS_MASK_32BIT == Self::TRANSL_FAULT_BASE_32BIT { 83 Self::DataAbortTranslationFault 84 } else if esr & Self::PERM_FAULT_ISS_MASK_32BIT == Self::PERM_FAULT_BASE_32BIT { 85 Self::DataAbortPermissionFault 86 } else { 87 Self::Unknown(esr) 88 } 89 } 90 } 91 92 impl fmt::Display for Esr { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 94 match self { 95 Self::DataAbortSyncExternalAbort => write!(f, "Synchronous external abort"), 96 Self::DataAbortTranslationFault => write!(f, "Translation fault"), 97 Self::DataAbortPermissionFault => write!(f, "Permission fault"), 98 Self::Unknown(v) => write!(f, "Unknown exception esr={v:#08x}"), 99 } 100 } 101 } 102 /// A struct representing an Armv8 exception. 103 pub struct ArmException { 104 /// The value of the exception syndrome register. 105 pub esr: Esr, 106 /// The faulting virtual address read from the fault address register. 107 pub far: VirtualAddress, 108 } 109 110 impl fmt::Display for ArmException { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 112 write!(f, "ArmException: esr={}, far={}", self.esr, self.far) 113 } 114 } 115 116 impl ArmException { 117 /// Reads the values of the EL1 exception syndrome register (`esr_el1`) 118 /// and fault address register (`far_el1`) and returns a new instance of 119 /// `ArmException` with these values. from_el1_regs() -> Self120 pub fn from_el1_regs() -> Self { 121 let esr: Esr = read_sysreg!("esr_el1").into(); 122 let far = read_sysreg!("far_el1"); 123 Self { esr, far: VirtualAddress(far) } 124 } 125 126 /// Prints the details of an obj and the exception, excluding UART exceptions. print<T: fmt::Display>(&self, exception_name: &str, obj: T, elr: u64)127 pub fn print<T: fmt::Display>(&self, exception_name: &str, obj: T, elr: u64) { 128 // Don't print to the UART if we are handling an exception it could raise. 129 if !self.is_uart_exception() { 130 eprintln!("{exception_name}"); 131 eprintln!("{obj}"); 132 eprintln!("{}, elr={:#08x}", self, elr); 133 } 134 } 135 is_uart_exception(&self) -> bool136 fn is_uart_exception(&self) -> bool { 137 self.esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(self.far.0) == UART_PAGE 138 } 139 } 140