mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 18:20:34 +00:00
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>
This commit is contained in:
parent
be1ad40a0e
commit
3007ff3cf4
2 changed files with 69 additions and 6 deletions
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -458,16 +458,26 @@ impl X8664arch {
|
|||
|
||||
let initrd = match initrd_file {
|
||||
Some(mut initrd_file) => {
|
||||
let initrd_start = free_addr;
|
||||
let initrd_max_size = mem_size - initrd_start;
|
||||
let initrd_size = arch::load_image(
|
||||
let mut initrd_addr_max = u64::from(params.hdr.initrd_addr_max);
|
||||
// Default initrd_addr_max for old kernels (see Documentation/x86/boot.txt).
|
||||
if initrd_addr_max == 0 {
|
||||
initrd_addr_max = 0x37FFFFFF;
|
||||
}
|
||||
|
||||
let mem_max = mem.end_addr().offset() - 1;
|
||||
if initrd_addr_max > mem_max {
|
||||
initrd_addr_max = mem_max;
|
||||
}
|
||||
|
||||
let (initrd_start, initrd_size) = arch::load_image_high(
|
||||
mem,
|
||||
&mut initrd_file,
|
||||
GuestAddress(initrd_start),
|
||||
initrd_max_size,
|
||||
GuestAddress(free_addr),
|
||||
GuestAddress(initrd_addr_max),
|
||||
sys_util::pagesize() as u64,
|
||||
)
|
||||
.map_err(Error::LoadInitrd)?;
|
||||
Some((GuestAddress(initrd_start), initrd_size))
|
||||
Some((initrd_start, initrd_size))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue