Skip to content

Commit 1380c09

Browse files
committed
ch4 ok
1 parent 4014758 commit 1380c09

File tree

9 files changed

+348
-11
lines changed

9 files changed

+348
-11
lines changed

os/src/mm/memory_set.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,40 @@ impl MemorySet {
262262
false
263263
}
264264
}
265+
266+
/// find target area by start_va, then insert it to areas
267+
pub fn find_area_insert(&mut self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) -> bool {
268+
if let Some(_area) = self.areas.iter().find(|area| {
269+
debug!("=============== insert ===============");
270+
debug!("area start: {}, end: {}", area.vpn_range.get_start().0, area.vpn_range.get_end().0);
271+
debug!("target area start: {}, end: {}", start_va.floor().0, end_va.ceil().0);
272+
debug!("======================================");
273+
area.vpn_range.get_start() < end_va.ceil() && area.vpn_range.get_end() > start_va.floor()
274+
}) {
275+
debug!("!!! find area has been used !!!");
276+
false
277+
} else {
278+
debug!("!!! area not be used, insert it!!!");
279+
self.insert_framed_area(start_va, end_va, permission);
280+
true
281+
}
282+
}
283+
/// find target area by start_va, then remove it from areas
284+
pub fn find_area_remove(&mut self, start_va: VirtAddr, end_va: VirtAddr) -> bool {
285+
if let Some(index) = self.areas.iter().position(|area| {
286+
debug!("=============== remove ===============");
287+
debug!("area start: {}, end: {}", area.vpn_range.get_start().0, area.vpn_range.get_end().0);
288+
debug!("target area start: {}, end: {}", start_va.floor().0, end_va.ceil().0);
289+
debug!("======================================");
290+
area.vpn_range.get_start() == start_va.floor() && area.vpn_range.get_end() == end_va.ceil()
291+
}) {
292+
self.areas[index].unmap(&mut self.page_table);
293+
self.areas.remove(index);
294+
true
295+
} else {
296+
false
297+
}
298+
}
265299
}
266300
/// map area structure, controls a contiguous piece of virtual memory
267301
pub struct MapArea {

os/src/mm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use address::{StepByOne, VPNRange};
1717
pub use frame_allocator::{frame_alloc, FrameTracker};
1818
pub use memory_set::remap_test;
1919
pub use memory_set::{kernel_stack_position, MapPermission, MemorySet, KERNEL_SPACE};
20-
pub use page_table::{translated_byte_buffer, PageTableEntry};
20+
pub use page_table::{translated_byte_buffer, translated_physaddr, PageTableEntry};
2121
pub use page_table::{PTEFlags, PageTable};
2222

2323
/// initiate heap allocator, frame allocator and kernel space

os/src/mm/page_table.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Implementation of [`PageTableEntry`] and [`PageTable`].
22
3-
use super::{frame_alloc, FrameTracker, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
3+
use super::{frame_alloc, FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
44
use alloc::vec;
55
use alloc::vec::Vec;
66
use bitflags::*;
@@ -179,3 +179,16 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
179179
}
180180
v
181181
}
182+
183+
/// translate a ptr and return its mut
184+
pub fn translated_physaddr(token: usize, ptr: *const u8) -> PhysAddr {
185+
let page_table = PageTable::from_token(token);
186+
let va = VirtAddr::from(ptr as usize);
187+
let vpn = va.floor();
188+
let ppn: PhysPageNum = page_table.translate(vpn).unwrap().ppn();
189+
let pa: PhysAddr = ppn.into();
190+
191+
let offset = va.page_offset();
192+
let pa_offset = (pa.0 + offset).into();
193+
return pa_offset;
194+
}

os/src/syscall/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ mod process;
3131
use fs::*;
3232
use process::*;
3333

34+
use crate::task::TASK_MANAGER;
35+
3436
/// handle syscall exception with `syscall_id` and other arguments
3537
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
38+
TASK_MANAGER.add_syscall_counter(syscall_id);
3639
match syscall_id {
3740
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
3841
SYSCALL_EXIT => sys_exit(args[0] as i32),

os/src/syscall/process.rs

Lines changed: 107 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Process management syscalls
2-
use crate::task::{change_program_brk, exit_current_and_run_next, suspend_current_and_run_next};
2+
use crate::{mm::{translated_physaddr, MapPermission, PTEFlags, PageTable, VirtAddr}, task::{change_program_brk, current_user_token, exit_current_and_run_next, suspend_current_and_run_next, TASK_MANAGER}, timer::get_time_us};
33

44
#[repr(C)]
55
#[derive(Debug)]
@@ -27,26 +27,126 @@ pub fn sys_yield() -> isize {
2727
/// HINT: What if [`TimeVal`] is splitted by two pages ?
2828
pub fn sys_get_time(_ts: *mut TimeVal, _tz: usize) -> isize {
2929
trace!("kernel: sys_get_time");
30-
-1
30+
let pa = translated_physaddr(current_user_token(), _ts as *const u8);
31+
let phy_ts = pa.0 as *mut TimeVal;
32+
33+
let us = get_time_us();
34+
let time_val = TimeVal {
35+
sec : us / 1_000_000,
36+
usec: us % 1_000_000,
37+
};
38+
39+
unsafe { *phy_ts = time_val };
40+
0
41+
}
42+
43+
fn is_readable(va: usize) -> bool {
44+
let vpn = VirtAddr::from(va).floor();
45+
if let Some(pte) = PageTable::from_token(current_user_token()).translate(vpn) {
46+
pte.flags().contains(PTEFlags::U | PTEFlags::R)
47+
} else {
48+
false
49+
}
50+
}
51+
52+
fn is_writeable(va: usize) -> bool {
53+
let vpn = VirtAddr::from(va).floor();
54+
if let Some(pte) = PageTable::from_token(current_user_token()).translate(vpn) {
55+
pte.flags().contains(PTEFlags::U | PTEFlags::W)
56+
} else {
57+
false
58+
}
3159
}
3260

3361
/// TODO: Finish sys_trace to pass testcases
3462
/// HINT: You might reimplement it with virtual memory management.
3563
pub fn sys_trace(_trace_request: usize, _id: usize, _data: usize) -> isize {
3664
trace!("kernel: sys_trace");
37-
-1
65+
match _trace_request {
66+
0 => {
67+
if !is_readable(_id) {
68+
return -1;
69+
}
70+
let pa = translated_physaddr(current_user_token(), _id as *const u8);
71+
let phy_data = pa.0 as *mut u8;
72+
unsafe { (*phy_data).into() }
73+
},
74+
1 => {
75+
if !is_writeable(_id) {
76+
return -1;
77+
}
78+
let pa = translated_physaddr(current_user_token(), _id as *const u8);
79+
let phy_data = pa.0 as *mut u8;
80+
unsafe { *phy_data = _data as u8 ; };
81+
return 0;
82+
},
83+
2 => TASK_MANAGER.get_syscall_counter(_id).try_into().unwrap(),
84+
_ => -1
85+
}
86+
}
87+
88+
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
89+
pub struct Flag(pub usize);
90+
91+
impl Flag {
92+
pub fn is_readable(&self) -> bool {
93+
self.0 & 0x1 == 0x1
94+
}
95+
96+
pub fn is_writeable(&self) -> bool {
97+
self.0 & 0x2 == 0x2
98+
}
99+
100+
pub fn is_execute(&self) -> bool {
101+
self.0 & 0x4 == 0x4
102+
}
38103
}
39104

40105
// YOUR JOB: Implement mmap.
41106
pub fn sys_mmap(_start: usize, _len: usize, _port: usize) -> isize {
42-
trace!("kernel: sys_mmap NOT IMPLEMENTED YET!");
43-
-1
107+
trace!("kernel: sys_mmap ");
108+
109+
debug!("mmap start: {}, len: {}, port: {}", _start, _len, _port);
110+
111+
let start_va = VirtAddr::from(_start);
112+
if !start_va.aligned() {
113+
return -1;
114+
}
115+
let end_va: VirtAddr = (_start + _len).into();
116+
if _port & !0x7 != 0 || _port & 0x7 == 0 {
117+
return -1;
118+
}
119+
120+
let mut map_perm: MapPermission = MapPermission::U;
121+
let pte_flag = Flag(_port);
122+
if pte_flag.is_readable() {
123+
map_perm |= MapPermission::R;
124+
}
125+
if pte_flag.is_writeable() {
126+
map_perm |= MapPermission::W;
127+
}
128+
if pte_flag.is_execute() {
129+
map_perm |= MapPermission::X;
130+
}
131+
132+
if !TASK_MANAGER.find_area_insert(start_va, end_va, map_perm) {
133+
return -1;
134+
}
135+
return 0;
44136
}
45137

46138
// YOUR JOB: Implement munmap.
47139
pub fn sys_munmap(_start: usize, _len: usize) -> isize {
48-
trace!("kernel: sys_munmap NOT IMPLEMENTED YET!");
49-
-1
140+
trace!("kernel: sys_munmap ");
141+
let start_va = VirtAddr::from(_start);
142+
if !start_va.aligned() {
143+
return -1;
144+
}
145+
let end_va: VirtAddr = (_start + _len).into();
146+
if !TASK_MANAGER.find_area_remove(start_va, end_va) {
147+
return -1;
148+
}
149+
return 0;
50150
}
51151
/// change data segment size
52152
pub fn sys_sbrk(size: i32) -> isize {

os/src/task/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod switch;
1515
mod task;
1616

1717
use crate::loader::{get_app_data, get_num_app};
18+
use crate::mm::{VirtAddr, MapPermission};
1819
use crate::sync::UPSafeCell;
1920
use crate::trap::TrapContext;
2021
use alloc::vec::Vec;
@@ -133,6 +134,32 @@ impl TaskManager {
133134
inner.tasks[cur].change_program_brk(size)
134135
}
135136

137+
/// add syscall counter by syscall_id
138+
pub fn add_syscall_counter(&self, syscall_id: usize) {
139+
let mut inner = self.inner.exclusive_access();
140+
let cur = inner.current_task;
141+
inner.tasks[cur].add_syscall_counter(syscall_id);
142+
}
143+
144+
/// get syscall counter by syscall_id
145+
pub fn get_syscall_counter(&self, syscall_id: usize) -> usize {
146+
let inner = self.inner.exclusive_access();
147+
inner.tasks[inner.current_task].get_syscall_counter(syscall_id)
148+
}
149+
150+
/// find area of memory to insert, return false if not found
151+
pub fn find_area_insert(&self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) -> bool {
152+
let mut inner = self.inner.exclusive_access();
153+
let cur = inner.current_task;
154+
inner.tasks[cur].find_area_insert(start_va, end_va, permission)
155+
}
156+
/// find area of memory to remove, return false if not found
157+
pub fn find_area_remove(&self, start_va: VirtAddr, end_va: VirtAddr) -> bool {
158+
let mut inner = self.inner.exclusive_access();
159+
let cur = inner.current_task;
160+
inner.tasks[cur].find_area_remove(start_va, end_va)
161+
}
162+
136163
/// Switch current `Running` task to the task we have found,
137164
/// or there is no `Ready` task and we can exit with all applications completed
138165
fn run_next_task(&self) {

os/src/task/task.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Types related to task management
22
use super::TaskContext;
3-
use crate::config::TRAP_CONTEXT_BASE;
3+
use crate::config::{MAX_SYSCALL_NUM, TRAP_CONTEXT_BASE};
44
use crate::mm::{
5-
kernel_stack_position, MapPermission, MemorySet, PhysPageNum, VirtAddr, KERNEL_SPACE,
5+
kernel_stack_position, MemorySet, MapPermission, PhysPageNum, VirtAddr, KERNEL_SPACE,
66
};
77
use crate::trap::{trap_handler, TrapContext};
88

@@ -28,6 +28,9 @@ pub struct TaskControlBlock {
2828

2929
/// Program break
3030
pub program_brk: usize,
31+
32+
/// Syscall counter
33+
pub syscall_counter: [usize; MAX_SYSCALL_NUM]
3134
}
3235

3336
impl TaskControlBlock {
@@ -63,6 +66,7 @@ impl TaskControlBlock {
6366
base_size: user_sp,
6467
heap_bottom: user_sp,
6568
program_brk: user_sp,
69+
syscall_counter: [0; MAX_SYSCALL_NUM]
6670
};
6771
// prepare TrapContext in user space
6872
let trap_cx = task_control_block.get_trap_cx();
@@ -96,6 +100,22 @@ impl TaskControlBlock {
96100
None
97101
}
98102
}
103+
/// add syscall counter by syscall_id
104+
pub fn add_syscall_counter(&mut self, syscall_id: usize) {
105+
self.syscall_counter[syscall_id] += 1;
106+
}
107+
/// get syscall counter by syscall_id
108+
pub fn get_syscall_counter(&self, syscall_id: usize) -> usize {
109+
self.syscall_counter[syscall_id]
110+
}
111+
/// find area of memory set to insert
112+
pub fn find_area_insert(&mut self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) -> bool {
113+
self.memory_set.find_area_insert(start_va, end_va, permission)
114+
}
115+
/// find area of memory set to remove
116+
pub fn find_area_remove(&mut self, start_va: VirtAddr, end_va: VirtAddr) -> bool {
117+
self.memory_set.find_area_remove(start_va, end_va)
118+
}
99119
}
100120

101121
#[derive(Copy, Clone, PartialEq)]

reports/lab1.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
### 总结实现的功能
2+
`sys_trace`实现了三个功能:
3+
1. 根据传入的参数(_id)读取对应内存地址的值并返回
4+
2. 根据传入的参数(_id, _data)向对应地址写入值
5+
3. 获取传入的参数(_id)对应的系统调用执行的次数
6+
7+
为了实现第3个功能,我修改了`TaskManagerInner`结构体,向里面添加了对应不同系统调用的计数器,用于统计不同系统调用的执行次数。并且,提供了两个函数`add_syscall_counter``get_syscall_counter`用于修改和查询系统调用的执行次数。
8+
9+
### 问答题
10+
#### 1. 正确进入 U 态后,程序的特征还应有:使用 S 态特权指令,访问 S 态寄存器后会报错。 请同学们可以自行测试这些内容(运行 三个 bad 测例 (ch2b_bad_*.rs) ), 描述程序出错行为,同时注意注明你使用的 sbi 及其版本。
11+
12+
使用RustSBI,版本号:version 0.4.0-alpha.1
13+
14+
- ch2b_bad_address.rs: OS首先输出`PageFault`异常,这表明程序尝试请求非法的内存地址,OS提示该地址`bad addr = 0x0`,且该错误的指令存储在这个位置:`bad instruction = 0x804003a4`
15+
16+
如果同时运行三个bad测例,则后两个测例的输出为:`IllegalInstruction in application, kernel killed it.`
17+
18+
我尝试单独运行后两个测例后,可得到以下输出:
19+
- ch2b_bad_instructions.rs: OS会输出`InstructionFault`非法指令异常,此时`stval = 0x0`
20+
- ch2b_bad_register.rs: 此测例会在进行系统调用时提示不支持的trap异常,`scause`的输出信息为`LoadFault``stval = 0x10`,这表明程序在U模式尝试访问了S模式的寄存器,导致程序出错。
21+
22+
#### 2.深入理解 trap.S 中两个函数 __alltraps 和 __restore 的作用,并回答如下问题:
23+
1. L40:刚进入 __restore 时,sp 代表了什么值。请指出 __restore 的两种使用情景。
24+
- sp指向了内核栈的TrapContext结构体的起始位置,也就是内核态的栈指针
25+
- 使用场景:
26+
- 在任务上下文切换中,__restore会成为__switch返回后继续执行的函数
27+
- Trap处理后的返回
28+
29+
2. L43-L48:这几行汇编代码特殊处理了哪些寄存器?这些寄存器的的值对于进入用户态有何意义?请分别解释。
30+
分别处理了以下寄存器:
31+
- sstatus: 记录和控制当前特权级别以及在异常发生前的特权级别,同时还能够恢复用户程序的中断使能状态。
32+
- sepc: 将内核TrapContext的pc值保存,在后面执行`sret`指令从S态返回时,pc寄存器将从sepc寄存器中读取该值。
33+
- sscratch: 在特权级切换的过程中,sscratch和sp寄存器会互相交换值,从而保存用户态或者内核态的栈指针
34+
35+
3. L50-L56:为何跳过了 x2 和 x4?
36+
- x2 寄存器就是 sp寄存器,我们通过 csrrw 指令将sp寄存器和sscratch寄存器的值进行交换保存了
37+
- x4 寄存器是 tp寄存器,用于支持线程局部存储,这个寄存器只有在某些特殊用途的情况下会用到。
38+
39+
4. L60:该指令之后,sp 和 sscratch 中的值分别有什么意义?
40+
- sp: 存储的是用户态的栈指针
41+
- sscratch: 暂存了内核态的栈指针
42+
43+
5. __restore:中发生状态切换在哪一条指令?为何该指令执行之后会进入用户态?
44+
- 状态切换发生在`sret`指令
45+
- `sret`指令会将特权级别切换到`sstatus.SPP`指定的特权级别。从用户态进入内核态时,硬件会自动将`sstatus.SPP`设置为0,表示之前是用户态。所以执行`sret`后会进入用户态。并且,在执行`sret`之前,我们已经正确设置了sepc和sstatus寄存器,从而使得进入用户态后,程序能够跳转到正确的地址执行。
46+
47+
6. L13:该指令之后,sp 和 sscratch 中的值分别有什么意义?
48+
- sp: 指向了内核栈的TrapContext结构体的起始位置,也就是内核态的栈指针
49+
- sscratch: 暂存了用户态TrapContext结构体的起始位置,也就是用户态的栈指针
50+
51+
7. 从 U 态进入 S 态是哪一条指令发生的?
52+
`ecall`
53+
54+
### 荣誉准则
55+
1. 在完成本次实验的过程(含此前学习的过程)中,我曾分别与 以下各位 就(与本次实验相关的)以下方面做过交流,还在代码中对应的位置以注释形式记录了具体的交流对象及内容:
56+
57+
向claude3.7老师请教了许多问题,感谢它的帮助
58+
59+
2. 此外,我也参考了 以下资料 ,还在代码中对应的位置以注释形式记录了具体的参考来源及内容:
60+
61+
参考了 https://cheats.rs/ 手册的一些语法细节。
62+
63+
3. 我独立完成了本次实验除以上方面之外的所有工作,包括代码与文档。 我清楚地知道,从以上方面获得的信息在一定程度上降低了实验难度,可能会影响起评分。
64+
65+
4. 我从未使用过他人的代码,不管是原封不动地复制,还是经过了某些等价转换。 我未曾也不会向他人(含此后各届同学)复制或公开我的实验代码,我有义务妥善保管好它们。 我提交至本实验的评测系统的代码,均无意于破坏或妨碍任何计算机系统的正常运转。 我清楚地知道,以上情况均为本课程纪律所禁止,若违反,对应的实验成绩将按“-100”分计。

0 commit comments

Comments
 (0)