feat(vfs): CoW for memfs, init start
This commit is contained in:
Generated
+10
@@ -108,6 +108,7 @@ dependencies = [
|
||||
"cortex-a",
|
||||
"error",
|
||||
"fdt-rs",
|
||||
"libcommon",
|
||||
"memfs",
|
||||
"tock-registers",
|
||||
"vfs",
|
||||
@@ -119,6 +120,13 @@ version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce"
|
||||
|
||||
[[package]]
|
||||
name = "libcommon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libusr"
|
||||
version = "0.1.0"
|
||||
@@ -128,6 +136,7 @@ name = "memfs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"error",
|
||||
"libcommon",
|
||||
"vfs",
|
||||
]
|
||||
|
||||
@@ -259,6 +268,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"error",
|
||||
"hashbrown",
|
||||
"libcommon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -11,6 +11,7 @@ edition = "2018"
|
||||
members = [
|
||||
"fs/vfs",
|
||||
"fs/memfs",
|
||||
"libcommon",
|
||||
"kernel",
|
||||
"libusr",
|
||||
"init",
|
||||
|
||||
@@ -55,13 +55,10 @@ endif
|
||||
|
||||
.PHONY: address error etc kernel src
|
||||
|
||||
all: kernel
|
||||
all: kernel initrd
|
||||
|
||||
kernel:
|
||||
cd kernel && cargo build $(CARGO_BUILD_OPTS)
|
||||
cd init && cargo build --target=../etc/$(ARCH)-osdev5.json -Z build-std=core,alloc,compiler_builtins
|
||||
echo "This is a test file" >$(O)/test.txt
|
||||
cd $(O) && tar cf initrd.img test.txt
|
||||
ifeq ($(ARCH),aarch64)
|
||||
$(LLVM_BASE)/llvm-strip -o $(O)/kernel.strip $(O)/kernel
|
||||
$(LLVM_BASE)/llvm-size $(O)/kernel.strip
|
||||
@@ -80,6 +77,11 @@ ifeq ($(MACH),orangepi3)
|
||||
$(O)/uImage
|
||||
endif
|
||||
|
||||
initrd:
|
||||
cd init && cargo build --target=../etc/$(ARCH)-osdev5.json -Z build-std=core,alloc,compiler_builtins
|
||||
cp target/$(ARCH)-osdev5/debug/init $(O)
|
||||
cd $(O) && tar cf initrd.img init
|
||||
|
||||
test:
|
||||
cd fs/vfs && cargo test
|
||||
cd fs/memfs && cargo test
|
||||
|
||||
@@ -8,3 +8,8 @@ edition = "2021"
|
||||
[dependencies]
|
||||
vfs = { path = "../vfs" }
|
||||
error = { path = "../../error" }
|
||||
libcommon = { path = "../../libcommon" }
|
||||
|
||||
[features]
|
||||
cow = []
|
||||
default = ["cow"]
|
||||
|
||||
@@ -12,6 +12,8 @@ pub struct Bvec<'a, A: BlockAllocator + Copy> {
|
||||
l0: [MaybeUninit<BlockRef<'a, A>>; L0_BLOCKS],
|
||||
l1: [MaybeUninit<BlockRef<'a, A>>; L1_BLOCKS],
|
||||
l2: MaybeUninit<BlockRef<'a, A>>,
|
||||
#[cfg(feature = "cow")]
|
||||
cow_source: *const u8,
|
||||
alloc: A,
|
||||
}
|
||||
impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
|
||||
@@ -23,6 +25,8 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
|
||||
l1: MaybeUninit::uninit_array(),
|
||||
l2: MaybeUninit::uninit(),
|
||||
alloc,
|
||||
#[cfg(feature = "cow")]
|
||||
cow_source: core::ptr::null_mut()
|
||||
};
|
||||
for it in res.l0.iter_mut() {
|
||||
it.write(BlockRef::null());
|
||||
@@ -33,7 +37,31 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
|
||||
res.l2.write(BlockRef::null());
|
||||
res
|
||||
}
|
||||
|
||||
#[cfg(feature = "cow")]
|
||||
pub unsafe fn setup_cow(&mut self, src: *const u8, size: usize) {
|
||||
self.cow_source = src;
|
||||
self.size = size;
|
||||
}
|
||||
|
||||
pub const fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
#[cfg(feature = "cow")]
|
||||
pub fn drop_cow(&mut self) {
|
||||
assert!(!self.cow_source.is_null());
|
||||
let src_slice = unsafe { core::slice::from_raw_parts(self.cow_source, self.size) };
|
||||
self.cow_source = core::ptr::null_mut();
|
||||
|
||||
self.resize((self.size + 4095) / 4096).unwrap();
|
||||
self.write(0, src_slice).unwrap();
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, cap: usize) -> Result<(), Errno> {
|
||||
#[cfg(feature = "cow")]
|
||||
assert!(self.cow_source.is_null());
|
||||
|
||||
if cap <= self.capacity {
|
||||
let mut curr = self.capacity;
|
||||
while curr != cap {
|
||||
@@ -126,6 +154,12 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
|
||||
if pos > self.size {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
#[cfg(feature = "cow")]
|
||||
if !self.cow_source.is_null() {
|
||||
self.drop_cow();
|
||||
}
|
||||
|
||||
let mut rem = data.len();
|
||||
let mut doff = 0usize;
|
||||
if pos + rem > self.size {
|
||||
@@ -150,7 +184,16 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
|
||||
if pos > self.size {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
let mut rem = min(self.size - pos, data.len());
|
||||
|
||||
#[cfg(feature = "cow")]
|
||||
if !self.cow_source.is_null() {
|
||||
let cow_data = unsafe { core::slice::from_raw_parts(self.cow_source, self.size) };
|
||||
data[..rem].copy_from_slice(&cow_data[pos..pos + rem]);
|
||||
return Ok(rem);
|
||||
}
|
||||
|
||||
let mut doff = 0usize;
|
||||
while rem > 0 {
|
||||
let index = pos / block::SIZE;
|
||||
|
||||
+52
-9
@@ -13,7 +13,9 @@ extern crate std;
|
||||
|
||||
use alloc::{boxed::Box, rc::Rc};
|
||||
use core::cell::RefCell;
|
||||
use core::ffi::c_void;
|
||||
use error::Errno;
|
||||
use libcommon::path_component_left;
|
||||
use vfs::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||
|
||||
pub mod block;
|
||||
@@ -34,6 +36,12 @@ pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> {
|
||||
|
||||
pub struct DirInode;
|
||||
|
||||
struct SetupFileParam {
|
||||
data: &'static [u8]
|
||||
}
|
||||
|
||||
const FILE_SETUP_COW: u64 = 0x1001;
|
||||
|
||||
impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
|
||||
fn create(&mut self, _parent: VnodeRef, _node: VnodeRef) -> Result<(), Errno> {
|
||||
panic!()
|
||||
@@ -51,17 +59,35 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
self.data.read(pos, data)
|
||||
}
|
||||
|
||||
fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno> {
|
||||
fn write(&mut self, _node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno> {
|
||||
self.data.write(pos, data)
|
||||
}
|
||||
|
||||
fn truncate(&mut self, _node: VnodeRef, size: usize) -> Result<(), Errno> {
|
||||
self.data.resize((size + 4095) / 4096)
|
||||
}
|
||||
|
||||
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
|
||||
Ok(self.data.size())
|
||||
}
|
||||
|
||||
fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
|
||||
match cmd {
|
||||
#[cfg(feature = "cow")]
|
||||
FILE_SETUP_COW => {
|
||||
let data = unsafe { (value as *mut SetupFileParam).as_ref().unwrap() };
|
||||
unsafe {
|
||||
self.data.setup_cow(data.data.as_ptr(), data.data.len());
|
||||
}
|
||||
Ok(0)
|
||||
},
|
||||
_ => Err(Errno::InvalidArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VnodeImpl for DirInode {
|
||||
@@ -92,6 +118,14 @@ impl VnodeImpl for DirInode {
|
||||
fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator + Copy + 'static> Filesystem for Ramfs<A> {
|
||||
@@ -100,7 +134,7 @@ impl<A: BlockAllocator + Copy + 'static> Filesystem for Ramfs<A> {
|
||||
}
|
||||
|
||||
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
|
||||
let mut node = Vnode::new(name, kind);
|
||||
let mut node = Vnode::new(name, kind, Vnode::SEEKABLE);
|
||||
let data: Box<dyn VnodeImpl> = match kind {
|
||||
VnodeKind::Regular => Box::new(FileInode {
|
||||
data: Bvec::new(self.alloc),
|
||||
@@ -134,7 +168,7 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
kind: VnodeKind,
|
||||
do_create: bool,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
let (element, rest) = vfs::util::path_component_left(path);
|
||||
let (element, rest) = path_component_left(path);
|
||||
assert!(!element.is_empty());
|
||||
|
||||
let node_kind = if rest.is_empty() {
|
||||
@@ -177,7 +211,6 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
// 2. Setup data blocks
|
||||
for block in TarIterator::new(base, base.add(size)) {
|
||||
if block.is_file() {
|
||||
let size = block.size();
|
||||
let node = self.clone().make_path(
|
||||
root.clone(),
|
||||
block.path()?,
|
||||
@@ -185,10 +218,20 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
false,
|
||||
)?;
|
||||
|
||||
node.truncate(size).unwrap();
|
||||
let res = node.write(0, block.data()).unwrap();
|
||||
if res != size {
|
||||
panic!("Expected to write {}B, got {}B", size, res);
|
||||
#[cfg(feature = "cow")]
|
||||
{
|
||||
let mut param = SetupFileParam {
|
||||
data: block.data()
|
||||
};
|
||||
node.ioctl(FILE_SETUP_COW, &mut param as *mut _ as *mut _)?;
|
||||
}
|
||||
#[cfg(not(feature = "cow"))]
|
||||
{
|
||||
let size = block.size();
|
||||
node.truncate(size)?;
|
||||
if node.write(0, block.data())? != size {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
error = { path = "../../error" }
|
||||
libcommon = { path = "../../libcommon" }
|
||||
hashbrown = "0.11.*"
|
||||
|
||||
+35
-8
@@ -1,7 +1,9 @@
|
||||
use crate::VnodeRef;
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use core::cmp::min;
|
||||
use error::Errno;
|
||||
use libcommon::{Read, Seek, SeekDir, Write};
|
||||
|
||||
struct NormalFile {
|
||||
vnode: VnodeRef,
|
||||
@@ -16,14 +18,8 @@ pub struct File {
|
||||
inner: FileInner,
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn normal(vnode: VnodeRef, pos: usize) -> Self {
|
||||
Self {
|
||||
inner: FileInner::Normal(NormalFile { vnode, pos }),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&mut self, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
impl Read for File {
|
||||
fn read(&mut self, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
match &mut self.inner {
|
||||
FileInner::Normal(inner) => {
|
||||
let count = inner.vnode.read(inner.pos, data)?;
|
||||
@@ -35,6 +31,37 @@ impl File {
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for File {
|
||||
fn seek(&mut self, off: isize, whence: SeekDir) -> Result<usize, Errno> {
|
||||
match &mut self.inner {
|
||||
FileInner::Normal(inner) => {
|
||||
if !inner.vnode.is_seekable() {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
let size = inner.vnode.size()?;
|
||||
let pos = match whence {
|
||||
SeekDir::Set => min(off as usize, size),
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
inner.pos = pos;
|
||||
|
||||
Ok(pos)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn normal(vnode: VnodeRef, pos: usize) -> Self {
|
||||
Self {
|
||||
inner: FileInner::Normal(NormalFile { vnode, pos }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
+4
-3
@@ -1,5 +1,6 @@
|
||||
use crate::{util, FileMode, VnodeRef};
|
||||
use crate::{FileMode, VnodeRef};
|
||||
use error::Errno;
|
||||
use libcommon::{path_component_left, path_component_right};
|
||||
|
||||
pub struct Ioctx {
|
||||
root: VnodeRef,
|
||||
@@ -19,7 +20,7 @@ impl Ioctx {
|
||||
let mut rest = path;
|
||||
|
||||
loop {
|
||||
(element, rest) = util::path_component_left(rest);
|
||||
(element, rest) = path_component_left(rest);
|
||||
|
||||
if !at.is_directory() {
|
||||
return Err(Errno::NotADirectory);
|
||||
@@ -62,7 +63,7 @@ impl Ioctx {
|
||||
}
|
||||
|
||||
pub fn mkdir(&self, at: Option<VnodeRef>, path: &str, mode: FileMode) -> Result<(), Errno> {
|
||||
let (parent, name) = util::path_component_right(path);
|
||||
let (parent, name) = path_component_right(path);
|
||||
let parent_node = self.find(at, parent)?;
|
||||
|
||||
parent_node.mkdir(name, mode).map(|_| ())
|
||||
|
||||
@@ -13,4 +13,3 @@ pub mod ioctx;
|
||||
pub use ioctx::Ioctx;
|
||||
pub mod file;
|
||||
pub use file::File;
|
||||
pub mod util;
|
||||
|
||||
+47
-1
@@ -1,6 +1,7 @@
|
||||
use crate::{File, FileMode, Filesystem};
|
||||
use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec};
|
||||
use core::cell::{RefCell, RefMut};
|
||||
use core::ffi::c_void;
|
||||
use core::fmt;
|
||||
use error::Errno;
|
||||
|
||||
@@ -34,6 +35,7 @@ pub struct Vnode {
|
||||
props: RefCell<VnodeProps>,
|
||||
|
||||
kind: VnodeKind,
|
||||
flags: u32,
|
||||
|
||||
pub data: RefCell<Option<VnodeData>>,
|
||||
}
|
||||
@@ -48,13 +50,19 @@ pub trait VnodeImpl {
|
||||
fn truncate(&mut self, node: VnodeRef, size: usize) -> Result<(), Errno>;
|
||||
fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno>;
|
||||
fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno>;
|
||||
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno>;
|
||||
fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno>;
|
||||
}
|
||||
|
||||
impl Vnode {
|
||||
pub fn new(name: &str, kind: VnodeKind) -> VnodeRef {
|
||||
pub const SEEKABLE: u32 = 1 << 0;
|
||||
|
||||
pub fn new(name: &str, kind: VnodeKind, flags: u32) -> VnodeRef {
|
||||
Rc::new(Self {
|
||||
name: name.to_owned(),
|
||||
kind,
|
||||
flags,
|
||||
props: RefCell::new(VnodeProps {
|
||||
mode: FileMode::empty(),
|
||||
}),
|
||||
@@ -78,6 +86,10 @@ impl Vnode {
|
||||
self.kind == VnodeKind::Directory
|
||||
}
|
||||
|
||||
pub fn is_seekable(&self) -> bool {
|
||||
self.flags & Self::SEEKABLE != 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn kind(&self) -> VnodeKind {
|
||||
self.kind
|
||||
@@ -218,6 +230,22 @@ impl Vnode {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(self: &VnodeRef) -> Result<usize, Errno> {
|
||||
if let Some(ref mut data) = *self.data.borrow_mut() {
|
||||
data.node.size(self.clone())
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ioctl(self: &VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
|
||||
if let Some(ref mut data) = *self.data.borrow_mut() {
|
||||
data.node.ioctl(self.clone(), cmd, value)
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Vnode {
|
||||
@@ -262,6 +290,24 @@ mod tests {
|
||||
fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
_node: VnodeRef,
|
||||
_cmd: u64,
|
||||
_value: *mut c_void,
|
||||
) -> Result<isize, Errno> {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
|
||||
fn seek(
|
||||
&mut self,
|
||||
_node: VnodeRef,
|
||||
_pos: usize,
|
||||
_whence: SeekWhence,
|
||||
) -> Result<usize, Errno> {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
impl Filesystem for DummyFs {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
pub fn path_component_left(path: &str) -> (&str, &str) {
|
||||
if let Some((left, right)) = path.split_once('/') {
|
||||
(left, right.trim_start_matches('/'))
|
||||
} else {
|
||||
(path, "")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_component_right(path: &str) -> (&str, &str) {
|
||||
if let Some((left, right)) = path.rsplit_once('/') {
|
||||
(left.trim_end_matches('/'), right)
|
||||
} else {
|
||||
(path, "")
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ test = false
|
||||
error = { path = "../error" }
|
||||
vfs = { path = "../fs/vfs" }
|
||||
memfs = { path = "../fs/memfs" }
|
||||
libcommon = { path = "../libcommon" }
|
||||
cfg-if = "1.x.x"
|
||||
tock-registers = "0.7.x"
|
||||
fdt-rs = { version = "0.x.x", default-features = false }
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::debug::Level;
|
||||
use crate::util;
|
||||
use error::Errno;
|
||||
use fdt_rs::prelude::*;
|
||||
use fdt_rs::{
|
||||
base::DevTree,
|
||||
index::{DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp},
|
||||
};
|
||||
use libcommon::path_component_left;
|
||||
|
||||
#[repr(align(16))]
|
||||
struct Wrap {
|
||||
@@ -74,7 +74,7 @@ fn dump_node(level: Level, node: &INode, depth: usize) {
|
||||
}
|
||||
|
||||
fn find_node<'a>(at: INode<'a>, path: &str) -> Option<INode<'a>> {
|
||||
let (item, path) = util::path_component_left(path);
|
||||
let (item, path) = path_component_left(path);
|
||||
if item == "" {
|
||||
assert_eq!(path, "");
|
||||
Some(at)
|
||||
|
||||
+29
-11
@@ -5,7 +5,9 @@ use crate::mem::{
|
||||
phys::{self, PageUsage},
|
||||
virt::{MapAttributes, Space},
|
||||
};
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
use error::Errno;
|
||||
use libcommon::{Read, Seek, SeekDir};
|
||||
|
||||
trait Elf {
|
||||
type Addr;
|
||||
@@ -86,12 +88,12 @@ fn map_flags(elf_flags: usize) -> MapAttributes {
|
||||
unsafe fn load_bytes<F>(
|
||||
space: &mut Space,
|
||||
dst_virt: usize,
|
||||
read: F,
|
||||
mut read: F,
|
||||
size: usize,
|
||||
flags: usize,
|
||||
) -> Result<(), Errno>
|
||||
where
|
||||
F: Fn(usize, &mut [u8]) -> Result<(), Errno>,
|
||||
F: FnMut(usize, &mut [u8]) -> Result<(), Errno>,
|
||||
{
|
||||
let dst_page_off = dst_virt & 0xFFF;
|
||||
let dst_page = dst_virt & !0xFFF;
|
||||
@@ -125,17 +127,32 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn read_struct<T, F: Seek + Read>(src: &mut F, pos: usize) -> Result<T, Errno> {
|
||||
let mut storage: MaybeUninit<T> = MaybeUninit::uninit();
|
||||
let size = size_of::<T>();
|
||||
src.seek(pos as isize, SeekDir::Set)?;
|
||||
let res = src.read(core::slice::from_raw_parts_mut(
|
||||
storage.as_mut_ptr() as *mut u8,
|
||||
size,
|
||||
))?;
|
||||
if res != size {
|
||||
Err(Errno::InvalidArgument)
|
||||
} else {
|
||||
Ok(storage.assume_init())
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn load_elf(space: &mut Space, elf_base: *const u8) -> Result<usize, Errno> {
|
||||
let ehdr: &Ehdr<Elf64> = unsafe { &*(elf_base as *const _) };
|
||||
pub fn load_elf<F: Seek + Read>(space: &mut Space, source: &mut F) -> Result<usize, Errno> {
|
||||
let ehdr: Ehdr<Elf64> = unsafe { read_struct(source, 0).unwrap() };
|
||||
|
||||
if &ehdr.ident[0..4] != b"\x7FELF" {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
for i in 0..(ehdr.phnum as usize) {
|
||||
let phdr: &Phdr<Elf64> = unsafe {
|
||||
&*(elf_base.add(ehdr.phoff as usize + ehdr.phentsize as usize * i) as *const _)
|
||||
let phdr: Phdr<Elf64> = unsafe {
|
||||
read_struct(source, ehdr.phoff as usize + ehdr.phentsize as usize * i).unwrap()
|
||||
};
|
||||
|
||||
if phdr.typ == 1
|
||||
@@ -154,11 +171,12 @@ pub fn load_elf(space: &mut Space, elf_base: *const u8) -> Result<usize, Errno>
|
||||
space,
|
||||
phdr.vaddr as usize,
|
||||
|off, dst| {
|
||||
let src = elf_base.add(phdr.offset as usize + off);
|
||||
assert!(off + dst.len() <= phdr.filesz as usize);
|
||||
let src_slice = core::slice::from_raw_parts(src, dst.len());
|
||||
dst.copy_from_slice(src_slice);
|
||||
Ok(())
|
||||
source.seek(phdr.offset as isize + off as isize, SeekDir::Set)?;
|
||||
if source.read(dst)? == dst.len() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Errno::InvalidArgument)
|
||||
}
|
||||
},
|
||||
phdr.filesz as usize,
|
||||
phdr.flags as usize,
|
||||
|
||||
@@ -66,21 +66,17 @@ pub unsafe fn enter(initrd: Option<(usize, usize)>) -> ! {
|
||||
let (start, end) = unsafe { *(initrd_ptr as *const (usize, usize)) };
|
||||
let size = end - start;
|
||||
|
||||
infoln!("Constructing initrd filesystem in memory, this may take a while...");
|
||||
let fs = Ramfs::open(start as *mut u8, size, MemfsBlockAlloc {}).unwrap();
|
||||
infoln!("Done constructing ramfs");
|
||||
let root = fs.root().unwrap();
|
||||
let ioctx = Ioctx::new(root);
|
||||
|
||||
// Open a test file
|
||||
let node = ioctx.find(None, "/test.txt").unwrap();
|
||||
let node = ioctx.find(None, "/init").unwrap();
|
||||
let mut file = node.open().unwrap();
|
||||
let mut buf = [0u8; 16];
|
||||
|
||||
while let Ok(count) = file.read(&mut buf) {
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
debugln!("Read {} bytes: {:?}", count, &buf[0..count]);
|
||||
}
|
||||
Process::execve(|space| elf::load_elf(space, &mut file), 0).unwrap();
|
||||
}, initrd as usize);
|
||||
}
|
||||
SCHED.enter();
|
||||
|
||||
@@ -51,12 +51,3 @@ impl<T> InitOnce<T> {
|
||||
}
|
||||
|
||||
unsafe impl<T> Sync for InitOnce<T> {}
|
||||
|
||||
///
|
||||
pub fn path_component_left(path: &str) -> (&str, &str) {
|
||||
if let Some((left, right)) = path.split_once('/') {
|
||||
(left, right.trim_start_matches('/'))
|
||||
} else {
|
||||
(path, "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "libcommon"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
error = { path = "../error" }
|
||||
@@ -0,0 +1,42 @@
|
||||
#![no_std]
|
||||
|
||||
use error::Errno;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum SeekDir {
|
||||
Set,
|
||||
End,
|
||||
Current,
|
||||
}
|
||||
|
||||
pub trait Read {
|
||||
fn read(&mut self, data: &mut [u8]) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub trait Seek {
|
||||
fn seek(&mut self, off: isize, whence: SeekDir) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub trait Write {
|
||||
fn write(&mut self, data: &[u8]) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub fn path_component_left(path: &str) -> (&str, &str) {
|
||||
if let Some((left, right)) = path.split_once('/') {
|
||||
(left, right.trim_start_matches('/'))
|
||||
} else {
|
||||
(path, "")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_component_right(path: &str) -> (&str, &str) {
|
||||
if let Some((left, right)) = path.rsplit_once('/') {
|
||||
(left.trim_end_matches('/'), right)
|
||||
} else {
|
||||
(path, "")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
}
|
||||
Reference in New Issue
Block a user