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 eprintln,
19 layout::UART_PAGE_ADDR,
20 memory::{page_4kb_of, MemoryTrackerError, MEMORY},
21 read_sysreg,
22 };
23 use aarch64_paging::paging::VirtualAddress;
24 use core::fmt;
25 use core::result;
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_ADDR
138 }
139 }
140
141 /// Handles a translation fault with the given fault address register (FAR).
142 #[inline]
handle_translation_fault(far: VirtualAddress) -> result::Result<(), HandleExceptionError>143 pub fn handle_translation_fault(far: VirtualAddress) -> result::Result<(), HandleExceptionError> {
144 let mut guard = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
145 let memory = guard.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
146 Ok(memory.handle_mmio_fault(far)?)
147 }
148
149 /// Handles a permission fault with the given fault address register (FAR).
150 #[inline]
handle_permission_fault(far: VirtualAddress) -> result::Result<(), HandleExceptionError>151 pub fn handle_permission_fault(far: VirtualAddress) -> result::Result<(), HandleExceptionError> {
152 let mut guard = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
153 let memory = guard.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
154 Ok(memory.handle_permission_fault(far)?)
155 }
156