blob: 4d376cd51b4083838647c480703b99af6b479a35 [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 Wang110476e2023-06-07 13:12:21 +000017use crate::memory::MEMORY;
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 Wang110476e2023-06-07 13:12:21 +000021use vmbase::memory::{page_4kb_of, MemoryTrackerError};
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]
94fn handle_translation_fault(far: usize) -> Result<(), HandleExceptionError> {
95 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]
101fn handle_permission_fault(far: usize) -> Result<(), HandleExceptionError> {
102 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
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100107fn handle_exception(esr: Esr, far: usize) -> Result<(), HandleExceptionError> {
108 // 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.
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100111 match esr {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100112 Esr::DataAbortTranslationFault => handle_translation_fault(far),
113 Esr::DataAbortPermissionFault => handle_permission_fault(far),
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100114 _ => Err(HandleExceptionError::UnknownException),
115 }
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100116}
117
118#[inline]
119fn handling_uart_exception(esr: Esr, far: usize) -> bool {
120 esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(far) == UART_PAGE
121}
122
Andrew Walbrandfb73372022-04-21 10:52:27 +0000123#[no_mangle]
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000124extern "C" fn sync_exception_current(elr: u64, _spsr: u64) {
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100125 // Disable logging in exception handler to prevent unsafe writes to UART.
126 let _guard = logger::suppress();
127 let esr: Esr = read_sysreg!("esr_el1").into();
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000128 let far = read_sysreg!("far_el1");
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100129
130 if let Err(e) = handle_exception(esr, far) {
131 // Don't print to the UART if we are handling an exception it could raise.
132 if !handling_uart_exception(esr, far) {
133 eprintln!("sync_exception_current");
134 eprintln!("{e}");
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000135 eprintln!("{esr}, far={far:#08x}, elr={elr:#08x}");
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100136 }
137 reboot()
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +0100138 }
Andrew Walbrandfb73372022-04-21 10:52:27 +0000139}
140
141#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100142extern "C" fn irq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100143 eprintln!("irq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000144 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000145}
146
147#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100148extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100149 eprintln!("fiq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000150 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000151}
152
153#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100154extern "C" fn serr_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000155 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100156 eprintln!("serr_current");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000157 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000158 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000159}
160
161#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100162extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000163 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100164 eprintln!("sync_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000165 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000166 reboot();
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_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100171 eprintln!("irq_lower");
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_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100177 eprintln!("fiq_lower");
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_lower(_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_lower");
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}