1 // Copyright 2022, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! Low-level allocation and tracking of main memory. 16 17 use crate::entry::RebootReason; 18 use crate::fdt::{read_initrd_range_from, read_kernel_range_from}; 19 use core::num::NonZeroUsize; 20 use core::slice; 21 use log::debug; 22 use log::error; 23 use log::info; 24 use log::warn; 25 use vmbase::{ 26 layout::crosvm, 27 memory::{map_data, map_rodata, resize_available_memory}, 28 }; 29 30 pub(crate) struct MemorySlices<'a> { 31 pub fdt: &'a mut libfdt::Fdt, 32 pub kernel: &'a [u8], 33 pub ramdisk: Option<&'a [u8]>, 34 } 35 36 impl<'a> MemorySlices<'a> { new(fdt: usize, kernel: usize, kernel_size: usize) -> Result<Self, RebootReason>37 pub fn new(fdt: usize, kernel: usize, kernel_size: usize) -> Result<Self, RebootReason> { 38 let fdt_size = NonZeroUsize::new(crosvm::FDT_MAX_SIZE).unwrap(); 39 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload() 40 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW, 41 // overwrite with the template DT and apply the DTBO. 42 map_data(fdt, fdt_size).map_err(|e| { 43 error!("Failed to allocate the FDT range: {e}"); 44 RebootReason::InternalError 45 })?; 46 47 // SAFETY: map_data validated the range to be in main memory, mapped, and not overlap. 48 let untrusted_fdt = unsafe { slice::from_raw_parts_mut(fdt as *mut u8, fdt_size.into()) }; 49 let untrusted_fdt = libfdt::Fdt::from_mut_slice(untrusted_fdt).map_err(|e| { 50 error!("Failed to load input FDT: {e}"); 51 RebootReason::InvalidFdt 52 })?; 53 54 let memory_range = untrusted_fdt.first_memory_range().map_err(|e| { 55 error!("Failed to read memory range from DT: {e}"); 56 RebootReason::InvalidFdt 57 })?; 58 debug!("Resizing MemoryTracker to range {memory_range:#x?}"); 59 resize_available_memory(&memory_range).map_err(|e| { 60 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}"); 61 RebootReason::InvalidFdt 62 })?; 63 64 let kernel_range = read_kernel_range_from(untrusted_fdt).map_err(|e| { 65 error!("Failed to read kernel range: {e}"); 66 RebootReason::InvalidFdt 67 })?; 68 let (kernel_start, kernel_size) = if let Some(r) = kernel_range { 69 (r.start, r.len()) 70 } else if cfg!(feature = "legacy") { 71 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI"); 72 (kernel, kernel_size) 73 } else { 74 error!("Failed to locate the kernel from the DT"); 75 return Err(RebootReason::InvalidPayload); 76 }; 77 let kernel_size = kernel_size.try_into().map_err(|_| { 78 error!("Invalid kernel size: {kernel_size:#x}"); 79 RebootReason::InvalidPayload 80 })?; 81 82 map_rodata(kernel_start, kernel_size).map_err(|e| { 83 error!("Failed to map kernel range: {e}"); 84 RebootReason::InternalError 85 })?; 86 87 let kernel = kernel_start as *const u8; 88 // SAFETY: map_rodata validated the range to be in main memory, mapped, and not overlap. 89 let kernel = unsafe { slice::from_raw_parts(kernel, kernel_size.into()) }; 90 91 let initrd_range = read_initrd_range_from(untrusted_fdt).map_err(|e| { 92 error!("Failed to read initrd range: {e}"); 93 RebootReason::InvalidFdt 94 })?; 95 let ramdisk = if let Some(r) = initrd_range { 96 debug!("Located ramdisk at {r:?}"); 97 let ramdisk_size = r.len().try_into().map_err(|_| { 98 error!("Invalid ramdisk size: {:#x}", r.len()); 99 RebootReason::InvalidRamdisk 100 })?; 101 map_rodata(r.start, ramdisk_size).map_err(|e| { 102 error!("Failed to obtain the initrd range: {e}"); 103 RebootReason::InvalidRamdisk 104 })?; 105 106 // SAFETY: map_rodata validated the range to be in main memory, mapped, and not 107 // overlap. 108 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) }) 109 } else { 110 info!("Couldn't locate the ramdisk from the device tree"); 111 None 112 }; 113 114 Ok(Self { fdt: untrusted_fdt, kernel, ramdisk }) 115 } 116 } 117