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+ //! - [Aarch64Pe](struct.Aarch64Pe.html): aarch64_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" ) ) ]
2423use std:: io:: SeekFrom ;
2524use std:: io:: { Read , Seek } ;
26- #[ cfg( feature = "elf" ) ]
27- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
2825use std:: mem;
2926
3027use vm_memory:: { Address , Bytes , GuestAddress , GuestMemory , GuestUsize } ;
@@ -42,8 +39,6 @@ pub mod bootparam;
4239#[ allow( non_upper_case_globals) ]
4340#[ cfg_attr( feature = "cargo-clippy" , allow( clippy:: all) ) ]
4441mod elf;
45- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
46- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
4742mod struct_util;
4843
4944#[ derive( Debug , PartialEq ) ]
@@ -55,8 +50,8 @@ pub enum Error {
5550 CommandLineCopy ,
5651 /// Command line overflowed guest memory.
5752 CommandLineOverflow ,
58- /// Invalid ELF magic number
59- InvalidElfMagicNumber ,
53+ /// Invalid magic number
54+ InvalidMagicNumber ,
6055 /// Invalid program header size.
6156 InvalidProgramHeaderSize ,
6257 /// Invalid program header offset.
@@ -67,6 +62,8 @@ pub enum Error {
6762 InvalidEntryAddress ,
6863 /// Invalid bzImage binary.
6964 InvalidBzImage ,
65+ /// Invalid PE image binary.
66+ InvalidPeImage ,
7067 /// Invalid kernel start address.
7168 InvalidKernelStartAddress ,
7269 /// Memory to load kernel image is too small.
@@ -93,6 +90,14 @@ pub enum Error {
9390 SeekBzImageHeader ,
9491 /// Unable to seek to bzImage compressed kernel.
9592 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 ,
96101}
97102
98103/// A specialized `Result` type for the kernel loader.
@@ -106,13 +111,14 @@ impl error::Error for Error {
106111 }
107112 Error :: CommandLineCopy => "Failed writing command line to guest memory" ,
108113 Error :: CommandLineOverflow => "Command line overflowed guest memory" ,
109- Error :: InvalidElfMagicNumber => "Invalid Elf magic number" ,
114+ Error :: InvalidMagicNumber => "Invalid magic number" ,
110115 Error :: InvalidProgramHeaderSize => "Invalid program header size" ,
111116 Error :: InvalidProgramHeaderOffset => "Invalid program header offset" ,
112117 Error :: InvalidProgramHeaderAddress => "Invalid Program Header Address" ,
113118 Error :: InvalidEntryAddress => "Invalid entry address" ,
114119 Error :: InvalidBzImage => "Invalid bzImage" ,
115120 Error :: InvalidKernelStartAddress => "Invalid kernel start address" ,
121+ Error :: InvalidPeImage => "Invalid PE image" ,
116122 Error :: MemoryOverflow => "Memory to load kernel image is not enough" ,
117123 Error :: ReadElfHeader => "Unable to read elf header" ,
118124 Error :: ReadKernelImage => "Unable to read kernel image" ,
@@ -125,6 +131,10 @@ impl error::Error for Error {
125131 Error :: SeekBzImageEnd => "Unable to seek bzImage end" ,
126132 Error :: SeekBzImageHeader => "Unable to seek bzImage header" ,
127133 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" ,
128138 }
129139 }
130140}
@@ -184,9 +194,6 @@ impl KernelLoader for Elf {
184194 /// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
185195 /// * `kernel_image` - Input vmlinux image.
186196 /// * `highmem_start_address` - This is the start of the high memory, kernel should above it.
187- ///
188- /// # Returns
189- /// * KernelLoaderResult
190197 fn load < F , M : GuestMemory > (
191198 guest_mem : & M ,
192199 kernel_start : Option < GuestAddress > ,
@@ -211,7 +218,7 @@ impl KernelLoader for Elf {
211218 || ehdr. e_ident [ elf:: EI_MAG2 as usize ] != elf:: ELFMAG2
212219 || ehdr. e_ident [ elf:: EI_MAG3 as usize ] != elf:: ELFMAG3
213220 {
214- return Err ( Error :: InvalidElfMagicNumber ) ;
221+ return Err ( Error :: InvalidMagicNumber ) ;
215222 }
216223 if ehdr. e_ident [ elf:: EI_DATA as usize ] != elf:: ELFDATA2LSB as u8 {
217224 return Err ( Error :: BigEndianElfOnLittle ) ;
@@ -299,9 +306,6 @@ impl KernelLoader for BzImage {
299306 /// * `kernel_start` - The offset into 'guest_mem' at which to load the kernel.
300307 /// * `kernel_image` - Input bzImage image.
301308 /// * `highmem_start_address` - This is the start of the high memory, kernel should above it.
302- ///
303- /// # Returns
304- /// * KernelLoaderResult
305309 fn load < F , M : GuestMemory > (
306310 guest_mem : & M ,
307311 kernel_start : Option < GuestAddress > ,
@@ -378,6 +382,115 @@ impl KernelLoader for BzImage {
378382 }
379383}
380384
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+
381494/// Writes the command line string to the given memory slice.
382495///
383496/// # Arguments
@@ -412,8 +525,6 @@ pub fn load_cmdline<M: GuestMemory>(
412525#[ cfg( test) ]
413526mod test {
414527 use super :: * ;
415- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
416- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
417528 use std:: io:: Cursor ;
418529 use vm_memory:: { Address , GuestAddress , GuestMemoryMmap } ;
419530
@@ -440,6 +551,15 @@ mod test {
440551 v
441552 }
442553
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+
443563 #[ allow( safe_packed_borrows) ]
444564 #[ allow( non_snake_case) ]
445565 #[ test]
@@ -562,6 +682,29 @@ mod test {
562682 ) ;
563683 }
564684
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+
565708 #[ test]
566709 fn cmdline_overflow ( ) {
567710 let gm = create_guest_mem ( ) ;
@@ -613,11 +756,26 @@ mod test {
613756 let mut bad_image = make_elf_bin ( ) ;
614757 bad_image[ 0x1 ] = 0x33 ;
615758 assert_eq ! (
616- Err ( Error :: InvalidElfMagicNumber ) ,
759+ Err ( Error :: InvalidMagicNumber ) ,
617760 Elf :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & bad_image) , None )
618761 ) ;
619762 }
620763
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+
621779 #[ cfg( feature = "elf" ) ]
622780 #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
623781 #[ test]
0 commit comments