Skip to content

Commit 1ba7ad9

Browse files
committed
feat: Add conversion of trapframe to kprobe's pt_regs
Add custom callback for break exception. Signed-off-by: Godones <[email protected]>
1 parent f046e84 commit 1ba7ad9

File tree

8 files changed

+200
-23
lines changed

8 files changed

+200
-23
lines changed

Cargo.lock

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ cfg-if = "1.0"
3636
memory_addr = "0.4"
3737
page_table_entry = "0.5"
3838
static_assertions = "1.1.0"
39+
axprobe = { git = "https://github.com/Starry-OS/axprobe" }
3940

4041
[target.'cfg(target_arch = "x86_64")'.dependencies]
4142
x86 = "0.52"

src/loongarch64/context.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use core::arch::naked_asm;
22
#[cfg(feature = "fp-simd")]
33
use core::mem::offset_of;
4+
5+
use axprobe::PtRegs;
46
use memory_addr::VirtAddr;
57

68
/// General registers of Loongarch64.
@@ -259,8 +261,8 @@ impl TaskContext {
259261

260262
/// Switches to another task.
261263
///
262-
/// It first saves the current task's context from CPU to this place, and then
263-
/// restores the next task's context from `next_ctx` to CPU.
264+
/// It first saves the current task's context from CPU to this place, and
265+
/// then restores the next task's context from `next_ctx` to CPU.
264266
pub fn switch_to(&mut self, next_ctx: &Self) {
265267
#[cfg(feature = "tls")]
266268
{
@@ -353,3 +355,40 @@ unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task:
353355
ret",
354356
)
355357
}
358+
359+
impl TrapFrame {
360+
pub fn to_pt_regs(&mut self) -> axprobe::PtRegs {
361+
let regs = [0; 32];
362+
unsafe {
363+
core::ptr::copy_nonoverlapping(
364+
&self.regs.zero as *const usize,
365+
regs.as_ptr() as *mut usize,
366+
32,
367+
);
368+
}
369+
PtRegs {
370+
regs,
371+
orig_a0: 0,
372+
csr_era: self.era,
373+
csr_badvaddr: 0,
374+
csr_crmd: 0,
375+
csr_prmd: self.prmd,
376+
csr_euen: 0,
377+
csr_ecfg: 0,
378+
csr_estat: 0,
379+
}
380+
}
381+
382+
pub fn update_from_pt_regs(&mut self, pt_regs: axprobe::PtRegs) {
383+
unsafe {
384+
core::ptr::copy_nonoverlapping(
385+
pt_regs.regs.as_ptr() as *const usize,
386+
&mut self.regs.zero as *mut usize,
387+
32,
388+
);
389+
}
390+
self.era = pt_regs.csr_era;
391+
self.prmd = pt_regs.csr_prmd;
392+
// other csr fields are ignored
393+
}
394+
}

src/loongarch64/trap.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ core::arch::global_asm!(
1212
trapframe_size = const (core::mem::size_of::<TrapFrame>()),
1313
);
1414

15-
fn handle_breakpoint(era: &mut usize) {
16-
debug!("Exception(Breakpoint) @ {era:#x} ");
17-
*era += 4;
15+
fn handle_breakpoint(tf: &mut TrapFrame) {
16+
if core::hint::likely(handle_trap!(BREAK_HANDLER, tf)) {
17+
return;
18+
}
19+
debug!("Exception(Breakpoint) @ {:#x} ", tf.era);
20+
tf.era += 2; // skip ebreak instruction
1821
}
1922

2023
fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
@@ -51,7 +54,7 @@ fn loongarch64_trap_handler(tf: &mut TrapFrame) {
5154
| Trap::Exception(Exception::PageNonExecutableFault) => {
5255
handle_page_fault(tf, PageFaultFlags::EXECUTE);
5356
}
54-
Trap::Exception(Exception::Breakpoint) => handle_breakpoint(&mut tf.era),
57+
Trap::Exception(Exception::Breakpoint) => handle_breakpoint(tf),
5558
Trap::Exception(Exception::AddressNotAligned) => unsafe {
5659
tf.emulate_unaligned().unwrap();
5760
},

src/riscv/asm.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,7 @@ pub unsafe fn write_thread_pointer(tp: usize) {
140140
unsafe { core::arch::asm!("mv tp, {}", in(reg) tp) }
141141
}
142142

143-
core::arch::global_asm!(
144-
include_asm_macros!(),
145-
include_str!("user_copy.S")
146-
);
143+
core::arch::global_asm!(include_asm_macros!(), include_str!("user_copy.S"));
147144

148145
unsafe extern "C" {
149146
pub fn user_copy(dst: *mut u8, src: *const u8, size: usize) -> usize;

src/riscv/context.rs

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::arch::naked_asm;
2+
23
use memory_addr::VirtAddr;
34
use riscv::register::sstatus::{self, FS};
45

@@ -83,7 +84,8 @@ impl FpState {
8384

8485
/// Handles floating-point state context switching
8586
///
86-
/// Saves the current task's FP state (if needed) and restores the next task's FP state
87+
/// Saves the current task's FP state (if needed) and restores the next
88+
/// task's FP state
8789
pub fn switch_to(&mut self, next_fp_state: &FpState) {
8890
// get the real FP state of the current task
8991
let current_fs = sstatus::read().fs();
@@ -96,9 +98,12 @@ impl FpState {
9698
}
9799
// restore the next task's FP state
98100
match next_fp_state.fs {
99-
FS::Clean => next_fp_state.restore(), // the next task's FP state is clean, we should restore it
100-
FS::Initial => FpState::clear(), // restore the FP state as constant values(all 0)
101-
FS::Off => {} // do nothing
101+
// the next task's FP state is clean, we should restore it
102+
FS::Clean => next_fp_state.restore(),
103+
// restore the FP state as constant values(all 0)
104+
FS::Initial => FpState::clear(),
105+
// do nothing
106+
FS::Off => {}
102107
FS::Dirty => unreachable!("FP state of the next task should not be dirty"),
103108
}
104109
unsafe { sstatus::set_fs(next_fp_state.fs) }; // set the FP state to the next task's FP state
@@ -324,8 +329,8 @@ impl TaskContext {
324329

325330
/// Switches to another task.
326331
///
327-
/// It first saves the current task's context from CPU to this place, and then
328-
/// restores the next task's context from `next_ctx` to CPU.
332+
/// It first saves the current task's context from CPU to this place, and
333+
/// then restores the next task's context from `next_ctx` to CPU.
329334
pub fn switch_to(&mut self, next_ctx: &Self) {
330335
#[cfg(feature = "tls")]
331336
{
@@ -423,3 +428,83 @@ unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task:
423428
ret",
424429
)
425430
}
431+
432+
impl TrapFrame {
433+
pub fn to_pt_regs(&mut self) -> axprobe::PtRegs {
434+
axprobe::PtRegs {
435+
epc: self.sepc,
436+
ra: self.regs.ra,
437+
sp: self.regs.sp,
438+
gp: self.regs.gp,
439+
tp: self.regs.tp,
440+
t0: self.regs.t0,
441+
t1: self.regs.t1,
442+
t2: self.regs.t2,
443+
s0: self.regs.s0,
444+
s1: self.regs.s1,
445+
a0: self.regs.a0,
446+
a1: self.regs.a1,
447+
a2: self.regs.a2,
448+
a3: self.regs.a3,
449+
a4: self.regs.a4,
450+
a5: self.regs.a5,
451+
a6: self.regs.a6,
452+
a7: self.regs.a7,
453+
s2: self.regs.s2,
454+
s3: self.regs.s3,
455+
s4: self.regs.s4,
456+
s5: self.regs.s5,
457+
s6: self.regs.s6,
458+
s7: self.regs.s7,
459+
s8: self.regs.s8,
460+
s9: self.regs.s9,
461+
s10: self.regs.s10,
462+
s11: self.regs.s11,
463+
t3: self.regs.t3,
464+
t4: self.regs.t4,
465+
t5: self.regs.t5,
466+
t6: self.regs.t6,
467+
status: self.sstatus.bits(),
468+
// todo : other fields
469+
badaddr: 0,
470+
cause: 0,
471+
orig_a0: 0,
472+
}
473+
}
474+
475+
pub fn update_from_pt_regs(&mut self, pt_regs: axprobe::PtRegs) {
476+
self.sepc = pt_regs.epc;
477+
self.regs.ra = pt_regs.ra;
478+
self.regs.sp = pt_regs.sp;
479+
self.regs.gp = pt_regs.gp;
480+
self.regs.tp = pt_regs.tp;
481+
self.regs.t0 = pt_regs.t0;
482+
self.regs.t1 = pt_regs.t1;
483+
self.regs.t2 = pt_regs.t2;
484+
self.regs.s0 = pt_regs.s0;
485+
self.regs.s1 = pt_regs.s1;
486+
self.regs.a0 = pt_regs.a0;
487+
self.regs.a1 = pt_regs.a1;
488+
self.regs.a2 = pt_regs.a2;
489+
self.regs.a3 = pt_regs.a3;
490+
self.regs.a4 = pt_regs.a4;
491+
self.regs.a5 = pt_regs.a5;
492+
self.regs.a6 = pt_regs.a6;
493+
self.regs.a7 = pt_regs.a7;
494+
self.regs.s2 = pt_regs.s2;
495+
self.regs.s3 = pt_regs.s3;
496+
self.regs.s4 = pt_regs.s4;
497+
self.regs.s5 = pt_regs.s5;
498+
self.regs.s6 = pt_regs.s6;
499+
self.regs.s7 = pt_regs.s7;
500+
self.regs.s8 = pt_regs.s8;
501+
self.regs.s9 = pt_regs.s9;
502+
self.regs.s10 = pt_regs.s10;
503+
self.regs.s11 = pt_regs.s11;
504+
self.regs.t3 = pt_regs.t3;
505+
self.regs.t4 = pt_regs.t4;
506+
self.regs.t5 = pt_regs.t5;
507+
self.regs.t6 = pt_regs.t6;
508+
// todo : other fields
509+
}
510+
}

src/riscv/trap.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
use riscv::interrupt::supervisor::{Exception as E, Interrupt as I};
2-
use riscv::interrupt::Trap;
31
#[cfg(feature = "fp-simd")]
42
use riscv::register::sstatus;
5-
use riscv::register::{scause, stval};
3+
use riscv::{
4+
interrupt::{
5+
supervisor::{Exception as E, Interrupt as I},
6+
Trap,
7+
},
8+
register::{scause, stval},
9+
};
610

711
use super::TrapFrame;
812
use crate::trap::PageFaultFlags;
@@ -13,9 +17,12 @@ core::arch::global_asm!(
1317
trapframe_size = const core::mem::size_of::<TrapFrame>(),
1418
);
1519

16-
fn handle_breakpoint(sepc: &mut usize) {
17-
debug!("Exception(Breakpoint) @ {sepc:#x} ");
18-
*sepc += 2
20+
fn handle_breakpoint(tf: &mut TrapFrame) {
21+
if core::hint::likely(handle_trap!(BREAK_HANDLER, tf)) {
22+
return;
23+
}
24+
debug!("Exception(Breakpoint) @ {:#x} ", tf.sepc);
25+
tf.sepc += 2; // skip ebreak instruction
1926
}
2027

2128
fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
@@ -45,7 +52,7 @@ fn riscv_trap_handler(tf: &mut TrapFrame) {
4552
Trap::Exception(E::InstructionPageFault) => {
4653
handle_page_fault(tf, PageFaultFlags::EXECUTE)
4754
}
48-
Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc),
55+
Trap::Exception(E::Breakpoint) => handle_breakpoint(tf),
4956
Trap::Interrupt(_) => {
5057
handle_trap!(IRQ, scause.bits());
5158
}

src/trap.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ pub static IRQ: [fn(usize) -> bool];
1717
#[def_trap_handler]
1818
pub static PAGE_FAULT: [fn(VirtAddr, PageFaultFlags) -> bool];
1919

20+
/// A slice of breakpoint handler functions.
21+
#[def_trap_handler]
22+
pub static BREAK_HANDLER: [fn(&mut TrapFrame) -> bool];
23+
2024
#[allow(unused_macros)]
2125
macro_rules! handle_trap {
2226
($trap:ident, $($args:tt)*) => {{

0 commit comments

Comments
 (0)