commit
90b9070800
9 changed files with 154 additions and 2 deletions
|
@ -204,6 +204,16 @@ impl MemorySet {
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
// used in sbrk
|
||||||
|
memory_set.push(
|
||||||
|
MapArea::new(
|
||||||
|
user_stack_top.into(),
|
||||||
|
user_stack_top.into(),
|
||||||
|
MapType::Framed,
|
||||||
|
MapPermission::R | MapPermission::W | MapPermission::U,
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
);
|
||||||
// map TrapContext
|
// map TrapContext
|
||||||
memory_set.push(
|
memory_set.push(
|
||||||
MapArea::new(
|
MapArea::new(
|
||||||
|
@ -230,6 +240,32 @@ impl MemorySet {
|
||||||
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
|
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
|
||||||
self.page_table.translate(vpn)
|
self.page_table.translate(vpn)
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn shrink_to(&mut self, start: VirtAddr, new_end: VirtAddr) -> bool {
|
||||||
|
if let Some(area) = self
|
||||||
|
.areas
|
||||||
|
.iter_mut()
|
||||||
|
.find(|area| area.vpn_range.get_start() == start.floor())
|
||||||
|
{
|
||||||
|
area.shrink_to(&mut self.page_table, new_end.ceil());
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn append_to(&mut self, start: VirtAddr, new_end: VirtAddr) -> bool {
|
||||||
|
if let Some(area) = self
|
||||||
|
.areas
|
||||||
|
.iter_mut()
|
||||||
|
.find(|area| area.vpn_range.get_start() == start.floor())
|
||||||
|
{
|
||||||
|
area.append_to(&mut self.page_table, new_end.ceil());
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// map area structure, controls a contiguous piece of virtual memory
|
/// map area structure, controls a contiguous piece of virtual memory
|
||||||
|
@ -289,6 +325,20 @@ impl MapArea {
|
||||||
self.unmap_one(page_table, vpn);
|
self.unmap_one(page_table, vpn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn shrink_to(&mut self, page_table: &mut PageTable, new_end: VirtPageNum) {
|
||||||
|
for vpn in VPNRange::new(new_end, self.vpn_range.get_end()) {
|
||||||
|
self.unmap_one(page_table, vpn)
|
||||||
|
}
|
||||||
|
self.vpn_range = VPNRange::new(self.vpn_range.get_start(), new_end);
|
||||||
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn append_to(&mut self, page_table: &mut PageTable, new_end: VirtPageNum) {
|
||||||
|
for vpn in VPNRange::new(self.vpn_range.get_end(), new_end) {
|
||||||
|
self.map_one(page_table, vpn)
|
||||||
|
}
|
||||||
|
self.vpn_range = VPNRange::new(self.vpn_range.get_start(), new_end);
|
||||||
|
}
|
||||||
/// data: start-aligned but maybe with shorter length
|
/// data: start-aligned but maybe with shorter length
|
||||||
/// assume that all frames were cleared before
|
/// assume that all frames were cleared before
|
||||||
pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) {
|
pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) {
|
||||||
|
|
|
@ -44,7 +44,6 @@ pub fn console_putchar(c: usize) {
|
||||||
// pub fn console_getchar() -> usize {
|
// pub fn console_getchar() -> usize {
|
||||||
// sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
// sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
use crate::board::QEMUExit;
|
use crate::board::QEMUExit;
|
||||||
/// use sbi call to shutdown the kernel
|
/// use sbi call to shutdown the kernel
|
||||||
pub fn shutdown() -> ! {
|
pub fn shutdown() -> ! {
|
||||||
|
|
|
@ -14,6 +14,7 @@ const SYSCALL_WRITE: usize = 64;
|
||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
const SYSCALL_YIELD: usize = 124;
|
const SYSCALL_YIELD: usize = 124;
|
||||||
const SYSCALL_GET_TIME: usize = 169;
|
const SYSCALL_GET_TIME: usize = 169;
|
||||||
|
const SYSCALL_SBRK: usize = 214;
|
||||||
|
|
||||||
mod fs;
|
mod fs;
|
||||||
mod process;
|
mod process;
|
||||||
|
@ -28,6 +29,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
||||||
SYSCALL_YIELD => sys_yield(),
|
SYSCALL_YIELD => sys_yield(),
|
||||||
SYSCALL_GET_TIME => sys_get_time(),
|
SYSCALL_GET_TIME => sys_get_time(),
|
||||||
|
SYSCALL_SBRK => sys_sbrk(args[0] as i32),
|
||||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Process management syscalls
|
//! Process management syscalls
|
||||||
|
|
||||||
use crate::task::{exit_current_and_run_next, suspend_current_and_run_next};
|
use crate::task::{change_program_brk, exit_current_and_run_next, suspend_current_and_run_next};
|
||||||
use crate::timer::get_time_ms;
|
use crate::timer::get_time_ms;
|
||||||
|
|
||||||
/// task exits and submit an exit code
|
/// task exits and submit an exit code
|
||||||
|
@ -20,3 +20,12 @@ pub fn sys_yield() -> isize {
|
||||||
pub fn sys_get_time() -> isize {
|
pub fn sys_get_time() -> isize {
|
||||||
get_time_ms() as isize
|
get_time_ms() as isize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// change data segment size
|
||||||
|
pub fn sys_sbrk(size: i32) -> isize {
|
||||||
|
if let Some(old_brk) = change_program_brk(size) {
|
||||||
|
old_brk as isize
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -126,6 +126,13 @@ impl TaskManager {
|
||||||
inner.tasks[inner.current_task].get_trap_cx()
|
inner.tasks[inner.current_task].get_trap_cx()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the current 'Running' task's program break
|
||||||
|
pub fn change_current_program_brk(&self, size: i32) -> Option<usize> {
|
||||||
|
let mut inner = self.inner.exclusive_access();
|
||||||
|
let cur = inner.current_task;
|
||||||
|
inner.tasks[cur].change_program_brk(size)
|
||||||
|
}
|
||||||
|
|
||||||
/// Switch current `Running` task to the task we have found,
|
/// Switch current `Running` task to the task we have found,
|
||||||
/// or there is no `Ready` task and we can exit with all applications completed
|
/// or there is no `Ready` task and we can exit with all applications completed
|
||||||
fn run_next_task(&self) {
|
fn run_next_task(&self) {
|
||||||
|
@ -192,3 +199,8 @@ pub fn current_user_token() -> usize {
|
||||||
pub fn current_trap_cx() -> &'static mut TrapContext {
|
pub fn current_trap_cx() -> &'static mut TrapContext {
|
||||||
TASK_MANAGER.get_current_trap_cx()
|
TASK_MANAGER.get_current_trap_cx()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the current 'Running' task's program break
|
||||||
|
pub fn change_program_brk(size: i32) -> Option<usize> {
|
||||||
|
TASK_MANAGER.change_current_program_brk(size)
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ pub struct TaskControlBlock {
|
||||||
pub memory_set: MemorySet,
|
pub memory_set: MemorySet,
|
||||||
pub trap_cx_ppn: PhysPageNum,
|
pub trap_cx_ppn: PhysPageNum,
|
||||||
pub base_size: usize,
|
pub base_size: usize,
|
||||||
|
pub heap_bottom: usize,
|
||||||
|
pub program_brk: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskControlBlock {
|
impl TaskControlBlock {
|
||||||
|
@ -41,6 +43,8 @@ impl TaskControlBlock {
|
||||||
memory_set,
|
memory_set,
|
||||||
trap_cx_ppn,
|
trap_cx_ppn,
|
||||||
base_size: user_sp,
|
base_size: user_sp,
|
||||||
|
heap_bottom: user_sp,
|
||||||
|
program_brk: user_sp,
|
||||||
};
|
};
|
||||||
// prepare TrapContext in user space
|
// prepare TrapContext in user space
|
||||||
let trap_cx = task_control_block.get_trap_cx();
|
let trap_cx = task_control_block.get_trap_cx();
|
||||||
|
@ -53,6 +57,27 @@ impl TaskControlBlock {
|
||||||
);
|
);
|
||||||
task_control_block
|
task_control_block
|
||||||
}
|
}
|
||||||
|
/// change the location of the program break. return None if failed.
|
||||||
|
pub fn change_program_brk(&mut self, size: i32) -> Option<usize> {
|
||||||
|
let old_break = self.program_brk;
|
||||||
|
let new_brk = self.program_brk as isize + size as isize;
|
||||||
|
if new_brk < self.heap_bottom as isize {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let result = if size < 0 {
|
||||||
|
self.memory_set
|
||||||
|
.shrink_to(VirtAddr(self.heap_bottom), VirtAddr(new_brk as usize))
|
||||||
|
} else {
|
||||||
|
self.memory_set
|
||||||
|
.append_to(VirtAddr(self.heap_bottom), VirtAddr(new_brk as usize))
|
||||||
|
};
|
||||||
|
if result {
|
||||||
|
self.program_brk = new_brk as usize;
|
||||||
|
Some(old_break)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
|
46
user/src/bin/sbrk_test.rs
Normal file
46
user/src/bin/sbrk_test.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate user_lib;
|
||||||
|
|
||||||
|
use user_lib::sbrk;
|
||||||
|
use core::ptr::slice_from_raw_parts_mut;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
fn main() -> i32 {
|
||||||
|
println!("Test sbrk start.");
|
||||||
|
const PAGE_SIZE: usize = 0x1000;
|
||||||
|
let origin_brk = sbrk(0);
|
||||||
|
println!("origin break point = {:x}", origin_brk);
|
||||||
|
let brk = sbrk(PAGE_SIZE as i32);
|
||||||
|
if brk != origin_brk {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
let brk = sbrk(0);
|
||||||
|
println!("one page allocated, break point = {:x}", brk);
|
||||||
|
println!("try write to allocated page");
|
||||||
|
let new_page = unsafe { &mut *slice_from_raw_parts_mut(origin_brk as usize as *const u8 as *mut u8, PAGE_SIZE) };
|
||||||
|
for pos in 0..PAGE_SIZE {
|
||||||
|
new_page[pos] = 1;
|
||||||
|
}
|
||||||
|
println!("write ok");
|
||||||
|
sbrk(PAGE_SIZE as i32 * 10);
|
||||||
|
let brk = sbrk(0);
|
||||||
|
println!("10 page allocated, break point = {:x}", brk);
|
||||||
|
sbrk(PAGE_SIZE as i32 * -11);
|
||||||
|
let brk = sbrk(0);
|
||||||
|
println!("11 page DEALLOCATED, break point = {:x}", brk);
|
||||||
|
println!("try DEALLOCATED more one page, should be failed.");
|
||||||
|
let ret = sbrk(PAGE_SIZE as i32 * -1);
|
||||||
|
if ret != -1 {
|
||||||
|
println!("Test sbrk failed!");
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
println!("Test sbrk almost OK!");
|
||||||
|
println!("now write to deallocated page, should cause page fault.");
|
||||||
|
for pos in 0..PAGE_SIZE {
|
||||||
|
new_page[pos] = 2;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
|
@ -34,3 +34,7 @@ pub fn yield_() -> isize {
|
||||||
pub fn get_time() -> isize {
|
pub fn get_time() -> isize {
|
||||||
sys_get_time()
|
sys_get_time()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sbrk(size: i32) -> isize {
|
||||||
|
sys_sbrk(size)
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ const SYSCALL_WRITE: usize = 64;
|
||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
const SYSCALL_YIELD: usize = 124;
|
const SYSCALL_YIELD: usize = 124;
|
||||||
const SYSCALL_GET_TIME: usize = 169;
|
const SYSCALL_GET_TIME: usize = 169;
|
||||||
|
const SYSCALL_SBRK: usize = 214;
|
||||||
|
|
||||||
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
||||||
let mut ret: isize;
|
let mut ret: isize;
|
||||||
|
@ -34,3 +35,7 @@ pub fn sys_yield() -> isize {
|
||||||
pub fn sys_get_time() -> isize {
|
pub fn sys_get_time() -> isize {
|
||||||
syscall(SYSCALL_GET_TIME, [0, 0, 0])
|
syscall(SYSCALL_GET_TIME, [0, 0, 0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sys_sbrk(size: i32) -> isize {
|
||||||
|
syscall(SYSCALL_SBRK, [size as usize, 0, 0])
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue