diff --git a/os/StarryOS/kernel/src/syscall/task/schedule.rs b/os/StarryOS/kernel/src/syscall/task/schedule.rs index 7e87f814b0..0be6e1456e 100644 --- a/os/StarryOS/kernel/src/syscall/task/schedule.rs +++ b/os/StarryOS/kernel/src/syscall/task/schedule.rs @@ -1,14 +1,15 @@ use alloc::{sync::Arc, vec::Vec}; use ax_errno::{AxError, AxResult}; -use ax_runtime::hal::time::TimeValue; +use ax_runtime::hal::{self, time::TimeValue}; use ax_task::{ AxCpuMask, current, future::{block_on, interruptible, sleep}, }; +use bytemuck::{Pod, Zeroable}; use linux_raw_sys::general::{ __kernel_clockid_t, CLOCK_MONOTONIC, CLOCK_REALTIME, PRIO_PGRP, PRIO_PROCESS, PRIO_USER, - SCHED_RR, TIMER_ABSTIME, timespec, + SCHED_BATCH, SCHED_FIFO, SCHED_IDLE, SCHED_NORMAL, SCHED_RR, TIMER_ABSTIME, timespec, }; use starry_vm::{VmMutPtr, VmPtr, vm_load, vm_write_slice}; @@ -20,6 +21,12 @@ use crate::{ time::TimeValueLike, }; +#[repr(C)] +#[derive(Copy, Clone, Pod, Zeroable)] +struct SchedParam { + sched_priority: i32, +} + pub fn sys_sched_yield() -> AxResult { ax_task::yield_now(); Ok(0) @@ -43,7 +50,7 @@ pub fn sys_nanosleep(req: *const timespec, rem: *mut timespec) -> AxResult rem: {diff:?}"); @@ -63,8 +70,8 @@ pub fn sys_clock_nanosleep( rem: *mut timespec, ) -> AxResult { let clock = match clock_id as u32 { - CLOCK_REALTIME => ax_runtime::hal::time::wall_time, - CLOCK_MONOTONIC => ax_runtime::hal::time::monotonic_time, + CLOCK_REALTIME => hal::time::wall_time, + CLOCK_MONOTONIC => hal::time::monotonic_time, _ => { warn!("Unsupported clock_id: {clock_id}"); return Err(AxError::InvalidInput); @@ -94,7 +101,7 @@ pub fn sys_clock_nanosleep( } pub fn sys_sched_getaffinity(pid: i32, cpusetsize: usize, user_mask: *mut u8) -> AxResult { - if cpusetsize * 8 < ax_runtime::hal::cpu_num() { + if cpusetsize * 8 < hal::cpu_num() { return Err(AxError::InvalidInput); } @@ -107,12 +114,32 @@ pub fn sys_sched_getaffinity(pid: i32, cpusetsize: usize, user_mask: *mut u8) -> Ok(mask_bytes.len() as _) } +pub fn check_sched_permission(pid: i32) -> AxResult<()> { + let caller = current().as_thread().cred(); + let task = get_task_by_sched_pid(pid)?; + if task.id() == current().id() { + return Ok(()); + } + let target_proc = get_process_data(pid as u32)?; + let target_cred = process_cred(&target_proc)?; + if caller.has_cap_sys_nice() + || caller.euid == target_cred.uid + || caller.euid == target_cred.euid + { + Ok(()) + } else { + Err(AxError::OperationNotPermitted) + } +} + pub fn sys_sched_setaffinity(pid: i32, cpusetsize: usize, user_mask: *const u8) -> AxResult { - let size = cpusetsize.min(ax_runtime::hal::cpu_num().div_ceil(8)); + check_sched_permission(pid)?; + let task = get_task_by_sched_pid(pid)?; + let size = cpusetsize.min(hal::cpu_num().div_ceil(8)); let user_mask = vm_load(user_mask, size)?; let mut cpu_mask = AxCpuMask::new(); - for i in 0..(size * 8).min(ax_runtime::hal::cpu_num()) { + for i in 0..(size * 8).min(hal::cpu_num()) { if user_mask[i / 8] & (1 << (i % 8)) != 0 { cpu_mask.set(i, true); } @@ -121,8 +148,6 @@ pub fn sys_sched_setaffinity(pid: i32, cpusetsize: usize, user_mask: *const u8) if cpu_mask.is_empty() { return Err(AxError::InvalidInput); } - - let task = get_task_by_sched_pid(pid)?; if task.id() == current().id() { ax_task::set_current_affinity(cpu_mask); } else { @@ -141,14 +166,65 @@ fn get_task_by_sched_pid(pid: i32) -> AxResult { } pub fn sys_sched_getscheduler(_pid: i32) -> AxResult { - Ok(SCHED_RR as _) + let task = get_task_by_sched_pid(_pid)?; + Ok(task.sched_policy() as isize) } pub fn sys_sched_setscheduler(_pid: i32, _policy: i32, _param: *const ()) -> AxResult { + check_sched_permission(_pid)?; + let task = get_task_by_sched_pid(_pid)?; + let caller = current().as_thread().cred(); + if _param.is_null() { + return Err(AxError::InvalidInput); + } + let user_param = vm_load::(_param.cast(), 1)?; + let user_param = user_param[0]; + let mut policy = _policy as u32; + const SCHED_RESET_ON_FORK: u32 = 0x40000000; + let _reset_on_fork = (policy & SCHED_RESET_ON_FORK) != 0; + policy &= !SCHED_RESET_ON_FORK; + let prio = user_param.sched_priority; + match policy { + SCHED_NORMAL | SCHED_FIFO | SCHED_RR | SCHED_BATCH | SCHED_IDLE => {} + _ => return Err(AxError::InvalidInput), + } + match policy { + SCHED_NORMAL | SCHED_BATCH | SCHED_IDLE => { + if prio != 0 { + return Err(AxError::InvalidInput); + } + } + SCHED_FIFO | SCHED_RR => { + if !(1..=99).contains(&prio) { + return Err(AxError::InvalidInput); + } + if !caller.has_cap_sys_nice() { + return Err(AxError::OperationNotPermitted); + } + } + _ => unreachable!(), + } + task.set_sched_policy(policy as i32); + task.set_sched_priority(prio); Ok(0) } pub fn sys_sched_getparam(_pid: i32, _param: *mut ()) -> AxResult { + let task = get_task_by_sched_pid(_pid)?; + if _param.is_null() { + return Err(AxError::InvalidInput); + } + let param = SchedParam { + sched_priority: task.sched_priority(), + }; + let ptr = _param as *mut SchedParam; + unsafe { + let bytes = core::slice::from_raw_parts( + ¶m as *const SchedParam as *const u8, + core::mem::size_of::(), + ); + vm_write_slice(ptr as *mut u8, bytes)?; + } Ok(0) } diff --git a/os/arceos/modules/axtask/src/task.rs b/os/arceos/modules/axtask/src/task.rs index 0e535dbd25..24790a11af 100644 --- a/os/arceos/modules/axtask/src/task.rs +++ b/os/arceos/modules/axtask/src/task.rs @@ -82,6 +82,12 @@ pub struct TaskInner { /// CPU affinity mask. cpumask: SpinNoIrq, + /// Scheduling policy of the task. + sched_policy: AtomicI32, + + /// Scheduling priority of the task. + sched_priority: AtomicI32, + /// Mark whether the task is in the wait queue. in_wait_queue: AtomicBool, @@ -264,6 +270,26 @@ impl TaskInner { *self.cpumask.lock() = cpumask } + #[inline] + pub fn sched_policy(&self) -> i32 { + self.sched_policy.load(Ordering::Acquire) + } + + #[inline] + pub fn set_sched_policy(&self, policy: i32) { + self.sched_policy.store(policy, Ordering::Release) + } + + #[inline] + pub fn sched_priority(&self) -> i32 { + self.sched_priority.load(Ordering::Acquire) + } + + #[inline] + pub fn set_sched_priority(&self, prio: i32) { + self.sched_priority.store(prio, Ordering::Release) + } + /// Polls whether the task has been interrupted. #[inline] pub fn poll_interrupt(&self, cx: &Context) -> Poll<()> { @@ -324,6 +350,8 @@ impl TaskInner { state: AtomicU8::new(TaskState::Ready as u8), // By default, the task is allowed to run on all CPUs. cpumask: SpinNoIrq::new(crate::api::cpu_mask_full()), + sched_policy: AtomicI32::new(0), + sched_priority: AtomicI32::new(0), in_wait_queue: AtomicBool::new(false), #[cfg(feature = "irq")] timer_ticket_id: AtomicU64::new(0), diff --git a/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/CMakeLists.txt b/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/CMakeLists.txt new file mode 100644 index 0000000000..e43ed15910 --- /dev/null +++ b/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.20) +project(test-sched-family C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) +add_executable(test-sched-family src/main.c) +target_include_directories(test-sched-family PRIVATE src) +target_compile_options(test-sched-family PRIVATE -Wall -Wextra -Werror) +install(TARGETS test-sched-family RUNTIME DESTINATION usr/bin) diff --git a/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/src/main.c b/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/src/main.c new file mode 100644 index 0000000000..a2438da743 --- /dev/null +++ b/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/src/main.c @@ -0,0 +1,271 @@ +#define _GNU_SOURCE +#include "test_framework.h" +#include +#include +#include +#include +#include +#include +#include + + +/* + * Check whether the current process has CAP_SYS_NICE in its + * effective capability set. + * + * Linux exposes process capabilities through /proc/self/status: + * + * CapEff: + * + * CAP_SYS_NICE is capability number 23, which permits privileged + * scheduling operations such as changing another task's CPU affinity. + * + * Return: + * 1 -> CAP_SYS_NICE is present + * 0 -> CAP_SYS_NICE is absent or capability information is unavailable + */ +static int has_cap_sys_nice(void) +{ + FILE *f = fopen("/proc/self/status", "r"); + if (!f) return 0; + + char line[256]; + int ok = 0; + + while (fgets(line, sizeof(line), f)) { + if (strncmp(line, "CapEff:", 7) == 0) { + unsigned long long cap = 0; + + if (sscanf(line + 7, "%llx", &cap) == 1) { + /* CAP_SYS_NICE == 23 */ + if (cap & (1ULL << 23)) + ok = 1; + } + break; + } + } + + fclose(f); + return ok; +} + +/* + * test-sched-family 对比测试: + * Linux/WSL 行为 vs StarryOS 行为 + */ + +int main(void) +{ + TEST_START("sched_setaffinity / sched_getaffinity"); + + // 测试 sched_setaffinity() / sched_getaffinity 在当前线程上的正常行为 + { + + // 常规用例:将当前线程绑定到 CPU 0,并验证 getaffinity 返回正确的结果 + { + cpu_set_t mask, readback; + + CPU_ZERO(&mask); + CPU_SET(0, &mask); + memset(&readback, 0, sizeof(readback)); + CHECK_RET(sched_setaffinity(0, sizeof(mask), &mask), 0, "setaffinity current pid to cpu0"); + CHECK_RET(sched_getaffinity(0, sizeof(readback), &readback), 0, "getaffinity current pid"); + CHECK(CPU_ISSET(0, &readback), "getaffinity result contains cpu0"); + } + + // EFAULT: supplied memory address was invalid + { + CHECK_ERR(sched_setaffinity(0, sizeof(cpu_set_t), (cpu_set_t *)0x1), EFAULT, "setaffinity with invalid pointer returns EFAULT"); + CHECK_ERR(sched_getaffinity(0, sizeof(cpu_set_t), (cpu_set_t *)0x1), EFAULT, "getaffinity with invalid pointer returns EFAULT"); + } + + // EINVAL: affinity mask contains no online CPUs + { + long nprocs = sysconf(_SC_NPROCESSORS_ONLN); + if (nprocs < 1) nprocs = 1; + cpu_set_t mask; + CPU_ZERO(&mask); + CHECK_ERR(sched_setaffinity(0, sizeof(mask), &mask), EINVAL, "setaffinity with mask containing no online CPUs returns EINVAL"); + } + + // EINVAL: cpusetsize smaller than the kernel affinity mask size + { + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(0, &mask); + CHECK_ERR(sched_getaffinity(0, 0, &mask), EINVAL, "getaffinity with too small cpusetsize returns EINVAL"); + } + + // ==== EPERM: sched_setaffinity permission test (fork-based) ==== + { + pid_t target = fork(); + if (target == 0) { + while (1) pause(); // child stays alive + } + + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(0, &mask); + + uid_t my_euid = geteuid(); + + // fork child: uid/euid == parent (no /proc parsing needed) + uid_t target_ruid = my_euid; + uid_t target_euid = my_euid; + + if (my_euid == target_ruid || my_euid == target_euid || has_cap_sys_nice()) { + CHECK_RET(sched_setaffinity(target, sizeof(mask), &mask), 0, + "setaffinity forked child allowed returns 0"); + } else { + CHECK_ERR(sched_setaffinity(target, sizeof(mask), &mask), EPERM, + "setaffinity forked child returns EPERM"); + } + + kill(target, SIGKILL); + waitpid(target, NULL, 0); + } + + // ESRCH: non-existent pid should return ESRCH + { + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(0, &mask); + pid_t fake = 999999; + CHECK_ERR(sched_setaffinity(fake, sizeof(mask), &mask), ESRCH, "setaffinity for non-existent pid returns ESRCH"); + CHECK_ERR(sched_getaffinity(fake, sizeof(mask), &mask), ESRCH, "getaffinity for non-existent pid returns ESRCH"); + } + } + + // sched_yield() 应当成功返回 0 + { + CHECK_RET(sched_yield(), 0, "sched_yield returns 0"); + } + + // 测试 sched_setscheduler() / sched_getscheduler + { + #define SCHED_RESET_ON_FORK 0x40000000 + struct sched_param sp; + memset(&sp, 0, sizeof(sp)); + sp.sched_priority = 0; + int policy = SCHED_FIFO | SCHED_RESET_ON_FORK; + + // 正常情况测试 + CHECK_RET(syscall(SYS_SCHED_SETSCHEDULER, 0, SCHED_OTHER, &sp), 0, "sched_setscheduler with valid parameters returns 0"); + CHECK_RET(syscall(SYS_SCHED_GETSCHEDULER, 0), SCHED_OTHER, "sched_getscheduler for current pid returns SCHED_OTHER"); + + // 负 pid -> EINVAL + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, -5, SCHED_OTHER, &sp), EINVAL, "sched_setscheduler with negative pid returns EINVAL"); + + CHECK_ERR(syscall(SYS_SCHED_GETSCHEDULER, -5), EINVAL, "sched_getscheduler with negative pid returns EINVAL"); + + // NULL param -> EINVAL + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, 0, SCHED_OTHER, NULL), EINVAL, "sched_setscheduler with NULL param returns EINVAL"); + + // invalid policy + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, 0, 0xdeadbeef, &sp), EINVAL, "sched_setscheduler with invalid policy returns EINVAL"); + + // FIFO | RESET_ON_FORK is valid combination + sp.sched_priority = 2; + CHECK_RET(syscall(SYS_SCHED_SETSCHEDULER, 0, policy, &sp), 0, "sched_setscheduler with SCHED_RESET_ON_FORK should succeed"); + + // SCHED_OTHER with non-zero priority + sp.sched_priority = 1; + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, 0, SCHED_OTHER, &sp), EINVAL, "sched_setscheduler SCHED_OTHER with nonzero priority returns EINVAL"); + sp.sched_priority = 0; + + // SCHED_BATCH with non-zero priority + sp.sched_priority = 1; + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, 0, SCHED_BATCH, &sp), EINVAL, "sched_setscheduler SCHED_BATCH with nonzero priority returns EINVAL"); + sp.sched_priority = 0; + + // SCHED_IDLE with non-zero priority + sp.sched_priority = 1; + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, 0, SCHED_IDLE, &sp), EINVAL, "sched_setscheduler SCHED_IDLE with nonzero priority returns EINVAL"); + sp.sched_priority = 0; + + // sched_getscheduler(0) + CHECK(syscall(SYS_SCHED_GETSCHEDULER, 0) >= 0, "sched_getscheduler(0) returns non-negative policy"); + + // fake pid -> ESRCH + CHECK_ERR(syscall(SYS_SCHED_GETSCHEDULER, 999999), ESRCH, "sched_getscheduler for non-existent pid returns ESRCH"); + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, 999999, SCHED_OTHER, &sp), ESRCH, "sched_setscheduler for non-existent pid returns ESRCH"); + + // ==== EPERM: sched_setscheduler permission test (fork-based) ==== + { + pid_t target = fork(); + if (target == 0) { + while (1) pause(); // child stays alive + } + + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(0, &mask); + + uid_t my_euid = geteuid(); + + // fork child: uid/euid == parent (no /proc parsing needed) + uid_t target_ruid = my_euid; + uid_t target_euid = my_euid; + + if (my_euid == target_ruid || my_euid == target_euid || has_cap_sys_nice()) { + CHECK_RET(syscall(SYS_SCHED_SETSCHEDULER, target, SCHED_OTHER, &sp), 0, + "sched_setscheduler forked child allowed returns 0"); + } else { + CHECK_ERR(syscall(SYS_SCHED_SETSCHEDULER, target, SCHED_OTHER, &sp), EPERM, + "sched_setscheduler forked child returns EPERM"); + } + + kill(target, SIGKILL); + waitpid(target, NULL, 0); + } + } + + // 测试 sched_getparam() 边界条件和权限 + { + struct sched_param gp; + memset(&gp, 0, sizeof(gp)); + + int pol, prio; + CHECK_RET(syscall(SYS_SCHED_GETPARAM, 0, &gp), 0, "sched_getparam for current pid returns 0"); + + pol = syscall(SYS_SCHED_GETSCHEDULER, 0); + prio = gp.sched_priority; + + if (pol == SCHED_FIFO || pol == SCHED_RR) { + CHECK(prio >= 1 && prio <= 99, "RT priority range"); + } else { + CHECK(prio == 0, "non-RT priority must be 0"); + } + + // fake pid -> ESRCH + CHECK_ERR(syscall(SYS_SCHED_GETPARAM, 999999, &gp), ESRCH, "sched_getparam for non-existent pid returns ESRCH"); + } + + // ==== getpriority 边界条件测试 ==== + { + int pr; + + errno = 0; + pr = getpriority(PRIO_PROCESS, 0); + CHECK(errno == 0, "getpriority(PRIO_PROCESS,0) does not set errno"); + CHECK(pr >= -20 && pr <= 19, "getpriority(PRIO_PROCESS,0) returns raw priority in -20..19"); + + errno = 0; + pr = getpriority(PRIO_PGRP, 0); + CHECK(errno == 0, "getpriority(PRIO_PGRP,0) does not set errno"); + CHECK(pr >= -20 && pr <= 19, "getpriority(PRIO_PGRP,0) returns raw priority in -20..19"); + + errno = 0; + pr = getpriority(PRIO_USER, 0); + CHECK(errno == 0, "getpriority(PRIO_USER,0) does not set errno"); + CHECK(pr >= -20 && pr <= 19, "getpriority(PRIO_USER,0) returns raw priority in -20..19"); + + // invalid which -> EINVAL + CHECK_ERR(getpriority(0xdead, 0), EINVAL, "getpriority with invalid which returns EINVAL"); + + // nonexistent pid -> ESRCH + CHECK_ERR(getpriority(PRIO_PROCESS, 999999), ESRCH, "getpriority for non-existent pid returns ESRCH"); + } + + TEST_DONE(); +} diff --git a/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/src/test_framework.h b/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/src/test_framework.h new file mode 100644 index 0000000000..f0f7d0b899 --- /dev/null +++ b/test-suit/starryos/normal/qemu-smp4/test-sched-family/c/src/test_framework.h @@ -0,0 +1,90 @@ +#pragma once + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE + +#endif +#if defined(__x86_64__) + #define SYS_SCHED_GETPARAM 143 + #define SYS_SCHED_GETSCHEDULER 145 + #define SYS_SCHED_SETSCHEDULER 144 + +#elif defined(__riscv) + #define SYS_SCHED_GETPARAM 121 + #define SYS_SCHED_GETSCHEDULER 120 + #define SYS_SCHED_SETSCHEDULER 119 + +#elif defined(__aarch64__) + #define SYS_SCHED_GETPARAM 121 + #define SYS_SCHED_GETSCHEDULER 120 + #define SYS_SCHED_SETSCHEDULER 119 + +#elif defined(__loongarch64) + #define SYS_SCHED_GETPARAM 121 + #define SYS_SCHED_GETSCHEDULER 120 + #define SYS_SCHED_SETSCHEDULER 119 + +#else + #error "unsupported architecture for sched syscalls" +#endif + +#include +#include +#include +#include + +static int __pass = 0; +static int __fail = 0; + +#define CHECK(cond, msg) do { \ + if (cond) { \ + printf(" PASS | %s:%d | %s\n", __FILE__, __LINE__, msg); \ + __pass++; \ + } else { \ + printf(" FAIL | %s:%d | %s | errno=%d (%s)\n", \ + __FILE__, __LINE__, msg, errno, strerror(errno)); \ + __fail++; \ + } \ +} while(0) + +#define CHECK_RET(call, expected, msg) do { \ + errno = 0; \ + long _r = (long)(call); \ + long _e = (long)(expected); \ + if (_r == _e) { \ + printf(" PASS | %s:%d | %s (ret=%ld)\n", \ + __FILE__, __LINE__, msg, _r); \ + __pass++; \ + } else { \ + printf(" FAIL | %s:%d | %s | expected=%ld got=%ld | errno=%d (%s)\n", \ + __FILE__, __LINE__, msg, _e, _r, errno, strerror(errno));\ + __fail++; \ + } \ +} while(0) + +#define CHECK_ERR(call, exp_errno, msg) do { \ + errno = 0; \ + long _r = (long)(call); \ + if (_r == -1 && errno == (exp_errno)) { \ + printf(" PASS | %s:%d | %s (errno=%d as expected)\n", \ + __FILE__, __LINE__, msg, errno); \ + __pass++; \ + } else { \ + printf(" FAIL | %s:%d | %s | expected errno=%d got ret=%ld errno=%d (%s)\n", \ + __FILE__, __LINE__, msg, (int)(exp_errno), _r, errno, strerror(errno));\ + __fail++; \ + } \ +} while(0) + +#define TEST_START(name) \ + printf("================================================\n"); \ + printf(" TEST: %s\n", name); \ + printf(" FILE: %s\n", __FILE__); \ + printf("================================================\n") + +#define TEST_DONE() \ + printf("------------------------------------------------\n"); \ + printf(" DONE: %d pass, %d fail\n", __pass, __fail); \ + printf("================================================\n\n"); \ + return __fail > 0 ? 1 : 0 + \ No newline at end of file diff --git a/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-aarch64.toml b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-aarch64.toml new file mode 100644 index 0000000000..62e5b9d5cb --- /dev/null +++ b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-aarch64.toml @@ -0,0 +1,16 @@ +args = [ + "-nographic", "-cpu", "cortex-a53", + "-m", "512M", + "-smp", "4", + "-device", "virtio-blk-pci,drive=disk0", + "-drive", "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-aarch64-alpine.img", + "-device", "virtio-net-pci,netdev=net0", + "-netdev", "user,id=net0", +] +uefi = false +to_bin = true +shell_prefix = "root@starry:" +shell_init_cmd = "/usr/bin/test-sched-family" +success_regex = ["(?m)DONE: \\d+ pass, 0 fail"] +fail_regex = ['(?i)\bpanic(?:ked)?\b', '(?m)FAIL'] +timeout = 120 diff --git a/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-loongarch64.toml b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-loongarch64.toml new file mode 100644 index 0000000000..f85185f44e --- /dev/null +++ b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-loongarch64.toml @@ -0,0 +1,18 @@ +args = [ + "-machine", "virt", + "-cpu", "la464", + "-nographic", + "-m", "512M", + "-smp", "4", + "-device", "virtio-blk-pci,drive=disk0", + "-drive", "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-loongarch64-alpine.img", + "-device", "virtio-net-pci,netdev=net0", + "-netdev", "user,id=net0", +] +uefi = false +to_bin = true +shell_prefix = "root@starry:" +shell_init_cmd = "/usr/bin/test-sched-family" +success_regex = ["(?m)DONE: \\d+ pass, 0 fail"] +fail_regex = ['(?i)\bpanic(?:ked)?\b', '(?m)FAIL'] +timeout = 120 diff --git a/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-riscv64.toml b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-riscv64.toml new file mode 100644 index 0000000000..d114a26a68 --- /dev/null +++ b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-riscv64.toml @@ -0,0 +1,16 @@ +args = [ + "-nographic", "-cpu", "rv64", + "-m", "512M", + "-smp", "4", + "-device", "virtio-blk-pci,drive=disk0", + "-drive", "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img", + "-device", "virtio-net-pci,netdev=net0", + "-netdev", "user,id=net0", +] +uefi = false +to_bin = true +shell_prefix = "root@starry:" +shell_init_cmd = "/usr/bin/test-sched-family" +success_regex = ["(?m)DONE: \\d+ pass, 0 fail"] +fail_regex = ['(?i)\bpanic(?:ked)?\b', '(?m)FAIL'] +timeout = 360 diff --git a/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-x86_64.toml b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-x86_64.toml new file mode 100644 index 0000000000..821fbc5876 --- /dev/null +++ b/test-suit/starryos/normal/qemu-smp4/test-sched-family/qemu-x86_64.toml @@ -0,0 +1,27 @@ +target = "x86_64-unknown-none" +env = { AX_IP = "10.0.2.15", AX_GW = "10.0.2.2" } +features = [ + "qemu", +] +plat_dyn = false +max_cpu_num = 4 +log = "Warn" +args = [ + "-nographic", + "-m", "512M", + "-smp", "4", + "-device", "virtio-blk-pci,drive=disk0", + "-drive", "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-x86_64-alpine.img", + "-device", "virtio-net-pci,netdev=net0", + "-netdev", "user,id=net0", +] +uefi = false +to_bin = false +shell_prefix = "root@starry:" +shell_init_cmd = "/usr/bin/test-sched-family" +success_regex = ["(?m)DONE: \\d+ pass, 0 fail"] +fail_regex = [ + '(?i)\\bpanic(?:ked)?\\b', + '(?m)FAIL' +] +timeout = 120