Skip to content

Commit b3e74fe

Browse files
committed
riscv64: Refactor loader
Refactor RISC-V loader to work with PE image. Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
1 parent 484db1b commit b3e74fe

File tree

6 files changed

+64
-23
lines changed

6 files changed

+64
-23
lines changed

.cargo/config

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
[target.aarch64-unknown-linux-musl]
22
rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc" ]
33

4-
[target.riscv64gc-unknown-linux-gnu]
5-
linker = "riscv64-unknown-linux-gnu-gcc"

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# Upcoming Release
22

3+
## Added
4+
5+
- Introduce RISC-V support to `loader` module.
6+
37
# [v0.12.0]
48

59
## Changed
10+
611
- [[#187](https://github.com/rust-vmm/linux-loader/pull/187)] Updated vm-memory to 0.15.0.
712
- [[#179](https://github.com/rust-vmm/linux-loader/pull/179)] Load hvm_modlist_entry into guest memory when requested.
813
- [[#177](https://github.com/rust-vmm/linux-loader/pull/176)] Added loading

src/loader/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ mod aarch64;
4343
pub use aarch64::*;
4444

4545
#[cfg(target_arch = "riscv64")]
46-
mod riscv;
46+
mod riscv64;
4747
#[cfg(target_arch = "riscv64")]
48-
pub use riscv::*;
48+
pub use riscv64::*;
4949

5050
#[derive(Debug, PartialEq, Eq)]
5151
/// Kernel loader errors.
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright 2024 © Institute of Software, CAS. All rights reserved.
12
// Copyright (c) 2023 StarFive Technology Co., Ltd. All rights reserved.
23
// Copyright (c) 2019 Intel Corporation. All rights reserved.
34
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
@@ -8,9 +9,7 @@
89
//
910
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
1011

11-
//! Traits and structs for loading `riscv` kernels into guest memory.
12-
13-
#![cfg(target_arch = "riscv64")]
12+
//! Traits and structs for loading `riscv64` kernels into guest memory.
1413
1514
#[cfg(feature = "pe")]
1615
pub mod pe;

src/loader/riscv/pe/mod.rs renamed to src/loader/riscv64/pe/mod.rs

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright 2024 © Institute of Software, CAS. All rights reserved.
12
// Copyright (c) 2023 StarFive Technology Co., Ltd. All rights reserved.
23
// Copyright © 2020, Oracle and/or its affiliates.
34
// Copyright (c) 2019 Intel Corporation. All rights reserved.
@@ -11,8 +12,6 @@
1112

1213
//! Traits and structs for loading pe image kernels into guest memory.
1314
14-
#![cfg(feature = "pe")]
15-
1615
use std::fmt;
1716
use std::io::{Read, Seek, SeekFrom};
1817

@@ -25,7 +24,7 @@ pub struct PE;
2524

2625
// SAFETY: The layout of the structure is fixed and can be initialized by
2726
// reading its content from byte array.
28-
unsafe impl ByteValued for riscv_image_header {}
27+
unsafe impl ByteValued for riscv64_image_header {}
2928

3029
#[derive(Debug, PartialEq, Eq)]
3130
/// PE kernel loader errors.
@@ -34,13 +33,21 @@ pub enum Error {
3433
SeekImageEnd,
3534
/// Unable to seek to Image header.
3635
SeekImageHeader,
36+
/// Unable to seek to DTB start.
37+
SeekDtbStart,
38+
/// Unable to seek to DTB end.
39+
SeekDtbEnd,
40+
/// Device tree binary too big.
41+
DtbTooBig,
3742
/// Unable to read kernel image.
3843
ReadKernelImage,
3944
/// Unable to read Image header.
4045
ReadImageHeader,
46+
/// Unable to read DTB image
47+
ReadDtbImage,
4148
/// Invalid Image binary.
4249
InvalidImage,
43-
/// Invalid Image magic2 number.
50+
/// Invalid Image magic number.
4451
InvalidImageMagicNumber,
4552
/// Invalid base address alignment
4653
InvalidBaseAddrAlignment,
@@ -52,10 +59,14 @@ impl fmt::Display for Error {
5259
Error::SeekImageEnd => "unable to seek Image end",
5360
Error::SeekImageHeader => "unable to seek Image header",
5461
Error::ReadImageHeader => "unable to read Image header",
62+
Error::ReadDtbImage => "unable to read DTB image",
63+
Error::SeekDtbStart => "unable to seek DTB start",
64+
Error::SeekDtbEnd => "unable to seek DTB end",
5565
Error::InvalidImage => "invalid Image",
56-
Error::InvalidImageMagicNumber => "invalid Image magic2 number",
66+
Error::InvalidImageMagicNumber => "invalid Image magic number",
67+
Error::DtbTooBig => "device tree image too big",
5768
Error::ReadKernelImage => "unable to read kernel image",
58-
Error::InvalidBaseAddrAlignment => "base address not aligned to 2MiB (for riscv64)",
69+
Error::InvalidBaseAddrAlignment => "base address not aligned to 2 MB",
5970
};
6071

6172
write!(f, "PE Kernel Loader: {}", desc)
@@ -66,9 +77,9 @@ impl std::error::Error for Error {}
6677

6778
#[repr(C)]
6879
#[derive(Debug, Copy, Clone, Default)]
69-
// See kernel doc Documentation/riscv/boot-image-header.rst
80+
// See kernel doc Documentation/arch/riscv/boot-image-header.rst
7081
// All these fields should be little endian.
71-
struct riscv_image_header {
82+
struct riscv64_image_header {
7283
code0: u32,
7384
code1: u32,
7485
text_offset: u64,
@@ -88,7 +99,7 @@ impl KernelLoader for PE {
8899
/// # Arguments
89100
///
90101
/// * `guest_mem` - The guest memory where the kernel image is loaded.
91-
/// * `kernel_offset` - 2MiB-aligned (for riscv64) base address in guest memory at which to load the kernel.
102+
/// * `kernel_offset` - 2MB-aligned base addres in guest memory at which to load the kernel.
92103
/// * `kernel_image` - Input Image format kernel image.
93104
/// * `highmem_start_address` - ignored on RISC-V.
94105
///
@@ -106,21 +117,21 @@ impl KernelLoader for PE {
106117
let kernel_size = kernel_image
107118
.seek(SeekFrom::End(0))
108119
.map_err(|_| Error::SeekImageEnd)? as usize;
109-
let mut riscv_header: riscv_image_header = Default::default();
120+
let mut riscv64_header: riscv64_image_header = Default::default();
110121
kernel_image.rewind().map_err(|_| Error::SeekImageHeader)?;
111122

112123
kernel_image
113-
.read_exact(riscv_header.as_mut_slice())
124+
.read_exact(riscv64_header.as_mut_slice())
114125
.map_err(|_| Error::ReadImageHeader)?;
115126

116-
if u32::from_le(riscv_header.magic2) != 0x05435352 {
127+
if u32::from_le(riscv64_header.magic2) != 0x05435352 {
117128
return Err(Error::InvalidImageMagicNumber.into());
118129
}
119130

120-
let text_offset = u64::from_le(riscv_header.text_offset);
131+
let text_offset = u64::from_le(riscv64_header.text_offset);
121132

122-
// Validate that kernel_offset is 2MiB aligned (for riscv64)
123-
#[cfg(target_arch = "riscv64")]
133+
// Validate that kernel_offset is 2 MB aligned, as required by the
134+
// RISC-V boot protocol
124135
if let Some(kernel_offset) = kernel_offset {
125136
if kernel_offset.raw_value() % 0x0020_0000 != 0 {
126137
return Err(Error::InvalidBaseAddrAlignment.into());
@@ -151,6 +162,34 @@ impl KernelLoader for PE {
151162
}
152163
}
153164

165+
/// Writes the device tree to the given memory slice.
166+
///
167+
/// # Arguments
168+
///
169+
/// * `guest_mem` - A u8 slice that will be partially overwritten by the device tree blob.
170+
/// * `guest_addr` - The address in `guest_mem` at which to load the device tree blob.
171+
/// * `dtb_image` - The device tree blob.
172+
#[cfg(target_arch = "riscv64")]
173+
pub fn load_dtb<F, M: GuestMemory>(
174+
guest_mem: &M,
175+
guest_addr: GuestAddress,
176+
dtb_image: &mut F,
177+
) -> Result<()>
178+
where
179+
F: ReadVolatile + Read + Seek,
180+
{
181+
let dtb_size = dtb_image
182+
.seek(SeekFrom::End(0))
183+
.map_err(|_| Error::SeekDtbEnd)? as usize;
184+
if dtb_size > 0x200000 {
185+
return Err(Error::DtbTooBig.into());
186+
}
187+
dtb_image.rewind().map_err(|_| Error::SeekDtbStart)?;
188+
guest_mem
189+
.read_exact_volatile_from(guest_addr, dtb_image, dtb_size)
190+
.map_err(|_| Error::ReadDtbImage.into())
191+
}
192+
154193
#[cfg(test)]
155194
mod tests {
156195
use super::*;
@@ -181,7 +220,7 @@ mod tests {
181220
assert_eq!(loader_result.kernel_load.raw_value(), 0x600000);
182221
assert_eq!(loader_result.kernel_end, 0x601000);
183222

184-
// Attempt to load the kernel at an address that is not aligned to 2MiB boundary
223+
// Attempt to load the kernel at an address that is not aligned to 2MB boundary
185224
let kernel_offset = GuestAddress(0x0030_0000);
186225
let loader_result = PE::load(&gm, Some(kernel_offset), &mut Cursor::new(&image), None);
187226
assert_eq!(
File renamed without changes.

0 commit comments

Comments
 (0)