1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Loader for bzImage-format Linux kernels as described in
6 // https://www.kernel.org/doc/Documentation/x86/boot.txt
7
8 use std::io::{Read, Seek, SeekFrom};
9
10 use base::AsRawDescriptor;
11 use data_model::DataInit;
12 use remain::sorted;
13 use thiserror::Error;
14 use vm_memory::{GuestAddress, GuestMemory};
15
16 use crate::bootparam::boot_params;
17
18 #[sorted]
19 #[derive(Error, Debug, PartialEq)]
20 pub enum Error {
21 #[error("bad kernel header signature")]
22 BadSignature,
23 #[error("invalid setup_sects value")]
24 InvalidSetupSects,
25 #[error("invalid syssize value")]
26 InvalidSysSize,
27 #[error("unable to read boot_params")]
28 ReadBootParams,
29 #[error("unable to read kernel image")]
30 ReadKernelImage,
31 #[error("unable to seek to boot_params")]
32 SeekBootParams,
33 #[error("unable to seek to kernel start")]
34 SeekKernelStart,
35 }
36
37 pub type Result<T> = std::result::Result<T, Error>;
38
39 /// Loads a kernel from a bzImage to a slice
40 ///
41 /// # Arguments
42 ///
43 /// * `guest_mem` - The guest memory region the kernel is written to.
44 /// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
45 /// * `kernel_image` - Input bzImage.
load_bzimage<F>( guest_mem: &GuestMemory, kernel_start: GuestAddress, mut kernel_image: &mut F, ) -> Result<(boot_params, u64)> where F: Read + Seek + AsRawDescriptor,46 pub fn load_bzimage<F>(
47 guest_mem: &GuestMemory,
48 kernel_start: GuestAddress,
49 mut kernel_image: &mut F,
50 ) -> Result<(boot_params, u64)>
51 where
52 F: Read + Seek + AsRawDescriptor,
53 {
54 kernel_image
55 .seek(SeekFrom::Start(0))
56 .map_err(|_| Error::SeekBootParams)?;
57 let params = boot_params::from_reader(&mut kernel_image).map_err(|_| Error::ReadBootParams)?;
58
59 // bzImage header signature "HdrS"
60 if params.hdr.header != 0x53726448 {
61 return Err(Error::BadSignature);
62 }
63
64 let setup_sects = if params.hdr.setup_sects == 0 {
65 4u64
66 } else {
67 params.hdr.setup_sects as u64
68 };
69
70 let kernel_offset = setup_sects
71 .checked_add(1)
72 .ok_or(Error::InvalidSetupSects)?
73 .checked_mul(512)
74 .ok_or(Error::InvalidSetupSects)?;
75 let kernel_size = (params.hdr.syssize as usize)
76 .checked_mul(16)
77 .ok_or(Error::InvalidSysSize)?;
78
79 kernel_image
80 .seek(SeekFrom::Start(kernel_offset))
81 .map_err(|_| Error::SeekKernelStart)?;
82
83 // Load the whole kernel image to kernel_start
84 guest_mem
85 .read_to_memory(kernel_start, kernel_image, kernel_size)
86 .map_err(|_| Error::ReadKernelImage)?;
87
88 Ok((params, kernel_start.offset() + kernel_size as u64))
89 }
90