-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathtrap.rs
More file actions
159 lines (140 loc) · 4.53 KB
/
Copy pathtrap.rs
File metadata and controls
159 lines (140 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! ARM32 exception handling routines.
use aarch32_cpu::register::{
cpsr::{Cpsr, ProcessorMode},
dfsr::DfsrStatus,
ifsr::FsrStatus,
};
use super::TrapFrame;
use crate::trap::PageFaultFlags;
core::arch::global_asm!(include_str!("trap.S"));
/// ARM32 exception types.
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum TrapKind {
/// Reset exception
Reset = 0,
/// Undefined instruction exception
Undefined = 1,
/// Software interrupt (SVC) exception
Svc = 2,
/// Prefetch abort exception
PrefetchAbort = 3,
/// Data abort exception
DataAbort = 4,
/// Reserved (should never occur)
Reserved = 5,
/// IRQ interrupt
Irq = 6,
/// FIQ interrupt
Fiq = 7,
}
/// Handler for invalid/unhandled exceptions.
#[unsafe(no_mangle)]
fn invalid_exception(tf: &TrapFrame, kind: u32) {
let kind = match kind {
0 => TrapKind::Reset,
1 => TrapKind::Undefined,
2 => TrapKind::Svc,
3 => TrapKind::PrefetchAbort,
4 => TrapKind::DataAbort,
5 => TrapKind::Reserved,
6 => TrapKind::Irq,
7 => TrapKind::Fiq,
_ => TrapKind::Reserved,
};
panic!("Invalid exception {:?}:\n{:#x?}", kind, tf);
}
/// Handler for IRQ exceptions.
#[unsafe(no_mangle)]
fn handle_irq_exception(_tf: &TrapFrame) {
trace!("IRQ received");
handle_trap!(IRQ, 0);
}
/// Handler for SVC (software interrupt) exceptions.
#[unsafe(no_mangle)]
fn handle_sync_exception(tf: &mut TrapFrame) {
// In ARM EABI, the system call number is passed in register r7.
let svc_num = tf.r[7];
trace!("SVC #{} at {:#x}", svc_num, tf.pc);
// Handle syscall through the trap handler
#[cfg(feature = "uspace")]
{
tf.r[0] = crate::trap::handle_syscall(tf, svc_num as usize) as u32;
}
#[cfg(not(feature = "uspace"))]
{
panic!(
"SVC #{} at {:#x} but uspace feature not enabled:\n{:#x?}",
svc_num, tf.pc, tf
);
}
}
fn handle_page_fault(tf: &TrapFrame, vaddr: usize, base_flags: PageFaultFlags) {
let is_user = Cpsr::new_with_raw_value(tf.cpsr).mode() == Ok(ProcessorMode::Usr);
let mut access_flags = base_flags;
if is_user {
access_flags |= PageFaultFlags::USER;
}
handle_trap!(PAGE_FAULT, vaddr.into(), access_flags, is_user);
}
/// Handler for prefetch abort exceptions.
#[unsafe(no_mangle)]
fn handle_prefetch_abort_exception(tf: &mut TrapFrame) {
let (fsr, far) = (super::asm::read_ifsr(), super::asm::read_ifar());
let fsr_status = match fsr.status() {
Ok(status) => status,
Err(raw) => panic!(
"Unknown IFSR status {:#x} in Prefetch Abort at {:#x}:\n{:#x?}",
raw, tf.pc, tf
),
};
match fsr_status {
FsrStatus::TranslationFaultFirstLevel | FsrStatus::TranslationFaultSecondLevel => {
handle_page_fault(tf, far.0 as usize, PageFaultFlags::EXECUTE);
}
FsrStatus::DebugEvent => {
// Treat BKPT as a handled breakpoint and continue at next instruction.
let is_thumb = (tf.cpsr & (1 << 5)) != 0;
let instr_len = if is_thumb { 2 } else { 4 };
tf.pc = tf.pc.wrapping_add(instr_len);
}
_ => {
panic!(
"Unhandled IFSR status {:?} in Prefetch Abort at {:#x} (IFAR={:#x}):\n{:#x?}",
fsr_status, tf.pc, far.0, tf
);
}
}
}
/// Handler for data abort exceptions.
#[unsafe(no_mangle)]
fn handle_data_abort_exception(tf: &mut TrapFrame) {
let (fsr, far) = (super::asm::read_dfsr(), super::asm::read_dfar());
let base_flags = if fsr.wnr() {
PageFaultFlags::WRITE
} else {
PageFaultFlags::READ
};
let fsr_status = match fsr.status() {
Ok(status) => status,
Err(raw) => panic!(
"Unknown DFSR status {:#x} in Data Abort at {:#x}:\n{:#x?}",
raw, tf.pc, tf
),
};
match fsr_status {
DfsrStatus::CommonFsr(FsrStatus::TranslationFaultFirstLevel)
| DfsrStatus::CommonFsr(FsrStatus::TranslationFaultSecondLevel)
| DfsrStatus::CommonFsr(FsrStatus::PermissionFaultFirstLevel)
| DfsrStatus::CommonFsr(FsrStatus::PermissionFaultSecondLevel) => {
handle_page_fault(tf, far.0 as usize, base_flags);
}
_ => {
panic!(
"Unhandled DFSR status {:?} in Data Abort at {:#x}, FAR={:#x}:\n{:#x?}",
fsr_status, tf.pc, far.0, tf
);
}
}
}