Skip to content

Commit

Permalink
Moves note reader to a dedicated module (#1211)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Dec 28, 2024
1 parent 95906d8 commit 0a875cc
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 164 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ path = "src/main.rs"
[dependencies]
async-net = "2.0.0"
bitfield-struct = "0.9.2"
bytes = "1.9.0"
ciborium = "0.2.2"
clap = { version = "4.5.21", features = ["derive"] }
erdp = "0.1.1"
Expand Down
4 changes: 2 additions & 2 deletions gui/src/hv/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub unsafe fn new(
ram_size: NonZero<usize>,
ram_block: NonZero<usize>,
debug: bool,
) -> Result<Kvm, KvmError> {
) -> Result<impl Hypervisor, KvmError> {
// Create RAM.
let ram = Ram::new(ram_size, ram_block, KvmMapper).map_err(KvmError::CreateRamFailed)?;

Expand Down Expand Up @@ -320,7 +320,7 @@ fn get_ext(kvm: BorrowedFd, id: c_int) -> Result<c_uint, Error> {
/// Implementation of [`Hypervisor`] using KVM.
///
/// Fields in this struct need to drop in a correct order (e.g. vm must be dropped before ram).
pub struct Kvm {
struct Kvm {
feats: CpuFeats,
cpus: Vec<Mutex<OwnedFd>>,
vcpu_mmap_size: usize,
Expand Down
4 changes: 2 additions & 2 deletions gui/src/hv/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub unsafe fn new(
ram_size: NonZero<usize>,
ram_block: NonZero<usize>,
debug: bool,
) -> Result<Hvf, HvfError> {
) -> Result<impl Hypervisor, HvfError> {
// Create RAM.
let ram = Ram::new(ram_size, ram_block, HvfMapper).map_err(HvfError::CreateRamFailed)?;

Expand Down Expand Up @@ -72,7 +72,7 @@ pub unsafe fn new(
}

/// Implementation of [`Hypervisor`] using Hypervisor Framework.
pub struct Hvf {
struct Hvf {
ram: Ram<HvfMapper>,
debug: bool,
cpu_config: hv_vcpu_config_t,
Expand Down
9 changes: 0 additions & 9 deletions gui/src/hv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ mod arch;
mod os;
mod ram;

#[cfg(target_os = "linux")]
pub type Default = self::os::Kvm;

#[cfg(target_os = "macos")]
pub type Default = self::os::Hvf;

#[cfg(target_os = "windows")]
pub type Default = self::os::Whp;

#[cfg(target_os = "linux")]
pub type HypervisorError = self::os::KvmError;

Expand Down
4 changes: 2 additions & 2 deletions gui/src/hv/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub unsafe fn new(
ram_size: NonZero<usize>,
ram_block: NonZero<usize>,
debug: bool,
) -> Result<Whp, WhpError> {
) -> Result<impl Hypervisor, WhpError> {
// Create RAM.
let ram = Ram::new(ram_size, ram_block, WhpMapper).map_err(WhpError::CreateRamFailed)?;

Expand Down Expand Up @@ -50,7 +50,7 @@ pub unsafe fn new(
/// Implementation of [`Hypervisor`] using Windows Hypervisor Platform.
///
/// Fields in this struct need to drop in a correct order.
pub struct Whp {
struct Whp {
part: Partition,
feats: CpuFeats,
ram: Ram<WhpMapper>,
Expand Down
9 changes: 6 additions & 3 deletions gui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,10 @@ async fn run(args: ProgramArgs, exe: PathBuf) -> Result<(), ProgramError> {
let mut gdb_in = [0; 1024];

// Start VMM.
let mut vmm = Vmm::new(&profile, &kernel, None, &shutdown).map_err(ProgramError::StartVmm)?;
let mut vmm = match Vmm::new(&profile, &kernel, None, &shutdown) {
Ok(v) => v,
Err(e) => return Err(ProgramError::StartVmm(kernel, e)),
};

loop {
// Prepare futures to poll.
Expand Down Expand Up @@ -520,6 +523,6 @@ enum ProgramError {
#[error("couldn't build graphics engine")]
BuildGraphicsEngine(#[source] GraphicsError),

#[error("couldn't start VMM")]
StartVmm(#[source] VmmError),
#[error("couldn't start VMM for {0}")]
StartVmm(PathBuf, #[source] VmmError),
}
32 changes: 22 additions & 10 deletions gui/src/vmm/kernel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pub use self::note::*;
pub use self::segment::*;

use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Take};
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};
use std::path::Path;
use thiserror::Error;

pub use self::segment::*;

mod note;
mod segment;

/// Encapsulates a kernel ELF file.
Expand Down Expand Up @@ -66,23 +68,33 @@ impl Kernel {
self.e_entry
}

pub fn program_headers(&mut self) -> Result<ProgramHeaders, std::io::Error> {
pub fn program_headers(&mut self) -> Result<ProgramHeaders, Error> {
let off = self.file.seek(SeekFrom::Start(self.e_phoff))?;

if off != self.e_phoff {
Err(std::io::Error::from(std::io::ErrorKind::UnexpectedEof))
Err(Error::from(ErrorKind::UnexpectedEof))
} else {
Ok(ProgramHeaders::new(&mut self.file, off, self.e_phnum))
}
}

pub fn segment_data(&mut self, hdr: &ProgramHeader) -> Result<Take<&mut File>, std::io::Error> {
/// Note that this will load the whole segment into the memory so you need to check
/// [`ProgramHeader::p_filesz`] before calling this method.
pub fn notes(&mut self, hdr: &ProgramHeader) -> Result<Notes, Error> {
let mut data = Vec::with_capacity(hdr.p_filesz);

self.segment_data(hdr)?.read_to_end(&mut data)?;

Ok(Notes::new(data))
}

pub fn segment_data(&mut self, hdr: &ProgramHeader) -> Result<impl Read + '_, Error> {
let off = self.file.seek(SeekFrom::Start(hdr.p_offset))?;

if off != hdr.p_offset {
Err(std::io::Error::from(std::io::ErrorKind::UnexpectedEof))
Err(Error::from(ErrorKind::UnexpectedEof))
} else {
Ok(self.file.by_ref().take(hdr.p_filesz))
Ok(self.file.by_ref().take(hdr.p_filesz.try_into().unwrap()))
}
}
}
Expand All @@ -96,10 +108,10 @@ const ELF_MACHINE: u16 = 183;
#[derive(Debug, Error)]
pub enum KernelError {
#[error("couldn't open kernel file")]
OpenImageFailed(#[source] std::io::Error),
OpenImageFailed(#[source] Error),

#[error("couldn't read ELF header")]
ReadElfHeaderFailed(#[source] std::io::Error),
ReadElfHeaderFailed(#[source] Error),

#[error("the kernel is not an ELF file")]
NotElf,
Expand Down
84 changes: 84 additions & 0 deletions gui/src/vmm/kernel/note.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use bytes::{Buf, Bytes};
use std::cmp::min;
use thiserror::Error;

/// Iterator to enumerate ELF notes.
pub struct Notes(Bytes);

impl Notes {
pub(super) fn new(data: impl Into<Bytes>) -> Self {
Self(data.into())
}
}

impl Iterator for Notes {
type Item = Result<Note, NoteError>;

fn next(&mut self) -> Option<Self::Item> {
// Check remaining data.
let hdr = 4 * 3;

if self.0.is_empty() {
return None;
} else if self.0.len() < hdr {
return Some(Err(NoteError::InvalidHeader));
}

// Parse header.
let mut hdr = self.0.split_to(hdr);
let nlen: usize = hdr.get_u32_ne().try_into().unwrap();
let dlen: usize = hdr.get_u32_ne().try_into().unwrap();
let ty = hdr.get_u32_ne();

if nlen == 0 {
// Name is null-terminated so it should have at least 1 byte.
return Some(Err(NoteError::InvalidName));
} else if nlen > self.0.len() {
return Some(Err(NoteError::InvalidHeader));
}

// Get name.
let mut name = self.0.split_to(nlen);
let len = nlen - 1;

if name.iter().position(|&b| b == 0) != Some(len) {
return Some(Err(NoteError::InvalidName));
}

name.truncate(len);

// Skip alignment.
let skip = nlen.next_multiple_of(4) - nlen;

self.0.advance(min(skip, self.0.len()));

if dlen > self.0.len() {
return Some(Err(NoteError::InvalidHeader));
}

// Get description.
let desc = self.0.split_to(dlen);
let skip = dlen.next_multiple_of(4) - dlen;

self.0.advance(min(skip, self.0.len()));

Some(Ok(Note { name, desc, ty }))
}
}

/// Parsed ELF program header.
pub struct Note {
pub name: Bytes,
pub desc: Bytes,
pub ty: u32,
}

/// Represents an error when [`Notes`] fails to enumerate next ELF note.
#[derive(Debug, Error)]
pub enum NoteError {
#[error("invalid header")]
InvalidHeader,

#[error("invalid name")]
InvalidName,
}
18 changes: 9 additions & 9 deletions gui/src/vmm/kernel/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ use std::io::Read;
use std::iter::FusedIterator;
use thiserror::Error;

pub(crate) const PT_LOAD: u32 = 1;
pub(crate) const PT_DYNAMIC: u32 = 2;
pub(crate) const PT_NOTE: u32 = 4;
pub(crate) const PT_PHDR: u32 = 6;
pub(crate) const PT_GNU_EH_FRAME: u32 = 0x6474e550;
pub(crate) const PT_GNU_STACK: u32 = 0x6474e551;
pub(crate) const PT_GNU_RELRO: u32 = 0x6474e552;
pub const PT_LOAD: u32 = 1;
pub const PT_DYNAMIC: u32 = 2;
pub const PT_NOTE: u32 = 4;
pub const PT_PHDR: u32 = 6;
pub const PT_GNU_EH_FRAME: u32 = 0x6474e550;
pub const PT_GNU_STACK: u32 = 0x6474e551;
pub const PT_GNU_RELRO: u32 = 0x6474e552;

/// Iterator to enumerate ELF program headers.
pub struct ProgramHeaders<'a> {
Expand Down Expand Up @@ -54,7 +54,7 @@ impl Iterator for ProgramHeaders<'_> {
let p_type = u32::from_ne_bytes(data[..4].try_into().unwrap());
let p_offset = u64::from_ne_bytes(data[8..16].try_into().unwrap());
let p_vaddr = usize::from_ne_bytes(data[16..24].try_into().unwrap());
let p_filesz = u64::from_ne_bytes(data[32..40].try_into().unwrap());
let p_filesz = usize::from_ne_bytes(data[32..40].try_into().unwrap());
let p_memsz = usize::from_ne_bytes(data[40..48].try_into().unwrap());

self.parsed += 1;
Expand All @@ -76,7 +76,7 @@ pub struct ProgramHeader {
pub p_type: u32,
pub p_offset: u64,
pub p_vaddr: usize,
pub p_filesz: u64,
pub p_filesz: usize,
pub p_memsz: usize,
}

Expand Down
Loading

0 comments on commit 0a875cc

Please sign in to comment.