diff --git a/docs/elfio_files/bad_align_writer.cpp b/docs/elfio_files/bad_align_writer.cpp index 80f965c2..0804c500 100644 --- a/docs/elfio_files/bad_align_writer.cpp +++ b/docs/elfio_files/bad_align_writer.cpp @@ -56,10 +56,10 @@ int main( void ) // Create a loadable segment segment* text_seg = writer.segments.add(); text_seg->set_type( PT_LOAD ); - text_seg->set_virtual_address( 0x400 ); - text_seg->set_physical_address( 0x400 ); + text_seg->set_virtual_address( 0x200000 ); + text_seg->set_physical_address( 0x200000 ); text_seg->set_flags( PF_X | PF_R ); - text_seg->set_align( 0x100 ); + text_seg->set_align( 0x200000 ); // Add code section into program segment text_seg->add_section_index( text_sec->get_index(), @@ -80,10 +80,10 @@ int main( void ) // Create a read/write segment segment* data_seg = writer.segments.add(); data_seg->set_type( PT_NOTE ); - data_seg->set_virtual_address( 0x8888048020 ); - data_seg->set_physical_address( 0x8888048020 ); + data_seg->set_virtual_address( 0x8888400000 ); + data_seg->set_physical_address( 0x888400000 ); data_seg->set_flags( PF_W | PF_R ); - data_seg->set_align( 13 ); + data_seg->set_align( 0x200000 ); // Add code section into program segment data_seg->add_section_index( data_sec->get_index(), @@ -103,7 +103,7 @@ int main( void ) // In this example, the code starts at the first address of the // 'text_seg' segment. Therefore, the start address is set // to be equal to the segment location - writer.set_entry( 0x400 ); + writer.set_entry( 0x200000 ); // Create ELF file writer.save( "test_bad_align.bin" ); diff --git a/docs/elfio_files/basic_elf.cpp b/docs/elfio_files/basic_elf.cpp index 35922cc3..9515a0d2 100644 --- a/docs/elfio_files/basic_elf.cpp +++ b/docs/elfio_files/basic_elf.cpp @@ -56,10 +56,10 @@ int main( void ) // Create a loadable segment segment* text_seg = writer.segments.add(); text_seg->set_type( PT_LOAD ); - text_seg->set_virtual_address( 0x400 ); - text_seg->set_physical_address( 0x0 ); + text_seg->set_virtual_address( 0x200000 ); + text_seg->set_physical_address( 0x200000 ); text_seg->set_flags( PF_X | PF_R ); - text_seg->set_align( 0x1 ); + text_seg->set_align( 0x200000 ); // Add code section into program segment text_seg->add_section_index( text_sec->get_index(), @@ -80,10 +80,10 @@ int main( void ) // Create a read/write segment segment* data_seg = writer.segments.add(); data_seg->set_type( PT_LOAD ); - data_seg->set_virtual_address( 0x0420 ); - data_seg->set_physical_address( 0x0420 ); + data_seg->set_virtual_address( 0x400000 ); + data_seg->set_physical_address( 0x400000 ); data_seg->set_flags( PF_W | PF_R ); - data_seg->set_align( 0x10 ); + data_seg->set_align( 0x200000 ); // Add code section into program segment data_seg->add_section_index( data_sec->get_index(), @@ -103,7 +103,7 @@ int main( void ) // In this example, the code starts at the first address of the // 'text_seg' segment. Therefore, the start address is set // to be equal to the segment location - writer.set_entry( 0x400 ); + writer.set_entry( 0x200000 ); // Create ELF file writer.save( "test_elf.bin" ); diff --git a/src/loader/elf/mod.rs b/src/loader/elf/mod.rs index ddf8c6fa..a7b8b9f9 100644 --- a/src/loader/elf/mod.rs +++ b/src/loader/elf/mod.rs @@ -159,6 +159,9 @@ impl Elf { } } +// x86-64 kernel must be aligned to 2MB. +const KERNEL_SEGMENT_ALIGN: u64 = 0x200000; // 2 MiB + impl KernelLoader for Elf { /// Loads a kernel from a vmlinux elf image into guest memory. /// @@ -280,6 +283,12 @@ impl KernelLoader for Elf { None => GuestAddress(phdr.p_paddr), }; + // Ensure that mem_offset is aligned to 2M, otherwise, the kernel may hang during + // booting. Refer to the check in __startup_64() in the Linux kernel source code. + if mem_offset.raw_value() & (KERNEL_SEGMENT_ALIGN - 1) != 0 { + return Err(Error::Align.into()); + } + guest_mem .read_exact_volatile_from(mem_offset, kernel_image, phdr.p_filesz as usize) .map_err(|_| Error::ReadKernelImage)?; @@ -479,10 +488,10 @@ mod tests { Some(highmem_start_address), ) .unwrap(); - assert_eq!(loader_result.kernel_load.raw_value(), 0x200400); + assert_eq!(loader_result.kernel_load.raw_value(), 0x400000); loader_result = Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&image), None).unwrap(); - assert_eq!(loader_result.kernel_load.raw_value(), 0x200400); + assert_eq!(loader_result.kernel_load.raw_value(), 0x400000); loader_result = Elf::load( &gm, @@ -491,7 +500,7 @@ mod tests { Some(highmem_start_address), ) .unwrap(); - assert_eq!(loader_result.kernel_load.raw_value(), 0x400); + assert_eq!(loader_result.kernel_load.raw_value(), 0x200000); highmem_start_address = GuestAddress(0xa00000); assert_eq!( @@ -632,4 +641,20 @@ mod tests { .err() ); } + + #[test] + fn test_unaligned_loadaddr() { + let gm = create_guest_mem(); + let image = make_elf_bin(); + assert_eq!( + Some(KernelLoaderError::Elf(Error::Align)), + Elf::load( + &gm, + Some(GuestAddress(0x1000)), + &mut Cursor::new(&image), + None + ) + .err() + ); + } } diff --git a/src/loader/elf/test_bad_align.bin b/src/loader/elf/test_bad_align.bin index 2fbcc682..1dae1a43 100644 Binary files a/src/loader/elf/test_bad_align.bin and b/src/loader/elf/test_bad_align.bin differ diff --git a/src/loader/elf/test_elf.bin b/src/loader/elf/test_elf.bin index 08fe05c5..7b06074c 100644 Binary files a/src/loader/elf/test_elf.bin and b/src/loader/elf/test_elf.bin differ