From 90d66ee4ac5cb72bdc744098036c6d36a1edf0d0 Mon Sep 17 00:00:00 2001 From: LittleSand <1840309785@qq.com> Date: Mon, 8 Jun 2026 16:16:44 +0800 Subject: [PATCH 1/7] =?UTF-8?q?fix(oscomp):=20=E5=AE=8C=E5=96=84=E8=AF=84?= =?UTF-8?q?=E6=B5=8B=20rootfs=20=E5=85=BC=E5=AE=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在构建 ext4 镜像时预创建 /dev、/proc、/sys、/tmp、/tests、/lib 和 /lib64,并补齐 glibc 运行库符号链接,减少启动阶段对根文件系统写入的依赖。 - 调整 mkfs.ext4 参数,固定 inode 大小并关闭 journal、resize_inode、dir_index 和 metadata_csum 等特性,降低内核 ext4 写路径与额外 ext4 特性的耦合。 - 支持读取 ext4 fast symlink,修复短符号链接目标内联存储在 inode i_block 时无法正确解析的问题。 - 统一 uname 与 /sys/kernel/{version,osrelease} 的版本信息,对齐评测环境期望的 Linux 5.10.0 标识。 - rcS 创建 glibc 运行库链接时避免覆盖既有文件,保留镜像构建阶段已经准备好的链接。 --- data/loongarch_musl/etc/init.d/rcS | 8 ++-- data/risc-v_musl/etc/init.d/rcS | 4 +- os/build.rs | 69 +++++++++++++++++++++++++++--- os/src/fs/ext4/inode.rs | 32 +++++++++++++- os/src/fs/sysfs/builders/kernel.rs | 11 ++--- os/src/uapi/uts_namespace.rs | 15 ++++--- 6 files changed, 111 insertions(+), 28 deletions(-) diff --git a/data/loongarch_musl/etc/init.d/rcS b/data/loongarch_musl/etc/init.d/rcS index b2dc878a..9560cc4d 100755 --- a/data/loongarch_musl/etc/init.d/rcS +++ b/data/loongarch_musl/etc/init.d/rcS @@ -64,13 +64,13 @@ run_oscomp_tests_if_present() { for f in /tests/glibc/lib/ld-linux-*.so.*; do [ -f "$f" ] || continue base="${f##*/}" - /bin/ln -sf "$f" "/lib/$base" - /bin/ln -sf "$f" "/lib64/$base" + [ -e "/lib/$base" ] || /bin/ln -s "$f" "/lib/$base" + [ -e "/lib64/$base" ] || /bin/ln -s "$f" "/lib64/$base" done for base in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 librt.so.1 libresolv.so.2; do if [ -f "/tests/glibc/lib/$base" ]; then - /bin/ln -sf "/tests/glibc/lib/$base" "/lib/$base" - /bin/ln -sf "/tests/glibc/lib/$base" "/lib64/$base" + [ -e "/lib/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib/$base" + [ -e "/lib64/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib64/$base" fi done fi diff --git a/data/risc-v_musl/etc/init.d/rcS b/data/risc-v_musl/etc/init.d/rcS index aa449af0..26434fa7 100755 --- a/data/risc-v_musl/etc/init.d/rcS +++ b/data/risc-v_musl/etc/init.d/rcS @@ -63,11 +63,11 @@ run_oscomp_tests_if_present() { for f in /tests/glibc/lib/ld-linux-*.so.*; do [ -f "$f" ] || continue base="${f##*/}" - /bin/ln -sf "$f" "/lib/$base" + [ -e "/lib/$base" ] || /bin/ln -s "$f" "/lib/$base" done for base in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 librt.so.1 libresolv.so.2; do if [ -f "/tests/glibc/lib/$base" ]; then - /bin/ln -sf "/tests/glibc/lib/$base" "/lib/$base" + [ -e "/lib/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib/$base" fi done fi diff --git a/os/build.rs b/os/build.rs index 77208f74..0f4bdeb6 100644 --- a/os/build.rs +++ b/os/build.rs @@ -9,6 +9,8 @@ use std::env; use std::fs; +use std::os::unix::fs::PermissionsExt; +use std::os::unix::fs::symlink; use std::path::{Path, PathBuf}; use std::process::Command; @@ -162,7 +164,11 @@ fn main() { // 检查依赖 println!("cargo:rerun-if-changed={}", data_dir.display()); - let dependencies = vec![data_dir.clone(), user_bin_dir]; + let dependencies = vec![ + data_dir.clone(), + user_bin_dir, + PathBuf::from(&manifest_dir).join("build.rs"), + ]; let force_rebuild = match fs::read_to_string(&arch_stamp) { Ok(saved) => saved.trim() != arch_key, @@ -375,7 +381,24 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path) ); } - // 3. 创建 /home/user/bin 目录并复制 user/bin + // 3. 预创建启动和评测需要的顶层目录,避免内核启动阶段写 rootfs。 + for (dir, mode) in [ + ("dev", 0o755), + ("proc", 0o755), + ("sys", 0o755), + ("tmp", 0o1777), + ("tests", 0o755), + ("lib", 0o755), + ("lib64", 0o755), + ] { + let path = temp_root.join(dir); + fs::create_dir_all(&path).unwrap_or_else(|_| panic!("Failed to create /{}", dir)); + fs::set_permissions(&path, fs::Permissions::from_mode(mode)) + .unwrap_or_else(|_| panic!("Failed to set permissions on /{}", dir)); + } + create_glibc_runtime_symlinks(&temp_root); + + // 4. 创建 /home/user/bin 目录并复制 user/bin let home_user_bin = temp_root.join("home").join("user").join("bin"); fs::create_dir_all(&home_user_bin).expect("Failed to create home/user/bin"); @@ -385,7 +408,7 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path) println!("cargo:warning=[build.rs] Copied user/bin to /home/user/bin"); } - // 4. 创建空镜像 + // 5. 创建空镜像 let dd_status = Command::new("dd") .arg("if=/dev/zero") .arg(format!("of={}", path.display())) @@ -400,13 +423,18 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path) panic!("Failed to create disk image"); } - // 5. 使用 mkfs.ext4 -d 选项从临时目录创建文件系统 + // 6. 使用 mkfs.ext4 -d 选项从临时目录创建文件系统。 + // 保持 feature 集合保守,降低 ext4_rs 写路径和目录索引/校验特性的耦合。 let mkfs_status = Command::new("mkfs.ext4") .arg("-F") .arg("-b") .arg("4096") .arg("-m") .arg("0") + .arg("-I") + .arg("256") + .arg("-O") + .arg("64bit,^has_journal,^resize_inode,^dir_index,^metadata_csum") .arg("-d") .arg(&temp_root) // 使用临时目录作为根 .arg(path) @@ -419,10 +447,39 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path) panic!("Failed to format ext4 image with data!"); } - // 6. 清理临时目录 + // 7. 清理临时目录 fs::remove_dir_all(&temp_root).ok(); - println!("cargo:warning=[build.rs] Full ext4 image created successfully (1GB)."); + println!("cargo:warning=[build.rs] Full ext4 image created successfully (4GB)."); +} + +fn create_glibc_runtime_symlinks(temp_root: &Path) { + for name in [ + "ld-linux-riscv64-lp64d.so.1", + "ld-linux-loongarch-lp64d.so.1", + "libc.so.6", + "libm.so.6", + "libpthread.so.0", + "libdl.so.2", + "librt.so.1", + "libresolv.so.2", + ] { + for libdir in ["lib", "lib64"] { + let link_path = temp_root.join(libdir).join(name); + if link_path.exists() || link_path.is_symlink() { + continue; + } + let target = format!("/tests/glibc/lib/{}", name); + if let Err(e) = symlink(&target, &link_path) { + println!( + "cargo:warning=[build.rs] Failed to create symlink {} -> {}: {}", + link_path.display(), + target, + e + ); + } + } + } } /// 递归复制目录 diff --git a/os/src/fs/ext4/inode.rs b/os/src/fs/ext4/inode.rs index 1ca710c2..655a7383 100644 --- a/os/src/fs/ext4/inode.rs +++ b/os/src/fs/ext4/inode.rs @@ -75,6 +75,31 @@ impl Ext4Inode { _ => InodeType::File, } } + + fn read_fast_symlink_target(&self, size: usize) -> Result, FsError> { + const FAST_SYMLINK_MAX_LEN: usize = 15 * core::mem::size_of::(); + + if size > FAST_SYMLINK_MAX_LEN { + return Ok(None); + } + + let fs = self.fs.lock(); + let inode_ref = fs.get_inode_ref(self.ino); + let inode = &inode_ref.inode; + if inode.blocks_count() != 0 { + return Ok(None); + } + + let mut buf = Vec::with_capacity(FAST_SYMLINK_MAX_LEN); + for block_word in inode.block { + buf.extend_from_slice(&block_word.to_le_bytes()); + } + buf.truncate(size); + + String::from_utf8(buf) + .map(Some) + .map_err(|_| FsError::InvalidArgument) + } } impl Inode for Ext4Inode { @@ -749,8 +774,11 @@ impl Inode for Ext4Inode { return Ok(String::new()); } - // 读取符号链接目标 - // 符号链接的目标存储在inode的数据区(与普通文件相同的方式) + if let Some(target) = self.read_fast_symlink_target(size)? { + return Ok(target); + } + + // 读取长符号链接目标。短符号链接已在上面从 inode 的 i_block 内联区读取。 let fs = self.fs.lock(); let mut buf = alloc::vec![0u8; size]; diff --git a/os/src/fs/sysfs/builders/kernel.rs b/os/src/fs/sysfs/builders/kernel.rs index 135a23ba..60475df1 100644 --- a/os/src/fs/sysfs/builders/kernel.rs +++ b/os/src/fs/sysfs/builders/kernel.rs @@ -4,6 +4,7 @@ use alloc::string::ToString; use alloc::sync::Arc; use crate::fs::sysfs::inode::{SysfsAttr, SysfsInode}; +use crate::uapi::uts_namespace::{UTS_RELEASE, UTS_VERSION}; use crate::vfs::{FileMode, FsError, Inode}; /// 构建内核信息 sysfs 树 @@ -17,10 +18,7 @@ pub fn build_kernel_info(root: &Arc) -> Result<(), FsError> { let version_attr = SysfsAttr { name: "version".to_string(), mode: FileMode::from_bits_truncate(0o444), - show: Arc::new(|| { - // TODO: 从内核配置获取编译时间 - Ok("#1 SMP Mon Jan 1 00:00:00 UTC 2025\n".to_string()) - }), + show: Arc::new(|| Ok(alloc::format!("{}\n", UTS_VERSION))), store: None, }; kernel_dir.add_child("version", SysfsInode::new_attribute(version_attr))?; @@ -29,10 +27,7 @@ pub fn build_kernel_info(root: &Arc) -> Result<(), FsError> { let osrelease_attr = SysfsAttr { name: "osrelease".to_string(), mode: FileMode::from_bits_truncate(0o444), - show: Arc::new(|| { - // TODO: 从内核配置获取版本号 - Ok("0.1.0\n".to_string()) - }), + show: Arc::new(|| Ok(alloc::format!("{}\n", UTS_RELEASE))), store: None, }; kernel_dir.add_child("osrelease", SysfsInode::new_attribute(osrelease_attr))?; diff --git a/os/src/uapi/uts_namespace.rs b/os/src/uapi/uts_namespace.rs index 031dfe32..5e2a59c5 100644 --- a/os/src/uapi/uts_namespace.rs +++ b/os/src/uapi/uts_namespace.rs @@ -5,6 +5,9 @@ use crate::arch::ArchImpl; /// UTS 名称最大长度 pub const UTS_NAME_LEN: usize = 65; +pub const UTS_SYSNAME: &str = "Linux"; +pub const UTS_RELEASE: &str = "5.10.0"; +pub const UTS_VERSION: &str = "#1 SMP Mon Jan 1 00:00:00 UTC 2025"; /// UTS 命名空间结构体 /// 用于隔离不同任务的主机名和域名设置 @@ -29,10 +32,10 @@ impl Default for UtsNamespace { /// 创建一个默认的 UTS 命名空间实例 /// /// 默认值为: - /// - sysname: "ComixOS" + /// - sysname: "Linux" /// - nodename: "localhost" - /// - release: "0.1.0" - /// - version: "Version 0.1.0" + /// - release: "5.10.0" + /// - version: "#1 SMP Mon Jan 1 00:00:00 UTC 2025" /// - machine: ArchImpl::name() (架构名称,如 "riscv64") /// - domainname: "localdomain" fn default() -> Self { @@ -51,19 +54,19 @@ impl Default for UtsNamespace { }, sysname: { let mut buf = [0u8; 65]; - let bytes = "ComixOS".as_bytes(); + let bytes = UTS_SYSNAME.as_bytes(); buf[..bytes.len()].copy_from_slice(bytes); buf }, release: { let mut buf = [0u8; 65]; - let bytes = "0.1.0".as_bytes(); + let bytes = UTS_RELEASE.as_bytes(); buf[..bytes.len()].copy_from_slice(bytes); buf }, version: { let mut buf = [0u8; 65]; - let bytes = "Version 0.1.0".as_bytes(); + let bytes = UTS_VERSION.as_bytes(); buf[..bytes.len()].copy_from_slice(bytes); buf }, From faf96f33b6876f3854af48bd419b63ebef718474 Mon Sep 17 00:00:00 2001 From: LittleSand <1840309785@qq.com> Date: Tue, 9 Jun 2026 12:52:33 +0800 Subject: [PATCH 2/7] =?UTF-8?q?fix=EF=BC=9A=E6=9A=82=E6=97=B6=E5=85=88?= =?UTF-8?q?=E5=8F=AA=E8=B7=91musl=EF=BC=8C=E7=8E=B0=E5=9C=A8glic=E8=BF=98?= =?UTF-8?q?=E4=B8=8D=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/loongarch_musl/etc/init.d/rcS | 65 ++++++++++++++++++++++-------- data/risc-v_musl/etc/init.d/rcS | 65 ++++++++++++++++++++++-------- 2 files changed, 98 insertions(+), 32 deletions(-) diff --git a/data/loongarch_musl/etc/init.d/rcS b/data/loongarch_musl/etc/init.d/rcS index 9560cc4d..1da92a93 100755 --- a/data/loongarch_musl/etc/init.d/rcS +++ b/data/loongarch_musl/etc/init.d/rcS @@ -56,9 +56,10 @@ run_oscomp_tests_if_present() { # 检测到官方测试脚本就非交互地依次执行,跑完主动关机。 [ -d /tests ] || return 1 - # 官方测试二进制硬编码了 ELF 解释器路径(如 /lib64/ld-linux-*.so.*)。 - # 我们是 musl rootfs,把测试镜像里的 glibc loader/库软链到常见 ABI libdir 以便加载。 - if [ -d /tests/glibc/lib ]; then + prepare_glibc_libs() { + # 官方 glibc 测试二进制硬编码了 ELF 解释器路径(如 /lib64/ld-linux-*.so.*)。 + # 默认先跑 musl 分组;后续支持 glibc 时再启用这段准备逻辑。 + [ -d /tests/glibc/lib ] || return 0 [ -d /lib ] || /bin/mkdir -p /lib [ -d /lib64 ] || /bin/mkdir -p /lib64 for f in /tests/glibc/lib/ld-linux-*.so.*; do @@ -73,7 +74,7 @@ run_oscomp_tests_if_present() { [ -e "/lib64/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib64/$base" fi done - fi + } scripts="" add_script() { @@ -84,21 +85,53 @@ run_oscomp_tests_if_present() { scripts="$scripts $1" } - # 1) /tests 根下的脚本。 - for f in /tests/*_testcode.sh; do - [ -f "$f" ] || continue - add_script "$f" - done - - # 2) 下一层:/tests/*/*,匹配官方镜像布局 /tests/glibc/*.sh、/tests/musl/*.sh。 - for d in /tests/*; do - [ -d "$d" ] || continue - [ "$d" = "/tests/tests" ] && continue - for f in "$d"/*_testcode.sh; do + add_scripts_in_dir() { + dir="$1" + [ -d "$dir" ] || return 0 + for f in "$dir"/*_testcode.sh; do [ -f "$f" ] || continue add_script "$f" done - done + } + + add_other_suite_scripts() { + for d in /tests/*; do + [ -d "$d" ] || continue + [ "$d" = "/tests/tests" ] && continue + [ "$d" = "/tests/musl" ] && continue + [ "$d" = "/tests/glibc" ] && continue + add_scripts_in_dir "$d" + done + } + + # 默认只跑 musl 分组,避免当前尚未完整支持的 glibc/Linux ABI 卡住启动链路。 + # 后续支持 glibc 后,可在 rootfs 中设置 OSCOMP_TEST_LIBC=glibc 或 all 复用同一入口。 + oscomp_test_libc="${OSCOMP_TEST_LIBC:-musl}" + [ "${OSCOMP_RUN_GLIBC:-0}" = "1" ] && oscomp_test_libc="all" + + case "$oscomp_test_libc" in + musl|MUSL|"") + add_scripts_in_dir /tests/musl + if [ -d /tests/glibc ]; then + echo "[OSCOMP] glibc test scripts skipped; set OSCOMP_TEST_LIBC=glibc/all to enable" + fi + ;; + glibc|GLIBC) + prepare_glibc_libs + add_scripts_in_dir /tests/glibc + ;; + all|ALL|both|BOTH) + add_scripts_in_dir /tests + add_scripts_in_dir /tests/musl + prepare_glibc_libs + add_scripts_in_dir /tests/glibc + add_other_suite_scripts + ;; + *) + echo "[OSCOMP] unknown OSCOMP_TEST_LIBC=$oscomp_test_libc; defaulting to musl" + add_scripts_in_dir /tests/musl + ;; + esac [ -n "$scripts" ] || return 1 echo "[OSCOMP] detected test scripts under /tests; running in rcS" diff --git a/data/risc-v_musl/etc/init.d/rcS b/data/risc-v_musl/etc/init.d/rcS index 26434fa7..6558aea3 100755 --- a/data/risc-v_musl/etc/init.d/rcS +++ b/data/risc-v_musl/etc/init.d/rcS @@ -56,9 +56,10 @@ run_oscomp_tests_if_present() { # 检测到官方测试脚本就非交互地依次执行,跑完主动关机。 [ -d /tests ] || return 1 - # 官方测试二进制硬编码了 ELF 解释器路径(如 /lib/ld-linux-*.so.*)。 - # 我们是 musl rootfs,把测试镜像里的 glibc loader/库软链到 /lib 以便加载。 - if [ -d /tests/glibc/lib ]; then + prepare_glibc_libs() { + # 官方 glibc 测试二进制硬编码了 ELF 解释器路径(如 /lib/ld-linux-*.so.*)。 + # 默认先跑 musl 分组;后续支持 glibc 时再启用这段准备逻辑。 + [ -d /tests/glibc/lib ] || return 0 [ -d /lib ] || /bin/mkdir -p /lib for f in /tests/glibc/lib/ld-linux-*.so.*; do [ -f "$f" ] || continue @@ -70,7 +71,7 @@ run_oscomp_tests_if_present() { [ -e "/lib/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib/$base" fi done - fi + } scripts="" add_script() { @@ -81,21 +82,53 @@ run_oscomp_tests_if_present() { scripts="$scripts $1" } - # 1) /tests 根下的脚本。 - for f in /tests/*_testcode.sh; do - [ -f "$f" ] || continue - add_script "$f" - done - - # 2) 下一层:/tests/*/*,匹配官方镜像布局 /tests/glibc/*.sh、/tests/musl/*.sh。 - for d in /tests/*; do - [ -d "$d" ] || continue - [ "$d" = "/tests/tests" ] && continue - for f in "$d"/*_testcode.sh; do + add_scripts_in_dir() { + dir="$1" + [ -d "$dir" ] || return 0 + for f in "$dir"/*_testcode.sh; do [ -f "$f" ] || continue add_script "$f" done - done + } + + add_other_suite_scripts() { + for d in /tests/*; do + [ -d "$d" ] || continue + [ "$d" = "/tests/tests" ] && continue + [ "$d" = "/tests/musl" ] && continue + [ "$d" = "/tests/glibc" ] && continue + add_scripts_in_dir "$d" + done + } + + # 默认只跑 musl 分组,避免当前尚未完整支持的 glibc/Linux ABI 卡住启动链路。 + # 后续支持 glibc 后,可在 rootfs 中设置 OSCOMP_TEST_LIBC=glibc 或 all 复用同一入口。 + oscomp_test_libc="${OSCOMP_TEST_LIBC:-musl}" + [ "${OSCOMP_RUN_GLIBC:-0}" = "1" ] && oscomp_test_libc="all" + + case "$oscomp_test_libc" in + musl|MUSL|"") + add_scripts_in_dir /tests/musl + if [ -d /tests/glibc ]; then + echo "[OSCOMP] glibc test scripts skipped; set OSCOMP_TEST_LIBC=glibc/all to enable" + fi + ;; + glibc|GLIBC) + prepare_glibc_libs + add_scripts_in_dir /tests/glibc + ;; + all|ALL|both|BOTH) + add_scripts_in_dir /tests + add_scripts_in_dir /tests/musl + prepare_glibc_libs + add_scripts_in_dir /tests/glibc + add_other_suite_scripts + ;; + *) + echo "[OSCOMP] unknown OSCOMP_TEST_LIBC=$oscomp_test_libc; defaulting to musl" + add_scripts_in_dir /tests/musl + ;; + esac [ -n "$scripts" ] || return 1 echo "[OSCOMP] detected test scripts under /tests; running in rcS" From 44a7c96faa1c996be7d6936ce3cbff233a62eba7 Mon Sep 17 00:00:00 2001 From: LittleSand <1840309785@qq.com> Date: Tue, 9 Jun 2026 23:06:09 +0800 Subject: [PATCH 3/7] fix(ext4): handle fast symlink storage --- os/src/fs/ext4/inode.rs | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/os/src/fs/ext4/inode.rs b/os/src/fs/ext4/inode.rs index 655a7383..5603b323 100644 --- a/os/src/fs/ext4/inode.rs +++ b/os/src/fs/ext4/inode.rs @@ -40,6 +40,14 @@ impl Ext4Inode { } } + #[cfg(test)] + pub(crate) fn set_blocks_count_for_test(&self, blocks: u64) { + let fs = self.fs.lock(); + let mut inode_ref = fs.get_inode_ref(self.ino); + inode_ref.inode.set_blocks_count(blocks); + fs.write_back_inode(&mut inode_ref); + } + /// 辅助方法:获取完整路径(从 Dentry 动态获取) fn get_full_path(&self) -> Result { let dentry = self.dentry.lock().upgrade().ok_or(FsError::IoError)?; @@ -79,16 +87,13 @@ impl Ext4Inode { fn read_fast_symlink_target(&self, size: usize) -> Result, FsError> { const FAST_SYMLINK_MAX_LEN: usize = 15 * core::mem::size_of::(); - if size > FAST_SYMLINK_MAX_LEN { + if size >= FAST_SYMLINK_MAX_LEN { return Ok(None); } let fs = self.fs.lock(); let inode_ref = fs.get_inode_ref(self.ino); let inode = &inode_ref.inode; - if inode.blocks_count() != 0 { - return Ok(None); - } let mut buf = Vec::with_capacity(FAST_SYMLINK_MAX_LEN); for block_word in inode.block { @@ -280,8 +285,25 @@ impl Inode for Ext4Inode { .create(parent, name, inode_mod) .map_err(|_| FsError::NoSpace)?; - fs.write_at(new_inode.inode_num, 0, target.as_bytes()) - .map_err(|_| FsError::IoError)?; + const FAST_SYMLINK_MAX_LEN: usize = 15 * core::mem::size_of::(); + let target_bytes = target.as_bytes(); + if target_bytes.len() < FAST_SYMLINK_MAX_LEN { + const EXT4_INODE_FLAG_EXTENTS: u32 = 0x0008_0000; + + let mut inode_ref = fs.get_inode_ref(new_inode.inode_num); + inode_ref.inode.block = [0; 15]; + for (word, chunk) in inode_ref.inode.block.iter_mut().zip(target_bytes.chunks(4)) { + let mut bytes = [0u8; 4]; + bytes[..chunk.len()].copy_from_slice(chunk); + *word = u32::from_le_bytes(bytes); + } + inode_ref.inode.flags &= !EXT4_INODE_FLAG_EXTENTS; + inode_ref.inode.set_size(target_bytes.len() as u64); + fs.write_back_inode(&mut inode_ref); + } else { + fs.write_at(new_inode.inode_num, 0, target_bytes) + .map_err(|_| FsError::IoError)?; + } Ok(Arc::new(Ext4Inode::new( self.fs.clone(), From 48bbf88e139d379b8864c41dd8cc3653b0b1f710 Mon Sep 17 00:00:00 2001 From: LittleSand <1840309785@qq.com> Date: Tue, 9 Jun 2026 23:06:25 +0800 Subject: [PATCH 4/7] test(ext4): cover symlink length boundary --- os/src/fs/tests/ext4/ext4_symlink.rs | 52 ++++++++++++++++++++++++++++ os/src/fs/tests/ext4/mod.rs | 1 + 2 files changed, 53 insertions(+) create mode 100644 os/src/fs/tests/ext4/ext4_symlink.rs diff --git a/os/src/fs/tests/ext4/ext4_symlink.rs b/os/src/fs/tests/ext4/ext4_symlink.rs new file mode 100644 index 00000000..7fda8c0c --- /dev/null +++ b/os/src/fs/tests/ext4/ext4_symlink.rs @@ -0,0 +1,52 @@ +use super::*; +use crate::fs::ext4::Ext4Inode; +use crate::vfs::file_system::FileSystem; +use crate::vfs::inode::InodeType; +use crate::{kassert, test_case}; +use alloc::string::String; + +fn repeated_target(byte: u8, len: usize) -> String { + String::from_utf8(alloc::vec![byte; len]).unwrap() +} + +test_case!(test_ext4_fast_symlink_59_bytes, { + let fs = create_test_ext4(); + let root = fs.root_inode(); + let target = repeated_target(b'f', 59); + + let link = root.symlink("fast59", &target).unwrap(); + let metadata = link.metadata().unwrap(); + + kassert!(metadata.inode_type == InodeType::Symlink); + kassert!(metadata.size == 59); + kassert!(metadata.blocks == 0); + kassert!(link.readlink().unwrap() == target); +}); + +test_case!(test_ext4_slow_symlink_60_bytes, { + let fs = create_test_ext4(); + let root = fs.root_inode(); + let target = repeated_target(b's', 60); + + let link = root.symlink("slow60", &target).unwrap(); + let metadata = link.metadata().unwrap(); + + kassert!(metadata.inode_type == InodeType::Symlink); + kassert!(metadata.size == 60); + kassert!(metadata.blocks > 0); + kassert!(link.readlink().unwrap() == target); +}); + +test_case!(test_ext4_fast_symlink_ignores_blocks_count, { + let fs = create_test_ext4(); + let root = fs.root_inode(); + let target = repeated_target(b'x', 59); + + let link = root.symlink("fast_with_blocks", &target).unwrap(); + let ext4_inode = link.downcast_ref::().unwrap(); + ext4_inode.set_blocks_count_for_test(8); + + let metadata = link.metadata().unwrap(); + kassert!(metadata.blocks > 0); + kassert!(link.readlink().unwrap() == target); +}); diff --git a/os/src/fs/tests/ext4/mod.rs b/os/src/fs/tests/ext4/mod.rs index 64970eb9..e2c89e91 100644 --- a/os/src/fs/tests/ext4/mod.rs +++ b/os/src/fs/tests/ext4/mod.rs @@ -175,3 +175,4 @@ pub mod ext4_io; pub mod ext4_metadata; pub mod ext4_permissions; pub mod ext4_rename; +pub mod ext4_symlink; From c7f1c02ee276a31da2dbb086721f2550510fc41f Mon Sep 17 00:00:00 2001 From: LittleSand <1840309785@qq.com> Date: Tue, 9 Jun 2026 23:16:30 +0800 Subject: [PATCH 5/7] build(oscomp): embed test suites in rootfs --- os/build.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/os/build.rs b/os/build.rs index 0f4bdeb6..7e4cd402 100644 --- a/os/build.rs +++ b/os/build.rs @@ -161,14 +161,22 @@ fn main() { // user_bin_dir 已经在上面通过 user_dir 引用了, user/bin let user_bin_dir = user_dir.join("bin"); let arch_stamp = PathBuf::from(&out_dir).join(format!("fs_img_arch_{}.txt", arch_key)); + let test_suite_dir = project_root + .join("testsuits-for-oskernel") + .join("sdcard") + .join(arch_key); // 检查依赖 println!("cargo:rerun-if-changed={}", data_dir.display()); - let dependencies = vec![ + println!("cargo:rerun-if-changed={}", test_suite_dir.display()); + let mut dependencies = vec![ data_dir.clone(), user_bin_dir, PathBuf::from(&manifest_dir).join("build.rs"), ]; + if test_suite_dir.exists() { + dependencies.push(test_suite_dir); + } let force_rebuild = match fs::read_to_string(&arch_stamp) { Ok(saved) => saved.trim() != arch_key, @@ -185,7 +193,7 @@ fn main() { println!( "cargo:warning=[build.rs] Creating full ext4 runtime image (4GB) at fs.img..." ); - create_full_ext4_image(&fs_img_path, &data_dir, &project_root); + create_full_ext4_image(&fs_img_path, &data_dir, &project_root, arch_key); let _ = fs::write(&arch_stamp, format!("{}\n", arch_key)); println!( "cargo:warning=[build.rs] Runtime image created: {}", @@ -353,8 +361,8 @@ fn create_empty_ext4_image(path: &PathBuf, size_mb: usize) { } } -/// 创建完整的 ext4 镜像 (包含 data/ 和 user/bin/) -fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path) { +/// 创建完整的 ext4 镜像 (包含 data/、测试套件和 user/bin/) +fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path, arch_key: &str) { const IMG_SIZE_MB: usize = 4096; // 4GB const BLOCK_SIZE: usize = 1024 * 1024; @@ -396,6 +404,7 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path) fs::set_permissions(&path, fs::Permissions::from_mode(mode)) .unwrap_or_else(|_| panic!("Failed to set permissions on /{}", dir)); } + copy_oscomp_test_suites(&temp_root, project_root, arch_key); create_glibc_runtime_symlinks(&temp_root); // 4. 创建 /home/user/bin 目录并复制 user/bin @@ -453,6 +462,42 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path) println!("cargo:warning=[build.rs] Full ext4 image created successfully (4GB)."); } +fn copy_oscomp_test_suites(temp_root: &Path, project_root: &Path, arch_key: &str) { + let suite_root = project_root + .join("testsuits-for-oskernel") + .join("sdcard") + .join(arch_key); + if !suite_root.exists() { + println!( + "cargo:warning=[build.rs] OSCOMP test suite not found at {}, skipping /tests population", + suite_root.display() + ); + return; + } + + let tests_root = temp_root.join("tests"); + for libc in ["musl", "glibc"] { + let src = suite_root.join(libc); + if !src.exists() { + println!( + "cargo:warning=[build.rs] OSCOMP {} suite not found at {}, skipping", + libc, + src.display() + ); + continue; + } + let dst = tests_root.join(libc); + if dst.exists() { + fs::remove_dir_all(&dst).expect("Failed to remove stale test suite directory"); + } + copy_dir_recursive(&src, &dst).expect("Failed to copy OSCOMP test suite"); + println!( + "cargo:warning=[build.rs] Copied OSCOMP {} tests to /tests/{}", + libc, libc + ); + } +} + fn create_glibc_runtime_symlinks(temp_root: &Path) { for name in [ "ld-linux-riscv64-lp64d.so.1", @@ -482,8 +527,8 @@ fn create_glibc_runtime_symlinks(temp_root: &Path) { } } -/// 递归复制目录 -fn copy_dir_recursive(src: &PathBuf, dst: &PathBuf) -> std::io::Result<()> { +/// 递归复制目录,保留符号链接。 +fn copy_dir_recursive(src: &Path, dst: &Path) -> std::io::Result<()> { if !dst.exists() { fs::create_dir_all(dst)?; } @@ -492,8 +537,12 @@ fn copy_dir_recursive(src: &PathBuf, dst: &PathBuf) -> std::io::Result<()> { let entry = entry?; let src_path = entry.path(); let dst_path = dst.join(entry.file_name()); + let file_type = fs::symlink_metadata(&src_path)?.file_type(); - if src_path.is_dir() { + if file_type.is_symlink() { + let target = fs::read_link(&src_path)?; + symlink(target, &dst_path)?; + } else if file_type.is_dir() { copy_dir_recursive(&src_path, &dst_path)?; } else { fs::copy(&src_path, &dst_path)?; From fd05fa2949d3fd15a957995137354af3a434e1a1 Mon Sep 17 00:00:00 2001 From: LittleSand <1840309785@qq.com> Date: Tue, 9 Jun 2026 23:16:51 +0800 Subject: [PATCH 6/7] fix(oscomp): use single rootfs disk --- Makefile | 46 +++++++---------------- os/src/fs/mod.rs | 85 +++++-------------------------------------- os/src/kernel/boot.rs | 2 +- 3 files changed, 23 insertions(+), 110 deletions(-) diff --git a/Makefile b/Makefile index 52c8ac4f..349db795 100644 --- a/Makefile +++ b/Makefile @@ -36,15 +36,13 @@ else PROFILE_DIR := release endif -# 评测内核默认启用 oscomp 特性:启动时探测双盘、把测试镜像挂到 /tests, -# 由 rootfs 的 rcS 自动跑测试并主动关机(赛题要求“自动运行 + 自动关闭”)。 +# 评测内核默认启用 oscomp 特性:使用单盘 rootfs(内含 /tests), +# 由 rootfs 的 rcS 自动跑 musl 测试并主动关机(赛题要求“自动运行 + 自动关闭”)。 # 本地交互式开发请用 `make run`(os/Makefile,不带 oscomp)。 OSCOMP_FEATURE ?= --features oscomp # 本地复现评测用 QEMU 参数(可在命令行覆盖,如 `make run-oscomp-rv OSCOMP_RV_MEM=2G`)。 -# 测试镜像默认取仓库根的 sdcard-{rv,la}.img;rootfs 用 make all 产出的 disk{,-la}.img。 -TESTIMG_RV ?= sdcard-rv.img -TESTIMG_LA ?= sdcard-la.img +# rootfs 用 make all 产出的 disk{,-la}.img,里面已经包含 /tests/{musl,glibc}。 OSCOMP_RV_MEM ?= 4G OSCOMP_RV_SMP ?= 1 OSCOMP_LA_MEM ?= 4G @@ -52,7 +50,7 @@ OSCOMP_LA_SMP ?= 1 .PHONY: docker build_docker fmt run build clean clean-all gdb .PHONY: all kernel-rv kernel-la os-cargo-config -.PHONY: run-oscomp-rv run-oscomp-la prepare-testimg-rv prepare-testimg-la +.PHONY: run-oscomp-rv run-oscomp-la docker: docker run --rm -it -v ${PWD}:/mnt -w /mnt --name comix ${DOCKER_TAG} bash @@ -131,42 +129,24 @@ disk-la.img: kernel-la cp -f $(OS_DIR)/fs-loongarch.img disk-la.img # ------------------------------------------------------------ -# 本地复现评测:启动 QEMU,挂测试镜像(x0) + 我们的 rootfs(x1), -# 内核自动跑测试并主动关机;-no-reboot 让关机时 QEMU 退出。 +# 本地复现评测:启动 QEMU,只挂单盘 rootfs(内含 /tests), +# 内核自动跑 musl 测试并主动关机;-no-reboot 让关机时 QEMU 退出。 # 设备型号对齐 os/qemu-run.sh(riscv: virtio-mmio)与 os/qemu-loongarch-run.sh(loongarch: pci)。 # ------------------------------------------------------------ -prepare-testimg-rv: - @test -f "$(TESTIMG_RV)" || ( \ - echo "[OSCOMP] 缺少 RISC-V 测试镜像: $(TESTIMG_RV)"; \ - echo "[OSCOMP] 请把官方测试镜像放到该路径,或用 TESTIMG_RV=... 覆盖。"; \ - exit 1; ) - @echo "[OSCOMP] 使用 RISC-V 测试镜像: $(TESTIMG_RV)" - -prepare-testimg-la: - @test -f "$(TESTIMG_LA)" || ( \ - echo "[OSCOMP] 缺少 LoongArch 测试镜像: $(TESTIMG_LA)"; \ - echo "[OSCOMP] 请把官方测试镜像放到该路径,或用 TESTIMG_LA=... 覆盖。"; \ - exit 1; ) - @echo "[OSCOMP] 使用 LoongArch 测试镜像: $(TESTIMG_LA)" - -run-oscomp-rv: kernel-rv disk.img prepare-testimg-rv - @echo "[OSCOMP] 运行 RISC-V QEMU(测试镜像 + rootfs,自动跑测试并关机)" +run-oscomp-rv: kernel-rv disk.img + @echo "[OSCOMP] 运行 RISC-V QEMU(单盘 rootfs + tests,自动跑测试并关机)" qemu-system-riscv64 -machine virt -kernel kernel-rv -m $(OSCOMP_RV_MEM) -nographic \ -smp $(OSCOMP_RV_SMP) -bios default -no-reboot -rtc base=utc \ - -drive file=$(TESTIMG_RV),if=none,format=raw,id=x0 \ + -drive file=disk.img,if=none,format=raw,id=x0 \ -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 \ - -drive file=disk.img,if=none,format=raw,id=x1 \ - -device virtio-blk-device,drive=x1,bus=virtio-mmio-bus.1 \ -device virtio-net-device,netdev=net -netdev user,id=net -run-oscomp-la: kernel-la disk-la.img prepare-testimg-la - @echo "[OSCOMP] 运行 LoongArch QEMU(测试镜像 + rootfs,自动跑测试并关机)" +run-oscomp-la: kernel-la disk-la.img + @echo "[OSCOMP] 运行 LoongArch QEMU(单盘 rootfs + tests,自动跑测试并关机)" qemu-system-loongarch64 -machine virt -kernel kernel-la -m $(OSCOMP_LA_MEM) -nographic \ -smp $(OSCOMP_LA_SMP) -no-reboot -rtc base=utc \ - -drive file=$(TESTIMG_LA),if=none,format=raw,id=x0 \ + -drive file=disk-la.img,if=none,format=raw,id=x0 \ -device virtio-blk-pci,drive=x0 \ - -drive file=disk-la.img,if=none,format=raw,id=x1 \ - -device virtio-blk-pci,drive=x1 \ -device virtio-net-pci,netdev=net0 \ -netdev user,id=net0,hostfwd=tcp::5555-:5555,hostfwd=udp::5555-:5555 @@ -217,4 +197,4 @@ help: @echo "Examples:" @echo " make build # Build for RISC-V" @echo " make build ARCH=loongarch # Build for LoongArch" - @echo " make run ARCH=loongarch # Run LoongArch kernel" \ No newline at end of file + @echo " make run ARCH=loongarch # Run LoongArch kernel" diff --git a/os/src/fs/mod.rs b/os/src/fs/mod.rs index a1c708bd..976dd6ab 100644 --- a/os/src/fs/mod.rs +++ b/os/src/fs/mod.rs @@ -212,13 +212,10 @@ pub fn init_ext4_from_block_device() -> Result<(), crate::vfs::FsError> { // ============================================================ // OSCOMP 评测模式文件系统初始化(仅 `oscomp` feature 下编译) // ============================================================ -// 评测机用 QEMU 同时挂两块盘: -// - 评测测试镜像(含 *_testcode.sh) -// - 我们的 rootfs(disk.img / disk-la.img,含 /bin/sh) -// virtio-blk 探测顺序在不同 QEMU 配置下不稳定,故按内容判别: -// - rootfs 认 `/bin/sh`(或 `/bin/ash`) -// - testfs 认(根或下一层)`*_testcode.sh`,挂到 /tests -// 测试发现/执行/关机由 rootfs 的 rcS 负责(见 data/*/etc/init.d/rcS)。 +// oscomp rootfs 与开发环境一样走单盘启动:disk.img / disk-la.img 内含 +// `/bin/sh`、`/sbin/init` 和 `/tests/{musl,glibc}`。virtio-blk 探测顺序在 +// 不同 QEMU 配置下可能变化,故仍按内容判别 rootfs(认 `/bin/sh` 或 +// `/bin/ash`)。测试发现/执行/关机由 rootfs 的 rcS 负责。 /// 确保 rootfs 上存在某个顶层挂载点目录(如 /dev、/tests)。 #[cfg(feature = "oscomp")] @@ -256,12 +253,12 @@ fn clear_current_task_root_cwd() { fs.cwd = None; } -/// OSCOMP 评测模式:探测并挂载 rootfs(/)与评测测试镜像(/tests)。 +/// OSCOMP 评测模式:探测并挂载单盘 rootfs(内含 /tests)。 #[cfg(feature = "oscomp")] pub fn init_oscomp_filesystems() -> Result<(), FsError> { use crate::config::EXT4_BLOCK_SIZE; - pr_info!("[OSCOMP][Ext4] Initializing filesystems (rootfs + testfs)"); + pr_info!("[OSCOMP][Ext4] Initializing single-disk rootfs"); let blk_list = BLK_DRIVERS.read(); if blk_list.is_empty() { @@ -271,7 +268,7 @@ pub fn init_oscomp_filesystems() -> Result<(), FsError> { let devices: alloc::vec::Vec<_> = blk_list.iter().cloned().collect(); drop(blk_list); - // 1) 探测并挂载 rootfs 到 "/"(认 /bin/sh 或 /bin/ash)。 + // 探测并挂载 rootfs 到 "/"(认 /bin/sh 或 /bin/ash)。 let mut root_idx: Option = None; for (idx, dev) in devices.iter().enumerate() { let bytes = dev.total_blocks().saturating_mul(dev.block_size()); @@ -299,7 +296,7 @@ pub fn init_oscomp_filesystems() -> Result<(), FsError> { clear_current_task_root_cwd(); } } - let root_idx = root_idx.ok_or(FsError::NoDevice)?; + let _root_idx = root_idx.ok_or(FsError::NoDevice)?; // 确保 rootfs 上存在常用挂载点。 let dir_mode = FileMode::S_IFDIR | FileMode::from_bits_truncate(0o755); @@ -308,71 +305,7 @@ pub fn init_oscomp_filesystems() -> Result<(), FsError> { let _ = ensure_top_level_dir("/sys", dir_mode); let _ = ensure_top_level_dir("/tmp", dir_mode); let _ = ensure_top_level_dir("/tests", dir_mode); - - // 检测某挂载点(根或下一层)是否含 *_testcode.sh。 - fn testsuite_has_scripts(mount_root: &str) -> bool { - let Ok(root) = vfs_lookup(mount_root) else { - return false; - }; - let Ok(ents) = root.inode.readdir() else { - return false; - }; - if ents.iter().any(|e| e.name.ends_with("_testcode.sh")) { - return true; - } - for e in ents { - if e.inode_type != crate::vfs::InodeType::Directory { - continue; - } - if e.name == "." || e.name == ".." { - continue; - } - let sub = alloc::format!("{}/{}", mount_root.trim_end_matches('/'), e.name); - let Ok(d) = vfs_lookup(&sub) else { - continue; - }; - let Ok(sub_ents) = d.inode.readdir() else { - continue; - }; - if sub_ents.iter().any(|se| se.name.ends_with("_testcode.sh")) { - return true; - } - } - false - } - - // 2) 探测并挂载 testfs 到 "/tests"(认 *_testcode.sh)。 - let mut test_found = false; - for (idx, dev) in devices.iter().enumerate() { - if idx == root_idx { - continue; - } - let bytes = dev.total_blocks().saturating_mul(dev.block_size()); - let total_blocks = bytes / EXT4_BLOCK_SIZE; - let Ok(fs) = Ext4FileSystem::open(dev.clone(), EXT4_BLOCK_SIZE, total_blocks, idx) else { - continue; - }; - MOUNT_TABLE.mount( - fs, - "/tests", - MountFlags::empty(), - Some(alloc::format!("virtio-blk{}", idx)), - )?; - if testsuite_has_scripts("/tests") { - pr_info!( - "[OSCOMP][Ext4] Selected testfs: virtio-blk{} (device_bytes={} MB)", - idx, - bytes / 1024 / 1024 - ); - test_found = true; - break; - } else { - let _ = MOUNT_TABLE.umount("/tests"); - } - } - if !test_found { - pr_info!("[OSCOMP][Ext4] Testfs not found; rcS will scan / for test scripts"); - } + pr_info!("[OSCOMP][Ext4] Rootfs ready; rcS will scan /tests/musl"); Ok(()) } diff --git a/os/src/kernel/boot.rs b/os/src/kernel/boot.rs index 655d7e9a..f8afd84a 100644 --- a/os/src/kernel/boot.rs +++ b/os/src/kernel/boot.rs @@ -203,7 +203,7 @@ pub fn rest_init() { fn init() { create_kthreadd(); - // OSCOMP 评测模式:探测双盘(rootfs + 测试镜像),把测试镜像挂到 /tests。 + // OSCOMP 评测模式:按内容探测并挂载单盘 rootfs(内含 /tests)。 // 测试发现/执行/关机交给 rootfs 的 rcS(见 data/*/etc/init.d/rcS)。 #[cfg(feature = "oscomp")] { From 9a11b6002e73d1aaf2f8f8f99e0b5fb0245a92c4 Mon Sep 17 00:00:00 2001 From: LittleSand <1840309785@qq.com> Date: Tue, 9 Jun 2026 23:17:05 +0800 Subject: [PATCH 7/7] fix(oscomp): run musl tests and honor reboot ops --- data/loongarch_musl/etc/init.d/rcS | 65 ++---------------------------- data/risc-v_musl/etc/init.d/rcS | 62 ++-------------------------- os/src/kernel/syscall/sys.rs | 18 ++++----- 3 files changed, 15 insertions(+), 130 deletions(-) diff --git a/data/loongarch_musl/etc/init.d/rcS b/data/loongarch_musl/etc/init.d/rcS index 1da92a93..179c1fc9 100755 --- a/data/loongarch_musl/etc/init.d/rcS +++ b/data/loongarch_musl/etc/init.d/rcS @@ -52,30 +52,10 @@ echo "Mounting file systems via fstab..." echo "System initialization finished." run_oscomp_tests_if_present() { - # 评测测试镜像由内核挂到 /tests(init_oscomp_filesystems())。 - # 检测到官方测试脚本就非交互地依次执行,跑完主动关机。 + # rootfs 内置 /tests。当前自动入口只跑 musl 分组; + # glibc 分组保留在镜像中,后续需要时直接调整本脚本。 [ -d /tests ] || return 1 - prepare_glibc_libs() { - # 官方 glibc 测试二进制硬编码了 ELF 解释器路径(如 /lib64/ld-linux-*.so.*)。 - # 默认先跑 musl 分组;后续支持 glibc 时再启用这段准备逻辑。 - [ -d /tests/glibc/lib ] || return 0 - [ -d /lib ] || /bin/mkdir -p /lib - [ -d /lib64 ] || /bin/mkdir -p /lib64 - for f in /tests/glibc/lib/ld-linux-*.so.*; do - [ -f "$f" ] || continue - base="${f##*/}" - [ -e "/lib/$base" ] || /bin/ln -s "$f" "/lib/$base" - [ -e "/lib64/$base" ] || /bin/ln -s "$f" "/lib64/$base" - done - for base in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 librt.so.1 libresolv.so.2; do - if [ -f "/tests/glibc/lib/$base" ]; then - [ -e "/lib/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib/$base" - [ -e "/lib64/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib64/$base" - fi - done - } - scripts="" add_script() { # 简单去重,避免 VFS 把 /tests 暴露成 /tests/tests 之类的病态情况。 @@ -94,47 +74,10 @@ run_oscomp_tests_if_present() { done } - add_other_suite_scripts() { - for d in /tests/*; do - [ -d "$d" ] || continue - [ "$d" = "/tests/tests" ] && continue - [ "$d" = "/tests/musl" ] && continue - [ "$d" = "/tests/glibc" ] && continue - add_scripts_in_dir "$d" - done - } - - # 默认只跑 musl 分组,避免当前尚未完整支持的 glibc/Linux ABI 卡住启动链路。 - # 后续支持 glibc 后,可在 rootfs 中设置 OSCOMP_TEST_LIBC=glibc 或 all 复用同一入口。 - oscomp_test_libc="${OSCOMP_TEST_LIBC:-musl}" - [ "${OSCOMP_RUN_GLIBC:-0}" = "1" ] && oscomp_test_libc="all" - - case "$oscomp_test_libc" in - musl|MUSL|"") - add_scripts_in_dir /tests/musl - if [ -d /tests/glibc ]; then - echo "[OSCOMP] glibc test scripts skipped; set OSCOMP_TEST_LIBC=glibc/all to enable" - fi - ;; - glibc|GLIBC) - prepare_glibc_libs - add_scripts_in_dir /tests/glibc - ;; - all|ALL|both|BOTH) - add_scripts_in_dir /tests - add_scripts_in_dir /tests/musl - prepare_glibc_libs - add_scripts_in_dir /tests/glibc - add_other_suite_scripts - ;; - *) - echo "[OSCOMP] unknown OSCOMP_TEST_LIBC=$oscomp_test_libc; defaulting to musl" - add_scripts_in_dir /tests/musl - ;; - esac + add_scripts_in_dir /tests/musl [ -n "$scripts" ] || return 1 - echo "[OSCOMP] detected test scripts under /tests; running in rcS" + echo "[OSCOMP] detected musl test scripts under /tests; running in rcS" export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/tests" export HOME="/" diff --git a/data/risc-v_musl/etc/init.d/rcS b/data/risc-v_musl/etc/init.d/rcS index 6558aea3..179c1fc9 100755 --- a/data/risc-v_musl/etc/init.d/rcS +++ b/data/risc-v_musl/etc/init.d/rcS @@ -52,27 +52,10 @@ echo "Mounting file systems via fstab..." echo "System initialization finished." run_oscomp_tests_if_present() { - # 评测测试镜像由内核挂到 /tests(init_oscomp_filesystems())。 - # 检测到官方测试脚本就非交互地依次执行,跑完主动关机。 + # rootfs 内置 /tests。当前自动入口只跑 musl 分组; + # glibc 分组保留在镜像中,后续需要时直接调整本脚本。 [ -d /tests ] || return 1 - prepare_glibc_libs() { - # 官方 glibc 测试二进制硬编码了 ELF 解释器路径(如 /lib/ld-linux-*.so.*)。 - # 默认先跑 musl 分组;后续支持 glibc 时再启用这段准备逻辑。 - [ -d /tests/glibc/lib ] || return 0 - [ -d /lib ] || /bin/mkdir -p /lib - for f in /tests/glibc/lib/ld-linux-*.so.*; do - [ -f "$f" ] || continue - base="${f##*/}" - [ -e "/lib/$base" ] || /bin/ln -s "$f" "/lib/$base" - done - for base in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 librt.so.1 libresolv.so.2; do - if [ -f "/tests/glibc/lib/$base" ]; then - [ -e "/lib/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib/$base" - fi - done - } - scripts="" add_script() { # 简单去重,避免 VFS 把 /tests 暴露成 /tests/tests 之类的病态情况。 @@ -91,47 +74,10 @@ run_oscomp_tests_if_present() { done } - add_other_suite_scripts() { - for d in /tests/*; do - [ -d "$d" ] || continue - [ "$d" = "/tests/tests" ] && continue - [ "$d" = "/tests/musl" ] && continue - [ "$d" = "/tests/glibc" ] && continue - add_scripts_in_dir "$d" - done - } - - # 默认只跑 musl 分组,避免当前尚未完整支持的 glibc/Linux ABI 卡住启动链路。 - # 后续支持 glibc 后,可在 rootfs 中设置 OSCOMP_TEST_LIBC=glibc 或 all 复用同一入口。 - oscomp_test_libc="${OSCOMP_TEST_LIBC:-musl}" - [ "${OSCOMP_RUN_GLIBC:-0}" = "1" ] && oscomp_test_libc="all" - - case "$oscomp_test_libc" in - musl|MUSL|"") - add_scripts_in_dir /tests/musl - if [ -d /tests/glibc ]; then - echo "[OSCOMP] glibc test scripts skipped; set OSCOMP_TEST_LIBC=glibc/all to enable" - fi - ;; - glibc|GLIBC) - prepare_glibc_libs - add_scripts_in_dir /tests/glibc - ;; - all|ALL|both|BOTH) - add_scripts_in_dir /tests - add_scripts_in_dir /tests/musl - prepare_glibc_libs - add_scripts_in_dir /tests/glibc - add_other_suite_scripts - ;; - *) - echo "[OSCOMP] unknown OSCOMP_TEST_LIBC=$oscomp_test_libc; defaulting to musl" - add_scripts_in_dir /tests/musl - ;; - esac + add_scripts_in_dir /tests/musl [ -n "$scripts" ] || return 1 - echo "[OSCOMP] detected test scripts under /tests; running in rcS" + echo "[OSCOMP] detected musl test scripts under /tests; running in rcS" export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/tests" export HOME="/" diff --git a/os/src/kernel/syscall/sys.rs b/os/src/kernel/syscall/sys.rs index e472bf92..7629a8ee 100644 --- a/os/src/kernel/syscall/sys.rs +++ b/os/src/kernel/syscall/sys.rs @@ -8,7 +8,7 @@ use core::{ use crate::{ arch::{ - lib::shutdown, + lib::{restart, shutdown}, timer::{TICKS_PER_SEC, TIMER_TICKS, clock_freq}, }, kernel::{ @@ -20,13 +20,13 @@ use crate::{ DEFAULT_CONSOLE_LEVEL, LogLevel, format_log_entry, get_console_level, read_log, set_console_level, }, - pr_alert, security::{BiogasPoll, EntropyPool}, uapi::{ errno::{EINVAL, ENOSYS}, log::SyslogAction, reboot::{ - REBOOT_CMD_POWER_OFF, REBOOT_MAGIC1, REBOOT_MAGIC2, REBOOT_MAGIC2A, REBOOT_MAGIC2B, + REBOOT_CMD_CAD_OFF, REBOOT_CMD_CAD_ON, REBOOT_CMD_HALT, REBOOT_CMD_POWER_OFF, + REBOOT_CMD_RESTART, REBOOT_MAGIC1, REBOOT_MAGIC2, REBOOT_MAGIC2A, REBOOT_MAGIC2B, REBOOT_MAGIC2C, }, sysinfo::SysInfo, @@ -54,7 +54,6 @@ use crate::{ /// 成功返回 0,失败返回负错误码 /// 对于重启或关机操作,函数不会返回 pub fn reboot(magic: c_int, magic2: c_int, op: c_int, _arg: *mut c_void) -> c_int { - // TODO: 支持更多重启操作码 if magic as u32 != REBOOT_MAGIC1 { return -EINVAL; } @@ -66,14 +65,11 @@ pub fn reboot(magic: c_int, magic2: c_int, op: c_int, _arg: *mut c_void) -> c_in return -EINVAL; } match op as u32 { - REBOOT_CMD_POWER_OFF => { - shutdown(true); - } - _ => { - pr_alert!("reboot: unsupported reboot operation code {}\n", op); - } + REBOOT_CMD_CAD_OFF | REBOOT_CMD_CAD_ON => 0, + REBOOT_CMD_RESTART => restart(), + REBOOT_CMD_HALT | REBOOT_CMD_POWER_OFF => shutdown(false), + _ => -EINVAL, } - 0 } /// 获取系统信息系统调用