blob: 525cdbaae6b4d5740cd9e24da18c35c5e0c777b5 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::task::PageFaultExceptionReport;
use starnix_uapi::signals::{SIGFPE, Signal};
// See https://developer.arm.com/documentation/ddi0601/2022-03/AArch64-Registers/ESR-EL1--Exception-Syndrome-Register--EL1-
// for details about the values used in this file.
// Returns "Exception Class" from the exception context.
fn get_ec_from_exception_context(arch: &zx::ExceptionArchData) -> u8 {
// Exception Class is bits 26-31 (inclusive).
((arch.esr >> 26) & 0b111111u32) as u8
}
// Returns "Instruction Specific Syndrome" from the exception context.
fn get_iss_from_exception_context(arch: &zx::ExceptionArchData) -> u32 {
// ISS is bits 0-24 (inclusive).
arch.esr & 0xffffffu32
}
pub fn decode_page_fault_exception_report(
arch: &zx::ExceptionArchData,
) -> PageFaultExceptionReport {
let faulting_address = arch.far;
let ec = get_ec_from_exception_context(arch);
let iss = get_iss_from_exception_context(arch);
let is_execute = ec == 0b100000 || ec == 0b100001; // Instruction abort exceptions.
let data_abort = ec == 0b100100 || ec == 0b100101; // Data abort exceptions.
// Data Fault Status Code or Instruction Fault Status Code (bits [0:5] of ISS).
let dfsc = iss & 0b111111;
// Translation faults, level 0-3.
let not_present =
(dfsc == 0b000100) || (dfsc == 0b000101) || (dfsc == 0b000110) || (dfsc == 0b000111);
// Note that the Zircon exception handler arm64_data_abort_handler() adds some
// extra checking of the "cache maintenance" bit which causes it to treat more
// things as reads. We may need similar handling.
let is_write = data_abort && (arch.esr & 0b1000000 != 0); // WnR "write not read" = bit 6.
PageFaultExceptionReport { faulting_address, not_present, is_write, is_execute }
}
pub fn get_signal_for_general_exception(arch: &zx::ExceptionArchData) -> Option<Signal> {
match get_ec_from_exception_context(arch) {
// Floating point exception.
0b101000 | 0b101100 => Some(SIGFPE),
_ => None,
}
}