Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ Supported commands include:
* `inflate <src addr>,<src len> [<dst addr>,<dst len>]`
decompresses the a ZLIB compressed slice from the given
source to the given destination.
* `mount <addr,len>` to mount the UFS ramdisk.
* `mount <addr,len>` to mount a UFS ramdisk or cpio miniroot.
* `umount` to unmount the ramdisk.
* `ls <file>` to list a file or directory on the ramdisk.
* `cat <file>` to display the contents of a file.
* `copy <file> <dst addr>,<dst len>` to copy the contents of a
Expand Down
7 changes: 3 additions & 4 deletions src/bldb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ use crate::mmu;
use crate::ramdisk;
use crate::result::Error;
use crate::uart::{self, Uart};
use crate::ufs;
use alloc::boxed::Box;
use core::fmt;
use core::ops::Range;
Expand All @@ -63,13 +62,13 @@ pub(crate) struct Config {
pub(crate) gpios: &'static mut gpio::Gpios,
pub(crate) loader_region: Range<mem::V4KA>,
pub(crate) page_table: mmu::LoaderPageTable,
pub(crate) ramdisk: Option<ufs::FileSystem<'static>>,
pub(crate) ramdisk: Option<Box<dyn ramdisk::FileSystem>>,
pub(crate) prompt: cons::Prompt,
}

impl Config {
pub fn mount(&mut self, ramdisk: &'static [u8]) -> Result<(), Error> {
self.ramdisk = ramdisk::mount(ramdisk)?;
self.ramdisk = Some(ramdisk::mount(ramdisk)?);
Ok(())
}
}
Expand All @@ -87,7 +86,7 @@ impl fmt::Debug for Config {
writeln!(
f,
" ramdisk: {:?}",
self.ramdisk.as_ref().map(|_| "mounted")
self.ramdisk.as_ref().map(|fs| fs.as_str())
)?;
writeln!(f, " prompt: {:?}", self.prompt)?;
write!(f, "}}")
Expand Down
160 changes: 160 additions & 0 deletions src/cpio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! cpio miniroot support.

use crate::io;
use crate::ramdisk;
use crate::result::{Error, Result};
use crate::{print, println};
use alloc::boxed::Box;
use core::slice;

pub(crate) struct FileSystem {
sd: io::Sd,
}

impl FileSystem {
pub(crate) fn try_new(bs: &[u8]) -> Result<FileSystem> {
if bs.starts_with(b"070707") {
let sd = io::Sd::from_slice(bs);
Ok(FileSystem { sd })
} else {
Err(Error::FsInvMagic)
}
}
}

pub(crate) struct File {
data: io::Sd,
}

impl File {
fn as_slice(&self) -> &[u8] {
let ptr = self.data.as_ptr();
let len = self.data.len();
unsafe { slice::from_raw_parts(ptr, len) }
}
}

impl ramdisk::File for File {
fn file_type(&self) -> ramdisk::FileType {
ramdisk::FileType::Regular
}
}

impl io::Read for File {
fn read(&self, offset: u64, dst: &mut [u8]) -> Result<usize> {
let s = self.as_slice();
s.read(offset, dst)
}

fn size(&self) -> usize {
self.data.len()
}
}

impl ramdisk::FileSystem for FileSystem {
fn open(&self, path: &str) -> Result<Box<dyn ramdisk::File>> {
let ptr: *const u8 = self.sd.as_ptr();
let len = self.sd.len();
let cpio = unsafe { core::slice::from_raw_parts(ptr, len) };
let key = path.strip_prefix("/").unwrap_or(path);
for file in cpio_reader::iter_files(cpio) {
if file.name() == key {
let data = io::Sd::from_slice(file.file());
return Ok(Box::new(File { data }));
}
}
Err(Error::FsNoFile)
}

fn list(&self, path: &str) -> Result<()> {
let ptr: *const u8 = self.sd.as_ptr();
let len = self.sd.len();
let cpio = unsafe { core::slice::from_raw_parts(ptr, len) };
let key = path.strip_prefix('/').unwrap_or(path);
for file in cpio_reader::iter_files(cpio) {
if file.name() == key {
lsfile(path, &file);
return Ok(());
}
}
let mut found = false;
for file in cpio_reader::iter_files(cpio) {
if file.name().starts_with(key) {
lsfile(file.name(), &file);
found = true;
}
}
if found { Ok(()) } else { Err(Error::FsNoFile) }
}

fn as_str(&self) -> &str {
"cpio"
}

fn with_addr(&self, addr: usize) -> *const u8 {
self.sd.as_ptr().with_addr(addr)
}
}

fn lsfile(path: &str, file: &cpio_reader::Entry) {
print!("#{ino:<4} ", ino = file.ino());
print_mode(file.mode());
println!(
" {nlink:<2} {uid:<3} {gid:<3} {size:>8} {path}",
nlink = file.nlink(),
uid = file.uid(),
gid = file.gid(),
size = file.file().len(),
);
}

fn first_char(mode: cpio_reader::Mode) -> char {
use cpio_reader::Mode;
match mode {
_ if mode.contains(Mode::DIRECTORY) => 'd',
_ if mode.contains(Mode::CHARACTER_SPECIAL_DEVICE) => 'c',
_ if mode.contains(Mode::BLOCK_SPECIAL_DEVICE) => 'b',
_ if mode.contains(Mode::SYMBOLIK_LINK) => 'l',
_ if mode.contains(Mode::SOCKET) => 's',
_ if mode.contains(Mode::NAMED_PIPE_FIFO) => 'f',
_ => '-',
}
}

fn print_mode(mode: cpio_reader::Mode) {
use cpio_reader::Mode;
print!("{}", first_char(mode));
let alt = |bit, t, f| {
if mode.contains(bit) { t } else { f }
};
// For some reason, the cpio reader library appears to have
// the meaning of these bits mirrored with respect to the owner
// bits.
print!("{}", alt(Mode::WORLD_READABLE, 'r', '-'));
print!("{}", alt(Mode::WORLD_WRITABLE, 'w', '-'));
if !mode.contains(Mode::SUID) {
print!("{}", alt(Mode::WORLD_EXECUTABLE, 'x', '-'));
} else {
print!("{}", alt(Mode::WORLD_EXECUTABLE, 's', 'S'));
}

print!("{}", alt(Mode::GROUP_READABLE, 'r', '-'));
print!("{}", alt(Mode::GROUP_WRITABLE, 'w', '-'));
if !mode.contains(Mode::SGID) {
print!("{}", alt(Mode::GROUP_EXECUTABLE, 'x', '-'));
} else {
print!("{}", alt(Mode::GROUP_EXECUTABLE, 's', 'S'));
}

print!("{}", alt(Mode::USER_READABLE, 'r', '-'));
print!("{}", alt(Mode::USER_WRITABLE, 'w', '-'));
if !mode.contains(Mode::STICKY) {
print!("{}", alt(Mode::USER_EXECUTABLE, 'x', '-'));
} else {
print!("{}", alt(Mode::USER_EXECUTABLE, 't', 'T'));
}
}
59 changes: 59 additions & 0 deletions src/io.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::result::Result;

#[derive(Debug)]
pub(crate) struct Sd {
pub(crate) ptr: *const u8,
pub(crate) len: usize,
}

impl Sd {
pub(crate) fn new(ptr: *const u8, len: usize) -> Sd {
Sd { ptr, len }
}

pub(crate) fn from_slice(bs: &[u8]) -> Sd {
Sd::new(bs.as_ptr(), bs.len())
}

pub(crate) fn as_ptr(&self) -> *const u8 {
self.ptr
}

pub(crate) fn len(&self) -> usize {
self.len
}

pub(crate) fn subset(&self, offset: usize, len: usize) -> Sd {
assert!(offset + len <= self.len);
let ptr = self.ptr.wrapping_add(offset);
Sd { ptr, len }
}
}

pub(crate) trait Read {
fn read(&self, off: u64, dst: &mut [u8]) -> Result<usize>;
fn size(&self) -> usize;
}

impl Read for &[u8] {
fn read(&self, off: u64, dst: &mut [u8]) -> Result<usize> {
let off = off as usize;
if off > self.len() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... i did not know that &slice[slice.len()..] would work, but apparently it does and produces an empty slice!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed! It occurs to me that, regardless of correctness, it's clearer all around to just use >= here.

return Ok(0);
}
let bytes = &self[off..];
let len = usize::min(bytes.len(), dst.len());
if len > 0 {
dst[..len].copy_from_slice(&bytes[..len]);
}
Ok(len)
}

fn size(&self) -> usize {
self.len()
}
}
38 changes: 7 additions & 31 deletions src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

extern crate alloc;

use crate::io::Read;
use crate::mem;
use crate::mmu::LoaderPageTable;
use crate::println;
use crate::ramdisk::File;
use crate::result::{Error, Result};
use crate::ufs;
use alloc::vec::Vec;
use goblin::container::{Container, Ctx, Endian};
use goblin::elf::ProgramHeader;
Expand All @@ -20,37 +21,12 @@ use goblin::elf::{self, Elf};

const PAGE_SIZE: usize = 4096;

pub(crate) trait Read {
fn read(&self, off: u64, dst: &mut [u8]) -> Result<usize>;
}

impl Read for ufs::Inode<'_> {
fn read(&self, off: u64, dst: &mut [u8]) -> Result<usize> {
self.read(off, dst).map_err(|_| Error::FsRead)
}
}

impl Read for &[u8] {
fn read(&self, off: u64, dst: &mut [u8]) -> Result<usize> {
let off = off as usize;
if off > self.len() {
return Err(Error::ElfTruncatedObj);
}
let bytes = &self[off..];
let len = usize::min(bytes.len(), dst.len());
if len > 0 {
dst[..len].copy_from_slice(&bytes[..len]);
}
Ok(0)
}
}

/// Loads an executable image contained in the given file
/// creating virtual mappings as required. Returns the image's
/// ELF entry point on success.
pub(crate) fn load(
page_table: &mut LoaderPageTable,
file: &ufs::Inode<'_>,
file: &dyn File,
) -> Result<u64> {
let mut buf = [0u8; PAGE_SIZE];
file.read(0, &mut buf).map_err(|_| Error::FsRead)?;
Expand Down Expand Up @@ -88,7 +64,7 @@ pub(crate) fn load_bytes(
Ok(elf.entry)
}

pub(crate) fn elfinfo<T: Read>(file: &T) -> Result<()> {
pub(crate) fn elfinfo(file: &dyn File) -> Result<()> {
use goblin::elf;

let mut buf = [0u8; PAGE_SIZE];
Expand Down Expand Up @@ -193,7 +169,7 @@ fn parse_program_headers(

/// Loads the given ELF segment, creating virtual mappings for
/// it as required.
fn load_segment<T: Read>(
fn load_segment<T: Read + ?Sized>(
page_table: &mut LoaderPageTable,
segment: &ProgramHeader,
file: &T,
Expand Down Expand Up @@ -226,8 +202,8 @@ fn load_segment<T: Read>(
};
let filesz = segment.p_filesz as usize;
let len = usize::min(filesz, dst.len());
if len > 0 {
file.read(segment.p_offset, &mut dst[..len])?;
if len > 0 && file.read(segment.p_offset, &mut dst[..len])? != len {
return Err(Error::ElfTruncatedObj);
}
}
let attrs = mem::Attrs::new_kernel(
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ mod allocator;
mod bldb;
mod clock;
mod cons;
mod cpio;
mod cpuid;
mod gpio;
mod idt;
mod io;
mod iomux;
mod loader;
mod mem;
Expand Down
Loading