This repository has been archived by the owner on Feb 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathuser_syscall.rs
287 lines (279 loc) · 11.9 KB
/
user_syscall.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
//! 从用户过来的系统调用在这里处理
use super::{syscall, SyscallResult};
use crate::{
async_rt::{self, ext_intr_off, ext_intr_on, TaskState},
hart::KernelHartInfo,
memory::{self, Satp},
memory::{AddressSpaceId, VirtualAddress, VirtualPageNumber, KERNEL_MAP_OFFSET},
plic, task,
trap::timer,
trap::{self, SwapContext},
SHAREDPAYLOAD_BASE,
};
#[allow(unused)]
use crate::{sdcard::SD_CARD, virtio::VIRTIO_BLOCK};
use riscv::register::{
scause::{self, Interrupt, Trap},
sepc, stval,
};
const BLOCK_SIZE: usize = 512;
pub static mut WAKE_NUM: usize = 1;
/// 中断/异常/系统调用处理函数,用户态发生中断/异常/系统调用会陷入到这里
#[no_mangle]
pub extern "C" fn user_trap_handler() {
// 从[`KernelHartInfo`]中获取用户地址空间的 [`Satp`] 结构
let user_satp = KernelHartInfo::prev_satp().expect("get prev user satp");
// 从[`KernelHartInfo`]中获取用户地址空间编号
let asid = KernelHartInfo::get_prev_asid();
let swap_cx = unsafe { get_swap_cx(&user_satp, asid) };
// 从SwapContext中获取用户传给内核的参数
let mut param = [0usize; 6];
for (idx, x) in swap_cx.x[9..15].iter().enumerate() {
param[idx] = *x;
}
let a6 = swap_cx.x[15];
let a7 = swap_cx.x[16];
match scause::read().cause() {
Trap::Interrupt(Interrupt::SupervisorTimer) => {
// todo: 切换地址空间
//
// 不跳过指令,继续运行
timer::tick();
trap::switch_to_user(swap_cx, user_satp.inner(), asid)
}
Trap::Exception(scause::Exception::Breakpoint) => {
// 用户目前通过断点异常通知内核发生了错误,这时候直接退出
println!("user mode panic!");
crate::sbi::shutdown();
}
Trap::Exception(scause::Exception::UserEnvCall) => {
// 用户系统调用
match syscall(param, user_satp.inner(), a6, a7) {
SyscallResult::Procceed { code, extra } => {
swap_cx.x[9] = code;
swap_cx.x[10] = extra;
swap_cx.epc = swap_cx.epc.wrapping_add(4);
trap::switch_to_user(swap_cx, user_satp.inner(), asid)
}
SyscallResult::Retry => {
// 不跳过指令,继续运行
trap::switch_to_user(swap_cx, user_satp.inner(), asid)
}
SyscallResult::NextASID { asid, satp } => {
// 需要切换地址空间
// 跳过`do_yield`指令
swap_cx.epc = swap_cx.epc.wrapping_add(4);
// 需要转到目标地址空间去运行
// println!("[syscall] yield: {}", asid);
let next_swap_contex = unsafe { get_swap_cx(&satp, asid) };
trap::switch_to_user(next_swap_contex, satp.inner(), asid)
}
SyscallResult::KernelTask => {
// 需要运行内核任务
// 跳过 `do_yield` 指令
swap_cx.epc = swap_cx.epc.wrapping_add(4);
// println!("[syscall] yield kernel");
let shared_payload =
unsafe { async_rt::SharedPayload::load(crate::SHAREDPAYLOAD_BASE) };
trap::init();
async_rt::run_until_idle(
|| unsafe { shared_payload.peek_task(async_rt::kernel_should_switch) },
|task_repr| unsafe { shared_payload.delete_task(task_repr) },
|task_repr, new_state| unsafe {
shared_payload.set_task_state(task_repr, new_state)
},
);
crate::end()
}
SyscallResult::IOTask {
// 需要注册IO任务
block_id,
buf_ptr,
write,
} => {
let wake_task_repr = unsafe { next_task_repr() };
let process = KernelHartInfo::current_process().expect("get kernel process");
unsafe {
let shared_payload = async_rt::SharedPayload::load(SHAREDPAYLOAD_BASE);
let task = if write {
task::new_kernel(
write_block_task(
block_id,
buf_ptr,
user_satp.inner(),
wake_task_repr,
),
process,
shared_payload.shared_scheduler,
shared_payload.shared_set_task_state,
)
} else {
task::new_kernel(
read_block_task(
block_id,
buf_ptr,
user_satp.inner(),
wake_task_repr,
),
process,
shared_payload.shared_scheduler,
shared_payload.shared_set_task_state,
)
};
let task_repr = task.task_repr();
// println!("[syscall] new kernel task: {:x}", task_repr);
ext_intr_off();
shared_payload.add_task(0, AddressSpaceId::from_raw(0), task_repr);
ext_intr_on();
}
// 运行下一条指令
swap_cx.epc = swap_cx.epc.wrapping_add(4);
trap::switch_to_user(swap_cx, user_satp.inner(), asid)
}
SyscallResult::Check => {
// 内核检查
// 如果有未唤醒的块设备读写任务,将其唤醒
unsafe {
if WAKE_NUM > 1 {
VIRTIO_BLOCK.0.wake_ops.notify(WAKE_NUM);
WAKE_NUM = 1;
}
}
// 运行下一条指令
swap_cx.epc = swap_cx.epc.wrapping_add(4);
trap::switch_to_user(swap_cx, user_satp.inner(), asid)
}
SyscallResult::Terminate(_exit_code) => {
// 用户执行器认为可以退出系统了
println!("User exit!");
crate::sbi::shutdown();
}
}
}
Trap::Interrupt(Interrupt::SupervisorExternal) => {
// 用户态被外部中断打断
// 用户态被外部中断打断
//
// todo: 这里有个问题,就是最后一次外部中断的时候程序运行在共享调度器里面的时候
// 后面的任务不会被唤醒,执行器一直轮询找不到`醒着的`任务
//
// 目前的想法是用户执行器需要一个自检机制,当一直轮询找不到任务的次数达到某个阈值的时候
// 通过一个系统调用陷入内核检查是否有没有唤醒的块设备读写任务,将其唤醒
unsafe {
let irq = plic::plic_claim();
if irq == 1 {
// virtio 外部中断
let _intr_ret = VIRTIO_BLOCK.handle_interrupt().unwrap();
let sepc = sepc::read();
if sepc < SHAREDPAYLOAD_BASE {
println!("extr intr in user");
// 运行在用户程序中
// 唤醒一定数量的任务
VIRTIO_BLOCK.0.wake_ops.notify(WAKE_NUM);
WAKE_NUM = 1;
} else {
// 运行在共享调度器中
// 这里不唤醒,增加计数,下次外部中断来的时候一起唤醒
println!("extr intr in shared");
WAKE_NUM += 1;
}
plic::plic_complete(irq);
// 不跳过指令回到用户态运行
trap::switch_to_user(swap_cx, user_satp.inner(), asid)
} else {
panic!("unknown S mode external interrupt! irq: {}", irq);
}
}
}
Trap::Exception(scause::Exception::IllegalInstruction) => {
let sepc = sepc::read();
let vpn = VirtualPageNumber::ceil(VirtualAddress(sepc));
let ppn = user_satp.translate(vpn).unwrap();
let ptr = ppn.start_address().virtual_address_linear().0 as *const usize;
let ins: usize = unsafe { core::ptr::read_volatile(ptr) };
panic!("[exception] invalid instruction, sepc: {:016x?}, instruction: {:016x?}, swap_cx: {:x?}", sepc, ins, swap_cx);
}
_ => todo!(
"scause: {:?}, sepc: {:#x}, stval: {:#x}, {:x?}",
scause::read().cause(),
sepc::read(),
stval::read(),
swap_cx
),
}
}
/// 获取[`SwapContext`]的可变引用
///
/// 给定satp寄存器,获取[`SwapContext`]的裸指针
///
/// todo: 需要根据地址空间编号来得到[`SwapContext`]
pub unsafe fn get_swap_cx<'cx>(satp: &'cx Satp, asid: usize) -> &'cx mut SwapContext {
let swap_cx_va = VirtualAddress(memory::swap_contex_va(asid));
let swap_cx_vpn = VirtualPageNumber::floor(swap_cx_va);
let swap_cx_ppn = satp.translate(swap_cx_vpn).unwrap();
// 将物理页号转换成裸指针
(swap_cx_ppn
.start_address()
.0
.wrapping_add(KERNEL_MAP_OFFSET) as *mut SwapContext)
.as_mut()
.unwrap()
}
#[allow(missing_docs)]
async fn read_block_task(block_id: usize, buf_ptr: usize, user_satp: usize, wake_task_repr: usize) {
let buf = unsafe { super::get_user_buf_mut(user_satp, buf_ptr, BLOCK_SIZE) };
#[cfg(feature = "qemu")]
VIRTIO_BLOCK.read_block(block_id, buf).await;
#[cfg(feature = "k210")]
SD_CARD.read_block(block_id, buf).await;
unsafe {
let shared_payload = async_rt::SharedPayload::load(SHAREDPAYLOAD_BASE);
ext_intr_off();
shared_payload.set_task_state(wake_task_repr, TaskState::Ready);
ext_intr_on();
}
}
#[allow(missing_docs)]
async fn write_block_task(
block_id: usize,
buf_ptr: usize,
user_satp: usize,
wake_task_repr: usize,
) {
let buf = unsafe { super::get_user_buf_mut(user_satp, buf_ptr, BLOCK_SIZE) };
VIRTIO_BLOCK.write_block(block_id, buf).await;
unsafe {
let shared_payload = async_rt::SharedPayload::load(SHAREDPAYLOAD_BASE);
ext_intr_off();
shared_payload.set_task_state(wake_task_repr, TaskState::Ready);
ext_intr_on();
}
}
/// 从共享调度器中拿出下一个任务的指针,不弹出
///
/// note: 这个函数需要保证调用时共享调度器`peek_task`的返回值是[`TaskResult::Task`]
///
/// 一般只用于`enroll_read`或`enroll_write`系统调用
unsafe fn next_task_repr() -> usize {
let shared_payload = async_rt::SharedPayload::load(SHAREDPAYLOAD_BASE);
ext_intr_off();
let next_task = shared_payload.peek_task(should_switch);
ext_intr_on();
match next_task {
task::TaskResult::Task(task_repr) => task_repr,
_ => unreachable!(),
}
}
extern "C" fn should_switch(asid: AddressSpaceId) -> bool {
asid.into_inner() != KernelHartInfo::get_prev_asid()
}
/// 读取当前 PC 值
#[allow(unused)]
#[inline]
fn read_pc() -> usize {
let pc: usize;
unsafe {
asm!("auipc {}, 0", out(reg) pc, options(nomem, nostack));
}
pc
}