From ae8be0350784adc3513664cfaa5d1451e004fd14 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Mon, 2 Mar 2020 05:01:23 +0000 Subject: [PATCH] loader: add support for ARM64 PE format Signed-off-by: Qiu Wenbo --- Cargo.toml | 1 + src/loader/mod.rs | 107 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4ba0e36e..69e33693 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"]} diff --git a/src/loader/mod.rs b/src/loader/mod.rs index b5804449..6c438deb 100644 --- a/src/loader/mod.rs +++ b/src/loader/mod.rs @@ -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")] @@ -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)] @@ -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. @@ -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. @@ -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. @@ -113,11 +119,14 @@ 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", @@ -125,6 +134,8 @@ impl error::Error for Error { 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", } } } @@ -409,6 +420,94 @@ pub fn load_cmdline( 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( + guest_mem: &M, + kernel_start: Option, + kernel_image: &mut F, + _highmem_start_address: Option, + ) -> Result + 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::*;