blob: 430b524bef7b99df72405034a867e01e12399322 [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
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010017use core::fmt;
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +010018use vmbase::console;
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010019use vmbase::logger;
Alice Wang93ee98a2023-06-08 08:20:39 +000020use vmbase::memory::{page_4kb_of, MemoryTrackerError, MEMORY};
Alice Wang81399f52023-05-26 14:23:43 +000021use vmbase::read_sysreg;
Jakob Vukalovicbff22e12023-04-18 14:50:47 +010022use vmbase::{eprintln, power::reboot};
Andrew Walbrandfb73372022-04-21 10:52:27 +000023
Pierre-Clément Tosi446136e2022-10-19 10:10:42 +010024const UART_PAGE: usize = page_4kb_of(console::BASE_ADDRESS);
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +010025
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010026#[derive(Debug)]
27enum HandleExceptionError {
Jakob Vukalovicb99905d2023-04-20 15:46:02 +010028 PageTableUnavailable,
29 PageTableNotInitialized,
30 InternalError(MemoryTrackerError),
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010031 UnknownException,
32}
33
Jakob Vukalovicb99905d2023-04-20 15:46:02 +010034impl From<MemoryTrackerError> for HandleExceptionError {
35 fn from(other: MemoryTrackerError) -> Self {
36 Self::InternalError(other)
37 }
38}
39
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010040impl fmt::Display for HandleExceptionError {
41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42 match self {
Jakob Vukalovicb99905d2023-04-20 15:46:02 +010043 Self::PageTableUnavailable => write!(f, "Page table is not available."),
44 Self::PageTableNotInitialized => write!(f, "Page table is not initialized."),
45 Self::InternalError(e) => write!(f, "Error while updating page table: {e}"),
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010046 Self::UnknownException => write!(f, "An unknown exception occurred, not handled."),
47 }
48 }
49}
50
51#[derive(Debug, PartialEq, Copy, Clone)]
52enum Esr {
53 DataAbortTranslationFault,
54 DataAbortPermissionFault,
55 DataAbortSyncExternalAbort,
56 Unknown(usize),
57}
58
59impl Esr {
60 const EXT_DABT_32BIT: usize = 0x96000010;
61 const TRANSL_FAULT_BASE_32BIT: usize = 0x96000004;
62 const TRANSL_FAULT_ISS_MASK_32BIT: usize = !0x143;
63 const PERM_FAULT_BASE_32BIT: usize = 0x9600004C;
64 const PERM_FAULT_ISS_MASK_32BIT: usize = !0x103;
65}
66
67impl From<usize> for Esr {
68 fn from(esr: usize) -> Self {
69 if esr == Self::EXT_DABT_32BIT {
70 Self::DataAbortSyncExternalAbort
71 } else if esr & Self::TRANSL_FAULT_ISS_MASK_32BIT == Self::TRANSL_FAULT_BASE_32BIT {
72 Self::DataAbortTranslationFault
73 } else if esr & Self::PERM_FAULT_ISS_MASK_32BIT == Self::PERM_FAULT_BASE_32BIT {
74 Self::DataAbortPermissionFault
75 } else {
76 Self::Unknown(esr)
77 }
78 }
79}
80
81impl fmt::Display for Esr {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 match self {
84 Self::DataAbortSyncExternalAbort => write!(f, "Synchronous external abort"),
85 Self::DataAbortTranslationFault => write!(f, "Translation fault"),
86 Self::DataAbortPermissionFault => write!(f, "Permission fault"),
87 Self::Unknown(v) => write!(f, "Unknown exception esr={v:#08x}"),
88 }
89 }
90}
91
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010092#[inline]
93fn handle_translation_fault(far: usize) -> Result<(), HandleExceptionError> {
94 let mut guard = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
95 let memory = guard.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
96 Ok(memory.handle_mmio_fault(far)?)
97}
98
99#[inline]
100fn handle_permission_fault(far: usize) -> Result<(), HandleExceptionError> {
101 let mut guard = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
102 let memory = guard.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
103 Ok(memory.handle_permission_fault(far)?)
104}
105
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100106fn handle_exception(esr: Esr, far: usize) -> Result<(), HandleExceptionError> {
107 // Handle all translation faults on both read and write, and MMIO guard map
108 // flagged invalid pages or blocks that caused the exception.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100109 // Handle permission faults for DBM flagged entries, and flag them as dirty on write.
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100110 match esr {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100111 Esr::DataAbortTranslationFault => handle_translation_fault(far),
112 Esr::DataAbortPermissionFault => handle_permission_fault(far),
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100113 _ => Err(HandleExceptionError::UnknownException),
114 }
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100115}
116
Alice Wang8364a482023-07-05 08:06:05 +0000117/// Prints the details of an exception failure, excluding UART exceptions.
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100118#[inline]
Alice Wang8364a482023-07-05 08:06:05 +0000119fn print_exception_failure(esr: Esr, far: usize, elr: u64, e: HandleExceptionError) {
120 let is_uart_exception = esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(far) == UART_PAGE;
121 // Don't print to the UART if we are handling an exception it could raise.
122 if !is_uart_exception {
123 eprintln!("sync_exception_current");
124 eprintln!("{e}");
125 eprintln!("{esr}, far={far:#08x}, elr={elr:#08x}");
126 }
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100127}
128
Andrew Walbrandfb73372022-04-21 10:52:27 +0000129#[no_mangle]
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000130extern "C" fn sync_exception_current(elr: u64, _spsr: u64) {
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100131 // Disable logging in exception handler to prevent unsafe writes to UART.
132 let _guard = logger::suppress();
133 let esr: Esr = read_sysreg!("esr_el1").into();
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000134 let far = read_sysreg!("far_el1");
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100135
136 if let Err(e) = handle_exception(esr, far) {
Alice Wang8364a482023-07-05 08:06:05 +0000137 print_exception_failure(esr, far, elr, e);
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100138 reboot()
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +0100139 }
Andrew Walbrandfb73372022-04-21 10:52:27 +0000140}
141
142#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100143extern "C" fn irq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100144 eprintln!("irq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000145 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000146}
147
148#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100149extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100150 eprintln!("fiq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000151 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000152}
153
154#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100155extern "C" fn serr_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000156 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100157 eprintln!("serr_current");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000158 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000159 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000160}
161
162#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100163extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000164 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100165 eprintln!("sync_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000166 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000167 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000168}
169
170#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100171extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100172 eprintln!("irq_lower");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000173 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000174}
175
176#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100177extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100178 eprintln!("fiq_lower");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000179 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000180}
181
182#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100183extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000184 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100185 eprintln!("serr_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000186 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000187 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000188}