From 35a6caa54178d602dae3c9cbc9b16859df96f4b9 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sat, 20 Dec 2025 15:42:08 -0800 Subject: [PATCH] Implement sys_sysinfo (#71) --- etc/syscalls_linux_aarch64.md | 2 +- libkernel/src/memory/page_alloc.rs | 12 ++++ src/arch/arm64/exceptions/syscall.rs | 2 + src/kernel/mod.rs | 1 + src/kernel/sysinfo.rs | 92 ++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/kernel/sysinfo.rs diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index 6797b5c..66b3275 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -179,7 +179,7 @@ | 0xb0 (176) | getgid | () | __arm64_sys_getgid | true | | 0xb1 (177) | getegid | () | __arm64_sys_getegid | true | | 0xb2 (178) | gettid | () | __arm64_sys_gettid | true | -| 0xb3 (179) | sysinfo | (struct sysinfo *info) | __arm64_sys_sysinfo | false | +| 0xb3 (179) | sysinfo | (struct sysinfo *info) | __arm64_sys_sysinfo | true | | 0xb4 (180) | mq_open | (const char *u_name, int oflag, umode_t mode, struct mq_attr *u_attr) | __arm64_sys_mq_open | false | | 0xb5 (181) | mq_unlink | (const char *u_name) | __arm64_sys_mq_unlink | false | | 0xb6 (182) | mq_timedsend | (mqd_t mqdes, const char *u_msg_ptr, size_t msg_len, unsigned int msg_prio, const struct __kernel_timespec *u_abs_timeout) | __arm64_sys_mq_timedsend | false | diff --git a/libkernel/src/memory/page_alloc.rs b/libkernel/src/memory/page_alloc.rs index f8ef7a2..f60035d 100644 --- a/libkernel/src/memory/page_alloc.rs +++ b/libkernel/src/memory/page_alloc.rs @@ -331,6 +331,18 @@ impl FrameAllocator { } } + /// Returns the total number of pages managed by this allocator. + #[inline] + pub fn total_pages(&self) -> usize { + self.inner.lock_save_irq().total_pages + } + + /// Returns the current number of free pages available for allocation. + #[inline] + pub fn free_pages(&self) -> usize { + self.inner.lock_save_irq().free_pages + } + /// Initializes the frame allocator. This is the main bootstrap function. /// /// # Safety diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index f97d503..3a8956e 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -28,6 +28,7 @@ use crate::{ sync::sys_sync, }, }, + kernel::sysinfo::sys_sysinfo, kernel::uname::sys_uname, memory::{ brk::sys_brk, @@ -231,6 +232,7 @@ pub async fn handle_syscall() { 0xb0 => sys_getgid().map_err(|e| match e {}), 0xb1 => sys_getegid().map_err(|e| match e {}), 0xb2 => sys_gettid().map_err(|e| match e {}), + 0xb3 => sys_sysinfo(TUA::from_value(arg1 as _)).await, 0xc6 => Err(KernelError::NotSupported), 0xd6 => sys_brk(VA::from_value(arg1 as _)) .await diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index a2a5316..7796e65 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,4 +1,5 @@ pub mod kpipe; pub mod power; pub mod rand; +pub mod sysinfo; pub mod uname; diff --git a/src/kernel/sysinfo.rs b/src/kernel/sysinfo.rs new file mode 100644 index 0000000..08790e0 --- /dev/null +++ b/src/kernel/sysinfo.rs @@ -0,0 +1,92 @@ +use crate::drivers::timer::uptime; +use crate::memory::uaccess::{UserCopyable, copy_to_user}; +use crate::{memory::PAGE_ALLOC, process::TASK_LIST}; +use core::mem::size_of; +use libkernel::memory::PAGE_SIZE; +use libkernel::{error::Result, memory::address::TUA}; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SysInfo { + /// Seconds since boot + pub uptime: u64, + /// 1, 5, and 15 minute load averages + pub loads: [u64; 3], + /// Total usable main memory size + pub total_ram: u64, + /// Available memory size + pub free_ram: u64, + /// Amount of shared memory + pub shared_ram: u64, + /// Memory used by buffers + pub buffer_ram: u64, + /// Total swap space size + pub total_swap: u64, + /// Swap space still available + pub free_swap: u64, + /// Number of current processes + pub procs: u32, + /// Total high memory size + pub total_high: u64, + /// Available high memory size + pub free_high: u64, + /// Memory unit size in bytes + pub mem_unit: u32, +} + +impl SysInfo { + pub fn new() -> SysInfo { + // Gather memory statistics from the global page allocator. + let page_alloc = PAGE_ALLOC.get().expect("PAGE_ALLOC must be initialised"); + + let total_pages = page_alloc.total_pages(); + let free_pages = page_alloc.free_pages(); + + let total_ram = (total_pages * PAGE_SIZE) as u64; + let free_ram = (free_pages * PAGE_SIZE) as u64; + + // Count the number of processes currently known to the scheduler. + let procs = TASK_LIST.lock_save_irq().len() as u32; + + SysInfo { + uptime: uptime().as_secs(), + loads: [0, 0, 0], // TODO: implement actual load averages + total_ram, + free_ram, + shared_ram: 0, + buffer_ram: 0, + total_swap: 0, + free_swap: 0, + procs, + total_high: 0, + free_high: 0, + mem_unit: 1, // All memory figures are given in bytes + } + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PaddedSysInfo { + pub info: SysInfo, + /// Padding to 64 bytes + _f: [u8; 20 - (2 * size_of::()) - size_of::()], +} + +impl From for PaddedSysInfo { + fn from(info: SysInfo) -> Self { + Self { + info, + _f: [0; 20 - (2 * size_of::()) - size_of::()], + } + } +} + +unsafe impl UserCopyable for PaddedSysInfo {} + +pub async fn sys_sysinfo(info_ptr: TUA) -> Result { + // Build the structure in kernel memory first + let padded = PaddedSysInfo::from(SysInfo::new()); + copy_to_user(info_ptr, padded).await?; + Ok(0) +}