Add getdents syscall, and switch schemes to it.
This commit is contained in:
@@ -49,6 +49,7 @@ default = [
|
||||
"serial_debug",
|
||||
"self_modifying",
|
||||
"x86_kvm_pv",
|
||||
"syscall_debug",
|
||||
]
|
||||
|
||||
# Activates some limited code-overwriting optimizations, based on CPU features.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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();
|
||||
|
||||
+21
-8
@@ -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<Box<[u8]>> = Once::new();
|
||||
|
||||
const TOPLEVEL_CONTENTS: &[u8] = b"rxsdt\nkstop\n";
|
||||
|
||||
static KSTOP_WAITCOND: WaitCondition = WaitCondition::new();
|
||||
static KSTOP_FLAG: Mutex<bool> = 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<usize> {
|
||||
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 {
|
||||
|
||||
+43
-58
@@ -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<u8>), // CPU id, data, offset
|
||||
TopLevel(Vec<u8>), // 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<usize> {
|
||||
use core::fmt::Write;
|
||||
|
||||
fn fsize(&self, id: usize) -> Result<u64> {
|
||||
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<usize> {
|
||||
@@ -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<usize> {
|
||||
@@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +451,9 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
fn getdents(&self, id: usize, buf: UserSliceWo, header_size: u16) -> Result<usize> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
|
||||
fn fsync(&self, id: usize) -> Result<()> {
|
||||
Ok(())
|
||||
|
||||
+30
-48
@@ -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<usize> {
|
||||
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<UserInner>),
|
||||
File(Arc<Box<[u8]>>),
|
||||
Folder(Arc<FolderInner>),
|
||||
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<usize> {
|
||||
@@ -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<usize> {
|
||||
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()
|
||||
},
|
||||
})?;
|
||||
|
||||
+57
-51
@@ -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<u8>,
|
||||
mode: u16,
|
||||
enum Handle {
|
||||
TopLevel,
|
||||
Resource { path: &'static str, data: Vec<u8> },
|
||||
}
|
||||
|
||||
type SysFn = fn() -> Result<Vec<u8>>;
|
||||
@@ -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<u64> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -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<usize> {
|
||||
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)?;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+15
-1
@@ -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::<DirentHeader>() {
|
||||
// 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)?)
|
||||
}),
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
Submodule syscall updated: 227f7fd487...c043410366
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user