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.
1112
1213//! Traits and structs for loading pe image kernels into guest memory.
1314
14- #![ cfg( feature = "pe" ) ]
15-
1615use std:: fmt;
1716use 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) ]
155194mod 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 ! (
0 commit comments