summary refs log tree commit diff
path: root/arch
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2019-05-17 10:55:45 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-05-20 15:47:23 -0700
commit3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47 (patch)
tree339cc27c92c02bb818f4d30550ba090ddd020e19 /arch
parentbe1ad40a0e698a0b6c483d0162cd80df6ce78ed8 (diff)
downloadcrosvm-3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47.tar
crosvm-3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47.tar.gz
crosvm-3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47.tar.bz2
crosvm-3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47.tar.lz
crosvm-3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47.tar.xz
crosvm-3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47.tar.zst
crosvm-3007ff3cf408f9e6a2e0731a4fa7d6f8f65dfa47.zip
x86_64: load initrd at max address
This matches behavior of other bootloaders (grub2, iPXE), and the kernel
seems to be relying on this; decompression of the initrd fails if the
initrd is loaded right after the kernel as before, but succeeds if
loaded at the maximum address.

BUG=None
TEST=Boot Debian kernel + initrd on workstation

Change-Id: If7712efb05f55ef413a419dfe276ed3f68c335b7
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1616989
Tested-by: kokoro <noreply+kokoro@google.com>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/src/lib.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index b9791c8..433d89a 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -271,6 +271,7 @@ pub fn add_serial_devices(
 /// Errors for image loading.
 #[derive(Debug)]
 pub enum LoadImageError {
+    BadAlignment(u64),
     Seek(io::Error),
     ImageSizeTooLarge(u64),
     ReadToMemory(GuestMemoryError),
@@ -281,6 +282,7 @@ impl Display for LoadImageError {
         use self::LoadImageError::*;
 
         match self {
+            BadAlignment(a) => write!(f, "Alignment not a power of two: {}", a),
             Seek(e) => write!(f, "Seek failed: {}", e),
             ImageSizeTooLarge(size) => write!(f, "Image size too large: {}", size),
             ReadToMemory(e) => write!(f, "Reading image into memory failed: {}", e),
@@ -326,3 +328,54 @@ where
 
     Ok(size)
 }
+
+/// Load an image from a file into guest memory at the highest possible address.
+///
+/// # Arguments
+///
+/// * `guest_mem` - The memory to be used by the guest.
+/// * `image` - The file containing the image to be loaded.
+/// * `min_guest_addr` - The minimum address of the start of the image.
+/// * `max_guest_addr` - The address to load the last byte of the image.
+/// * `align` - The minimum alignment of the start address of the image in bytes
+///   (must be a power of two).
+///
+/// The guest address and size in bytes of the loaded image are returned.
+pub fn load_image_high<F>(
+    guest_mem: &GuestMemory,
+    image: &mut F,
+    min_guest_addr: GuestAddress,
+    max_guest_addr: GuestAddress,
+    align: u64,
+) -> Result<(GuestAddress, usize), LoadImageError>
+where
+    F: Read + Seek,
+{
+    if !align.is_power_of_two() {
+        return Err(LoadImageError::BadAlignment(align));
+    }
+
+    let max_size = max_guest_addr.offset_from(min_guest_addr) & !(align - 1);
+    let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
+
+    if size > usize::max_value() as u64 || size > max_size {
+        return Err(LoadImageError::ImageSizeTooLarge(size));
+    }
+
+    image
+        .seek(SeekFrom::Start(0))
+        .map_err(LoadImageError::Seek)?;
+
+    // Load image at the maximum aligned address allowed.
+    // The subtraction cannot underflow because of the size checks above.
+    let guest_addr = GuestAddress((max_guest_addr.offset() - size) & !(align - 1));
+
+    // This is safe due to the bounds check above.
+    let size = size as usize;
+
+    guest_mem
+        .read_to_memory(guest_addr, image, size)
+        .map_err(LoadImageError::ReadToMemory)?;
+
+    Ok((guest_addr, size))
+}