Merge branch 'merge_bootstrap_into_initfs' into 'master'
Allow embedding bootstrap code into the initfs blob See merge request redox-os/redox-initfs!2
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(offset_of)]
|
||||
//! A super simple initfs, only meant to be loaded into RAM by the bootloader, and then directly be
|
||||
//! read.
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use core::mem::offset_of;
|
||||
|
||||
pub const MAGIC_LEN: usize = 8;
|
||||
pub const MAGIC: [u8; 8] = *b"RedoxFtw";
|
||||
|
||||
@@ -69,8 +71,15 @@ pub struct Header {
|
||||
pub inode_table_offset: Offset,
|
||||
pub creation_time: Timespec,
|
||||
pub inode_count: U16,
|
||||
pub bootstrap_entry: U64,
|
||||
pub initfs_size: U64,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
// Ensure the offsets of field used by the bootloader stay stable.
|
||||
assert!(offset_of!(Header, bootstrap_entry) == 0x1a);
|
||||
};
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct InodeHeader {
|
||||
|
||||
@@ -14,6 +14,7 @@ fn archive_and_read() -> Result<()> {
|
||||
let args = self::archive::Args {
|
||||
destination_path: Path::new("out.img"),
|
||||
source: Path::new("data"),
|
||||
bootstrap_code: None,
|
||||
max_size: self::archive::DEFAULT_MAX_SIZE,
|
||||
};
|
||||
self::archive::archive(&args).context("failed to archive")?;
|
||||
|
||||
@@ -355,8 +355,16 @@ pub struct Args<'a> {
|
||||
pub destination_path: &'a Path,
|
||||
pub max_size: u64,
|
||||
pub source: &'a Path,
|
||||
pub bootstrap_code: Option<&'a Path>,
|
||||
}
|
||||
pub fn archive(&Args { destination_path, max_size, source }: &Args) -> Result<()> {
|
||||
pub fn archive(
|
||||
&Args {
|
||||
destination_path,
|
||||
max_size,
|
||||
source,
|
||||
bootstrap_code,
|
||||
}: &Args,
|
||||
) -> Result<()> {
|
||||
let previous_extension = destination_path.extension().map_or("", |ext| {
|
||||
ext.to_str()
|
||||
.expect("expected destination path to be valid UTF-8")
|
||||
@@ -407,15 +415,30 @@ pub fn archive(&Args { destination_path, max_size, source }: &Args) -> Result<()
|
||||
log::debug!("there are {} inodes", state.inode_count);
|
||||
|
||||
// NOTE: The header is always stored at offset zero.
|
||||
let header_offset = bump_alloc(
|
||||
&mut state,
|
||||
std::mem::size_of::<initfs::Header>()
|
||||
.try_into()
|
||||
.expect("expected header size to fit"),
|
||||
"allocate header",
|
||||
)?;
|
||||
let header_offset = bump_alloc(&mut state, 4096, "allocate header")?;
|
||||
assert_eq!(header_offset, 0);
|
||||
|
||||
let bootstrap_entry = if let Some(bootstrap_code) = bootstrap_code {
|
||||
allocate_and_write_file(
|
||||
&mut state,
|
||||
&File::open(bootstrap_code).with_context(|| {
|
||||
anyhow!(
|
||||
"failed to open bootstrap code file `{}`",
|
||||
bootstrap_code.to_string_lossy(),
|
||||
)
|
||||
})?,
|
||||
)?;
|
||||
let bootstrap_data = std::fs::read(bootstrap_code).with_context(|| {
|
||||
anyhow!(
|
||||
"failed to read bootstrap code file `{}`",
|
||||
bootstrap_code.to_string_lossy(),
|
||||
)
|
||||
})?;
|
||||
elf_entry(&bootstrap_data)
|
||||
} else {
|
||||
u64::MAX
|
||||
};
|
||||
|
||||
let inode_table_length = {
|
||||
let inode_entry_size: u64 = std::mem::size_of::<initfs::InodeHeader>()
|
||||
.try_into()
|
||||
@@ -463,6 +486,8 @@ pub fn archive(&Args { destination_path, max_size, source }: &Args) -> Result<()
|
||||
},
|
||||
inode_count: state.inode_count.into(),
|
||||
inode_table_offset,
|
||||
bootstrap_entry: bootstrap_entry.into(),
|
||||
initfs_size: state.file.metadata().context("failed to get initfs size")?.len().into(),
|
||||
};
|
||||
write_all_at(&*state.file, &header_bytes, header_offset, "writing header")
|
||||
.context("failed to write header")?;
|
||||
@@ -475,3 +500,28 @@ pub fn archive(&Args { destination_path, max_size, source }: &Args) -> Result<()
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn elf_entry(data: &[u8]) -> u64 {
|
||||
assert!(&data[..4] == b"\x7FELF");
|
||||
match (data[4], data[5]) {
|
||||
// 32-bit, little endian
|
||||
(1, 1) => u32::from_le_bytes(
|
||||
<[u8; 4]>::try_from(&data[0x18..0x18 + 4]).expect("conversion cannot fail"),
|
||||
) as u64,
|
||||
// 32-bit, big endian
|
||||
(1, 2) => u32::from_be_bytes(
|
||||
<[u8; 4]>::try_from(&data[0x18..0x18 + 4]).expect("conversion cannot fail"),
|
||||
) as u64,
|
||||
// 64-bit, little endian
|
||||
(2, 1) => u64::from_le_bytes(
|
||||
<[u8; 8]>::try_from(&data[0x18..0x18 + 8]).expect("conversion cannot fail"),
|
||||
),
|
||||
// 64-bit, big endian
|
||||
(2, 2) => u64::from_be_bytes(
|
||||
<[u8; 8]>::try_from(&data[0x18..0x18 + 8]).expect("conversion cannot fail"),
|
||||
),
|
||||
(ei_class, ei_data) => {
|
||||
panic!("Unsupported ELF EI_CLASS {} EI_DATA {}", ei_class, ei_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ fn main() -> Result<()> {
|
||||
.required(true)
|
||||
.help("Specify the source directory to build the image from."),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("BOOTSTRAP_CODE")
|
||||
.required(false)
|
||||
.help("Specify the bootstrap ELF file to include in the image.")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("OUTPUT")
|
||||
.required(true)
|
||||
@@ -47,12 +52,15 @@ fn main() -> Result<()> {
|
||||
.get_one::<String>("SOURCE")
|
||||
.expect("expected the required arg SOURCE to exist");
|
||||
|
||||
let bootstrap_code = matches.get_one::<String>("BOOTSTRAP_CODE");
|
||||
|
||||
let destination = matches
|
||||
.get_one::<String>("OUTPUT")
|
||||
.expect("expected the required arg OUTPUT to exist");
|
||||
|
||||
let args = Args {
|
||||
source: Path::new(source),
|
||||
bootstrap_code: bootstrap_code.map(|bootstrap_code| Path::new(bootstrap_code)),
|
||||
destination_path: Path::new(destination),
|
||||
max_size,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user