fast_trap/
lib.rs

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
//! 快速陷入处理。

#![no_std]
#![feature(naked_functions, asm_const)]
#![deny(warnings, missing_docs)]

mod entire;
mod fast;
mod hal;

pub use entire::*;
pub use fast::*;
pub use hal::{load_direct_trap_entry, reuse_stack_for_trap, soft_trap, trap_entry, FlowContext};

use core::{
    alloc::Layout,
    marker::PhantomPinned,
    mem::{align_of, forget, MaybeUninit},
    ops::Range,
    ptr::NonNull,
};

/// 游离的陷入栈。
pub struct FreeTrapStack(NonNull<TrapHandler>);

/// 已加载的陷入栈。
pub struct LoadedTrapStack(usize);

/// 构造陷入栈失败。
#[derive(Debug)]
pub struct IllegalStack;

impl FreeTrapStack {
    /// 在内存块上构造游离的陷入栈。
    pub fn new(
        range: Range<usize>,
        drop: fn(Range<usize>),

        context_ptr: NonNull<FlowContext>,
        fast_handler: FastHandler,
    ) -> Result<Self, IllegalStack> {
        const LAYOUT: Layout = Layout::new::<TrapHandler>();
        let bottom = range.start;
        let top = range.end;
        let ptr = (top - LAYOUT.size()) & !(LAYOUT.align() - 1);
        if ptr >= bottom {
            let handler = unsafe { &mut *(ptr as *mut TrapHandler) };
            handler.range = range;
            handler.drop = drop;
            handler.context = context_ptr;
            handler.fast_handler = fast_handler;
            Ok(Self(unsafe { NonNull::new_unchecked(handler) }))
        } else {
            Err(IllegalStack)
        }
    }

    /// 将这个陷入栈加载为预备陷入栈。
    #[inline]
    pub fn load(self) -> LoadedTrapStack {
        let scratch = hal::exchange_scratch(self.0.as_ptr() as _);
        forget(self);
        LoadedTrapStack(scratch)
    }
}

impl Drop for FreeTrapStack {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let handler = self.0.as_ref();
            (handler.drop)(handler.range.clone());
        }
    }
}

impl LoadedTrapStack {
    /// 获取从 `sscratch` 寄存器中换出的值。
    #[inline]
    pub const fn val(&self) -> usize {
        self.0
    }

    /// 卸载陷入栈。
    #[inline]
    pub fn unload(self) -> FreeTrapStack {
        let ans = unsafe { self.unload_unchecked() };
        forget(self);
        ans
    }

    /// 卸载但不消费所有权。
    ///
    /// # Safety
    ///
    /// 间接复制了所有权。用于 `Drop`。
    #[inline]
    unsafe fn unload_unchecked(&self) -> FreeTrapStack {
        let ptr = hal::exchange_scratch(self.0) as *mut TrapHandler;
        let handler = unsafe { NonNull::new_unchecked(ptr) };
        FreeTrapStack(handler)
    }
}

impl Drop for LoadedTrapStack {
    #[inline]
    fn drop(&mut self) {
        drop(unsafe { self.unload_unchecked() })
    }
}

/// 陷入处理器上下文。
#[repr(C)]
struct TrapHandler {
    /// 指向一个陷入上下文的指针。
    ///
    /// # TODO
    ///
    /// 这个东西是怎么来的?生命周期是什么?
    /// 似乎让它生命周期和陷入栈绑定也很合理。
    /// 它可以交换,只是和陷入栈同时释放而已。
    ///
    /// - 发生陷入时,将寄存器保存到此对象。
    /// - 离开陷入处理时,按此对象的内容设置寄存器。
    context: NonNull<FlowContext>,
    /// 快速路径函数。
    ///
    /// 必须在初始化陷入时设置好。
    fast_handler: FastHandler,
    /// 可在汇编使用的临时存储。
    ///
    /// - 在快速路径开始时暂存 a0。
    /// - 在快速路径结束时保存完整路径函数。
    scratch: usize,

    range: Range<usize>,
    drop: fn(Range<usize>),

    /// 禁止移动标记。
    ///
    /// `TrapHandler` 是放在其内部定义的 `block` 块里的,这是一种自引用结构,不能移动。
    pinned: PhantomPinned,
}

impl TrapHandler {
    /// 如果从快速路径向完整路径转移,可以把一个对象放在栈底。
    /// 用这个方法找到栈底的一个对齐的位置。
    #[inline]
    fn locate_fast_mail<T>(&mut self) -> *mut MaybeUninit<T> {
        let top = self.range.end as *mut u8;
        let offset = top.align_offset(align_of::<T>());
        unsafe { &mut *top.add(offset).cast() }
    }
}