***: fix clippy and check warnings

This commit is contained in:
Mark Poliakov 2023-07-20 18:51:56 +03:00
parent 9e0555f7a3
commit 69a413f6bb
15 changed files with 258 additions and 367 deletions

View File

@ -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"]

View File

@ -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(

View File

@ -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);
}

View File

@ -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(())

View File

@ -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],
}

View File

@ -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");

View File

@ -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();
}

View File

@ -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();

View File

@ -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!()
// }

View File

@ -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
View 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)
}

View File

@ -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)
}

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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())