You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
3.9 KiB
Rust
153 lines
3.9 KiB
Rust
2 years ago
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||
|
//
|
||
|
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
|
||
|
|
||
|
//! Architectural asynchronous exception handling.
|
||
|
//!
|
||
|
//! # Orientation
|
||
|
//!
|
||
|
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
||
|
//! file is:
|
||
|
//!
|
||
|
//! crate::exception::asynchronous::arch_asynchronous
|
||
|
|
||
|
use core::arch::asm;
|
||
|
use cortex_a::registers::*;
|
||
|
use tock_registers::interfaces::{Readable, Writeable};
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------
|
||
|
// Private Definitions
|
||
|
//--------------------------------------------------------------------------------------------------
|
||
|
|
||
|
mod daif_bits {
|
||
|
pub const IRQ: u8 = 0b0010;
|
||
|
}
|
||
|
|
||
|
trait DaifField {
|
||
|
fn daif_field() -> tock_registers::fields::Field<u64, DAIF::Register>;
|
||
|
}
|
||
|
|
||
|
struct Debug;
|
||
|
struct SError;
|
||
|
struct IRQ;
|
||
|
struct FIQ;
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------
|
||
|
// Private Code
|
||
|
//--------------------------------------------------------------------------------------------------
|
||
|
|
||
|
impl DaifField for Debug {
|
||
|
fn daif_field() -> tock_registers::fields::Field<u64, DAIF::Register> {
|
||
|
DAIF::D
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl DaifField for SError {
|
||
|
fn daif_field() -> tock_registers::fields::Field<u64, DAIF::Register> {
|
||
|
DAIF::A
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl DaifField for IRQ {
|
||
|
fn daif_field() -> tock_registers::fields::Field<u64, DAIF::Register> {
|
||
|
DAIF::I
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl DaifField for FIQ {
|
||
|
fn daif_field() -> tock_registers::fields::Field<u64, DAIF::Register> {
|
||
|
DAIF::F
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn is_masked<T>() -> bool
|
||
|
where
|
||
|
T: DaifField,
|
||
|
{
|
||
|
DAIF.is_set(T::daif_field())
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------
|
||
|
// Public Code
|
||
|
//--------------------------------------------------------------------------------------------------
|
||
|
|
||
|
/// Returns whether IRQs are masked on the executing core.
|
||
|
pub fn is_local_irq_masked() -> bool {
|
||
|
!is_masked::<IRQ>()
|
||
|
}
|
||
|
|
||
|
/// Unmask IRQs on the executing core.
|
||
|
///
|
||
|
/// It is not needed to place an explicit instruction synchronization barrier after the `msr`.
|
||
|
/// Quoting the Architecture Reference Manual for ARMv8-A, section C5.1.3:
|
||
|
///
|
||
|
/// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional
|
||
|
/// synchronization."
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// - Changes the HW state of the executing core.
|
||
|
#[inline(always)]
|
||
|
pub unsafe fn local_irq_unmask() {
|
||
|
#[rustfmt::skip]
|
||
|
asm!(
|
||
|
"msr DAIFClr, {arg}",
|
||
|
arg = const daif_bits::IRQ,
|
||
|
options(nomem, nostack, preserves_flags)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// Mask IRQs on the executing core.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// - Changes the HW state of the executing core.
|
||
|
#[inline(always)]
|
||
|
pub unsafe fn local_irq_mask() {
|
||
|
#[rustfmt::skip]
|
||
|
asm!(
|
||
|
"msr DAIFSet, {arg}",
|
||
|
arg = const daif_bits::IRQ,
|
||
|
options(nomem, nostack, preserves_flags)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF).
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// - Changes the HW state of the executing core.
|
||
|
#[inline(always)]
|
||
|
pub unsafe fn local_irq_mask_save() -> u64 {
|
||
|
let saved = DAIF.get();
|
||
|
local_irq_mask();
|
||
|
|
||
|
saved
|
||
|
}
|
||
|
|
||
|
/// Restore the interrupt mask bits (DAIF) using the callee's argument.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// - Changes the HW state of the executing core.
|
||
|
/// - No sanity checks on the input.
|
||
|
#[inline(always)]
|
||
|
pub unsafe fn local_irq_restore(saved: u64) {
|
||
|
DAIF.set(saved);
|
||
|
}
|
||
|
|
||
|
/// Print the AArch64 exceptions status.
|
||
|
#[rustfmt::skip]
|
||
|
pub fn print_state() {
|
||
|
use crate::info;
|
||
|
|
||
|
let to_mask_str = |x| -> _ {
|
||
|
if x { "Masked" } else { "Unmasked" }
|
||
|
};
|
||
|
|
||
|
info!(" Debug: {}", to_mask_str(is_masked::<Debug>()));
|
||
|
info!(" SError: {}", to_mask_str(is_masked::<SError>()));
|
||
|
info!(" IRQ: {}", to_mask_str(is_masked::<IRQ>()));
|
||
|
info!(" FIQ: {}", to_mask_str(is_masked::<FIQ>()));
|
||
|
}
|