Skip to content

Commit 943bf75

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

File tree

6 files changed

+173
-11
lines changed

6 files changed

+173
-11
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/aarch64/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
//! Traits and structs for loading `aarch64` kernels into guest memory.
1111
1212
#![cfg(target_arch = "aarch64")]
13+
14+
#[cfg(feature = "pe")]
15+
pub mod pe;

src/loader/aarch64/pe/mod.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// Copyright (c) 2019 Intel Corporation. All rights reserved.
2+
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
//
4+
// Copyright 2017 The Chromium OS Authors. All rights reserved.
5+
// Use of this source code is governed by a BSD-style license that can be
6+
// found in the LICENSE-BSD-3-Clause file.
7+
//
8+
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
9+
10+
//! Traits and structs for loading pe image kernels into guest memory.
11+
12+
#![cfg(all(feature = "pe", target_arch = "aarch64"))]
13+
14+
use std::error::{self, Error as StdError};
15+
use std::fmt::{self, Display};
16+
use std::io::{Read, Seek, SeekFrom};
17+
use std::mem;
18+
19+
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestUsize};
20+
21+
use super::super::{Error as KernelLoaderError, KernelLoader, KernelLoaderResult, Result};
22+
23+
/// ARM64 Image (PE) format support
24+
pub struct PE;
25+
26+
unsafe impl ByteValued for arm64_image_header {}
27+
28+
#[derive(Debug, PartialEq)]
29+
/// Elf kernel loader errors.
30+
pub enum Error {
31+
/// Unable to seek to Image end.
32+
SeekImageEnd,
33+
/// Unable to seek to Image header.
34+
SeekImageHeader,
35+
/// Unable to read kernel image.
36+
ReadKernelImage,
37+
/// Unable to read Image header
38+
ReadImageHeader,
39+
/// Invalid Image binary.
40+
InvalidImage,
41+
/// Invalid Image magic number.
42+
InvalidImageMagicNumber,
43+
}
44+
45+
impl error::Error for Error {
46+
fn description(&self) -> &str {
47+
match self {
48+
Error::SeekImageEnd => "Unable to seek Image end",
49+
Error::SeekImageHeader => "Unable to seek image header",
50+
Error::ReadImageHeader => "Unable to read Image header",
51+
Error::InvalidImage => "Invalid Image",
52+
Error::InvalidImageMagicNumber => "Invalid Image magic number",
53+
Error::ReadKernelImage => "Unable to read kernel image",
54+
}
55+
}
56+
}
57+
58+
impl Display for Error {
59+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60+
write!(f, "Kernel Loader Error: {}", self.description())
61+
}
62+
}
63+
64+
#[repr(C)]
65+
#[derive(Debug, Copy, Clone, Default)]
66+
// See kernel doc Documentation/arm64/booting.txt for more information.
67+
// All these fields should be little endian.
68+
struct arm64_image_header {
69+
code0: u32,
70+
code1: u32,
71+
text_offset: u64,
72+
image_size: u64,
73+
flags: u64,
74+
res2: u64,
75+
res3: u64,
76+
res4: u64,
77+
magic: u32,
78+
res5: u32,
79+
}
80+
81+
impl KernelLoader for PE {
82+
/// Loads a PE Image into guest memory.
83+
///
84+
/// # Arguments
85+
///
86+
/// * `guest_mem` - The guest memory where the kernel image is loaded.
87+
/// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
88+
/// * `kernel_image` - Input Image image.
89+
/// * `highmem_start_address` - ignored on ARM64
90+
///
91+
/// # Returns
92+
/// * KernelLoaderResult
93+
fn load<F, M: GuestMemory>(
94+
guest_mem: &M,
95+
kernel_start: Option<GuestAddress>,
96+
kernel_image: &mut F,
97+
_highmem_start_address: Option<GuestAddress>,
98+
) -> Result<KernelLoaderResult>
99+
where
100+
F: Read + Seek,
101+
{
102+
let kernel_size = kernel_image
103+
.seek(SeekFrom::End(0))
104+
.map_err(|_| Error::SeekImageEnd)? as usize;
105+
let mut arm64_header: arm64_image_header = Default::default();
106+
kernel_image
107+
.seek(SeekFrom::Start(0))
108+
.map_err(|_| Error::SeekImageHeader)?;
109+
110+
arm64_header
111+
.as_bytes()
112+
.read_from(0, kernel_image, mem::size_of::<arm64_image_header>())
113+
.map_err(|_| Error::ReadImageHeader)?;
114+
115+
if u32::from_le(arm64_header.magic) != 0x644d_5241 {
116+
return Err(Error::InvalidImageMagicNumber.into());
117+
}
118+
119+
let image_size = u64::from_le(arm64_header.image_size);
120+
let mut text_offset = u64::from_le(arm64_header.text_offset);
121+
122+
if image_size == 0 {
123+
text_offset = 0x80000;
124+
}
125+
126+
let mem_offset = kernel_start
127+
.unwrap_or(GuestAddress(0))
128+
.checked_add(text_offset)
129+
.ok_or(Error::InvalidImage)?;
130+
131+
let mut loader_result: KernelLoaderResult = Default::default();
132+
loader_result.kernel_load = mem_offset;
133+
134+
kernel_image
135+
.seek(SeekFrom::Start(0))
136+
.map_err(|_| Error::SeekImageHeader)?;
137+
guest_mem
138+
.read_exact_from(mem_offset, kernel_image, kernel_size)
139+
.map_err(|_| Error::ReadKernelImage)?;
140+
141+
loader_result.kernel_end = mem_offset
142+
.raw_value()
143+
.checked_add(kernel_size as GuestUsize)
144+
.ok_or(KernelLoaderError::MemoryOverflow)?;
145+
146+
Ok(loader_result)
147+
}
148+
}

src/loader/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ pub enum Error {
5454
#[cfg(all(feature = "elf", any(target_arch = "x86", target_arch = "x86_64")))]
5555
Elf(elf::Error),
5656

57+
/// Failed to load PE image.
58+
#[cfg(all(feature = "pe", target_arch = "aarch64"))]
59+
Pe(pe::Error),
60+
5761
/// Failed writing command line to guest memory.
5862
CommandLineCopy,
5963
/// Command line overflowed guest memory.
@@ -74,6 +78,8 @@ impl StdError for Error {
7478
Error::Bzimage(ref e) => e.description(),
7579
#[cfg(all(feature = "elf", any(target_arch = "x86", target_arch = "x86_64")))]
7680
Error::Elf(ref e) => e.description(),
81+
#[cfg(all(feature = "elf", target_arch = "aarch64"))]
82+
Error::Pe(ref e) => e.description(),
7783

7884
Error::CommandLineCopy => "Failed writing command line to guest memory",
7985
Error::CommandLineOverflow => "Command line overflowed guest memory",
@@ -103,6 +109,13 @@ impl From<bzimage::Error> for Error {
103109
}
104110
}
105111

112+
#[cfg(all(feature = "pe", target_arch = "aarch64"))]
113+
impl From<pe::Error> for Error {
114+
fn from(err: pe::Error) -> Self {
115+
Error::Pe(err)
116+
}
117+
}
118+
106119
/// Result of [`KernelLoader.load()`](trait.KernelLoader.html#tymethod.load).
107120
///
108121
/// This specifies where the kernel is loading and passes additional

0 commit comments

Comments
 (0)