diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/os/run.sh b/os/run.sh
index bed9ec8..2188894 100755
--- a/os/run.sh
+++ b/os/run.sh
@@ -1,3 +1,4 @@
+#!/usr/bin/env bash
cargo build --release
qemu-system-riscv64 \
diff --git a/os/src/batch.rs b/os/src/batch.rs
deleted file mode 100644
index 2b09e78..0000000
--- a/os/src/batch.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-use core::arch::asm;
-
-use lazy_static::lazy_static;
-
-use crate::log_information;
-use crate::sbi::shutdown;
-use crate::sync::single_cell::SingleCell;
-use crate::trap::context::TrapContext;
-
-const MAX_APP_NUMBER: usize = 32;
-const APP_BASE_ADDRESS: usize = 0x80400000;
-const APP_SIZE_LIMIT: usize = 0x20000;
-
-struct AppManager {
- app_count: usize,
- current: usize,
- start_addresses: [usize; MAX_APP_NUMBER + 1],
-}
-
-lazy_static! {
- static ref APP_MANAGER: SingleCell = unsafe {
- SingleCell::new({
- extern "C" {
- fn _num_app();
- }
-
- let num_app_ptr = _num_app as usize as *const usize;
- let num_app = num_app_ptr.read_volatile();
- let mut start_addresses: [usize; MAX_APP_NUMBER + 1] = [0; MAX_APP_NUMBER + 1];
- let start_addresses_raw: &[usize] =
- core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1);
- start_addresses[..=num_app].copy_from_slice(start_addresses_raw);
- AppManager {
- app_count: num_app,
- current: 0,
- start_addresses,
- }
- })
- };
-}
-
-impl AppManager {
- pub fn print_app_information(&self) {
- log_information!("[kernel] Application count is {}.", self.app_count);
-
- for i in 0..self.app_count {
- log_information!(
- "[kernel] Application_{} ({:#x} -> {:#x})",
- i,
- self.start_addresses[i],
- self.start_addresses[i + 1]
- );
- }
- }
-
- pub fn get_current_app(&self) -> usize {
- self.current
- }
-
- pub fn move_to_next_app(&mut self) {
- self.current += 1;
- }
-
- unsafe fn load_app(&self, app_id: usize) {
- if app_id >= self.app_count {
- panic!("Application id is invalid!");
- }
-
- log_information!("[kernel] Loading application_{}...", app_id);
-
- core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, APP_SIZE_LIMIT).fill(0);
-
- let app_source = core::slice::from_raw_parts(
- self.start_addresses[app_id] as *const u8,
- self.start_addresses[app_id + 1] - self.start_addresses[app_id],
- );
- let app_destination =
- core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, app_source.len());
- app_destination.copy_from_slice(app_source);
-
- // 保证指令缓存的更新
- // 因为上述代码会修改指令数据段
- asm!("fence.i");
- }
-}
-
-const USER_STACK_SIZE: usize = 4096 * 2;
-const KERNEL_STACK_SIZE: usize = 4096 * 2;
-
-#[repr(align(4096))]
-struct UserStack {
- data: [u8; USER_STACK_SIZE],
-}
-
-impl UserStack {
- fn get_sp(&self) -> usize {
- self.data.as_ptr() as usize + USER_STACK_SIZE
- }
-}
-
-#[repr(align(4096))]
-struct KernelStack {
- data: [u8; KERNEL_STACK_SIZE],
-}
-
-impl KernelStack {
- fn get_sp(&self) -> usize {
- self.data.as_ptr() as usize + KERNEL_STACK_SIZE
- }
-
- pub fn push_context(&self, context: TrapContext) -> &'static mut TrapContext {
- let context_pointer = (self.get_sp() - size_of::()) as *mut TrapContext;
- unsafe {
- *context_pointer = context;
- context_pointer.as_mut().unwrap()
- }
- }
-}
-
-static KERNEL_STACK: KernelStack = KernelStack {
- data: [0; KERNEL_STACK_SIZE],
-};
-static USER_STACK: UserStack = UserStack {
- data: [0; USER_STACK_SIZE],
-};
-
-pub fn print_app_information() {
- let app_manager = APP_MANAGER.exclusive_borrow();
- app_manager.print_app_information();
-}
-
-pub fn run_next_application() -> ! {
- let mut app_manager = APP_MANAGER.exclusive_borrow();
- let current_app = app_manager.get_current_app();
- if current_app >= app_manager.app_count {
- log_information!("Run out of applications, the os will stop!");
- shutdown(true);
- }
-
- unsafe {
- app_manager.load_app(current_app);
- }
- app_manager.move_to_next_app();
-
- // We must drop resource manually
- // As this function will never return!
- drop(app_manager);
-
- extern "C" {
- fn __restore(context_address: usize);
- }
-
- unsafe {
- let context_address = KERNEL_STACK.push_context(TrapContext::init_application_context(
- APP_BASE_ADDRESS,
- USER_STACK.get_sp(),
- )) as *const _ as usize;
- __restore(context_address);
-
- unreachable!()
- }
-}
diff --git a/os/src/boards.rs b/os/src/boards.rs
new file mode 100644
index 0000000..1d6396d
--- /dev/null
+++ b/os/src/boards.rs
@@ -0,0 +1 @@
+pub mod qemu;
\ No newline at end of file
diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs
new file mode 100644
index 0000000..ed95dd0
--- /dev/null
+++ b/os/src/boards/qemu.rs
@@ -0,0 +1 @@
+pub const CLOCK_FREQUENCY: usize = 10000000;
\ No newline at end of file
diff --git a/os/src/config.rs b/os/src/config.rs
new file mode 100644
index 0000000..1c7c317
--- /dev/null
+++ b/os/src/config.rs
@@ -0,0 +1,8 @@
+pub const USER_STACK_SIZE: usize = 4096;
+pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
+
+pub const MAX_APP_NUM: usize = 4;
+pub const APP_BASE_ADDRESS: usize = 0x80400000;
+pub const APP_SIZE_LIMIT: usize = 0x20000;
+
+pub use crate::boards::qemu::CLOCK_FREQUENCY;
\ No newline at end of file
diff --git a/os/src/loader.rs b/os/src/loader.rs
new file mode 100644
index 0000000..e33e14b
--- /dev/null
+++ b/os/src/loader.rs
@@ -0,0 +1,98 @@
+use crate::config::{
+ APP_BASE_ADDRESS, APP_SIZE_LIMIT, KERNEL_STACK_SIZE, MAX_APP_NUM, USER_STACK_SIZE,
+};
+use core::arch::asm;
+use crate::trap::context::TrapContext;
+
+#[repr(align(4096))]
+#[derive(Copy, Clone)]
+struct KernelStack {
+ data: [u8; KERNEL_STACK_SIZE],
+}
+
+#[repr(align(4096))]
+#[derive(Copy, Clone)]
+struct UserStack {
+ data: [u8; USER_STACK_SIZE],
+}
+
+static KERNEL_STACK: [KernelStack; MAX_APP_NUM] = [KernelStack {
+ data: [0; KERNEL_STACK_SIZE],
+}; MAX_APP_NUM];
+
+static USER_STACK: [UserStack; MAX_APP_NUM] = [UserStack {
+ data: [0; USER_STACK_SIZE],
+}; MAX_APP_NUM];
+
+impl KernelStack {
+ fn get_sp(&self) -> usize {
+ self.data.as_ptr() as usize + KERNEL_STACK_SIZE
+ }
+
+ pub fn push_context(&self, trap_context: TrapContext) -> usize {
+ let pointer = (self.get_sp() - core::mem::size_of::()) as *mut TrapContext;
+
+ unsafe {
+ *pointer = trap_context;
+ }
+
+ pointer as usize
+ }
+}
+
+impl UserStack {
+ fn get_sp(&self) -> usize {
+ self.data.as_ptr() as usize + USER_STACK_SIZE
+ }
+}
+
+pub fn get_app_num() -> usize {
+ extern "C" {
+ fn _num_app();
+ }
+
+ let app_num_ptr = _num_app as usize as *const usize;
+
+ unsafe { app_num_ptr.read_volatile() }
+}
+
+pub fn load_apps() {
+ extern "C" {
+ fn _num_app();
+ }
+
+ let app_num_ptr = _num_app as usize as *const usize;
+ let app_num = unsafe { app_num_ptr.read_volatile() };
+ let app_start = unsafe { core::slice::from_raw_parts(app_num_ptr.add(1), app_num + 1) };
+
+ for i in 0..app_num {
+ let base_address = APP_BASE_ADDRESS + i * APP_SIZE_LIMIT;
+
+ // 清除目标的内存区域
+ for address in base_address..base_address + APP_SIZE_LIMIT {
+ unsafe {
+ (address as *mut u8).write_volatile(0);
+ }
+ }
+
+ // 将程序从数据段复制过来
+ let source = unsafe {
+ core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i])
+ };
+ let destination =
+ unsafe { core::slice::from_raw_parts_mut(base_address as *mut u8, source.len()) };
+
+ destination.copy_from_slice(source);
+ }
+
+ unsafe {
+ asm!("fence.i");
+ }
+}
+
+pub fn initialize_app_context(app_id: usize) -> usize {
+ KERNEL_STACK[app_id].push_context(TrapContext::init_application_context(
+ APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT,
+ USER_STACK[app_id].get_sp()
+ ))
+}
\ No newline at end of file
diff --git a/os/src/main.rs b/os/src/main.rs
index c2e2c42..b1f37a1 100644
--- a/os/src/main.rs
+++ b/os/src/main.rs
@@ -4,13 +4,17 @@
use crate::utils::clear_bss;
use core::arch::global_asm;
-mod batch;
mod console;
mod sbi;
mod sync;
mod syscall;
mod trap;
mod utils;
+mod loader;
+mod boards;
+mod config;
+mod task;
+mod timer;
global_asm!(include_str!("entry.asm"));
global_asm!(include_str!("link_app.asm"));
@@ -20,6 +24,8 @@ fn rust_main() -> ! {
clear_bss();
log_information!("[kernel] Hello, rCore!");
trap::init();
- batch::print_app_information();
- batch::run_next_application();
+ loader::load_apps();
+ task::run_first_task();
+
+ unreachable!()
}
diff --git a/os/src/sbi.rs b/os/src/sbi.rs
index 73c351c..cda8d70 100644
--- a/os/src/sbi.rs
+++ b/os/src/sbi.rs
@@ -14,3 +14,7 @@ pub fn shutdown(failure: bool) -> ! {
unreachable!()
}
+
+pub fn set_timer(timer: usize) {
+ sbi_rt::set_timer(timer as _);
+}
diff --git a/os/src/syscall.rs b/os/src/syscall.rs
index 91cf8d9..03dcfbe 100644
--- a/os/src/syscall.rs
+++ b/os/src/syscall.rs
@@ -1,18 +1,22 @@
use crate::syscall::fs::sys_write;
-use crate::syscall::process::sys_exit;
+use crate::syscall::process::{sys_exit, sys_get_time, sys_yield};
mod fs;
mod process;
const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93;
+const SYSCALL_YIELD: usize = 124;
+const SYSCALL_GET_TIME: usize = 169;
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> usize {
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(),
_ => {
panic!("Unsupported syscall: {}", syscall_id)
- }
+ },
}
}
diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs
index 859e998..97d129b 100644
--- a/os/src/syscall/fs.rs
+++ b/os/src/syscall/fs.rs
@@ -8,7 +8,7 @@ pub fn sys_write(fd: usize, buffer: *const u8, len: usize) -> usize {
let slice = unsafe { core::slice::from_raw_parts(buffer, len) };
let str = core::str::from_utf8(slice).unwrap();
print!("{}", str);
- len as usize
+ len
}
_ => {
panic!("Unsupported file descriptor in sys_write");
diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs
index 619c197..54059cd 100644
--- a/os/src/syscall/process.rs
+++ b/os/src/syscall/process.rs
@@ -1,7 +1,20 @@
-use crate::batch::run_next_application;
use crate::println;
+use crate::task::{exit_current_and_run_next, suspend_current_and_run_next};
+use crate::timer::get_time_ms;
pub fn sys_exit(exit_state: i32) -> ! {
println!("[kernel] Application exited with code {}.", exit_state);
- run_next_application()
+ exit_current_and_run_next();
+
+ unreachable!()
+}
+
+pub fn sys_yield() -> usize {
+ suspend_current_and_run_next();
+
+ 0
+}
+
+pub fn sys_get_time() -> usize {
+ get_time_ms()
}
diff --git a/os/src/task.rs b/os/src/task.rs
new file mode 100644
index 0000000..e65477c
--- /dev/null
+++ b/os/src/task.rs
@@ -0,0 +1,133 @@
+use crate::config::MAX_APP_NUM;
+use crate::loader::{get_app_num, initialize_app_context};
+use crate::log_information;
+use crate::sbi::shutdown;
+use crate::sync::single_cell::SingleCell;
+use crate::task::context::TaskContext;
+use crate::task::switch::__switch;
+use lazy_static::lazy_static;
+
+mod context;
+mod switch;
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum TaskStatus {
+ NotInitialized,
+ Ready,
+ Running,
+ Exited,
+}
+
+#[derive(Copy, Clone)]
+pub struct TaskControlBlock {
+ pub status: TaskStatus,
+ pub context: TaskContext,
+}
+
+pub struct TaskManagerInner {
+ tasks: [TaskControlBlock; MAX_APP_NUM],
+ current_task: usize,
+}
+
+pub struct TaskManager {
+ app_numer: usize,
+ inner: SingleCell,
+}
+
+lazy_static! {
+ static ref TASK_MANAGER: TaskManager = {
+ let app_num = get_app_num();
+ let mut tasks = [TaskControlBlock {
+ context: TaskContext::new(),
+ status: TaskStatus::NotInitialized,
+ }; MAX_APP_NUM];
+
+ for (i, task) in tasks.iter_mut().enumerate() {
+ task.context = TaskContext::goto_restore(initialize_app_context(i));
+ task.status = TaskStatus::Ready;
+ }
+
+ TaskManager {
+ app_numer: app_num,
+ inner: unsafe {
+ SingleCell::new(TaskManagerInner {
+ tasks,
+ current_task: 0,
+ })
+ },
+ }
+ };
+}
+
+pub fn run_first_task() {
+ TASK_MANAGER.run_first_task();
+}
+
+pub fn suspend_current_and_run_next() {
+ TASK_MANAGER.mark_current_suspended();
+ TASK_MANAGER.run_next_task();
+}
+
+pub fn exit_current_and_run_next() {
+ TASK_MANAGER.mark_current_exited();
+ TASK_MANAGER.run_next_task();
+}
+
+impl TaskManager {
+ /// status from running to ready
+ fn mark_current_suspended(&self) {
+ let mut inner = self.inner.exclusive_borrow();
+ let current = inner.current_task;
+ inner.tasks[current].status = TaskStatus::Ready;
+ }
+
+ /// status from running to exited
+ fn mark_current_exited(&self) {
+ let mut inner = self.inner.exclusive_borrow();
+ let current = inner.current_task;
+ inner.tasks[current].status = TaskStatus::Exited;
+ }
+
+ fn find_next_task(&self) -> Option {
+ let inner = self.inner.exclusive_borrow();
+ (inner.current_task + 1..inner.current_task + self.app_numer + 1)
+ .map(|id| id % self.app_numer)
+ .find(|id| inner.tasks[*id].status == TaskStatus::Ready)
+ }
+
+ fn run_next_task(&self) {
+ if let Some(next) = self.find_next_task() {
+ let mut inner = self.inner.exclusive_borrow();
+ let current = inner.current_task;
+
+ inner.tasks[next].status = TaskStatus::Running;
+ inner.current_task = next;
+
+ let current_task_context = &mut inner.tasks[current].context as *mut TaskContext;
+ let next_task_context = &inner.tasks[next].context as *const TaskContext;
+ drop(inner);
+
+ unsafe {
+ __switch(current_task_context, next_task_context);
+ }
+ } else {
+ log_information!("All application completed!");
+ shutdown(false);
+ }
+ }
+
+ fn run_first_task(&self) -> ! {
+ let mut inner = self.inner.exclusive_borrow();
+ let task0 = &mut inner.tasks[0];
+ task0.status = TaskStatus::Running;
+ let next_task_context = &task0.context as *const TaskContext;
+ drop(inner);
+
+ let mut unused = TaskContext::new();
+ unsafe {
+ __switch(&mut unused as *mut TaskContext, next_task_context);
+ }
+
+ unreachable!();
+ }
+}
diff --git a/os/src/task/context.rs b/os/src/task/context.rs
new file mode 100644
index 0000000..9b0b887
--- /dev/null
+++ b/os/src/task/context.rs
@@ -0,0 +1,31 @@
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct TaskContext {
+ ra: usize,
+ sp: usize,
+ s: [usize; 12]
+}
+
+impl TaskContext {
+ pub fn new() -> Self {
+ Self {
+ ra: 0,
+ sp: 0,
+ s: [0; 12]
+ }
+ }
+
+ /// set the task context { __restore function, kernel stack, s_0 -> s_12 }
+ pub fn goto_restore(kernel_stack_pointer: usize) -> Self {
+ extern "C" {
+ fn __restore();
+ }
+
+ Self {
+ ra: __restore as usize,
+ sp: kernel_stack_pointer,
+ s: [0; 12]
+ }
+ }
+}
diff --git a/os/src/task/switch.asm b/os/src/task/switch.asm
new file mode 100644
index 0000000..72abfa6
--- /dev/null
+++ b/os/src/task/switch.asm
@@ -0,0 +1,33 @@
+.altmacro
+.macro SAVE_SN n
+ sd s\n, (\n+2)*8(a0)
+.endm
+.macro LOAD_SN n
+ ld s\n, (\n+2)*8(a1)
+.endm
+ .section .text
+ .globl __switch
+__switch:
+ # __switch(
+ # current_task_cx_ptr: *mut TaskContext,
+ # next_task_cx_ptr: *const TaskContext
+ # )
+ # save kernel stack of current task
+ sd sp, 8(a0)
+ # save ra & s0~s11 of current execution
+ sd ra, 0(a0)
+ .set n, 0
+ .rept 12
+ SAVE_SN %n
+ .set n, n + 1
+ .endr
+ # restore ra & s0~s11 of next execution
+ ld ra, 0(a1)
+ .set n, 0
+ .rept 12
+ LOAD_SN %n
+ .set n, n + 1
+ .endr
+ # restore kernel stack of next task
+ ld sp, 8(a1)
+ ret
\ No newline at end of file
diff --git a/os/src/task/switch.rs b/os/src/task/switch.rs
new file mode 100644
index 0000000..6ef6dcf
--- /dev/null
+++ b/os/src/task/switch.rs
@@ -0,0 +1,10 @@
+use crate::task::context::TaskContext;
+use core::arch::global_asm;
+
+global_asm!(include_str!("switch.asm"));
+
+extern "C" {
+ pub fn __switch(current_task_context: *mut TaskContext, next_task_context: *const TaskContext);
+}
+
+
diff --git a/os/src/timer.rs b/os/src/timer.rs
new file mode 100644
index 0000000..6c0ec82
--- /dev/null
+++ b/os/src/timer.rs
@@ -0,0 +1,18 @@
+use riscv::register::time;
+use crate::config::CLOCK_FREQUENCY;
+use crate::sbi::set_timer;
+
+pub fn get_time() -> usize {
+ time::read()
+}
+
+/// 每秒执行100次,即10ms执行一次
+const TICKS_PRE_SECOND: usize = 100;
+
+pub fn get_time_ms() -> usize {
+ time::read() / CLOCK_FREQUENCY * 1000
+}
+
+pub fn set_next_trigger() {
+ set_timer(get_time() + CLOCK_FREQUENCY / TICKS_PRE_SECOND);
+}
diff --git a/os/src/trap.asm b/os/src/trap.asm
index 7ca7154..3aaad85 100644
--- a/os/src/trap.asm
+++ b/os/src/trap.asm
@@ -39,9 +39,6 @@ __alltraps:
call trap_handler
__restore:
- # case1: start running app by __restore
- # case2: back to U after handling trap
- mv sp, a0
# now sp->kernel stack(after allocated), sscratch->user stack
# restore sstatus/sepc
ld t0, 32*8(sp)
@@ -50,7 +47,7 @@ __restore:
csrw sstatus, t0
csrw sepc, t1
csrw sscratch, t2
- # restore general-purpuse registers except sp/tp
+ # restore general-purpose registers except sp/tp
ld x1, 1*8(sp)
ld x3, 3*8(sp)
.set n, 5
diff --git a/os/src/trap.rs b/os/src/trap.rs
index e7aec3e..d97caac 100644
--- a/os/src/trap.rs
+++ b/os/src/trap.rs
@@ -1,13 +1,10 @@
-use crate::batch::run_next_application;
use crate::println;
use crate::syscall::syscall;
use crate::trap::context::TrapContext;
use core::arch::global_asm;
-use riscv::register::{
- mtvec::TrapMode,
- scause::{self, Exception, Trap},
- stval, stvec,
-};
+use riscv::register::{mtvec::TrapMode, scause::{self, Exception, Trap, Interrupt}, sie, stval, stvec};
+use crate::task::{exit_current_and_run_next, suspend_current_and_run_next};
+use crate::timer::set_next_trigger;
pub mod context;
@@ -18,7 +15,12 @@ pub fn init() {
fn __alltraps();
}
unsafe {
+ // 设置中断向量
stvec::write(__alltraps as usize, TrapMode::Direct);
+
+ // 启动时钟中断
+ sie::set_stimer();
+ set_next_trigger();
}
}
@@ -34,11 +36,15 @@ pub fn trap_handler(context: &mut TrapContext) -> &mut TrapContext {
}
Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) => {
println!("[kernel] PageFault in application, kernel will kill it.");
- run_next_application();
+ exit_current_and_run_next();
}
Trap::Exception(Exception::IllegalInstruction) => {
println!("[kernel] Illegal instruction in application, kernel will kill it.");
- run_next_application();
+ exit_current_and_run_next();
+ }
+ Trap::Interrupt(Interrupt::SupervisorTimer) => {
+ set_next_trigger();
+ suspend_current_and_run_next();
}
_ => {
panic!(
diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs
index c467b0a..d1171ea 100644
--- a/os/src/trap/context.rs
+++ b/os/src/trap/context.rs
@@ -8,9 +8,11 @@ pub struct TrapContext {
}
impl TrapContext {
- pub unsafe fn init_application_context(entry: usize, sp: usize) -> Self {
+ pub fn init_application_context(entry: usize, sp: usize) -> Self {
let sstatus = sstatus::read();
- sstatus::set_spp(SPP::User);
+ unsafe {
+ sstatus::set_spp(SPP::User);
+ }
let mut context = Self {
x: [0; 32],
s_status: sstatus,
diff --git a/user/Makefile b/user/Makefile
deleted file mode 100644
index c643fbe..0000000
--- a/user/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET := riscv64gc-unknown-none-elf
-MODE := release
-APP_DIR := src/bin
-TARGET_DIR := target/$(TARGET)/$(MODE)
-APPS := $(wildcard $(APP_DIR)/*.rs)
-ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS))
-BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS))
-
-OBJDUMP := rust-objdump --arch-name=riscv64
-OBJCOPY := rust-objcopy --binary-architecture=riscv64
-
-elf:
- @cargo build --release
-
-binary: elf
- @$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
-
-build: binary
\ No newline at end of file
diff --git a/user/build.py b/user/build.py
new file mode 100755
index 0000000..c82f02e
--- /dev/null
+++ b/user/build.py
@@ -0,0 +1,30 @@
+#!/bin/python3
+import os
+
+base_address = 0x80400000
+step = 0x20000
+linker = 'src/linker.ld'
+target_dir = "target/riscv64gc-unknown-none-elf/release/"
+
+app_id = 0
+apps = os.listdir('src/bin')
+apps.sort()
+for app in apps:
+ app = app[:app.find('.')]
+ lines = []
+ lines_before = []
+ with open(linker, 'r') as f:
+ for line in f.readlines():
+ lines_before.append(line)
+ line = line.replace(hex(base_address), hex(base_address+step * app_id))
+ lines.append(line)
+ with open(linker, 'w+') as f:
+ f.writelines(lines)
+ os.system('cargo build --bin %s --release' % app)
+ source_name = target_dir + app
+ dest_name = target_dir + app + ".bin"
+ os.system("rust-objcopy %s --binary-architecture=riscv64 --strip-all -O binary %s" %(source_name, dest_name))
+ print('[build.py] application %s start with address %s' %(app, hex(base_address+step*app_id)))
+ with open(linker, 'w+') as f:
+ f.writelines(lines_before)
+ app_id = app_id + 1
\ No newline at end of file
diff --git a/user/src/bin/hello_world.rs b/user/src/bin/hello_world.rs
deleted file mode 100644
index f457094..0000000
--- a/user/src/bin/hello_world.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-#![no_std]
-#![no_main]
-
-#[macro_use]
-extern crate user_lib;
-
-#[no_mangle]
-fn main() -> i32 {
- println!("Hello, world!");
-
- 0
-}
diff --git a/user/src/bin/illegal_instruction.rs b/user/src/bin/illegal_instruction.rs
deleted file mode 100644
index 04dac37..0000000
--- a/user/src/bin/illegal_instruction.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![no_std]
-#![no_main]
-
-#[macro_use]
-extern crate user_lib;
-
-use core::arch::asm;
-
-#[no_mangle]
-fn main() -> i32 {
- println!("Try to execute privileged instruction in U Mode");
- println!("Kernel should kill this application!");
- unsafe {
- asm!("sret");
- }
- 0
-}
diff --git a/user/src/bin/power.rs b/user/src/bin/power.rs
deleted file mode 100644
index f628f34..0000000
--- a/user/src/bin/power.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-#![no_std]
-#![no_main]
-
-#[macro_use]
-extern crate user_lib;
-
-const SIZE: usize = 10;
-const P: u32 = 3;
-const STEP: usize = 100000;
-const MOD: u32 = 10007;
-
-#[no_mangle]
-fn main() -> i32 {
- let mut pow = [0u32; SIZE];
- let mut index: usize = 0;
- pow[index] = 1;
- for i in 1..=STEP {
- let last = pow[index];
- index = (index + 1) % SIZE;
- pow[index] = last * P % MOD;
- if i % 10000 == 0 {
- println!("{}^{}={}(MOD {})", P, i, pow[index], MOD);
- }
- }
- println!("Test power OK!");
- 0
-}
diff --git a/user/src/bin/power_3.rs b/user/src/bin/power_3.rs
new file mode 100644
index 0000000..e0ec5f3
--- /dev/null
+++ b/user/src/bin/power_3.rs
@@ -0,0 +1,28 @@
+#![no_std]
+#![no_main]
+
+#[macro_use]
+extern crate user_lib;
+
+const LEN: usize = 100;
+
+#[no_mangle]
+fn main() -> i32 {
+ let p = 3u64;
+ let m = 998244353u64;
+ let iter: usize = 200000;
+ let mut s = [0u64; LEN];
+ let mut cur = 0usize;
+ s[cur] = 1;
+ for i in 1..=iter {
+ let next = if cur + 1 == LEN { 0 } else { cur + 1 };
+ s[next] = s[cur] * p % m;
+ cur = next;
+ if i % 10000 == 0 {
+ println!("power_3 [{}/{}]", i, iter);
+ }
+ }
+ println!("{}^{} = {}(MOD {})", p, iter, s[cur], m);
+ println!("Test power_3 OK!");
+ 0
+}
\ No newline at end of file
diff --git a/user/src/bin/power_5.rs b/user/src/bin/power_5.rs
new file mode 100644
index 0000000..f31a24e
--- /dev/null
+++ b/user/src/bin/power_5.rs
@@ -0,0 +1,28 @@
+#![no_std]
+#![no_main]
+
+#[macro_use]
+extern crate user_lib;
+
+const LEN: usize = 100;
+
+#[no_mangle]
+fn main() -> i32 {
+ let p = 5u64;
+ let m = 998244353u64;
+ let iter: usize = 140000;
+ let mut s = [0u64; LEN];
+ let mut cur = 0usize;
+ s[cur] = 1;
+ for i in 1..=iter {
+ let next = if cur + 1 == LEN { 0 } else { cur + 1 };
+ s[next] = s[cur] * p % m;
+ cur = next;
+ if i % 10000 == 0 {
+ println!("power_5 [{}/{}]", i, iter);
+ }
+ }
+ println!("{}^{} = {}(MOD {})", p, iter, s[cur], m);
+ println!("Test power_5 OK!");
+ 0
+}
\ No newline at end of file
diff --git a/user/src/bin/power_7.rs b/user/src/bin/power_7.rs
new file mode 100644
index 0000000..fd9f23e
--- /dev/null
+++ b/user/src/bin/power_7.rs
@@ -0,0 +1,28 @@
+#![no_std]
+#![no_main]
+
+#[macro_use]
+extern crate user_lib;
+
+const LEN: usize = 100;
+
+#[no_mangle]
+fn main() -> i32 {
+ let p = 7u64;
+ let m = 998244353u64;
+ let iter: usize = 160000;
+ let mut s = [0u64; LEN];
+ let mut cur = 0usize;
+ s[cur] = 1;
+ for i in 1..=iter {
+ let next = if cur + 1 == LEN { 0 } else { cur + 1 };
+ s[next] = s[cur] * p % m;
+ cur = next;
+ if i % 10000 == 0 {
+ println!("power_7 [{}/{}]", i, iter);
+ }
+ }
+ println!("{}^{} = {}(MOD {})", p, iter, s[cur], m);
+ println!("Test power_7 OK!");
+ 0
+}
\ No newline at end of file
diff --git a/user/src/bin/sleep.rs b/user/src/bin/sleep.rs
new file mode 100644
index 0000000..b19774a
--- /dev/null
+++ b/user/src/bin/sleep.rs
@@ -0,0 +1,20 @@
+#![no_std]
+#![no_main]
+
+#[macro_use]
+extern crate user_lib;
+
+use user_lib::{get_time, sys_yield};
+
+#[no_mangle]
+fn main() -> i32 {
+ let current_time = get_time();
+ let wait_time = current_time + 3000;
+
+ while get_time() < wait_time {
+ sys_yield();
+ }
+
+ println!("Test sleep OK!");
+ 0
+}
\ No newline at end of file
diff --git a/user/src/bin/store_fault.rs b/user/src/bin/store_fault.rs
deleted file mode 100644
index f8023eb..0000000
--- a/user/src/bin/store_fault.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![no_std]
-#![no_main]
-
-#[macro_use]
-extern crate user_lib;
-
-#[no_mangle]
-fn main() -> i32 {
- println!("Into Test store_fault, we will insert an invalid store operation...");
- println!("Kernel should kill this application!");
- unsafe {
- core::ptr::null_mut::().write_volatile(0);
- }
- 0
-}
diff --git a/user/src/lib.rs b/user/src/lib.rs
index fbe8862..dcbfc32 100644
--- a/user/src/lib.rs
+++ b/user/src/lib.rs
@@ -1,7 +1,7 @@
#![no_std]
#![feature(linkage)]
-use crate::syscall::{sys_exit, sys_write};
+use crate::syscall::{sys_exit, sys_get_time, sys_write};
mod syscall;
mod utils;
@@ -28,3 +28,11 @@ pub fn write(fd: usize, buf: &[u8]) -> isize {
pub fn exit(exit_code: i32) -> isize {
sys_exit(exit_code)
}
+
+pub fn get_time() -> isize {
+ sys_get_time()
+}
+
+pub fn sys_yield() -> isize {
+ syscall::sys_yield()
+}
diff --git a/user/src/syscall.rs b/user/src/syscall.rs
index 6025b8e..44551fd 100644
--- a/user/src/syscall.rs
+++ b/user/src/syscall.rs
@@ -2,6 +2,8 @@ use core::arch::asm;
const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93;
+const SYSCALL_YIELD: usize = 124;
+const SYSCALL_GET_TIME: usize = 169;
fn syscall(id: usize, args: [usize; 3]) -> isize {
let mut result: isize;
@@ -26,3 +28,11 @@ pub fn sys_write(fd: usize, buffer: &[u8]) -> isize {
pub fn sys_exit(exit_code: i32) -> isize {
syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0])
}
+
+pub fn sys_yield() -> isize {
+ syscall(SYSCALL_YIELD, [0, 0, 0])
+}
+
+pub fn sys_get_time() -> isize {
+ syscall(SYSCALL_GET_TIME, [0, 0, 0])
+}