1212//! - [KernelLoaderResult](struct.KernelLoaderResult.html): the structure which loader
1313//! returns to VMM to assist zero page construction and boot environment setup
1414//! - [Elf](struct.Elf.html): elf image loader
15+ //! - [Arm64Pe](struct.Arm64Pe.html): arm64_pe image loader
1516//! - [BzImage](struct.BzImage.html): bzImage loader
1617
1718extern crate vm_memory;
1819
1920use std:: error:: { self , Error as KernelLoaderError } ;
2021use std:: ffi:: CStr ;
2122use 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" ) ) ]
2425use std:: io:: SeekFrom ;
2526use 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" ) ) ]
2829use std:: mem;
2930
3031use vm_memory:: { Address , Bytes , GuestAddress , GuestMemory , GuestUsize } ;
@@ -42,8 +43,6 @@ pub mod bootparam;
4243#[ allow( non_upper_case_globals) ]
4344#[ cfg_attr( feature = "cargo-clippy" , allow( clippy:: all) ) ]
4445mod elf;
45- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
46- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
4746mod struct_util;
4847
4948#[ derive( Debug , PartialEq ) ]
@@ -81,6 +80,10 @@ pub enum Error {
8180 ReadBzImageHeader ,
8281 /// Unable to read bzImage compressed image.
8382 ReadBzImageCompressedKernel ,
83+ /// Unable to read image magic number.
84+ ReadImageMagicNumber ,
85+ /// Unable to read entry address.
86+ ReadEntryAddress ,
8487 /// Unable to seek to kernel start.
8588 SeekKernelStart ,
8689 /// Unable to seek to ELF start.
@@ -93,6 +96,14 @@ pub enum Error {
9396 SeekBzImageHeader ,
9497 /// Unable to seek to bzImage compressed kernel.
9598 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 ,
96107}
97108
98109/// A specialized `Result` type for the kernel loader.
@@ -119,12 +130,18 @@ impl error::Error for Error {
119130 Error :: ReadProgramHeader => "Unable to read program header" ,
120131 Error :: ReadBzImageHeader => "Unable to read bzImage header" ,
121132 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" ,
122135 Error :: SeekKernelStart => "Unable to seek to kernel start" ,
123136 Error :: SeekElfStart => "Unable to seek to elf start" ,
124137 Error :: SeekProgramHeader => "Unable to seek to program header" ,
125138 Error :: SeekBzImageEnd => "Unable to seek bzImage end" ,
126139 Error :: SeekBzImageHeader => "Unable to seek bzImage header" ,
127140 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" ,
128145 }
129146 }
130147}
@@ -378,6 +395,117 @@ impl KernelLoader for BzImage {
378395 }
379396}
380397
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+
381509/// Writes the command line string to the given memory slice.
382510///
383511/// # Arguments
@@ -412,8 +540,6 @@ pub fn load_cmdline<M: GuestMemory>(
412540#[ cfg( test) ]
413541mod test {
414542 use super :: * ;
415- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
416- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
417543 use std:: io:: Cursor ;
418544 use vm_memory:: { Address , GuestAddress , GuestMemoryMmap } ;
419545
@@ -440,6 +566,15 @@ mod test {
440566 v
441567 }
442568
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+
443578 #[ allow( safe_packed_borrows) ]
444579 #[ allow( non_snake_case) ]
445580 #[ test]
@@ -562,6 +697,29 @@ mod test {
562697 ) ;
563698 }
564699
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+
565723 #[ test]
566724 fn cmdline_overflow ( ) {
567725 let gm = create_guest_mem ( ) ;
@@ -618,6 +776,21 @@ mod test {
618776 ) ;
619777 }
620778
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+
621794 #[ cfg( feature = "elf" ) ]
622795 #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
623796 #[ test]
0 commit comments