blob: 11fcd9398790ece381378b4552ef36fad020290a [file] [log] [blame]
Alice Wanga9fe1fb2023-07-04 09:10:35 +00001// 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
17use crate::{
Pierre-Clément Tosi38a36212024-06-06 11:30:39 +010018 eprintln,
19 layout::UART_PAGE_ADDR,
Alice Wanga9fe1fb2023-07-04 09:10:35 +000020 memory::{page_4kb_of, MemoryTrackerError},
21 read_sysreg,
22};
23use aarch64_paging::paging::VirtualAddress;
24use core::fmt;
25
Alice Wanga9fe1fb2023-07-04 09:10:35 +000026/// Represents an error that can occur while handling an exception.
27#[derive(Debug)]
28pub enum HandleExceptionError {
29 /// The page table is unavailable.
30 PageTableUnavailable,
31 /// The page table has not been initialized.
32 PageTableNotInitialized,
33 /// An internal error occurred in the memory tracker.
34 InternalError(MemoryTrackerError),
35 /// An unknown exception occurred.
36 UnknownException,
37}
38
39impl From<MemoryTrackerError> for HandleExceptionError {
40 fn from(other: MemoryTrackerError) -> Self {
41 Self::InternalError(other)
42 }
43}
44
45impl fmt::Display for HandleExceptionError {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47 match self {
48 Self::PageTableUnavailable => write!(f, "Page table is not available."),
49 Self::PageTableNotInitialized => write!(f, "Page table is not initialized."),
50 Self::InternalError(e) => write!(f, "Error while updating page table: {e}"),
51 Self::UnknownException => write!(f, "An unknown exception occurred, not handled."),
52 }
53 }
54}
55
56/// Represents the possible types of exception syndrome register (ESR) values.
57#[derive(Debug, PartialEq, Copy, Clone)]
58pub enum Esr {
59 /// Data abort due to translation fault.
60 DataAbortTranslationFault,
61 /// Data abort due to permission fault.
62 DataAbortPermissionFault,
63 /// Data abort due to a synchronous external abort.
64 DataAbortSyncExternalAbort,
65 /// An unknown ESR value.
66 Unknown(usize),
67}
68
69impl Esr {
70 const EXT_DABT_32BIT: usize = 0x96000010;
71 const TRANSL_FAULT_BASE_32BIT: usize = 0x96000004;
72 const TRANSL_FAULT_ISS_MASK_32BIT: usize = !0x143;
73 const PERM_FAULT_BASE_32BIT: usize = 0x9600004C;
74 const PERM_FAULT_ISS_MASK_32BIT: usize = !0x103;
75}
76
77impl From<usize> for Esr {
78 fn from(esr: usize) -> Self {
79 if esr == Self::EXT_DABT_32BIT {
80 Self::DataAbortSyncExternalAbort
81 } else if esr & Self::TRANSL_FAULT_ISS_MASK_32BIT == Self::TRANSL_FAULT_BASE_32BIT {
82 Self::DataAbortTranslationFault
83 } else if esr & Self::PERM_FAULT_ISS_MASK_32BIT == Self::PERM_FAULT_BASE_32BIT {
84 Self::DataAbortPermissionFault
85 } else {
86 Self::Unknown(esr)
87 }
88 }
89}
90
91impl fmt::Display for Esr {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 match self {
94 Self::DataAbortSyncExternalAbort => write!(f, "Synchronous external abort"),
95 Self::DataAbortTranslationFault => write!(f, "Translation fault"),
96 Self::DataAbortPermissionFault => write!(f, "Permission fault"),
97 Self::Unknown(v) => write!(f, "Unknown exception esr={v:#08x}"),
98 }
99 }
100}
101/// A struct representing an Armv8 exception.
102pub struct ArmException {
103 /// The value of the exception syndrome register.
104 pub esr: Esr,
105 /// The faulting virtual address read from the fault address register.
106 pub far: VirtualAddress,
107}
108
109impl fmt::Display for ArmException {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 write!(f, "ArmException: esr={}, far={}", self.esr, self.far)
112 }
113}
114
115impl ArmException {
116 /// Reads the values of the EL1 exception syndrome register (`esr_el1`)
117 /// and fault address register (`far_el1`) and returns a new instance of
118 /// `ArmException` with these values.
119 pub fn from_el1_regs() -> Self {
120 let esr: Esr = read_sysreg!("esr_el1").into();
121 let far = read_sysreg!("far_el1");
122 Self { esr, far: VirtualAddress(far) }
123 }
124
125 /// Prints the details of an obj and the exception, excluding UART exceptions.
126 pub fn print<T: fmt::Display>(&self, exception_name: &str, obj: T, elr: u64) {
127 // Don't print to the UART if we are handling an exception it could raise.
128 if !self.is_uart_exception() {
129 eprintln!("{exception_name}");
130 eprintln!("{obj}");
131 eprintln!("{}, elr={:#08x}", self, elr);
132 }
133 }
134
135 fn is_uart_exception(&self) -> bool {
Pierre-Clément Tosi38a36212024-06-06 11:30:39 +0100136 self.esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(self.far.0) == UART_PAGE_ADDR
Alice Wanga9fe1fb2023-07-04 09:10:35 +0000137 }
138}