Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moves note reader to a dedicated module #1211

Merged
merged 1 commit into from
Dec 28, 2024
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
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