258 lines
7.4 KiB
Rust
Raw Normal View History

2023-07-18 18:03:45 +03:00
//! Exception and interrupt management functions
use core::arch::global_asm;
2023-07-18 18:03:45 +03:00
use aarch64_cpu::{
asm::barrier,
registers::{
2024-11-26 22:59:23 +02:00
ELR_EL1, ESR_EL1, FAR_EL1, SCTLR_EL1, SP_EL0, TCR_EL1, TPIDR_EL0, TPIDR_EL1, TTBR0_EL1,
TTBR1_EL1, VBAR_EL1,
},
};
2024-07-27 14:37:46 +03:00
use abi::{process::Signal, SyscallFunction};
2024-11-30 23:51:02 +02:00
use kernel_arch::{sync::hack_locks, Architecture, ArchitectureImpl};
use kernel_arch_aarch64::context::ExceptionFrame;
2024-07-27 14:37:46 +03:00
use libk::{arch::Cpu, device::external_interrupt_controller, task::thread::Thread};
2023-07-18 18:03:45 +03:00
use tock_registers::interfaces::{Readable, Writeable};
2024-07-27 14:37:46 +03:00
use crate::{
2024-11-26 22:59:23 +02:00
mem::KERNEL_VIRT_OFFSET,
2024-07-27 14:37:46 +03:00
syscall::{self, raw_syscall_handler},
};
2023-07-18 18:03:45 +03:00
/// Initializes the exception/interrupt vectors. May be called repeatedly (though that makes no
/// sense).
pub fn init_exceptions() {
extern "C" {
static __aarch64_el1_vectors: u8;
}
let vbar = unsafe { &__aarch64_el1_vectors as *const _ };
VBAR_EL1.set(vbar as u64);
barrier::isb(barrier::SY);
2023-07-18 18:03:45 +03:00
}
fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
2024-07-27 14:37:46 +03:00
let cpu = Cpu::try_local();
2024-11-26 22:59:23 +02:00
let far = FAR_EL1.get() as usize;
let ttbr0 = TTBR0_EL1.get();
2023-07-18 18:03:45 +03:00
2024-11-30 23:51:02 +02:00
log::error!(target: "raw", "SYNC exception:\n");
log::error!(target: "raw", "FAR: {:#x}\n", far);
log::error!(target: "raw", "ELR: {:#x}\n", ELR_EL1.get());
log::error!(target: "raw", "ESR: {:#x}\n", ESR_EL1.get());
log::error!(target: "raw", "SP_EL0: {:#x}\n", SP_EL0.get());
log::error!(target: "raw", "TTBR0_EL1: {:#x}\n", ttbr0);
log::error!(target: "raw", "TTBR1_EL1: {:#x}\n", TTBR1_EL1.get());
log::error!(target: "raw", "Register dump:\n");
log::error!(target: "raw", "{:?}\n", frame);
2023-07-18 18:03:45 +03:00
2024-07-27 14:37:46 +03:00
if let Some(cpu) = cpu {
// let current = cpu.queue().current_process();
let current = cpu.current_thread_id().and_then(Thread::get);
2023-07-18 18:03:45 +03:00
2024-07-27 14:37:46 +03:00
if let Some(current) = current {
2024-11-30 23:51:02 +02:00
log::error!(target: "raw", "In thread {}\n", current.id);
2024-11-26 22:59:23 +02:00
let space = current.address_space();
if far < KERNEL_VIRT_OFFSET && space.as_address_with_asid() == ttbr0 {
match space.translate(far) {
2024-11-30 23:51:02 +02:00
Ok(phys) => log::error!(
target: "raw",
2024-11-26 22:59:23 +02:00
"FAR translation: {:#x} -> {:#x}\n",
far,
phys
),
2024-11-30 23:51:02 +02:00
Err(_) => log::error!(target: "raw", "FAR does not translate\n"),
2024-11-26 22:59:23 +02:00
}
}
2024-07-27 14:37:46 +03:00
}
}
2023-07-18 18:03:45 +03:00
match ec {
// Data abort from lower level
0b100100 => {
2024-11-30 23:51:02 +02:00
log::error!(target: "raw", "Exception kind: Data Abort from EL0\n");
2023-07-18 18:03:45 +03:00
let dfsc = iss & 0x3F;
if iss & (1 << 24) != 0 {
let access_size_str = match (iss >> 22) & 0x3 {
0 => "i8",
1 => "i16",
2 => "i32",
3 => "i64",
_ => unreachable!(),
};
let access_type_str = if iss & (1 << 6) != 0 { "write" } else { "read" };
2024-11-30 23:51:02 +02:00
log::error!(
target: "raw",
2023-07-18 18:03:45 +03:00
"Invalid {} of a {} to/from {:#x}\n",
access_type_str,
access_size_str,
FAR_EL1.get()
);
}
2024-11-30 23:51:02 +02:00
log::error!(target: "raw", "DFSC = {:#x}\n", dfsc);
2023-07-18 18:03:45 +03:00
}
// Instruction abort from lower level
0b100000 => {
2024-11-30 23:51:02 +02:00
log::error!(
target: "raw",
2023-07-18 18:03:45 +03:00
"Exception kind: Instruction Abort from EL0\n"
);
let ifsc = iss & 0x3F;
2024-11-30 23:51:02 +02:00
log::error!(target: "raw", "IFSC = {:#x}\n", ifsc);
2023-07-18 18:03:45 +03:00
}
_ => (),
}
2024-11-30 23:51:02 +02:00
log::error!(target: "raw", "System register dump:\n");
log::error!(target: "raw", "SCTLR_EL1 = {:#x}\n", SCTLR_EL1.get());
log::error!(target: "raw", "TCR_EL1 = {:#x}\n", TCR_EL1.get());
log::error!(target: "raw", "TPIDR_EL1 = {:#x}\n", TPIDR_EL1.get());
log::error!(target: "raw", "TPIDR_EL0 = {:#x}\n", TPIDR_EL0.get());
2023-07-18 18:03:45 +03:00
}
#[no_mangle]
2023-07-27 16:24:52 +03:00
extern "C" fn __aa64_el0_sync_handler(frame: *mut ExceptionFrame) {
2023-08-15 13:32:48 +03:00
assert!(ArchitectureImpl::interrupt_mask());
2023-07-27 16:24:52 +03:00
let frame = unsafe { &mut *frame };
2023-08-15 13:32:48 +03:00
2023-07-27 16:24:52 +03:00
el0_sync_inner(frame);
2023-08-15 13:32:48 +03:00
2023-07-27 16:24:52 +03:00
unsafe {
let thread = Thread::current();
2024-03-13 23:52:51 +02:00
thread.handle_pending_signals(frame);
2023-07-27 16:24:52 +03:00
}
}
#[no_mangle]
extern "C" fn __aa64_el0_irq_handler(frame: *mut ExceptionFrame) {
2023-08-15 13:32:48 +03:00
assert!(ArchitectureImpl::interrupt_mask());
2023-07-18 18:03:45 +03:00
let frame = unsafe { &mut *frame };
2023-08-15 13:32:48 +03:00
2023-07-27 16:24:52 +03:00
irq_common();
2023-08-15 13:32:48 +03:00
2023-07-27 16:24:52 +03:00
unsafe {
let thread = Thread::current();
2024-03-13 23:52:51 +02:00
thread.handle_pending_signals(frame);
2023-07-27 16:24:52 +03:00
}
}
#[no_mangle]
extern "C" fn __aa64_el0_fiq_handler() {
2024-11-05 22:00:10 +02:00
unimplemented!()
2023-07-27 16:24:52 +03:00
}
#[no_mangle]
extern "C" fn __aa64_el0_serror_handler() {
2024-11-05 22:00:10 +02:00
unimplemented!()
2023-07-27 16:24:52 +03:00
}
2023-07-18 18:03:45 +03:00
2023-07-27 16:24:52 +03:00
// EL1
#[no_mangle]
extern "C" fn __aa64_el1_sync_handler(frame: *mut ExceptionFrame) {
let frame = unsafe { &*frame };
let esr_el1 = ESR_EL1.get();
let ec = (esr_el1 >> 26) & 0x3F;
let iss = esr_el1 & 0x1FFFFFF;
2024-11-30 23:51:02 +02:00
unsafe { hack_locks() };
dump_irrecoverable_exception(frame, ec, iss);
panic!("Irrecoverable exception in kernel mode");
2023-07-27 16:24:52 +03:00
}
#[no_mangle]
extern "C" fn __aa64_el1_irq_handler(_frame: *mut ExceptionFrame) {
irq_common();
}
#[no_mangle]
extern "C" fn __aa64_el1_fiq_handler() {
2024-11-05 22:00:10 +02:00
unimplemented!()
2023-07-27 16:24:52 +03:00
}
#[no_mangle]
extern "C" fn __aa64_el1_serror_handler() {
2024-11-05 22:00:10 +02:00
unimplemented!()
2023-07-27 16:24:52 +03:00
}
fn el0_sync_inner(frame: &mut ExceptionFrame) {
2023-07-18 18:03:45 +03:00
let esr_el1 = ESR_EL1.get();
let ec = (esr_el1 >> 26) & 0x3F;
2024-11-05 22:00:10 +02:00
let iss = esr_el1 & 0x1FFFFFF;
2023-07-18 18:03:45 +03:00
2024-11-05 22:00:10 +02:00
let dump = match ec {
2023-07-18 18:03:45 +03:00
// SVC in AArch64
0b010101 => {
let func = frame.r[8];
2024-10-11 15:29:41 +03:00
if func == usize::from(SyscallFunction::ExitSignal) {
2023-07-27 16:24:52 +03:00
unsafe {
2024-07-27 14:37:46 +03:00
syscall::handle_signal_exit(frame);
2023-07-27 16:24:52 +03:00
}
return;
}
2023-07-18 18:03:45 +03:00
let args = &frame.r[0..6];
2024-10-11 15:29:41 +03:00
let result = raw_syscall_handler(func, args) as _;
2023-07-18 18:03:45 +03:00
frame.r[0] = result;
2024-11-05 22:00:10 +02:00
false
2023-07-18 18:03:45 +03:00
}
// Software Step from lower Exception Level
0b110010 => {
let thread = Thread::current();
2024-11-05 22:00:10 +02:00
if thread.handle_single_step(frame) {
// Make the PE actually step the instruction
frame.spsr_el1 |= 1 << 21;
false
} else {
thread.raise_signal(Signal::Aborted);
true
}
}
2023-07-18 18:03:45 +03:00
// BRK in AArch64
0b111100 => {
let thread = Thread::current();
2024-11-30 23:51:02 +02:00
log::warn!(
2024-11-22 17:18:44 +02:00
"Thread {} {:?} hit a breakpoint",
thread.id,
*thread.name.read()
);
thread.raise_signal(Signal::Aborted);
2024-11-05 22:00:10 +02:00
true
2023-07-18 18:03:45 +03:00
}
_ => {
let thread = Thread::current();
2023-07-25 16:47:00 +03:00
if ec == 0b100100 {
// Data abort from lower level
let thread = Thread::current();
2024-11-30 23:51:02 +02:00
log::warn!(
"Data abort in {} {:?} at {:#x} with address {:#x}",
2024-01-04 23:04:34 +02:00
thread.id,
2024-11-22 17:18:44 +02:00
*thread.name.read(),
2023-07-25 16:47:00 +03:00
ELR_EL1.get(),
FAR_EL1.get()
);
}
2023-07-18 18:03:45 +03:00
thread.raise_signal(Signal::MemoryAccessViolation);
2024-11-05 22:00:10 +02:00
true
2023-07-18 18:03:45 +03:00
}
2024-11-05 22:00:10 +02:00
};
if dump {
dump_irrecoverable_exception(frame, ec, iss);
2023-07-18 18:03:45 +03:00
}
}
2023-07-27 16:24:52 +03:00
fn irq_common() {
external_interrupt_controller().handle_pending_irqs();
2023-07-18 18:03:45 +03:00
}
global_asm!(include_str!("vectors.S"));