Skip to content
Open

Ch4 #21

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
3 changes: 2 additions & 1 deletion os/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ bitflags = "1.2.1"
buddy_system_allocator = "0.6"
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
log = "0.4"
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
riscv = { git = "https://gitee.com/rcore-os/riscv", features = ["inline-asm"] }
virtio-drivers = { git = "https://gitee.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
xmas-elf = "0.7.0"
25 changes: 25 additions & 0 deletions os/src/mm/memory_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ impl MemorySet {
None,
);
}

/// Unmap a area
pub fn remove_framed_area(
&mut self,
start_va: VirtAddr,
end_va: VirtAddr,
) -> isize {
let start_vpn: VirtPageNum = start_va.floor();
let end_vpn: VirtPageNum = end_va.ceil();
let vpns = VPNRange::new(start_vpn, end_vpn);
for vpn in vpns {
if let Some(pte) = self.page_table.translate(vpn) {
if !pte.is_valid() {
return -1;
}
self.page_table.unmap(vpn);
} else {
return -1;
}
}
0
}

fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
map_area.map(&mut self.page_table);
if let Some(data) = data {
Expand Down Expand Up @@ -386,6 +409,8 @@ pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
(bottom, top)
}



/// remap test in kernel space
#[allow(unused)]
pub fn remap_test() {
Expand Down
71 changes: 70 additions & 1 deletion os/src/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod memory_set;
mod page_table;

pub use address::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum};
use address::{StepByOne, VPNRange};
pub use address::{StepByOne, VPNRange};
pub use frame_allocator::{frame_alloc, FrameTracker};
pub use memory_set::remap_test;
pub use memory_set::{kernel_stack_position, MapPermission, MemorySet, KERNEL_SPACE};
Expand All @@ -26,3 +26,72 @@ pub fn init() {
frame_allocator::init_frame_allocator();
KERNEL_SPACE.exclusive_access().activate();
}

///
pub fn copy_to_user(user_token: usize, user_ptr: *mut u8, kernel_src: *const u8, len: usize) -> Result<(), ()> {
let mut buffers = translated_byte_buffer(user_token, user_ptr, len);
let mut offset = 0;

for buf in buffers.iter_mut() {
let copy_len = core::cmp::min(buf.len(), len - offset);
if len == 0 || copy_len == 0 {
return Err(());
}
unsafe {
core::ptr::copy_nonoverlapping(kernel_src.add(offset), buf.as_mut_ptr(), copy_len);
}
offset += copy_len;
}

if offset == len {
Ok(())
} else {
Err(())
}
}

///
pub fn read_virtaddr(token: usize, virtaddr: usize) -> Result<isize, ()> {
let pgtb = PageTable::from_token(token);
let vpn = VirtAddr::from(virtaddr).floor();
// 获取pte
if let Some(pte) = pgtb.translate(vpn) {
if !pte.is_valid() || !pte.readable() {
//页表项无效或不可读
Err(())
} else {
let buf = translated_byte_buffer(token, virtaddr as *const u8, 1);
if buf.is_empty() {
Err(())
} else {
let val = buf[0][0];
Ok(val as isize)
}
}
} else {
Err(())
}
}

///
pub fn write_virtaddr(token: usize, virtaddr: usize, data: u8) -> Result<(), ()> {
let pgtb = PageTable::from_token(token);
let vpn = VirtAddr::from(virtaddr).floor();
// 获取pte
if let Some(pte) = pgtb.translate(vpn) {
if !pte.is_valid() || !pte.writable() {
//页表项无效或不可写
Err(())
} else {
let mut buf = translated_byte_buffer(token, virtaddr as *const u8, 1);
if buf.is_empty() {
Err(())
} else {
buf[0][0] = data;
Ok(())
}
}
} else {
Err(())
}
}
1 change: 1 addition & 0 deletions os/src/mm/page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,4 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
}
v
}

5 changes: 5 additions & 0 deletions os/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
//! For clarity, each single syscall is implemented as its own function, named
//! `sys_` then the name of the syscall. You can find functions like this in
//! submodules, and you should also implement syscalls this way.

use crate::task::syscall_num_inc;

/// write syscall
const SYSCALL_WRITE: usize = 64;
/// exit syscall
const SYSCALL_EXIT: usize = 93;
Expand All @@ -33,6 +37,7 @@ use process::*;

/// handle syscall exception with `syscall_id` and other arguments
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
syscall_num_inc(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
115 changes: 106 additions & 9 deletions os/src/syscall/process.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
//! Process management syscalls
use crate::task::{change_program_brk, exit_current_and_run_next, suspend_current_and_run_next};

use crate::config::MEMORY_END;
use crate::task::{get_syscall_times, change_program_brk, exit_current_and_run_next,
suspend_current_and_run_next, current_user_token, map_new_area,
munmap_used_area};
use crate::timer::get_time_us;
use crate::mm::{copy_to_user, read_virtaddr, write_virtaddr, MapPermission};
use crate::mm::{VPNRange, VirtAddr, PageTable};

#[repr(C)]
#[derive(Debug)]
Expand All @@ -25,28 +32,118 @@ pub fn sys_yield() -> isize {
/// YOUR JOB: get time with second and microsecond
/// HINT: You might reimplement it with virtual memory management.
/// HINT: What if [`TimeVal`] is splitted by two pages ?
pub fn sys_get_time(_ts: *mut TimeVal, _tz: usize) -> isize {
pub fn sys_get_time(ts: *mut TimeVal, _tz: usize) -> isize {
trace!("kernel: sys_get_time");
-1
let us = get_time_us();
let time_val = TimeVal {
sec: us / 1_000_000,
usec: us % 1_000_000,
};
let user_token = current_user_token(); // 获取当前任务的虚拟内存上下文
let kernel_src = &time_val as *const TimeVal as *const u8;
let len = core::mem::size_of::<TimeVal>();

// 使用封装函数复制数据到用户态
if copy_to_user(user_token, ts as *mut u8, kernel_src, len).is_ok() {
0 // 返回成功
} else {
-1 // 返回失败
}
}

/// TODO: Finish sys_trace to pass testcases
/// HINT: You might reimplement it with virtual memory management.
pub fn sys_trace(_trace_request: usize, _id: usize, _data: usize) -> isize {
pub fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize {
trace!("kernel: sys_trace");
-1
if id > MEMORY_END {
return -1;
}
match trace_request {
// _trace_request = 0, 获取当前任务id地址处一个字节的无符号整数值
0 => {
let addr = id as usize;
let cur_token = current_user_token();
match read_virtaddr(cur_token, addr) {
Ok(val) => return val,
Err(()) => return -1 as isize,
};
},
// _trace_request = 1, 将data写入到id对应地址处
1 => {
let addr = id as usize;
let cur_token = current_user_token();
match write_virtaddr(cur_token, addr, data as u8) {
Ok(()) => 0 as isize,
Err(()) => -1 as isize,
}
},
// _trace_request = 2, 查询编号为id的系统调用的调用次数
2 => {
get_syscall_times(id) as isize
},
_ => -1,
}
}

// YOUR JOB: Implement mmap.
pub fn sys_mmap(_start: usize, _len: usize, _port: usize) -> isize {
pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
trace!("kernel: sys_mmap NOT IMPLEMENTED YET!");
-1
let start_va = VirtAddr(start);
if !start_va.aligned() {
return -1;
}
if len <= 0 {
return -1;
}
if (prot & !0x7 != 0) || (prot & 0x7 == 0) {
return -1;
}
// len按页向上取整
let start_va = VirtAddr(start).floor();
let end_va = VirtAddr(start + len).ceil();
let pgtb = PageTable::from_token(current_user_token());

// 检查虚拟地址是否已经被映射
let vpns = VPNRange::new(start_va, end_va);
for vpn in vpns {
if let Some(pte) = pgtb.translate(vpn) {
if pte.is_valid() {
return -1;
}
}
};

// 构造permission: MapPermission
let mut perm: MapPermission = MapPermission::U;
if prot & 0x1 != 0 {
perm |= MapPermission::R;
}
if prot & 0x2 != 0 {
perm |= MapPermission::W;
}
if prot & 0x4 != 0 {
perm |= MapPermission::X;
}
// 完成虚拟地址到物理地址的映射
map_new_area(start_va.into(), end_va.into(), perm);
0
}

// YOUR JOB: Implement munmap.
pub fn sys_munmap(_start: usize, _len: usize) -> isize {
pub fn sys_munmap(start: usize, len: usize) -> isize {
trace!("kernel: sys_munmap NOT IMPLEMENTED YET!");
-1
// 处理参数,获取需要取消映射的区间
let start_va = VirtAddr(start);
if !start_va.aligned() {
return -1;
}
if len <= 0 {
return -1;
}
let start_vpn = start_va.floor();
let end_vpn = VirtAddr(start + len).ceil();
// munmap_used_area的实现参考了荣誉准则标注的内容
munmap_used_area(start_vpn.into(), end_vpn.into())
}
/// change data segment size
pub fn sys_sbrk(size: i32) -> isize {
Expand Down
54 changes: 54 additions & 0 deletions os/src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ mod switch;
#[allow(clippy::module_inception)]
mod task;

use crate::config::MAX_SYSCALL_NUM;
use crate::loader::{get_app_data, get_num_app};
use crate::sync::UPSafeCell;
use crate::trap::TrapContext;
use alloc::vec::Vec;
use lazy_static::*;
use switch::__switch;
pub use task::{TaskControlBlock, TaskStatus};
use crate::mm::{VirtAddr, MapPermission};

pub use context::TaskContext;

Expand Down Expand Up @@ -153,6 +155,46 @@ impl TaskManager {
panic!("All applications completed!");
}
}

// syscall_num_inc
fn syscall_num_inc(&self, id: usize) {
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
if id <= MAX_SYSCALL_NUM {
inner.tasks[current].task_syscall_num[id] += 1;
}
}

fn get_syscall_times(&self, id: usize) -> u8{
let inner = self.inner.exclusive_access();
let current = inner.current_task;
inner.tasks[current].task_syscall_num[id]
}

fn map_new_area(&self, start_va: VirtAddr,
end_va: VirtAddr,
permission: MapPermission) -> () {
let mut inner = self.inner.exclusive_access();
let cur = inner.current_task;
inner.tasks[cur].map_virtual_area(start_va, end_va, permission);
}

fn munmap_used_area(&self, start_va: VirtAddr, end_va: VirtAddr) -> isize {
let mut inner = self.inner.exclusive_access();
let cur = inner.current_task;
let res = inner.tasks[cur].memory_set.remove_framed_area(start_va, end_va);
res
}
}

/// increase num_syscall[id]
pub fn syscall_num_inc(id: usize) {
TASK_MANAGER.syscall_num_inc(id);
}

/// Get the number of times the syscall with call number id is used.
pub fn get_syscall_times(id: usize) -> u8{
TASK_MANAGER.get_syscall_times(id)
}

/// Run the first task in task list.
Expand Down Expand Up @@ -193,6 +235,18 @@ pub fn current_user_token() -> usize {
TASK_MANAGER.get_current_token()
}

/// Map a new virtual area
pub fn map_new_area(start_va: VirtAddr,
end_va: VirtAddr,
permission: MapPermission) -> () {
TASK_MANAGER.map_new_area(start_va, end_va, permission);
}

///
pub fn munmap_used_area(start_va: VirtAddr, end_va: VirtAddr) -> isize{
TASK_MANAGER.munmap_used_area(start_va, end_va)
}

/// Get the current 'Running' task's trap contexts.
pub fn current_trap_cx() -> &'static mut TrapContext {
TASK_MANAGER.get_current_trap_cx()
Expand Down
Loading