Skip to content

Commit

Permalink
loader: add support for ARM64 PE format
Browse files Browse the repository at this point in the history
Signed-off-by: Qiu Wenbo <[email protected]>
  • Loading branch information
crab2313 committed Mar 9, 2020
1 parent 0c754f3 commit ae8be03
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 4 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ license = "Apache-2.0 AND BSD-3-Clause"
default = ["elf"]
elf = []
bzimage = []
image = []

[dependencies]
vm-memory = {version = "0.1.0", features = ["backend-mmap"]}
107 changes: 103 additions & 4 deletions src/loader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ extern crate vm_memory;
use std::error::{self, Error as KernelLoaderError};
use std::ffi::CStr;
use std::fmt::{self, Display};
#[cfg(any(feature = "elf", feature = "bzimage"))]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use std::io::SeekFrom;
use std::io::{Read, Seek};
#[cfg(feature = "elf")]
Expand All @@ -42,8 +40,6 @@ pub mod bootparam;
#[allow(non_upper_case_globals)]
#[cfg_attr(feature = "cargo-clippy", allow(clippy::all))]
mod elf;
#[cfg(any(feature = "elf", feature = "bzimage"))]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod struct_util;

#[derive(Debug, PartialEq)]
Expand All @@ -67,6 +63,10 @@ pub enum Error {
InvalidEntryAddress,
/// Invalid bzImage binary.
InvalidBzImage,
/// Invalid Image binary.
InvalidImage,
/// Invalid Image magic number.
InvalidImageMagicNumber,
/// Invalid kernel start address.
InvalidKernelStartAddress,
/// Memory to load kernel image is too small.
Expand All @@ -81,6 +81,8 @@ pub enum Error {
ReadBzImageHeader,
/// Unable to read bzImage compressed image.
ReadBzImageCompressedKernel,
/// Unable to read Image header
ReadImageHeader,
/// Unable to seek to kernel start.
SeekKernelStart,
/// Unable to seek to ELF start.
Expand All @@ -93,6 +95,10 @@ pub enum Error {
SeekBzImageHeader,
/// Unable to seek to bzImage compressed kernel.
SeekBzImageCompressedKernel,
/// Unable to seek to Image end.
SeekImageEnd,
/// Unable to seek to Image header.
SeekImageHeader,
}

/// A specialized `Result` type for the kernel loader.
Expand All @@ -113,18 +119,23 @@ impl error::Error for Error {
Error::InvalidEntryAddress => "Invalid entry address",
Error::InvalidBzImage => "Invalid bzImage",
Error::InvalidKernelStartAddress => "Invalid kernel start address",
Error::InvalidImage => "Invalid Image",
Error::InvalidImageMagicNumber => "Invalid Image magic number",
Error::MemoryOverflow => "Memory to load kernel image is not enough",
Error::ReadElfHeader => "Unable to read elf header",
Error::ReadKernelImage => "Unable to read kernel image",
Error::ReadProgramHeader => "Unable to read program header",
Error::ReadBzImageHeader => "Unable to read bzImage header",
Error::ReadImageHeader => "Unable to read Image header",
Error::ReadBzImageCompressedKernel => "Unable to read bzImage compressed kernel",
Error::SeekKernelStart => "Unable to seek to kernel start",
Error::SeekElfStart => "Unable to seek to elf start",
Error::SeekProgramHeader => "Unable to seek to program header",
Error::SeekBzImageEnd => "Unable to seek bzImage end",
Error::SeekBzImageHeader => "Unable to seek bzImage header",
Error::SeekBzImageCompressedKernel => "Unable to seek bzImage compressed kernel",
Error::SeekImageEnd => "Unable to seek Image end",
Error::SeekImageHeader => "Unable to seek image header",
}
}
}
Expand Down Expand Up @@ -409,6 +420,94 @@ pub fn load_cmdline<M: GuestMemory>(
Ok(())
}

#[cfg(feature = "image")]
#[cfg(target_arch = "aarch64")]
/// ARM64 Image (PE) format support
pub struct Image;

#[cfg(feature = "image")]
#[cfg(target_arch = "aarch64")]
#[allow(missing_docs)]
#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
pub struct arm64_image_header {
pub code0: u32,
pub code1: u32,
pub text_offset: u64,
pub image_size: u64,
pub flags: u64,
pub res2: u64,
pub res3: u64,
pub res4: u64,
pub magic: u32,
pub res5: u32,
}

#[cfg(feature = "image")]
#[cfg(target_arch = "aarch64")]
impl KernelLoader for Image {
/// Loads a Image
///
/// # Arguments
///
/// * `guest_mem` - The guest memory where the kernel image is loaded.
/// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
/// * `kernel_image` - Input Image image.
/// * `highmem_start_address` - ignored on ARM64
///
/// # Returns
/// * KernelLoaderResult
fn load<F, M: GuestMemory>(
guest_mem: &M,
kernel_start: Option<GuestAddress>,
kernel_image: &mut F,
_highmem_start_address: Option<GuestAddress>,
) -> Result<KernelLoaderResult>
where
F: Read + Seek,
{
let kernel_size = kernel_image
.seek(SeekFrom::End(0))
.map_err(|_| Error::SeekImageEnd)? as usize;
let mut arm64_header: arm64_image_header = Default::default();
kernel_image
.seek(SeekFrom::Start(0))
.map_err(|_| Error::SeekImageHeader)?;
unsafe {
// read_struct is safe when reading a POD struct. It can be used and dropped without issue.
struct_util::read_struct(kernel_image, &mut arm64_header)
.map_err(|_| Error::ReadImageHeader)?;
}

if u32::from_le(arm64_header.magic) != 0x644d_5241 {
return Err(Error::InvalidImageMagicNumber);
}

let text_offset = u64::from_le(arm64_header.text_offset);
let mem_offset = kernel_start
.unwrap_or(GuestAddress(0))
.checked_add(text_offset)
.ok_or(Error::InvalidImage)?;

let mut loader_result: KernelLoaderResult = Default::default();
loader_result.kernel_load = mem_offset;

kernel_image
.seek(SeekFrom::Start(0))
.map_err(|_| Error::SeekImageHeader)?;
guest_mem
.read_exact_from(mem_offset, kernel_image, kernel_size)
.map_err(|_| Error::ReadKernelImage)?;

loader_result.kernel_end = mem_offset
.raw_value()
.checked_add(kernel_size as GuestUsize)
.ok_or(Error::MemoryOverflow)?;

Ok(loader_result)
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down

0 comments on commit ae8be03

Please sign in to comment.