From 339271b4d724b2f20f0f7a7a97f4ba35ddc62e57 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 8 Sep 2024 22:21:55 +0200 Subject: [PATCH] Add getdents syscall, and switch schemes to it. --- Cargo.toml | 1 + src/arch/x86_64/rmm.rs | 12 ++-- src/main.rs | 2 - src/panic.rs | 1 + src/scheme/acpi.rs | 29 +++++--- src/scheme/irq.rs | 101 ++++++++++++--------------- src/scheme/mod.rs | 3 + src/scheme/root.rs | 78 ++++++++------------- src/scheme/sys/mod.rs | 108 +++++++++++++++-------------- src/scheme/user.rs | 23 ++++++ src/syscall/debug.rs | 2 +- src/syscall/mod.rs | 16 ++++- src/syscall/usercopy.rs | 21 ++++++ syscall | 2 +- targets/x86_64-unknown-kernel.json | 2 +- 15 files changed, 224 insertions(+), 177 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3d891a35fd..87ff6012c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ default = [ "serial_debug", "self_modifying", "x86_kvm_pv", + "syscall_debug", ] # Activates some limited code-overwriting optimizations, based on CPU features. diff --git a/src/arch/x86_64/rmm.rs b/src/arch/x86_64/rmm.rs index 372b49dd78..65ed22366d 100644 --- a/src/arch/x86_64/rmm.rs +++ b/src/arch/x86_64/rmm.rs @@ -296,19 +296,19 @@ pub unsafe fn init( let real_size = 0x100000; let real_end = real_base + real_size; - let kernel_size_aligned = ((kernel_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE; + let kernel_size_aligned = kernel_size.next_multiple_of(A::PAGE_SIZE); let kernel_end = kernel_base + kernel_size_aligned; - let stack_size_aligned = ((stack_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE; + let stack_size_aligned = stack_size.next_multiple_of(A::PAGE_SIZE); let stack_end = stack_base + stack_size_aligned; - let env_size_aligned = ((env_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE; + let env_size_aligned = env_size.next_multiple_of(A::PAGE_SIZE); let env_end = env_base + env_size_aligned; - let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE; + let acpi_size_aligned = acpi_size.next_multiple_of(A::PAGE_SIZE); let acpi_end = acpi_base + acpi_size_aligned; - let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE; + let initfs_size_aligned = initfs_size.next_multiple_of(A::PAGE_SIZE); let initfs_end = initfs_base + initfs_size_aligned; let bootloader_areas = slice::from_raw_parts( @@ -329,7 +329,7 @@ pub unsafe fn init( let mut base = bootloader_area.base as usize; let mut size = bootloader_area.size as usize; - log::debug!("{:X}:{:X}", base, size); + log::info!("{:X}:{:X}", base, size); // Page align base let base_offset = (A::PAGE_SIZE - (base & A::PAGE_OFFSET_MASK)) & A::PAGE_OFFSET_MASK; diff --git a/src/main.rs b/src/main.rs index 4e73c817a6..a2c18145bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,12 +42,10 @@ // Ensure that all must_use results are used #![deny(unused_must_use)] #![feature(allocator_api)] -#![feature(asm_const)] // TODO: Relax requirements of most asm invocations #![feature(int_roundings)] #![feature(iter_next_chunk)] #![feature(let_chains)] #![feature(naked_functions)] -#![feature(new_uninit)] #![feature(sync_unsafe_cell)] #![feature(variant_count)] #![no_std] diff --git a/src/panic.rs b/src/panic.rs index 92cb9879f2..50ba36a27e 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -8,6 +8,7 @@ use crate::{context, cpu_id, interrupt, syscall}; #[panic_handler] fn rust_begin_unwind(info: &PanicInfo) -> ! { println!("KERNEL PANIC: {}", info); + loop {} unsafe { interrupt::stack_trace(); diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index 277c33829a..4ae38b659b 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -7,6 +7,10 @@ use core::{ use alloc::{boxed::Box, collections::BTreeMap}; use spin::{Mutex, Once, RwLock}; +use syscall::{ + dirent::{DirentBuf, DirentKind}, + EIO, +}; use crate::{ acpi::{RxsdtEnum, RXSDT_ENUM}, @@ -47,8 +51,6 @@ static NEXT_FD: AtomicUsize = AtomicUsize::new(0); static DATA: Once> = Once::new(); -const TOPLEVEL_CONTENTS: &[u8] = b"rxsdt\nkstop\n"; - static KSTOP_WAITCOND: WaitCondition = WaitCondition::new(); static KSTOP_FLAG: Mutex = Mutex::new(false); @@ -169,7 +171,7 @@ impl KernelScheme for AcpiScheme { Ok(match handle.kind { HandleKind::Rxsdt => DATA.get().ok_or(Error::new(EBADFD))?.len() as u64, HandleKind::ShutdownPipe => 1, - HandleKind::TopLevel => TOPLEVEL_CONTENTS.len() as u64, + HandleKind::TopLevel => 0, }) } // TODO @@ -227,7 +229,7 @@ impl KernelScheme for AcpiScheme { return dst_buf.copy_exactly(&[0x42]).map(|()| 1); } HandleKind::Rxsdt => DATA.get().ok_or(Error::new(EBADFD))?, - HandleKind::TopLevel => TOPLEVEL_CONTENTS, + HandleKind::TopLevel => return Err(Error::new(EISDIR)), }; let src_offset = core::cmp::min(offset, data.len()); @@ -237,6 +239,20 @@ impl KernelScheme for AcpiScheme { dst_buf.copy_common_bytes_from_slice(src_buf) } + fn getdents(&self, id: usize, buf: UserSliceWo, header_size: u16) -> Result { + let Some(Handle { + kind: HandleKind::TopLevel, + .. + }) = HANDLES.read().get(&id) + else { + return Err(Error::new(ENOTDIR)); + }; + + let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?; + buf.entry(DirentKind::Regular, "rxsdt")?; + buf.entry(DirentKind::Socket, "kstop")?; + Ok(buf.finalize()) + } fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> { let handles = HANDLES.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; @@ -253,10 +269,7 @@ impl KernelScheme for AcpiScheme { } HandleKind::TopLevel => Stat { st_mode: MODE_DIR, - st_size: TOPLEVEL_CONTENTS - .len() - .try_into() - .unwrap_or(u64::max_value()), + st_size: 0, ..Default::default() }, HandleKind::ShutdownPipe => Stat { diff --git a/src/scheme/irq.rs b/src/scheme/irq.rs index da6e39cf93..238996c9aa 100644 --- a/src/scheme/irq.rs +++ b/src/scheme/irq.rs @@ -10,6 +10,7 @@ use core::{ use alloc::{collections::BTreeMap, string::String, vec::Vec}; use spin::{Mutex, Once, RwLock}; +use syscall::dirent::{DirentBuf, DirentKind}; use crate::{ arch::interrupt::{available_irqs_iter, bsp_apic_id, is_reserved, set_reserved}, @@ -68,8 +69,8 @@ pub extern "C" fn irq_trigger(irq: u8) { enum Handle { Irq { ack: AtomicUsize, irq: u8 }, - Avail(u8, Vec), // CPU id, data, offset - TopLevel(Vec), // data, offset + Avail(u8), // CPU id + TopLevel, Bsp, } impl Handle { @@ -175,27 +176,7 @@ impl crate::scheme::KernelScheme for IrqScheme { return Err(Error::new(EISDIR)); } - // list every logical CPU in the format of e.g. `cpu-1b` - - let mut bytes = String::new(); - - use core::fmt::Write; - - for cpu_id in CPUS.get().expect("IRQ scheme not initialized") { - writeln!(bytes, "cpu-{:02x}", cpu_id).unwrap(); - } - - if bsp_apic_id().is_some() { - writeln!(bytes, "bsp").unwrap(); - } - - // TODO: When signals are used for IRQs, there will probably also be a file - // `irq:signal` that maps IRQ numbers and their source APIC IDs to signal numbers. - - ( - Handle::TopLevel(bytes.into_bytes()), - InternalFlags::POSITIONED, - ) + (Handle::TopLevel, InternalFlags::POSITIONED) } else { if path_str == "bsp" { if bsp_apic_id().is_none() { @@ -208,21 +189,7 @@ impl crate::scheme::KernelScheme for IrqScheme { let path_str = path_str[2..].trim_end_matches('/'); if path_str.is_empty() { - let mut data = String::new(); - use core::fmt::Write; - - for vector in available_irqs_iter(LogicalCpuId::new(cpu_id.into())) { - let irq = vector_to_irq(vector); - if Some(u32::from(cpu_id)) == bsp_apic_id() && irq < BASE_IRQ_COUNT { - continue; - } - writeln!(data, "{}", irq).unwrap(); - } - - ( - Handle::Avail(cpu_id, data.into_bytes()), - InternalFlags::POSITIONED, - ) + (Handle::Avail(cpu_id), InternalFlags::POSITIONED) } else if path_str.starts_with('/') { let path_str = &path_str[1..]; Self::open_ext_irq(flags, cpu_id, path_str)? @@ -249,15 +216,39 @@ impl crate::scheme::KernelScheme for IrqScheme { HANDLES.write().insert(fd, handle); Ok(OpenResult::SchemeLocal(fd, int_flags)) } + fn getdents(&self, id: usize, buf: UserSliceWo, header_size: u16) -> Result { + use core::fmt::Write; - fn fsize(&self, id: usize) -> Result { - let handles_guard = HANDLES.read(); - let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?; + let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?; + let mut intermediate = String::new(); - match *handle { - Handle::Avail(_, ref buf) | Handle::TopLevel(ref buf) => Ok(buf.len() as u64), - _ => Err(Error::new(ESPIPE)), + match *HANDLES.read().get(&id).ok_or(Error::new(EBADF))? { + Handle::TopLevel => { + // list every logical CPU in the format of e.g. `cpu-1b` + for cpu_id in CPUS.get().expect("IRQ scheme not initialized") { + intermediate.clear(); + write!(&mut intermediate, "cpu-{:02x}", cpu_id).unwrap(); + buf.entry(DirentKind::Directory, &intermediate)?; + } + + if bsp_apic_id().is_some() { + buf.entry(DirentKind::CharDev, "bsp")?; + } + } + Handle::Avail(cpu_id) => { + for vector in available_irqs_iter(LogicalCpuId::new(cpu_id.into())) { + let irq = vector_to_irq(vector); + if Some(u32::from(cpu_id)) == bsp_apic_id() && irq < BASE_IRQ_COUNT { + continue; + } + intermediate.clear(); + write!(intermediate, "{}", irq).unwrap(); + buf.entry(DirentKind::CharDev, &intermediate)?; + } + } + _ => return Err(Error::new(ENOTDIR)), } + Ok(buf.finalize()) } fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result { @@ -345,16 +336,16 @@ impl crate::scheme::KernelScheme for IrqScheme { st_nlink: 1, ..Default::default() }, - Handle::Avail(cpu_id, ref buf) => Stat { + Handle::Avail(cpu_id) => Stat { st_mode: MODE_DIR | 0o700, - st_size: buf.len() as u64, + st_size: 0, st_ino: INO_AVAIL | u64::from(cpu_id) << 32, st_nlink: 2, ..Default::default() }, - Handle::TopLevel(ref buf) => Stat { + Handle::TopLevel => Stat { st_mode: MODE_DIR | 0o500, - st_size: buf.len() as u64, + st_size: 0, st_ino: INO_TOPLEVEL, st_nlink: 1, ..Default::default() @@ -370,8 +361,8 @@ impl crate::scheme::KernelScheme for IrqScheme { let scheme_path = match handle { Handle::Irq { irq, .. } => format!("irq:{}", irq), Handle::Bsp => format!("irq:bsp"), - Handle::Avail(cpu_id, _) => format!("irq:cpu-{:2x}", cpu_id), - Handle::TopLevel(_) => format!("irq:"), + Handle::Avail(cpu_id) => format!("irq:cpu-{:2x}", cpu_id), + Handle::TopLevel => format!("irq:"), } .into_bytes(); @@ -381,7 +372,7 @@ impl crate::scheme::KernelScheme for IrqScheme { &self, file: usize, buffer: UserSliceWo, - offset: u64, + _offset: u64, _flags: u32, _stored_flags: u32, ) -> Result { @@ -416,13 +407,7 @@ impl crate::scheme::KernelScheme for IrqScheme { Err(Error::new(EBADFD)) } } - Handle::Avail(_, ref buf) | Handle::TopLevel(ref buf) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| buf.get(o..)) - .unwrap_or(&[]); - buffer.copy_common_bytes_from_slice(src) - } + Handle::Avail(_) | Handle::TopLevel => Err(Error::new(EISDIR)), } } } diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index 454c344484..499cc65e47 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -451,6 +451,9 @@ pub trait KernelScheme: Send + Sync + 'static { ) -> Result { Err(Error::new(EOPNOTSUPP)) } + fn getdents(&self, id: usize, buf: UserSliceWo, header_size: u16) -> Result { + Err(Error::new(EOPNOTSUPP)) + } fn fsync(&self, id: usize) -> Result<()> { Ok(()) diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 08a2fa1c69..c7f3b699b7 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -5,7 +5,10 @@ use core::{ }; use hashbrown::HashMap; use spin::RwLock; -use syscall::O_FSYNC; +use syscall::{ + dirent::{DirentBuf, DirentKind}, + O_FSYNC, +}; use crate::{ context::{self, file::InternalFlags, process}, @@ -24,25 +27,11 @@ use crate::{ use super::{CallerCtx, KernelScheme, KernelSchemes, OpenResult}; -struct FolderInner { - data: Box<[u8]>, -} - -impl FolderInner { - fn read(&self, buf: UserSliceWo, offset: u64) -> Result { - let avail_buf = usize::try_from(offset) - .ok() - .and_then(|o| self.data.get(o..)) - .unwrap_or(&[]); - buf.copy_common_bytes_from_slice(avail_buf) - } -} - #[derive(Clone)] enum Handle { Scheme(Arc), File(Arc>), - Folder(Arc), + List { ens: SchemeNamespace }, } pub struct RootScheme { @@ -111,23 +100,10 @@ impl KernelScheme for RootScheme { Ok(OpenResult::SchemeLocal(id, InternalFlags::empty())) } else if path.is_empty() { - let scheme_ns = process::current()?.read().ens; - - let mut data = Vec::new(); - { - let schemes = scheme::schemes(); - for (name, _scheme_id) in schemes.iter_name(scheme_ns) { - data.extend_from_slice(name.as_bytes()); - data.push(b'\n'); - } - } - - let inner = Arc::new(FolderInner { - data: data.into_boxed_slice(), - }); + let ens = process::current()?.read().ens; let id = self.next_id.fetch_add(1, Ordering::Relaxed); - self.handles.write().insert(id, Handle::Folder(inner)); + self.handles.write().insert(id, Handle::List { ens }); Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED)) } else { let inner = Arc::new(path.as_bytes().to_vec().into_boxed_slice()); @@ -175,7 +151,7 @@ impl KernelScheme for RootScheme { match handle { Handle::Scheme(_) => Err(Error::new(EBADF)), Handle::File(_) => Err(Error::new(EBADF)), - Handle::Folder(inner) => Ok(inner.data.len() as u64), + Handle::List { .. } => Ok(0), } } @@ -189,7 +165,7 @@ impl KernelScheme for RootScheme { match handle { Handle::Scheme(inner) => inner.fevent(flags), Handle::File(_) => Err(Error::new(EBADF)), - Handle::Folder(_) => Err(Error::new(EBADF)), + Handle::List { .. } => Err(Error::new(EBADF)), } } @@ -210,7 +186,7 @@ impl KernelScheme for RootScheme { Handle::File(inner) => { bytes_copied += buf.copy_common_bytes_from_slice(&inner)?; } - Handle::Folder(_) => (), + Handle::List { .. } => (), } Ok(bytes_copied) @@ -226,7 +202,7 @@ impl KernelScheme for RootScheme { match handle { Handle::Scheme(inner) => inner.fsync(), Handle::File(_) => Err(Error::new(EBADF)), - Handle::Folder(_) => Err(Error::new(EBADF)), + Handle::List { .. } => Err(Error::new(EBADF)), } } @@ -248,7 +224,7 @@ impl KernelScheme for RootScheme { &self, file: usize, buf: UserSliceWo, - offset: u64, + _offset: u64, flags: u32, _stored_flags: u32, ) -> Result { @@ -261,9 +237,24 @@ impl KernelScheme for RootScheme { match handle { Handle::Scheme(inner) => inner.read(buf, flags), Handle::File(_) => Err(Error::new(EBADF)), - Handle::Folder(inner) => inner.read(buf, offset), + Handle::List { .. } => Err(Error::new(EISDIR)), } } + fn getdents(&self, id: usize, buf: UserSliceWo, header_size: u16) -> Result { + let Handle::List { ens } = *self.handles.read().get(&id).ok_or(Error::new(EBADF))? else { + return Err(Error::new(ENOTDIR)); + }; + + let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?; + { + let schemes = scheme::schemes(); + for (name, _scheme_id) in schemes.iter_name(ens) { + buf.entry(DirentKind::Unspecified, name)?; + } + } + + Ok(buf.finalize()) + } fn kwrite( &self, @@ -281,7 +272,7 @@ impl KernelScheme for RootScheme { match handle { Handle::Scheme(inner) => inner.write(buf), Handle::File(_) => Err(Error::new(EBADF)), - Handle::Folder(_) => Err(Error::new(EBADF)), + Handle::List { .. } => Err(Error::new(EISDIR)), } } @@ -295,23 +286,14 @@ impl KernelScheme for RootScheme { buf.copy_exactly(&match handle { Handle::Scheme(_) => Stat { st_mode: MODE_FILE, - st_uid: 0, - st_gid: 0, - st_size: 0, ..Default::default() }, Handle::File(_) => Stat { st_mode: MODE_FILE, - st_uid: 0, - st_gid: 0, - st_size: 0, ..Default::default() }, - Handle::Folder(inner) => Stat { + Handle::List { .. } => Stat { st_mode: MODE_DIR, - st_uid: 0, - st_gid: 0, - st_size: inner.data.len() as u64, ..Default::default() }, })?; diff --git a/src/scheme/sys/mod.rs b/src/scheme/sys/mod.rs index d04f1dfd3f..4a8b90a4d4 100644 --- a/src/scheme/sys/mod.rs +++ b/src/scheme/sys/mod.rs @@ -1,3 +1,7 @@ +use ::syscall::{ + dirent::{DirentBuf, DirentKind}, + EIO, EISDIR, ENOTDIR, +}; use alloc::{collections::BTreeMap, vec::Vec}; use core::{ str, @@ -31,10 +35,9 @@ mod scheme_num; mod syscall; mod uname; -struct Handle { - path: &'static str, - data: Vec, - mode: u16, +enum Handle { + TopLevel, + Resource { path: &'static str, data: Vec }, } type SysFn = fn() -> Result>; @@ -74,23 +77,9 @@ impl KernelScheme for SysScheme { let path = path.trim_matches('/'); if path.is_empty() { - let mut data = Vec::new(); - for entry in FILES.iter() { - if !data.is_empty() { - data.push(b'\n'); - } - data.extend_from_slice(entry.0.as_bytes()); - } - let id = NEXT_ID.fetch_add(1, Ordering::Relaxed); - HANDLES.write().insert( - id, - Handle { - path: "", - data, - mode: MODE_DIR | 0o444, - }, - ); + + HANDLES.write().insert(id, Handle::TopLevel); return Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED)); } else { //Have to iterate to get the path without allocation @@ -100,10 +89,9 @@ impl KernelScheme for SysScheme { let data = entry.1()?; HANDLES.write().insert( id, - Handle { + Handle::Resource { path: entry.0, data, - mode: MODE_FILE | 0o444, }, ); return Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED)); @@ -115,32 +103,28 @@ impl KernelScheme for SysScheme { } fn fsize(&self, id: usize) -> Result { - let mut handles = HANDLES.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - Ok(handle.data.len() as u64) - } - - fn fsync(&self, _id: usize) -> Result<()> { - Ok(()) + match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? { + Handle::TopLevel => Ok(0), + Handle::Resource { data, .. } => Ok(data.len() as u64), + } } fn close(&self, id: usize) -> Result<()> { - HANDLES - .write() - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(())) + HANDLES.write().remove(&id).ok_or(Error::new(EBADF))?; + Ok(()) } fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result { let handles = HANDLES.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + let path = match handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::TopLevel => "", + Handle::Resource { path, .. } => path, + }; const FIRST: &[u8] = b"sys:"; let mut bytes_read = buf.copy_common_bytes_from_slice(FIRST)?; if let Some(remaining) = buf.advance(FIRST.len()) { - bytes_read += remaining.copy_common_bytes_from_slice(handle.path.as_bytes())?; + bytes_read += remaining.copy_common_bytes_from_slice(path.as_bytes())?; } Ok(bytes_read) @@ -157,25 +141,47 @@ impl KernelScheme for SysScheme { return Ok(0); }; - let mut handles = HANDLES.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? { + Handle::TopLevel => return Err(Error::new(EISDIR)), + Handle::Resource { data, .. } => { + let avail_buf = data.get(pos..).unwrap_or(&[]); - let avail_buf = handle.data.get(pos..).unwrap_or(&[]); - - buffer.copy_common_bytes_from_slice(avail_buf) + buffer.copy_common_bytes_from_slice(avail_buf) + } + } + } + fn getdents(&self, id: usize, buf: UserSliceWo, header_size: u16) -> Result { + match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? { + Handle::Resource { .. } => return Err(Error::new(ENOTDIR)), + Handle::TopLevel => { + let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?; + for (name, _) in FILES { + buf.entry(DirentKind::Regular, name)?; + } + Ok(buf.finalize()) + } + } } fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> { - let handles = HANDLES.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + let stat = match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? { + Handle::Resource { data, .. } => Stat { + st_mode: 0o444 | MODE_FILE, + st_uid: 0, + st_gid: 0, + st_size: data.len() as u64, + ..Default::default() + }, + Handle::TopLevel => Stat { + st_mode: 0o444 | MODE_DIR, + st_uid: 0, + st_gid: 0, + st_size: 0, + ..Default::default() + }, + }; - buf.copy_exactly(&Stat { - st_mode: handle.mode, - st_uid: 0, - st_gid: 0, - st_size: handle.data.len() as u64, - ..Default::default() - })?; + buf.copy_exactly(&stat)?; Ok(()) } diff --git a/src/scheme/user.rs b/src/scheme/user.rs index a26dd1bc5f..f3fffe81d9 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -769,6 +769,18 @@ impl UserInner { gid: (sqe.args[3] >> 32) as u32, // offset hi }); } + Opcode::Getdents => { + return Ok(Packet { + id: u64::from(sqe.tag) + 1, + pid: sqe.caller as usize, + a: SYS_GETDENTS, + b: sqe.args[0] as usize, + c: sqe.args[1] as usize, + d: sqe.args[2] as usize, + uid: sqe.args[3] as u32, + gid: (sqe.args[3] >> 32) as u32, + }); + } Opcode::Mremap => SYS_MREMAP, Opcode::Msync => KSMSG_MSYNC, @@ -1542,6 +1554,17 @@ impl KernelScheme for UserScheme { address.release()?; result } + fn getdents(&self, file: usize, stat: UserSliceWo, header_size: u16) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + let address = inner.capture_user(stat)?; + let result = inner.call( + Opcode::Getdents, + [file, address.base(), address.len(), header_size.into()], + address.span(), + ); + address.release()?; + result + } fn kfstat(&self, file: usize, stat: UserSliceWo) -> Result<()> { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture_user(stat)?; diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index f600259d51..0e13682ffe 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -219,7 +219,7 @@ impl SyscallDebugInfo { } #[cfg(feature = "syscall_debug")] pub fn debug_start([a, b, c, d, e, f]: [usize; 6]) { - let do_debug = if crate::context::current().read().name.contains("sigchld") { + let do_debug = if false && crate::context::current().read().name.contains("acpid") { if a == SYS_CLOCK_GETTIME || a == SYS_YIELD || a == SYS_FUTEX { false } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) { diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index d61c14a816..e933e1a5e0 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -4,7 +4,9 @@ extern crate syscall; -use syscall::{RwFlags, EINVAL, SIGKILL}; +use core::mem::size_of; + +use syscall::{dirent::DirentHeader, RwFlags, EINVAL, SIGKILL}; pub use self::syscall::{ data, error, flag, io, number, ptrace_event, EnvRegisters, FloatRegisters, IntRegisters, @@ -103,6 +105,18 @@ pub fn syscall( }) } } + SYS_GETDENTS => { + let header_size = u16::try_from(e).map_err(|_| Error::new(EINVAL))?; + + if usize::from(header_size) != size_of::() { + // TODO: allow? If so, zero_out must be implemented for UserSlice + return Err(Error::new(EINVAL)); + } + + file_op_generic(fd, |scheme, number| { + scheme.getdents(number, UserSlice::wo(c, d)?, header_size) + }) + } SYS_FUTIMENS => file_op_generic(fd, |scheme, number| { scheme.kfutimens(number, UserSlice::ro(c, d)?) }), diff --git a/src/syscall/usercopy.rs b/src/syscall/usercopy.rs index 0a2b752a5a..b70a125c6e 100644 --- a/src/syscall/usercopy.rs +++ b/src/syscall/usercopy.rs @@ -1,3 +1,5 @@ +use syscall::dirent::Buffer; + use crate::{ memory::PAGE_SIZE, paging::{Page, VirtualAddress}, @@ -231,3 +233,22 @@ pub fn validate_region(address: usize, size: usize) -> Result<(Page, usize)> { size / PAGE_SIZE, )) } +impl Buffer<'static> for UserSliceWo { + fn empty() -> Self { + UserSliceWo::empty() + } + fn length(&self) -> usize { + self.len() + } + fn split_at(self, index: usize) -> Option<[Self; 2]> { + let (a, b) = self.split_at(index)?; + Some([a, b]) + } + fn copy_from_slice_exact(self, src: &[u8]) -> Result<()> { + self.copy_exactly(src) + } + fn zero_out(self) -> Result<()> { + // TODO: Implement this. Don't need to as long as the header size is constant, for now. + Ok(()) + } +} diff --git a/syscall b/syscall index 227f7fd487..c043410366 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 227f7fd4873b17680957c75604cf4a5a674f5792 +Subproject commit c043410366e61345902808df8337e16623465035 diff --git a/targets/x86_64-unknown-kernel.json b/targets/x86_64-unknown-kernel.json index d4ebea0a8d..848ef0e197 100644 --- a/targets/x86_64-unknown-kernel.json +++ b/targets/x86_64-unknown-kernel.json @@ -10,7 +10,7 @@ "vendor": "unknown", "linker": "rust-lld", "linker-flavor": "gnu-lld", - "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", + "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float", "dynamic-linking": false, "executables": true, "relocation-model": "static",