diff --git a/Cargo.lock b/Cargo.lock index 06d9ae08..d8bcb5c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,15 @@ dependencies = [ "talc", ] +[[package]] +name = "addr2line" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +dependencies = [ + "gimli 0.24.0", +] + [[package]] name = "adler" version = "1.0.2" @@ -86,6 +95,13 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" +[[package]] +name = "async_test" +version = "0.1.0" +dependencies = [ + "tokio", +] + [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -119,6 +135,21 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "backtrace" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.4.4", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.21.7" @@ -719,7 +750,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.1", ] [[package]] @@ -918,7 +949,7 @@ dependencies = [ "flume", "half", "lebe", - "miniz_oxide", + "miniz_oxide 0.7.2", "rayon-core", "smallvec", "zune-inflate", @@ -990,7 +1021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.2", ] [[package]] @@ -1122,6 +1153,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "gimli" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" + [[package]] name = "gimli" version = "0.26.2" @@ -1191,6 +1228,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hello" +version = "0.1.0" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "home" version = "0.5.9" @@ -1906,6 +1953,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -1916,6 +1973,18 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "mkdir" version = "0.1.0" @@ -2135,6 +2204,12 @@ dependencies = [ "objc", ] +[[package]] +name = "object" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" + [[package]] name = "object-chain" version = "0.1.3" @@ -2195,7 +2270,7 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pconst" version = "0.1.0" -source = "git+https://github.com/os-module/pconst.git#1a376a236849ccddd26d12adcfbc03399de66132" +source = "git+https://github.com/os-module/pconst.git#ed1dd3dd6a427b3d7c9cb14731c775476afca160" dependencies = [ "bitflags 1.3.2", "int-enum", @@ -2293,7 +2368,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.2", ] [[package]] @@ -2643,6 +2718,12 @@ dependencies = [ "Mstd", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2773,6 +2854,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -2935,6 +3025,16 @@ dependencies = [ "scheduler", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket_test" version = "0.1.0" @@ -3069,7 +3169,7 @@ dependencies = [ [[package]] name = "syscall-table" version = "0.1.0" -source = "git+https://github.com/os-module/syscall-table.git#8363c7c6619a57580bad6e0a07c4c830ad184f74" +source = "git+https://github.com/os-module/syscall-table.git#ce816b94bf4874c4541ef7dc93580988bb7c83de" dependencies = [ "inventory", "paste", @@ -3090,7 +3190,7 @@ dependencies = [ [[package]] name = "systable-macro-derive" version = "0.1.0" -source = "git+https://github.com/os-module/syscall-table.git#8363c7c6619a57580bad6e0a07c4c830ad184f74" +source = "git+https://github.com/os-module/syscall-table.git#ce816b94bf4874c4541ef7dc93580988bb7c83de" dependencies = [ "quote", "syn 2.0.65", @@ -3279,6 +3379,33 @@ dependencies = [ "virt2slint", ] +[[package]] +name = "tokio" +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +dependencies = [ + "backtrace", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + [[package]] name = "toml_datetime" version = "0.6.5" @@ -3309,7 +3436,7 @@ version = "0.2.0" source = "git+https://github.com/os-module/tracer#a02d62f74e11de9ea94b2ba71f4a0cd080f76932" dependencies = [ "bit_field", - "gimli", + "gimli 0.26.2", "log", ] @@ -3554,6 +3681,7 @@ dependencies = [ "ramfs", "shim", "spin", + "timer", "tinyrlibc", "vfscore", ] @@ -3656,6 +3784,12 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.91" diff --git a/Cargo.toml b/Cargo.toml index b7ff8dae..57bdeab8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ members = [ "user/userlib", "subsystems/*", "user/apps/*", + "user/musl/hello", + "user/musl/async_test", ] diff --git a/Makefile b/Makefile index 1cbc78b9..6d4ec6a6 100644 --- a/Makefile +++ b/Makefile @@ -120,6 +120,7 @@ user: @echo "Building user apps" @make all -C ./user/apps @make all -C ./user/c_apps ARCH=riscv64 + @make all -C ./user/musl @echo "Building user apps done" sdcard:$(FS) mount testelf user initramfs diff --git a/docs/doc/musl.md b/docs/doc/musl.md index 47722767..c41af978 100644 --- a/docs/doc/musl.md +++ b/docs/doc/musl.md @@ -1,4 +1,58 @@ # 编译 riscv64gc-unknown-linux-musl rust程序 +`riscv64gc-unknown-linux-musl` target 是Tier3,因此不能像`riscv64gc-unknown-none-elf` 一样直接使用。为了编译出静态链接的程序,需要修改相关的参数。 + +在user/musl/.cargo目录下,展示了必要的配置。 + +``` +[target.riscv64gc-unknown-linux-musl] +rustflags = [ + "-L/opt/riscv-musl/lib/gcc/riscv64-linux-musl/11.2.1/", + "-L/opt/riscv-musl/riscv64-linux-musl/lib", + "-C", "target-feature=+crt-static" +] +linker = "riscv64-linux-musl-gcc" +``` + +编译命令也需要修改: + +``` +cargo build --release -Z build-std=core,std,panic_abort +``` + +在编写程序时,我们可以使用`#![no_main]` 关闭默认的`main` 函数。这可以减少一些不必要的系统调用,因为rust的默认实现会做一些保护措施,一上来就会调用奇怪的系统调用。 + + + ## 提示找不到运行时库的问题 -https://stackoverflow.com/questions/74424444/how-to-build-a-rust-program-for-riscv64gc-unknown-linux-musl \ No newline at end of file + +运行时库在工具链中存在,但需要我们手动指定,-L命令用于指定搜索路径。 + +在工具链中不存在unwind.o这个库,但是rust所需要的符号可以在libgcc.a 这个库中找到,因此按照[创建符号链接](https://github.com/rust-lang/rust/issues/120655)的方法,可以解决这个问题。 + + + +https://github.com/m00nwtchr/oc2_hello_world +https://stackoverflow.com/questions/74424444/how-to-build-a-rust-program-for-riscv64gc-unknown-linux-musl + +https://www.reddit.com/r/rust/comments/17nxdc3/help_trying_to_build_for_riscv64gcunknownlinuxmusl/ + +https://github.com/rust-lang/rust/issues/120655 给出了解决方案 + + + +## 缺少浮点数相关的函数的问题 + +在创建线程的程序中,编译时会产生一系列符号缺失错误,原因是在这个target下这些函数没有被实现。解决方法是静态链接 c 库实现。 + +``` +"-C", "link-arg=-lgcc" +``` + + + + + + + +https://www.cnblogs.com/fengyc/p/13665471.html \ No newline at end of file diff --git "a/docs/doc/\345\274\200\345\217\221\346\227\245\345\277\227.md" "b/docs/doc/\345\274\200\345\217\221\346\227\245\345\277\227.md" index 66c601e0..fdb02c25 100644 --- "a/docs/doc/\345\274\200\345\217\221\346\227\245\345\277\227.md" +++ "b/docs/doc/\345\274\200\345\217\221\346\227\245\345\277\227.md" @@ -631,7 +631,7 @@ bug修复记录:在调用read系统调用中,发现明明文件存在的但 可以看到,test.txt的结尾多出了几个字符,一开始怀疑是oepn的实现出错,但是看了一下代码,错误来源应该来自用户态,因为内核只会判断结尾是否有\0,再次检查用户态的cat实现,发现其在调用open实现时,没有按照系统调用规范,在字符串的结尾加上\0. -## 2023.2.16-记一次bug修复记录 +## 2024.2.16-记一次bug修复记录 这几天我们添加了对`initramfs`的支持,在内核启动阶段,我们会根据`initramfs`的内容创建好`/bin` `/sbin`目录,并创建里面的软链接和`busybox`, 我们将之前挂载在/bin目录的测试程序移动到tests目录,同时修改init程序的环境变量,使得bash可以正确查找到命令的位置,现在我们可以直接使用busybox的常见命令。 @@ -652,7 +652,7 @@ lmbench_all lat_proc -P 1 shell -## 2023.2.25 vf2的initrd支持 +## 2024.2.25 vf2的initrd支持 我们修改vf2的设备树文件节点`chosen`: @@ -682,3 +682,27 @@ initrd { }; ``` + + +## 2024.7.30 + +想要运行tokei或者smol等异步运行时,内核需要支持一些epoll相关的系统调用: + +- [x] `poll_createl` +- [x] `get_random` +- [x] `sigaltstack` : https://man7.org/linux/man-pages/man2/sigaltstack.2.html +- [x] `epoll_ctl`: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html +- [x] `epoll_pwait`: https://man7.org/linux/man-pages/man2/epoll_pwait.2.html +- [x] `eventfd2` +- [x] `prctl`: https://man7.org/linux/man-pages/man2/prctl.2.html +- [x] `timerfd_create`: https://man7.org/linux/man-pages/man2/timerfd_gettime.2.html + + + +`poll_createl` + +`timerfd_create` + +https://www.cnblogs.com/wenqiang/p/6698371.html + +https://blog.csdn.net/lihuan680680/article/details/120850344 diff --git a/kernel/build.rs b/kernel/build.rs index d656ed05..eb19857b 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -9,21 +9,22 @@ fn main() { let ld_path = Path::new("../tools/link.ld"); let ld = fs::read_to_string(ld_path).unwrap(); - #[cfg(not(feature = "vf2"))] - let base_addr = 0x80200000usize; - #[cfg(feature = "vf2")] - let base_addr: usize = 0x40200000; - let base_addr = format!("BASE_ADDRESS = {};", base_addr); - let mut new_config = String::new(); - for line in ld.lines() { - if line.starts_with("BASE_ADDRESS = ") { - new_config.push_str(base_addr.as_str()); - } else { - new_config.push_str(line); - new_config.push_str("\n"); + if cfg!(feature = "vf2") { + let base_addr: usize = 0x40200000; + let base_addr = format!("BASE_ADDRESS = {};", base_addr); + let mut new_config = String::new(); + for line in ld.lines() { + if line.starts_with("BASE_ADDRESS = ") { + new_config.push_str(base_addr.as_str()); + } else { + new_config.push_str(line); + new_config.push_str("\n"); + } } + script.write_all(new_config.as_bytes()).unwrap(); + } else { + script.write_all(ld.as_bytes()).unwrap(); } - script.write_all(new_config.as_bytes()).unwrap(); println!("cargo:rustc-link-arg=-T{}", &link_script.display()); } diff --git a/kernel/src/fs/basic.rs b/kernel/src/fs/basic.rs index 030c3422..bcc665b3 100644 --- a/kernel/src/fs/basic.rs +++ b/kernel/src/fs/basic.rs @@ -716,7 +716,7 @@ pub fn copy_file_range( #[syscall_func(19)] pub fn sys_eventfd2(init_val: u32, flags: u32) -> AlienResult { - let eventfd_file = eventfd(init_val, flags)?; + let eventfd_file = eventfd(init_val, flags).unwrap(); let task = current_task().unwrap(); let fd = task .add_file(eventfd_file) diff --git a/kernel/src/fs/control.rs b/kernel/src/fs/control.rs index e4a102cd..7632b804 100644 --- a/kernel/src/fs/control.rs +++ b/kernel/src/fs/control.rs @@ -1,10 +1,11 @@ use constants::{ io::{FaccessatFlags, FaccessatMode, Fcntl64Cmd, OpenFlags, TeletypeCommand}, + time::TimeSpec, AlienResult, LinuxErrno, AT_FDCWD, }; use log::{info, warn}; use syscall_table::syscall_func; -use timer::TimeSpec; +use timer::{TimeNow, ToVfsTimeSpec}; use vfscore::utils::*; use crate::{fs::user_path_at, task::current_task}; @@ -143,12 +144,12 @@ pub fn utimensat( TimeSpec::now() ); dt.inode()?.update_time( - VfsTime::AccessTime(TimeSpec::now().into()), - TimeSpec::now().into(), + VfsTime::AccessTime(TimeSpec::now().into_vfs()), + TimeSpec::now().into_vfs(), )?; dt.inode()?.update_time( - VfsTime::ModifiedTime(TimeSpec::now().into()), - TimeSpec::now().into(), + VfsTime::ModifiedTime(TimeSpec::now().into_vfs()), + TimeSpec::now().into_vfs(), )?; } else { let mut atime = TimeSpec::new(0, 0); @@ -163,25 +164,29 @@ pub fn utimensat( ); if atime.tv_nsec == UTIME_NOW { dt.inode()?.update_time( - VfsTime::AccessTime(TimeSpec::now().into()), - TimeSpec::now().into(), + VfsTime::AccessTime(TimeSpec::now().into_vfs()), + TimeSpec::now().into_vfs(), )?; } else if atime.tv_nsec == UTIME_OMIT { // do nothing } else { - dt.inode()? - .update_time(VfsTime::AccessTime(atime.into()), TimeSpec::now().into())?; + dt.inode()?.update_time( + VfsTime::AccessTime(atime.into_vfs()), + TimeSpec::now().into_vfs(), + )?; }; if mtime.tv_nsec == UTIME_NOW { dt.inode()?.update_time( - VfsTime::ModifiedTime(TimeSpec::now().into()), - TimeSpec::now().into(), + VfsTime::ModifiedTime(TimeSpec::now().into_vfs()), + TimeSpec::now().into_vfs(), )?; } else if mtime.tv_nsec == UTIME_OMIT { // do nothing } else { - dt.inode()? - .update_time(VfsTime::ModifiedTime(mtime.into()), TimeSpec::now().into())?; + dt.inode()?.update_time( + VfsTime::ModifiedTime(mtime.into_vfs()), + TimeSpec::now().into_vfs(), + )?; }; }; Ok(0) diff --git a/kernel/src/fs/poll.rs b/kernel/src/fs/poll.rs index 77c7ee7e..1b92bf14 100644 --- a/kernel/src/fs/poll.rs +++ b/kernel/src/fs/poll.rs @@ -1,12 +1,15 @@ -use alloc::vec::Vec; +use alloc::{sync::Arc, vec::Vec}; use constants::{ - io::{PollEvents, PollFd}, + epoll::{EpollCtlOp, EpollEvent}, + io::{OpenFlags, PollEvents, PollFd}, + time::TimeSpec, AlienResult, LinuxErrno, }; use log::{info, warn}; use syscall_table::syscall_func; -use timer::TimeSpec; +use timer::{get_time_ms, TimeNow, ToClock}; +use vfs::epoll::EpollFile; use crate::task::{current_task, do_suspend}; @@ -65,7 +68,7 @@ pub fn ppoll(fds_ptr: usize, nfds: usize, time: usize, _mask: usize) -> AlienRes pfd.revents = event; } else { // todo: error - pfd.events = PollEvents::INVAL; + pfd.events = PollEvents::EPOLLERR; } } @@ -95,3 +98,97 @@ pub fn ppoll(fds_ptr: usize, nfds: usize, time: usize, _mask: usize) -> AlienRes } } } + +#[syscall_func(20)] +/// See https://man7.org/linux/man-pages/man2/epoll_create1.2.html +pub fn poll_createl(flags: usize) -> AlienResult { + let flags = OpenFlags::from_bits_truncate(flags); + // println_color!(32, "poll_createl: flags: {:?}", flags); + let epoll_file = Arc::new(EpollFile::new(flags)); + let task = current_task().unwrap(); + let fd = task.add_file(epoll_file).map_err(|_| LinuxErrno::EMFILE)?; + Ok(fd as isize) +} + +#[syscall_func(21)] +/// See https://man7.org/linux/man-pages/man2/epoll_ctl.2.html +pub fn epoll_ctl(epfd: usize, op: u32, fd: usize, event_ptr: usize) -> AlienResult { + let op = EpollCtlOp::try_from(op).unwrap(); + let task = current_task().unwrap(); + let mut event = EpollEvent::default(); + task.access_inner() + .copy_from_user(event_ptr as _, &mut event); + // println_color!( + // 32, + // "epoll_ctl: epfd: {}, op: {:?}, fd: {}, event: {:?}", + // epfd, + // op, + // fd, + // event + // ); + let epoll_file = task.get_file(epfd).ok_or(LinuxErrno::EBADF)?; + let epoll_file = epoll_file + .downcast_arc::() + .map_err(|_| LinuxErrno::EINVAL)?; + epoll_file.ctl(op, fd, event)?; + Ok(0) +} + +#[syscall_func(22)] +/// See https://man7.org/linux/man-pages/man2/epoll_pwait.2.html +pub fn epoll_pwait( + epfd: usize, + events_ptr: usize, + maxevents: usize, + timeout_ms: usize, + _sigmask: usize, +) -> AlienResult { + // println_color!( + // 32, + // "epoll_pwait: epfd: {}, maxevents: {}, timeout: {:#x}", + // epfd, + // maxevents, + // timeout_ms + // ); + let now_ms = get_time_ms() as usize; + let res = loop { + let task = current_task().unwrap(); + let epoll_file = task.get_file(epfd).ok_or(LinuxErrno::EBADF)?; + let epoll_file = epoll_file + .downcast_arc::() + .map_err(|_| LinuxErrno::EINVAL)?; + + let interset = epoll_file.interest(); + let mut res = Vec::with_capacity(interset.len()); + for (fd, event) in interset.iter() { + let file = task.get_file(*fd); + if let Some(file) = file { + let event_res = file.poll(event.events).unwrap(); + if !event_res.is_empty() { + res.push(EpollEvent { + events: event_res, + data: event.data, + }); + } + } + } + if !res.is_empty() { + break res; + } + let now = get_time_ms() as usize; + if now - now_ms >= timeout_ms { + break Vec::new(); + } + }; + if res.len() > maxevents { + panic!("epoll_pwait: res.len() > maxevents"); + } + // println_color!(32, "epoll_pwait: res: {:?}", res); + if res.is_empty() { + return Ok(0); + } + let task = current_task().unwrap(); + task.access_inner() + .copy_to_user_buffer(res.as_ptr(), events_ptr as *mut EpollEvent, res.len()); + Ok(res.len() as isize) +} diff --git a/kernel/src/fs/select.rs b/kernel/src/fs/select.rs index 78a1acdf..7f437d21 100644 --- a/kernel/src/fs/select.rs +++ b/kernel/src/fs/select.rs @@ -6,11 +6,12 @@ use config::MAX_FD_NUM; use constants::{ io::PollEvents, signal::{SignalNumber, SimpleBitSet}, + time::TimeSpec, AlienResult, LinuxErrno, }; use log::{info, trace}; use syscall_table::syscall_func; -use timer::TimeSpec; +use timer::{TimeNow, ToClock}; use crate::task::{current_task, do_suspend}; @@ -120,8 +121,8 @@ pub fn pselect6( for i in 0..nfds { if ori_readfds.get_bit(i) { if let Some(fd) = task.get_file(i) { - let event = fd.poll(PollEvents::IN).expect("poll error"); - if event.contains(PollEvents::IN) { + let event = fd.poll(PollEvents::EPOLLIN).expect("poll error"); + if event.contains(PollEvents::EPOLLIN) { info!("pselect6: fd {} ready to read", i); readfds.set_bit(i, true); set += 1; @@ -145,8 +146,8 @@ pub fn pselect6( for i in 0..nfds { if ori_writefds.get_bit(i) { if let Some(fd) = task.get_file(i) { - let event = fd.poll(PollEvents::OUT).expect("poll error"); - if event.contains(PollEvents::OUT) { + let event = fd.poll(PollEvents::EPOLLOUT).expect("poll error"); + if event.contains(PollEvents::EPOLLOUT) { info!("pselect6: fd {} ready to write", i); writefds.set_bit(i, true); set += 1; @@ -170,8 +171,8 @@ pub fn pselect6( for i in 0..nfds { if ori_exceptfds.get_bit(i) { if let Some(fd) = task.get_file(i) { - let event = fd.poll(PollEvents::ERR).expect("poll error"); - if event.contains(PollEvents::ERR) { + let event = fd.poll(PollEvents::EPOLLERR).expect("poll error"); + if event.contains(PollEvents::EPOLLERR) { info!("pselect6: fd {} in exceptional conditions", i); exceptfds.set_bit(i, true); set += 1; diff --git a/kernel/src/ipc/mod.rs b/kernel/src/ipc/mod.rs index f9189ba2..b3650e48 100644 --- a/kernel/src/ipc/mod.rs +++ b/kernel/src/ipc/mod.rs @@ -10,6 +10,7 @@ use core::sync::atomic::{AtomicI32, Ordering}; use constants::{ ipc::{FutexOp, RobustList}, + time::TimeSpec, AlienResult, LinuxErrno, }; use ksync::Mutex; @@ -17,7 +18,7 @@ pub use pipe::*; pub use shm::*; pub use signal::*; use spin::Lazy; -use timer::TimeSpec; +use timer::{TimeNow, ToClock}; use crate::{ fs::basic::sys_close, diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 97dc4ac8..801dd51d 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -138,8 +138,8 @@ impl File for PipeFile { fn poll(&self, _event: PollEvents) -> AlienResult { let inode = self.dentry.inode()?; let res = inode - .poll(VfsPollEvents::from_bits_truncate(_event.bits())) - .map(|e| PollEvents::from_bits_truncate(e.bits())); + .poll(VfsPollEvents::from_bits_truncate(_event.bits() as u16)) + .map(|e| PollEvents::from_bits_truncate(e.bits() as u32)); res.map_err(Into::into) } } diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 8bd82444..0e167857 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -5,16 +5,10 @@ use alloc::{collections::BTreeMap, sync::Arc, vec::Vec}; use core::mem::size_of; -use constants::{ - signal::{ - SigAction, SigActionDefault, SigActionFlags, SigInfo, SigProcMaskHow, SignalNumber, - SignalReceivers, SignalUserContext, SimpleBitSet, - }, - LinuxErrno, -}; +use constants::{signal::*, time::TimeSpec, AlienResult, LinuxErrno}; use ksync::Mutex; use syscall_table::syscall_func; -use timer::{read_timer, TimeSpec}; +use timer::{read_timer, ToClock}; use crate::task::{current_task, do_exit, do_suspend}; @@ -80,12 +74,13 @@ pub fn sigaction(sig: usize, action: usize, old_action: usize) -> isize { if !old_action.is_null() { let mut tmp = SigAction::empty(); signal_handler.get_action(sig, &mut tmp); + warn!("get sig {:?} old action is {:?}", signum, tmp); task_inner.copy_to_user(&tmp, old_action); } if !action.is_null() { let mut tmp_action = SigAction::empty(); task_inner.copy_from_user(action, &mut tmp_action); - warn!("sig {:?} action is {:?}", signum, tmp_action); + warn!("set sig {:?} action is {:?}", signum, tmp_action); signal_handler.set_action(sig, &tmp_action); } 0 @@ -310,7 +305,7 @@ pub fn signal_handler() { drop(handler); drop(receiver); warn!("task {:?} exit by signal {:?}", task.tid, sig); - do_exit(-1); + do_exit(-1, 0); } _ => { if let Some(action) = handler.get_action_ref(signum) { @@ -385,7 +380,7 @@ pub fn signal_handler() { drop(task_inner); drop(handler); drop(receiver); - do_exit(-1); + do_exit(-1, 0); } SigActionDefault::Ignore => { // 忽略信号时,要将已保存的上下文删除 @@ -412,3 +407,23 @@ pub fn sigsuspend() -> isize { } } } + +#[syscall_func(132)] +/// See https://man7.org/linux/man-pages/man2/sigaltstack.2.html +pub fn sigaltstack(uss: usize, uoss: usize) -> AlienResult { + //println_color!(32, "sigaltstack: uss: {:x}, uoss: {:x}", uss, uoss); + let task = current_task().unwrap(); + if uoss != 0 { + let old_ss_stack = task.access_inner().ss_stack; + // println_color!(32, "get old sigaltstack: {:x?}", old_ss_stack); + task.access_inner() + .copy_to_user(&old_ss_stack, uoss as *mut SignalStack); + } + if uss != 0 { + let mut ss_stack = SignalStack::default(); + task.access_inner().copy_from_user(uss as _, &mut ss_stack); + // println_color!(32, "set sigaltstack: {:x?}", ss_stack); + task.access_inner().ss_stack = ss_stack; + } + Ok(0) +} diff --git a/kernel/src/net/mod.rs b/kernel/src/net/mod.rs index 2e3cb08c..0a0dba4e 100644 --- a/kernel/src/net/mod.rs +++ b/kernel/src/net/mod.rs @@ -452,15 +452,35 @@ pub fn shutdown(socketfd: usize, how: usize) -> AlienResult<()> { /// /// 如果创建成功则返回0,否则返回错误信息。 #[syscall_func(199)] -pub fn socket_pair(domain: usize, c_type: usize, proto: usize, sv: usize) -> AlienResult { +pub fn socket_pair(domain: usize, s_type: usize, protocol: usize, sv: usize) -> AlienResult { let domain = Domain::try_from(domain).map_err(|_| LinuxErrno::EINVAL)?; - let c_type = SocketType::try_from(c_type).map_err(|_| LinuxErrno::EINVAL)?; - info!( - "socketpair: {:?}, {:?}, {:?}, {:?}", - domain, c_type, proto, sv - ); - // panic!("socketpair"); - Err(LinuxErrno::EAFNOSUPPORT.into()) + let socket_type = SocketType::try_from(s_type).map_err(|_| LinuxErrno::EINVAL)?; + if domain != Domain::AF_UNIX { + return Err(LinuxErrno::EAFNOSUPPORT); + } + // println_color!(32, + // "socketpair: {:?}, {:?}, {:?}, {:?}", + // domain, s_type, protocol, sv + // ); + let file1 = SocketData::new(domain, socket_type, protocol)?; + let file2 = file1.clone(); + info!("socket domain: {:?}, type: {:?}", domain, socket_type); + if s_type & SocketType::SOCK_NONBLOCK as usize != 0 { + let socket = file1.get_socketdata()?; + file1.set_open_flag(file1.get_open_flag() | OpenFlags::O_NONBLOCK); + socket.set_socket_nonblock(true); + info!("socket with nonblock"); + } + if s_type & SocketType::SOCK_CLOEXEC as usize != 0 { + file1.set_close_on_exec(); + info!("socket with cloexec"); + } + let task = current_task().unwrap(); + let fd1 = task.add_file(file1).map_err(|_| LinuxErrno::EMFILE)?; + let fd2 = task.add_file(file2).map_err(|_| LinuxErrno::EMFILE)?; + task.access_inner() + .copy_to_user_buffer([fd1 as u32, fd2 as u32].as_ptr(), sv as _, 2); + Ok(0) } /// 通过socket文件描述符fd获取对应的文件 diff --git a/kernel/src/system.rs b/kernel/src/system.rs index 2b3dabc5..ccb400a4 100644 --- a/kernel/src/system.rs +++ b/kernel/src/system.rs @@ -1,4 +1,6 @@ //! uname系统调用实现 + +use alloc::vec; use core::cmp::min; use constants::{ @@ -218,9 +220,26 @@ pub fn getrusage(who: isize, usage: usize) -> AlienResult { Ok(0) } +#[syscall_func(278)] +pub fn get_random(buf: *mut u8, len: usize, flags: u32) -> AlienResult { + info!( + "get_random: buf: {:x?}, len: {}, flags: {}", + buf, len, flags + ); + let task = current_task().unwrap(); + let mut rand_buf = vec![0; len]; + for v in rand_buf.iter_mut() { + let time_ms = get_time_ms(); + *v = (time_ms & 0xff) as u8; + } + task.access_inner() + .copy_to_user_buffer(rand_buf.as_ptr(), buf, len); + Ok(len as isize) +} + /// 一个系统调用,通过调用 SBI_SHUTDOWN 来关闭操作系统(直接退出 QEMU) #[syscall_func(2003)] pub fn system_shutdown() -> AlienResult { println!("shutdown..."); - platform::system_shutdown(); + platform::system_shutdown() } diff --git a/kernel/src/task/control.rs b/kernel/src/task/control.rs new file mode 100644 index 00000000..13964f36 --- /dev/null +++ b/kernel/src/task/control.rs @@ -0,0 +1,19 @@ +use constants::{sys::PrctlOp, AlienResult}; + +use crate::task::current_task; + +#[syscall_func(167)] +pub fn prctl(op: u32, _arg2: u64, _arg3: u64, _arg4: u64, _arg5: u64) -> AlienResult { + let op = PrctlOp::try_from(op).unwrap(); + match op { + PrctlOp::PR_SET_NAME => { + let name_ptr = _arg2 as *const u8; + let task = current_task().unwrap(); + let str = task.transfer_str(name_ptr); + // println_color!(32, "prctl: set task name: {}", str); + task.access_inner().set_name(str); + Ok(0) + } + op => panic!("prctl: op {:?} not implemented", op), + } +} diff --git a/kernel/src/task/cpu.rs b/kernel/src/task/cpu.rs index 017d887c..313a1b97 100644 --- a/kernel/src/task/cpu.rs +++ b/kernel/src/task/cpu.rs @@ -124,7 +124,7 @@ pub fn current_trap_frame() -> &'static mut TrapFrame { /// /// 当调用该函数的进程为`pid==0`的init进程时,将直接调用`system_shutdown`使得内核终止。 #[syscall_func(93)] -pub fn do_exit(exit_code: i32) -> isize { +pub fn do_exit(exit_code: i32, exit_group: u8) -> isize { let task = current_task().unwrap(); let exit_code = (exit_code & 0xff) << 8; if task.get_pid() == 1 { @@ -134,6 +134,9 @@ pub fn do_exit(exit_code: i32) -> isize { { let init = INIT_PROCESS.clone(); task.take_children().into_iter().for_each(|child| { + if exit_group != 0 { + child.set_exit_group(); + } child.update_parent(init.clone()); init.insert_child(child); }); @@ -163,7 +166,14 @@ pub fn do_exit(exit_code: i32) -> isize { /// 目前该系统调用直接调用[`do_exit`],有关进程组的相关功能有待实现。 #[syscall_func(94)] pub fn exit_group(exit_code: i32) -> isize { - do_exit(exit_code) + do_exit(exit_code, 1) +} + +pub fn check_exit_group() { + let task = current_task().unwrap(); + if task.access_inner().exit_group { + do_exit(0, 1); + } } /// 一个系统调用,用于使当前正在运行的进程让渡CPU。 diff --git a/kernel/src/task/kthread.rs b/kernel/src/task/kthread.rs index 9dee1c5c..e156a1c0 100644 --- a/kernel/src/task/kthread.rs +++ b/kernel/src/task/kthread.rs @@ -4,8 +4,8 @@ use bit_field::BitField; use config::{CPU_NUM, FRAME_SIZE, MAX_FD_NUM, MAX_THREAD_NUM, USER_KERNEL_STACK_SIZE}; use constants::{ ipc::RobustList, - signal::{SignalHandlers, SignalReceivers}, - AlienError, AlienResult, + signal::{SignalStack, *}, + *, }; use gmanager::MinimalManager; use ksync::Mutex; @@ -78,6 +78,12 @@ pub fn ktread_create(func: fn(), name: &str) -> AlienResult<()> { // user mode stack info stack: 0..0, need_wait: 0, + ss_stack: SignalStack { + ss_sp: 0, + ss_flags: 0x2, + ss_size: 0, + }, + exit_group: false, }), send_sigchld_when_exit: false, }; diff --git a/kernel/src/task/mod.rs b/kernel/src/task/mod.rs index 10168ec6..11c034ac 100644 --- a/kernel/src/task/mod.rs +++ b/kernel/src/task/mod.rs @@ -19,6 +19,7 @@ pub use crate::task::task::FsContext; use crate::{fs::read_all, task::schedule::schedule_now}; mod context; +mod control; mod cpu; mod kthread; mod resource; diff --git a/kernel/src/task/task.rs b/kernel/src/task/task.rs index 861a787d..e2f966ef 100644 --- a/kernel/src/task/task.rs +++ b/kernel/src/task/task.rs @@ -18,15 +18,7 @@ use core::{ use bit_field::BitField; use config::*; -use constants::{ - aux::*, - io::MMapFlags, - ipc::RobustList, - signal::{SignalHandlers, SignalNumber, SignalReceivers, SignalUserContext}, - task::CloneFlags, - time::{TimeVal, TimerType}, - AlienError, AlienResult, LinuxErrno, PrLimitResType, RLimit64, -}; +use constants::{aux::*, io::MMapFlags, ipc::RobustList, signal::*, task::CloneFlags, time::*, *}; use gmanager::MinimalManager; use ksync::{Mutex, MutexGuard}; use mem::{kernel_satp, VmmPageAllocator, FRAME_REF_MANAGER}; @@ -35,7 +27,7 @@ use page_table::{ pte::MappingFlags, table::Sv39PageTable, }; -use timer::{read_timer, ITimerVal, TimeNow, ToClock}; +use timer::{read_timer, TimeNow, ToClock}; use vfs::kfile::File; use vfscore::dentry::VfsDentry; @@ -136,6 +128,13 @@ pub struct TaskInner { pub stack: Range, /// 是否需要等待 pub need_wait: u8, + /// 用于异常处理的栈信息 + /// + /// - SS_ONSTACK = 1 + /// - SS_DISABLE = 2 + pub ss_stack: SignalStack, + + pub exit_group: bool, } #[derive(Debug, Copy, Clone)] @@ -264,6 +263,10 @@ pub enum TaskState { } impl Task { + pub fn set_exit_group(&self) { + self.access_inner().exit_group = true; + } + /// 终止进程,回收内核栈等资源,同时将该任务的状态修改为 `Terminated` pub fn terminate(self: Arc) { // recycle kernel stack @@ -540,6 +543,10 @@ impl TaskInner { self.fs_info.clone() } + pub fn set_name(&mut self, name: String) { + self.name = name; + } + /// 获取进程的计时器 pub fn get_timer(&self) -> TaskTimer { self.timer.clone() @@ -1431,6 +1438,12 @@ impl Task { unmask: 0o022, stack: stack_info, need_wait: 0, + ss_stack: SignalStack { + ss_sp: 0, + ss_flags: 0x2, + ss_size: 0, + }, + exit_group: false, }), send_sigchld_when_exit: false, }; @@ -1629,6 +1642,12 @@ impl Task { unmask: 0o022, stack: inner.stack.clone(), need_wait: 0, + ss_stack: SignalStack { + ss_sp: 0, + ss_flags: 0x2, + ss_size: 0, + }, + exit_group: false, }), send_sigchld_when_exit: sig == SignalNumber::SIGCHLD, }; diff --git a/kernel/src/time.rs b/kernel/src/time.rs index 2f000481..e18b2da5 100644 --- a/kernel/src/time.rs +++ b/kernel/src/time.rs @@ -10,14 +10,19 @@ //! 在任务控制块中记录相应数据的字段为 `timer`(结构为 `TaskTimer` )。 //! //! 对于时间片 (每次引发时钟中断的时间间隔) 大小的设计:目前 Alien 中用户态和内核态下采用相同的时间片间隔,1s 内触发 10 次时钟中断。 + +use alloc::sync::Arc; + use constants::{ - time::{ClockId, TimeVal, TimerType}, - FromUsize, LinuxErrno, + io::OpenFlags, + time::{ClockId, ITimeSpec, ITimerVal, TimeSpec, TimeVal, TimerFdFlags, TimerType}, + AlienResult, FromUsize, LinuxErrno, }; use log::{info, warn}; use platform::{config::CLOCK_FREQ, set_timer}; use syscall_table::syscall_func; -use timer::{read_timer, ITimerVal, TimeNow, TimeSpec, Times}; +use timer::{read_timer, TimeNow, Times, ToClock}; +use vfs::timerfd::TimerFile; use crate::task::{current_task, do_suspend, StatisticalData}; @@ -258,3 +263,80 @@ pub fn clock_nanosleep(clock_id: usize, flags: usize, req: usize, remain: usize) } 0 } + +#[syscall_func(85)] +/// See https://man7.org/linux/man-pages/man2/timerfd_create.2.html +/// +/// See https://blog.csdn.net/lihuan680680/article/details/120850344 +pub fn timerfd_create(clock_id: usize, flags: u32) -> AlienResult { + let id = ClockId::try_from(clock_id).unwrap(); + let flags = OpenFlags::from_bits_truncate(flags as usize); + let task = current_task().unwrap(); + // println_color!(32, "timerfd_create: Id: {:?} ,flags: {:?}", id, flags); + let timer_file = TimerFile::new(flags, ITimeSpec::default(), id); + let fd = task + .add_file(Arc::new(timer_file)) + .map_err(|_| LinuxErrno::EMFILE)?; + Ok(fd as isize) +} + +#[syscall_func(87)] +pub fn timerfd_gettime(fd: usize, current_val: usize) -> AlienResult { + // println_color!( + // 32, + // "timerfd_gettime: fd {:?} ,current_val {:#x}", + // fd, + // current_val + // ); + let task = current_task().unwrap(); + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let timer_file = file + .as_any() + .downcast_ref::() + .ok_or(LinuxErrno::EINVAL)?; + let itimer = ITimeSpec { + it_interval: timer_file.get_interval(), + it_value: timer_file.get_it_value(), + }; + task.access_inner() + .copy_to_user(&itimer, current_val as *mut ITimeSpec); + Ok(0) +} + +#[syscall_func(86)] +pub fn timerfd_settime( + fd: usize, + flags: u32, + new_value: usize, + old_value: usize, +) -> AlienResult { + let _flags = TimerFdFlags::from_bits_truncate(flags); + let task = current_task().unwrap(); + let mut itimer = ITimeSpec::default(); + task.access_inner() + .copy_from_user(new_value as *const ITimeSpec, &mut itimer); + // println_color!( + // 32, + // "timerfd_settime: fd {:?} ,flags {:?}, new_value {:#x}, old_value {:#x}", + // fd, + // flags, + // new_value, + // old_value + // ); + // println_color!(32, "timerfd_settime: new_timer: {:#x?}", itimer); + let file = task.get_file(fd).ok_or(LinuxErrno::EBADF)?; + let timer_file = file + .downcast_arc::() + .map_err(|_| LinuxErrno::EINVAL)?; + + if old_value != 0 { + let old_timer = ITimeSpec { + it_interval: timer_file.get_interval(), + it_value: timer_file.get_it_value(), + }; + task.access_inner() + .copy_to_user(&old_timer, old_value as *mut ITimeSpec); + } + timer_file.set_timer(itimer); + Ok(0) +} diff --git a/kernel/src/trap/exception.rs b/kernel/src/trap/exception.rs index 70dd57ae..14258be5 100644 --- a/kernel/src/trap/exception.rs +++ b/kernel/src/trap/exception.rs @@ -21,6 +21,8 @@ pub fn syscall_exception_handler() { cx.update_sepc(); // get system call return value let parameters = cx.parameters(); + + // See https://gpages.juszkiewicz.com.pl/syscalls-table/syscalls.html let syscall_name = constants::syscall_name(parameters[0]); let task = current_task().unwrap(); diff --git a/kernel/src/trap/mod.rs b/kernel/src/trap/mod.rs index 8e9b9d7c..9ba1a0ff 100644 --- a/kernel/src/trap/mod.rs +++ b/kernel/src/trap/mod.rs @@ -143,7 +143,7 @@ impl TrapHandler for Trap { // println!("thread need wait"); do_suspend(); } else if err == AlienError::EPERM { - do_exit(-1); + do_exit(-1, 0); } else { send_signal(tid as usize, SignalNumber::SIGSEGV as usize) } @@ -256,6 +256,7 @@ pub fn user_trap_vector() { } task.access_inner().update_timer(); check_task_timer_expired(); + crate::task::check_exit_group(); trap_return(); } diff --git a/subsystems/drivers/src/net.rs b/subsystems/drivers/src/net.rs index 8f7f924e..866123f1 100644 --- a/subsystems/drivers/src/net.rs +++ b/subsystems/drivers/src/net.rs @@ -1,8 +1,9 @@ use core::ptr::NonNull; +use constants::time::TimeSpec; pub use loopback::LoopbackDev; use netcore::{KernelNetFunc, NetInstant}; -use timer::TimeSpec; +use timer::TimeNow; use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader}; use virtio_net::VirtIONetDeviceWrapper; diff --git a/subsystems/knet/src/socket.rs b/subsystems/knet/src/socket.rs index 06964391..b641272a 100644 --- a/subsystems/knet/src/socket.rs +++ b/subsystems/knet/src/socket.rs @@ -131,14 +131,14 @@ impl File for SocketFile { let mut res = PollEvents::empty(); netcore::poll_interfaces(); let socket = self.get_socketdata().unwrap(); - if _event.contains(PollEvents::IN) { + if _event.contains(PollEvents::EPOLLIN) { if socket.ready_read() { - res |= PollEvents::IN; + res |= PollEvents::EPOLLIN; } } - if _event.contains(PollEvents::OUT) { + if _event.contains(PollEvents::EPOLLOUT) { if socket.ready_write() { - res |= PollEvents::OUT; + res |= PollEvents::EPOLLOUT; } } Ok(res) @@ -247,6 +247,7 @@ impl SocketData { Socket::Udp(udp) => { udp.set_nonblocking(blocking); } + Socket::Unix(_) => {} _ => { panic!("set_socket_nonblock is not supported") } diff --git a/subsystems/platform/src/console.rs b/subsystems/platform/src/console.rs index 7bbfc48f..9a8a379d 100644 --- a/subsystems/platform/src/console.rs +++ b/subsystems/platform/src/console.rs @@ -20,6 +20,33 @@ macro_rules! println { concat!($fmt, "\n"), $($arg)*)); } +/// Print with color +/// +/// The first argument is the color, which should be one of the following: +/// - 30: Black +/// - 31: Red +/// - 32: Green +/// - 33: Yellow +/// - 34: Blue +/// - 35: Magenta +/// - 36: Cyan +/// - 37: White +/// +/// # Examples +/// ```rust +/// use platform::println_color; +/// println_color!(31, "This is red"); +/// ``` +#[macro_export] +macro_rules! println_color { + ($color:expr, $fmt:expr) => { + $crate::print!(concat!("\x1b[", $color, "m", $fmt, "\x1b[0m\n")); + }; + ($color:expr, $fmt:expr, $($arg:tt)*) => { + $crate::print!(concat!("\x1b[", $color, "m", $fmt, "\x1b[0m\n"), $($arg)*); + }; +} + pub struct Stdout; /// 对`Stdout`实现输出的Trait diff --git a/subsystems/timer/src/lib.rs b/subsystems/timer/src/lib.rs index 492cfd11..f69a8d61 100644 --- a/subsystems/timer/src/lib.rs +++ b/subsystems/timer/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use constants::time::TimeVal; +use constants::time::{TimeSpec, TimeVal}; use platform::config::CLOCK_FREQ; use vfscore::utils::VfsTimeSpec; /// 每秒包含的毫秒数 @@ -69,52 +69,48 @@ impl TimeFromFreq for TimeVal { } } -/// 更精细的时间,秒(s)+纳秒(ns) -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct TimeSpec { - pub tv_sec: usize, - pub tv_nsec: usize, //0~999999999 -} +// /// 更精细的时间,秒(s)+纳秒(ns) +// #[repr(C)] +// #[derive(Copy, Clone, Debug, PartialEq, Eq)] +// pub struct TimeSpec { +// pub tv_sec: usize, +// pub tv_nsec: usize, //0~999999999 +// } +// -impl TimeSpec { - /// 创建一个新的 [`TimeSpec`] 时钟 - pub fn new(sec: usize, ns: usize) -> Self { +impl TimeNow for TimeSpec { + fn now() -> Self { + let time = read_timer(); Self { - tv_sec: sec, - tv_nsec: ns, + tv_sec: time / CLOCK_FREQ, + tv_nsec: (time % CLOCK_FREQ) * 1000_000_000 / CLOCK_FREQ, } } +} - /// 获取一个可以表示当前 cpu 时间的一个 [`TimeSpec`] 时钟 - pub fn now() -> Self { - let time = arch::read_timer(); +impl TimeFromFreq for TimeSpec { + fn from_freq(freq: usize) -> Self { Self { - tv_sec: time / CLOCK_FREQ, - tv_nsec: (time % CLOCK_FREQ) * 1000_000_000 / CLOCK_FREQ, + tv_sec: freq / CLOCK_FREQ, + tv_nsec: (freq % CLOCK_FREQ) * 1000_000_000 / CLOCK_FREQ, } } +} - /// 将本时钟所表示的时间间隔转化为 cpu 上时钟的跳变数 - pub fn to_clock(&self) -> usize { +impl ToClock for TimeSpec { + fn to_clock(&self) -> usize { self.tv_sec * CLOCK_FREQ + self.tv_nsec * CLOCK_FREQ / 1000_000_000 } } -impl Into for TimeSpec { - fn into(self) -> VfsTimeSpec { - VfsTimeSpec::new(self.tv_sec as u64, self.tv_nsec as u64) - } +pub trait ToVfsTimeSpec { + fn into_vfs(self) -> VfsTimeSpec; } -/// [`getitimer`] / [`setitimer`] 指定的类型,用户执行系统调用时获取和输入的计时器 -#[repr(C)] -#[derive(Debug, Copy, Clone, Default)] -pub struct ITimerVal { - /// 计时器超时间隔 - pub it_interval: TimeVal, - /// 计时器当前所剩时间 - pub it_value: TimeVal, +impl ToVfsTimeSpec for TimeSpec { + fn into_vfs(self) -> VfsTimeSpec { + VfsTimeSpec::new(self.tv_sec as u64, self.tv_nsec as u64) + } } /// 获取当前计时器的值 diff --git a/subsystems/vfs/Cargo.toml b/subsystems/vfs/Cargo.toml index e90e4634..5ec966ea 100644 --- a/subsystems/vfs/Cargo.toml +++ b/subsystems/vfs/Cargo.toml @@ -15,6 +15,7 @@ interrupt = { path = "../interrupt" } platform = { path = "../platform" } mem = { path = "../mem" } shim = { path = "../shim" } +timer = { path = "../timer" } bitflags = "1.3" downcast-rs = { version = "1.2.0", default-features = false } diff --git a/subsystems/vfs/src/epoll.rs b/subsystems/vfs/src/epoll.rs new file mode 100644 index 00000000..8d9dfa0c --- /dev/null +++ b/subsystems/vfs/src/epoll.rs @@ -0,0 +1,84 @@ +use alloc::{collections::BTreeMap, sync::Arc}; + +use constants::{ + epoll::{EpollCtlOp, EpollEvent}, + io::{OpenFlags, SeekFrom}, + AlienError, AlienResult, +}; +use ksync::{Mutex, MutexGuard}; +use vfscore::{dentry::VfsDentry, inode::VfsInode, utils::VfsFileStat}; + +use crate::kfile::File; + +#[derive(Debug)] +pub struct EpollFile { + #[allow(unused)] + flags: OpenFlags, + interest: Mutex>, +} + +impl EpollFile { + pub fn new(flags: OpenFlags) -> Self { + EpollFile { + flags, + interest: Mutex::new(BTreeMap::new()), + } + } + pub fn ctl(&self, op: EpollCtlOp, fd: usize, events: EpollEvent) -> AlienResult<()> { + match op { + EpollCtlOp::EpollCtlAdd => { + self.interest.lock().insert(fd, events); + Ok(()) + } + EpollCtlOp::EpollCtlDel => { + self.interest.lock().remove(&fd); + Ok(()) + } + EpollCtlOp::EpollCtlMod => { + self.interest.lock().insert(fd, events); + Ok(()) + } + } + } + pub fn interest(&self) -> MutexGuard> { + self.interest.lock() + } +} + +impl File for EpollFile { + fn read(&self, _buf: &mut [u8]) -> AlienResult { + todo!() + } + + fn write(&self, _buf: &[u8]) -> AlienResult { + todo!() + } + + fn seek(&self, _pos: SeekFrom) -> AlienResult { + Err(AlienError::ENOSYS) + } + + fn get_attr(&self) -> AlienResult { + todo!() + } + + fn dentry(&self) -> Arc { + panic!("EpollFile does not have dentry") + } + + fn inode(&self) -> Arc { + panic!("EpollFile does not have inode") + } + + fn is_readable(&self) -> bool { + true + } + + fn is_writable(&self) -> bool { + true + } + + fn is_append(&self) -> bool { + true + } +} diff --git a/subsystems/vfs/src/eventfd.rs b/subsystems/vfs/src/eventfd.rs index f38f90d5..1f75a702 100644 --- a/subsystems/vfs/src/eventfd.rs +++ b/subsystems/vfs/src/eventfd.rs @@ -1,8 +1,11 @@ use alloc::{collections::VecDeque, sync::Arc}; use core::{fmt::Debug, sync::atomic::AtomicU32}; -use bitflags::bitflags; -use constants::{io::SeekFrom, AlienError, AlienResult}; +use constants::{ + epoll::EventFdFlags, + io::{PollEvents, SeekFrom}, + AlienError, AlienResult, +}; use ksync::Mutex; use shim::KTask; use vfscore::{dentry::VfsDentry, inode::VfsInode, utils::VfsFileStat}; @@ -11,14 +14,6 @@ use crate::kfile::File; static EVENTFD_ID: AtomicU32 = AtomicU32::new(0); -bitflags! { - pub struct EventFdFlags: u32{ - const EFD_SEMAPHORE = 1; - const EFD_CLOEXEC = 2; - const EFD_NONBLOCK = 4; - } -} - #[derive(Debug)] pub struct EventFd { count: u64, @@ -157,10 +152,22 @@ impl File for EventFdInode { fn is_append(&self) -> bool { true } + + fn poll(&self, event: PollEvents) -> AlienResult { + let mut events = PollEvents::empty(); + if self.eventfd.lock().count != 0 && event.contains(PollEvents::EPOLLIN) { + events |= PollEvents::EPOLLIN; + } + if self.eventfd.lock().count != u64::MAX && event.contains(PollEvents::EPOLLOUT) { + events |= PollEvents::EPOLLOUT + } + return Ok(events); + } } pub fn eventfd(init_val: u32, flags: u32) -> AlienResult> { - let flags = EventFdFlags::from_bits(flags).ok_or(AlienError::EINVAL)?; + let flags = EventFdFlags::from_bits_truncate(flags); + // println_color!(32, "eventfd: init_val: {}, flags: {:?}", init_val, flags); let id = EVENTFD_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed); let eventfd = EventFd::new(init_val as u64, flags, id); let inode = Arc::new(EventFdInode::new(eventfd)); diff --git a/subsystems/vfs/src/kfile.rs b/subsystems/vfs/src/kfile.rs index ba9a2ca5..ac970abe 100644 --- a/subsystems/vfs/src/kfile.rs +++ b/subsystems/vfs/src/kfile.rs @@ -85,7 +85,7 @@ pub trait File: DowncastSync + Debug { fn is_writable(&self) -> bool; fn is_append(&self) -> bool; fn poll(&self, _event: PollEvents) -> AlienResult { - Err(LinuxErrno::ENOSYS) + panic!("poll is not implemented for :{:?}", self) } } @@ -260,8 +260,8 @@ impl File for KernelFile { fn poll(&self, _event: PollEvents) -> AlienResult { let inode = self.dentry.inode()?; let res = inode - .poll(VfsPollEvents::from_bits_truncate(_event.bits())) - .map(|e| PollEvents::from_bits_truncate(e.bits())); + .poll(VfsPollEvents::from_bits_truncate(_event.bits() as u16)) + .map(|e| PollEvents::from_bits_truncate(e.bits() as u32)); res.map_err(Into::into) } } diff --git a/subsystems/vfs/src/lib.rs b/subsystems/vfs/src/lib.rs index 966ec4ac..e4472296 100644 --- a/subsystems/vfs/src/lib.rs +++ b/subsystems/vfs/src/lib.rs @@ -21,6 +21,7 @@ use vfscore::{dentry::VfsDentry, fstype::VfsFsType, path::VfsPath, utils::VfsTim use crate::dev::DevFsProviderImpl; pub mod dev; +pub mod epoll; pub mod eventfd; #[cfg(feature = "ext")] mod extffi; @@ -30,6 +31,7 @@ pub mod pipefs; pub mod proc; pub mod ram; pub mod sys; +pub mod timerfd; pub static FS: Lazy>>> = Lazy::new(|| Mutex::new(BTreeMap::new())); @@ -145,9 +147,7 @@ pub fn init_filesystem() -> AlienResult<()> { .expect("open /dev/sda failed") .inode()?; - println!("mount fs success XXXXX"); let diskfs_root = diskfs.i_mount(0, "/tests", Some(blk_inode), &[])?; - println!("mount fs success XXXXX"); path.join("tests")?.mount(diskfs_root, 0)?; println!("mount fs success"); diff --git a/subsystems/vfs/src/timerfd.rs b/subsystems/vfs/src/timerfd.rs new file mode 100644 index 00000000..9cb942a6 --- /dev/null +++ b/subsystems/vfs/src/timerfd.rs @@ -0,0 +1,160 @@ +use alloc::sync::Arc; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + +use constants::{ + io::{OpenFlags, PollEvents, SeekFrom}, + time::{ClockId, ITimeSpec, TimeSpec}, + AlienError, AlienResult, +}; +use ksync::Mutex; +use timer::{TimeNow, ToClock}; +use vfscore::{dentry::VfsDentry, inode::VfsInode, utils::VfsFileStat}; + +use crate::kfile::File; + +#[derive(Debug)] +pub struct TimerFile { + flags: OpenFlags, + timer: Mutex, + timer_next_clock: AtomicUsize, + timer_interval_clock: AtomicUsize, + /// Record the number of ticks that have been triggered + ticks: AtomicUsize, + disable: AtomicBool, + #[allow(unused)] + id: ClockId, +} + +impl TimerFile { + pub fn new(flags: OpenFlags, timer: ITimeSpec, id: ClockId) -> Self { + TimerFile { + flags, + timer: Mutex::new(timer), + ticks: AtomicUsize::new(0), + timer_interval_clock: AtomicUsize::new(0), + timer_next_clock: AtomicUsize::new(0), + disable: AtomicBool::new(true), + id, + } + } + + /// Return the interval of the timer + pub fn get_interval(&self) -> TimeSpec { + self.timer.lock().it_interval + } + + /// Return the next expiration time + pub fn get_it_value(&self) -> TimeSpec { + self.timer.lock().it_value + } + + /// Reset the timer + pub fn set_timer(&self, timer: ITimeSpec) { + if timer.it_value == TimeSpec::default() { + self.disable.store(true, Ordering::Relaxed); + } else { + self.disable.store(false, Ordering::Relaxed); + } + let next_clock = timer.it_value.to_clock() + TimeSpec::now().to_clock(); + let interval_clock = timer.it_interval.to_clock(); + *self.timer.lock() = timer; + self.timer_next_clock.store(next_clock, Ordering::Relaxed); + self.timer_interval_clock + .store(interval_clock, Ordering::Relaxed); + } + + pub fn calculate_ticks(&self) { + if self.disable.load(Ordering::Relaxed) { + return; + } + let now = TimeSpec::now().to_clock(); + let mut t_ticks = 0; + let next_clock = self.timer_next_clock.load(Ordering::Relaxed); + let interval_clock = self.timer_interval_clock.load(Ordering::Relaxed); + if now > next_clock { + t_ticks += 1; + if interval_clock != 0 { + let diff = now - next_clock; + let nums = diff / interval_clock; + t_ticks += nums; + } + // update next_clock + let next_clock = now + interval_clock; + self.timer_next_clock.store(next_clock, Ordering::Relaxed); + self.ticks.fetch_add(t_ticks, Ordering::Relaxed); + } + } +} + +impl File for TimerFile { + fn read(&self, buf: &mut [u8]) -> AlienResult { + if buf.len() != 8 { + return Err(AlienError::EINVAL); + } + let ticks = loop { + self.calculate_ticks(); + let ticks = self.ticks.load(Ordering::Relaxed); + if ticks != 0 { + // reset ticks + self.ticks.store(0, Ordering::Relaxed); + break ticks; + } + if self.flags.contains(OpenFlags::O_NONBLOCK) { + return Err(AlienError::EAGAIN); + } else { + shim::suspend(); + } + }; + let bytes = ticks.to_ne_bytes(); + buf.copy_from_slice(&bytes); + Ok(8) + } + + fn write(&self, _buf: &[u8]) -> AlienResult { + Err(AlienError::EINVAL) + } + + fn read_at(&self, _offset: u64, buf: &mut [u8]) -> AlienResult { + self.read(buf) + } + + fn write_at(&self, _offset: u64, _buf: &[u8]) -> AlienResult { + self.write(_buf) + } + fn seek(&self, _pos: SeekFrom) -> AlienResult { + Err(AlienError::ENOSYS) + } + fn get_attr(&self) -> AlienResult { + panic!("TimerFile does not have attr") + } + + fn ioctl(&self, _cmd: u32, _arg: usize) -> AlienResult { + panic!("ioctl is not implemented for TimerFile") + } + + fn dentry(&self) -> Arc { + panic!("TimerFile does not have dentry") + } + + fn inode(&self) -> Arc { + panic!("TimerFile does not have inode") + } + + fn is_readable(&self) -> bool { + true + } + + fn is_writable(&self) -> bool { + true + } + + fn is_append(&self) -> bool { + true + } + fn poll(&self, event: PollEvents) -> AlienResult { + if self.ticks.load(Ordering::Relaxed) != 0 && event.contains(PollEvents::EPOLLIN) { + return Ok(PollEvents::EPOLLIN); + } + Ok(PollEvents::empty()) + } +} diff --git a/tools/link.ld b/tools/link.ld index 200f898a..96bfb83a 100644 --- a/tools/link.ld +++ b/tools/link.ld @@ -1,6 +1,6 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0x40200000; +BASE_ADDRESS = 0x80200000; SECTIONS { diff --git a/user/.cargo/config.toml b/user/.cargo/config.toml index 8798eb5b..d6cda90c 100644 --- a/user/.cargo/config.toml +++ b/user/.cargo/config.toml @@ -1,9 +1,5 @@ -# 编译的目标平台 -[build] -target = "riscv64gc-unknown-none-elf" - -# 使用我们的 linker script 来进行链接 -[target.riscv64gc-unknown-none-elf] -rustflags = [ - "-Clink-arg=-Tuser/apps/linker.ld", -] \ No newline at end of file +## 使用我们的 linker script 来进行链接 +#[target.riscv64gc-unknown-none-elf] +#rustflags = [ +# "-Clink-arg=-Tuser/apps/linker.ld", +#] \ No newline at end of file diff --git a/user/apps/Makefile b/user/apps/Makefile index 3cf80910..acbea378 100644 --- a/user/apps/Makefile +++ b/user/apps/Makefile @@ -1,10 +1,13 @@ APPS := $(shell ls -d */) -compile := cargo build --release +compile := cargo build --release --target riscv64gc-unknown-none-elf mode := release target := ../../target/riscv64gc-unknown-none-elf/$(mode)/ APPS_NAME := $(shell ls -d */ | cut -d '/' -f 1) GUI ?=n FSMOUNT := ../../diskfs +LD_SCRIPT := user/apps/linker.ld + +export RUSTFLAGS := ${RUSTFLAGS} -C link-arg=-T$(LD_SCRIPT) all:build @echo "Moving apps to ../diskfs/bin" diff --git a/user/musl/.cargo/config.toml b/user/musl/.cargo/config.toml new file mode 100644 index 00000000..813a77e2 --- /dev/null +++ b/user/musl/.cargo/config.toml @@ -0,0 +1,21 @@ +[build] +target = "riscv64gc-unknown-linux-musl" +#target = "x86_64-unknown-linux-musl" +[profile.release] +lto = true +strip = true +opt-level = 3 # Optimize for size. +#incremental = true +#debug = true +panic = "abort" + +[target.riscv64gc-unknown-linux-musl] +rustflags = [ + "-L/opt/riscv-musl/lib/gcc/riscv64-linux-musl/11.2.1/", + "-L/opt/riscv-musl/riscv64-linux-musl/lib", +# "-C", "link-args=-lc", +# "-C", "prefer-dynamic", + "-C", "target-feature=+crt-static", + "-C", "link-arg=-lgcc" +] +linker = "riscv64-linux-musl-gcc" \ No newline at end of file diff --git a/user/musl/Makefile b/user/musl/Makefile new file mode 100644 index 00000000..787b7a1c --- /dev/null +++ b/user/musl/Makefile @@ -0,0 +1,21 @@ +TARGET = riscv64gc-unknown-linux-musl +compile := cargo build --release -Z build-std=core,std,panic_abort +mode := release +target := ../../target/$(TARGET)/$(mode)/ +FSMOUNT := ../../diskfs + + + +all:build + @echo "Moving apps to ../diskfs/bin" + @$(foreach dir, $(BUILD_CRATES), (sudo cp $(target)$(dir) $(FSMOUNT)/$(dir););) + + +build: + @echo "Building apps" + $(foreach dir, $(BUILD_CRATES), ($(compile) -p $(dir));) + + +BUILD_CRATES := \ + hello \ + async_test \ No newline at end of file diff --git a/user/musl/async_test/Cargo.toml b/user/musl/async_test/Cargo.toml new file mode 100644 index 00000000..e9b1bb99 --- /dev/null +++ b/user/musl/async_test/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "async_test" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1.25", features = [ + "macros", + "rt", + "rt-multi-thread", + "net", + "signal", +] } + +#smol = "2.0.0" \ No newline at end of file diff --git a/user/musl/async_test/src/main.rs b/user/musl/async_test/src/main.rs new file mode 100644 index 00000000..49fbcc1e --- /dev/null +++ b/user/musl/async_test/src/main.rs @@ -0,0 +1,28 @@ +async fn say_world() { + println!("world"); +} + +#[tokio::main(flavor = "current_thread")] +async fn main() { + // Calling `say_world()` does not execute the body of `say_world()`. + let op = say_world(); + + // This println! comes first + println!("hello"); + + // Calling `.await` on `op` starts executing `say_world`. + op.await; +} + +// fn main() { +// smol::block_on(async { +// // Calling `say_world()` does not execute the body of `say_world()`. +// let op = say_world(); +// +// // This println! comes first +// println!("hello"); +// +// // Calling `.await` on `op` starts executing `say_world`. +// op.await; +// }); +// } diff --git a/user/musl/hello/Cargo.toml b/user/musl/hello/Cargo.toml new file mode 100644 index 00000000..fe619478 --- /dev/null +++ b/user/musl/hello/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/user/musl/hello/src/main.rs b/user/musl/hello/src/main.rs new file mode 100644 index 00000000..ce1b0cbe --- /dev/null +++ b/user/musl/hello/src/main.rs @@ -0,0 +1,11 @@ +use std::time::Instant; + +fn main() { + let now = Instant::now(); + println!("now: {:#x?}", now); + println!("Hello, world!"); + let thread = std::thread::spawn(|| { + println!("Hello from thread!"); + }); + thread.join().unwrap(); +}