blob: c3f8a295a0ec6bef451a6f1b3676ccf57437aedb [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
117#[inline]
118fn handling_uart_exception(esr: Esr, far: usize) -> bool {
119 esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(far) == UART_PAGE
120}
121
Andrew Walbrandfb73372022-04-21 10:52:27 +0000122#[no_mangle]
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000123extern "C" fn sync_exception_current(elr: u64, _spsr: u64) {
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100124 // Disable logging in exception handler to prevent unsafe writes to UART.
125 let _guard = logger::suppress();
126 let esr: Esr = read_sysreg!("esr_el1").into();
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000127 let far = read_sysreg!("far_el1");
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100128
129 if let Err(e) = handle_exception(esr, far) {
130 // Don't print to the UART if we are handling an exception it could raise.
131 if !handling_uart_exception(esr, far) {
132 eprintln!("sync_exception_current");
133 eprintln!("{e}");
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000134 eprintln!("{esr}, far={far:#08x}, elr={elr:#08x}");
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100135 }
136 reboot()
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +0100137 }
Andrew Walbrandfb73372022-04-21 10:52:27 +0000138}
139
140#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100141extern "C" fn irq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100142 eprintln!("irq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000143 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000144}
145
146#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100147extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100148 eprintln!("fiq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000149 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000150}
151
152#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100153extern "C" fn serr_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000154 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100155 eprintln!("serr_current");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000156 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000157 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000158}
159
160#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100161extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000162 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100163 eprintln!("sync_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000164 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000165 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000166}
167
168#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100169extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100170 eprintln!("irq_lower");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000171 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000172}
173
174#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100175extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100176 eprintln!("fiq_lower");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000177 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000178}
179
180#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100181extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000182 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100183 eprintln!("serr_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000184 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000185 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000186}