proc: add mount/unmount system calls
This commit is contained in:
parent
aa6b2ac469
commit
74cd9daed7
23
lib/vfs/src/debug.rs
Normal file
23
lib/vfs/src/debug.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
pub(crate) static mut DEBUG_HOOK: Option<&'static dyn Fn(fmt::Arguments)> = None;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug_raw {
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
$crate::debug::_debug_print(format_args!($($arg)+))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debugln {
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
debug_raw!("[VFS] {}\n", format_args!($($arg)+))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn _debug_print(args: fmt::Arguments) {
|
||||||
|
if let Some(hook) = unsafe { DEBUG_HOOK.as_mut() } {
|
||||||
|
hook(args);
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,13 @@ impl IoContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _find(&self, mut at: VnodeRef, path: &str, follow: bool) -> Result<VnodeRef, Error> {
|
fn _find(
|
||||||
|
&self,
|
||||||
|
mut at: VnodeRef,
|
||||||
|
path: &str,
|
||||||
|
follow: bool,
|
||||||
|
follow_mount: bool,
|
||||||
|
) -> Result<VnodeRef, Error> {
|
||||||
let mut element;
|
let mut element;
|
||||||
let mut rest = path;
|
let mut rest = path;
|
||||||
|
|
||||||
@ -35,18 +41,44 @@ impl IoContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO resolve link target
|
if follow || follow_mount {
|
||||||
|
while let Some(target) = at.target() {
|
||||||
|
assert!(at.is_mountpoint());
|
||||||
|
if at.is_mountpoint() && !follow_mount {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugln!("resolve parent: {:?} -> {:?}", at, target);
|
||||||
|
at = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !at.is_directory() {
|
||||||
|
return Err(Error::NotADirectory);
|
||||||
|
}
|
||||||
|
|
||||||
if element.is_empty() && rest.is_empty() {
|
if element.is_empty() && rest.is_empty() {
|
||||||
return Ok(at);
|
return Ok(at);
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = at.lookup_or_load(element)?;
|
let mut node = at.lookup_or_load(element)?;
|
||||||
|
|
||||||
|
if follow || follow_mount {
|
||||||
|
while let Some(target) = node.target() {
|
||||||
|
assert!(node.is_mountpoint());
|
||||||
|
if node.is_mountpoint() && !follow_mount {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugln!("resolve node: {:?} -> {:?}", node, target);
|
||||||
|
node = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if rest.is_empty() {
|
if rest.is_empty() {
|
||||||
Ok(node)
|
Ok(node)
|
||||||
} else {
|
} else {
|
||||||
self._find(node, rest, follow)
|
self._find(node, rest, follow, follow_mount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +87,10 @@ impl IoContext {
|
|||||||
at: Option<VnodeRef>,
|
at: Option<VnodeRef>,
|
||||||
mut path: &str,
|
mut path: &str,
|
||||||
follow: bool,
|
follow: bool,
|
||||||
|
follow_mount: bool,
|
||||||
) -> Result<VnodeRef, Error> {
|
) -> Result<VnodeRef, Error> {
|
||||||
|
debugln!("_find {:?} in {:?}", path, at);
|
||||||
|
|
||||||
let at = if path.starts_with('/') {
|
let at = if path.starts_with('/') {
|
||||||
path = path.trim_start_matches('/');
|
path = path.trim_start_matches('/');
|
||||||
self.root.clone()
|
self.root.clone()
|
||||||
@ -65,7 +100,7 @@ impl IoContext {
|
|||||||
self.cwd.clone()
|
self.cwd.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
self._find(at, path, follow)
|
self._find(at, path, follow, follow_mount)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(
|
pub fn open(
|
||||||
@ -74,7 +109,7 @@ impl IoContext {
|
|||||||
path: &str,
|
path: &str,
|
||||||
opts: OpenFlags,
|
opts: OpenFlags,
|
||||||
) -> Result<FileRef, Error> {
|
) -> Result<FileRef, Error> {
|
||||||
let node = match self.find(at.clone(), path, true) {
|
let node = match self.find(at.clone(), path, true, true) {
|
||||||
Err(Error::DoesNotExist) => {
|
Err(Error::DoesNotExist) => {
|
||||||
// TODO check for create option
|
// TODO check for create option
|
||||||
return Err(Error::DoesNotExist);
|
return Err(Error::DoesNotExist);
|
||||||
@ -84,11 +119,15 @@ impl IoContext {
|
|||||||
|
|
||||||
node.open(opts)
|
node.open(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn root(&self) -> &VnodeRef {
|
||||||
|
&self.root
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use abi::error::Error;
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
use crate::{node::VnodeRef, IoContext};
|
use crate::{node::VnodeRef, IoContext};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -115,7 +154,7 @@ mod tests {
|
|||||||
|
|
||||||
impl fmt::Debug for DumpNode<'_> {
|
impl fmt::Debug for DumpNode<'_> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.node.dump(f, 0)
|
self.node.dump(f, 0, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,79 +176,93 @@ mod tests {
|
|||||||
|
|
||||||
// Absolute lookups
|
// Absolute lookups
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(None, "/file1.txt", false).unwrap().name(),
|
ctx.find(None, "/file1.txt", false, false).unwrap().name(),
|
||||||
"file1.txt"
|
"file1.txt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(None, "/file3.txt", false).unwrap_err(),
|
ctx.find(None, "/file3.txt", false, false).unwrap_err(),
|
||||||
Error::DoesNotExist
|
Error::DoesNotExist
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(None, "/dir1/file3.txt", false).unwrap().name(),
|
ctx.find(None, "/dir1/file3.txt", false, false)
|
||||||
|
.unwrap()
|
||||||
|
.name(),
|
||||||
"file3.txt"
|
"file3.txt"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Non-absolute lookups from root
|
// Non-absolute lookups from root
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(None, "file1.txt", false).unwrap().name(),
|
ctx.find(None, "file1.txt", false, false).unwrap().name(),
|
||||||
"file1.txt"
|
"file1.txt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(None, "dir1/file3.txt", false).unwrap().name(),
|
ctx.find(None, "dir1/file3.txt", false, false)
|
||||||
|
.unwrap()
|
||||||
|
.name(),
|
||||||
"file3.txt"
|
"file3.txt"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Absolute lookups from non-root
|
// Absolute lookups from non-root
|
||||||
let cwd = ctx.find(None, "/dir1", false).unwrap();
|
let cwd = ctx.find(None, "/dir1", false, false).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "/file1.txt", false)
|
ctx.find(Some(cwd.clone()), "/file1.txt", false, false)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.name(),
|
.name(),
|
||||||
"file1.txt"
|
"file1.txt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "/dir1/file3.txt", false)
|
ctx.find(Some(cwd.clone()), "/dir1/file3.txt", false, false)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.name(),
|
.name(),
|
||||||
"file3.txt"
|
"file3.txt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "/file3.txt", false)
|
ctx.find(Some(cwd.clone()), "/file3.txt", false, false)
|
||||||
.unwrap_err(),
|
.unwrap_err(),
|
||||||
Error::DoesNotExist
|
Error::DoesNotExist
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "/dir2", false).unwrap_err(),
|
ctx.find(Some(cwd.clone()), "/dir2", false, false)
|
||||||
|
.unwrap_err(),
|
||||||
Error::DoesNotExist
|
Error::DoesNotExist
|
||||||
);
|
);
|
||||||
|
|
||||||
// Non-absolute lookups in non-root
|
// Non-absolute lookups in non-root
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "file3.txt", false)
|
ctx.find(Some(cwd.clone()), "file3.txt", false, false)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.name(),
|
.name(),
|
||||||
"file3.txt"
|
"file3.txt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "././file3.txt", false)
|
ctx.find(Some(cwd.clone()), "././file3.txt", false, false)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.name(),
|
.name(),
|
||||||
"file3.txt"
|
"file3.txt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "../dir1/file3.txt", false)
|
ctx.find(Some(cwd.clone()), "../dir1/file3.txt", false, false)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.name(),
|
.name(),
|
||||||
"file3.txt"
|
"file3.txt"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), ".", false).unwrap().name(),
|
ctx.find(Some(cwd.clone()), ".", false, false)
|
||||||
|
.unwrap()
|
||||||
|
.name(),
|
||||||
"dir1"
|
"dir1"
|
||||||
);
|
);
|
||||||
assert_eq!(ctx.find(Some(cwd.clone()), "..", false).unwrap().name(), "");
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ctx.find(Some(cwd.clone()), "../..", false).unwrap().name(),
|
ctx.find(Some(cwd.clone()), "..", false, false)
|
||||||
|
.unwrap()
|
||||||
|
.name(),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ctx.find(Some(cwd.clone()), "../..", false, false)
|
||||||
|
.unwrap()
|
||||||
|
.name(),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ extern crate alloc;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub(crate) mod debug;
|
||||||
|
|
||||||
pub(crate) mod block;
|
pub(crate) mod block;
|
||||||
pub(crate) mod char;
|
pub(crate) mod char;
|
||||||
pub(crate) mod file;
|
pub(crate) mod file;
|
||||||
@ -62,3 +65,7 @@ fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [u8]) -> Res
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init_debug_hook(hook: &'static dyn Fn(core::fmt::Arguments)) {
|
||||||
|
debug::DEBUG_HOOK.replace(hook);
|
||||||
|
}
|
||||||
|
@ -42,6 +42,7 @@ pub struct Vnode {
|
|||||||
kind: VnodeKind,
|
kind: VnodeKind,
|
||||||
data: RefCell<Option<Box<dyn VnodeImpl>>>,
|
data: RefCell<Option<Box<dyn VnodeImpl>>>,
|
||||||
fs: RefCell<Option<Rc<dyn Filesystem>>>,
|
fs: RefCell<Option<Rc<dyn Filesystem>>>,
|
||||||
|
target: RefCell<Option<VnodeRef>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VnodeImpl {
|
pub trait VnodeImpl {
|
||||||
@ -69,6 +70,7 @@ impl Vnode {
|
|||||||
kind,
|
kind,
|
||||||
data: RefCell::new(None),
|
data: RefCell::new(None),
|
||||||
fs: RefCell::new(None),
|
fs: RefCell::new(None),
|
||||||
|
target: RefCell::new(None),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +84,11 @@ impl Vnode {
|
|||||||
self.kind
|
self.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn target(&self) -> Option<VnodeRef> {
|
||||||
|
self.target.borrow().clone()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn data(&self) -> RefMut<Option<Box<dyn VnodeImpl>>> {
|
pub fn data(&self) -> RefMut<Option<Box<dyn VnodeImpl>>> {
|
||||||
self.data.borrow_mut()
|
self.data.borrow_mut()
|
||||||
@ -92,6 +99,11 @@ impl Vnode {
|
|||||||
self.fs.borrow().clone()
|
self.fs.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_target(&self, target: Option<VnodeRef>) {
|
||||||
|
self.target.replace(target);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parent(self: &VnodeRef) -> VnodeRef {
|
pub fn parent(self: &VnodeRef) -> VnodeRef {
|
||||||
match &self.tree.borrow().parent {
|
match &self.tree.borrow().parent {
|
||||||
Some(parent) => parent.upgrade().unwrap(),
|
Some(parent) => parent.upgrade().unwrap(),
|
||||||
@ -112,6 +124,11 @@ impl Vnode {
|
|||||||
self.kind == VnodeKind::Directory
|
self.kind == VnodeKind::Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_mountpoint(&self) -> bool {
|
||||||
|
self.is_directory() && self.target.borrow().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
// Cache tree operations
|
// Cache tree operations
|
||||||
pub fn add_child(self: &VnodeRef, child: VnodeRef) {
|
pub fn add_child(self: &VnodeRef, child: VnodeRef) {
|
||||||
let parent_weak = Rc::downgrade(self);
|
let parent_weak = Rc::downgrade(self);
|
||||||
@ -126,22 +143,32 @@ impl Vnode {
|
|||||||
parent_borrow.children.push(child);
|
parent_borrow.children.push(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(&self, f: &mut fmt::Formatter<'_>, depth: usize) -> fmt::Result {
|
pub fn dump(&self, f: &mut fmt::Formatter<'_>, depth: usize, indent: bool) -> fmt::Result {
|
||||||
|
if indent {
|
||||||
for _ in 0..depth {
|
for _ in 0..depth {
|
||||||
f.write_str(" ")?;
|
f.write_str(" ")?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
write!(f, "{:?}", self.name)?;
|
write!(f, "{:?}", self.name)?;
|
||||||
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
VnodeKind::Directory => {
|
VnodeKind::Directory => {
|
||||||
let tree = self.tree.borrow();
|
let tree = self.tree.borrow();
|
||||||
|
let target = self.target();
|
||||||
|
|
||||||
|
if let Some(target) = target {
|
||||||
|
assert_eq!(tree.children.len(), 0);
|
||||||
|
f.write_str(" -> ")?;
|
||||||
|
return target.dump(f, depth, false);
|
||||||
|
}
|
||||||
|
|
||||||
if tree.children.is_empty() {
|
if tree.children.is_empty() {
|
||||||
f.write_str(" []")?;
|
f.write_str(" []")?;
|
||||||
} else {
|
} else {
|
||||||
f.write_str(" [\n")?;
|
f.write_str(" [\n")?;
|
||||||
for child in tree.children.iter() {
|
for child in tree.children.iter() {
|
||||||
child.dump(f, depth + 1)?;
|
child.dump(f, depth + 1, true)?;
|
||||||
f.write_str("\n")?;
|
f.write_str("\n")?;
|
||||||
}
|
}
|
||||||
for _ in 0..depth {
|
for _ in 0..depth {
|
||||||
@ -265,6 +292,48 @@ impl Vnode {
|
|||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mount(self: &VnodeRef, fs_root: VnodeRef) -> Result<(), Error> {
|
||||||
|
if !self.is_directory() {
|
||||||
|
return Err(Error::NotADirectory);
|
||||||
|
}
|
||||||
|
if !fs_root.is_directory() {
|
||||||
|
todo!("Filesystem root is not a directory");
|
||||||
|
}
|
||||||
|
if self.target.borrow().is_some() {
|
||||||
|
todo!("Target mountpoint is busy");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut child_borrow = fs_root.tree.borrow_mut();
|
||||||
|
if child_borrow.parent.is_some() {
|
||||||
|
todo!("Filesystem is already mounted somewhere else");
|
||||||
|
}
|
||||||
|
child_borrow.parent = Some(Rc::downgrade(self));
|
||||||
|
}
|
||||||
|
self.target.replace(Some(fs_root));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmount_target(self: &VnodeRef) -> Result<(), Error> {
|
||||||
|
if !self.is_directory() {
|
||||||
|
return Err(Error::NotADirectory);
|
||||||
|
}
|
||||||
|
let Some(fs_root) = self.target.take() else {
|
||||||
|
todo!();
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut target_borrow = fs_root.tree.borrow_mut();
|
||||||
|
let Some(parent) = target_borrow.parent.take() else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
assert!(Rc::ptr_eq(self, &parent.upgrade().unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Vnode {
|
impl fmt::Debug for Vnode {
|
||||||
@ -288,6 +357,6 @@ impl VnodeDump {
|
|||||||
|
|
||||||
impl fmt::Debug for VnodeDump {
|
impl fmt::Debug for VnodeDump {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.node.dump(f, 0)
|
self.node.dump(f, 0, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,11 @@ pub fn init() {
|
|||||||
DEBUG_PRINTER.init(IrqSafeSpinlock::new(DebugPrinter {
|
DEBUG_PRINTER.init(IrqSafeSpinlock::new(DebugPrinter {
|
||||||
sink: PLATFORM.primary_serial().unwrap(),
|
sink: PLATFORM.primary_serial().unwrap(),
|
||||||
}));
|
}));
|
||||||
|
unsafe {
|
||||||
|
vfs::init_debug_hook(&move |args| {
|
||||||
|
debug_internal(args, LogLevel::Debug);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc = "hide"]
|
#[doc = "hide"]
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
//! Filesystem implementations
|
//! Filesystem implementations
|
||||||
|
|
||||||
|
use vfs::VnodeRef;
|
||||||
|
use yggdrasil_abi::{error::Error, io::MountOptions};
|
||||||
|
|
||||||
use crate::util::OneTimeInit;
|
use crate::util::OneTimeInit;
|
||||||
|
|
||||||
|
pub mod devfs;
|
||||||
|
pub mod tar;
|
||||||
|
|
||||||
pub struct Initrd {
|
pub struct Initrd {
|
||||||
pub phys_page_start: usize,
|
pub phys_page_start: usize,
|
||||||
pub phys_page_len: usize,
|
pub phys_page_len: usize,
|
||||||
@ -10,5 +16,11 @@ pub struct Initrd {
|
|||||||
|
|
||||||
pub static INITRD_DATA: OneTimeInit<Initrd> = OneTimeInit::new();
|
pub static INITRD_DATA: OneTimeInit<Initrd> = OneTimeInit::new();
|
||||||
|
|
||||||
pub mod devfs;
|
pub fn create_filesystem(options: &MountOptions) -> Result<VnodeRef, Error> {
|
||||||
pub mod tar;
|
let fs_name = options.filesystem.unwrap();
|
||||||
|
|
||||||
|
match fs_name {
|
||||||
|
"devfs" => Ok(devfs::root().clone()),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
29
src/main.rs
29
src/main.rs
@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
extern crate yggdrasil_abi as abi;
|
extern crate yggdrasil_abi as abi;
|
||||||
|
|
||||||
use core::ops::DerefMut;
|
|
||||||
|
|
||||||
use abi::{
|
use abi::{
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{OpenFlags, RawFd},
|
io::{OpenFlags, RawFd},
|
||||||
@ -67,7 +65,7 @@ pub fn kernel_main() {
|
|||||||
let tty_node = devfs_root.lookup("ttyS0").unwrap();
|
let tty_node = devfs_root.lookup("ttyS0").unwrap();
|
||||||
|
|
||||||
let ioctx = IoContext::new(root);
|
let ioctx = IoContext::new(root);
|
||||||
let node = ioctx.find(None, "/init", false).unwrap();
|
let node = ioctx.find(None, "/init", true, true).unwrap();
|
||||||
let file = node.open(OpenFlags::new().read()).unwrap();
|
let file = node.open(OpenFlags::new().read()).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -83,30 +81,5 @@ pub fn kernel_main() {
|
|||||||
user_init.enqueue_somewhere();
|
user_init.enqueue_somewhere();
|
||||||
}
|
}
|
||||||
|
|
||||||
// static USER_PROGRAM: &[u8] = include_bytes!(concat!(
|
|
||||||
// "../../target/aarch64-unknown-yggdrasil/",
|
|
||||||
// env!("PROFILE"),
|
|
||||||
// "/test_program"
|
|
||||||
// ));
|
|
||||||
|
|
||||||
// let ioctx = IoContext::new(devfs_root.clone());
|
|
||||||
|
|
||||||
// // Spawn a test user task
|
|
||||||
// let proc =
|
|
||||||
// proc::exec::create_from_memory(USER_PROGRAM, &["user-program", "argument 1", "argument 2"]);
|
|
||||||
|
|
||||||
// match proc {
|
|
||||||
// Ok(proc) => {
|
|
||||||
// // Setup I/O for the process
|
|
||||||
// // let mut io = proc.io.lock();
|
|
||||||
// // io.set_file(RawFd::STDOUT, todo!()).unwrap();
|
|
||||||
|
|
||||||
// proc.enqueue_somewhere();
|
|
||||||
// }
|
|
||||||
// Err(err) => {
|
|
||||||
// warnln!("Failed to create user process: {:?}", err);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
Process::current().exit(0);
|
Process::current().exit(0);
|
||||||
}
|
}
|
||||||
|
@ -53,12 +53,12 @@ impl PhysicalMemoryRegion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an address range covered by the region
|
/// Returns an address range covered by the region
|
||||||
pub const fn range(&self) -> Range<usize> {
|
pub fn range(&self) -> Range<usize> {
|
||||||
self.base..self.end()
|
self.base..self.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides an iterator over the pages in the region
|
/// Provides an iterator over the pages in the region
|
||||||
pub const fn pages(&self) -> StepBy<Range<usize>> {
|
pub fn pages(&self) -> StepBy<Range<usize>> {
|
||||||
self.range().step_by(0x1000)
|
self.range().step_by(0x1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
src/syscall/arg.rs
Normal file
32
src/syscall/arg.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use core::alloc::Layout;
|
||||||
|
|
||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
|
pub(super) fn arg_buffer_ref<'a>(base: usize, len: usize) -> Result<&'a [u8], Error> {
|
||||||
|
if base + len > crate::mem::KERNEL_VIRT_OFFSET {
|
||||||
|
panic!("Invalid argument");
|
||||||
|
}
|
||||||
|
Ok(unsafe { core::slice::from_raw_parts(base as *const u8, len) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn arg_buffer_mut<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Error> {
|
||||||
|
if base + len > crate::mem::KERNEL_VIRT_OFFSET {
|
||||||
|
panic!("Invalid argument");
|
||||||
|
}
|
||||||
|
Ok(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, len) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn arg_user_str<'a>(base: usize, len: usize) -> Result<&'a str, Error> {
|
||||||
|
let slice = arg_buffer_ref(base, len)?;
|
||||||
|
Ok(core::str::from_utf8(slice).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn arg_user_ref<'a, T: Sized>(addr: usize) -> Result<&'a T, Error> {
|
||||||
|
let layout = Layout::new::<T>();
|
||||||
|
if addr % layout.align() != 0 {
|
||||||
|
todo!("Misaligned argument");
|
||||||
|
}
|
||||||
|
// TODO check that addr actually points to mapped (and user-accessible) memory
|
||||||
|
let value = unsafe { core::mem::transmute::<_, &'a T>(addr) };
|
||||||
|
Ok(value)
|
||||||
|
}
|
@ -7,31 +7,17 @@ use abi::{
|
|||||||
syscall::SyscallFunction,
|
syscall::SyscallFunction,
|
||||||
};
|
};
|
||||||
use vfs::{Read, Write};
|
use vfs::{Read, Write};
|
||||||
|
use yggdrasil_abi::io::{MountOptions, UnmountOptions};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
fs,
|
||||||
mem::table::{PageAttributes, VirtualMemoryManager},
|
mem::table::{PageAttributes, VirtualMemoryManager},
|
||||||
proc::wait,
|
proc::wait,
|
||||||
task::process::Process,
|
task::process::Process,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn arg_buffer_ref<'a>(base: usize, len: usize) -> Result<&'a [u8], Error> {
|
mod arg;
|
||||||
if base + len > crate::mem::KERNEL_VIRT_OFFSET {
|
use arg::*;
|
||||||
panic!("Invalid argument");
|
|
||||||
}
|
|
||||||
Ok(unsafe { core::slice::from_raw_parts(base as *const u8, len) })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn arg_buffer_mut<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Error> {
|
|
||||||
if base + len > crate::mem::KERNEL_VIRT_OFFSET {
|
|
||||||
panic!("Invalid argument");
|
|
||||||
}
|
|
||||||
Ok(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, len) })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn arg_user_str<'a>(base: usize, len: usize) -> Result<&'a str, Error> {
|
|
||||||
let slice = arg_buffer_ref(base, len)?;
|
|
||||||
Ok(core::str::from_utf8(slice).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error> {
|
fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error> {
|
||||||
match func {
|
match func {
|
||||||
@ -132,6 +118,38 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
|||||||
io.close_file(fd)?;
|
io.close_file(fd)?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
SyscallFunction::Mount => {
|
||||||
|
let options = arg_user_ref::<MountOptions>(args[0] as usize)?;
|
||||||
|
|
||||||
|
let proc = Process::current();
|
||||||
|
let mut io = proc.io.lock();
|
||||||
|
|
||||||
|
let target_node = io.ioctx().find(None, options.target, true, false)?;
|
||||||
|
if !target_node.is_directory() {
|
||||||
|
return Err(Error::NotADirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
let fs_root = fs::create_filesystem(options)?;
|
||||||
|
|
||||||
|
target_node.mount(fs_root)?;
|
||||||
|
|
||||||
|
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
SyscallFunction::Unmount => {
|
||||||
|
let options = arg_user_ref::<UnmountOptions>(args[0] as usize)?;
|
||||||
|
|
||||||
|
let proc = Process::current();
|
||||||
|
let mut io = proc.io.lock();
|
||||||
|
|
||||||
|
let mountpoint = io.ioctx().find(None, options.mountpoint, true, false)?;
|
||||||
|
mountpoint.unmount_target()?;
|
||||||
|
|
||||||
|
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user