diff --git a/ch1/README.md b/ch1/README.md new file mode 100644 index 00000000..eef7a09b --- /dev/null +++ b/ch1/README.md @@ -0,0 +1,3 @@ +# Tutorial 第一章测试用例 + +第一章只需要在 RV64 裸机平台运行一个嵌入式应用,因此只要能够在 SBI 的帮助下在屏幕上输出一行字符串就算成功。 \ No newline at end of file diff --git a/ch2/.cargo/config b/ch2/.cargo/config new file mode 100644 index 00000000..e5ded8a1 --- /dev/null +++ b/ch2/.cargo/config @@ -0,0 +1,7 @@ +[build] +target = "riscv64gc-unknown-none-elf" + +[target.riscv64gc-unknown-none-elf] +rustflags = [ + "-Clink-args=-Tsrc/linker.ld", +] diff --git a/ch2/.gitignore b/ch2/.gitignore new file mode 100644 index 00000000..fbd7c914 --- /dev/null +++ b/ch2/.gitignore @@ -0,0 +1,2 @@ +target/* +Cargo.lock diff --git a/ch2/.idea/misc.xml b/ch2/.idea/misc.xml new file mode 100644 index 00000000..56189180 --- /dev/null +++ b/ch2/.idea/misc.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/ch2/.idea/user.iml b/ch2/.idea/user.iml new file mode 100644 index 00000000..b44d0258 --- /dev/null +++ b/ch2/.idea/user.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ch2/.idea/vcs.xml b/ch2/.idea/vcs.xml new file mode 100644 index 00000000..6c0b8635 --- /dev/null +++ b/ch2/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ch2/.idea/workspace.xml b/ch2/.idea/workspace.xml new file mode 100644 index 00000000..b4ed534b --- /dev/null +++ b/ch2/.idea/workspace.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1605727203780 + + + + + + + + + \ No newline at end of file diff --git a/ch3-coop/Cargo.toml b/ch3-coop/Cargo.toml new file mode 100644 index 00000000..817ca525 --- /dev/null +++ b/ch3-coop/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "user_lib" +version = "0.1.0" +authors = ["Yifan Wu "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/ch3-coop/Makefile b/ch3-coop/Makefile new file mode 100644 index 00000000..5ca334ea --- /dev/null +++ b/ch3-coop/Makefile @@ -0,0 +1,23 @@ +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: $(APPS) + @python3 build.py + +binary: elf + $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) + +build: binary + +clean: + @cargo clean + +.PHONY: elf binary build clean \ No newline at end of file diff --git a/ch3-coop/README.md b/ch3-coop/README.md new file mode 100644 index 00000000..b5bf1e13 --- /dev/null +++ b/ch3-coop/README.md @@ -0,0 +1,4 @@ +# Tutorial 第三章测试用例 part1 + +在 Tutorial 第三章第一阶段中,只需实现一个非抢占式调度的分时多任务系统。 + diff --git a/ch3-coop/build.py b/ch3-coop/build.py new file mode 100644 index 00000000..b558177a --- /dev/null +++ b/ch3-coop/build.py @@ -0,0 +1,25 @@ +import os + +base_address = 0x80100000 +step = 0x20000 +linker = 'src/linker.ld' + +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) + 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 diff --git a/ch3-coop/src/bin/00write_a.rs b/ch3-coop/src/bin/00write_a.rs new file mode 100644 index 00000000..f7ada612 --- /dev/null +++ b/ch3-coop/src/bin/00write_a.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::sys_yield; + +const WIDTH: usize = 10; +const HEIGHT: usize = 5; + +#[no_mangle] +fn main() -> i32 { + for i in 0..HEIGHT { + for _ in 0..WIDTH { print!("A"); } + println!(" [{}/{}]", i + 1, HEIGHT); + sys_yield(); + } + println!("Test write_a OK!"); + 0 +} \ No newline at end of file diff --git a/ch3-coop/src/bin/01write_b.rs b/ch3-coop/src/bin/01write_b.rs new file mode 100644 index 00000000..e16b79da --- /dev/null +++ b/ch3-coop/src/bin/01write_b.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::sys_yield; + +const WIDTH: usize = 10; +const HEIGHT: usize = 2; + +#[no_mangle] +fn main() -> i32 { + for i in 0..HEIGHT { + for _ in 0..WIDTH { print!("B"); } + println!(" [{}/{}]", i + 1, HEIGHT); + sys_yield(); + } + println!("Test write_b OK!"); + 0 +} diff --git a/ch3-coop/src/bin/02write_c.rs b/ch3-coop/src/bin/02write_c.rs new file mode 100644 index 00000000..771f6447 --- /dev/null +++ b/ch3-coop/src/bin/02write_c.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::sys_yield; + +const WIDTH: usize = 10; +const HEIGHT: usize = 3; + +#[no_mangle] +fn main() -> i32 { + for i in 0..HEIGHT { + for _ in 0..WIDTH { print!("C"); } + println!(" [{}/{}]", i + 1, HEIGHT); + sys_yield(); + } + println!("Test write_c OK!"); + 0 +} diff --git a/ch3-coop/src/console.rs b/ch3-coop/src/console.rs new file mode 100644 index 00000000..a826b8fe --- /dev/null +++ b/ch3-coop/src/console.rs @@ -0,0 +1,29 @@ +use core::fmt::{self, Write}; +use crate::syscall::{STDOUT, sys_write}; + +struct Stdout; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + sys_write(STDOUT, s.as_bytes()); + Ok(()) + } +} + +pub fn print(args: fmt::Arguments) { + Stdout.write_fmt(args).unwrap(); +} + +#[macro_export] +macro_rules! print { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!($fmt $(, $($arg)+)?)); + } +} + +#[macro_export] +macro_rules! println { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); + } +} \ No newline at end of file diff --git a/ch3-coop/src/lang_items.rs b/ch3-coop/src/lang_items.rs new file mode 100644 index 00000000..c90d297f --- /dev/null +++ b/ch3-coop/src/lang_items.rs @@ -0,0 +1,10 @@ +#[panic_handler] +fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { + let err = panic_info.message().unwrap(); + if let Some(location) = panic_info.location() { + println!("Panicked at {}:{}, {}", location.file(), location.line(), err); + } else { + println!("Panicked: {}", err); + } + loop {} +} \ No newline at end of file diff --git a/ch3-coop/src/lib.rs b/ch3-coop/src/lib.rs new file mode 100644 index 00000000..fdcb6d56 --- /dev/null +++ b/ch3-coop/src/lib.rs @@ -0,0 +1,35 @@ +#![no_std] +#![feature(llvm_asm)] +#![feature(linkage)] +#![feature(panic_info_message)] + +#[macro_use] +pub mod console; +mod syscall; +mod lang_items; + +#[no_mangle] +#[link_section = ".text.entry"] +pub extern "C" fn _start() -> ! { + clear_bss(); + syscall::sys_exit(main()); + panic!("unreachable after sys_exit!"); +} + +#[linkage = "weak"] +#[no_mangle] +fn main() -> i32 { + panic!("Cannot find main!"); +} + +fn clear_bss() { + extern "C" { + fn start_bss(); + fn end_bss(); + } + (start_bss as usize..end_bss as usize).for_each(|addr| { + unsafe { (addr as *mut u8).write_volatile(0); } + }); +} + +pub use syscall::*; \ No newline at end of file diff --git a/ch3-coop/src/linker.ld b/ch3-coop/src/linker.ld new file mode 100644 index 00000000..1c64a19b --- /dev/null +++ b/ch3-coop/src/linker.ld @@ -0,0 +1,29 @@ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0x80100000; + +SECTIONS +{ + . = BASE_ADDRESS; + .text : { + *(.text.entry) + *(.text .text.*) + } + .rodata : { + *(.rodata .rodata.*) + } + .data : { + *(.data .data.*) + } + .bss : { + start_bss = .; + *(.bss .bss.*) + end_bss = .; + } + /DISCARD/ : { + *(.eh_frame) + *(.debug*) + } +} \ No newline at end of file diff --git a/ch3-coop/src/syscall.rs b/ch3-coop/src/syscall.rs new file mode 100644 index 00000000..8e4ff50b --- /dev/null +++ b/ch3-coop/src/syscall.rs @@ -0,0 +1,35 @@ +pub const STDOUT: usize = 1; + +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 ret: isize; + unsafe { + llvm_asm!("ecall" + : "={x10}" (ret) + : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id) + : "memory" + : "volatile" + ); + } + ret +} + +pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { + syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) +} + +pub fn sys_exit(xstate: i32) -> isize { + syscall(SYSCALL_EXIT, [xstate 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]) +} \ No newline at end of file diff --git a/ch3/.cargo/config b/ch3/.cargo/config new file mode 100644 index 00000000..e5ded8a1 --- /dev/null +++ b/ch3/.cargo/config @@ -0,0 +1,7 @@ +[build] +target = "riscv64gc-unknown-none-elf" + +[target.riscv64gc-unknown-none-elf] +rustflags = [ + "-Clink-args=-Tsrc/linker.ld", +] diff --git a/ch3/.gitignore b/ch3/.gitignore new file mode 100644 index 00000000..e420ee4b --- /dev/null +++ b/ch3/.gitignore @@ -0,0 +1 @@ +target/* diff --git a/ch3/.idea/misc.xml b/ch3/.idea/misc.xml new file mode 100644 index 00000000..56189180 --- /dev/null +++ b/ch3/.idea/misc.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/ch3/.idea/user.iml b/ch3/.idea/user.iml new file mode 100644 index 00000000..b44d0258 --- /dev/null +++ b/ch3/.idea/user.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ch3/.idea/vcs.xml b/ch3/.idea/vcs.xml new file mode 100644 index 00000000..6c0b8635 --- /dev/null +++ b/ch3/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ch3/.idea/workspace.xml b/ch3/.idea/workspace.xml new file mode 100644 index 00000000..b4ed534b --- /dev/null +++ b/ch3/.idea/workspace.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1605727203780 + + + + + + + + + \ No newline at end of file diff --git a/ch4/Cargo.toml b/ch4/Cargo.toml new file mode 100644 index 00000000..817ca525 --- /dev/null +++ b/ch4/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "user_lib" +version = "0.1.0" +authors = ["Yifan Wu "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/ch4/Makefile b/ch4/Makefile new file mode 100644 index 00000000..5e0f87c3 --- /dev/null +++ b/ch4/Makefile @@ -0,0 +1,23 @@ +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: $(APPS) + @cargo build --release + +binary: elf + $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) + +build: binary + +clean: + @cargo clean + +.PHONY: elf binary build clean \ No newline at end of file diff --git a/ch4/src/bin/00power_3.rs b/ch4/src/bin/00power_3.rs new file mode 100644 index 00000000..532829da --- /dev/null +++ b/ch4/src/bin/00power_3.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +const LEN: usize = 100; + +static mut S: [u64; LEN] = [0u64; LEN]; + +#[no_mangle] +unsafe fn main() -> i32 { + let p = 3u64; + let m = 998244353u64; + let iter: usize = 300000; + 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/ch4/src/bin/01power_5.rs b/ch4/src/bin/01power_5.rs new file mode 100644 index 00000000..f23e3b84 --- /dev/null +++ b/ch4/src/bin/01power_5.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +const LEN: usize = 100; + +static mut S: [u64; LEN] = [0u64; LEN]; + +#[no_mangle] +unsafe fn main() -> i32 { + let p = 5u64; + let m = 998244353u64; + let iter: usize = 210000; + 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 +} diff --git a/ch4/src/bin/02power_7.rs b/ch4/src/bin/02power_7.rs new file mode 100644 index 00000000..35bada18 --- /dev/null +++ b/ch4/src/bin/02power_7.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +const LEN: usize = 100; + +static mut S: [u64; LEN] = [0u64; LEN]; + +#[no_mangle] +unsafe fn main() -> i32 { + let p = 7u64; + let m = 998244353u64; + let iter: usize = 240000; + 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 +} diff --git a/ch4/src/bin/03sleep.rs b/ch4/src/bin/03sleep.rs new file mode 100644 index 00000000..f3d9f31b --- /dev/null +++ b/ch4/src/bin/03sleep.rs @@ -0,0 +1,18 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{sys_get_time, sys_yield}; + +#[no_mangle] +fn main() -> i32 { + let current_timer = sys_get_time(); + let wait_for = current_timer + 10000000; + while sys_get_time() < wait_for { + sys_yield(); + } + println!("Test sleep OK!"); + 0 +} \ No newline at end of file diff --git a/ch4/src/console.rs b/ch4/src/console.rs new file mode 100644 index 00000000..a826b8fe --- /dev/null +++ b/ch4/src/console.rs @@ -0,0 +1,29 @@ +use core::fmt::{self, Write}; +use crate::syscall::{STDOUT, sys_write}; + +struct Stdout; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + sys_write(STDOUT, s.as_bytes()); + Ok(()) + } +} + +pub fn print(args: fmt::Arguments) { + Stdout.write_fmt(args).unwrap(); +} + +#[macro_export] +macro_rules! print { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!($fmt $(, $($arg)+)?)); + } +} + +#[macro_export] +macro_rules! println { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); + } +} \ No newline at end of file diff --git a/ch4/src/lang_items.rs b/ch4/src/lang_items.rs new file mode 100644 index 00000000..c90d297f --- /dev/null +++ b/ch4/src/lang_items.rs @@ -0,0 +1,10 @@ +#[panic_handler] +fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { + let err = panic_info.message().unwrap(); + if let Some(location) = panic_info.location() { + println!("Panicked at {}:{}, {}", location.file(), location.line(), err); + } else { + println!("Panicked: {}", err); + } + loop {} +} \ No newline at end of file diff --git a/ch4/src/lib.rs b/ch4/src/lib.rs new file mode 100644 index 00000000..c072ef49 --- /dev/null +++ b/ch4/src/lib.rs @@ -0,0 +1,25 @@ +#![no_std] +#![feature(llvm_asm)] +#![feature(linkage)] +#![feature(panic_info_message)] + +#[macro_use] +pub mod console; +mod syscall; +mod lang_items; + +#[no_mangle] +#[link_section = ".text.entry"] +pub extern "C" fn _start() -> ! { + syscall::sys_exit(main()); + panic!("unreachable after sys_exit!"); +} + +#[linkage = "weak"] +#[no_mangle] +fn main() -> i32 { + panic!("Cannot find main!"); +} + + +pub use syscall::*; \ No newline at end of file diff --git a/ch4/src/linker.ld b/ch4/src/linker.ld new file mode 100644 index 00000000..e05a98ba --- /dev/null +++ b/ch4/src/linker.ld @@ -0,0 +1,29 @@ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0x0; + +SECTIONS +{ + . = BASE_ADDRESS; + .text : { + *(.text.entry) + *(.text .text.*) + } + . = ALIGN(4K); + .rodata : { + *(.rodata .rodata.*) + } + . = ALIGN(4K); + .data : { + *(.data .data.*) + } + .bss : { + *(.bss .bss.*) + } + /DISCARD/ : { + *(.eh_frame) + *(.debug*) + } +} \ No newline at end of file diff --git a/ch4/src/syscall.rs b/ch4/src/syscall.rs new file mode 100644 index 00000000..8e4ff50b --- /dev/null +++ b/ch4/src/syscall.rs @@ -0,0 +1,35 @@ +pub const STDOUT: usize = 1; + +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 ret: isize; + unsafe { + llvm_asm!("ecall" + : "={x10}" (ret) + : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id) + : "memory" + : "volatile" + ); + } + ret +} + +pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { + syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) +} + +pub fn sys_exit(xstate: i32) -> isize { + syscall(SYSCALL_EXIT, [xstate 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]) +} \ No newline at end of file diff --git a/ch5/.cargo/config b/ch5/.cargo/config new file mode 100644 index 00000000..e5ded8a1 --- /dev/null +++ b/ch5/.cargo/config @@ -0,0 +1,7 @@ +[build] +target = "riscv64gc-unknown-none-elf" + +[target.riscv64gc-unknown-none-elf] +rustflags = [ + "-Clink-args=-Tsrc/linker.ld", +] diff --git a/ch5/.gitignore b/ch5/.gitignore new file mode 100644 index 00000000..e420ee4b --- /dev/null +++ b/ch5/.gitignore @@ -0,0 +1 @@ +target/* diff --git a/ch5/.idea/misc.xml b/ch5/.idea/misc.xml new file mode 100644 index 00000000..56189180 --- /dev/null +++ b/ch5/.idea/misc.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/ch5/.idea/user.iml b/ch5/.idea/user.iml new file mode 100644 index 00000000..b44d0258 --- /dev/null +++ b/ch5/.idea/user.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ch5/.idea/vcs.xml b/ch5/.idea/vcs.xml new file mode 100644 index 00000000..6c0b8635 --- /dev/null +++ b/ch5/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ch5/.idea/workspace.xml b/ch5/.idea/workspace.xml new file mode 100644 index 00000000..b4ed534b --- /dev/null +++ b/ch5/.idea/workspace.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1605727203780 + + + + + + + + + \ No newline at end of file diff --git a/ch6/Cargo.toml b/ch6/Cargo.toml new file mode 100644 index 00000000..aa6e20fe --- /dev/null +++ b/ch6/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "user_lib" +version = "0.1.0" +authors = ["Yifan Wu "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +buddy_system_allocator = "0.6" \ No newline at end of file diff --git a/ch6/Makefile b/ch6/Makefile new file mode 100644 index 00000000..5e0f87c3 --- /dev/null +++ b/ch6/Makefile @@ -0,0 +1,23 @@ +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: $(APPS) + @cargo build --release + +binary: elf + $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) + +build: binary + +clean: + @cargo clean + +.PHONY: elf binary build clean \ No newline at end of file diff --git a/ch6/src/bin/exit.rs b/ch6/src/bin/exit.rs new file mode 100644 index 00000000..5bde550b --- /dev/null +++ b/ch6/src/bin/exit.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use user_lib::{fork, yield_, waitpid, exit, wait}; + +const MAGIC: i32 = -0x10384; + +#[no_mangle] +pub fn main() -> i32 { + println!("I am the parent. Forking the child..."); + let pid = fork(); + if pid == 0 { + println!("I am the child."); + for _ in 0..7 { yield_(); } + exit(MAGIC); + } else { + println!("I am parent, fork a child pid {}", pid); + } + println!("I am the parent, waiting now.."); + let mut xstate: i32 = 0; + assert!(waitpid(pid as usize, &mut xstate) == pid && xstate == MAGIC); + assert!(waitpid(pid as usize, &mut xstate) < 0 && wait(&mut xstate) <= 0); + println!("waitpid {} ok.", pid); + println!("exit pass."); + 0 +} + diff --git a/ch6/src/bin/fantastic_text.rs b/ch6/src/bin/fantastic_text.rs new file mode 100644 index 00000000..bb51db30 --- /dev/null +++ b/ch6/src/bin/fantastic_text.rs @@ -0,0 +1,44 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +macro_rules! color_text { + ($text:expr, $color:expr) => {{ + format_args!("\x1b[{}m{}\x1b[0m", $color, $text) + }}; +} + +#[no_mangle] +pub fn main() -> i32 { + println!( + "{}{}{}{}{} {}{}{}{} {}{}{}{}{}{}", + color_text!("H", 31), + color_text!("e", 32), + color_text!("l", 33), + color_text!("l", 34), + color_text!("o", 35), + color_text!("R", 36), + color_text!("u", 37), + color_text!("s", 90), + color_text!("t", 91), + color_text!("u", 92), + color_text!("C", 93), + color_text!("o", 94), + color_text!("r", 95), + color_text!("e", 96), + color_text!("!", 97), + ); + + let text = + "reguler \x1b[4munderline\x1b[24m \x1b[7mreverse\x1b[27m \x1b[9mstrikethrough\x1b[29m"; + println!("\x1b[47m{}\x1b[0m", color_text!(text, 30)); + for i in 31..38 { + println!("{}", color_text!(text, i)); + } + for i in 90..98 { + println!("{}", color_text!(text, i)); + } + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/forktest.rs b/ch6/src/bin/forktest.rs new file mode 100644 index 00000000..fea6967c --- /dev/null +++ b/ch6/src/bin/forktest.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, wait, exit}; + +const MAX_CHILD: usize = 40; + +#[no_mangle] +pub fn main() -> i32 { + for i in 0..MAX_CHILD { + let pid = fork(); + if pid == 0 { + println!("I am child {}", i); + exit(0); + } else { + println!("forked child pid = {}", pid); + } + assert!(pid > 0); + } + let mut exit_code: i32 = 0; + for _ in 0..MAX_CHILD { + if wait(&mut exit_code) <= 0 { + panic!("wait stopped early"); + } + } + if wait(&mut exit_code) > 0 { + panic!("wait got too many"); + } + println!("forktest pass."); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/forktest2.rs b/ch6/src/bin/forktest2.rs new file mode 100644 index 00000000..493fccd8 --- /dev/null +++ b/ch6/src/bin/forktest2.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, wait, getpid, exit, sleep, get_time}; + +static NUM: usize = 30; + +#[no_mangle] +pub fn main() -> i32 { + for _ in 0..NUM { + let pid = fork(); + if pid == 0 { + let current_time = get_time(); + let sleep_length = (current_time as i32 as isize) * (current_time as i32 as isize) % 1000 + 1000; + println!("pid {} sleep for {} ms", getpid(), sleep_length); + sleep(sleep_length as usize); + println!("pid {} OK!", getpid()); + exit(0); + } + } + + let mut xstate: i32 = 0; + for _ in 0..NUM { + assert!(wait(&mut xstate) > 0); + assert_eq!(xstate, 0); + } + assert!(wait(&mut xstate) < 0); + println!("forktest2 test passed!"); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/forktest_simple.rs b/ch6/src/bin/forktest_simple.rs new file mode 100644 index 00000000..1851aea0 --- /dev/null +++ b/ch6/src/bin/forktest_simple.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, getpid, wait}; + +#[no_mangle] +pub fn main() -> i32 { + assert_eq!(wait(&mut 0i32), -1); + println!("sys_wait without child process test passed!"); + println!("parent start, pid = {}!", getpid()); + let pid = fork(); + if pid == 0 { + // child process + println!("hello child process!"); + 100 + } else { + // parent process + let mut xstate: i32 = 0; + println!("ready waiting on parent process!"); + assert_eq!(pid, wait(&mut xstate)); + assert_eq!(xstate, 100); + println!("child process pid = {}, exit code = {}", pid, xstate); + 0 + } +} \ No newline at end of file diff --git a/ch6/src/bin/forktree.rs b/ch6/src/bin/forktree.rs new file mode 100644 index 00000000..26954b7a --- /dev/null +++ b/ch6/src/bin/forktree.rs @@ -0,0 +1,37 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{sleep, getpid, fork, exit, yield_}; + +const DEPTH: usize = 4; + +fn fork_child(cur: &str, branch: char) { + let mut next = [0u8; DEPTH + 1]; + let l = cur.len(); + if l >= DEPTH { + return; + } + &mut next[..l].copy_from_slice(cur.as_bytes()); + next[l] = branch as u8; + if fork() == 0 { + fork_tree(core::str::from_utf8(&next[..l + 1]).unwrap()); + yield_(); + exit(0); + } +} + +fn fork_tree(cur: &str) { + println!("pid{}: {}", getpid(), cur); + fork_child(cur, '0'); + fork_child(cur, '1'); +} + +#[no_mangle] +pub fn main() -> i32 { + fork_tree(""); + sleep(3000); + 0 +} diff --git a/ch6/src/bin/hello_world.rs b/ch6/src/bin/hello_world.rs new file mode 100644 index 00000000..de4a6a92 --- /dev/null +++ b/ch6/src/bin/hello_world.rs @@ -0,0 +1,11 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +pub fn main() -> i32 { + println!("Hello world from user mode program!"); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/initproc.rs b/ch6/src/bin/initproc.rs new file mode 100644 index 00000000..6d30fdb6 --- /dev/null +++ b/ch6/src/bin/initproc.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{ + fork, + wait, + exec, + yield_, +}; + +#[no_mangle] +fn main() -> i32 { + if fork() == 0 { + exec("user_shell\0"); + } else { + loop { + let mut exit_code: i32 = 0; + let pid = wait(&mut exit_code); + if pid == -1 { + yield_(); + continue; + } + println!( + "[initproc] Released a zombie process, pid={}, exit_code={}", + pid, + exit_code, + ); + } + } + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/matrix.rs b/ch6/src/bin/matrix.rs new file mode 100644 index 00000000..95904337 --- /dev/null +++ b/ch6/src/bin/matrix.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, wait, yield_, exit, getpid, get_time}; + +static NUM: usize = 35; +const N: usize = 10; +static P: i32 = 10007; +type Arr = [[i32; N]; N]; + +fn work(times: isize) { + let mut a: Arr = Default::default(); + let mut b: Arr = Default::default(); + let mut c: Arr = Default::default(); + for i in 0..N { + for j in 0..N { + a[i][j] = 1; + b[i][j] = 1; + } + } + yield_(); + println!("pid {} is running ({} times)!.", getpid(), times); + for _ in 0..times { + for i in 0..N { + for j in 0..N { + c[i][j] = 0; + for k in 0..N { + c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % P; + } + } + } + for i in 0..N { + for j in 0..N { + a[i][j] = c[i][j]; + b[i][j] = c[i][j]; + } + } + } + println!("pid {} done!.", getpid()); + exit(0); +} + +#[no_mangle] +pub fn main() -> i32 { + for _ in 0..NUM { + let pid = fork(); + if pid == 0 { + let current_time = get_time(); + let times = (current_time as i32 as isize) * (current_time as i32 as isize) % 1000; + work(times * 10); + } + } + + println!("fork ok."); + + let mut xstate: i32 = 0; + for _ in 0..NUM { + if wait(&mut xstate) < 0 { + panic!("wait failed."); + } + } + assert!(wait(&mut xstate) < 0); + println!("matrix passed."); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/pipe_large_test.rs b/ch6/src/bin/pipe_large_test.rs new file mode 100644 index 00000000..121987be --- /dev/null +++ b/ch6/src/bin/pipe_large_test.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use user_lib::{fork, close, pipe, read, write, wait, get_time}; +use alloc::format; + +const LENGTH: usize = 3000; +#[no_mangle] +pub fn main() -> i32 { + // create pipes + // parent write to child + let mut down_pipe_fd = [0usize; 2]; + // child write to parent + let mut up_pipe_fd = [0usize; 2]; + pipe(&mut down_pipe_fd); + pipe(&mut up_pipe_fd); + let mut random_str = [0u8; LENGTH]; + if fork() == 0 { + // close write end of down pipe + close(down_pipe_fd[1]); + // close read end of up pipe + close(up_pipe_fd[0]); + assert_eq!(read(down_pipe_fd[0], &mut random_str) as usize, LENGTH); + close(down_pipe_fd[0]); + let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); + println!("sum = {}(child)", sum); + let sum_str = format!("{}", sum); + write(up_pipe_fd[1], sum_str.as_bytes()); + close(up_pipe_fd[1]); + println!("Child process exited!"); + 0 + } else { + // close read end of down pipe + close(down_pipe_fd[0]); + // close write end of up pipe + close(up_pipe_fd[1]); + // generate a long random string + for i in 0..LENGTH { + random_str[i] = get_time() as u8; + } + // send it + assert_eq!(write(down_pipe_fd[1], &random_str) as usize, random_str.len()); + // close write end of down pipe + close(down_pipe_fd[1]); + // calculate sum(parent) + let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); + println!("sum = {}(parent)", sum); + // recv sum(child) + let mut child_result = [0u8; 32]; + let result_len = read(up_pipe_fd[0], &mut child_result) as usize; + close(up_pipe_fd[0]); + // check + assert_eq!( + sum, + str::parse::( + core::str::from_utf8(&child_result[..result_len]).unwrap() + ).unwrap() + ); + let mut _unused: i32 = 0; + wait(&mut _unused); + println!("pipe_large_test passed!"); + 0 + } +} \ No newline at end of file diff --git a/ch6/src/bin/pipetest.rs b/ch6/src/bin/pipetest.rs new file mode 100644 index 00000000..58237847 --- /dev/null +++ b/ch6/src/bin/pipetest.rs @@ -0,0 +1,42 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, close, pipe, read, write, wait}; + +static STR: &str = "Hello, world!"; + +#[no_mangle] +pub fn main() -> i32 { + // create pipe + let mut pipe_fd = [0usize; 2]; + pipe(&mut pipe_fd); + // read end + assert_eq!(pipe_fd[0], 3); + // write end + assert_eq!(pipe_fd[1], 4); + if fork() == 0 { + // child process, read from parent + // close write_end + close(pipe_fd[1]); + let mut buffer = [0u8; 32]; + let len_read = read(pipe_fd[0], &mut buffer) as usize; + assert_eq!(core::str::from_utf8(&buffer[..len_read]).unwrap(), STR); + println!("Read OK, child process exited!"); + 0 + } else { + // parent process, write to child + // close read end + close(pipe_fd[0]); + assert_eq!(write(pipe_fd[1], STR.as_bytes()), STR.len() as isize); + // close write end + close(pipe_fd[1]); + let mut child_exit_code: i32 = 0; + wait(&mut child_exit_code); + assert_eq!(child_exit_code, 0); + println!("pipetest passed!"); + 0 + } +} \ No newline at end of file diff --git a/ch6/src/bin/run_pipe_test.rs b/ch6/src/bin/run_pipe_test.rs new file mode 100644 index 00000000..ca2afd15 --- /dev/null +++ b/ch6/src/bin/run_pipe_test.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, exec, wait}; + +#[no_mangle] +pub fn main() -> i32 { + for i in 0..1000 { + if fork() == 0 { + exec("pipe_large_test\0"); + } else { + let mut _unused: i32 = 0; + wait(&mut _unused); + println!("Iter {} OK.", i); + } + } + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/sleep.rs b/ch6/src/bin/sleep.rs new file mode 100644 index 00000000..439e8a65 --- /dev/null +++ b/ch6/src/bin/sleep.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{sleep, exit, get_time, fork, waitpid}; + +fn sleepy() { + let time: usize = 100; + for i in 0..5 { + sleep(time); + println!("sleep {} x {} msecs.", i + 1, time); + } + exit(0); +} + +#[no_mangle] +pub fn main() -> i32 { + let current_time = get_time(); + let pid = fork(); + let mut xstate: i32 = 0; + if pid == 0 { + sleepy(); + } + assert!(waitpid(pid as usize, &mut xstate) == pid && xstate == 0); + println!("use {} msecs.", get_time() - current_time); + println!("sleep pass."); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/sleep_simple.rs b/ch6/src/bin/sleep_simple.rs new file mode 100644 index 00000000..4c058f87 --- /dev/null +++ b/ch6/src/bin/sleep_simple.rs @@ -0,0 +1,19 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{get_time, sleep}; + +#[no_mangle] +pub fn main() -> i32 { + println!("into sleep test!"); + let start = get_time(); + println!("current time_msec = {}", start); + sleep(100); + let end = get_time(); + println!("time_msec = {} after sleeping 100 ticks, delta = {}ms!", end, end - start); + println!("r_sleep passed!"); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/stack_overflow.rs b/ch6/src/bin/stack_overflow.rs new file mode 100644 index 00000000..e0ea471d --- /dev/null +++ b/ch6/src/bin/stack_overflow.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +fn f(d: usize) { + println!("d = {}",d); + f(d + 1); +} + +#[no_mangle] +pub fn main() -> i32 { + println!("It should trigger segmentation fault!"); + f(0); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/user_shell.rs b/ch6/src/bin/user_shell.rs new file mode 100644 index 00000000..973f8901 --- /dev/null +++ b/ch6/src/bin/user_shell.rs @@ -0,0 +1,70 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +#[macro_use] +extern crate user_lib; + +const LF: u8 = 0x0au8; +const CR: u8 = 0x0du8; +const DL: u8 = 0x7fu8; +const BS: u8 = 0x08u8; + +use alloc::string::String; +use user_lib::{fork, exec, waitpid, yield_}; +use user_lib::console::getchar; + +#[no_mangle] +pub fn main() -> i32 { + println!("Rust user shell"); + let mut line: String = String::new(); + print!(">> "); + loop { + let c = getchar(); + match c { + LF | CR => { + println!(""); + if !line.is_empty() { + line.push('\0'); + let pid = fork(); + if pid == 0 { + // child process + if exec(line.as_str()) == -1 { + println!("Error when executing!"); + return -4; + } + unreachable!(); + } else { + let mut xstate: i32 = 0; + let mut exit_pid: isize; + loop { + exit_pid = waitpid(pid as usize, &mut xstate); + if exit_pid == -1 { + yield_(); + } else { + assert_eq!(pid, exit_pid); + println!("Shell: Process {} exited with code {}", pid, xstate); + break; + } + } + } + line.clear(); + } + print!(">> "); + } + BS | DL => { + if !line.is_empty() { + print!("{}", BS as char); + print!(" "); + print!("{}", BS as char); + line.pop(); + } + } + _ => { + print!("{}", c as char); + line.push(c as char); + } + } + } +} \ No newline at end of file diff --git a/ch6/src/bin/usertests.rs b/ch6/src/bin/usertests.rs new file mode 100644 index 00000000..d5d0d7d2 --- /dev/null +++ b/ch6/src/bin/usertests.rs @@ -0,0 +1,40 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +static TESTS: &[&str] = &[ + "exit\0", + "fantastic_text\0", + "forktest\0", + "forktest2\0", + "forktest_simple\0", + "hello_world\0", + "matrix\0", + "sleep\0", + "sleep_simple\0", + "stack_overflow\0", + "yield\0", +]; + +use user_lib::{exec, fork, waitpid}; + +#[no_mangle] +pub fn main() -> i32 { + for test in TESTS { + println!("Usertests: Running {}", test); + let pid = fork(); + if pid == 0 { + exec(*test); + panic!("unreachable!"); + } else { + let mut xstate: i32 = Default::default(); + let wait_pid = waitpid(pid as usize, &mut xstate); + assert_eq!(pid, wait_pid); + println!("\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", test, pid, xstate); + } + } + println!("Usertests passed!"); + 0 +} \ No newline at end of file diff --git a/ch6/src/bin/yield.rs b/ch6/src/bin/yield.rs new file mode 100644 index 00000000..55032e40 --- /dev/null +++ b/ch6/src/bin/yield.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use user_lib::{getpid, yield_}; + +#[no_mangle] +pub fn main() -> i32 { + println!("Hello, I am process {}.", getpid()); + for i in 0..5 { + yield_(); + println!("Back in process {}, iteration {}.", getpid(), i); + } + println!("yield pass."); + 0 +} \ No newline at end of file diff --git a/ch6/src/console.rs b/ch6/src/console.rs new file mode 100644 index 00000000..810ebba1 --- /dev/null +++ b/ch6/src/console.rs @@ -0,0 +1,39 @@ +use core::fmt::{self, Write}; + +const STDIN: usize = 0; +const STDOUT: usize = 1; + +use super::{read, write}; + +struct Stdout; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + write(STDOUT, s.as_bytes()); + Ok(()) + } +} + +pub fn print(args: fmt::Arguments) { + Stdout.write_fmt(args).unwrap(); +} + +#[macro_export] +macro_rules! print { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!($fmt $(, $($arg)+)?)); + } +} + +#[macro_export] +macro_rules! println { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); + } +} + +pub fn getchar() -> u8 { + let mut c = [0u8; 1]; + read(STDIN, &mut c); + c[0] +} diff --git a/ch6/src/lang_items.rs b/ch6/src/lang_items.rs new file mode 100644 index 00000000..b5b98e08 --- /dev/null +++ b/ch6/src/lang_items.rs @@ -0,0 +1,12 @@ +use super::exit; + +#[panic_handler] +fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { + let err = panic_info.message().unwrap(); + if let Some(location) = panic_info.location() { + println!("Panicked at {}:{}, {}", location.file(), location.line(), err); + } else { + println!("Panicked: {}", err); + } + exit(-1); +} \ No newline at end of file diff --git a/ch6/src/lib.rs b/ch6/src/lib.rs new file mode 100644 index 00000000..32482859 --- /dev/null +++ b/ch6/src/lib.rs @@ -0,0 +1,79 @@ +#![no_std] +#![feature(llvm_asm)] +#![feature(linkage)] +#![feature(panic_info_message)] +#![feature(alloc_error_handler)] + +#[macro_use] +pub mod console; +mod syscall; +mod lang_items; + +extern crate alloc; + +use syscall::*; +use buddy_system_allocator::LockedHeap; + +const USER_HEAP_SIZE: usize = 16384; + +static mut HEAP_SPACE: [u8; USER_HEAP_SIZE] = [0; USER_HEAP_SIZE]; + +#[global_allocator] +static HEAP: LockedHeap = LockedHeap::empty(); + +#[alloc_error_handler] +pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { + panic!("Heap allocation error, layout = {:?}", layout); +} + +#[no_mangle] +#[link_section = ".text.entry"] +pub extern "C" fn _start() -> ! { + unsafe { + HEAP.lock() + .init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); + } + exit(main()); +} + +#[linkage = "weak"] +#[no_mangle] +fn main() -> i32 { + panic!("Cannot find main!"); +} + +pub fn close(fd: usize) -> isize { sys_close(fd) } +pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } +pub fn read(fd: usize, buf: &mut [u8]) -> isize { sys_read(fd, buf) } +pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) } +pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); } +pub fn yield_() -> isize { sys_yield() } +pub fn get_time() -> isize { sys_get_time() } +pub fn getpid() -> isize { sys_getpid() } +pub fn fork() -> isize { sys_fork() } +pub fn exec(path: &str) -> isize { sys_exec(path) } +pub fn wait(exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(-1, exit_code as *mut _) { + -2 => { yield_(); } + // -1 or a real pid + exit_pid => return exit_pid, + } + } +} + +pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(pid as isize, exit_code as *mut _) { + -2 => { yield_(); } + // -1 or a real pid + exit_pid => return exit_pid, + } + } +} +pub fn sleep(period_ms: usize) { + let start = sys_get_time(); + while sys_get_time() < start + period_ms as isize { + sys_yield(); + } +} \ No newline at end of file diff --git a/ch6/src/linker.ld b/ch6/src/linker.ld new file mode 100644 index 00000000..e05a98ba --- /dev/null +++ b/ch6/src/linker.ld @@ -0,0 +1,29 @@ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0x0; + +SECTIONS +{ + . = BASE_ADDRESS; + .text : { + *(.text.entry) + *(.text .text.*) + } + . = ALIGN(4K); + .rodata : { + *(.rodata .rodata.*) + } + . = ALIGN(4K); + .data : { + *(.data .data.*) + } + .bss : { + *(.bss .bss.*) + } + /DISCARD/ : { + *(.eh_frame) + *(.debug*) + } +} \ No newline at end of file diff --git a/ch6/src/syscall.rs b/ch6/src/syscall.rs new file mode 100644 index 00000000..76683649 --- /dev/null +++ b/ch6/src/syscall.rs @@ -0,0 +1,69 @@ +const SYSCALL_CLOSE: usize = 57; +const SYSCALL_PIPE: usize = 59; +const SYSCALL_READ: usize = 63; +const SYSCALL_WRITE: usize = 64; +const SYSCALL_EXIT: usize = 93; +const SYSCALL_YIELD: usize = 124; +const SYSCALL_GET_TIME: usize = 169; +const SYSCALL_GETPID: usize = 172; +const SYSCALL_FORK: usize = 220; +const SYSCALL_EXEC: usize = 221; +const SYSCALL_WAITPID: usize = 260; + +fn syscall(id: usize, args: [usize; 3]) -> isize { + let mut ret: isize; + unsafe { + llvm_asm!("ecall" + : "={x10}" (ret) + : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id) + : "memory" + : "volatile" + ); + } + ret +} + +pub fn sys_close(fd: usize) -> isize { + syscall(SYSCALL_CLOSE, [fd, 0, 0]) +} + +pub fn sys_pipe(pipe: &mut [usize]) -> isize { + syscall(SYSCALL_PIPE, [pipe.as_mut_ptr() as usize, 0, 0]) +} + +pub fn sys_read(fd: usize, buffer: &mut [u8]) -> isize { + syscall(SYSCALL_READ, [fd, buffer.as_mut_ptr() as usize, buffer.len()]) +} + +pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { + syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) +} + +pub fn sys_exit(exit_code: i32) -> ! { + syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]); + panic!("sys_exit never returns!"); +} + +pub fn sys_yield() -> isize { + syscall(SYSCALL_YIELD, [0, 0, 0]) +} + +pub fn sys_get_time() -> isize { + syscall(SYSCALL_GET_TIME, [0, 0, 0]) +} + +pub fn sys_getpid() -> isize { + syscall(SYSCALL_GETPID, [0, 0, 0]) +} + +pub fn sys_fork() -> isize { + syscall(SYSCALL_FORK, [0, 0, 0]) +} + +pub fn sys_exec(path: &str) -> isize { + syscall(SYSCALL_EXEC, [path.as_ptr() as usize, 0, 0]) +} + +pub fn sys_waitpid(pid: isize, xstatus: *mut i32) -> isize { + syscall(SYSCALL_WAITPID, [pid as usize, xstatus as usize, 0]) +} \ No newline at end of file diff --git a/tests/chapter1/hello_world.rs b/tests/chapter1/hello_world.rs deleted file mode 100644 index bf369df4..00000000 --- a/tests/chapter1/hello_world.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Run this as a application on RV64 bare-metal. - -fn main() { - println!("Hello, world!"); -} diff --git a/tests/chapter2/power_bad.rs b/tests/chapter2/power_bad.rs deleted file mode 100644 index 11226f33..00000000 --- a/tests/chapter2/power_bad.rs +++ /dev/null @@ -1,26 +0,0 @@ -/// rCore application without user_lib. -/// Load it manually to 0x80040000. -/// It should not OK. Kernel should catch the page fault. - -const SIZE: usize = 10; -const P: u32 = 3; -const STEP: usize = 10000000; -const MOD: u32 = 10007; -fn main() -> ! { - 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!("{}^{}={}", P, i, pow[index]); - } - if i == STEP / 2 { - // TODO: Modify satp to a malicious value in order to destroy memory access mechanism. - } - } - println!("Test power_bad OK!"); - loop {} -} \ No newline at end of file diff --git a/tests/chapter3/write_a.rs b/tests/chapter3/write_a.rs deleted file mode 100644 index a1a5f69b..00000000 --- a/tests/chapter3/write_a.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// rCore application without user_lib. -/// Load it manually to 0x80040000. - -use user_lib::{sys_yield}; - -fn main() -> ! { - for _ in 0..10 { - for _ in 0..10 { - print!("A"); - } - println!(); - sys_yield(); - } - loop {} -} \ No newline at end of file diff --git a/tests/chapter3/write_b.rs b/tests/chapter3/write_b.rs deleted file mode 100644 index e2a2b12a..00000000 --- a/tests/chapter3/write_b.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// rCore application without user_lib. -/// Load it manually to 0x80050000. - -use user_lib::{sys_yield}; - -fn main() -> ! { - for _ in 0..10 { - for _ in 0..10 { - print!("B"); - } - println!(); - sys_yield(); - } - loop {} -} \ No newline at end of file