xref: /aosp_15_r20/external/crosvm/kernel_loader/src/arm64.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Linux arm64 kernel loader.
6*bb4ee6a4SAndroid Build Coastguard Worker //! <https://www.kernel.org/doc/Documentation/arm64/booting.txt>
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker use std::cmp::max;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::io::BufRead;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Read;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Seek;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::io::SeekFrom;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of_val;
15*bb4ee6a4SAndroid Build Coastguard Worker 
16*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::FileGetLen;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::FileReadWriteAtVolatile;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::VolatileSlice;
20*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le32;
21*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le64;
22*bb4ee6a4SAndroid Build Coastguard Worker use lz4_flex::frame::FrameDecoder as Lz4FrameDecoder;
23*bb4ee6a4SAndroid Build Coastguard Worker use resources::AddressRange;
24*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
25*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
26*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
27*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
28*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker use crate::Error;
31*bb4ee6a4SAndroid Build Coastguard Worker use crate::LoadedKernel;
32*bb4ee6a4SAndroid Build Coastguard Worker use crate::Result;
33*bb4ee6a4SAndroid Build Coastguard Worker 
34*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, AsBytes, FromZeroes, FromBytes)]
35*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused)]
36*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
37*bb4ee6a4SAndroid Build Coastguard Worker struct Arm64ImageHeader {
38*bb4ee6a4SAndroid Build Coastguard Worker     code0: Le32,
39*bb4ee6a4SAndroid Build Coastguard Worker     code1: Le32,
40*bb4ee6a4SAndroid Build Coastguard Worker     text_offset: Le64,
41*bb4ee6a4SAndroid Build Coastguard Worker     image_size: Le64,
42*bb4ee6a4SAndroid Build Coastguard Worker     flags: Le64,
43*bb4ee6a4SAndroid Build Coastguard Worker     res2: Le64,
44*bb4ee6a4SAndroid Build Coastguard Worker     res3: Le64,
45*bb4ee6a4SAndroid Build Coastguard Worker     res4: Le64,
46*bb4ee6a4SAndroid Build Coastguard Worker     magic: Le32,
47*bb4ee6a4SAndroid Build Coastguard Worker     res5: Le32,
48*bb4ee6a4SAndroid Build Coastguard Worker }
49*bb4ee6a4SAndroid Build Coastguard Worker 
50*bb4ee6a4SAndroid Build Coastguard Worker const ARM64_IMAGE_MAGIC: u32 = 0x644d5241; // "ARM\x64"
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker const ARM64_IMAGE_FLAG_BE_MASK: u64 = 0x1;
53*bb4ee6a4SAndroid Build Coastguard Worker 
54*bb4ee6a4SAndroid Build Coastguard Worker const ARM64_TEXT_OFFSET_DEFAULT: u64 = 0x80000;
55*bb4ee6a4SAndroid Build Coastguard Worker 
56*bb4ee6a4SAndroid Build Coastguard Worker impl Arm64ImageHeader {
parse_load_addr(&self, kernel_start: GuestAddress) -> Result<GuestAddress>57*bb4ee6a4SAndroid Build Coastguard Worker     fn parse_load_addr(&self, kernel_start: GuestAddress) -> Result<GuestAddress> {
58*bb4ee6a4SAndroid Build Coastguard Worker         let magic: u32 = self.magic.into();
59*bb4ee6a4SAndroid Build Coastguard Worker         if magic != ARM64_IMAGE_MAGIC {
60*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidMagicNumber);
61*bb4ee6a4SAndroid Build Coastguard Worker         }
62*bb4ee6a4SAndroid Build Coastguard Worker 
63*bb4ee6a4SAndroid Build Coastguard Worker         let flags: u64 = self.flags.into();
64*bb4ee6a4SAndroid Build Coastguard Worker         if flags & ARM64_IMAGE_FLAG_BE_MASK != 0 {
65*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::BigEndianOnLittle);
66*bb4ee6a4SAndroid Build Coastguard Worker         }
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker         let mut text_offset: u64 = self.text_offset.into();
69*bb4ee6a4SAndroid Build Coastguard Worker         let image_size: u64 = self.image_size.into();
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker         if image_size == 0 {
72*bb4ee6a4SAndroid Build Coastguard Worker             warn!("arm64 Image header has an effective size of zero");
73*bb4ee6a4SAndroid Build Coastguard Worker             // arm64/booting.txt:
74*bb4ee6a4SAndroid Build Coastguard Worker             // "Where image_size is zero, text_offset can be assumed to be 0x80000."
75*bb4ee6a4SAndroid Build Coastguard Worker             text_offset = ARM64_TEXT_OFFSET_DEFAULT;
76*bb4ee6a4SAndroid Build Coastguard Worker         }
77*bb4ee6a4SAndroid Build Coastguard Worker 
78*bb4ee6a4SAndroid Build Coastguard Worker         // Load the image into guest memory at `text_offset` bytes past `kernel_start`.
79*bb4ee6a4SAndroid Build Coastguard Worker         kernel_start
80*bb4ee6a4SAndroid Build Coastguard Worker             .checked_add(text_offset)
81*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(Error::InvalidKernelOffset)
82*bb4ee6a4SAndroid Build Coastguard Worker     }
83*bb4ee6a4SAndroid Build Coastguard Worker }
84*bb4ee6a4SAndroid Build Coastguard Worker 
load_arm64_kernel<F>( guest_mem: &GuestMemory, kernel_start: GuestAddress, kernel_image: &mut F, ) -> Result<LoadedKernel> where F: FileReadWriteAtVolatile + FileGetLen,85*bb4ee6a4SAndroid Build Coastguard Worker pub fn load_arm64_kernel<F>(
86*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: &GuestMemory,
87*bb4ee6a4SAndroid Build Coastguard Worker     kernel_start: GuestAddress,
88*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image: &mut F,
89*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<LoadedKernel>
90*bb4ee6a4SAndroid Build Coastguard Worker where
91*bb4ee6a4SAndroid Build Coastguard Worker     F: FileReadWriteAtVolatile + FileGetLen,
92*bb4ee6a4SAndroid Build Coastguard Worker {
93*bb4ee6a4SAndroid Build Coastguard Worker     let mut header = Arm64ImageHeader::new_zeroed();
94*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image
95*bb4ee6a4SAndroid Build Coastguard Worker         .read_exact_at_volatile(VolatileSlice::new(header.as_bytes_mut()), 0)
96*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadHeader)?;
97*bb4ee6a4SAndroid Build Coastguard Worker     let load_addr = header.parse_load_addr(kernel_start)?;
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker     let file_size = kernel_image.get_len().map_err(|_| Error::SeekKernelEnd)?;
100*bb4ee6a4SAndroid Build Coastguard Worker     let load_size = usize::try_from(file_size).map_err(|_| Error::InvalidKernelSize)?;
101*bb4ee6a4SAndroid Build Coastguard Worker     let range_size = max(file_size, u64::from(header.image_size));
102*bb4ee6a4SAndroid Build Coastguard Worker 
103*bb4ee6a4SAndroid Build Coastguard Worker     let guest_slice = guest_mem
104*bb4ee6a4SAndroid Build Coastguard Worker         .get_slice_at_addr(load_addr, load_size)
105*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadKernelImage)?;
106*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image
107*bb4ee6a4SAndroid Build Coastguard Worker         .read_exact_at_volatile(guest_slice, 0)
108*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadKernelImage)?;
109*bb4ee6a4SAndroid Build Coastguard Worker 
110*bb4ee6a4SAndroid Build Coastguard Worker     Ok(LoadedKernel {
111*bb4ee6a4SAndroid Build Coastguard Worker         size: file_size,
112*bb4ee6a4SAndroid Build Coastguard Worker         address_range: AddressRange::from_start_and_size(load_addr.offset(), range_size)
113*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(Error::InvalidKernelSize)?,
114*bb4ee6a4SAndroid Build Coastguard Worker         entry: load_addr,
115*bb4ee6a4SAndroid Build Coastguard Worker     })
116*bb4ee6a4SAndroid Build Coastguard Worker }
117*bb4ee6a4SAndroid Build Coastguard Worker 
load_arm64_kernel_from_reader<F: BufRead>( guest_mem: &GuestMemory, kernel_start: GuestAddress, mut kernel_image: F, ) -> Result<LoadedKernel>118*bb4ee6a4SAndroid Build Coastguard Worker fn load_arm64_kernel_from_reader<F: BufRead>(
119*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: &GuestMemory,
120*bb4ee6a4SAndroid Build Coastguard Worker     kernel_start: GuestAddress,
121*bb4ee6a4SAndroid Build Coastguard Worker     mut kernel_image: F,
122*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<LoadedKernel> {
123*bb4ee6a4SAndroid Build Coastguard Worker     let mut header = Arm64ImageHeader::new_zeroed();
124*bb4ee6a4SAndroid Build Coastguard Worker     let header_size = u64::try_from(size_of_val(&header)).unwrap();
125*bb4ee6a4SAndroid Build Coastguard Worker 
126*bb4ee6a4SAndroid Build Coastguard Worker     // Read and parse the kernel header.
127*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image
128*bb4ee6a4SAndroid Build Coastguard Worker         .read_exact(header.as_bytes_mut())
129*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadHeader)?;
130*bb4ee6a4SAndroid Build Coastguard Worker     let load_addr = header.parse_load_addr(kernel_start)?;
131*bb4ee6a4SAndroid Build Coastguard Worker 
132*bb4ee6a4SAndroid Build Coastguard Worker     // Write the parsed kernel header to memory. Avoid rewinding the reader back to the start.
133*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem
134*bb4ee6a4SAndroid Build Coastguard Worker         .write_all_at_addr(header.as_bytes(), load_addr)
135*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadKernelImage)?;
136*bb4ee6a4SAndroid Build Coastguard Worker 
137*bb4ee6a4SAndroid Build Coastguard Worker     // Continue reading from the source and copy the kernel image into GuestMemory.
138*bb4ee6a4SAndroid Build Coastguard Worker     let mut current_addr = load_addr
139*bb4ee6a4SAndroid Build Coastguard Worker         .checked_add(header_size)
140*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or(Error::InvalidKernelSize)?;
141*bb4ee6a4SAndroid Build Coastguard Worker     loop {
142*bb4ee6a4SAndroid Build Coastguard Worker         let buf = match kernel_image.fill_buf() {
143*bb4ee6a4SAndroid Build Coastguard Worker             Ok([]) => break,
144*bb4ee6a4SAndroid Build Coastguard Worker             Ok(buf) => buf,
145*bb4ee6a4SAndroid Build Coastguard Worker             Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
146*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => return Err(Error::ReadKernelImage),
147*bb4ee6a4SAndroid Build Coastguard Worker         };
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem
150*bb4ee6a4SAndroid Build Coastguard Worker             .write_all_at_addr(buf, current_addr)
151*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| Error::ReadKernelImage)?;
152*bb4ee6a4SAndroid Build Coastguard Worker 
153*bb4ee6a4SAndroid Build Coastguard Worker         let consumed = buf.len();
154*bb4ee6a4SAndroid Build Coastguard Worker         kernel_image.consume(consumed);
155*bb4ee6a4SAndroid Build Coastguard Worker 
156*bb4ee6a4SAndroid Build Coastguard Worker         let offset = u64::try_from(consumed).map_err(|_| Error::InvalidKernelSize)?;
157*bb4ee6a4SAndroid Build Coastguard Worker         current_addr = current_addr
158*bb4ee6a4SAndroid Build Coastguard Worker             .checked_add(offset)
159*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(Error::InvalidKernelSize)?;
160*bb4ee6a4SAndroid Build Coastguard Worker     }
161*bb4ee6a4SAndroid Build Coastguard Worker 
162*bb4ee6a4SAndroid Build Coastguard Worker     let file_size = current_addr.offset_from(load_addr);
163*bb4ee6a4SAndroid Build Coastguard Worker     let range_size = max(file_size, u64::from(header.image_size));
164*bb4ee6a4SAndroid Build Coastguard Worker     Ok(LoadedKernel {
165*bb4ee6a4SAndroid Build Coastguard Worker         size: file_size,
166*bb4ee6a4SAndroid Build Coastguard Worker         address_range: AddressRange::from_start_and_size(load_addr.offset(), range_size)
167*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(Error::InvalidKernelSize)?,
168*bb4ee6a4SAndroid Build Coastguard Worker         entry: load_addr,
169*bb4ee6a4SAndroid Build Coastguard Worker     })
170*bb4ee6a4SAndroid Build Coastguard Worker }
171*bb4ee6a4SAndroid Build Coastguard Worker 
load_arm64_kernel_lz4<F: Read + Seek>( guest_mem: &GuestMemory, kernel_start: GuestAddress, mut kernel_image: F, ) -> Result<LoadedKernel>172*bb4ee6a4SAndroid Build Coastguard Worker pub fn load_arm64_kernel_lz4<F: Read + Seek>(
173*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: &GuestMemory,
174*bb4ee6a4SAndroid Build Coastguard Worker     kernel_start: GuestAddress,
175*bb4ee6a4SAndroid Build Coastguard Worker     mut kernel_image: F,
176*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<LoadedKernel> {
177*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image
178*bb4ee6a4SAndroid Build Coastguard Worker         .seek(SeekFrom::Start(0))
179*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::SeekKernelStart)?;
180*bb4ee6a4SAndroid Build Coastguard Worker     load_arm64_kernel_from_reader(
181*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem,
182*bb4ee6a4SAndroid Build Coastguard Worker         kernel_start,
183*bb4ee6a4SAndroid Build Coastguard Worker         &mut Lz4FrameDecoder::new(kernel_image),
184*bb4ee6a4SAndroid Build Coastguard Worker     )
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker 
187*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
188*bb4ee6a4SAndroid Build Coastguard Worker mod test {
189*bb4ee6a4SAndroid Build Coastguard Worker     use std::fs::File;
190*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::Seek;
191*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::SeekFrom;
192*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::Write;
193*bb4ee6a4SAndroid Build Coastguard Worker 
194*bb4ee6a4SAndroid Build Coastguard Worker     use tempfile::tempfile;
195*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestAddress;
196*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestMemory;
197*bb4ee6a4SAndroid Build Coastguard Worker 
198*bb4ee6a4SAndroid Build Coastguard Worker     use crate::load_arm64_kernel;
199*bb4ee6a4SAndroid Build Coastguard Worker     use crate::load_arm64_kernel_lz4;
200*bb4ee6a4SAndroid Build Coastguard Worker     use crate::Error;
201*bb4ee6a4SAndroid Build Coastguard Worker 
202*bb4ee6a4SAndroid Build Coastguard Worker     const MEM_SIZE: u64 = 0x200_0000;
203*bb4ee6a4SAndroid Build Coastguard Worker 
create_guest_mem() -> GuestMemory204*bb4ee6a4SAndroid Build Coastguard Worker     fn create_guest_mem() -> GuestMemory {
205*bb4ee6a4SAndroid Build Coastguard Worker         GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap()
206*bb4ee6a4SAndroid Build Coastguard Worker     }
207*bb4ee6a4SAndroid Build Coastguard Worker 
208*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(clippy::unusual_byte_groupings)]
write_valid_kernel() -> File209*bb4ee6a4SAndroid Build Coastguard Worker     fn write_valid_kernel() -> File {
210*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = tempfile().expect("failed to create tempfile");
211*bb4ee6a4SAndroid Build Coastguard Worker 
212*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0x00, 0xC0, 0x2E, 0x14]).unwrap(); // code0
213*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0x00, 0x00, 0x00, 0x00]).unwrap(); // code1
214*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000_00E70000u64.to_le_bytes()).unwrap(); // text_offset
215*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000_0000000Au64.to_le_bytes()).unwrap(); // image_size
216*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); // flags
217*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); // res2
218*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); // res3
219*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); // res4
220*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x644D5241u32.to_le_bytes()).unwrap(); // magic
221*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000u32.to_le_bytes()).unwrap(); // res5
222*bb4ee6a4SAndroid Build Coastguard Worker 
223*bb4ee6a4SAndroid Build Coastguard Worker         f.set_len(0xDC3808).unwrap();
224*bb4ee6a4SAndroid Build Coastguard Worker         f
225*bb4ee6a4SAndroid Build Coastguard Worker     }
226*bb4ee6a4SAndroid Build Coastguard Worker 
mutate_file(mut f: &File, offset: u64, val: &[u8])227*bb4ee6a4SAndroid Build Coastguard Worker     fn mutate_file(mut f: &File, offset: u64, val: &[u8]) {
228*bb4ee6a4SAndroid Build Coastguard Worker         f.seek(SeekFrom::Start(offset))
229*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to seek file");
230*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(val)
231*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to write mutated value to file");
232*bb4ee6a4SAndroid Build Coastguard Worker     }
233*bb4ee6a4SAndroid Build Coastguard Worker 
234*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_valid()235*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_valid() {
236*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
237*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
238*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel();
239*bb4ee6a4SAndroid Build Coastguard Worker         let kernel = load_arm64_kernel(&gm, kernel_addr, &mut f).unwrap();
240*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.start, 0x107_0000);
241*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.end, 0x1E3_3807);
242*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.size, 0xDC_3808);
243*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.entry, GuestAddress(0x107_0000));
244*bb4ee6a4SAndroid Build Coastguard Worker     }
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_image_size_zero()247*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_image_size_zero() {
248*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
249*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
250*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel();
251*bb4ee6a4SAndroid Build Coastguard Worker 
252*bb4ee6a4SAndroid Build Coastguard Worker         // Set image_size = 0 and validate the default text_offset is applied.
253*bb4ee6a4SAndroid Build Coastguard Worker         mutate_file(&f, 16, &0u64.to_le_bytes());
254*bb4ee6a4SAndroid Build Coastguard Worker 
255*bb4ee6a4SAndroid Build Coastguard Worker         let kernel = load_arm64_kernel(&gm, kernel_addr, &mut f).unwrap();
256*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.start, 0x28_0000);
257*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.end, 0x104_3807);
258*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.size, 0xDC_3808);
259*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.entry, GuestAddress(0x28_0000));
260*bb4ee6a4SAndroid Build Coastguard Worker     }
261*bb4ee6a4SAndroid Build Coastguard Worker 
262*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_bad_magic()263*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_bad_magic() {
264*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
265*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
266*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel();
267*bb4ee6a4SAndroid Build Coastguard Worker 
268*bb4ee6a4SAndroid Build Coastguard Worker         // Mutate magic number so it doesn't match
269*bb4ee6a4SAndroid Build Coastguard Worker         mutate_file(&f, 56, &[0xCC, 0xCC, 0xCC, 0xCC]);
270*bb4ee6a4SAndroid Build Coastguard Worker 
271*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
272*bb4ee6a4SAndroid Build Coastguard Worker             load_arm64_kernel(&gm, kernel_addr, &mut f),
273*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::InvalidMagicNumber)
274*bb4ee6a4SAndroid Build Coastguard Worker         );
275*bb4ee6a4SAndroid Build Coastguard Worker     }
276*bb4ee6a4SAndroid Build Coastguard Worker 
write_valid_kernel_lz4() -> File277*bb4ee6a4SAndroid Build Coastguard Worker     fn write_valid_kernel_lz4() -> File {
278*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = tempfile().expect("failed to create tempfile");
279*bb4ee6a4SAndroid Build Coastguard Worker 
280*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x184d2204u32.to_le_bytes()).unwrap(); // magic
281*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0x44, 0x70, 0x1d]).unwrap(); // flg, bd, hc
282*bb4ee6a4SAndroid Build Coastguard Worker 
283*bb4ee6a4SAndroid Build Coastguard Worker         // Compressed block #1.
284*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00004065u32.to_le_bytes()).unwrap();
285*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[
286*bb4ee6a4SAndroid Build Coastguard Worker             0x51, 0x00, 0xc0, 0x2e, 0x14, 0x00, 0x01, 0x00, 0x11, 0xe7, 0x06, 0x00, 0x11, 0x0a,
287*bb4ee6a4SAndroid Build Coastguard Worker             0x06, 0x00, 0x0f, 0x02, 0x00, 0x0f, 0x4f, 0x41, 0x52, 0x4d, 0x64, 0x26, 0x00, 0x0f,
288*bb4ee6a4SAndroid Build Coastguard Worker             0x0f, 0x02, 0x00,
289*bb4ee6a4SAndroid Build Coastguard Worker         ])
290*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
291*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0xff; 16447]).unwrap();
292*bb4ee6a4SAndroid Build Coastguard Worker 
293*bb4ee6a4SAndroid Build Coastguard Worker         // Compressed block #2.
294*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x000050c9u32.to_le_bytes()).unwrap();
295*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[
296*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x4b, 0x40, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
297*bb4ee6a4SAndroid Build Coastguard Worker         ])
298*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
299*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0xff; 16448]).unwrap();
300*bb4ee6a4SAndroid Build Coastguard Worker 
301*bb4ee6a4SAndroid Build Coastguard Worker         // Compressed block #3.
302*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00005027u32.to_le_bytes()).unwrap();
303*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[
304*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x4b, 0x40, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
305*bb4ee6a4SAndroid Build Coastguard Worker         ])
306*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
307*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0xff; 16448]).unwrap();
308*bb4ee6a4SAndroid Build Coastguard Worker 
309*bb4ee6a4SAndroid Build Coastguard Worker         // Compressed block #4.
310*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00005027u32.to_le_bytes()).unwrap();
311*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[
312*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x5f, 0x1c, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
313*bb4ee6a4SAndroid Build Coastguard Worker         ])
314*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
315*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0xff; 7252]).unwrap();
316*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0x43, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00])
317*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
318*bb4ee6a4SAndroid Build Coastguard Worker 
319*bb4ee6a4SAndroid Build Coastguard Worker         // EndMark
320*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x00000000u32.to_le_bytes()).unwrap();
321*bb4ee6a4SAndroid Build Coastguard Worker 
322*bb4ee6a4SAndroid Build Coastguard Worker         // Checksum
323*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x22a9944cu32.to_le_bytes()).unwrap();
324*bb4ee6a4SAndroid Build Coastguard Worker 
325*bb4ee6a4SAndroid Build Coastguard Worker         f
326*bb4ee6a4SAndroid Build Coastguard Worker     }
327*bb4ee6a4SAndroid Build Coastguard Worker 
write_valid_kernel_lz4_legacy() -> File328*bb4ee6a4SAndroid Build Coastguard Worker     fn write_valid_kernel_lz4_legacy() -> File {
329*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = tempfile().expect("failed to create tempfile");
330*bb4ee6a4SAndroid Build Coastguard Worker 
331*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x184c2102u32.to_le_bytes()).unwrap(); // magic
332*bb4ee6a4SAndroid Build Coastguard Worker 
333*bb4ee6a4SAndroid Build Coastguard Worker         // Compressed block #1.
334*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x000080a6u32.to_le_bytes()).unwrap();
335*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[
336*bb4ee6a4SAndroid Build Coastguard Worker             0x51, 0x00, 0xc0, 0x2e, 0x14, 0x00, 0x01, 0x00, 0x11, 0xe7, 0x06, 0x00, 0x11, 0x0a,
337*bb4ee6a4SAndroid Build Coastguard Worker             0x06, 0x00, 0x0f, 0x02, 0x00, 0x0f, 0x4f, 0x41, 0x52, 0x4d, 0x64, 0x26, 0x00, 0x0f,
338*bb4ee6a4SAndroid Build Coastguard Worker             0x0f, 0x02, 0x00,
339*bb4ee6a4SAndroid Build Coastguard Worker         ])
340*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
341*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0xff; 32896]).unwrap();
342*bb4ee6a4SAndroid Build Coastguard Worker 
343*bb4ee6a4SAndroid Build Coastguard Worker         // Compressed block #2.
344*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&0x0000500au32.to_le_bytes()).unwrap();
345*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[
346*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x9f, 0x5c, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
347*bb4ee6a4SAndroid Build Coastguard Worker         ])
348*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
349*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0xff; 23700]).unwrap();
350*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0x83, 0x50, 0x00]).unwrap();
351*bb4ee6a4SAndroid Build Coastguard Worker 
352*bb4ee6a4SAndroid Build Coastguard Worker         // EndMark
353*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[0x00, 0x00, 0x00, 0x00]).unwrap();
354*bb4ee6a4SAndroid Build Coastguard Worker 
355*bb4ee6a4SAndroid Build Coastguard Worker         f
356*bb4ee6a4SAndroid Build Coastguard Worker     }
357*bb4ee6a4SAndroid Build Coastguard Worker 
358*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_lz4_valid()359*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_lz4_valid() {
360*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
361*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
362*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel_lz4();
363*bb4ee6a4SAndroid Build Coastguard Worker         let kernel = load_arm64_kernel_lz4(&gm, kernel_addr, &mut f).unwrap();
364*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.start, 0x107_0000);
365*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.end, 0x1E3_3807);
366*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.size, 0xDC_3808);
367*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.entry, GuestAddress(0x107_0000));
368*bb4ee6a4SAndroid Build Coastguard Worker     }
369*bb4ee6a4SAndroid Build Coastguard Worker 
370*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_lz4_bad_magic()371*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_lz4_bad_magic() {
372*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
373*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
374*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel_lz4();
375*bb4ee6a4SAndroid Build Coastguard Worker 
376*bb4ee6a4SAndroid Build Coastguard Worker         mutate_file(&f, 0, &[0xCC, 0xCC, 0xCC, 0xCC]);
377*bb4ee6a4SAndroid Build Coastguard Worker 
378*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
379*bb4ee6a4SAndroid Build Coastguard Worker             load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
380*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::ReadHeader)
381*bb4ee6a4SAndroid Build Coastguard Worker         );
382*bb4ee6a4SAndroid Build Coastguard Worker     }
383*bb4ee6a4SAndroid Build Coastguard Worker 
384*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_lz4_bad_block()385*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_lz4_bad_block() {
386*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
387*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
388*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel_lz4();
389*bb4ee6a4SAndroid Build Coastguard Worker 
390*bb4ee6a4SAndroid Build Coastguard Worker         mutate_file(&f, 7, &[0xCC, 0xCC, 0xCC, 0xCC]);
391*bb4ee6a4SAndroid Build Coastguard Worker 
392*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
393*bb4ee6a4SAndroid Build Coastguard Worker             load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
394*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::ReadHeader)
395*bb4ee6a4SAndroid Build Coastguard Worker         );
396*bb4ee6a4SAndroid Build Coastguard Worker     }
397*bb4ee6a4SAndroid Build Coastguard Worker 
398*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_lz4_legacy_valid()399*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_lz4_legacy_valid() {
400*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
401*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
402*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel_lz4_legacy();
403*bb4ee6a4SAndroid Build Coastguard Worker         let kernel = load_arm64_kernel_lz4(&gm, kernel_addr, &mut f).unwrap();
404*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.start, 0x107_0000);
405*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.end, 0x1E3_3807);
406*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.size, 0xDC_3808);
407*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.entry, GuestAddress(0x107_0000));
408*bb4ee6a4SAndroid Build Coastguard Worker     }
409*bb4ee6a4SAndroid Build Coastguard Worker 
410*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_lz4_legacy_bad_magic()411*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_lz4_legacy_bad_magic() {
412*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
413*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
414*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel_lz4_legacy();
415*bb4ee6a4SAndroid Build Coastguard Worker 
416*bb4ee6a4SAndroid Build Coastguard Worker         mutate_file(&f, 0, &[0xCC, 0xCC, 0xCC, 0xCC]);
417*bb4ee6a4SAndroid Build Coastguard Worker 
418*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
419*bb4ee6a4SAndroid Build Coastguard Worker             load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
420*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::ReadHeader)
421*bb4ee6a4SAndroid Build Coastguard Worker         );
422*bb4ee6a4SAndroid Build Coastguard Worker     }
423*bb4ee6a4SAndroid Build Coastguard Worker 
424*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_arm64_lz4_legacy_bad_block()425*bb4ee6a4SAndroid Build Coastguard Worker     fn load_arm64_lz4_legacy_bad_block() {
426*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
427*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(2 * 1024 * 1024);
428*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = write_valid_kernel_lz4_legacy();
429*bb4ee6a4SAndroid Build Coastguard Worker 
430*bb4ee6a4SAndroid Build Coastguard Worker         mutate_file(&f, 4, &[0xCC, 0xCC, 0xCC, 0xCC]);
431*bb4ee6a4SAndroid Build Coastguard Worker 
432*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
433*bb4ee6a4SAndroid Build Coastguard Worker             load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
434*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::ReadHeader)
435*bb4ee6a4SAndroid Build Coastguard Worker         );
436*bb4ee6a4SAndroid Build Coastguard Worker     }
437*bb4ee6a4SAndroid Build Coastguard Worker }
438