12
12
//! - [KernelLoaderResult](struct.KernelLoaderResult.html): the structure which loader
13
13
//! returns to VMM to assist zero page construction and boot environment setup
14
14
//! - [Elf](struct.Elf.html): elf image loader
15
+ //! - [Aarch64Pe](struct.Aarch64Pe.html): aarch64_pe image loader
15
16
//! - [BzImage](struct.BzImage.html): bzImage loader
16
17
17
18
extern crate vm_memory;
18
19
19
20
use std:: error:: { self , Error as KernelLoaderError } ;
20
21
use std:: ffi:: CStr ;
21
22
use std:: fmt:: { self , Display } ;
22
- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
23
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
24
23
use std:: io:: SeekFrom ;
25
24
use std:: io:: { Read , Seek } ;
26
- #[ cfg( feature = "elf" ) ]
27
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
28
25
use std:: mem;
29
26
30
27
use vm_memory:: { Address , Bytes , GuestAddress , GuestMemory , GuestUsize } ;
@@ -42,8 +39,6 @@ pub mod bootparam;
42
39
#[ allow( non_upper_case_globals) ]
43
40
#[ cfg_attr( feature = "cargo-clippy" , allow( clippy:: all) ) ]
44
41
mod elf;
45
- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
46
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
47
42
mod struct_util;
48
43
49
44
#[ derive( Debug , PartialEq ) ]
@@ -55,8 +50,8 @@ pub enum Error {
55
50
CommandLineCopy ,
56
51
/// Command line overflowed guest memory.
57
52
CommandLineOverflow ,
58
- /// Invalid ELF magic number
59
- InvalidElfMagicNumber ,
53
+ /// Invalid magic number
54
+ InvalidMagicNumber ,
60
55
/// Invalid program header size.
61
56
InvalidProgramHeaderSize ,
62
57
/// Invalid program header offset.
@@ -67,6 +62,8 @@ pub enum Error {
67
62
InvalidEntryAddress ,
68
63
/// Invalid bzImage binary.
69
64
InvalidBzImage ,
65
+ /// Invalid PE image binary.
66
+ InvalidPeImage ,
70
67
/// Invalid kernel start address.
71
68
InvalidKernelStartAddress ,
72
69
/// Memory to load kernel image is too small.
@@ -93,6 +90,14 @@ pub enum Error {
93
90
SeekBzImageHeader ,
94
91
/// Unable to seek to bzImage compressed kernel.
95
92
SeekBzImageCompressedKernel ,
93
+ /// Unable to seek to image start.
94
+ SeekImageStart ,
95
+ /// Unable to seek to image end.
96
+ SeekImageEnd ,
97
+ /// Unable to seek to magic image number.
98
+ SeekImageMagicNumber ,
99
+ /// Unable to seek to entry address.
100
+ SeekEntryAddress ,
96
101
}
97
102
98
103
/// A specialized `Result` type for the kernel loader.
@@ -106,13 +111,14 @@ impl error::Error for Error {
106
111
}
107
112
Error :: CommandLineCopy => "Failed writing command line to guest memory" ,
108
113
Error :: CommandLineOverflow => "Command line overflowed guest memory" ,
109
- Error :: InvalidElfMagicNumber => "Invalid Elf magic number" ,
114
+ Error :: InvalidMagicNumber => "Invalid magic number" ,
110
115
Error :: InvalidProgramHeaderSize => "Invalid program header size" ,
111
116
Error :: InvalidProgramHeaderOffset => "Invalid program header offset" ,
112
117
Error :: InvalidProgramHeaderAddress => "Invalid Program Header Address" ,
113
118
Error :: InvalidEntryAddress => "Invalid entry address" ,
114
119
Error :: InvalidBzImage => "Invalid bzImage" ,
115
120
Error :: InvalidKernelStartAddress => "Invalid kernel start address" ,
121
+ Error :: InvalidPeImage => "Invalid PE image" ,
116
122
Error :: MemoryOverflow => "Memory to load kernel image is not enough" ,
117
123
Error :: ReadElfHeader => "Unable to read elf header" ,
118
124
Error :: ReadKernelImage => "Unable to read kernel image" ,
@@ -125,6 +131,10 @@ impl error::Error for Error {
125
131
Error :: SeekBzImageEnd => "Unable to seek bzImage end" ,
126
132
Error :: SeekBzImageHeader => "Unable to seek bzImage header" ,
127
133
Error :: SeekBzImageCompressedKernel => "Unable to seek bzImage compressed kernel" ,
134
+ Error :: SeekImageStart => "Unable to seek to image start" ,
135
+ Error :: SeekImageEnd => "Unable to seek to image end" ,
136
+ Error :: SeekImageMagicNumber => "Unable to seek to magic image number" ,
137
+ Error :: SeekEntryAddress => "Unable to seek to entry address" ,
128
138
}
129
139
}
130
140
}
@@ -184,9 +194,6 @@ impl KernelLoader for Elf {
184
194
/// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
185
195
/// * `kernel_image` - Input vmlinux image.
186
196
/// * `highmem_start_address` - This is the start of the high memory, kernel should above it.
187
- ///
188
- /// # Returns
189
- /// * KernelLoaderResult
190
197
fn load < F , M : GuestMemory > (
191
198
guest_mem : & M ,
192
199
kernel_start : Option < GuestAddress > ,
@@ -211,7 +218,7 @@ impl KernelLoader for Elf {
211
218
|| ehdr. e_ident [ elf:: EI_MAG2 as usize ] != elf:: ELFMAG2
212
219
|| ehdr. e_ident [ elf:: EI_MAG3 as usize ] != elf:: ELFMAG3
213
220
{
214
- return Err ( Error :: InvalidElfMagicNumber ) ;
221
+ return Err ( Error :: InvalidMagicNumber ) ;
215
222
}
216
223
if ehdr. e_ident [ elf:: EI_DATA as usize ] != elf:: ELFDATA2LSB as u8 {
217
224
return Err ( Error :: BigEndianElfOnLittle ) ;
@@ -299,9 +306,6 @@ impl KernelLoader for BzImage {
299
306
/// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
300
307
/// * `kernel_image` - Input bzImage image.
301
308
/// * `highmem_start_address` - This is the start of the high memory, kernel should above it.
302
- ///
303
- /// # Returns
304
- /// * KernelLoaderResult
305
309
fn load < F , M : GuestMemory > (
306
310
guest_mem : & M ,
307
311
kernel_start : Option < GuestAddress > ,
@@ -378,6 +382,115 @@ impl KernelLoader for BzImage {
378
382
}
379
383
}
380
384
385
+ #[ cfg( all( feature = "aarch64_pe" , target_arch = "aarch64" ) ) ]
386
+ /// Aarch64 kernel image support.
387
+ pub struct Aarch64Pe ;
388
+
389
+ impl Aarch64Pe {
390
+ const AARCH64_KERNEL_LOAD_ADDR : usize = 0x80000 ;
391
+ const AARCH64_MAGIC_NUMBER : u32 = 0x644d_5241 ;
392
+ const AARCH64_MAGIC_OFFSET : u64 =
393
+ 2 * mem:: size_of :: < u32 > ( ) as u64 + 6 * mem:: size_of :: < u64 > ( ) as u64 ; // This should total 56.
394
+ const AARCH64_TEXT_OFFSET : u64 = 2 * mem:: size_of :: < u32 > ( ) as u64 ;
395
+ }
396
+
397
+ #[ cfg( all( feature = "aarch64_pe" , target_arch = "aarch64" ) ) ]
398
+ impl KernelLoader for Aarch64Pe {
399
+ /// Loads a Aarch64 kernel image
400
+ ///
401
+ /// Aarch64 kernel boot protocol is specified in the kernel docs
402
+ /// Documentation/arm/Booting and Documentation/arm64/booting.txt.
403
+ ///
404
+ /// ======aarch64 kernel header========
405
+ /// u32 code0; /* Executable code */
406
+ /// u32 code1; /* Executable code */
407
+ /// u64 text_offset; /* Image load offset, little endian */
408
+ /// u64 image_size; /* Effective Image size, little endian */
409
+ /// u64 flags; /* kernel flags, little endian */
410
+ /// u64 res2 = 0; /* reserved */
411
+ /// u64 res3 = 0; /* reserved */
412
+ /// u64 res4 = 0; /* reserved */
413
+ /// u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
414
+ /// u32 res5; /* reserved (used for PE COFF offset) */
415
+ /// ====================================
416
+ ///
417
+ /// # Arguments
418
+ ///
419
+ /// * `guest_mem` - The guest memory region the kernel is written to.
420
+ /// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
421
+ /// * `kernel_image` - Input vmlinux image.
422
+ /// * `highmem_start_address` - Start of the high memory, ignored on Aarch64.
423
+ fn load < F , M : GuestMemory > (
424
+ guest_mem : & M ,
425
+ kernel_start : Option < GuestAddress > ,
426
+ kernel_image : & mut F ,
427
+ _highmem_start_address : Option < GuestAddress > ,
428
+ ) -> Result < KernelLoaderResult >
429
+ where
430
+ F : Read + Seek ,
431
+ {
432
+ let mut kernel_load_offset = Aarch64Pe :: AARCH64_KERNEL_LOAD_ADDR ;
433
+
434
+ /* Look for the magic number inside the elf header. */
435
+ kernel_image
436
+ . seek ( SeekFrom :: Start ( Aarch64Pe :: AARCH64_MAGIC_OFFSET ) )
437
+ . map_err ( |_| Error :: SeekImageMagicNumber ) ?;
438
+ let mut magic_number: u32 = 0 ;
439
+ unsafe {
440
+ struct_util:: read_struct ( kernel_image, & mut magic_number)
441
+ . map_err ( |_| Error :: InvalidPeImage ) ?
442
+ }
443
+ if u32:: from_le ( magic_number) != Aarch64Pe :: AARCH64_MAGIC_NUMBER {
444
+ return Err ( Error :: InvalidMagicNumber ) ;
445
+ }
446
+
447
+ /* Look for the `text_offset` from the elf header. */
448
+ kernel_image
449
+ . seek ( SeekFrom :: Start ( Aarch64Pe :: AARCH64_TEXT_OFFSET ) ) // This should total 8.
450
+ . map_err ( |_| Error :: SeekEntryAddress ) ?;
451
+ let mut hdrvals: [ u64 ; 2 ] = [ 0 ; 2 ] ;
452
+ unsafe {
453
+ struct_util:: read_struct ( kernel_image, & mut hdrvals)
454
+ . map_err ( |_| Error :: InvalidPeImage ) ?;
455
+ }
456
+ /* Following the boot protocol mentioned above. */
457
+ if u64:: from_le ( hdrvals[ 1 ] ) != 0 {
458
+ kernel_load_offset = u64:: from_le ( hdrvals[ 0 ] ) as usize ;
459
+ }
460
+ /* Get the total size of kernel image. */
461
+ let kernel_size = kernel_image
462
+ . seek ( SeekFrom :: End ( 0 ) )
463
+ . map_err ( |_| Error :: SeekImageEnd ) ?;
464
+
465
+ /* Last `seek` will leave the image with the cursor at its end, rewind it to start. */
466
+ kernel_image
467
+ . seek ( SeekFrom :: Start ( 0 ) )
468
+ . map_err ( |_| Error :: SeekImageStart ) ?;
469
+
470
+ let mut loader_result: KernelLoaderResult = Default :: default ( ) ;
471
+ // where the kernel will be start loaded.
472
+ let mem_offset = match kernel_start {
473
+ Some ( start) => GuestAddress ( start. raw_value ( ) + ( kernel_load_offset as u64 ) ) ,
474
+ None => GuestAddress ( kernel_load_offset as u64 ) ,
475
+ } ;
476
+
477
+ loader_result. kernel_load = mem_offset;
478
+
479
+ guest_mem
480
+ . read_exact_from ( mem_offset, kernel_image, kernel_size as usize )
481
+ . map_err ( |_| Error :: ReadKernelImage ) ?;
482
+
483
+ loader_result. kernel_end = mem_offset
484
+ . raw_value ( )
485
+ . checked_add ( kernel_size as GuestUsize )
486
+ . ok_or ( Error :: MemoryOverflow ) ?;
487
+
488
+ loader_result. setup_header = None ;
489
+
490
+ Ok ( loader_result)
491
+ }
492
+ }
493
+
381
494
/// Writes the command line string to the given memory slice.
382
495
///
383
496
/// # Arguments
@@ -412,8 +525,6 @@ pub fn load_cmdline<M: GuestMemory>(
412
525
#[ cfg( test) ]
413
526
mod test {
414
527
use super :: * ;
415
- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
416
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
417
528
use std:: io:: Cursor ;
418
529
use vm_memory:: { Address , GuestAddress , GuestMemoryMmap } ;
419
530
@@ -440,6 +551,15 @@ mod test {
440
551
v
441
552
}
442
553
554
+ // Aarch64 image.
555
+ #[ cfg( feature = "aarch64_pe" ) ]
556
+ #[ cfg( target_arch = "aarch64" ) ]
557
+ fn make_aarch64_bin ( ) -> Vec < u8 > {
558
+ let mut v = Vec :: new ( ) ;
559
+ v. extend_from_slice ( include_bytes ! ( "test_pe.bin" ) ) ;
560
+ v
561
+ }
562
+
443
563
#[ allow( safe_packed_borrows) ]
444
564
#[ allow( non_snake_case) ]
445
565
#[ test]
@@ -562,6 +682,29 @@ mod test {
562
682
) ;
563
683
}
564
684
685
+ // Aarch64 image.
686
+ #[ cfg( feature = "aarch64_pe" ) ]
687
+ #[ cfg( target_arch = "aarch64" ) ]
688
+ #[ test]
689
+ fn load_aarch64 ( ) {
690
+ const TEST_IMAGE_KERNEL_OFFSET : u64 = 0x8_0000 ; // test binary specific
691
+ const TEST_IMAGE_KERNEL_SIZE : u64 = 0x50 ; // test binary specific
692
+ let gm = create_guest_mem ( ) ;
693
+ let image = make_aarch64_bin ( ) ;
694
+ let kernel_addr = GuestAddress ( 0x80000 ) ;
695
+
696
+ assert_eq ! (
697
+ Ok ( KernelLoaderResult {
698
+ kernel_load: GuestAddress ( kernel_addr. raw_value( ) + TEST_IMAGE_KERNEL_OFFSET ) ,
699
+ kernel_end: ( kernel_addr. raw_value( )
700
+ + TEST_IMAGE_KERNEL_OFFSET
701
+ + TEST_IMAGE_KERNEL_SIZE ) as u64 ,
702
+ setup_header: None
703
+ } ) ,
704
+ Aarch64Pe :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & image) , None )
705
+ ) ;
706
+ }
707
+
565
708
#[ test]
566
709
fn cmdline_overflow ( ) {
567
710
let gm = create_guest_mem ( ) ;
@@ -613,11 +756,26 @@ mod test {
613
756
let mut bad_image = make_elf_bin ( ) ;
614
757
bad_image[ 0x1 ] = 0x33 ;
615
758
assert_eq ! (
616
- Err ( Error :: InvalidElfMagicNumber ) ,
759
+ Err ( Error :: InvalidMagicNumber ) ,
617
760
Elf :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & bad_image) , None )
618
761
) ;
619
762
}
620
763
764
+ #[ cfg( feature = "aarch64_pe" ) ]
765
+ #[ cfg( target_arch = "aarch64" ) ]
766
+ #[ test]
767
+ fn bad_magic ( ) {
768
+ let gm = create_guest_mem ( ) ;
769
+ let kernel_addr = GuestAddress ( 0x0 ) ;
770
+ let mut bad_image = make_aarch64_bin ( ) ;
771
+ bad_image[ 0x38 ] = 0x33 ;
772
+
773
+ assert_eq ! (
774
+ Err ( Error :: InvalidMagicNumber ) ,
775
+ Aarch64Pe :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & bad_image) , None )
776
+ ) ;
777
+ }
778
+
621
779
#[ cfg( feature = "elf" ) ]
622
780
#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
623
781
#[ test]
0 commit comments