starry-kernel 0.10.0

A Linux-compatible OS kernel built on ArceOS unikernel
Documentation
use crate::{
    StarryError, StarryResult,
    task::{PidView, UserTaskRef},
};

#[inline(never)]
pub fn sys_getpid(current: &UserTaskRef) -> StarryResult<isize> {
    Ok(current
        .as_thread()
        .proc_data
        .identity()
        .active_number()
        .get() as isize)
}

pub fn sys_getppid(current: &crate::task::UserTaskRef) -> crate::StarryResult<isize> {
    let parent = current
        .as_thread()
        .proc_data
        .proc
        .parent()
        .ok_or(StarryError::NoSuchProcess)?;
    Ok(PidView::new(current.as_thread().active_pid_namespace())
        .visible_process_number(&parent.identity())
        .map_or(0, |pid| pid.get() as isize))
}

pub fn sys_gettid(current: &crate::task::UserTaskRef) -> crate::StarryResult<isize> {
    // `Thread::tid` rather than the scheduler ID: after a non-leader
    // `execve` they differ (the calling thread inherits the leader's TID
    // so that `gettid() == getpid()` holds in the new image).
    Ok(current.as_thread().user_tid().get() as _)
}

/// `getcpu(2)`: report the CPU and NUMA node the caller is running on.
///
/// glibc's `sched_getcpu` and NUMA-aware allocators query this. We report the
/// current CPU id and node 0 (single NUMA node); the obsolete `tcache` arg is
/// ignored. Either pointer may be NULL.
pub fn sys_getcpu(
    current: &crate::task::UserTaskRef,
    cpu: *mut u32,
    node: *mut u32,
    _tcache: usize,
) -> crate::StarryResult<isize> {
    use ax_runtime::hal::percpu::this_cpu_id;

    use crate::mm::VmMutPtr;

    if !cpu.is_null() {
        cpu.vm_write(current, this_cpu_id() as u32)?;
    }
    if !node.is_null() {
        node.vm_write(current, 0)?;
    }
    Ok(0)
}

/// ARCH_PRCTL codes
///
/// It is only available on x86_64, and is not convenient
/// to generate automatically via c_to_rust binding.
#[cfg(target_arch = "x86_64")]
#[derive(Debug, Eq, PartialEq, num_enum::TryFromPrimitive)]
#[repr(i32)]
enum ArchPrctlCode {
    /// Set the GS segment base
    SetGs    = 0x1001,
    /// Set the FS segment base
    SetFs    = 0x1002,
    /// Get the FS segment base
    GetFs    = 0x1003,
    /// Get the GS segment base
    GetGs    = 0x1004,
    /// The setting of the flag manipulated by ARCH_SET_CPUID
    GetCpuid = 0x1011,
    /// Enable (addr != 0) or disable (addr == 0) the cpuid instruction for the
    /// calling thread.
    SetCpuid = 0x1012,
}

/// To set the clear_child_tid field in the task extended data.
///
/// The set_tid_address() always succeeds
pub fn sys_set_tid_address(
    current: &crate::task::UserTaskRef,
    clear_child_tid: usize,
) -> crate::StarryResult<isize> {
    let curr = current;
    let thr = curr.as_thread();
    thr.set_clear_child_tid(clear_child_tid);
    Ok(thr.user_tid().get() as isize)
}

#[cfg(target_arch = "x86_64")]
pub fn sys_arch_prctl(
    current: &crate::task::UserTaskRef,
    uctx: &mut ax_runtime::hal::cpu::user::UserContext,
    code: i32,
    addr: usize,
) -> crate::StarryResult<isize> {
    use crate::mm::VmMutPtr;

    let code = ArchPrctlCode::try_from(code).map_err(|_| StarryError::InvalidInput)?;
    debug!("sys_arch_prctl: code = {code:?}, addr = {addr:#x}");

    match code {
        // According to Linux implementation, SetFs & SetGs does not return
        // error at all
        ArchPrctlCode::GetFs => {
            (addr as *mut usize).vm_write(current, uctx.tls())?;
            Ok(0)
        }
        ArchPrctlCode::SetFs => {
            uctx.set_tls(addr);
            Ok(0)
        }
        ArchPrctlCode::GetGs => {
            (addr as *mut usize).vm_write(current, uctx.gs_base as _)?;
            Ok(0)
        }
        ArchPrctlCode::SetGs => {
            uctx.gs_base = addr as _;
            Ok(0)
        }
        // Linux get_cpuid_mode() returns 1 (ARCH_CPUID_ENABLE) when the CPUID
        // instruction is enabled for the thread and 0 when it faults. StarryOS
        // never installs CPUID faulting, so CPUID is always enabled and GET must
        // report 1 rather than a hardcoded 0. SET stays ENODEV: without faulting
        // support Linux rejects every requested mode.
        ArchPrctlCode::GetCpuid => Ok(1),
        ArchPrctlCode::SetCpuid => Err(crate::StarryError::NoSuchDevice),
    }
}