1
+ // Copyright 2024 © Institute of Software, CAS. All rights reserved.
1
2
// Copyright © 2020, Oracle and/or its affiliates.
2
3
// Copyright (c) 2019 Intel Corporation. All rights reserved.
3
4
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
@@ -17,13 +18,9 @@ use vm_memory::{Address, ByteValued, GuestAddress, GuestMemory, GuestUsize, Read
17
18
18
19
use crate :: loader:: { Error as KernelLoaderError , KernelLoader , KernelLoaderResult , Result } ;
19
20
20
- /// ARM64 Image (PE) format support
21
+ /// ARM64 and RISC-V64 Image (PE) format support
21
22
pub struct PE ;
22
23
23
- // SAFETY: The layout of the structure is fixed and can be initialized by
24
- // reading its content from byte array.
25
- unsafe impl ByteValued for arm64_image_header { }
26
-
27
24
#[ derive( Debug , PartialEq , Eq ) ]
28
25
/// PE kernel loader errors.
29
26
pub enum Error {
@@ -73,6 +70,7 @@ impl fmt::Display for Error {
73
70
74
71
impl std:: error:: Error for Error { }
75
72
73
+ #[ cfg( target_arch = "aarch64" ) ]
76
74
#[ repr( C ) ]
77
75
#[ derive( Debug , Copy , Clone , Default ) ]
78
76
// See kernel doc Documentation/arm64/booting.txt for more information.
@@ -90,6 +88,35 @@ struct arm64_image_header {
90
88
res5 : u32 ,
91
89
}
92
90
91
+ #[ cfg( target_arch = "aarch64" ) ]
92
+ // SAFETY: The layout of the structure is fixed and can be initialized by
93
+ // reading its content from byte array.
94
+ unsafe impl ByteValued for arm64_image_header { }
95
+
96
+ #[ cfg( target_arch = "riscv64" ) ]
97
+ #[ repr( C ) ]
98
+ #[ derive( Debug , Copy , Clone , Default ) ]
99
+ // See kernel doc Documentation/arch/riscv/boot-image-header.rst
100
+ // All these fields should be little endian.
101
+ struct riscv64_image_header {
102
+ code0 : u32 ,
103
+ code1 : u32 ,
104
+ text_offset : u64 ,
105
+ image_size : u64 ,
106
+ flags : u64 ,
107
+ version : u32 ,
108
+ res1 : u32 ,
109
+ res2 : u64 ,
110
+ magic : u64 ,
111
+ magic2 : u32 ,
112
+ res3 : u32 ,
113
+ }
114
+
115
+ #[ cfg( target_arch = "riscv64" ) ]
116
+ // SAFETY: The layout of the structure is fixed and can be initialized by
117
+ // reading its content from byte array.
118
+ unsafe impl ByteValued for riscv64_image_header { }
119
+
93
120
impl KernelLoader for PE {
94
121
/// Loads a PE Image into guest memory.
95
122
///
@@ -98,7 +125,7 @@ impl KernelLoader for PE {
98
125
/// * `guest_mem` - The guest memory where the kernel image is loaded.
99
126
/// * `kernel_offset` - 2MB-aligned base addres in guest memory at which to load the kernel.
100
127
/// * `kernel_image` - Input Image format kernel image.
101
- /// * `highmem_start_address` - ignored on ARM64.
128
+ /// * `highmem_start_address` - ignored on ARM64 and RISC-V64 .
102
129
///
103
130
/// # Returns
104
131
/// * KernelLoaderResult
@@ -114,26 +141,38 @@ impl KernelLoader for PE {
114
141
let kernel_size = kernel_image
115
142
. seek ( SeekFrom :: End ( 0 ) )
116
143
. map_err ( |_| Error :: SeekImageEnd ) ? as usize ;
117
- let mut arm64_header: arm64_image_header = Default :: default ( ) ;
144
+
145
+ #[ cfg( target_arch = "aarch64" ) ]
146
+ let mut image_header: arm64_image_header = Default :: default ( ) ;
147
+ #[ cfg( target_arch = "riscv64" ) ]
148
+ let mut image_header: riscv64_image_header = Default :: default ( ) ;
149
+
118
150
kernel_image. rewind ( ) . map_err ( |_| Error :: SeekImageHeader ) ?;
119
151
120
152
kernel_image
121
- . read_exact ( arm64_header . as_mut_slice ( ) )
153
+ . read_exact ( image_header . as_mut_slice ( ) )
122
154
. map_err ( |_| Error :: ReadImageHeader ) ?;
123
155
124
- if u32:: from_le ( arm64_header. magic ) != 0x644d_5241 {
156
+ #[ cfg( target_arch = "aarch64" ) ]
157
+ if u32:: from_le ( image_header. magic ) != 0x644d_5241 {
125
158
return Err ( Error :: InvalidImageMagicNumber . into ( ) ) ;
126
159
}
127
-
128
- let image_size = u64:: from_le ( arm64_header. image_size ) ;
129
- let mut text_offset = u64:: from_le ( arm64_header. text_offset ) ;
130
-
131
- if image_size == 0 {
132
- text_offset = 0x80000 ;
160
+ #[ cfg( target_arch = "riscv64" ) ]
161
+ if u32:: from_le ( image_header. magic2 ) != 0x0543_5352 {
162
+ return Err ( Error :: InvalidImageMagicNumber . into ( ) ) ;
133
163
}
134
164
165
+ #[ cfg( target_arch = "aarch64" ) ]
166
+ let text_offset = if u64:: from_le ( image_header. image_size ) == 0 {
167
+ 0x80000
168
+ } else {
169
+ u64:: from_le ( image_header. text_offset )
170
+ } ;
171
+ #[ cfg( target_arch = "riscv64" ) ]
172
+ let text_offset = u64:: from_le ( image_header. text_offset ) ;
173
+
135
174
// Validate that kernel_offset is 2 MB aligned, as required by the
136
- // arm64 boot protocol
175
+ // arm64 and riscv64 boot protocol
137
176
if let Some ( kernel_offset) = kernel_offset {
138
177
if kernel_offset. raw_value ( ) % 0x0020_0000 != 0 {
139
178
return Err ( Error :: InvalidBaseAddrAlignment . into ( ) ) ;
@@ -171,7 +210,7 @@ impl KernelLoader for PE {
171
210
/// * `guest_mem` - A u8 slice that will be partially overwritten by the device tree blob.
172
211
/// * `guest_addr` - The address in `guest_mem` at which to load the device tree blob.
173
212
/// * `dtb_image` - The device tree blob.
174
- #[ cfg( target_arch = "aarch64" ) ]
213
+ #[ cfg( any ( target_arch = "aarch64" , target_arch = "riscv64" ) ) ]
175
214
pub fn load_dtb < F , M : GuestMemory > (
176
215
guest_mem : & M ,
177
216
guest_addr : GuestAddress ,
@@ -207,12 +246,16 @@ mod tests {
207
246
208
247
fn make_image_bin ( ) -> Vec < u8 > {
209
248
let mut v = Vec :: new ( ) ;
210
- v. extend_from_slice ( include_bytes ! ( "test_image.bin" ) ) ;
249
+ #[ cfg( target_arch = "aarch64" ) ]
250
+ v. extend_from_slice ( include_bytes ! ( "test_arm64_image.bin" ) ) ;
251
+ #[ cfg( target_arch = "riscv64" ) ]
252
+ v. extend_from_slice ( include_bytes ! ( "test_riscv64_image.bin" ) ) ;
211
253
v
212
254
}
213
255
256
+ #[ cfg( target_arch = "aarch64" ) ]
214
257
#[ test]
215
- fn load_image ( ) {
258
+ fn load_arm64_image ( ) {
216
259
let gm = create_guest_mem ( ) ;
217
260
let mut image = make_image_bin ( ) ;
218
261
let kernel_addr = GuestAddress ( 0x200000 ) ;
@@ -237,4 +280,32 @@ mod tests {
237
280
Err ( KernelLoaderError :: Pe ( Error :: InvalidImageMagicNumber ) )
238
281
) ;
239
282
}
283
+
284
+ #[ cfg( target_arch = "riscv64" ) ]
285
+ #[ test]
286
+ fn load_riscv64_image ( ) {
287
+ let gm = create_guest_mem ( ) ;
288
+ let mut image = make_image_bin ( ) ;
289
+ let kernel_addr = GuestAddress ( 0x400000 ) ;
290
+
291
+ let loader_result =
292
+ PE :: load ( & gm, Some ( kernel_addr) , & mut Cursor :: new ( & image) , None ) . unwrap ( ) ;
293
+ assert_eq ! ( loader_result. kernel_load. raw_value( ) , 0x600000 ) ;
294
+ assert_eq ! ( loader_result. kernel_end, 0x601000 ) ;
295
+
296
+ // Attempt to load the kernel at an address that is not aligned to 2MB boundary
297
+ let kernel_offset = GuestAddress ( 0x0030_0000 ) ;
298
+ let loader_result = PE :: load ( & gm, Some ( kernel_offset) , & mut Cursor :: new ( & image) , None ) ;
299
+ assert_eq ! (
300
+ loader_result,
301
+ Err ( KernelLoaderError :: Pe ( Error :: InvalidBaseAddrAlignment ) )
302
+ ) ;
303
+
304
+ image[ 0x38 ] = 0x0 ;
305
+ let loader_result = PE :: load ( & gm, Some ( kernel_addr) , & mut Cursor :: new ( & image) , None ) ;
306
+ assert_eq ! (
307
+ loader_result,
308
+ Err ( KernelLoaderError :: Pe ( Error :: InvalidImageMagicNumber ) )
309
+ ) ;
310
+ }
240
311
}
0 commit comments