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
27 changes: 14 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ members = [
"lib/crypto",
"lib/device-memory",
"lib/devicepath",
"lib/elf",
"lib/display-output",
"lib/edid",
"lib/elide",
Expand All @@ -68,6 +67,7 @@ members = [
"lib/radio",
"lib/random",
"lib/rootimage",
"lib/kimage",
"lib/scsi",
"lib/session",
"lib/ssh",
Expand Down Expand Up @@ -238,9 +238,11 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1"
bcachefs = { path = "lib/bcachefs" }
toyos-abi = { path = "sdk/abi" }
# What `build::syscall_entry_bytes` finds a staged kernel's entry with: its
# segments, and its symbol table where the kernel's own backtrace finds it.
toyos-elf = { path = "lib/elf" }
# The one ELF parser (`toyos::elf`), which the build reads the kernel's and
# the supervisor's images with.
toyos = { path = "sdk/toyos" }
# The kernel section the build writes (`build::kimage`).
toyos-kimage = { path = "lib/kimage" }
toyos-symbols = { path = "lib/symbols" }
# What `build::fpgate` decodes the linked x86-64 kernel with, to refuse an
# instruction that touches the user FP or vector state outside `arch::fpu`:
Expand Down
28 changes: 16 additions & 12 deletions build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1796,21 +1796,21 @@ const MOV_RSP_GS_LEN: usize = 9;
/// A kernel's `syscall_entry` from its first instruction to the end of the
/// segment it is in, found at its symbol.
fn syscall_entry_bytes(kernel: &[u8]) -> Result<&[u8], String> {
use toyos_elf::header::{ProgramHeader, PT_LOAD};
use toyos::elf::header::{ProgramHeader, PT_LOAD};

let (syms, strs) =
toyos_symbols::locate(kernel).ok_or("the kernel has no readable `.symtab`")?;
let table = toyos_elf::SymTab::new(syms, strs);
toyos::elf::section::symbol_tables(kernel).ok_or("the kernel has no readable `.symtab`")?;
let table = toyos::elf::SymTab::new(syms, strs);
let mut entries = table.defined().filter(|&(i, sym)| {
sym.kind() == toyos_elf::sym::STT_FUNC && table.name(i).ends_with(SYSCALL_ENTRY_SYMBOL)
sym.kind() == toyos::elf::sym::STT_FUNC && table.name(i).ends_with(SYSCALL_ENTRY_SYMBOL)
});
let (Some((_, entry)), None) = (entries.next(), entries.next()) else {
return Err(format!(
"the kernel's `.symtab` does not name exactly one function `…{SYSCALL_ENTRY_SYMBOL}`"
));
};
let header = toyos_elf::FileHeader::parse(kernel).map_err(|e| format!("{e:?}"))?;
let extent = toyos_elf::Layout::parse(kernel, header.machine).map_err(|e| format!("{e}"))?.extent();
let header = toyos::elf::FileHeader::parse(kernel).map_err(|e| format!("{e:?}"))?;
let extent = toyos::elf::Layout::parse(kernel, header.machine).map_err(|e| format!("{e}"))?.extent();
let value = entry
.address(extent)
.map(|at| extent.min() + at.get())
Expand All @@ -1822,7 +1822,7 @@ fn syscall_entry_bytes(kernel: &[u8]) -> Result<&[u8], String> {
.find_map(|segment| {
let within = value.checked_sub(segment.vaddr)?;
let left = segment.filesz.checked_sub(within).filter(|&left| left != 0)?;
toyos_symbols::file_range(kernel, segment.offset.checked_add(within)?, left)
toyos::elf::file_range(kernel, segment.offset.checked_add(within)?, left)
})
.ok_or_else(|| format!("no `PT_LOAD` holds `syscall_entry` at {value:#x} in the file"))
}
Expand Down Expand Up @@ -2050,7 +2050,8 @@ fn said_key(plan: &Plan) -> &'static crate::signing::Key {
key
}

/// The kernel, the loader and the userland a mode's image is made of.
/// The kernel section (`build::kimage`), the loader and the userland a mode's
/// image is made of.
fn shipped_parts(root: &Path, boot: &Boot, plan: &Plan) -> (Vec<u8>, Vec<u8>, Userland) {
let kernel_features = plan.features.join(",");
let arch = plan.arch;
Expand Down Expand Up @@ -2081,7 +2082,7 @@ fn shipped_parts(root: &Path, boot: &Boot, plan: &Plan) -> (Vec<u8>, Vec<u8>, Us
let userland = build_and_assemble(root, &config, &env, &[], &plan.root_omits, false, arch, plan.machines);

let bl_bytes = fs::read(&bl_art).expect("Failed to read staged bootloader");
(kernel_bytes, bl_bytes, userland)
(crate::kimage::section(&kernel_bytes, &userland.supervisor, arch), bl_bytes, userland)
}

/// Create an empty disk image the guest sees at full size and the host pays
Expand Down Expand Up @@ -2213,7 +2214,9 @@ pub fn build_test_image(
)
}

/// The three parts one image is made of, each memoized for this process.
/// The three parts one image is made of: the kernel section
/// ([`crate::kimage`]) of the memoized kernel and userland, and the memoized
/// loader and userland.
pub struct Parts {
pub kernel: Arc<Vec<u8>>,
pub bootloader: Arc<Vec<u8>>,
Expand Down Expand Up @@ -2253,7 +2256,7 @@ pub fn build_test_parts(
// staleness sweep to protect.
let memo = (KERNEL.get(kernel_key), BOOTLOADER.get(bl_key), USERLAND.get(root_image_key));
if let (Some(kernel), Some(bootloader), Some(userland)) = memo {
return Parts { kernel, bootloader, userland };
return Parts { kernel: Arc::new(crate::kimage::section(&kernel, &userland.supervisor, arch)), bootloader, userland };
}

// A cache miss is shared setup, not a property of whichever test happened
Expand Down Expand Up @@ -2303,7 +2306,8 @@ pub fn build_test_parts(

drop(building);

Parts { kernel: kernel_bytes, bootloader: bl_bytes, userland }
let kernel = Arc::new(crate::kimage::section(&kernel_bytes, &userland.supervisor, arch));
Parts { kernel, bootloader: bl_bytes, userland }
}

/// Build all binaries in a multi-binary crate. Returns vec of (binary_name, bytes).
Expand Down
12 changes: 6 additions & 6 deletions build/fpgate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
//! pass, and only in a function of the [`OWNER`] module.

use iced_x86::{CpuidFeature, Decoder, DecoderOptions, Instruction, InstructionInfoFactory, Mnemonic, Register};
use toyos_elf::section::SectionHeader;
use toyos_elf::{FileHeader, Layout, Machine, SectionTable, SymTab};
use toyos::elf::section::SectionHeader;
use toyos::elf::{FileHeader, Layout, Machine, SectionTable, SymTab};

/// `SHT_PROGBITS` and `SHF_EXECINSTR` (System V gABI, "Sections").
const SHT_PROGBITS: u32 = 1;
Expand Down Expand Up @@ -86,7 +86,7 @@ pub fn judge(kernel: &[u8]) -> Result<(), String> {
if header.machine != Machine::X86_64 {
return Err(format!("the kernel is for {:?}, and this reads x86-64", header.machine));
}
let table = toyos_symbols::file_range(kernel, header.shoff, toyos_symbols::shdr_table_len(&header))
let table = toyos::elf::file_range(kernel, header.shoff, u64::from(header.shnum) * u64::from(header.shentsize))
.ok_or("the kernel's section headers lie outside it")?;
let sections: Vec<SectionHeader> = SectionTable::new(table)
.iter()
Expand All @@ -103,7 +103,7 @@ pub fn judge(kernel: &[u8]) -> Result<(), String> {
boundaries.push((at, bitness));
}
for section in &sections {
let bytes = toyos_symbols::file_range(kernel, section.offset, section.size)
let bytes = toyos::elf::file_range(kernel, section.offset, section.size)
.ok_or("an executable section lies outside the kernel")?;
let end = section.addr + section.size;
let mut cuts: Vec<(u64, u32)> = vec![(section.addr, 64)];
Expand Down Expand Up @@ -137,13 +137,13 @@ struct Functions<'a> {

impl<'a> Functions<'a> {
fn of(kernel: &'a [u8], header: &FileHeader, sections: &[SectionHeader]) -> Result<Self, String> {
let (syms, strs) = toyos_symbols::locate(kernel).ok_or("the kernel has no readable `.symtab`")?;
let (syms, strs) = toyos::elf::section::symbol_tables(kernel).ok_or("the kernel has no readable `.symtab`")?;
let table = SymTab::new(syms, strs);
let extent = Layout::parse(kernel, header.machine).map_err(|e| format!("{e}"))?.extent();
let in_code = |at: u64| sections.iter().any(|s| at >= s.addr && at < s.addr + s.size);
let mut starts: Vec<(u64, &str)> = table
.defined()
.filter(|(_, sym)| matches!(sym.kind(), toyos_elf::sym::STT_FUNC | STT_NOTYPE))
.filter(|(_, sym)| matches!(sym.kind(), toyos::elf::sym::STT_FUNC | STT_NOTYPE))
.filter_map(|(i, sym)| Some((extent.min() + sym.address(extent)?.get(), table.name(i))))
.filter(|&(at, name)| in_code(at) && !name.is_empty())
.collect();
Expand Down
6 changes: 3 additions & 3 deletions build/hostws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ mod tests {
#[test]
fn the_gate_refuses_a_crate_that_joined_neither_list() {
let members: BTreeSet<String> =
[".", "lib/elf", "system/usbd", "system/usbd/xhci"].iter().map(|s| s.to_string()).collect();
[".", "lib/kimage", "system/usbd", "system/usbd/xhci"].iter().map(|s| s.to_string()).collect();

let all_declared: BTreeSet<String> = members.clone();
assert!(unclaimed(&members, &all_declared).is_empty());
Expand All @@ -336,7 +336,7 @@ mod tests {
let root = repo_root();
let found = crate_dirs(&root);
assert!(found.contains("."), "the walk did not find the root package");
assert!(found.contains("lib/elf"), "the walk did not find lib/elf: {found:?}");
assert!(found.contains("lib/kimage"), "the walk did not find lib/kimage: {found:?}");
assert!(
found.contains("system/usbd/xhci"),
"the walk did not descend past the first level, so a nested member could \
Expand Down Expand Up @@ -450,7 +450,7 @@ mod tests {
#[test]
fn the_dead_path_scan_names_the_member_and_ignores_an_excluded_crate() {
let members: BTreeSet<String> =
[".", "toyos-abi", "toyos-elf"].iter().map(|s| s.to_string()).collect();
[".", "toyos-abi", "toyos-kimage"].iter().map(|s| s.to_string()).collect();
assert_eq!(
dead_member_target_paths(&members, "let abi = root.join(\"../../toyos-abi/target/x\");"),
["toyos-abi/target"],
Expand Down
Loading