Skip to content

Commit ca20691

Browse files
committed
loader: add support for ARM64 PE format
Signed-off-by: Qiu Wenbo <qiuwenbo@phytium.com.cn>
1 parent 0ce5bfa commit ca20691

File tree

3 files changed

+113
-5
lines changed

3 files changed

+113
-5
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ edition = "2018"
66
license = "Apache-2.0 AND BSD-3-Clause"
77

88
[features]
9-
default = ["elf"]
9+
default = ["elf", "image"]
1010
elf = []
1111
bzimage = []
12+
image = []
1213

1314
[dependencies]
1415
vm-memory = {version = "0.1.0", features = ["backend-mmap"]}

src/loader/mod.rs

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ extern crate vm_memory;
2121
use std::error::{self, Error as KernelLoaderError};
2222
use std::ffi::CStr;
2323
use std::fmt::{self, Display};
24-
#[cfg(any(feature = "elf", feature = "bzimage"))]
25-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2624
use std::io::SeekFrom;
2725
use std::io::{Read, Seek};
2826
#[cfg(feature = "elf")]
@@ -51,8 +49,6 @@ pub mod start_info;
5149
#[allow(non_upper_case_globals)]
5250
#[cfg_attr(feature = "cargo-clippy", allow(clippy::all))]
5351
mod elf;
54-
#[cfg(any(feature = "elf", feature = "bzimage"))]
55-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
5652
mod struct_util;
5753

5854
#[derive(Debug, PartialEq)]
@@ -76,6 +72,10 @@ pub enum Error {
7672
InvalidEntryAddress,
7773
/// Invalid bzImage binary.
7874
InvalidBzImage,
75+
/// Invalid Image binary.
76+
InvalidImage,
77+
/// Invalid Image magic number.
78+
InvalidImageMagicNumber,
7979
/// Invalid kernel start address.
8080
InvalidKernelStartAddress,
8181
/// Memory to load kernel image is too small.
@@ -90,6 +90,8 @@ pub enum Error {
9090
ReadBzImageHeader,
9191
/// Unable to read bzImage compressed image.
9292
ReadBzImageCompressedKernel,
93+
/// Unable to read Image header
94+
ReadImageHeader,
9395
/// Unable to seek to kernel start.
9496
SeekKernelStart,
9597
/// Unable to seek to ELF start.
@@ -102,6 +104,10 @@ pub enum Error {
102104
SeekBzImageHeader,
103105
/// Unable to seek to bzImage compressed kernel.
104106
SeekBzImageCompressedKernel,
107+
/// Unable to seek to Image end.
108+
SeekImageEnd,
109+
/// Unable to seek to Image header.
110+
SeekImageHeader,
105111
/// Unable to seek to note header.
106112
SeekNoteHeader,
107113
/// Unable to read note header.
@@ -128,11 +134,14 @@ impl error::Error for Error {
128134
Error::InvalidEntryAddress => "Invalid entry address",
129135
Error::InvalidBzImage => "Invalid bzImage",
130136
Error::InvalidKernelStartAddress => "Invalid kernel start address",
137+
Error::InvalidImage => "Invalid Image",
138+
Error::InvalidImageMagicNumber => "Invalid Image magic number",
131139
Error::MemoryOverflow => "Memory to load kernel image is not enough",
132140
Error::ReadElfHeader => "Unable to read elf header",
133141
Error::ReadKernelImage => "Unable to read kernel image",
134142
Error::ReadProgramHeader => "Unable to read program header",
135143
Error::ReadBzImageHeader => "Unable to read bzImage header",
144+
Error::ReadImageHeader => "Unable to read Image header",
136145
Error::ReadBzImageCompressedKernel => "Unable to read bzImage compressed kernel",
137146
Error::SeekKernelStart => "Unable to seek to kernel start",
138147
Error::SeekElfStart => "Unable to seek to elf start",
@@ -143,6 +152,8 @@ impl error::Error for Error {
143152
Error::SeekNoteHeader => "Unable to seek to note header",
144153
Error::ReadNoteHeader => "Unable to read note header",
145154
Error::InvalidPvhNote => "Invalid PVH note header",
155+
Error::SeekImageEnd => "Unable to seek Image end",
156+
Error::SeekImageHeader => "Unable to seek image header",
146157
}
147158
}
148159
}
@@ -525,6 +536,100 @@ fn align_up(addr: u64, align: u64) -> usize {
525536
}
526537
}
527538

539+
#[cfg(feature = "image")]
540+
#[cfg(target_arch = "aarch64")]
541+
/// ARM64 Image (PE) format support
542+
pub struct Image;
543+
544+
#[cfg(feature = "image")]
545+
#[cfg(target_arch = "aarch64")]
546+
#[repr(C)]
547+
#[derive(Debug, Copy, Clone, Default)]
548+
// See kernel doc Documentation/arm64/booting.txt for more information.
549+
struct arm64_image_header {
550+
code0: u32,
551+
code1: u32,
552+
text_offset: u64,
553+
image_size: u64,
554+
flags: u64,
555+
res2: u64,
556+
res3: u64,
557+
res4: u64,
558+
magic: u32,
559+
res5: u32,
560+
}
561+
562+
#[cfg(feature = "image")]
563+
#[cfg(target_arch = "aarch64")]
564+
impl KernelLoader for Image {
565+
/// Loads a Image
566+
///
567+
/// # Arguments
568+
///
569+
/// * `guest_mem` - The guest memory where the kernel image is loaded.
570+
/// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
571+
/// * `kernel_image` - Input Image image.
572+
/// * `highmem_start_address` - ignored on ARM64
573+
///
574+
/// # Returns
575+
/// * KernelLoaderResult
576+
fn load<F, M: GuestMemory>(
577+
guest_mem: &M,
578+
kernel_start: Option<GuestAddress>,
579+
kernel_image: &mut F,
580+
_highmem_start_address: Option<GuestAddress>,
581+
) -> Result<KernelLoaderResult>
582+
where
583+
F: Read + Seek,
584+
{
585+
let kernel_size = kernel_image
586+
.seek(SeekFrom::End(0))
587+
.map_err(|_| Error::SeekImageEnd)? as usize;
588+
let mut arm64_header: arm64_image_header = Default::default();
589+
kernel_image
590+
.seek(SeekFrom::Start(0))
591+
.map_err(|_| Error::SeekImageHeader)?;
592+
unsafe {
593+
// read_struct is safe when reading a POD struct. It can be used and dropped without issue.
594+
struct_util::read_struct(kernel_image, &mut arm64_header)
595+
.map_err(|_| Error::ReadImageHeader)?;
596+
}
597+
598+
if u32::from_le(arm64_header.magic) != 0x644d_5241 {
599+
return Err(Error::InvalidImageMagicNumber);
600+
}
601+
602+
let image_size = u64::from_le(arm64_header.image_size);
603+
let mut text_offset = u64::from_le(arm64_header.text_offset);
604+
605+
if image_size == 0 {
606+
text_offset = 0x80000;
607+
}
608+
609+
let mem_offset = kernel_start
610+
.unwrap_or(GuestAddress(0))
611+
.checked_add(text_offset)
612+
.ok_or(Error::InvalidImage)?;
613+
614+
let mut loader_result: KernelLoaderResult = Default::default();
615+
loader_result.kernel_load = mem_offset;
616+
617+
kernel_image
618+
.seek(SeekFrom::Start(0))
619+
.map_err(|_| Error::SeekImageHeader)?;
620+
guest_mem
621+
.read_exact_from(mem_offset, kernel_image, kernel_size)
622+
.map_err(|_| Error::ReadKernelImage)?;
623+
624+
loader_result.kernel_end = mem_offset
625+
.raw_value()
626+
.checked_add(kernel_size as GuestUsize)
627+
.ok_or(Error::MemoryOverflow)?;
628+
629+
Ok(loader_result)
630+
}
631+
}
632+
528633
#[cfg(test)]
529634
mod test {
530635
use super::*;

src/loader/struct_util.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub unsafe fn read_struct<T: Copy, F: Read>(f: &mut F, out: &mut T) -> Result<()
4747
/// This is unsafe because the struct is initialized to unverified data read from the input.
4848
/// `read_struct_slice` should only be called to fill plain data structs. It is not endian safe.
4949
#[cfg(feature = "elf")]
50+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
5051
pub unsafe fn read_struct_slice<T: Copy, F: Read>(f: &mut F, len: usize) -> Result<Vec<T>> {
5152
let mut out: Vec<T> = Vec::with_capacity(len);
5253
out.set_len(len);
@@ -122,6 +123,7 @@ mod tests {
122123

123124
#[test]
124125
#[cfg(feature = "elf")]
126+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
125127
fn struct_slice_read() {
126128
let orig = vec![
127129
TestRead {

0 commit comments

Comments
 (0)