From 530eb841db5ae49e208e074e79d9baad9d2e438b Mon Sep 17 00:00:00 2001 From: Vasilito Date: Sat, 25 Apr 2026 18:07:46 +0100 Subject: [PATCH] Add relibc fenv and sched POSIX implementations P3-fenv: x86_64 SSE/x87 inline asm for 10 FP environment functions (feclearexcept, fegetenv, fegetexceptflag, fegetround, feholdexcept, feraiseexcept, fesetenv, fesetexceptflag, fesetround, fetestexcept, feupdateenv) with proper MXCSR and x87 CW register access. P3-sched: 6 scheduler functions (sched_get_priority_max/min, sched_getparam, sched_rr_get_interval, sched_setparam, sched_setscheduler) with EINVAL for bad policy and no-op validation since Redox has no real-time scheduler. --- local/patches/relibc/P3-fenv.patch | 230 ++++++++++++++++++++++++++++ local/patches/relibc/P3-sched.patch | 124 +++++++++++++++ recipes/core/relibc/recipe.toml | 2 + 3 files changed, 356 insertions(+) create mode 100644 local/patches/relibc/P3-fenv.patch create mode 100644 local/patches/relibc/P3-sched.patch diff --git a/local/patches/relibc/P3-fenv.patch b/local/patches/relibc/P3-fenv.patch new file mode 100644 index 00000000..54b958fe --- /dev/null +++ b/local/patches/relibc/P3-fenv.patch @@ -0,0 +1,230 @@ +diff --git a/src/header/_fenv/mod.rs b/src/header/_fenv/mod.rs +--- a/src/header/_fenv/mod.rs ++++ b/src/header/_fenv/mod.rs +@@ -4,82 +4,207 @@ + + use crate::platform::types::c_int; + +-/// See . +-pub const FE_ALL_EXCEPT: c_int = 0; +-/// See . +-pub const FE_TONEAREST: c_int = 0; ++// x86_64 SSE floating-point exception flags (MXCSR bits 0-5, excluding denormal bit 1) ++pub const FE_INVALID: c_int = 0x01; ++pub const FE_DIVBYZERO: c_int = 0x04; ++pub const FE_OVERFLOW: c_int = 0x08; ++pub const FE_UNDERFLOW: c_int = 0x10; ++pub const FE_INEXACT: c_int = 0x20; ++/// See . ++pub const FE_ALL_EXCEPT: c_int = ++ FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT; ++ ++// x86_64 rounding modes (MXCSR bits 13-14, x87 CW bits 10-11) ++/// See . ++pub const FE_TONEAREST: c_int = 0x000; ++pub const FE_DOWNWARD: c_int = 0x400; ++pub const FE_UPWARD: c_int = 0x800; ++pub const FE_TOWARDZERO: c_int = 0xC00; + + /// See . + pub type fexcept_t = u64; + + /// See . + #[repr(C)] + pub struct fenv_t { +- pub cw: u64, ++ pub cw: u32, // x87 control word (zero-extended from u16) ++ pub mxcsr: u32, // SSE MXCSR register + } + ++/// Read the x87 FPU control word. ++#[inline] ++unsafe fn fnstcw() -> u16 { ++ let mut cw: u16 = 0; ++ core::arch::asm!( ++ "fnstcw ({0})", ++ in(reg) &mut cw, ++ options(nostack, preserves_flags) ++ ); ++ cw ++} ++ ++/// Load the x87 FPU control word. ++#[inline] ++unsafe fn fldcw(cw: u16) { ++ core::arch::asm!( ++ "fldcw ({0})", ++ in(reg) &cw, ++ options(nostack, preserves_flags) ++ ); ++} ++ ++/// Read the SSE MXCSR register. ++#[inline] ++unsafe fn stmxcsr() -> u32 { ++ let mut mxcsr: u32 = 0; ++ core::arch::asm!( ++ "stmxcsr ({0})", ++ in(reg) &mut mxcsr, ++ options(nostack, preserves_flags) ++ ); ++ mxcsr ++} ++ ++/// Write the SSE MXCSR register. ++#[inline] ++unsafe fn ldmxcsr(val: u32) { ++ core::arch::asm!( ++ "ldmxcsr ({0})", ++ in(reg) &val, ++ options(nostack, preserves_flags) ++ ); ++} ++ + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn feclearexcept(excepts: c_int) -> c_int { +- unimplemented!(); ++ let mask = (excepts & FE_ALL_EXCEPT) as u32; ++ if mask != 0 { ++ let mxcsr = stmxcsr(); ++ ldmxcsr(mxcsr & !mask); ++ // Clear x87 status word exception flags ++ core::arch::asm!("fnclex", options(nostack, preserves_flags)); ++ } ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn fegetenv(envp: *mut fenv_t) -> c_int { +- unimplemented!(); ++ if envp.is_null() { ++ return 1; ++ } ++ (*envp).cw = fnstcw() as u32; ++ (*envp).mxcsr = stmxcsr(); ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn fegetexceptflag(flagp: *mut fexcept_t, excepts: c_int) -> c_int { +- unimplemented!(); ++ if flagp.is_null() { ++ return 1; ++ } ++ let mxcsr = stmxcsr(); ++ *flagp = (mxcsr & FE_ALL_EXCEPT as u32 & excepts as u32) as fexcept_t; ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn fegetround() -> c_int { +- FE_TONEAREST ++ let mxcsr = stmxcsr(); ++ (mxcsr & 0xC00) as c_int + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn feholdexcept(envp: *mut fenv_t) -> c_int { +- unimplemented!(); ++ if envp.is_null() { ++ return 1; ++ } ++ // Save current environment ++ (*envp).cw = fnstcw() as u32; ++ (*envp).mxcsr = stmxcsr(); ++ // Clear all exception flags and set non-stop mode (unmask all exceptions) ++ // MXCSR: clear status bits 0-5, clear mask bits 7-12 ++ let mxcsr = stmxcsr(); ++ ldmxcsr(mxcsr & !(FE_ALL_EXCEPT as u32) & !((FE_ALL_EXCEPT as u32) << 7)); ++ // x87: clear exception mask bits (bits 0-5 in CW) and clear status ++ let cw = fnstcw(); ++ fldcw(cw & !0x3F); ++ core::arch::asm!("fnclex", options(nostack, preserves_flags)); ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn feraiseexcept(excepts: c_int) -> c_int { +- unimplemented!(); ++ let mask = (excepts & FE_ALL_EXCEPT) as u32; ++ if mask == 0 { ++ return 0; ++ } ++ // Set exception status flags in MXCSR ++ let mxcsr = stmxcsr(); ++ ldmxcsr(mxcsr | mask); ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn fesetenv(envp: *const fenv_t) -> c_int { +- unimplemented!(); ++ if envp.is_null() { ++ // Restore default environment ++ fldcw(0x037F); // x87 default CW: all exceptions masked, double precision ++ ldmxcsr(0x1F80); // MXCSR default: all exceptions masked, round-to-nearest ++ return 0; ++ } ++ fldcw((*envp).cw as u16); ++ ldmxcsr((*envp).mxcsr); ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn fesetexceptflag(flagp: *const fexcept_t, excepts: c_int) -> c_int { +- unimplemented!(); ++ if flagp.is_null() { ++ return 1; ++ } ++ let mask = (excepts & FE_ALL_EXCEPT) as u32; ++ let mxcsr = stmxcsr(); ++ let flags = (*flagp as u32) & mask; ++ ldmxcsr((mxcsr & !mask) | flags); ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn fesetround(round: c_int) -> c_int { +- unimplemented!(); ++ let rm = round & 0xC00; ++ if rm != FE_TONEAREST && rm != FE_DOWNWARD && rm != FE_UPWARD && rm != FE_TOWARDZERO { ++ return 1; ++ } ++ // Set rounding mode in MXCSR (bits 13-14) ++ let mxcsr = stmxcsr(); ++ ldmxcsr((mxcsr & !0xC00u32) | rm as u32); ++ // Set rounding mode in x87 CW (bits 10-11) ++ let cw = fnstcw(); ++ fldcw((cw & !0x0C00) | rm as u16); ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn fetestexcept(excepts: c_int) -> c_int { +- unimplemented!(); ++ let mxcsr = stmxcsr(); ++ (mxcsr & FE_ALL_EXCEPT as u32 & excepts as u32) as c_int + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn feupdateenv(envp: *const fenv_t) -> c_int { +- unimplemented!(); ++ let mxcsr = stmxcsr(); ++ let excepts = (mxcsr & FE_ALL_EXCEPT as u32) as c_int; ++ if fesetenv(envp) != 0 { ++ return 1; ++ } ++ feraiseexcept(excepts); ++ 0 + } diff --git a/local/patches/relibc/P3-sched.patch b/local/patches/relibc/P3-sched.patch new file mode 100644 index 00000000..84f4a65b --- /dev/null +++ b/local/patches/relibc/P3-sched.patch @@ -0,0 +1,124 @@ +diff --git a/src/header/sched/mod.rs b/src/header/sched/mod.rs +--- a/src/header/sched/mod.rs ++++ b/src/header/sched/mod.rs +@@ -2,9 +2,11 @@ + //! + //! See . + + use crate::{ + error::ResultExt, +- header::bits_timespec::timespec, ++ header::{bits_timespec::timespec, errno}, + platform::{ +- Pal, Sys, ++ self, Pal, Sys, + types::{c_int, pid_t}, + }, + }; +@@ -29,42 +31,67 @@ + pub const SCHED_OTHER: c_int = 2; + + /// See . + // #[unsafe(no_mangle)] + pub extern "C" fn sched_get_priority_max(policy: c_int) -> c_int { +- todo!() ++ match policy { ++ SCHED_FIFO | SCHED_RR => 99, ++ SCHED_OTHER => 0, ++ _ => { ++ platform::ERRNO.set(errno::EINVAL); ++ -1 ++ } ++ } + } + + /// See . + // #[unsafe(no_mangle)] + pub extern "C" fn sched_get_priority_min(policy: c_int) -> c_int { +- todo!() ++ match policy { ++ SCHED_FIFO | SCHED_RR => 0, ++ SCHED_OTHER => 0, ++ _ => { ++ platform::ERRNO.set(errno::EINVAL); ++ -1 ++ } ++ } + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn sched_getparam(pid: pid_t, param: *mut sched_param) -> c_int { +- todo!() ++ if param.is_null() { ++ platform::ERRNO.set(errno::EINVAL); ++ return -1; ++ } ++ // Redox has no real-time scheduler; return default params ++ (*param).sched_priority = 0; ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub extern "C" fn sched_rr_get_interval(pid: pid_t, time: *const timespec) -> c_int { +- todo!() ++ if time.is_null() { ++ platform::ERRNO.set(errno::EINVAL); ++ return -1; ++ } ++ // Redox has no real-time scheduler; report a nominal 1-second round-robin interval ++ unsafe { ++ (*(time as *mut timespec)).tv_sec = 1; ++ (*(time as *mut timespec)).tv_nsec = 0; ++ } ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub unsafe extern "C" fn sched_setparam(pid: pid_t, param: *const sched_param) -> c_int { +- todo!() ++ if param.is_null() { ++ platform::ERRNO.set(errno::EINVAL); ++ return -1; ++ } ++ let priority = (*param).sched_priority; ++ if priority < 0 || priority > 99 { ++ platform::ERRNO.set(errno::EINVAL); ++ return -1; ++ } ++ // Redox has no real-time scheduler; validate and succeed as a no-op ++ 0 + } + + /// See . + // #[unsafe(no_mangle)] + pub extern "C" fn sched_setscheduler( + pid: pid_t, + policy: c_int, + param: *const sched_param, + ) -> c_int { +- todo!() ++ if param.is_null() { ++ platform::ERRNO.set(errno::EINVAL); ++ return -1; ++ } ++ match policy { ++ SCHED_FIFO | SCHED_RR | SCHED_OTHER => { ++ let priority = unsafe { (*param).sched_priority }; ++ if priority < 0 || priority > 99 { ++ platform::ERRNO.set(errno::EINVAL); ++ return -1; ++ } ++ // Redox has no real-time scheduler; validate and succeed as a no-op ++ 0 ++ } ++ _ => { ++ platform::ERRNO.set(errno::EINVAL); ++ -1 ++ } ++ } + } + + /// See . diff --git a/recipes/core/relibc/recipe.toml b/recipes/core/relibc/recipe.toml index 6e79992c..a84e43f5 100644 --- a/recipes/core/relibc/recipe.toml +++ b/recipes/core/relibc/recipe.toml @@ -34,6 +34,8 @@ patches = [ "../../../local/patches/relibc/P3-sysv-sem-impl.patch", "../../../local/patches/relibc/P3-sysv-shm-impl.patch", "../../../local/patches/relibc/P3-waitid-header.patch", + "../../../local/patches/relibc/P3-fenv.patch", + "../../../local/patches/relibc/P3-sched.patch", ] [build]