Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/aarch64/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use crate::trap::PageFaultFlags;
#[derive(Debug)]
pub(super) enum TrapKind {
Synchronous = 0,
Irq = 1,
Fiq = 2,
SError = 3,
Irq = 1,
Fiq = 2,
SError = 3,
}

#[repr(u8)]
Expand Down Expand Up @@ -70,6 +70,13 @@ fn esr_value() -> u64 {
}
}

fn handle_breakpoint(tf: &mut TrapFrame) {
if handle_trap!(BREAK_HANDLER, tf) {
return;
}
tf.elr += 4;
}

fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
let vaddr = va!(fault_addr());
if handle_trap!(PAGE_FAULT, vaddr, access_flags) {
Expand Down Expand Up @@ -162,12 +169,12 @@ fn aarch64_trap_handler(tf: &mut TrapFrame, kind: TrapKind, source: TrapSource)
#[cfg(not(feature = "arm-el2"))]
Some(ESR_EL1::EC::Value::Brk64) => {
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
tf.elr += 4;
handle_breakpoint(tf);
}
#[cfg(feature = "arm-el2")]
Some(ESR_EL2::EC::Value::Brk64) => {
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
tf.elr += 4;
handle_breakpoint(tf);
}
e => {
let vaddr = va!(fault_addr());
Expand Down
10 changes: 6 additions & 4 deletions src/aarch64/uspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

use core::ops::{Deref, DerefMut};

use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable};
use aarch64_cpu::registers::{Readable, ESR_EL1, FAR_EL1};
use memory_addr::VirtAddr;
use tock_registers::LocalRegisterCopy;

use super::trap::{TrapKind, is_valid_page_fault};
use super::trap::{is_valid_page_fault, TrapKind};
pub use crate::uspace_common::{ExceptionKind, ReturnReason};
use crate::{TrapFrame, trap::PageFaultFlags};
use crate::{trap::PageFaultFlags, TrapFrame};

/// Context to enter user space.
#[repr(C, align(16))]
Expand Down Expand Up @@ -149,7 +149,9 @@ impl ExceptionInfo {
/// Returns a generalized kind of this exception.
pub fn kind(&self) -> ExceptionKind {
match self.esr.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::BreakpointLowerEL) => ExceptionKind::Breakpoint,
Some(ESR_EL1::EC::Value::Brk64 | ESR_EL1::EC::Value::Bkpt32) => {
ExceptionKind::Breakpoint
}
Some(ESR_EL1::EC::Value::IllegalExecutionState) => ExceptionKind::IllegalInstruction,
Some(ESR_EL1::EC::Value::PCAlignmentFault)
| Some(ESR_EL1::EC::Value::SPAlignmentFault) => ExceptionKind::Misaligned,
Expand Down
11 changes: 7 additions & 4 deletions src/loongarch64/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ core::arch::global_asm!(
trapframe_size = const (core::mem::size_of::<TrapFrame>()),
);

fn handle_breakpoint(era: &mut usize) {
debug!("Exception(Breakpoint) @ {era:#x} ");
*era += 4;
fn handle_breakpoint(tf: &mut TrapFrame) {
debug!("Exception(Breakpoint) @ {:#x} ", tf.era);
if handle_trap!(BREAK_HANDLER, tf) {
return;
}
tf.era += 4;
}

fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
Expand Down Expand Up @@ -53,7 +56,7 @@ fn loongarch64_trap_handler(tf: &mut TrapFrame) {
| Trap::Exception(Exception::PageNonExecutableFault) => {
handle_page_fault(tf, PageFaultFlags::EXECUTE);
}
Trap::Exception(Exception::Breakpoint) => handle_breakpoint(&mut tf.era),
Trap::Exception(Exception::Breakpoint) => handle_breakpoint(tf),
Trap::Exception(Exception::AddressNotAligned) => unsafe {
tf.emulate_unaligned().unwrap();
},
Expand Down
2 changes: 1 addition & 1 deletion src/loongarch64/uspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use loongArch64::register::{
use memory_addr::VirtAddr;

pub use crate::uspace_common::{ExceptionKind, ReturnReason};
use crate::{TrapFrame, trap::PageFaultFlags};
use crate::{trap::PageFaultFlags, TrapFrame};

/// Context to enter user space.
#[derive(Debug, Clone, Copy)]
Expand Down
13 changes: 8 additions & 5 deletions src/riscv/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
use riscv::register::sstatus;
use riscv::{
interrupt::{
Trap,
supervisor::{Exception as E, Interrupt as I},
Trap,
},
register::{scause, stval},
};
Expand All @@ -17,9 +17,12 @@ core::arch::global_asm!(
trapframe_size = const core::mem::size_of::<TrapFrame>(),
);

fn handle_breakpoint(sepc: &mut usize) {
debug!("Exception(Breakpoint) @ {sepc:#x} ");
*sepc += 2
fn handle_breakpoint(tf: &mut TrapFrame) {
debug!("Exception(Breakpoint) @ {:#x} ", tf.sepc);
if handle_trap!(BREAK_HANDLER, tf) {
return;
}
tf.sepc += 2;
}

fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
Expand Down Expand Up @@ -51,7 +54,7 @@ fn riscv_trap_handler(tf: &mut TrapFrame) {
Trap::Exception(E::InstructionPageFault) => {
handle_page_fault(tf, PageFaultFlags::EXECUTE)
}
Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc),
Trap::Exception(E::Breakpoint) => handle_breakpoint(tf),
Trap::Interrupt(_) => {
handle_trap!(IRQ, scause.bits());
}
Expand Down
4 changes: 2 additions & 2 deletions src/riscv/uspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ use memory_addr::VirtAddr;
use riscv::register::sstatus::FS;
use riscv::{
interrupt::{
Trap,
supervisor::{Exception as E, Interrupt as I},
Trap,
},
register::{scause, sstatus::Sstatus, stval},
};

pub use crate::uspace_common::{ExceptionKind, ReturnReason};
use crate::{GeneralRegisters, TrapFrame, trap::PageFaultFlags};
use crate::{trap::PageFaultFlags, GeneralRegisters, TrapFrame};

/// Context to enter user space.
#[derive(Debug, Clone, Copy)]
Expand Down
43 changes: 43 additions & 0 deletions src/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,49 @@ pub static IRQ: [fn(usize) -> bool];
#[def_trap_handler]
pub static PAGE_FAULT: [fn(VirtAddr, PageFaultFlags) -> bool];

/// A slice of breakpoint handler functions.
///
/// Each handler is invoked with a mutable reference to the trapped [`TrapFrame`]
/// and must return a boolean indicating whether it has fully handled the trap:
///
/// - `true` means the breakpoint has been handled and control should resume
/// according to the state encoded in the trap frame.
/// - `false` means the breakpoint was not handled and default processing
/// (such as falling back to another mechanism or terminating) should occur.
///
/// When returning `true`, the handler is responsible for updating the saved
/// program counter (or equivalent PC field) in the trap frame as required by
/// the target architecture. In particular, the handler must ensure that,
/// upon resuming from the trap, execution does not immediately re-trigger the
/// same breakpoint instruction or condition, which could otherwise lead to an
/// infinite trap loop. The exact way to advance or modify the PC is
/// architecture-specific and depends on how [`TrapFrame`] encodes the saved
/// context.
#[def_trap_handler]
pub static BREAK_HANDLER: [fn(&mut TrapFrame) -> bool];

/// A slice of debug handler functions.
///
/// On `x86_64`, these handlers are invoked for debug-related traps (for
/// example, hardware breakpoints, single-step traps, or other debug
/// exceptions). The handler receives a mutable reference to the trapped
/// [`TrapFrame`] and returns a boolean with the following meaning:
///
/// - `true` means the debug trap has been fully handled and execution should
/// resume from the state stored in the trap frame.
/// - `false` means the debug trap was not handled and default/secondary
/// processing should take place.
///
/// As with [`BREAK_HANDLER`], when returning `true`, the handler must adjust
/// the saved program counter (or equivalent) in the trap frame if required by
/// the architecture so that resuming execution does not immediately cause the
/// same debug condition to fire again. Callers must take the architecture-
/// specific PC semantics into account when deciding how to advance or modify
/// the PC.
#[cfg(target_arch = "x86_64")]
#[def_trap_handler]
pub static DEBUG_HANDLER: [fn(&mut TrapFrame) -> bool];

#[allow(unused_macros)]
macro_rules! handle_trap {
($trap:ident, $($args:tt)*) => {{
Expand Down
9 changes: 6 additions & 3 deletions src/uspace_common.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use memory_addr::VirtAddr;

use crate::{TrapFrame, trap::PageFaultFlags, uspace::ExceptionInfo};
use crate::{trap::PageFaultFlags, uspace::ExceptionInfo, TrapFrame};

/// A reason as to why the control of the CPU is returned from
/// the user space to the kernel.
Expand All @@ -21,6 +21,9 @@ pub enum ReturnReason {
/// A generalized kind for [`ExceptionInfo`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExceptionKind {
#[cfg(target_arch = "x86_64")]
/// A debug exception.
Debug,
/// A breakpoint exception.
Breakpoint,
/// An illegal instruction exception.
Expand Down Expand Up @@ -50,7 +53,7 @@ impl ExceptionTableEntry {
#[cfg(target_arch = "aarch64")]
{
let base = (&self.from as *const i32) as isize;
return (base + self.from as isize) as usize;
(base + self.from as isize) as usize
}

#[cfg(not(target_arch = "aarch64"))]
Expand All @@ -64,7 +67,7 @@ impl ExceptionTableEntry {
#[cfg(target_arch = "aarch64")]
{
let base = (&self.to as *const i32) as isize;
return (base + self.to as isize) as usize;
(base + self.to as isize) as usize
}

#[cfg(not(target_arch = "aarch64"))]
Expand Down
4 changes: 2 additions & 2 deletions src/x86_64/gdt.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use x86_64::{
PrivilegeLevel,
instructions::tables::load_tss,
registers::segmentation::{CS, Segment, SegmentSelector},
registers::segmentation::{Segment, SegmentSelector, CS},
structures::{
gdt::{Descriptor, GlobalDescriptorTable},
tss::TaskStateSegment,
},
PrivilegeLevel,
};

#[percpu::def_percpu]
Expand Down
26 changes: 24 additions & 2 deletions src/x86_64/trap.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use core::panic;

use x86::{controlregs::cr2, irq::*};
use x86_64::structures::idt::PageFaultErrorCode;

use super::{TrapFrame, gdt};
use super::{gdt, TrapFrame};
use crate::trap::PageFaultFlags;

core::arch::global_asm!(
Expand Down Expand Up @@ -38,11 +40,31 @@ fn handle_page_fault(tf: &mut TrapFrame) {
);
}

fn handle_breakpoint(tf: &mut TrapFrame) {
debug!("#BP @ {:#x} ", tf.rip);
if handle_trap!(BREAK_HANDLER, tf) {}
}

fn handle_debug(tf: &mut TrapFrame) {
debug!("#DB @ {:#x} ", tf.rip);
if handle_trap!(DEBUG_HANDLER, tf) {
return;
}
panic!(
"Unhandled #DB @ {:#x}, error_code={:#x}:\n{:#x?}\n{}",
tf.rip,
tf.error_code,
tf,
tf.backtrace()
);
}

#[unsafe(no_mangle)]
fn x86_trap_handler(tf: &mut TrapFrame) {
match tf.vector as u8 {
PAGE_FAULT_VECTOR => handle_page_fault(tf),
BREAKPOINT_VECTOR => debug!("#BP @ {:#x} ", tf.rip),
BREAKPOINT_VECTOR => handle_breakpoint(tf),
DEBUG_VECTOR => handle_debug(tf),
GENERAL_PROTECTION_FAULT_VECTOR => {
panic!(
"#GP @ {:#x}, error_code={:#x}:\n{:#x?}\n{}",
Expand Down
5 changes: 3 additions & 2 deletions src/x86_64/uspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ use x86_64::{
};

use super::{
TrapFrame,
asm::{read_thread_pointer, write_thread_pointer},
gdt,
trap::{IRQ_VECTOR_END, IRQ_VECTOR_START, LEGACY_SYSCALL_VECTOR, err_code_to_flags},
trap::{err_code_to_flags, IRQ_VECTOR_END, IRQ_VECTOR_START, LEGACY_SYSCALL_VECTOR},
TrapFrame,
};
pub use crate::uspace_common::{ExceptionKind, ReturnReason};

Expand Down Expand Up @@ -140,6 +140,7 @@ impl ExceptionInfo {
/// Returns a generalized kind of this exception.
pub fn kind(&self) -> ExceptionKind {
match ExceptionVector::try_from(self.vector) {
Ok(ExceptionVector::Debug) => ExceptionKind::Debug,
Ok(ExceptionVector::Breakpoint) => ExceptionKind::Breakpoint,
Ok(ExceptionVector::InvalidOpcode) => ExceptionKind::IllegalInstruction,
_ => ExceptionKind::Other,
Expand Down
Loading