blob: 39641b09c10aca2e3d05668b4ba9fbbd9511a613 [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 Vukalovicb99905d2023-04-20 15:46:02 +010017use crate::memory::{MemoryTrackerError, MEMORY};
Jakob Vukalovicc9afb512023-03-30 16:04:32 +000018use crate::{helpers::page_4kb_of, read_sysreg};
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010019use core::fmt;
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +010020use vmbase::console;
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +010021use vmbase::logger;
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 Vukalovicb99905d2023-04-20 15:46:02 +010092fn handle_exception(esr: Esr, far: usize) -> Result<(), HandleExceptionError> {
93 // Handle all translation faults on both read and write, and MMIO guard map
94 // flagged invalid pages or blocks that caused the exception.
95 match esr {
96 Esr::DataAbortTranslationFault => {
97 let mut locked = MEMORY.try_lock().ok_or(HandleExceptionError::PageTableUnavailable)?;
98 let memory = locked.as_mut().ok_or(HandleExceptionError::PageTableNotInitialized)?;
99 Ok(memory.handle_mmio_fault(far)?)
100 }
101 _ => Err(HandleExceptionError::UnknownException),
102 }
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100103}
104
105#[inline]
106fn handling_uart_exception(esr: Esr, far: usize) -> bool {
107 esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(far) == UART_PAGE
108}
109
Andrew Walbrandfb73372022-04-21 10:52:27 +0000110#[no_mangle]
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000111extern "C" fn sync_exception_current(elr: u64, _spsr: u64) {
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100112 // Disable logging in exception handler to prevent unsafe writes to UART.
113 let _guard = logger::suppress();
114 let esr: Esr = read_sysreg!("esr_el1").into();
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000115 let far = read_sysreg!("far_el1");
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100116
117 if let Err(e) = handle_exception(esr, far) {
118 // Don't print to the UART if we are handling an exception it could raise.
119 if !handling_uart_exception(esr, far) {
120 eprintln!("sync_exception_current");
121 eprintln!("{e}");
Pierre-Clément Tosieeb1ace2023-05-15 17:23:51 +0000122 eprintln!("{esr}, far={far:#08x}, elr={elr:#08x}");
Jakob Vukalovicd3fe9ed2023-04-20 15:43:09 +0100123 }
124 reboot()
Pierre-Clément Tosida4440a2022-08-22 18:06:32 +0100125 }
Andrew Walbrandfb73372022-04-21 10:52:27 +0000126}
127
128#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100129extern "C" fn irq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100130 eprintln!("irq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000131 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000132}
133
134#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100135extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100136 eprintln!("fiq_current");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000137 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000138}
139
140#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100141extern "C" fn serr_current(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000142 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100143 eprintln!("serr_current");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000144 eprintln!("esr={esr:#08x}");
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 sync_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000150 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100151 eprintln!("sync_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000152 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000153 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000154}
155
156#[no_mangle]
Pierre-Clément Tosi8cbd4b72022-08-11 13:59:31 +0100157extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100158 eprintln!("irq_lower");
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 fiq_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100164 eprintln!("fiq_lower");
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 serr_lower(_elr: u64, _spsr: u64) {
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000170 let esr = read_sysreg!("esr_el1");
Jakob Vukalovicbff22e12023-04-18 14:50:47 +0100171 eprintln!("serr_lower");
Jakob Vukalovicc9afb512023-03-30 16:04:32 +0000172 eprintln!("esr={esr:#08x}");
Andrew Walbrandd74b902022-04-14 16:12:50 +0000173 reboot();
Andrew Walbrandfb73372022-04-21 10:52:27 +0000174}