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
6 changes: 6 additions & 0 deletions os/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ mod process;
use fs::*;
use process::*;

use crate::task::{add_syscall_count};

/// max syscall id
pub const MAX_SYSCALL_ID: usize = 474;

/// handle syscall exception with `syscall_id` and other arguments
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
add_syscall_count(syscall_id);
match syscall_id {
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
SYSCALL_EXIT => sys_exit(args[0] as i32),
Expand Down
21 changes: 19 additions & 2 deletions os/src/syscall/process.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Process management syscalls
use crate::{
task::{exit_current_and_run_next, suspend_current_and_run_next},
task::{exit_current_and_run_next, suspend_current_and_run_next, get_syscall_count},
timer::get_time_us,
};

Expand Down Expand Up @@ -29,6 +29,7 @@ pub fn sys_yield() -> isize {
pub fn sys_get_time(ts: *mut TimeVal, _tz: usize) -> isize {
trace!("kernel: sys_get_time");
let us = get_time_us();
trace!("kernel: sys_get_time, us = {}", us);
unsafe {
*ts = TimeVal {
sec: us / 1_000_000,
Expand All @@ -41,5 +42,21 @@ pub fn sys_get_time(ts: *mut TimeVal, _tz: usize) -> isize {
// TODO: implement the syscall
pub fn sys_trace(_trace_request: usize, _id: usize, _data: usize) -> isize {
trace!("kernel: sys_trace");
-1
match _trace_request {
0 => {
let id = _id as *const u8;
unsafe { *id as isize }
},
1 => {
let id = _id as *mut u8;
unsafe { *id = _data as u8 };
0
},
2 => {
get_syscall_count(_id) as isize
},
_ => {
-1
}
}
}
34 changes: 34 additions & 0 deletions os/src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ pub use task::{TaskControlBlock, TaskStatus};

pub use context::TaskContext;

pub use crate::syscall;
use crate::syscall::MAX_SYSCALL_ID;

/// The task manager, where all the tasks are managed.
///
/// Functions implemented on `TaskManager` deals with all task state transitions
Expand Down Expand Up @@ -54,6 +57,7 @@ lazy_static! {
let mut tasks = [TaskControlBlock {
task_cx: TaskContext::zero_init(),
task_status: TaskStatus::UnInit,
syscall_counts: [0; MAX_SYSCALL_ID],
}; MAX_APP_NUM];
for (i, task) in tasks.iter_mut().enumerate() {
task.task_cx = TaskContext::goto_restore(init_app_cx(i));
Expand Down Expand Up @@ -135,6 +139,26 @@ impl TaskManager {
panic!("All applications completed!");
}
}

/// Get syscall count of current task
fn get_syscall_count(&self, syscall_id: usize) -> usize {
let inner = self.inner.exclusive_access();
let current = inner.current_task;
let tcb = &inner.tasks[current];
let count = tcb.syscall_counts[syscall_id];
drop(inner);
count
}

/// Add syscall count of current task
fn add_syscall_count(&self, syscall_id: usize) {
// println!("add syscall count, syscall_id = {}", syscall_id);
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
let tcb = &mut inner.tasks[current];
tcb.syscall_counts[syscall_id] += 1;
drop(inner);
}
}

/// Run the first task in task list.
Expand Down Expand Up @@ -169,3 +193,13 @@ pub fn exit_current_and_run_next() {
mark_current_exited();
run_next_task();
}

/// Get syscall count of current task
pub fn get_syscall_count(syscall_id: usize) -> usize {
TASK_MANAGER.get_syscall_count(syscall_id)
}

/// Add syscall count of current task
pub fn add_syscall_count(syscall_id: usize) {
TASK_MANAGER.add_syscall_count(syscall_id);
}
6 changes: 5 additions & 1 deletion os/src/task/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

use super::TaskContext;

use crate::syscall::MAX_SYSCALL_ID;

/// The task control block (TCB) of a task.
#[derive(Copy, Clone)]
pub struct TaskControlBlock {
/// The task status in it's lifecycle
pub task_status: TaskStatus,
/// The task context
pub task_cx: TaskContext,
/// The syscall count
pub syscall_counts: [usize; MAX_SYSCALL_ID],
}

/// The status of a task
Expand All @@ -22,4 +26,4 @@ pub enum TaskStatus {
Running,
/// exited
Exited,
}
}
140 changes: 140 additions & 0 deletions reports/lab1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Lab1

## 实验题目

在 ch3 中,我们的系统已经能够支持多个任务分时轮流运行,我们希望引入一个新的系统调用 ``sys_trace``(ID 为 410)用来追踪当前任务系统调用的历史信息,并做对应的修改。定义如下。

```rust
fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize
```

- 调用规范:
- 这个系统调用有三种功能,根据 trace_request 的值不同,执行不同的操作:

- 如果 trace_request 为 0,则 id 应被视作 *const u8 ,表示读取当前任务 id 地址处一个字节的无符号整数值。此时应忽略 data 参数。返回值为 id 地址处的值。

如果 trace_request 为 1,则 id 应被视作 *mut u8 ,表示写入 data (作为 u8,即只考虑最低位的一个字节)到该用户程序 id 地址处。返回值应为0。

如果 trace_request 为 2,表示查询当前任务调用编号为 id 的系统调用的次数,返回值为这个调用次数。本次调用也计入统计 。

否则,忽略其他参数,返回值为 -1。

- 说明:
- 你可能会注意到,这个调用的读写并不安全,使用不当可能导致崩溃。这是因为在下一章节实现地址空间之前,系统中缺乏隔离机制。所以我们 不要求你实现安全检查机制,只需通过测试用例即可 。

- 你还可能注意到,这个系统调用读写本任务内存的功能并不是很有用。这是因为作业的灵感来源 syscall 主要依靠 trace 功能追踪其他任务的信息,但在本章节我们还没有进程、线程等概念,所以简化了操作,只要求追踪自身的信息。

## 解决方案

首先,我们需要在 `syscall` 中添加 `sys_trace` 系统调用的处理函数。

```rust
// TODO: implement the syscall
pub fn sys_trace(_trace_request: usize, _id: usize, _data: usize) -> isize {
trace!("kernel: sys_trace");
match _trace_request {
0 => {
let id = _id as *const u8;
unsafe { *id as isize }
},
1 => {
let id = _id as *mut u8;
unsafe { *id = _data as u8 };
0
},
2 => {
get_syscall_count(_id) as isize
},
_ => {
-1
}
}
}
```

- 0和1的情况比较简单,直接根据参数进行读写即可。

- 2的情况比较复杂,我们需要根据参数 id 来查询当前任务调用编号为 id 的系统调用的次数。

根据测试用例的要求,每个app的系统调用次数需要单独存储,因此不能直接使用一个内核中的数组来存储系统调用的次数

应当在每个TaskControlBlock中添加对系统调用次数的记录

```rust
/// The task control block (TCB) of a task.
#[derive(Copy, Clone)]
pub struct TaskControlBlock {
/// The task status in it's lifecycle
pub task_status: TaskStatus,
/// The task context
pub task_cx: TaskContext,
/// The syscall count
pub syscall_counts: [usize; MAX_SYSCALL_ID],
}
```

然后由 `TaskManager` 来对外暴露获取与增加系统调用计数的接口

```rust
/// Get syscall count of current task
fn get_syscall_count(&self, syscall_id: usize) -> usize {
let inner = self.inner.exclusive_access();
let current = inner.current_task;
let tcb = &inner.tasks[current];
let count = tcb.syscall_counts[syscall_id];
drop(inner);
count
}

/// Add syscall count of current task
fn add_syscall_count(&self, syscall_id: usize) {
// println!("add syscall count, syscall_id = {}", syscall_id);
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
let tcb = &mut inner.tasks[current];
tcb.syscall_counts[syscall_id] += 1;
drop(inner);
}
```

最后,在 `syscall` 中调用 `TaskManager` 提供的接口来增加系统调用计数

```rust
/// handle syscall exception with `syscall_id` and other arguments
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
add_syscall_count(syscall_id);
match syscall_id {
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
SYSCALL_EXIT => sys_exit(args[0] as i32),
SYSCALL_YIELD => sys_yield(),
SYSCALL_GET_TIME => sys_get_time(args[0] as *mut TimeVal, args[1]),
SYSCALL_TRACE => sys_trace(args[0], args[1], args[2]),
_ => panic!("Unsupported syscall_id: {}", syscall_id),
}
}
```

```rust
// TODO: implement the syscall
pub fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize {
trace!("kernel: sys_trace");
match trace_request {
0 => {
let id = id as *const u8;
unsafe { *id as isize }
},
1 => {
let id = id as *mut u8;
unsafe { *id = data as u8 };
0
},
2 => {
let count = get_syscall_count(id);
count as isize
},
_ => {
-1
}
}
}
```