proc: add simple initrd filesystem
This commit is contained in:
parent
901f311856
commit
aa6b2ac469
@ -8,6 +8,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||||
vfs = { path = "lib/vfs" }
|
vfs = { path = "lib/vfs" }
|
||||||
|
vfs-macros = { path = "lib/vfs/macros" }
|
||||||
|
|
||||||
aarch64-cpu = "9.3.1"
|
aarch64-cpu = "9.3.1"
|
||||||
atomic_enum = "0.2.0"
|
atomic_enum = "0.2.0"
|
||||||
@ -18,4 +19,4 @@ spinning_top = "0.2.5"
|
|||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
tock-registers = "0.8.1"
|
tock-registers = "0.8.1"
|
||||||
|
|
||||||
elf = { version = "0.7.2", default-features = false }
|
elf = { version = "0.7.2", path = "../../rust-elf", default-features = false, features = ["no_std_stream"] }
|
||||||
|
@ -7,5 +7,5 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||||
macros = { path = "macros" }
|
vfs-macros = { path = "macros" }
|
||||||
bitflags = "2.3.3"
|
bitflags = "2.3.3"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "macros"
|
name = "vfs-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Ident;
|
use proc_macro2::{Ident, Span};
|
||||||
use proc_macro_crate::{crate_name, FoundCrate};
|
use proc_macro_crate::{crate_name, FoundCrate};
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use syn::{parse_macro_input, ImplItem, ItemImpl};
|
use syn::{parse_macro_input, ImplItem, ItemImpl};
|
||||||
@ -14,9 +14,11 @@ pub fn auto_vnode_impl(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
let current_crate = crate_name("vfs").unwrap();
|
let current_crate = crate_name("vfs").unwrap();
|
||||||
|
|
||||||
let vfs_crate = match current_crate {
|
let vfs_crate = match current_crate {
|
||||||
FoundCrate::Itself => quote!(crate),
|
FoundCrate::Itself => Ident::new("crate", Span::call_site()),
|
||||||
FoundCrate::Name(name) => quote!( #name ),
|
FoundCrate::Name(name) => Ident::new(&name, Span::call_site()),
|
||||||
};
|
};
|
||||||
|
let vfs_crate = quote! { #vfs_crate };
|
||||||
|
|
||||||
let mut impl_item = parse_macro_input!(input as ItemImpl);
|
let mut impl_item = parse_macro_input!(input as ItemImpl);
|
||||||
let behavior = if attr.is_empty() {
|
let behavior = if attr.is_empty() {
|
||||||
"unimplemented".to_string()
|
"unimplemented".to_string()
|
||||||
|
@ -6,7 +6,7 @@ use quote::quote;
|
|||||||
fn impl_open(vfs: &TS2, behavior: &TS2) -> TS2 {
|
fn impl_open(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||||
quote! {
|
quote! {
|
||||||
fn open(&mut self, _node: &#vfs::VnodeRef, _opts: yggdrasil_abi::io::OpenFlags)
|
fn open(&mut self, _node: &#vfs::VnodeRef, _opts: yggdrasil_abi::io::OpenFlags)
|
||||||
-> Result<usize, yggdrasil_abi::error::Error> {
|
-> Result<u64, yggdrasil_abi::error::Error> {
|
||||||
#behavior
|
#behavior
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ fn impl_create(vfs: &TS2, behavior: &TS2) -> TS2 {
|
|||||||
|
|
||||||
fn impl_write(vfs: &TS2, behavior: &TS2) -> TS2 {
|
fn impl_write(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||||
quote! {
|
quote! {
|
||||||
fn write(&mut self, _node: &#vfs::VnodeRef, _pos: usize, _data: &[u8])
|
fn write(&mut self, _node: &#vfs::VnodeRef, _pos: u64, _data: &[u8])
|
||||||
-> Result<usize, yggdrasil_abi::error::Error> {
|
-> Result<usize, yggdrasil_abi::error::Error> {
|
||||||
#behavior
|
#behavior
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ fn impl_write(vfs: &TS2, behavior: &TS2) -> TS2 {
|
|||||||
|
|
||||||
fn impl_read(vfs: &TS2, behavior: &TS2) -> TS2 {
|
fn impl_read(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||||
quote! {
|
quote! {
|
||||||
fn read(&mut self, _node: &#vfs::VnodeRef, _pos: usize, _data: &mut [u8])
|
fn read(&mut self, _node: &#vfs::VnodeRef, _pos: u64, _data: &mut [u8])
|
||||||
-> Result<usize, yggdrasil_abi::error::Error> {
|
-> Result<usize, yggdrasil_abi::error::Error> {
|
||||||
#behavior
|
#behavior
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use macros::auto_vnode_impl;
|
use vfs_macros::auto_vnode_impl;
|
||||||
use yggdrasil_abi::{error::Error, io::OpenFlags};
|
use yggdrasil_abi::{error::Error, io::OpenFlags};
|
||||||
|
|
||||||
use crate::{node::VnodeImpl, VnodeRef};
|
use crate::{node::VnodeImpl, VnodeRef};
|
||||||
@ -20,7 +20,7 @@ impl CharDeviceWrapper {
|
|||||||
|
|
||||||
#[auto_vnode_impl(error)]
|
#[auto_vnode_impl(error)]
|
||||||
impl VnodeImpl for CharDeviceWrapper {
|
impl VnodeImpl for CharDeviceWrapper {
|
||||||
fn open(&mut self, _node: &VnodeRef, _opts: OpenFlags) -> Result<usize, Error> {
|
fn open(&mut self, _node: &VnodeRef, _opts: OpenFlags) -> Result<u64, Error> {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,11 +28,11 @@ impl VnodeImpl for CharDeviceWrapper {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, _node: &VnodeRef, _pos: usize, data: &mut [u8]) -> Result<usize, Error> {
|
fn read(&mut self, _node: &VnodeRef, _pos: u64, data: &mut [u8]) -> Result<usize, Error> {
|
||||||
self.device.read(true, data)
|
self.device.read(true, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, _node: &VnodeRef, _pos: usize, data: &[u8]) -> Result<usize, Error> {
|
fn write(&mut self, _node: &VnodeRef, _pos: u64, data: &[u8]) -> Result<usize, Error> {
|
||||||
self.device.write(true, data)
|
self.device.write(true, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use yggdrasil_abi::error::Error;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
node::{VnodeKind, VnodeRef},
|
node::{VnodeKind, VnodeRef},
|
||||||
Read, Write,
|
Read, Seek, SeekFrom, Write,
|
||||||
};
|
};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@ -20,7 +20,7 @@ pub type FileRef = Rc<RefCell<File>>;
|
|||||||
|
|
||||||
pub struct NormalFile {
|
pub struct NormalFile {
|
||||||
vnode: VnodeRef,
|
vnode: VnodeRef,
|
||||||
pos: usize,
|
pos: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FileInner {
|
pub enum FileInner {
|
||||||
@ -33,7 +33,7 @@ pub struct File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
pub fn normal(vnode: VnodeRef, pos: usize, flags: FileFlags) -> FileRef {
|
pub fn normal(vnode: VnodeRef, pos: u64, flags: FileFlags) -> FileRef {
|
||||||
Rc::new(RefCell::new(Self {
|
Rc::new(RefCell::new(Self {
|
||||||
inner: FileInner::Normal(NormalFile { vnode, pos }),
|
inner: FileInner::Normal(NormalFile { vnode, pos }),
|
||||||
flags,
|
flags,
|
||||||
@ -51,7 +51,7 @@ impl Write for File {
|
|||||||
FileInner::Normal(inner) => {
|
FileInner::Normal(inner) => {
|
||||||
let count = inner.vnode.write(inner.pos, data)?;
|
let count = inner.vnode.write(inner.pos, data)?;
|
||||||
if inner.vnode.kind() != VnodeKind::Char {
|
if inner.vnode.kind() != VnodeKind::Char {
|
||||||
inner.pos += count;
|
inner.pos += count as u64;
|
||||||
}
|
}
|
||||||
Ok(count)
|
Ok(count)
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ impl Read for File {
|
|||||||
FileInner::Normal(inner) => {
|
FileInner::Normal(inner) => {
|
||||||
let count = inner.vnode.read(inner.pos, data)?;
|
let count = inner.vnode.read(inner.pos, data)?;
|
||||||
if inner.vnode.kind() != VnodeKind::Char {
|
if inner.vnode.kind() != VnodeKind::Char {
|
||||||
inner.pos += count;
|
inner.pos += count as u64;
|
||||||
}
|
}
|
||||||
Ok(count)
|
Ok(count)
|
||||||
}
|
}
|
||||||
@ -77,6 +77,31 @@ impl Read for File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Seek for File {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> {
|
||||||
|
match &mut self.inner {
|
||||||
|
FileInner::Normal(inner) => {
|
||||||
|
// TODO check if the file is actually seekable
|
||||||
|
|
||||||
|
let size = inner.vnode.size()?;
|
||||||
|
let pos = match pos {
|
||||||
|
SeekFrom::Start(offset) => {
|
||||||
|
if offset > size {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
SeekFrom::End(0) => size,
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
inner.pos = pos;
|
||||||
|
|
||||||
|
Ok(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for File {
|
impl Drop for File {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
match &mut self.inner {
|
match &mut self.inner {
|
||||||
|
@ -17,8 +17,16 @@ pub(crate) mod node;
|
|||||||
pub use self::block::BlockDevice;
|
pub use self::block::BlockDevice;
|
||||||
pub use self::char::{CharDevice, CharDeviceWrapper};
|
pub use self::char::{CharDevice, CharDeviceWrapper};
|
||||||
pub use file::{File, FileFlags, FileRef};
|
pub use file::{File, FileFlags, FileRef};
|
||||||
|
pub use fs::Filesystem;
|
||||||
pub use ioctx::IoContext;
|
pub use ioctx::IoContext;
|
||||||
pub use node::{Vnode, VnodeImpl, VnodeKind, VnodeRef, VnodeWeak};
|
pub use node::{Vnode, VnodeDump, VnodeImpl, VnodeKind, VnodeRef, VnodeWeak};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SeekFrom {
|
||||||
|
Start(u64),
|
||||||
|
End(i64),
|
||||||
|
Current(i64),
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Write {
|
pub trait Write {
|
||||||
fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
|
fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
|
||||||
@ -26,4 +34,31 @@ pub trait Write {
|
|||||||
|
|
||||||
pub trait Read {
|
pub trait Read {
|
||||||
fn read(&mut self, data: &mut [u8]) -> Result<usize, Error>;
|
fn read(&mut self, data: &mut [u8]) -> Result<usize, Error>;
|
||||||
|
|
||||||
|
fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
||||||
|
default_read_exact(self, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Seek {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [u8]) -> Result<(), Error> {
|
||||||
|
while !buf.is_empty() {
|
||||||
|
match this.read(buf) {
|
||||||
|
Ok(0) => break,
|
||||||
|
Ok(n) => {
|
||||||
|
let tmp = buf;
|
||||||
|
buf = &mut tmp[n..];
|
||||||
|
}
|
||||||
|
Err(e) => todo!("default_read_exact: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
todo!("default_read_exact unexpected eof")
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,18 @@ use alloc::{
|
|||||||
};
|
};
|
||||||
use yggdrasil_abi::{error::Error, io::OpenFlags};
|
use yggdrasil_abi::{error::Error, io::OpenFlags};
|
||||||
|
|
||||||
use crate::file::{File, FileFlags, FileRef};
|
use crate::{
|
||||||
|
file::{File, FileFlags, FileRef},
|
||||||
|
fs::Filesystem,
|
||||||
|
};
|
||||||
|
|
||||||
pub type VnodeRef = Rc<Vnode>;
|
pub type VnodeRef = Rc<Vnode>;
|
||||||
pub type VnodeWeak = Weak<Vnode>;
|
pub type VnodeWeak = Weak<Vnode>;
|
||||||
|
|
||||||
|
pub struct VnodeDump {
|
||||||
|
node: VnodeRef,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum VnodeKind {
|
pub enum VnodeKind {
|
||||||
Directory,
|
Directory,
|
||||||
@ -34,16 +41,21 @@ pub struct Vnode {
|
|||||||
tree: RefCell<TreeNode>,
|
tree: RefCell<TreeNode>,
|
||||||
kind: VnodeKind,
|
kind: VnodeKind,
|
||||||
data: RefCell<Option<Box<dyn VnodeImpl>>>,
|
data: RefCell<Option<Box<dyn VnodeImpl>>>,
|
||||||
|
fs: RefCell<Option<Rc<dyn Filesystem>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VnodeImpl {
|
pub trait VnodeImpl {
|
||||||
fn create(&mut self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error>;
|
fn create(&mut self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error>;
|
||||||
|
|
||||||
fn open(&mut self, node: &VnodeRef, opts: OpenFlags) -> Result<usize, Error>;
|
fn open(&mut self, node: &VnodeRef, opts: OpenFlags) -> Result<u64, Error>;
|
||||||
fn close(&mut self, node: &VnodeRef) -> Result<(), Error>;
|
fn close(&mut self, node: &VnodeRef) -> Result<(), Error>;
|
||||||
|
|
||||||
fn read(&mut self, node: &VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Error>;
|
fn read(&mut self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error>;
|
||||||
fn write(&mut self, node: &VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Error>;
|
fn write(&mut self, node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error>;
|
||||||
|
|
||||||
|
fn size(&mut self, _node: &VnodeRef) -> Result<u64, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vnode {
|
impl Vnode {
|
||||||
@ -56,6 +68,7 @@ impl Vnode {
|
|||||||
}),
|
}),
|
||||||
kind,
|
kind,
|
||||||
data: RefCell::new(None),
|
data: RefCell::new(None),
|
||||||
|
fs: RefCell::new(None),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +87,11 @@ impl Vnode {
|
|||||||
self.data.borrow_mut()
|
self.data.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn fs(&self) -> Option<Rc<dyn Filesystem>> {
|
||||||
|
self.fs.borrow().clone()
|
||||||
|
}
|
||||||
|
|
||||||
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(),
|
||||||
@ -85,6 +103,10 @@ impl Vnode {
|
|||||||
self.data.borrow_mut().replace(data);
|
self.data.borrow_mut().replace(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_fs(&self, data: Rc<dyn Filesystem>) {
|
||||||
|
self.fs.replace(Some(data));
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_directory(&self) -> bool {
|
pub fn is_directory(&self) -> bool {
|
||||||
self.kind == VnodeKind::Directory
|
self.kind == VnodeKind::Directory
|
||||||
@ -186,7 +208,33 @@ impl Vnode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(self: &VnodeRef, pos: usize, buf: &[u8]) -> Result<usize, Error> {
|
pub fn create(self: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
|
||||||
|
if self.kind != VnodeKind::Directory {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
if name.contains('/') {
|
||||||
|
return Err(Error::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.lookup_or_load(name) {
|
||||||
|
Err(Error::DoesNotExist) => {}
|
||||||
|
Ok(_) => return Err(Error::AlreadyExists),
|
||||||
|
e => return e,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(ref mut data) = *self.data() {
|
||||||
|
let vnode = data.create(self, name, kind)?;
|
||||||
|
if let Some(fs) = self.fs() {
|
||||||
|
vnode.set_fs(fs);
|
||||||
|
}
|
||||||
|
self.add_child(vnode.clone());
|
||||||
|
Ok(vnode)
|
||||||
|
} else {
|
||||||
|
Err(Error::NotImplemented)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(self: &VnodeRef, pos: u64, buf: &[u8]) -> Result<usize, Error> {
|
||||||
if self.kind == VnodeKind::Directory {
|
if self.kind == VnodeKind::Directory {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -198,7 +246,7 @@ impl Vnode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: &VnodeRef, pos: usize, buf: &mut [u8]) -> Result<usize, Error> {
|
pub fn read(self: &VnodeRef, pos: u64, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
if self.kind == VnodeKind::Directory {
|
if self.kind == VnodeKind::Directory {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
@ -209,6 +257,14 @@ impl Vnode {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn size(self: &VnodeRef) -> Result<u64, Error> {
|
||||||
|
if let Some(ref mut data) = *self.data() {
|
||||||
|
data.size(self)
|
||||||
|
} else {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Vnode {
|
impl fmt::Debug for Vnode {
|
||||||
@ -223,3 +279,15 @@ impl fmt::Debug for Vnode {
|
|||||||
write!(f, "[{} {}]", prefix, self.name)
|
write!(f, "[{} {}]", prefix, self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VnodeDump {
|
||||||
|
pub fn new(node: VnodeRef) -> Self {
|
||||||
|
Self { node }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for VnodeDump {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.node.dump(f, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -126,7 +126,7 @@ fn find_node<'a>(at: TNode<'a>, path: &str) -> Option<TNode<'a>> {
|
|||||||
fn dump_node(node: &TNode, depth: usize, level: LogLevel) {
|
fn dump_node(node: &TNode, depth: usize, level: LogLevel) {
|
||||||
fn indent(level: LogLevel, depth: usize) {
|
fn indent(level: LogLevel, depth: usize) {
|
||||||
for _ in 0..depth {
|
for _ in 0..depth {
|
||||||
log_print!(level, " ");
|
log_print_raw!(level, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,18 +138,18 @@ fn dump_node(node: &TNode, depth: usize, level: LogLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
indent(level, depth);
|
indent(level, depth);
|
||||||
log_print!(level, "{:?} {{\n", node_name);
|
log_print_raw!(level, "{:?} {{\n", node_name);
|
||||||
for prop in node.props() {
|
for prop in node.props() {
|
||||||
indent(level, depth + 1);
|
indent(level, depth + 1);
|
||||||
let name = prop.name().unwrap();
|
let name = prop.name().unwrap();
|
||||||
log_print!(level, "{name:?} = ");
|
log_print_raw!(level, "{name:?} = ");
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
"compatible" | "stdout-path" => log_print!(level, "{:?}", prop.str().unwrap()),
|
"compatible" | "stdout-path" => log_print_raw!(level, "{:?}", prop.str().unwrap()),
|
||||||
_ => log_print!(level, "{:x?}", prop.raw()),
|
_ => log_print_raw!(level, "{:x?}", prop.raw()),
|
||||||
}
|
}
|
||||||
|
|
||||||
log_print!(level, "\n");
|
log_print_raw!(level, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
@ -157,5 +157,5 @@ fn dump_node(node: &TNode, depth: usize, level: LogLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
indent(level, depth);
|
indent(level, depth);
|
||||||
log_print!(level, "}}\n");
|
log_print_raw!(level, "}}\n");
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use core::sync::atomic::Ordering;
|
|||||||
|
|
||||||
use aarch64_cpu::registers::{DAIF, ID_AA64MMFR0_EL1, SCTLR_EL1, TCR_EL1, TTBR0_EL1, TTBR1_EL1};
|
use aarch64_cpu::registers::{DAIF, ID_AA64MMFR0_EL1, SCTLR_EL1, TCR_EL1, TTBR0_EL1, TTBR1_EL1};
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
|
use fdt_rs::prelude::PropReader;
|
||||||
use plat_qemu::PLATFORM;
|
use plat_qemu::PLATFORM;
|
||||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
debug,
|
debug,
|
||||||
device::platform::Platform,
|
device::platform::Platform,
|
||||||
fs::devfs,
|
fs::{devfs, Initrd, INITRD_DATA},
|
||||||
mem::{
|
mem::{
|
||||||
heap,
|
heap,
|
||||||
phys::{self, reserved::reserve_region, PageUsage, PhysicalMemoryRegion},
|
phys::{self, reserved::reserve_region, PageUsage, PhysicalMemoryRegion},
|
||||||
@ -135,6 +136,16 @@ impl AArch64 {
|
|||||||
unsafe fn init_physical_memory(&self, dtb_phys: usize) -> Result<(), Error> {
|
unsafe fn init_physical_memory(&self, dtb_phys: usize) -> Result<(), Error> {
|
||||||
let dt = self.device_tree();
|
let dt = self.device_tree();
|
||||||
|
|
||||||
|
if let Some(initrd) = INITRD_DATA.try_get() {
|
||||||
|
reserve_region(
|
||||||
|
"initrd",
|
||||||
|
PhysicalMemoryRegion {
|
||||||
|
base: initrd.phys_page_start,
|
||||||
|
size: initrd.phys_page_len,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
reserve_region(
|
reserve_region(
|
||||||
"dtb",
|
"dtb",
|
||||||
PhysicalMemoryRegion {
|
PhysicalMemoryRegion {
|
||||||
@ -148,6 +159,41 @@ impl AArch64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_initrd() {
|
||||||
|
let dt = ARCHITECTURE.device_tree();
|
||||||
|
let Some(chosen) = dt.node_by_path("/chosen") else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(initrd_start) = devtree::find_prop(&chosen, "linux,initrd-start") else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(initrd_end) = devtree::find_prop(&chosen, "linux,initrd-end") else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let initrd_start = initrd_start.u64(0).unwrap() as usize;
|
||||||
|
let initrd_end = initrd_end.u64(0).unwrap() as usize;
|
||||||
|
|
||||||
|
let start_aligned = initrd_start & !0xFFF;
|
||||||
|
let end_aligned = initrd_end & !0xFFF;
|
||||||
|
|
||||||
|
let data = unsafe {
|
||||||
|
core::slice::from_raw_parts(
|
||||||
|
initrd_start.virtualize() as *const _,
|
||||||
|
initrd_end - initrd_start,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let initrd = Initrd {
|
||||||
|
phys_page_start: start_aligned,
|
||||||
|
phys_page_len: end_aligned - start_aligned,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
|
||||||
|
INITRD_DATA.init(initrd);
|
||||||
|
}
|
||||||
|
|
||||||
/// AArch64 kernel main entry point
|
/// AArch64 kernel main entry point
|
||||||
pub fn kernel_main(dtb_phys: usize) -> ! {
|
pub fn kernel_main(dtb_phys: usize) -> ! {
|
||||||
// NOTE it is critical that the code does not panic until the debug is set up, otherwise no
|
// NOTE it is critical that the code does not panic until the debug is set up, otherwise no
|
||||||
@ -167,6 +213,9 @@ pub fn kernel_main(dtb_phys: usize) -> ! {
|
|||||||
|
|
||||||
exception::init_exceptions();
|
exception::init_exceptions();
|
||||||
|
|
||||||
|
// Setup initrd
|
||||||
|
setup_initrd();
|
||||||
|
|
||||||
debugln!("Initializing {} platform", PLATFORM.name());
|
debugln!("Initializing {} platform", PLATFORM.name());
|
||||||
unsafe {
|
unsafe {
|
||||||
ARCHITECTURE
|
ARCHITECTURE
|
||||||
|
20
src/debug.rs
20
src/debug.rs
@ -99,6 +99,26 @@ impl fmt::Write for DebugPrinter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hex_dump(level: LogLevel, addr_offset: usize, data: &[u8]) {
|
||||||
|
for (i, b) in data.iter().enumerate() {
|
||||||
|
if i % 16 == 0 {
|
||||||
|
log_print_raw!(level, "{:X}: ", addr_offset + i)
|
||||||
|
}
|
||||||
|
|
||||||
|
log_print_raw!(level, "{:02X}", data[i]);
|
||||||
|
|
||||||
|
if i % 16 == 15 {
|
||||||
|
log_print_raw!(level, "\n");
|
||||||
|
} else if i % 2 == 1 {
|
||||||
|
log_print_raw!(level, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.len() % 16 != 0 {
|
||||||
|
log_print_raw!(level, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Initializes the debug logging faclities.
|
/// Initializes the debug logging faclities.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
//! Filesystem implementations
|
//! Filesystem implementations
|
||||||
|
|
||||||
|
use crate::util::OneTimeInit;
|
||||||
|
|
||||||
|
pub struct Initrd {
|
||||||
|
pub phys_page_start: usize,
|
||||||
|
pub phys_page_len: usize,
|
||||||
|
pub data: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static INITRD_DATA: OneTimeInit<Initrd> = OneTimeInit::new();
|
||||||
|
|
||||||
pub mod devfs;
|
pub mod devfs;
|
||||||
|
pub mod tar;
|
||||||
|
332
src/fs/tar.rs
Normal file
332
src/fs/tar.rs
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
use abi::error::Error;
|
||||||
|
use alloc::{boxed::Box, rc::Rc};
|
||||||
|
use vfs::{Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||||
|
use vfs_macros::auto_vnode_impl;
|
||||||
|
use yggdrasil_abi::io::OpenFlags;
|
||||||
|
|
||||||
|
use crate::util::OneTimeInit;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct OctalField<const N: usize> {
|
||||||
|
data: [u8; N],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TarString<const N: usize> {
|
||||||
|
data: [u8; N],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TarIterator<'a> {
|
||||||
|
data: &'a [u8],
|
||||||
|
offset: usize,
|
||||||
|
zero_blocks: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct TarEntry {
|
||||||
|
name: TarString<100>,
|
||||||
|
mode: OctalField<8>,
|
||||||
|
uid: OctalField<8>,
|
||||||
|
gid: OctalField<8>,
|
||||||
|
size: OctalField<12>,
|
||||||
|
mtime: OctalField<12>,
|
||||||
|
checksum: OctalField<8>,
|
||||||
|
type_: u8,
|
||||||
|
link_name: [u8; 100],
|
||||||
|
magic: [u8; 8],
|
||||||
|
user: [u8; 32],
|
||||||
|
group: [u8; 32],
|
||||||
|
dev_major: OctalField<8>,
|
||||||
|
dev_minor: OctalField<8>,
|
||||||
|
prefix: [u8; 155],
|
||||||
|
__pad: [u8; 12],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TarIterator<'a> {
|
||||||
|
pub const fn new(data: &'a [u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
data,
|
||||||
|
offset: 0,
|
||||||
|
zero_blocks: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for TarIterator<'a> {
|
||||||
|
type Item = Result<(&'a TarEntry, Option<&'a [u8]>), Error>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
loop {
|
||||||
|
if self.offset + 512 > self.data.len() {
|
||||||
|
break None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hdr_ptr = &self.data[self.offset..];
|
||||||
|
let hdr = unsafe { core::mem::transmute::<*const u8, &TarEntry>(hdr_ptr.as_ptr()) };
|
||||||
|
|
||||||
|
if hdr.is_empty() {
|
||||||
|
if self.zero_blocks == 1 {
|
||||||
|
self.offset = self.data.len();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.zero_blocks += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (data, size_aligned) = match hdr.type_ {
|
||||||
|
0 | b'0' => {
|
||||||
|
let size = usize::from(&hdr.size);
|
||||||
|
|
||||||
|
if self.offset + 512 + size > self.data.len() {
|
||||||
|
return Some(Err(Error::InvalidArgument));
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = &self.data[self.offset + 512..self.offset + 512 + size];
|
||||||
|
let size_aligned = (size + 511) & !511;
|
||||||
|
|
||||||
|
(Some(data), size_aligned)
|
||||||
|
}
|
||||||
|
// Directory
|
||||||
|
b'5' => (None, 0),
|
||||||
|
_ => todo!("Unknown node kind: {}", hdr.type_),
|
||||||
|
};
|
||||||
|
self.offset += size_aligned + 512;
|
||||||
|
|
||||||
|
break Some(Ok((hdr, data)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> From<&OctalField<N>> for usize {
|
||||||
|
fn from(value: &OctalField<N>) -> Self {
|
||||||
|
let mut acc = 0;
|
||||||
|
for i in 0..N {
|
||||||
|
if value.data[i] == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
acc <<= 3;
|
||||||
|
acc |= (value.data[i] - b'0') as usize;
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> TarString<N> {
|
||||||
|
pub fn as_str(&self) -> Result<&str, Error> {
|
||||||
|
core::str::from_utf8(&self.data[..self.len()]).map_err(|_| Error::InvalidArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
for i in 0..N {
|
||||||
|
if self.data[i] == 0 {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
N
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TarEntry {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.name.data[0] == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn node_kind(&self) -> VnodeKind {
|
||||||
|
match self.type_ {
|
||||||
|
0 | b'0' => VnodeKind::Regular,
|
||||||
|
b'5' => VnodeKind::Directory,
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TarFilesystem {
|
||||||
|
root: OneTimeInit<VnodeRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Filesystem for TarFilesystem {
|
||||||
|
fn dev(self: Rc<Self>) -> Option<&'static dyn vfs::BlockDevice> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn root(self: Rc<Self>) -> Result<VnodeRef, Error> {
|
||||||
|
self.root.try_get().cloned().ok_or(Error::DoesNotExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn data(&self) -> Option<core::cell::Ref<dyn core::any::Any>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DirInode;
|
||||||
|
struct RegularInode {
|
||||||
|
data: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[auto_vnode_impl]
|
||||||
|
impl VnodeImpl for DirInode {
|
||||||
|
fn create(&mut self, _at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
|
||||||
|
let child = Vnode::new(name, kind);
|
||||||
|
match kind {
|
||||||
|
VnodeKind::Directory => child.set_data(Box::new(DirInode)),
|
||||||
|
VnodeKind::Regular => (),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
Ok(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[auto_vnode_impl]
|
||||||
|
impl VnodeImpl for RegularInode {
|
||||||
|
fn open(&mut self, node: &VnodeRef, opts: OpenFlags) -> Result<u64, Error> {
|
||||||
|
if opts.is_write() {
|
||||||
|
panic!("TODO: tarfs write");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&mut self, node: &VnodeRef) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
let pos = pos as usize;
|
||||||
|
if pos > self.data.len() {
|
||||||
|
return Err(Error::InvalidFile);
|
||||||
|
}
|
||||||
|
let mut rem = core::cmp::min(self.data.len() - pos, data.len());
|
||||||
|
data[..rem].copy_from_slice(&self.data[pos..pos + rem]);
|
||||||
|
Ok(rem)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&mut self, _node: &VnodeRef) -> Result<u64, Error> {
|
||||||
|
Ok(self.data.len() as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TarFilesystem {
|
||||||
|
fn make_path(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
at: &VnodeRef,
|
||||||
|
path: &str,
|
||||||
|
create: bool,
|
||||||
|
) -> Result<VnodeRef, Error> {
|
||||||
|
debugln!("make_path {:?}", path);
|
||||||
|
if path.is_empty() {
|
||||||
|
return Ok(at.clone());
|
||||||
|
}
|
||||||
|
let (element, rest) = abi::path::split_left(path);
|
||||||
|
assert!(!element.is_empty());
|
||||||
|
|
||||||
|
let node = at.lookup(element);
|
||||||
|
let node = match node {
|
||||||
|
Some(node) => node,
|
||||||
|
None => {
|
||||||
|
if !create {
|
||||||
|
debugln!("path {:?} does not exist", path);
|
||||||
|
return Err(Error::DoesNotExist);
|
||||||
|
}
|
||||||
|
|
||||||
|
infoln!("Create {:?}", element);
|
||||||
|
at.create(element, VnodeKind::Directory)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if rest.is_empty() {
|
||||||
|
Ok(node)
|
||||||
|
} else {
|
||||||
|
self.make_path(&node, rest, create)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_node_initial(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
name: &str,
|
||||||
|
hdr: &TarEntry,
|
||||||
|
data: Option<&[u8]>,
|
||||||
|
) -> VnodeRef {
|
||||||
|
assert!(!name.is_empty());
|
||||||
|
assert!(!name.contains('/'));
|
||||||
|
|
||||||
|
let kind = hdr.node_kind();
|
||||||
|
let node = Vnode::new(name, kind);
|
||||||
|
node.set_fs(self.clone());
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
VnodeKind::Directory => node.set_data(Box::new(DirInode)),
|
||||||
|
VnodeKind::Regular => {}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
node
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_slice_internal(self: &Rc<Self>, tar_data: &'static [u8]) -> Result<VnodeRef, Error> {
|
||||||
|
let root = Vnode::new("", VnodeKind::Directory);
|
||||||
|
root.set_fs(self.clone());
|
||||||
|
root.set_data(Box::new(DirInode));
|
||||||
|
|
||||||
|
// 1. Create paths in tar
|
||||||
|
for item in TarIterator::new(tar_data) {
|
||||||
|
let Ok((hdr, data)) = item else {
|
||||||
|
warnln!("Tar image is truncated");
|
||||||
|
return Err(Error::InvalidArgument);
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = hdr.name.as_str()?.trim_matches('/');
|
||||||
|
infoln!("path = {:?}", path);
|
||||||
|
let (dirname, filename) = abi::path::split_right(path);
|
||||||
|
let parent = self.make_path(&root, dirname, true)?;
|
||||||
|
let node = self.create_node_initial(filename, hdr, data);
|
||||||
|
|
||||||
|
parent.add_child(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Associate files with their data
|
||||||
|
for item in TarIterator::new(tar_data) {
|
||||||
|
let Ok((hdr, data)) = item else {
|
||||||
|
panic!("Unreachable");
|
||||||
|
};
|
||||||
|
if hdr.node_kind() == VnodeKind::Regular {
|
||||||
|
let data = data.unwrap();
|
||||||
|
let path = hdr.name.as_str()?.trim_matches('/');
|
||||||
|
let node = self.make_path(&root, path, false)?;
|
||||||
|
node.set_data(Box::new(RegularInode { data }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_slice(tar_data: &'static [u8]) -> Result<Rc<Self>, Error> {
|
||||||
|
let fs = Rc::new(TarFilesystem {
|
||||||
|
root: OneTimeInit::new(),
|
||||||
|
});
|
||||||
|
let root = fs.from_slice_internal(tar_data)?;
|
||||||
|
fs.root.init(root);
|
||||||
|
|
||||||
|
Ok(fs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn init() {
|
||||||
|
// let Some(initrd) = INITRD_DATA.try_get() else {
|
||||||
|
// warnln!("No initrd found");
|
||||||
|
// return;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// let fs = match TarFilesystem::from_slice(initrd.data) {
|
||||||
|
// Ok(fs) => fs,
|
||||||
|
// Err(err) => {
|
||||||
|
// warnln!("Could not initialize tar filesystem: {:?}", err);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// let r = fs.root().unwrap();
|
||||||
|
// let dump = VnodeDump::new(r);
|
||||||
|
// infoln!("{:?}", dump);
|
||||||
|
//
|
||||||
|
// todo!()
|
||||||
|
// }
|
54
src/main.rs
54
src/main.rs
@ -15,7 +15,15 @@
|
|||||||
|
|
||||||
extern crate yggdrasil_abi as abi;
|
extern crate yggdrasil_abi as abi;
|
||||||
|
|
||||||
|
use core::ops::DerefMut;
|
||||||
|
|
||||||
|
use abi::{
|
||||||
|
error::Error,
|
||||||
|
io::{OpenFlags, RawFd},
|
||||||
|
};
|
||||||
|
use fs::{devfs, tar::TarFilesystem, INITRD_DATA};
|
||||||
use task::process::Process;
|
use task::process::Process;
|
||||||
|
use vfs::{Filesystem, IoContext, Read, VnodeRef};
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
@ -34,6 +42,12 @@ pub mod syscall;
|
|||||||
pub mod task;
|
pub mod task;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
fn setup_root() -> Result<VnodeRef, Error> {
|
||||||
|
let initrd_data = INITRD_DATA.get();
|
||||||
|
let fs = TarFilesystem::from_slice(initrd_data.data)?;
|
||||||
|
fs.root()
|
||||||
|
}
|
||||||
|
|
||||||
/// Entry point for common kernel code.
|
/// Entry point for common kernel code.
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
@ -41,15 +55,40 @@ pub mod util;
|
|||||||
/// This function is meant to be used as a kernel-space process after all the platform-specific
|
/// This function is meant to be used as a kernel-space process after all the platform-specific
|
||||||
/// initialization has finished.
|
/// initialization has finished.
|
||||||
pub fn kernel_main() {
|
pub fn kernel_main() {
|
||||||
|
let root = match setup_root() {
|
||||||
|
Ok(root) => root,
|
||||||
|
Err(err) => {
|
||||||
|
warnln!("Could not setup root from initrd: {:?}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let devfs_root = devfs::root();
|
||||||
|
let tty_node = devfs_root.lookup("ttyS0").unwrap();
|
||||||
|
|
||||||
|
let ioctx = IoContext::new(root);
|
||||||
|
let node = ioctx.find(None, "/init", false).unwrap();
|
||||||
|
let file = node.open(OpenFlags::new().read()).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let user_init = proc::exec::load_elf(file, &["/init"]).unwrap();
|
||||||
|
let mut io = user_init.io.lock();
|
||||||
|
io.set_ioctx(ioctx);
|
||||||
|
let stdout = tty_node.open(OpenFlags::new().write()).unwrap();
|
||||||
|
let stderr = stdout.clone();
|
||||||
|
|
||||||
|
io.set_file(RawFd::STDOUT, stdout).unwrap();
|
||||||
|
io.set_file(RawFd::STDERR, stderr).unwrap();
|
||||||
|
drop(io);
|
||||||
|
user_init.enqueue_somewhere();
|
||||||
|
}
|
||||||
|
|
||||||
// static USER_PROGRAM: &[u8] = include_bytes!(concat!(
|
// static USER_PROGRAM: &[u8] = include_bytes!(concat!(
|
||||||
// "../../target/aarch64-unknown-yggdrasil/",
|
// "../../target/aarch64-unknown-yggdrasil/",
|
||||||
// env!("PROFILE"),
|
// env!("PROFILE"),
|
||||||
// "/test_program"
|
// "/test_program"
|
||||||
// ));
|
// ));
|
||||||
|
|
||||||
// let devfs_root = devfs::root();
|
|
||||||
// let tty_node = devfs_root.lookup("ttyS0").unwrap();
|
|
||||||
|
|
||||||
// let ioctx = IoContext::new(devfs_root.clone());
|
// let ioctx = IoContext::new(devfs_root.clone());
|
||||||
|
|
||||||
// // Spawn a test user task
|
// // Spawn a test user task
|
||||||
@ -61,15 +100,6 @@ pub fn kernel_main() {
|
|||||||
// // Setup I/O for the process
|
// // Setup I/O for the process
|
||||||
// // let mut io = proc.io.lock();
|
// // let mut io = proc.io.lock();
|
||||||
// // io.set_file(RawFd::STDOUT, todo!()).unwrap();
|
// // io.set_file(RawFd::STDOUT, todo!()).unwrap();
|
||||||
// {
|
|
||||||
// let mut io = proc.io.lock();
|
|
||||||
// io.set_ioctx(ioctx);
|
|
||||||
// let stdout = tty_node.open(OpenFlags::new().write()).unwrap();
|
|
||||||
// let stderr = stdout.clone();
|
|
||||||
|
|
||||||
// io.set_file(RawFd::STDOUT, stdout).unwrap();
|
|
||||||
// io.set_file(RawFd::STDERR, stderr).unwrap();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// proc.enqueue_somewhere();
|
// proc.enqueue_somewhere();
|
||||||
// }
|
// }
|
||||||
|
@ -3,6 +3,7 @@ use core::mem::size_of;
|
|||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
|
use vfs::{FileRef, Read, Seek};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::aarch64::context::TaskContext,
|
arch::aarch64::context::TaskContext,
|
||||||
@ -66,13 +67,13 @@ fn setup_args(space: &mut AddressSpace, virt: usize, args: &[&str]) -> Result<()
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up a userspace structure from a slice defining an ELF binary
|
fn setup_binary(
|
||||||
pub fn create_from_memory(data: &[u8], args: &[&str]) -> Result<Rc<Process>, Error> {
|
mut space: AddressSpace,
|
||||||
|
entry: usize,
|
||||||
|
args: &[&str],
|
||||||
|
) -> Result<Rc<Process>, Error> {
|
||||||
const USER_STACK_PAGES: usize = 8;
|
const USER_STACK_PAGES: usize = 8;
|
||||||
|
|
||||||
let mut space = AddressSpace::new_empty()?;
|
|
||||||
let elf_entry = proc::load_elf_from_memory(&mut space, data);
|
|
||||||
|
|
||||||
let virt_stack_base = 0x10000000;
|
let virt_stack_base = 0x10000000;
|
||||||
// 0x1000 of guard page
|
// 0x1000 of guard page
|
||||||
let virt_args_base = virt_stack_base + (USER_STACK_PAGES + 1) * 0x1000;
|
let virt_args_base = virt_stack_base + (USER_STACK_PAGES + 1) * 0x1000;
|
||||||
@ -88,10 +89,16 @@ pub fn create_from_memory(data: &[u8], args: &[&str]) -> Result<Rc<Process>, Err
|
|||||||
|
|
||||||
setup_args(&mut space, virt_args_base, args)?;
|
setup_args(&mut space, virt_args_base, args)?;
|
||||||
|
|
||||||
debugln!("Entry: {:#x}", elf_entry);
|
debugln!(
|
||||||
|
"Entry: {:#x}, Stack: {:#x}..{:#x}, Args: {:#x}",
|
||||||
|
entry,
|
||||||
|
virt_stack_base,
|
||||||
|
virt_stack_base + USER_STACK_PAGES * 0x1000,
|
||||||
|
virt_args_base
|
||||||
|
);
|
||||||
|
|
||||||
let context = TaskContext::user(
|
let context = TaskContext::user(
|
||||||
elf_entry,
|
entry,
|
||||||
virt_args_base,
|
virt_args_base,
|
||||||
space.physical_address(),
|
space.physical_address(),
|
||||||
virt_stack_base + USER_STACK_PAGES * 0x1000,
|
virt_stack_base + USER_STACK_PAGES * 0x1000,
|
||||||
@ -99,3 +106,18 @@ pub fn create_from_memory(data: &[u8], args: &[&str]) -> Result<Rc<Process>, Err
|
|||||||
|
|
||||||
Ok(Process::new_with_context(Some(space), context))
|
Ok(Process::new_with_context(Some(space), context))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_elf(file: FileRef, args: &[&str]) -> Result<Rc<Process>, Error> {
|
||||||
|
let mut space = AddressSpace::new_empty()?;
|
||||||
|
let elf_entry = proc::load_elf_from_file(&mut space, file)?;
|
||||||
|
|
||||||
|
setup_binary(space, elf_entry, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up a userspace structure from a slice defining an ELF binary
|
||||||
|
pub fn create_from_memory(data: &[u8], args: &[&str]) -> Result<Rc<Process>, Error> {
|
||||||
|
let mut space = AddressSpace::new_empty()?;
|
||||||
|
let elf_entry = proc::load_elf_from_memory(&mut space, data);
|
||||||
|
|
||||||
|
setup_binary(space, elf_entry, args)
|
||||||
|
}
|
||||||
|
165
src/proc/mod.rs
165
src/proc/mod.rs
@ -4,22 +4,76 @@ pub mod exec;
|
|||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod wait;
|
pub mod wait;
|
||||||
|
|
||||||
use aarch64_cpu::registers::TTBR0_EL1;
|
use aarch64_cpu::registers::{TCR_EL1::A1::TTBR0, TTBR0_EL1};
|
||||||
|
use alloc::rc::Rc;
|
||||||
use elf::{
|
use elf::{
|
||||||
abi::{PF_W, PF_X, PT_LOAD},
|
abi::{PF_W, PF_X, PT_LOAD},
|
||||||
endian::AnyEndian,
|
endian::AnyEndian,
|
||||||
ElfBytes,
|
ElfBytes, ElfStream, ParseError,
|
||||||
};
|
};
|
||||||
use tock_registers::interfaces::Writeable;
|
use tock_registers::interfaces::Writeable;
|
||||||
|
use vfs::{FileRef, Read, Seek, SeekFrom};
|
||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::aarch64::table::tlb_flush_vaae1,
|
arch::aarch64::table::tlb_flush_vaae1,
|
||||||
|
debug::hex_dump,
|
||||||
mem::{
|
mem::{
|
||||||
phys::{self, PageUsage},
|
phys::{self, PageUsage},
|
||||||
table::{AddressSpace, PageAttributes},
|
table::{AddressSpace, PageAttributes},
|
||||||
|
ConvertAddress,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct FileReader<'a> {
|
||||||
|
file: &'a FileRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl elf::io_traits::Read for FileReader<'_> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, elf::io_traits::StreamError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), elf::io_traits::StreamError> {
|
||||||
|
self.file
|
||||||
|
.borrow_mut()
|
||||||
|
.read_exact(buf)
|
||||||
|
.map_err(conv_stream_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl elf::io_traits::Seek for FileReader<'_> {
|
||||||
|
fn seek(&mut self, pos: elf::io_traits::SeekFrom) -> Result<u64, elf::io_traits::StreamError> {
|
||||||
|
self.file
|
||||||
|
.borrow_mut()
|
||||||
|
.seek(conv_seek_from(pos))
|
||||||
|
.map_err(conv_stream_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn conv_stream_error(v: Error) -> elf::io_traits::StreamError {
|
||||||
|
elf::io_traits::StreamError {
|
||||||
|
message: "Elf read error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn conv_seek_from(v: elf::io_traits::SeekFrom) -> SeekFrom {
|
||||||
|
match v {
|
||||||
|
elf::io_traits::SeekFrom::End(off) => SeekFrom::End(off),
|
||||||
|
elf::io_traits::SeekFrom::Start(off) => SeekFrom::Start(off),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_parse_error(v: ParseError) -> Error {
|
||||||
|
warnln!("ELF loading error: {:?}", v);
|
||||||
|
Error::InvalidFile
|
||||||
|
}
|
||||||
|
|
||||||
fn load_segment(space: &mut AddressSpace, addr: usize, data: &[u8], memsz: usize, elf_attrs: u32) {
|
fn load_segment(space: &mut AddressSpace, addr: usize, data: &[u8], memsz: usize, elf_attrs: u32) {
|
||||||
let attrs = match (elf_attrs & PF_W, elf_attrs & PF_X) {
|
let attrs = match (elf_attrs & PF_W, elf_attrs & PF_X) {
|
||||||
(0, 0) => PageAttributes::AP_BOTH_READONLY,
|
(0, 0) => PageAttributes::AP_BOTH_READONLY,
|
||||||
@ -62,6 +116,113 @@ fn load_segment(space: &mut AddressSpace, addr: usize, data: &[u8], memsz: usize
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_bytes<F>(
|
||||||
|
space: &mut AddressSpace,
|
||||||
|
addr: usize,
|
||||||
|
mut src: F,
|
||||||
|
len: usize,
|
||||||
|
elf_attrs: u32,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
F: FnMut(usize, &mut [u8]) -> Result<(), Error>,
|
||||||
|
{
|
||||||
|
// TODO check for crazy addresses here
|
||||||
|
|
||||||
|
let attrs = match (elf_attrs & PF_W, elf_attrs & PF_X) {
|
||||||
|
(0, 0) => PageAttributes::AP_BOTH_READONLY,
|
||||||
|
(_, 0) => PageAttributes::AP_BOTH_READWRITE,
|
||||||
|
(0, _) => PageAttributes::AP_BOTH_READONLY,
|
||||||
|
(_, _) => PageAttributes::AP_BOTH_READWRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let dst_page_off = addr & 0xFFF;
|
||||||
|
let dst_page_aligned = addr & !0xFFF;
|
||||||
|
let mut off = 0usize;
|
||||||
|
let mut rem = len;
|
||||||
|
|
||||||
|
while rem != 0 {
|
||||||
|
let page_idx = (dst_page_off + off) / 0x1000;
|
||||||
|
let page_off = (dst_page_off + off) % 0x1000;
|
||||||
|
let count = core::cmp::min(rem, 0x1000 - page_off);
|
||||||
|
|
||||||
|
let virt_page = dst_page_aligned + page_idx * 0x1000;
|
||||||
|
assert_eq!(virt_page & 0xFFF, 0);
|
||||||
|
if let Some(_) = space.translate(virt_page) {
|
||||||
|
// Handle these cases
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
let phys_page = phys::alloc_page(PageUsage::Used)?;
|
||||||
|
debugln!("map {:#x} -> {:#x}", virt_page, phys_page);
|
||||||
|
space.map_page(virt_page, phys_page, attrs)?;
|
||||||
|
|
||||||
|
let dst_slice = unsafe {
|
||||||
|
let addr = (phys_page + page_off).virtualize();
|
||||||
|
|
||||||
|
core::slice::from_raw_parts_mut(addr as *mut u8, count)
|
||||||
|
};
|
||||||
|
|
||||||
|
src(off, dst_slice)?;
|
||||||
|
debugln!("{:#x} (off = {}):", virt_page + page_off, page_off);
|
||||||
|
// hex_dump(
|
||||||
|
// crate::debug::LogLevel::Debug,
|
||||||
|
// virt_page + page_off,
|
||||||
|
// dst_slice,
|
||||||
|
// );
|
||||||
|
|
||||||
|
rem -= count;
|
||||||
|
off += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_elf_from_file(space: &mut AddressSpace, file: FileRef) -> Result<usize, Error> {
|
||||||
|
let file = FileReader { file: &file };
|
||||||
|
|
||||||
|
let elf = ElfStream::<AnyEndian, _>::open_stream(file).map_err(from_parse_error)?;
|
||||||
|
|
||||||
|
for phdr in elf.segments() {
|
||||||
|
if phdr.p_type != PT_LOAD {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugln!("LOAD {:#x}", phdr.p_vaddr);
|
||||||
|
|
||||||
|
if phdr.p_filesz > 0 {
|
||||||
|
load_bytes(
|
||||||
|
space,
|
||||||
|
phdr.p_vaddr as usize,
|
||||||
|
|off, dst| {
|
||||||
|
let mut source = file.file.borrow_mut();
|
||||||
|
source.seek(SeekFrom::Start(phdr.p_offset + off as u64))?;
|
||||||
|
source.read_exact(dst)
|
||||||
|
},
|
||||||
|
phdr.p_filesz as usize,
|
||||||
|
phdr.p_flags,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if phdr.p_memsz > phdr.p_filesz {
|
||||||
|
let addr = (phdr.p_vaddr + phdr.p_filesz) as usize;
|
||||||
|
let len = (phdr.p_memsz - phdr.p_filesz) as usize;
|
||||||
|
|
||||||
|
load_bytes(
|
||||||
|
space,
|
||||||
|
addr,
|
||||||
|
|_, dst| {
|
||||||
|
dst.fill(0);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
len,
|
||||||
|
phdr.p_flags,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(elf.ehdr.e_entry as usize)
|
||||||
|
}
|
||||||
|
|
||||||
/// Loads an ELF image into the address space from a slice
|
/// Loads an ELF image into the address space from a slice
|
||||||
pub fn load_elf_from_memory(space: &mut AddressSpace, src: &[u8]) -> usize {
|
pub fn load_elf_from_memory(space: &mut AddressSpace, src: &[u8]) -> usize {
|
||||||
// Map the address space temporarily
|
// Map the address space temporarily
|
||||||
|
@ -69,6 +69,14 @@ impl<T> OneTimeInit<T> {
|
|||||||
|
|
||||||
unsafe { (*self.value.get()).assume_init_ref() }
|
unsafe { (*self.value.get()).assume_init_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_get(&self) -> Option<&T> {
|
||||||
|
if self.state.load(Ordering::Acquire) {
|
||||||
|
Some(self.get())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const N: usize> StaticVector<T, N> {
|
impl<T, const N: usize> StaticVector<T, N> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user