Skip to content

Commit 4556283

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

File tree

4 files changed

+123
-15
lines changed

4 files changed

+123
-15
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", "pe"]
1010
elf = []
1111
bzimage = []
12+
pe = []
1213

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

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
## Short-description
44

5-
* Parsing and loading vmlinux (raw ELF image) and bzImage images
5+
* Parsing and loading vmlinux (raw ELF image), bzImage and PE images
66
* Linux command line parsing and generation
7+
* Loading device tree blobs
78
* Definitions and helpers for the Linux boot protocol
89

910
## How to build
@@ -44,7 +45,7 @@ locally build a bzImage, copy it to the `src/loader` directory and run
4445
# Assuming your linux-loader and linux-stable are both under ${LINUX_LOADER}:
4546
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git ${LINUX_LOADER}/linux-stable
4647
cd linux-stable
47-
make bzImage
48+
make bzImage
4849
cp linux-stable/arch/x86/boot/bzImage ${LINUX_LOADER}/linux-loader/src/loader/
4950
cd ${LINUX_LOADER}/linux-loader
5051
container_version=5
@@ -53,5 +54,5 @@ docker run -it \
5354
--volume $(pwd):/linux-loader \
5455
rustvmm/dev:v${container_version}
5556
cd linux-loader/
56-
cargo test
57+
cargo test
5758
```

src/lib.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,16 @@
1111

1212
//! A Linux kernel image loading crate.
1313
//!
14-
//! This crate offers support for loading raw ELF (vmlinux) and compressed
15-
//! big zImage (bzImage) kernel images.
14+
//! This crate offers support for loading raw ELF (vmlinux), compressed
15+
//! big zImage (bzImage) and PE (Image) kernel images.
1616
//! Support for any other kernel image format can be added by implementing
1717
//! the KernelLoader.
1818
//!
1919
//! # Platform support
2020
//!
2121
//! - x86_64
22+
//! - ARM64
2223
//!
23-
//! This crates only supports x86_64 platforms because it implements support
24-
//! for kernel image formats (vmlinux and bzImage) that are x86 specific.
25-
//!
26-
//! Extending it to support other kernel image formats (e.g. ARM's Image)
27-
//! will make it consumable by other platforms.
2824
2925
pub mod cmdline;
3026
pub mod loader;

src/loader/mod.rs

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,9 @@ 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};
28-
#[cfg(feature = "elf")]
29-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
26+
#[cfg(any(feature = "elf", feature = "pe"))]
3027
use std::mem;
3128

3229
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestUsize};
@@ -73,6 +70,10 @@ pub enum Error {
7370
InvalidEntryAddress,
7471
/// Invalid bzImage binary.
7572
InvalidBzImage,
73+
/// Invalid Image binary.
74+
InvalidImage,
75+
/// Invalid Image magic number.
76+
InvalidImageMagicNumber,
7677
/// Invalid kernel start address.
7778
InvalidKernelStartAddress,
7879
/// Memory to load kernel image is too small.
@@ -87,6 +88,8 @@ pub enum Error {
8788
ReadBzImageHeader,
8889
/// Unable to read bzImage compressed image.
8990
ReadBzImageCompressedKernel,
91+
/// Unable to read Image header
92+
ReadImageHeader,
9093
/// Unable to seek to kernel start.
9194
SeekKernelStart,
9295
/// Unable to seek to ELF start.
@@ -99,6 +102,10 @@ pub enum Error {
99102
SeekBzImageHeader,
100103
/// Unable to seek to bzImage compressed kernel.
101104
SeekBzImageCompressedKernel,
105+
/// Unable to seek to Image end.
106+
SeekImageEnd,
107+
/// Unable to seek to Image header.
108+
SeekImageHeader,
102109
/// Unable to seek to note header.
103110
SeekNoteHeader,
104111
/// Unable to read note header.
@@ -125,11 +132,14 @@ impl error::Error for Error {
125132
Error::InvalidEntryAddress => "Invalid entry address",
126133
Error::InvalidBzImage => "Invalid bzImage",
127134
Error::InvalidKernelStartAddress => "Invalid kernel start address",
135+
Error::InvalidImage => "Invalid Image",
136+
Error::InvalidImageMagicNumber => "Invalid Image magic number",
128137
Error::MemoryOverflow => "Memory to load kernel image is not enough",
129138
Error::ReadElfHeader => "Unable to read elf header",
130139
Error::ReadKernelImage => "Unable to read kernel image",
131140
Error::ReadProgramHeader => "Unable to read program header",
132141
Error::ReadBzImageHeader => "Unable to read bzImage header",
142+
Error::ReadImageHeader => "Unable to read Image header",
133143
Error::ReadBzImageCompressedKernel => "Unable to read bzImage compressed kernel",
134144
Error::SeekKernelStart => "Unable to seek to kernel start",
135145
Error::SeekElfStart => "Unable to seek to elf start",
@@ -140,6 +150,8 @@ impl error::Error for Error {
140150
Error::SeekNoteHeader => "Unable to seek to note header",
141151
Error::ReadNoteHeader => "Unable to read note header",
142152
Error::InvalidPvhNote => "Invalid PVH note header",
153+
Error::SeekImageEnd => "Unable to seek Image end",
154+
Error::SeekImageHeader => "Unable to seek image header",
143155
}
144156
}
145157
}
@@ -539,6 +551,104 @@ fn align_up(addr: u64, align: u64) -> usize {
539551
}
540552
}
541553

554+
#[cfg(feature = "pe")]
555+
#[cfg(target_arch = "aarch64")]
556+
/// ARM64 Image (PE) format support
557+
pub struct PE;
558+
559+
#[cfg(feature = "pe")]
560+
#[cfg(target_arch = "aarch64")]
561+
#[repr(C)]
562+
#[derive(Debug, Copy, Clone, Default)]
563+
// See kernel doc Documentation/arm64/booting.txt for more information.
564+
// All these fields should be little endian.
565+
struct arm64_image_header {
566+
code0: u32,
567+
code1: u32,
568+
text_offset: u64,
569+
image_size: u64,
570+
flags: u64,
571+
res2: u64,
572+
res3: u64,
573+
res4: u64,
574+
magic: u32,
575+
res5: u32,
576+
}
577+
578+
#[cfg(feature = "pe")]
579+
#[cfg(target_arch = "aarch64")]
580+
unsafe impl ByteValued for arm64_image_header {}
581+
582+
#[cfg(feature = "pe")]
583+
#[cfg(target_arch = "aarch64")]
584+
impl KernelLoader for PE {
585+
/// Loads a PE Image into guest memory.
586+
///
587+
/// # Arguments
588+
///
589+
/// * `guest_mem` - The guest memory where the kernel image is loaded.
590+
/// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
591+
/// * `kernel_image` - Input Image image.
592+
/// * `highmem_start_address` - ignored on ARM64
593+
///
594+
/// # Returns
595+
/// * KernelLoaderResult
596+
fn load<F, M: GuestMemory>(
597+
guest_mem: &M,
598+
kernel_start: Option<GuestAddress>,
599+
kernel_image: &mut F,
600+
_highmem_start_address: Option<GuestAddress>,
601+
) -> Result<KernelLoaderResult>
602+
where
603+
F: Read + Seek,
604+
{
605+
let kernel_size = kernel_image
606+
.seek(SeekFrom::End(0))
607+
.map_err(|_| Error::SeekImageEnd)? as usize;
608+
let mut arm64_header: arm64_image_header = Default::default();
609+
kernel_image
610+
.seek(SeekFrom::Start(0))
611+
.map_err(|_| Error::SeekImageHeader)?;
612+
613+
arm64_header.as_bytes()
614+
.read_from(0, kernel_image, mem::size_of::<arm64_image_header>())
615+
.map_err(|_| Error::ReadImageHeader)?;
616+
617+
if u32::from_le(arm64_header.magic) != 0x644d_5241 {
618+
return Err(Error::InvalidImageMagicNumber);
619+
}
620+
621+
let image_size = u64::from_le(arm64_header.image_size);
622+
let mut text_offset = u64::from_le(arm64_header.text_offset);
623+
624+
if image_size == 0 {
625+
text_offset = 0x80000;
626+
}
627+
628+
let mem_offset = kernel_start
629+
.unwrap_or(GuestAddress(0))
630+
.checked_add(text_offset)
631+
.ok_or(Error::InvalidImage)?;
632+
633+
let mut loader_result: KernelLoaderResult = Default::default();
634+
loader_result.kernel_load = mem_offset;
635+
636+
kernel_image
637+
.seek(SeekFrom::Start(0))
638+
.map_err(|_| Error::SeekImageHeader)?;
639+
guest_mem
640+
.read_exact_from(mem_offset, kernel_image, kernel_size)
641+
.map_err(|_| Error::ReadKernelImage)?;
642+
643+
loader_result.kernel_end = mem_offset
644+
.raw_value()
645+
.checked_add(kernel_size as GuestUsize)
646+
.ok_or(Error::MemoryOverflow)?;
647+
648+
Ok(loader_result)
649+
}
650+
}
651+
542652
#[cfg(test)]
543653
mod test {
544654
use super::*;

0 commit comments

Comments
 (0)