proc: add simple initrd filesystem
This commit is contained in:
parent
901f311856
commit
aa6b2ac469
@ -8,6 +8,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||
vfs = { path = "lib/vfs" }
|
||||
vfs-macros = { path = "lib/vfs/macros" }
|
||||
|
||||
aarch64-cpu = "9.3.1"
|
||||
atomic_enum = "0.2.0"
|
||||
@ -18,4 +19,4 @@ spinning_top = "0.2.5"
|
||||
static_assertions = "1.1.0"
|
||||
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]
|
||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||
macros = { path = "macros" }
|
||||
vfs-macros = { path = "macros" }
|
||||
bitflags = "2.3.3"
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "macros"
|
||||
name = "vfs-macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Ident;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use proc_macro_crate::{crate_name, FoundCrate};
|
||||
use quote::{quote, ToTokens};
|
||||
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 vfs_crate = match current_crate {
|
||||
FoundCrate::Itself => quote!(crate),
|
||||
FoundCrate::Name(name) => quote!( #name ),
|
||||
FoundCrate::Itself => Ident::new("crate", Span::call_site()),
|
||||
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 behavior = if attr.is_empty() {
|
||||
"unimplemented".to_string()
|
||||
|
@ -6,7 +6,7 @@ use quote::quote;
|
||||
fn impl_open(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||
quote! {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@ fn impl_create(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||
|
||||
fn impl_write(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||
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> {
|
||||
#behavior
|
||||
}
|
||||
@ -40,7 +40,7 @@ fn impl_write(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||
|
||||
fn impl_read(vfs: &TS2, behavior: &TS2) -> TS2 {
|
||||
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> {
|
||||
#behavior
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use macros::auto_vnode_impl;
|
||||
use vfs_macros::auto_vnode_impl;
|
||||
use yggdrasil_abi::{error::Error, io::OpenFlags};
|
||||
|
||||
use crate::{node::VnodeImpl, VnodeRef};
|
||||
@ -20,7 +20,7 @@ impl CharDeviceWrapper {
|
||||
|
||||
#[auto_vnode_impl(error)]
|
||||
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)
|
||||
}
|
||||
|
||||
@ -28,11 +28,11 @@ impl VnodeImpl for CharDeviceWrapper {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
node::{VnodeKind, VnodeRef},
|
||||
Read, Write,
|
||||
Read, Seek, SeekFrom, Write,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
@ -20,7 +20,7 @@ pub type FileRef = Rc<RefCell<File>>;
|
||||
|
||||
pub struct NormalFile {
|
||||
vnode: VnodeRef,
|
||||
pos: usize,
|
||||
pos: u64,
|
||||
}
|
||||
|
||||
pub enum FileInner {
|
||||
@ -33,7 +33,7 @@ pub struct 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 {
|
||||
inner: FileInner::Normal(NormalFile { vnode, pos }),
|
||||
flags,
|
||||
@ -51,7 +51,7 @@ impl Write for File {
|
||||
FileInner::Normal(inner) => {
|
||||
let count = inner.vnode.write(inner.pos, data)?;
|
||||
if inner.vnode.kind() != VnodeKind::Char {
|
||||
inner.pos += count;
|
||||
inner.pos += count as u64;
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
@ -69,7 +69,7 @@ impl Read for File {
|
||||
FileInner::Normal(inner) => {
|
||||
let count = inner.vnode.read(inner.pos, data)?;
|
||||
if inner.vnode.kind() != VnodeKind::Char {
|
||||
inner.pos += count;
|
||||
inner.pos += count as u64;
|
||||
}
|
||||
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 {
|
||||
fn drop(&mut self) {
|
||||
match &mut self.inner {
|
||||
|
@ -17,8 +17,16 @@ pub(crate) mod node;
|
||||
pub use self::block::BlockDevice;
|
||||
pub use self::char::{CharDevice, CharDeviceWrapper};
|
||||
pub use file::{File, FileFlags, FileRef};
|
||||
pub use fs::Filesystem;
|
||||
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 {
|
||||
fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
|
||||
@ -26,4 +34,31 @@ pub trait Write {
|
||||
|
||||
pub trait Read {
|
||||
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 crate::file::{File, FileFlags, FileRef};
|
||||
use crate::{
|
||||
file::{File, FileFlags, FileRef},
|
||||
fs::Filesystem,
|
||||
};
|
||||
|
||||
pub type VnodeRef = Rc<Vnode>;
|
||||
pub type VnodeWeak = Weak<Vnode>;
|
||||
|
||||
pub struct VnodeDump {
|
||||
node: VnodeRef,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum VnodeKind {
|
||||
Directory,
|
||||
@ -34,16 +41,21 @@ pub struct Vnode {
|
||||
tree: RefCell<TreeNode>,
|
||||
kind: VnodeKind,
|
||||
data: RefCell<Option<Box<dyn VnodeImpl>>>,
|
||||
fs: RefCell<Option<Rc<dyn Filesystem>>>,
|
||||
}
|
||||
|
||||
pub trait VnodeImpl {
|
||||
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 read(&mut self, node: &VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Error>;
|
||||
fn write(&mut self, node: &VnodeRef, pos: usize, data: &[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: u64, data: &[u8]) -> Result<usize, Error>;
|
||||
|
||||
fn size(&mut self, _node: &VnodeRef) -> Result<u64, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Vnode {
|
||||
@ -56,6 +68,7 @@ impl Vnode {
|
||||
}),
|
||||
kind,
|
||||
data: RefCell::new(None),
|
||||
fs: RefCell::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
@ -74,6 +87,11 @@ impl Vnode {
|
||||
self.data.borrow_mut()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fs(&self) -> Option<Rc<dyn Filesystem>> {
|
||||
self.fs.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn parent(self: &VnodeRef) -> VnodeRef {
|
||||
match &self.tree.borrow().parent {
|
||||
Some(parent) => parent.upgrade().unwrap(),
|
||||
@ -85,6 +103,10 @@ impl Vnode {
|
||||
self.data.borrow_mut().replace(data);
|
||||
}
|
||||
|
||||
pub fn set_fs(&self, data: Rc<dyn Filesystem>) {
|
||||
self.fs.replace(Some(data));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_directory(&self) -> bool {
|
||||
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 {
|
||||
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 {
|
||||
todo!();
|
||||
}
|
||||
@ -209,6 +257,14 @@ impl Vnode {
|
||||
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 {
|
||||
@ -223,3 +279,15 @@ impl fmt::Debug for Vnode {
|
||||
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 indent(level: LogLevel, depth: usize) {
|
||||
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);
|
||||
log_print!(level, "{:?} {{\n", node_name);
|
||||
log_print_raw!(level, "{:?} {{\n", node_name);
|
||||
for prop in node.props() {
|
||||
indent(level, depth + 1);
|
||||
let name = prop.name().unwrap();
|
||||
log_print!(level, "{name:?} = ");
|
||||
log_print_raw!(level, "{name:?} = ");
|
||||
|
||||
match name {
|
||||
"compatible" | "stdout-path" => log_print!(level, "{:?}", prop.str().unwrap()),
|
||||
_ => log_print!(level, "{:x?}", prop.raw()),
|
||||
"compatible" | "stdout-path" => log_print_raw!(level, "{:?}", prop.str().unwrap()),
|
||||
_ => log_print_raw!(level, "{:x?}", prop.raw()),
|
||||
}
|
||||
|
||||
log_print!(level, "\n");
|
||||
log_print_raw!(level, "\n");
|
||||
}
|
||||
|
||||
for child in node.children() {
|
||||
@ -157,5 +157,5 @@ fn dump_node(node: &TNode, depth: usize, level: LogLevel) {
|
||||
}
|
||||
|
||||
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 abi::error::Error;
|
||||
use fdt_rs::prelude::PropReader;
|
||||
use plat_qemu::PLATFORM;
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
|
||||
@ -15,7 +16,7 @@ use crate::{
|
||||
},
|
||||
debug,
|
||||
device::platform::Platform,
|
||||
fs::devfs,
|
||||
fs::{devfs, Initrd, INITRD_DATA},
|
||||
mem::{
|
||||
heap,
|
||||
phys::{self, reserved::reserve_region, PageUsage, PhysicalMemoryRegion},
|
||||
@ -135,6 +136,16 @@ impl AArch64 {
|
||||
unsafe fn init_physical_memory(&self, dtb_phys: usize) -> Result<(), Error> {
|
||||
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(
|
||||
"dtb",
|
||||
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
|
||||
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
|
||||
@ -167,6 +213,9 @@ pub fn kernel_main(dtb_phys: usize) -> ! {
|
||||
|
||||
exception::init_exceptions();
|
||||
|
||||
// Setup initrd
|
||||
setup_initrd();
|
||||
|
||||
debugln!("Initializing {} platform", PLATFORM.name());
|
||||
unsafe {
|
||||
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.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -1,3 +1,14 @@
|
||||
//! 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 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;
|
||||
|
||||
use core::ops::DerefMut;
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{OpenFlags, RawFd},
|
||||
};
|
||||
use fs::{devfs, tar::TarFilesystem, INITRD_DATA};
|
||||
use task::process::Process;
|
||||
use vfs::{Filesystem, IoContext, Read, VnodeRef};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
@ -34,6 +42,12 @@ pub mod syscall;
|
||||
pub mod task;
|
||||
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.
|
||||
///
|
||||
/// # 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
|
||||
/// initialization has finished.
|
||||
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!(
|
||||
// "../../target/aarch64-unknown-yggdrasil/",
|
||||
// env!("PROFILE"),
|
||||
// "/test_program"
|
||||
// ));
|
||||
|
||||
// let devfs_root = devfs::root();
|
||||
// let tty_node = devfs_root.lookup("ttyS0").unwrap();
|
||||
|
||||
// let ioctx = IoContext::new(devfs_root.clone());
|
||||
|
||||
// // Spawn a test user task
|
||||
@ -61,15 +100,6 @@ pub fn kernel_main() {
|
||||
// // Setup I/O for the process
|
||||
// // let mut io = proc.io.lock();
|
||||
// // 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();
|
||||
// }
|
||||
|
@ -3,6 +3,7 @@ use core::mem::size_of;
|
||||
|
||||
use abi::error::Error;
|
||||
use alloc::rc::Rc;
|
||||
use vfs::{FileRef, Read, Seek};
|
||||
|
||||
use crate::{
|
||||
arch::aarch64::context::TaskContext,
|
||||
@ -66,13 +67,13 @@ fn setup_args(space: &mut AddressSpace, virt: usize, args: &[&str]) -> Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
fn setup_binary(
|
||||
mut space: AddressSpace,
|
||||
entry: usize,
|
||||
args: &[&str],
|
||||
) -> Result<Rc<Process>, Error> {
|
||||
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;
|
||||
// 0x1000 of guard page
|
||||
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)?;
|
||||
|
||||
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(
|
||||
elf_entry,
|
||||
entry,
|
||||
virt_args_base,
|
||||
space.physical_address(),
|
||||
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))
|
||||
}
|
||||
|
||||
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 wait;
|
||||
|
||||
use aarch64_cpu::registers::TTBR0_EL1;
|
||||
use aarch64_cpu::registers::{TCR_EL1::A1::TTBR0, TTBR0_EL1};
|
||||
use alloc::rc::Rc;
|
||||
use elf::{
|
||||
abi::{PF_W, PF_X, PT_LOAD},
|
||||
endian::AnyEndian,
|
||||
ElfBytes,
|
||||
ElfBytes, ElfStream, ParseError,
|
||||
};
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use vfs::{FileRef, Read, Seek, SeekFrom};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
arch::aarch64::table::tlb_flush_vaae1,
|
||||
debug::hex_dump,
|
||||
mem::{
|
||||
phys::{self, PageUsage},
|
||||
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) {
|
||||
let attrs = match (elf_attrs & PF_W, elf_attrs & PF_X) {
|
||||
(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
|
||||
pub fn load_elf_from_memory(space: &mut AddressSpace, src: &[u8]) -> usize {
|
||||
// Map the address space temporarily
|
||||
|
@ -69,6 +69,14 @@ impl<T> OneTimeInit<T> {
|
||||
|
||||
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> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user