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