***: fix clippy and check warnings
This commit is contained in:
parent
9e0555f7a3
commit
69a413f6bb
@ -18,4 +18,8 @@ spinning_top = "0.2.5"
|
||||
static_assertions = "1.1.0"
|
||||
tock-registers = "0.8.1"
|
||||
|
||||
elf = { version = "0.7.2", path = "../../rust-elf", default-features = false, features = ["no_std_stream"] }
|
||||
[dependencies.elf]
|
||||
version = "0.7.2"
|
||||
git = "https://git.alnyan.me/yggdrasil/yggdrasil-elf.git"
|
||||
default-features = false
|
||||
features = ["no_std_stream"]
|
||||
|
@ -20,7 +20,6 @@ impl IoContext {
|
||||
}
|
||||
|
||||
fn _find(
|
||||
&self,
|
||||
mut at: VnodeRef,
|
||||
path: &str,
|
||||
follow: bool,
|
||||
@ -82,7 +81,7 @@ impl IoContext {
|
||||
if rest.is_empty() {
|
||||
Ok(node)
|
||||
} else {
|
||||
self._find(node, rest, follow, follow_mount)
|
||||
Self::_find(node, rest, follow, follow_mount)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +103,7 @@ impl IoContext {
|
||||
self.cwd.clone()
|
||||
};
|
||||
|
||||
self._find(at, path, follow, follow_mount)
|
||||
Self::_find(at, path, follow, follow_mount)
|
||||
}
|
||||
|
||||
pub fn open(
|
||||
|
@ -66,6 +66,9 @@ fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [u8]) -> Res
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: only meant to be called early in kernel init sequence
|
||||
pub unsafe fn init_debug_hook(hook: &'static dyn Fn(core::fmt::Arguments)) {
|
||||
debug::DEBUG_HOOK.replace(hook);
|
||||
}
|
||||
|
@ -172,32 +172,29 @@ impl Vnode {
|
||||
|
||||
write!(f, "{:?}", self.name)?;
|
||||
|
||||
match self.kind {
|
||||
VnodeKind::Directory => {
|
||||
let tree = self.tree.borrow();
|
||||
let target = self.target();
|
||||
if self.is_directory() {
|
||||
let tree = self.tree.borrow();
|
||||
let target = self.target();
|
||||
|
||||
if let Some(target) = target {
|
||||
assert_eq!(tree.children.len(), 0);
|
||||
f.write_str(" -> ")?;
|
||||
return target.dump(f, depth, false);
|
||||
}
|
||||
|
||||
if tree.children.is_empty() {
|
||||
f.write_str(" []")?;
|
||||
} else {
|
||||
f.write_str(" [\n")?;
|
||||
for child in tree.children.iter() {
|
||||
child.dump(f, depth + 1, true)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
for _ in 0..depth {
|
||||
f.write_str(" ")?;
|
||||
}
|
||||
f.write_str("]")?;
|
||||
}
|
||||
if let Some(target) = target {
|
||||
assert_eq!(tree.children.len(), 0);
|
||||
f.write_str(" -> ")?;
|
||||
return target.dump(f, depth, false);
|
||||
}
|
||||
|
||||
if tree.children.is_empty() {
|
||||
f.write_str(" []")?;
|
||||
} else {
|
||||
f.write_str(" [\n")?;
|
||||
for child in tree.children.iter() {
|
||||
child.dump(f, depth + 1, true)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
for _ in 0..depth {
|
||||
f.write_str(" ")?;
|
||||
}
|
||||
f.write_str("]")?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -45,11 +45,11 @@ pub mod smp;
|
||||
pub mod table;
|
||||
pub mod timer;
|
||||
|
||||
pub(self) const BOOT_STACK_SIZE: usize = 65536;
|
||||
const BOOT_STACK_SIZE: usize = 65536;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C, align(0x20))]
|
||||
pub(self) struct KernelStack {
|
||||
struct KernelStack {
|
||||
data: [u8; BOOT_STACK_SIZE],
|
||||
}
|
||||
|
||||
|
@ -99,13 +99,14 @@ impl fmt::Write for DebugPrinter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a hex-dump of a slice, appending a virtual address offset to the output
|
||||
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]);
|
||||
log_print_raw!(level, "{:02X}", b);
|
||||
|
||||
if i % 16 == 15 {
|
||||
log_print_raw!(level, "\n");
|
||||
|
@ -60,10 +60,12 @@ pub trait TtyDevice<const N: usize>: SerialDevice {
|
||||
}
|
||||
|
||||
if byte == b'\n' {
|
||||
let echo = config.line.contains(TerminalLineOptions::ECHO)
|
||||
// TODO implement proper echo here
|
||||
let _echo = config.line.contains(TerminalLineOptions::ECHO)
|
||||
|| config
|
||||
.line
|
||||
.contains(TerminalLineOptions::CANONICAL | TerminalLineOptions::ECHO_NL);
|
||||
|
||||
if config.output.contains(TerminalOutputOptions::NL_TO_CRNL) {
|
||||
self.send(b'\r').ok();
|
||||
}
|
||||
|
@ -8,14 +8,20 @@ use crate::util::OneTimeInit;
|
||||
pub mod devfs;
|
||||
pub mod tar;
|
||||
|
||||
/// Describes in-memory filesystem image used as initial root
|
||||
pub struct Initrd {
|
||||
/// Page-aligned start address of the initrd
|
||||
pub phys_page_start: usize,
|
||||
/// Page-aligned length
|
||||
pub phys_page_len: usize,
|
||||
/// Safe reference to the initrd data slice
|
||||
pub data: &'static [u8],
|
||||
}
|
||||
|
||||
/// Holds reference to the data of initrd as well as its page-aligned physical memory region
|
||||
pub static INITRD_DATA: OneTimeInit<Initrd> = OneTimeInit::new();
|
||||
|
||||
/// Constructs an instance of a filesystem for given set of [MountOptions]
|
||||
pub fn create_filesystem(options: &MountOptions) -> Result<VnodeRef, Error> {
|
||||
let fs_name = options.filesystem.unwrap();
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! In-memory filesystem implementation
|
||||
use abi::{error::Error, io::FileMode};
|
||||
use alloc::{boxed::Box, rc::Rc};
|
||||
use vfs::{Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||
@ -6,38 +7,38 @@ use yggdrasil_abi::io::OpenOptions;
|
||||
use crate::util::OneTimeInit;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct OctalField<const N: usize> {
|
||||
struct OctalField<const N: usize> {
|
||||
data: [u8; N],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct TarString<const N: usize> {
|
||||
struct TarString<const N: usize> {
|
||||
data: [u8; N],
|
||||
}
|
||||
|
||||
pub struct TarIterator<'a> {
|
||||
struct TarIterator<'a> {
|
||||
data: &'a [u8],
|
||||
offset: usize,
|
||||
zero_blocks: usize,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct TarEntry {
|
||||
struct TarEntry {
|
||||
name: TarString<100>,
|
||||
mode: OctalField<8>,
|
||||
uid: OctalField<8>,
|
||||
gid: OctalField<8>,
|
||||
_mode: OctalField<8>,
|
||||
_uid: OctalField<8>,
|
||||
_gid: OctalField<8>,
|
||||
size: OctalField<12>,
|
||||
mtime: OctalField<12>,
|
||||
checksum: OctalField<8>,
|
||||
_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],
|
||||
_link_name: TarString<100>,
|
||||
_magic: [u8; 8],
|
||||
_user: TarString<32>,
|
||||
_group: TarString<32>,
|
||||
_dev_major: OctalField<8>,
|
||||
_dev_minor: OctalField<8>,
|
||||
_prefix: TarString<155>,
|
||||
__pad: [u8; 12],
|
||||
}
|
||||
|
||||
@ -61,7 +62,7 @@ impl<'a> Iterator for TarIterator<'a> {
|
||||
}
|
||||
|
||||
let hdr_ptr = &self.data[self.offset..];
|
||||
let hdr = unsafe { core::mem::transmute::<*const u8, &TarEntry>(hdr_ptr.as_ptr()) };
|
||||
let hdr = unsafe { &*(hdr_ptr.as_ptr() as *const TarEntry) };
|
||||
|
||||
if hdr.is_empty() {
|
||||
if self.zero_blocks == 1 {
|
||||
@ -139,6 +140,7 @@ impl TarEntry {
|
||||
}
|
||||
}
|
||||
|
||||
/// tar-image based in-memory filesystem
|
||||
pub struct TarFilesystem {
|
||||
root: OneTimeInit<VnodeRef>,
|
||||
}
|
||||
@ -175,7 +177,7 @@ impl VnodeImpl for DirInode {
|
||||
}
|
||||
|
||||
impl VnodeImpl for RegularInode {
|
||||
fn open(&mut self, node: &VnodeRef, opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
|
||||
fn open(&mut self, _node: &VnodeRef, opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
|
||||
if opts.contains(OpenOptions::WRITE) {
|
||||
panic!("TODO: tarfs write");
|
||||
}
|
||||
@ -183,16 +185,16 @@ impl VnodeImpl for RegularInode {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn close(&mut self, node: &VnodeRef) -> Result<(), Error> {
|
||||
fn close(&mut self, _node: &VnodeRef) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&mut self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
|
||||
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());
|
||||
let rem = core::cmp::min(self.data.len() - pos, data.len());
|
||||
data[..rem].copy_from_slice(&self.data[pos..pos + rem]);
|
||||
Ok(rem)
|
||||
}
|
||||
@ -207,6 +209,7 @@ impl TarFilesystem {
|
||||
self: &Rc<Self>,
|
||||
at: &VnodeRef,
|
||||
path: &str,
|
||||
kind: VnodeKind,
|
||||
create: bool,
|
||||
) -> Result<VnodeRef, Error> {
|
||||
debugln!("make_path {:?}", path);
|
||||
@ -226,27 +229,25 @@ impl TarFilesystem {
|
||||
}
|
||||
|
||||
infoln!("Create {:?}", element);
|
||||
at.create(element, VnodeKind::Directory)?
|
||||
let node = self.create_node_initial(element, kind);
|
||||
at.add_child(node.clone());
|
||||
|
||||
node
|
||||
}
|
||||
};
|
||||
|
||||
if rest.is_empty() {
|
||||
Ok(node)
|
||||
} else {
|
||||
self.make_path(&node, rest, create)
|
||||
assert!(node.is_directory());
|
||||
self.make_path(&node, rest, kind, create)
|
||||
}
|
||||
}
|
||||
|
||||
fn create_node_initial(
|
||||
self: &Rc<Self>,
|
||||
name: &str,
|
||||
hdr: &TarEntry,
|
||||
data: Option<&[u8]>,
|
||||
) -> VnodeRef {
|
||||
fn create_node_initial(self: &Rc<Self>, name: &str, kind: VnodeKind) -> VnodeRef {
|
||||
assert!(!name.is_empty());
|
||||
assert!(!name.contains('/'));
|
||||
|
||||
let kind = hdr.node_kind();
|
||||
let node = Vnode::new(name, kind);
|
||||
node.set_fs(self.clone());
|
||||
|
||||
@ -266,7 +267,7 @@ impl TarFilesystem {
|
||||
|
||||
// 1. Create paths in tar
|
||||
for item in TarIterator::new(tar_data) {
|
||||
let Ok((hdr, data)) = item else {
|
||||
let Ok((hdr, _)) = item else {
|
||||
warnln!("Tar image is truncated");
|
||||
return Err(Error::InvalidArgument);
|
||||
};
|
||||
@ -274,8 +275,8 @@ impl TarFilesystem {
|
||||
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);
|
||||
let parent = self.make_path(&root, dirname, VnodeKind::Directory, true)?;
|
||||
let node = self.create_node_initial(filename, hdr.node_kind());
|
||||
|
||||
parent.add_child(node);
|
||||
}
|
||||
@ -288,7 +289,7 @@ impl TarFilesystem {
|
||||
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)?;
|
||||
let node = self.make_path(&root, path, VnodeKind::Directory, false)?;
|
||||
node.set_data(Box::new(RegularInode { data }));
|
||||
}
|
||||
}
|
||||
@ -296,6 +297,7 @@ impl TarFilesystem {
|
||||
Ok(root)
|
||||
}
|
||||
|
||||
/// Constructs a filesystem tree from a tar image in memory
|
||||
pub fn from_slice(tar_data: &'static [u8]) -> Result<Rc<Self>, Error> {
|
||||
let fs = Rc::new(TarFilesystem {
|
||||
root: OneTimeInit::new(),
|
||||
@ -306,24 +308,3 @@ impl TarFilesystem {
|
||||
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!()
|
||||
// }
|
||||
|
@ -17,9 +17,9 @@ extern crate yggdrasil_abi as abi;
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{FileMode, OpenOptions, RawFd},
|
||||
io::{FileMode, OpenOptions},
|
||||
};
|
||||
use fs::{devfs, tar::TarFilesystem, INITRD_DATA};
|
||||
use fs::{tar::TarFilesystem, INITRD_DATA};
|
||||
use task::process::Process;
|
||||
use vfs::{Filesystem, IoContext, VnodeRef};
|
||||
|
||||
@ -61,9 +61,6 @@ pub fn kernel_main() {
|
||||
}
|
||||
};
|
||||
|
||||
let devfs_root = devfs::root();
|
||||
let tty_node = devfs_root.lookup("ttyS0").unwrap();
|
||||
|
||||
let ioctx = IoContext::new(root);
|
||||
let node = ioctx.find(None, "/init", true, true).unwrap();
|
||||
let file = node.open(OpenOptions::READ, FileMode::empty()).unwrap();
|
||||
|
158
src/proc/elf.rs
Normal file
158
src/proc/elf.rs
Normal file
@ -0,0 +1,158 @@
|
||||
//! ELF binary format support
|
||||
use elf::{
|
||||
abi::{PF_W, PF_X, PT_LOAD},
|
||||
endian::AnyEndian,
|
||||
ElfStream, ParseError,
|
||||
};
|
||||
use vfs::{FileRef, Read, Seek, SeekFrom};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::mem::{
|
||||
phys::{self, PageUsage},
|
||||
table::{AddressSpace, PageAttributes},
|
||||
ConvertAddress,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct FileReader<'a> {
|
||||
file: &'a FileRef,
|
||||
}
|
||||
|
||||
impl elf::io_traits::InputStream for FileReader<'_> {
|
||||
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)
|
||||
}
|
||||
|
||||
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_bytes<F>(
|
||||
space: &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 space.translate(virt_page).is_some() {
|
||||
// Handle these cases
|
||||
todo!();
|
||||
}
|
||||
|
||||
let phys_page = phys::alloc_page(PageUsage::Used)?;
|
||||
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)?;
|
||||
|
||||
rem -= count;
|
||||
off += count;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Loads an ELF binary from `file` into the target address space
|
||||
pub fn load_elf_from_file(space: &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)
|
||||
}
|
@ -3,7 +3,7 @@ use core::mem::size_of;
|
||||
|
||||
use abi::error::Error;
|
||||
use alloc::rc::Rc;
|
||||
use vfs::{FileRef, Read, Seek};
|
||||
use vfs::FileRef;
|
||||
|
||||
use crate::{
|
||||
arch::aarch64::context::TaskContext,
|
||||
@ -16,7 +16,7 @@ use crate::{
|
||||
task::process::Process,
|
||||
};
|
||||
|
||||
fn setup_args(space: &mut AddressSpace, virt: usize, args: &[&str]) -> Result<(), Error> {
|
||||
fn setup_args(space: &AddressSpace, virt: usize, args: &[&str]) -> Result<(), Error> {
|
||||
// arg data len
|
||||
let args_size: usize = args.iter().map(|x| x.len()).sum();
|
||||
// 1 + arg ptr:len count
|
||||
@ -42,15 +42,15 @@ fn setup_args(space: &mut AddressSpace, virt: usize, args: &[&str]) -> Result<()
|
||||
(write as *mut usize).write_volatile(args.len());
|
||||
}
|
||||
|
||||
for i in 0..args.len() {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
// Place the argument pointer
|
||||
let ptr_place = write + (i * 2 + 1) * size_of::<usize>();
|
||||
let len_place = ptr_place + size_of::<usize>();
|
||||
unsafe {
|
||||
(ptr_place as *mut usize).write_volatile(virt + offset);
|
||||
(len_place as *mut usize).write_volatile(args[i].len());
|
||||
(len_place as *mut usize).write_volatile(arg.len());
|
||||
}
|
||||
offset += args[i].len();
|
||||
offset += arg.len();
|
||||
}
|
||||
|
||||
// Place the argument data
|
||||
@ -67,11 +67,7 @@ fn setup_args(space: &mut AddressSpace, virt: usize, args: &[&str]) -> Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_binary(
|
||||
mut space: AddressSpace,
|
||||
entry: usize,
|
||||
args: &[&str],
|
||||
) -> Result<Rc<Process>, Error> {
|
||||
fn setup_binary(space: AddressSpace, entry: usize, args: &[&str]) -> Result<Rc<Process>, Error> {
|
||||
const USER_STACK_PAGES: usize = 8;
|
||||
|
||||
let virt_stack_base = 0x10000000;
|
||||
@ -87,7 +83,7 @@ fn setup_binary(
|
||||
)?;
|
||||
}
|
||||
|
||||
setup_args(&mut space, virt_args_base, args)?;
|
||||
setup_args(&space, virt_args_base, args)?;
|
||||
|
||||
debugln!(
|
||||
"Entry: {:#x}, Stack: {:#x}..{:#x}, Args: {:#x}",
|
||||
@ -107,17 +103,10 @@ fn setup_binary(
|
||||
Ok(Process::new_with_context(Some(space), context))
|
||||
}
|
||||
|
||||
/// Loads an ELF bianary from `file` and sets up all the necessary data/argument memory
|
||||
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);
|
||||
let space = AddressSpace::new_empty()?;
|
||||
let elf_entry = proc::elf::load_elf_from_file(&space, file)?;
|
||||
|
||||
setup_binary(space, elf_entry, args)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Process I/O management
|
||||
use abi::{error::Error, io::RawFd};
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::collections::{btree_map::Entry, BTreeMap};
|
||||
use vfs::{FileRef, IoContext};
|
||||
|
||||
/// I/O context of a process, contains information like root, current directory and file
|
||||
@ -21,10 +21,7 @@ impl ProcessIo {
|
||||
|
||||
/// Returns a file given descriptor refers to
|
||||
pub fn file(&self, fd: RawFd) -> Result<FileRef, Error> {
|
||||
self.files
|
||||
.get(&fd)
|
||||
.cloned()
|
||||
.ok_or_else(|| Error::InvalidFile)
|
||||
self.files.get(&fd).cloned().ok_or(Error::InvalidFile)
|
||||
}
|
||||
|
||||
/// Sets the inner I/O context
|
||||
@ -47,8 +44,9 @@ impl ProcessIo {
|
||||
pub fn place_file(&mut self, file: FileRef) -> Result<RawFd, Error> {
|
||||
for idx in 0..64 {
|
||||
let fd = RawFd(idx);
|
||||
if !self.files.contains_key(&fd) {
|
||||
self.files.insert(fd, file);
|
||||
|
||||
if let Entry::Vacant(e) = self.files.entry(fd) {
|
||||
e.insert(file);
|
||||
return Ok(fd);
|
||||
}
|
||||
}
|
||||
|
248
src/proc/mod.rs
248
src/proc/mod.rs
@ -1,252 +1,6 @@
|
||||
//! Internal management for processes
|
||||
|
||||
pub mod elf;
|
||||
pub mod exec;
|
||||
pub mod io;
|
||||
pub mod wait;
|
||||
|
||||
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, 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,
|
||||
(_, 0) => PageAttributes::AP_BOTH_READWRITE,
|
||||
(0, _) => PageAttributes::AP_BOTH_READONLY,
|
||||
(_, _) => PageAttributes::AP_BOTH_READWRITE,
|
||||
};
|
||||
|
||||
let aligned_start = addr & !0xFFF;
|
||||
let aligned_end = (addr + memsz + 0xFFF) & !0xFFF;
|
||||
|
||||
// Map and write pages
|
||||
for page in (aligned_start..aligned_end).step_by(0x1000) {
|
||||
if let Some(_phys) = space.translate(page) {
|
||||
todo!();
|
||||
} else {
|
||||
let phys = phys::alloc_page(PageUsage::Used).unwrap();
|
||||
space
|
||||
.map_page(page, phys, PageAttributes::AP_BOTH_READWRITE)
|
||||
.unwrap();
|
||||
|
||||
debugln!("MAP (alloc) {:#x} -> {:#x}", page, phys);
|
||||
tlb_flush_vaae1(page);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Write the data
|
||||
let dst = core::slice::from_raw_parts_mut(addr as *mut u8, memsz);
|
||||
dst[..data.len()].copy_from_slice(data);
|
||||
|
||||
// Zero the rest
|
||||
dst[data.len()..memsz].fill(0);
|
||||
}
|
||||
|
||||
// Map the region as readonly
|
||||
for page in (aligned_start..aligned_end).step_by(0x1000) {
|
||||
let phys = space.translate(page).unwrap();
|
||||
space.map_page(page, phys, attrs).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
TTBR0_EL1.set(space.physical_address() as u64);
|
||||
|
||||
let elf = ElfBytes::<AnyEndian>::minimal_parse(src).unwrap();
|
||||
|
||||
for phdr in elf.segments().unwrap() {
|
||||
if phdr.p_type != PT_LOAD {
|
||||
continue;
|
||||
}
|
||||
|
||||
debugln!("LOAD {:#x}", phdr.p_vaddr);
|
||||
let data = &src[phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize];
|
||||
load_segment(
|
||||
space,
|
||||
phdr.p_vaddr as usize,
|
||||
data,
|
||||
phdr.p_memsz as usize,
|
||||
phdr.p_flags,
|
||||
);
|
||||
}
|
||||
|
||||
TTBR0_EL1.set_baddr(0);
|
||||
|
||||
elf.ehdr.e_entry as usize
|
||||
}
|
||||
|
@ -70,6 +70,8 @@ impl<T> OneTimeInit<T> {
|
||||
unsafe { (*self.value.get()).assume_init_ref() }
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the underlying value and [None] if the value hasn't yet
|
||||
/// been initialized
|
||||
pub fn try_get(&self) -> Option<&T> {
|
||||
if self.state.load(Ordering::Acquire) {
|
||||
Some(self.get())
|
||||
|
Loading…
x
Reference in New Issue
Block a user