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
+ //! - [Arm64Pe](struct.Arm64Pe.html): arm64_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" ) ) ]
23
+ #[ cfg( any( feature = "elf" , feature = "bzimage" , feature = "arm64_pe" ) ) ]
24
+ #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" , target_arch = "aarch64" ) ) ]
24
25
use std:: io:: SeekFrom ;
25
26
use std:: io:: { Read , Seek } ;
26
- #[ cfg( feature = "elf" ) ]
27
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
27
+ #[ cfg( any ( feature = "elf" , feature = "bzimage" , feature = "arm64_pe" ) ) ]
28
+ #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" , target_arch = "aarch64" ) ) ]
28
29
use std:: mem;
29
30
30
31
use vm_memory:: { Address , Bytes , GuestAddress , GuestMemory , GuestUsize } ;
@@ -42,8 +43,6 @@ pub mod bootparam;
42
43
#[ allow( non_upper_case_globals) ]
43
44
#[ cfg_attr( feature = "cargo-clippy" , allow( clippy:: all) ) ]
44
45
mod elf;
45
- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
46
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
47
46
mod struct_util;
48
47
49
48
#[ derive( Debug , PartialEq ) ]
@@ -81,6 +80,10 @@ pub enum Error {
81
80
ReadBzImageHeader ,
82
81
/// Unable to read bzImage compressed image.
83
82
ReadBzImageCompressedKernel ,
83
+ /// Unable to read image magic number.
84
+ ReadImageMagicNumber ,
85
+ /// Unable to read entry address.
86
+ ReadEntryAddress ,
84
87
/// Unable to seek to kernel start.
85
88
SeekKernelStart ,
86
89
/// Unable to seek to ELF start.
@@ -93,6 +96,14 @@ pub enum Error {
93
96
SeekBzImageHeader ,
94
97
/// Unable to seek to bzImage compressed kernel.
95
98
SeekBzImageCompressedKernel ,
99
+ /// Unable to seek to image start.
100
+ SeekImageStart ,
101
+ /// Unable to seek to image end.
102
+ SeekImageEnd ,
103
+ /// Unable to seek to magic image number.
104
+ SeekImageMagicNumber ,
105
+ /// Unable to seek to entry address.
106
+ SeekEntryAddress ,
96
107
}
97
108
98
109
/// A specialized `Result` type for the kernel loader.
@@ -119,12 +130,18 @@ impl error::Error for Error {
119
130
Error :: ReadProgramHeader => "Unable to read program header" ,
120
131
Error :: ReadBzImageHeader => "Unable to read bzImage header" ,
121
132
Error :: ReadBzImageCompressedKernel => "Unable to read bzImage compressed kernel" ,
133
+ Error :: ReadImageMagicNumber => "Unable to read image magic number" ,
134
+ Error :: ReadEntryAddress => "Unable to read entry address" ,
122
135
Error :: SeekKernelStart => "Unable to seek to kernel start" ,
123
136
Error :: SeekElfStart => "Unable to seek to elf start" ,
124
137
Error :: SeekProgramHeader => "Unable to seek to program header" ,
125
138
Error :: SeekBzImageEnd => "Unable to seek bzImage end" ,
126
139
Error :: SeekBzImageHeader => "Unable to seek bzImage header" ,
127
140
Error :: SeekBzImageCompressedKernel => "Unable to seek bzImage compressed kernel" ,
141
+ Error :: SeekImageStart => "Unable to seek to image start" ,
142
+ Error :: SeekImageEnd => "Unable to seek to image end" ,
143
+ Error :: SeekImageMagicNumber => "Unable to seek to magic image number" ,
144
+ Error :: SeekEntryAddress => "Unable to seek to entry address" ,
128
145
}
129
146
}
130
147
}
@@ -378,6 +395,117 @@ impl KernelLoader for BzImage {
378
395
}
379
396
}
380
397
398
+ #[ cfg( feature = "arm64_pe" ) ]
399
+ #[ cfg( target_arch = "aarch64" ) ]
400
+ /// Aarch64 kernel image support.
401
+ pub struct Arm64Pe ;
402
+
403
+ #[ cfg( feature = "arm64_pe" ) ]
404
+ #[ cfg( target_arch = "aarch64" ) ]
405
+ impl KernelLoader for Arm64Pe {
406
+ /// Loads a Aarch64 kernel image
407
+ ///
408
+ /// Aarch64 kernel boot protocol is specified in the kernel docs
409
+ /// Documentation/arm/Booting and Documentation/arm64/booting.txt.
410
+ ///
411
+ /// ======aarch64 kernel header========
412
+ /// u32 code0; /* Executable code */
413
+ /// u32 code1; /* Executable code */
414
+ /// u64 text_offset; /* Image load offset, little endian */
415
+ /// u64 image_size; /* Effective Image size, little endian */
416
+ /// u64 flags; /* kernel flags, little endian */
417
+ /// u64 res2 = 0; /* reserved */
418
+ /// u64 res3 = 0; /* reserved */
419
+ /// u64 res4 = 0; /* reserved */
420
+ /// u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
421
+ /// u32 res5; /* reserved (used for PE COFF offset) */
422
+ /// ====================================
423
+ ///
424
+ /// # Arguments
425
+ ///
426
+ /// * `guest_mem` - The guest memory region the kernel is written to.
427
+ /// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
428
+ /// * `kernel_image` - Input vmlinux image.
429
+ /// * `highmem_start_address` - This is the start of the high memory, kernel should above it.
430
+ ///
431
+ /// # Returns
432
+ /// * KernelLoaderResult
433
+ fn load < F , M : GuestMemory > (
434
+ guest_mem : & M ,
435
+ kernel_start : Option < GuestAddress > ,
436
+ kernel_image : & mut F ,
437
+ _highmem_start_address : Option < GuestAddress > ,
438
+ ) -> Result < KernelLoaderResult >
439
+ where
440
+ F : Read + Seek ,
441
+ {
442
+ const AARCH64_KERNEL_LOAD_ADDR : usize = 0x80000 ;
443
+ const AARCH64_MAGIC_NUMBER : u32 = 0x644d_5241 ;
444
+ const AARCH64_MAGIC_OFFSET : u64 =
445
+ 2 * mem:: size_of :: < u32 > ( ) as u64 + 6 * mem:: size_of :: < u64 > ( ) as u64 ; // This should total 56.
446
+ const AARCH64_TEXT_OFFSET : u64 = 2 * mem:: size_of :: < u32 > ( ) as u64 ;
447
+ let mut kernel_load_offset = AARCH64_KERNEL_LOAD_ADDR ;
448
+
449
+ /* Look for the magic number inside the elf header. */
450
+ kernel_image
451
+ . seek ( SeekFrom :: Start ( AARCH64_MAGIC_OFFSET ) )
452
+ . map_err ( |_| Error :: SeekImageMagicNumber ) ?;
453
+ let mut magic_number: u32 = 0 ;
454
+ unsafe {
455
+ struct_util:: read_struct ( kernel_image, & mut magic_number)
456
+ . map_err ( |_| Error :: ReadImageMagicNumber ) ?
457
+ }
458
+ if u32:: from_le ( magic_number) != AARCH64_MAGIC_NUMBER {
459
+ return Err ( Error :: InvalidElfMagicNumber ) ;
460
+ }
461
+
462
+ /* Look for the `text_offset` from the elf header. */
463
+ kernel_image
464
+ . seek ( SeekFrom :: Start ( AARCH64_TEXT_OFFSET ) ) // This should total 8.
465
+ . map_err ( |_| Error :: SeekEntryAddress ) ?;
466
+ let mut hdrvals: [ u64 ; 2 ] = [ 0 ; 2 ] ;
467
+ unsafe {
468
+ struct_util:: read_struct ( kernel_image, & mut hdrvals)
469
+ . map_err ( |_| Error :: ReadEntryAddress ) ?;
470
+ }
471
+ /* Following the boot protocol mentioned above. */
472
+ if u64:: from_le ( hdrvals[ 1 ] ) != 0 {
473
+ kernel_load_offset = u64:: from_le ( hdrvals[ 0 ] ) as usize ;
474
+ }
475
+ /* Get the total size of kernel image. */
476
+ let kernel_size = kernel_image
477
+ . seek ( SeekFrom :: End ( 0 ) )
478
+ . map_err ( |_| Error :: SeekImageEnd ) ?;
479
+
480
+ /* Last `seek` will leave the image with the cursor at its end, rewind it to start. */
481
+ kernel_image
482
+ . seek ( SeekFrom :: Start ( 0 ) )
483
+ . map_err ( |_| Error :: SeekImageStart ) ?;
484
+
485
+ let mut loader_result: KernelLoaderResult = Default :: default ( ) ;
486
+ // where the kernel will be start loaded.
487
+ let mem_offset = match kernel_start {
488
+ Some ( start) => GuestAddress ( start. raw_value ( ) + ( kernel_load_offset as u64 ) ) ,
489
+ None => GuestAddress ( kernel_load_offset as u64 ) ,
490
+ } ;
491
+
492
+ loader_result. kernel_load = mem_offset;
493
+
494
+ guest_mem
495
+ . read_exact_from ( mem_offset, kernel_image, kernel_size as usize )
496
+ . map_err ( |_| Error :: ReadKernelImage ) ?;
497
+
498
+ loader_result. kernel_end = mem_offset
499
+ . raw_value ( )
500
+ . checked_add ( kernel_size as GuestUsize )
501
+ . ok_or ( Error :: MemoryOverflow ) ?;
502
+
503
+ loader_result. setup_header = None ;
504
+
505
+ Ok ( loader_result)
506
+ }
507
+ }
508
+
381
509
/// Writes the command line string to the given memory slice.
382
510
///
383
511
/// # Arguments
@@ -412,8 +540,6 @@ pub fn load_cmdline<M: GuestMemory>(
412
540
#[ cfg( test) ]
413
541
mod test {
414
542
use super :: * ;
415
- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
416
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
417
543
use std:: io:: Cursor ;
418
544
use vm_memory:: { Address , GuestAddress , GuestMemoryMmap } ;
419
545
@@ -440,6 +566,15 @@ mod test {
440
566
v
441
567
}
442
568
569
+ // Aarch64 image.
570
+ #[ cfg( feature = "arm64_pe" ) ]
571
+ #[ cfg( target_arch = "aarch64" ) ]
572
+ fn make_aarch64_bin ( ) -> Vec < u8 > {
573
+ let mut v = Vec :: new ( ) ;
574
+ v. extend_from_slice ( include_bytes ! ( "test_arm64_pe.bin" ) ) ;
575
+ v
576
+ }
577
+
443
578
#[ allow( safe_packed_borrows) ]
444
579
#[ allow( non_snake_case) ]
445
580
#[ test]
@@ -562,6 +697,29 @@ mod test {
562
697
) ;
563
698
}
564
699
700
+ // Aarch64 image.
701
+ #[ cfg( feature = "arm64_pe" ) ]
702
+ #[ cfg( target_arch = "aarch64" ) ]
703
+ #[ test]
704
+ fn load_aarch64 ( ) {
705
+ const TEST_IMAGE_KERNEL_OFFSET : u64 = 0x8_0000 ; // test binary specific
706
+ const TEST_IMAGE_KERNEL_SIZE : u64 = 0x50 ; // test binary specific
707
+ let gm = create_guest_mem ( ) ;
708
+ let image = make_aarch64_bin ( ) ;
709
+ let kernel_addr = GuestAddress ( 0x80000 ) ;
710
+
711
+ assert_eq ! (
712
+ Ok ( KernelLoaderResult {
713
+ kernel_load: GuestAddress ( kernel_addr. raw_value( ) + TEST_IMAGE_KERNEL_OFFSET ) ,
714
+ kernel_end: ( kernel_addr. raw_value( )
715
+ + TEST_IMAGE_KERNEL_OFFSET
716
+ + TEST_IMAGE_KERNEL_SIZE ) as u64 ,
717
+ setup_header: None
718
+ } ) ,
719
+ Arm64Pe :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & image) , None )
720
+ ) ;
721
+ }
722
+
565
723
#[ test]
566
724
fn cmdline_overflow ( ) {
567
725
let gm = create_guest_mem ( ) ;
@@ -618,6 +776,21 @@ mod test {
618
776
) ;
619
777
}
620
778
779
+ #[ cfg( feature = "arm64_pe" ) ]
780
+ #[ cfg( target_arch = "aarch64" ) ]
781
+ #[ test]
782
+ fn bad_magic ( ) {
783
+ let gm = create_guest_mem ( ) ;
784
+ let kernel_addr = GuestAddress ( 0x0 ) ;
785
+ let mut bad_image = make_aarch64_bin ( ) ;
786
+ bad_image[ 0x38 ] = 0x33 ;
787
+
788
+ assert_eq ! (
789
+ Err ( Error :: InvalidElfMagicNumber ) ,
790
+ Arm64Pe :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & bad_image) , None )
791
+ ) ;
792
+ }
793
+
621
794
#[ cfg( feature = "elf" ) ]
622
795
#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
623
796
#[ test]
0 commit comments