1 // Copyright 2019 The ChromiumOS Authors
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;
9 use std::io::Seek;
10 use std::io::SeekFrom;
11
12 use base::AsRawDescriptor;
13 use data_model::zerocopy_from_reader;
14 use remain::sorted;
15 use thiserror::Error;
16 use vm_memory::GuestAddress;
17 use vm_memory::GuestMemory;
18
19 use crate::bootparam::boot_params;
20
21 #[sorted]
22 #[derive(Error, Debug, PartialEq, Eq)]
23 pub enum Error {
24 #[error("bad kernel header signature")]
25 BadSignature,
26 #[error("invalid setup_sects value")]
27 InvalidSetupSects,
28 #[error("invalid syssize value")]
29 InvalidSysSize,
30 #[error("unable to read boot_params")]
31 ReadBootParams,
32 #[error("unable to read kernel image")]
33 ReadKernelImage,
34 #[error("unable to seek to boot_params")]
35 SeekBootParams,
36 #[error("unable to seek to kernel start")]
37 SeekKernelStart,
38 }
39
40 pub type Result<T> = std::result::Result<T, Error>;
41
42 /// Loads a kernel from a bzImage to a slice
43 ///
44 /// # Arguments
45 ///
46 /// * `guest_mem` - The guest memory region the kernel is written to.
47 /// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
48 /// * `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,49 pub fn load_bzimage<F>(
50 guest_mem: &GuestMemory,
51 kernel_start: GuestAddress,
52 mut kernel_image: &mut F,
53 ) -> Result<(boot_params, u64)>
54 where
55 F: Read + Seek + AsRawDescriptor,
56 {
57 kernel_image
58 .seek(SeekFrom::Start(0))
59 .map_err(|_| Error::SeekBootParams)?;
60 let params: boot_params =
61 zerocopy_from_reader(&mut kernel_image).map_err(|_| Error::ReadBootParams)?;
62
63 // bzImage header signature "HdrS"
64 if params.hdr.header != 0x53726448 {
65 return Err(Error::BadSignature);
66 }
67
68 let setup_sects = if params.hdr.setup_sects == 0 {
69 4u64
70 } else {
71 params.hdr.setup_sects as u64
72 };
73
74 let kernel_offset = setup_sects
75 .checked_add(1)
76 .ok_or(Error::InvalidSetupSects)?
77 .checked_mul(512)
78 .ok_or(Error::InvalidSetupSects)?;
79 let kernel_size = (params.hdr.syssize as usize)
80 .checked_mul(16)
81 .ok_or(Error::InvalidSysSize)?;
82
83 kernel_image
84 .seek(SeekFrom::Start(kernel_offset))
85 .map_err(|_| Error::SeekKernelStart)?;
86
87 // Load the whole kernel image to kernel_start
88 guest_mem
89 .read_to_memory(kernel_start, kernel_image, kernel_size)
90 .map_err(|_| Error::ReadKernelImage)?;
91
92 Ok((params, kernel_start.offset() + kernel_size as u64))
93 }
94