blob: 802ebbb539ae985c944928aa416e259f8e648e09 [file] [log] [blame]
Andrew Walbrandfb73372022-04-21 10:52:27 +00001// Copyright 2022, 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//! Exception handlers.
16
Alice Wang88736462023-07-05 12:14:15 +000017use aarch64_paging::paging::VirtualAddress;
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010018use core::fmt;
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +010019use vmbase::console;
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010020use vmbase::logger;
Alice Wang93ee98a2023-06-08 08:20:39 +000021use vmbase::memory::{page_4kb_of, MemoryTrackerError, MEMORY};
Alice Wang81399f52023-05-26 14:23:43 +000022use vmbase::read_sysreg;
Jakob Vukalovicbff22e12023-04-18 14:50:47 +010023use vmbase::{eprintln, power::reboot};
Andrew Walbrandfb73372022-04-21 10:52:27 +000024
Pierre-Clément Tosi446136e2022-10-19 10:10:42 +010025const UART_PAGE: usize = page_4kb_of(console::BASE_ADDRESS);
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +010026
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010027#[derive(Debug)]
28enum HandleExceptionError {
Jakob Vukalovicb99905d2023-04-20 15:46:02 +010029 PageTableUnavailable,
30 PageTableNotInitialized,
31 InternalError(MemoryTrackerError),
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010032 UnknownException,
33}
34
Jakob Vukalovicb99905d2023-04-20 15:46:02 +010035impl From<MemoryTrackerError> for HandleExceptionError {
36 fn from(other: MemoryTrackerError) -> Self {
37 Self::InternalError(other)
38 }
39}
40
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010041impl fmt::Display for HandleExceptionError {
42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43 match self {
Jakob Vukalovicb99905d2023-04-20 15:46:02 +010044 Self::PageTableUnavailable => write!(f, "Page table is not available."),
45 Self::PageTableNotInitialized => write!(f, "Page table is not initialized."),
46 Self::InternalError(e) => write!(f, "Error while updating page table: {e}"),
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010047 Self::UnknownException => write!(f, "An unknown exception occurred, not handled."),
48 }
49 }
50}
51
52#[derive(Debug, PartialEq, Copy, Clone)]
53enum Esr {
54 DataAbortTranslationFault,
55 DataAbortPermissionFault,
56 DataAbortSyncExternalAbort,
57 Unknown(usize),
58}
59
60impl Esr {
61 const EXT_DABT_32BIT: usize = 0x96000010;
62 const TRANSL_FAULT_BASE_32BIT: usize = 0x96000004;
63 const TRANSL_FAULT_ISS_MASK_32BIT: usize = !0x143;
64 const PERM_FAULT_BASE_32BIT: usize = 0x9600004C;
65 const PERM_FAULT_ISS_MASK_32BIT: usize = !0x103;
66}
67
68impl From<usize> for Esr {
69 fn from(esr: usize) -> Self {
70 if esr == Self::EXT_DABT_32BIT {
71 Self::DataAbortSyncExternalAbort
72 } else if esr & Self::TRANSL_FAULT_ISS_MASK_32BIT == Self::TRANSL_FAULT_BASE_32BIT {
73 Self::DataAbortTranslationFault
74 } else if esr & Self::PERM_FAULT_ISS_MASK_32BIT == Self::PERM_FAULT_BASE_32BIT {
75 Self::DataAbortPermissionFault
76 } else {
77 Self::Unknown(esr)
78 }
79 }
80}
81
82impl fmt::Display for Esr {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 match self {
85 Self::DataAbortSyncExternalAbort => write!(f, "Synchronous external abort"),
86 Self::DataAbortTranslationFault => write!(f, "Translation fault"),
87 Self::DataAbortPermissionFault => write!(f, "Permission fault"),
88 Self::Unknown(v) => write!(f, "Unknown exception esr={v:#08x}"),
89 }
90 }
91}
92
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010093#[inline]
Alice Wang88736462023-07-05 12:14:15 +000094fn handle_translation_fault(far: VirtualAddress) -> Result<(), HandleExceptionError> {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010095 let mut guard = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
96 let memory = guard.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
97 Ok(memory.handle_mmio_fault(far)?)
98}
99
100#[inline]
Alice Wang88736462023-07-05 12:14:15 +0000101fn handle_permission_fault(far: VirtualAddress) -> Result<(), HandleExceptionError> {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100102 let mut guard = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
103 let memory = guard.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
104 Ok(memory.handle_permission_fault(far)?)
105}
106
Alice Wangae9ed2a2023-07-05 11:36:35 +0000107fn handle_exception(exception: &ArmException) -> Result<(), HandleExceptionError> {
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100108 // Handle all translation faults on both read and write, and MMIO guard map
109 // flagged invalid pages or blocks that caused the exception.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100110 // Handle permission faults for DBM flagged entries, and flag them as dirty on write.
Alice Wangae9ed2a2023-07-05 11:36:35 +0000111 match exception.esr {
112 Esr::DataAbortTranslationFault => handle_translation_fault(exception.far),
113 Esr::DataAbortPermissionFault => handle_permission_fault(exception.far),
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100114 _ => Err(HandleExceptionError::UnknownException),
115 }
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100116}
117
Alice Wangae9ed2a2023-07-05 11:36:35 +0000118/// A struct representing an Armv8 exception.
119struct ArmException {
120 /// The value of the exception syndrome register.
Alice Wang0ae33e92023-07-05 11:18:54 +0000121 esr: Esr,
Alice Wang88736462023-07-05 12:14:15 +0000122 /// The faulting virtual address read from the fault address register.
123 far: VirtualAddress,
Alice Wangae9ed2a2023-07-05 11:36:35 +0000124}
125
126impl fmt::Display for ArmException {
127 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alice Wang88736462023-07-05 12:14:15 +0000128 write!(f, "ArmException: esr={}, far={}", self.esr, self.far)
Alice Wangae9ed2a2023-07-05 11:36:35 +0000129 }
130}
131
132impl ArmException {
133 /// Reads the values of the EL1 exception syndrome register (`esr_el1`)
134 /// and fault address register (`far_el1`) and returns a new instance of
135 /// `ArmException` with these values.
136 fn from_el1_regs() -> Self {
137 let esr: Esr = read_sysreg!("esr_el1").into();
138 let far = read_sysreg!("far_el1");
Alice Wang88736462023-07-05 12:14:15 +0000139 Self { esr, far: VirtualAddress(far) }
Alice Wangae9ed2a2023-07-05 11:36:35 +0000140 }
141
142 /// Prints the details of an obj and the exception, excluding UART exceptions.
143 fn print<T: fmt::Display>(&self, exception_name: &str, obj: T, elr: u64) {
144 // Don't print to the UART if we are handling an exception it could raise.
145 if !self.is_uart_exception() {
146 eprintln!("{exception_name}");
147 eprintln!("{obj}");
148 eprintln!("{}, elr={:#08x}", self, elr);
149 }
150 }
151
152 fn is_uart_exception(&self) -> bool {
Alice Wang88736462023-07-05 12:14:15 +0000153 self.esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(self.far.0) == UART_PAGE
Alice Wang8364a482023-07-05 08:06:05 +0000154 }
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100155}
156
Andrew Walbrandfb73372022-04-21 10:52:27 +0000157#[no_mangle]
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000158extern "C" fn sync_exception_current(elr: u64, _spsr: u64) {
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100159 // Disable logging in exception handler to prevent unsafe writes to UART.
160 let _guard = logger::suppress();
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100161
Alice Wangae9ed2a2023-07-05 11:36:35 +0000162 let exception = ArmException::from_el1_regs();
163 if let Err(e) = handle_exception(&exception) {
164 exception.print("sync_exception_current", e, elr);
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100165 reboot()
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +0100166 }
Andrew Walbrandfb73372022-04-21 10:52:27 +0000167}
168
169#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100170extern "C" fn irq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100171 eprintln!("irq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000172 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000173}
174
175#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100176extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100177 eprintln!("fiq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000178 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000179}
180
181#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100182extern "C" fn serr_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000183 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100184 eprintln!("serr_current");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000185 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000186 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000187}
188
189#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100190extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000191 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100192 eprintln!("sync_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000193 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000194 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000195}
196
197#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100198extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100199 eprintln!("irq_lower");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000200 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000201}
202
203#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100204extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100205 eprintln!("fiq_lower");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000206 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000207}
208
209#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100210extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000211 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100212 eprintln!("serr_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000213 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000214 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000215}