add: ch3 finished

This commit is contained in:
jackfiled 2024-07-25 22:45:05 +08:00
parent 265e7adedf
commit 0d8d1ba8e1
32 changed files with 546 additions and 274 deletions

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@ -1,3 +1,4 @@
#!/usr/bin/env bash
cargo build --release cargo build --release
qemu-system-riscv64 \ qemu-system-riscv64 \

View File

@ -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<AppManager> = 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::<TrapContext>()) 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!()
}
}

1
os/src/boards.rs Normal file
View File

@ -0,0 +1 @@
pub mod qemu;

1
os/src/boards/qemu.rs Normal file
View File

@ -0,0 +1 @@
pub const CLOCK_FREQUENCY: usize = 10000000;

8
os/src/config.rs Normal file
View File

@ -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;

98
os/src/loader.rs Normal file
View File

@ -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::<TrapContext>()) 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()
))
}

View File

@ -4,13 +4,17 @@
use crate::utils::clear_bss; use crate::utils::clear_bss;
use core::arch::global_asm; use core::arch::global_asm;
mod batch;
mod console; mod console;
mod sbi; mod sbi;
mod sync; mod sync;
mod syscall; mod syscall;
mod trap; mod trap;
mod utils; mod utils;
mod loader;
mod boards;
mod config;
mod task;
mod timer;
global_asm!(include_str!("entry.asm")); global_asm!(include_str!("entry.asm"));
global_asm!(include_str!("link_app.asm")); global_asm!(include_str!("link_app.asm"));
@ -20,6 +24,8 @@ fn rust_main() -> ! {
clear_bss(); clear_bss();
log_information!("[kernel] Hello, rCore!"); log_information!("[kernel] Hello, rCore!");
trap::init(); trap::init();
batch::print_app_information(); loader::load_apps();
batch::run_next_application(); task::run_first_task();
unreachable!()
} }

View File

@ -14,3 +14,7 @@ pub fn shutdown(failure: bool) -> ! {
unreachable!() unreachable!()
} }
pub fn set_timer(timer: usize) {
sbi_rt::set_timer(timer as _);
}

View File

@ -1,18 +1,22 @@
use crate::syscall::fs::sys_write; 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 fs;
mod process; mod process;
const SYSCALL_WRITE: usize = 64; const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93; 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 { pub fn syscall(syscall_id: usize, args: [usize; 3]) -> usize {
match syscall_id { match syscall_id {
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
SYSCALL_EXIT => sys_exit(args[0] as i32), SYSCALL_EXIT => sys_exit(args[0] as i32),
SYSCALL_YIELD => sys_yield(),
SYSCALL_GET_TIME => sys_get_time(),
_ => { _ => {
panic!("Unsupported syscall: {}", syscall_id) panic!("Unsupported syscall: {}", syscall_id)
} },
} }
} }

View File

@ -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 slice = unsafe { core::slice::from_raw_parts(buffer, len) };
let str = core::str::from_utf8(slice).unwrap(); let str = core::str::from_utf8(slice).unwrap();
print!("{}", str); print!("{}", str);
len as usize len
} }
_ => { _ => {
panic!("Unsupported file descriptor in sys_write"); panic!("Unsupported file descriptor in sys_write");

View File

@ -1,7 +1,20 @@
use crate::batch::run_next_application;
use crate::println; 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) -> ! { pub fn sys_exit(exit_state: i32) -> ! {
println!("[kernel] Application exited with code {}.", exit_state); 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()
} }

133
os/src/task.rs Normal file
View File

@ -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<TaskManagerInner>,
}
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<usize> {
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!();
}
}

31
os/src/task/context.rs Normal file
View File

@ -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]
}
}
}

33
os/src/task/switch.asm Normal file
View File

@ -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

10
os/src/task/switch.rs Normal file
View File

@ -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);
}

18
os/src/timer.rs Normal file
View File

@ -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);
}

View File

@ -39,9 +39,6 @@ __alltraps:
call trap_handler call trap_handler
__restore: __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 # now sp->kernel stack(after allocated), sscratch->user stack
# restore sstatus/sepc # restore sstatus/sepc
ld t0, 32*8(sp) ld t0, 32*8(sp)
@ -50,7 +47,7 @@ __restore:
csrw sstatus, t0 csrw sstatus, t0
csrw sepc, t1 csrw sepc, t1
csrw sscratch, t2 csrw sscratch, t2
# restore general-purpuse registers except sp/tp # restore general-purpose registers except sp/tp
ld x1, 1*8(sp) ld x1, 1*8(sp)
ld x3, 3*8(sp) ld x3, 3*8(sp)
.set n, 5 .set n, 5

View File

@ -1,13 +1,10 @@
use crate::batch::run_next_application;
use crate::println; use crate::println;
use crate::syscall::syscall; use crate::syscall::syscall;
use crate::trap::context::TrapContext; use crate::trap::context::TrapContext;
use core::arch::global_asm; use core::arch::global_asm;
use riscv::register::{ use riscv::register::{mtvec::TrapMode, scause::{self, Exception, Trap, Interrupt}, sie, stval, stvec};
mtvec::TrapMode, use crate::task::{exit_current_and_run_next, suspend_current_and_run_next};
scause::{self, Exception, Trap}, use crate::timer::set_next_trigger;
stval, stvec,
};
pub mod context; pub mod context;
@ -18,7 +15,12 @@ pub fn init() {
fn __alltraps(); fn __alltraps();
} }
unsafe { unsafe {
// 设置中断向量
stvec::write(__alltraps as usize, TrapMode::Direct); 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) => { Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) => {
println!("[kernel] PageFault in application, kernel will kill it."); println!("[kernel] PageFault in application, kernel will kill it.");
run_next_application(); exit_current_and_run_next();
} }
Trap::Exception(Exception::IllegalInstruction) => { Trap::Exception(Exception::IllegalInstruction) => {
println!("[kernel] Illegal instruction in application, kernel will kill it."); 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!( panic!(

View File

@ -8,9 +8,11 @@ pub struct TrapContext {
} }
impl 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(); let sstatus = sstatus::read();
unsafe {
sstatus::set_spp(SPP::User); sstatus::set_spp(SPP::User);
}
let mut context = Self { let mut context = Self {
x: [0; 32], x: [0; 32],
s_status: sstatus, s_status: sstatus,

View File

@ -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

30
user/build.py Executable file
View File

@ -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

View File

@ -1,12 +0,0 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
#[no_mangle]
fn main() -> i32 {
println!("Hello, world!");
0
}

View File

@ -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
}

View File

@ -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
}

28
user/src/bin/power_3.rs Normal file
View File

@ -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
}

28
user/src/bin/power_5.rs Normal file
View File

@ -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
}

28
user/src/bin/power_7.rs Normal file
View File

@ -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
}

20
user/src/bin/sleep.rs Normal file
View File

@ -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
}

View File

@ -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::<u8>().write_volatile(0);
}
0
}

View File

@ -1,7 +1,7 @@
#![no_std] #![no_std]
#![feature(linkage)] #![feature(linkage)]
use crate::syscall::{sys_exit, sys_write}; use crate::syscall::{sys_exit, sys_get_time, sys_write};
mod syscall; mod syscall;
mod utils; mod utils;
@ -28,3 +28,11 @@ pub fn write(fd: usize, buf: &[u8]) -> isize {
pub fn exit(exit_code: i32) -> isize { pub fn exit(exit_code: i32) -> isize {
sys_exit(exit_code) sys_exit(exit_code)
} }
pub fn get_time() -> isize {
sys_get_time()
}
pub fn sys_yield() -> isize {
syscall::sys_yield()
}

View File

@ -2,6 +2,8 @@ use core::arch::asm;
const SYSCALL_WRITE: usize = 64; const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93; const SYSCALL_EXIT: usize = 93;
const SYSCALL_YIELD: usize = 124;
const SYSCALL_GET_TIME: usize = 169;
fn syscall(id: usize, args: [usize; 3]) -> isize { fn syscall(id: usize, args: [usize; 3]) -> isize {
let mut result: 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 { pub fn sys_exit(exit_code: i32) -> isize {
syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]) 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])
}