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,116 @@ 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+ #[ cfg( all( feature = "aarch64_pe" , target_arch = "aarch64" ) ) ]
390+ impl Aarch64Pe {
391+ const AARCH64_KERNEL_LOAD_ADDR : usize = 0x80000 ;
392+ const AARCH64_MAGIC_NUMBER : u32 = 0x644d_5241 ;
393+ const AARCH64_MAGIC_OFFSET : u64 =
394+ 2 * mem:: size_of :: < u32 > ( ) as u64 + 6 * mem:: size_of :: < u64 > ( ) as u64 ; // This should total 56.
395+ const AARCH64_TEXT_OFFSET : u64 = 2 * mem:: size_of :: < u32 > ( ) as u64 ;
396+ }
397+
398+ #[ cfg( all( feature = "aarch64_pe" , target_arch = "aarch64" ) ) ]
399+ impl KernelLoader for Aarch64Pe {
400+ /// Loads a Aarch64 kernel image
401+ ///
402+ /// Aarch64 kernel boot protocol is specified in the kernel docs
403+ /// Documentation/arm/Booting and Documentation/arm64/booting.txt.
404+ ///
405+ /// ======aarch64 kernel header========
406+ /// u32 code0; /* Executable code */
407+ /// u32 code1; /* Executable code */
408+ /// u64 text_offset; /* Image load offset, little endian */
409+ /// u64 image_size; /* Effective Image size, little endian */
410+ /// u64 flags; /* kernel flags, little endian */
411+ /// u64 res2 = 0; /* reserved */
412+ /// u64 res3 = 0; /* reserved */
413+ /// u64 res4 = 0; /* reserved */
414+ /// u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
415+ /// u32 res5; /* reserved (used for PE COFF offset) */
416+ /// ====================================
417+ ///
418+ /// # Arguments
419+ ///
420+ /// * `guest_mem` - The guest memory region the kernel is written to.
421+ /// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
422+ /// * `kernel_image` - Input vmlinux image.
423+ /// * `highmem_start_address` - Start of the high memory, ignored on Aarch64.
424+ fn load < F , M : GuestMemory > (
425+ guest_mem : & M ,
426+ kernel_start : Option < GuestAddress > ,
427+ kernel_image : & mut F ,
428+ _highmem_start_address : Option < GuestAddress > ,
429+ ) -> Result < KernelLoaderResult >
430+ where
431+ F : Read + Seek ,
432+ {
433+ let mut kernel_load_offset = Aarch64Pe :: AARCH64_KERNEL_LOAD_ADDR ;
434+
435+ /* Look for the magic number inside the elf header. */
436+ kernel_image
437+ . seek ( SeekFrom :: Start ( Aarch64Pe :: AARCH64_MAGIC_OFFSET ) )
438+ . map_err ( |_| Error :: SeekImageMagicNumber ) ?;
439+ let mut magic_number: u32 = 0 ;
440+ unsafe {
441+ struct_util:: read_struct ( kernel_image, & mut magic_number)
442+ . map_err ( |_| Error :: InvalidPeImage ) ?
443+ }
444+ if u32:: from_le ( magic_number) != Aarch64Pe :: AARCH64_MAGIC_NUMBER {
445+ return Err ( Error :: InvalidMagicNumber ) ;
446+ }
447+
448+ /* Look for the `text_offset` from the elf header. */
449+ kernel_image
450+ . seek ( SeekFrom :: Start ( Aarch64Pe :: AARCH64_TEXT_OFFSET ) ) // This should total 8.
451+ . map_err ( |_| Error :: SeekEntryAddress ) ?;
452+ let mut hdrvals: [ u64 ; 2 ] = [ 0 ; 2 ] ;
453+ unsafe {
454+ struct_util:: read_struct ( kernel_image, & mut hdrvals)
455+ . map_err ( |_| Error :: InvalidPeImage ) ?;
456+ }
457+ /* Following the boot protocol mentioned above. */
458+ if u64:: from_le ( hdrvals[ 1 ] ) != 0 {
459+ kernel_load_offset = u64:: from_le ( hdrvals[ 0 ] ) as usize ;
460+ }
461+ /* Get the total size of kernel image. */
462+ let kernel_size = kernel_image
463+ . seek ( SeekFrom :: End ( 0 ) )
464+ . map_err ( |_| Error :: SeekImageEnd ) ?;
465+
466+ /* Last `seek` will leave the image with the cursor at its end, rewind it to start. */
467+ kernel_image
468+ . seek ( SeekFrom :: Start ( 0 ) )
469+ . map_err ( |_| Error :: SeekImageStart ) ?;
470+
471+ let mut loader_result: KernelLoaderResult = Default :: default ( ) ;
472+ // where the kernel will be start loaded.
473+ let mem_offset = match kernel_start {
474+ Some ( start) => GuestAddress ( start. raw_value ( ) + ( kernel_load_offset as u64 ) ) ,
475+ None => GuestAddress ( kernel_load_offset as u64 ) ,
476+ } ;
477+
478+ loader_result. kernel_load = mem_offset;
479+
480+ guest_mem
481+ . read_exact_from ( mem_offset, kernel_image, kernel_size as usize )
482+ . map_err ( |_| Error :: ReadKernelImage ) ?;
483+
484+ loader_result. kernel_end = mem_offset
485+ . raw_value ( )
486+ . checked_add ( kernel_size as GuestUsize )
487+ . ok_or ( Error :: MemoryOverflow ) ?;
488+
489+ loader_result. setup_header = None ;
490+
491+ Ok ( loader_result)
492+ }
493+ }
494+
381495/// Writes the command line string to the given memory slice.
382496///
383497/// # Arguments
@@ -412,8 +526,6 @@ pub fn load_cmdline<M: GuestMemory>(
412526#[ cfg( test) ]
413527mod test {
414528 use super :: * ;
415- #[ cfg( any( feature = "elf" , feature = "bzimage" ) ) ]
416- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
417529 use std:: io:: Cursor ;
418530 use vm_memory:: { Address , GuestAddress , GuestMemoryMmap } ;
419531
@@ -440,6 +552,15 @@ mod test {
440552 v
441553 }
442554
555+ // Aarch64 image.
556+ #[ cfg( feature = "aarch64_pe" ) ]
557+ #[ cfg( target_arch = "aarch64" ) ]
558+ fn make_aarch64_bin ( ) -> Vec < u8 > {
559+ let mut v = Vec :: new ( ) ;
560+ v. extend_from_slice ( include_bytes ! ( "test_pe.bin" ) ) ;
561+ v
562+ }
563+
443564 #[ allow( safe_packed_borrows) ]
444565 #[ allow( non_snake_case) ]
445566 #[ test]
@@ -562,6 +683,29 @@ mod test {
562683 ) ;
563684 }
564685
686+ // Aarch64 image.
687+ #[ cfg( feature = "aarch64_pe" ) ]
688+ #[ cfg( target_arch = "aarch64" ) ]
689+ #[ test]
690+ fn load_aarch64 ( ) {
691+ const TEST_IMAGE_KERNEL_OFFSET : u64 = 0x8_0000 ; // test binary specific
692+ const TEST_IMAGE_KERNEL_SIZE : u64 = 0x50 ; // test binary specific
693+ let gm = create_guest_mem ( ) ;
694+ let image = make_aarch64_bin ( ) ;
695+ let kernel_addr = GuestAddress ( 0x80000 ) ;
696+
697+ assert_eq ! (
698+ Ok ( KernelLoaderResult {
699+ kernel_load: GuestAddress ( kernel_addr. raw_value( ) + TEST_IMAGE_KERNEL_OFFSET ) ,
700+ kernel_end: ( kernel_addr. raw_value( )
701+ + TEST_IMAGE_KERNEL_OFFSET
702+ + TEST_IMAGE_KERNEL_SIZE ) as u64 ,
703+ setup_header: None
704+ } ) ,
705+ Aarch64Pe :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & image) , None )
706+ ) ;
707+ }
708+
565709 #[ test]
566710 fn cmdline_overflow ( ) {
567711 let gm = create_guest_mem ( ) ;
@@ -613,11 +757,26 @@ mod test {
613757 let mut bad_image = make_elf_bin ( ) ;
614758 bad_image[ 0x1 ] = 0x33 ;
615759 assert_eq ! (
616- Err ( Error :: InvalidElfMagicNumber ) ,
760+ Err ( Error :: InvalidMagicNumber ) ,
617761 Elf :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & bad_image) , None )
618762 ) ;
619763 }
620764
765+ #[ cfg( feature = "aarch64_pe" ) ]
766+ #[ cfg( target_arch = "aarch64" ) ]
767+ #[ test]
768+ fn bad_magic ( ) {
769+ let gm = create_guest_mem ( ) ;
770+ let kernel_addr = GuestAddress ( 0x0 ) ;
771+ let mut bad_image = make_aarch64_bin ( ) ;
772+ bad_image[ 0x38 ] = 0x33 ;
773+
774+ assert_eq ! (
775+ Err ( Error :: InvalidMagicNumber ) ,
776+ Aarch64Pe :: load( & gm, Some ( kernel_addr) , & mut Cursor :: new( & bad_image) , None )
777+ ) ;
778+ }
779+
621780 #[ cfg( feature = "elf" ) ]
622781 #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
623782 #[ test]
0 commit comments