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 //! Project Rialto main source file.
16 
17 #![no_main]
18 #![no_std]
19 
20 mod communication;
21 mod error;
22 mod exceptions;
23 mod fdt;
24 
25 extern crate alloc;
26 
27 use crate::communication::VsockStream;
28 use crate::error::{Error, Result};
29 use crate::fdt::{read_dice_range_from, read_vendor_hashtree_root_digest};
30 use alloc::boxed::Box;
31 use bssl_sys::CRYPTO_library_init;
32 use ciborium_io::Write;
33 use core::num::NonZeroUsize;
34 use core::slice;
35 use diced_open_dice::{bcc_handover_parse, DiceArtifacts};
36 use fdtpci::PciInfo;
37 use libfdt::FdtError;
38 use log::{debug, error, info};
39 use service_vm_comm::{ServiceVmRequest, VmType};
40 use service_vm_fake_chain::service_vm;
41 use service_vm_requests::{process_request, RequestContext};
42 use virtio_drivers::{
43     device::socket::{VsockAddr, VMADDR_CID_HOST},
44     transport::{pci::bus::PciRoot, DeviceType, Transport},
45     Hal,
46 };
47 use vmbase::{
48     configure_heap,
49     fdt::SwiotlbInfo,
50     hyp::{get_mem_sharer, get_mmio_guard},
51     layout::{self, crosvm},
52     main,
53     memory::{MemoryTracker, PageTable, MEMORY, PAGE_SIZE, SIZE_128KB},
54     power::reboot,
55     virtio::{
56         pci::{self, PciTransportIterator, VirtIOSocket},
57         HalImpl,
58     },
59 };
60 
host_addr() -> VsockAddr61 fn host_addr() -> VsockAddr {
62     VsockAddr { cid: VMADDR_CID_HOST, port: vm_type().port() }
63 }
64 
vm_type() -> VmType65 fn vm_type() -> VmType {
66     // Use MMIO support to determine whether the VM is protected.
67     if get_mmio_guard().is_some() {
68         VmType::ProtectedVm
69     } else {
70         VmType::NonProtectedVm
71     }
72 }
73 
new_page_table() -> Result<PageTable>74 fn new_page_table() -> Result<PageTable> {
75     let mut page_table = PageTable::default();
76 
77     page_table.map_data(&layout::scratch_range().into())?;
78     page_table.map_data(&layout::stack_range(40 * PAGE_SIZE).into())?;
79     page_table.map_code(&layout::text_range().into())?;
80     page_table.map_rodata(&layout::rodata_range().into())?;
81     page_table.map_device(&layout::console_uart_range().into())?;
82 
83     Ok(page_table)
84 }
85 
86 /// # Safety
87 ///
88 /// Behavior is undefined if any of the following conditions are violated:
89 /// * The `fdt_addr` must be a valid pointer and points to a valid `Fdt`.
try_main(fdt_addr: usize) -> Result<()>90 unsafe fn try_main(fdt_addr: usize) -> Result<()> {
91     info!("Welcome to Rialto!");
92     let page_table = new_page_table()?;
93 
94     MEMORY.lock().replace(MemoryTracker::new(
95         page_table,
96         crosvm::MEM_START..layout::MAX_VIRT_ADDR,
97         crosvm::MMIO_RANGE,
98         None, // Rialto doesn't have any payload for now.
99     ));
100 
101     let fdt_range = MEMORY
102         .lock()
103         .as_mut()
104         .unwrap()
105         .alloc(fdt_addr, NonZeroUsize::new(crosvm::FDT_MAX_SIZE).unwrap())?;
106     // SAFETY: The tracker validated the range to be in main memory, mapped, and not overlap.
107     let fdt = unsafe { slice::from_raw_parts(fdt_range.start as *mut u8, fdt_range.len()) };
108     // We do not need to validate the DT since it is already validated in pvmfw.
109     let fdt = libfdt::Fdt::from_slice(fdt)?;
110 
111     let memory_range = fdt.first_memory_range()?;
112     MEMORY.lock().as_mut().unwrap().shrink(&memory_range).map_err(|e| {
113         error!("Failed to use memory range value from DT: {memory_range:#x?}");
114         e
115     })?;
116 
117     if let Some(mem_sharer) = get_mem_sharer() {
118         let granule = mem_sharer.granule()?;
119         MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool(granule).map_err(|e| {
120             error!("Failed to initialize dynamically shared pool.");
121             e
122         })?;
123     } else if let Ok(swiotlb_info) = SwiotlbInfo::new_from_fdt(fdt) {
124         let range = swiotlb_info.fixed_range().ok_or_else(|| {
125             error!("Pre-shared pool range not specified in swiotlb node");
126             Error::from(FdtError::BadValue)
127         })?;
128         MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).map_err(|e| {
129             error!("Failed to initialize pre-shared pool.");
130             e
131         })?;
132     } else {
133         info!("No MEM_SHARE capability detected or swiotlb found: allocating buffers from heap.");
134         MEMORY.lock().as_mut().unwrap().init_heap_shared_pool().map_err(|e| {
135             error!("Failed to initialize heap-based pseudo-shared pool.");
136             e
137         })?;
138     }
139 
140     // Initializes the crypto library before any crypto operations and after the heap is
141     // initialized.
142     // SAFETY: It is safe to call this function multiple times and concurrently.
143     unsafe {
144         CRYPTO_library_init();
145     }
146     let bcc_handover: Box<dyn DiceArtifacts> = match vm_type() {
147         VmType::ProtectedVm => {
148             let dice_range = read_dice_range_from(fdt)?;
149             info!("DICE range: {dice_range:#x?}");
150             // SAFETY: This region was written by pvmfw in its writable_data region. The region
151             // has no overlap with the main memory region and is safe to be mapped as read-only
152             // data.
153             let res = unsafe {
154                 MEMORY.lock().as_mut().unwrap().alloc_range_outside_main_memory(&dice_range)
155             };
156             res.map_err(|e| {
157                 error!("Failed to use DICE range from DT: {dice_range:#x?}");
158                 e
159             })?;
160             let dice_start = dice_range.start as *const u8;
161             // SAFETY: There's no memory overlap and the region is mapped as read-only data.
162             let bcc_handover = unsafe { slice::from_raw_parts(dice_start, dice_range.len()) };
163             Box::new(bcc_handover_parse(bcc_handover)?)
164         }
165         // Currently, a sample DICE data is used for non-protected VMs, as these VMs only run
166         // in tests at the moment.
167         VmType::NonProtectedVm => Box::new(service_vm::fake_service_vm_dice_artifacts()?),
168     };
169 
170     let pci_info = PciInfo::from_fdt(fdt)?;
171     debug!("PCI: {pci_info:#x?}");
172     let mut pci_root = pci::initialize(pci_info, MEMORY.lock().as_mut().unwrap())
173         .map_err(Error::PciInitializationFailed)?;
174     debug!("PCI root: {pci_root:#x?}");
175     let socket_device = find_socket_device::<HalImpl>(&mut pci_root)?;
176     debug!("Found socket device: guest cid = {:?}", socket_device.guest_cid());
177     let vendor_hashtree_root_digest = read_vendor_hashtree_root_digest(fdt)?;
178     let request_context =
179         RequestContext { dice_artifacts: bcc_handover.as_ref(), vendor_hashtree_root_digest };
180 
181     let mut vsock_stream = VsockStream::new(socket_device, host_addr())?;
182     while let ServiceVmRequest::Process(req) = vsock_stream.read_request()? {
183         info!("Received request: {}", req.name());
184         let response = process_request(req, &request_context);
185         info!("Sending response: {}", response.name());
186         vsock_stream.write_response(&response)?;
187         vsock_stream.flush()?;
188     }
189     vsock_stream.shutdown()?;
190 
191     Ok(())
192 }
193 
find_socket_device<T: Hal>(pci_root: &mut PciRoot) -> Result<VirtIOSocket<T>>194 fn find_socket_device<T: Hal>(pci_root: &mut PciRoot) -> Result<VirtIOSocket<T>> {
195     PciTransportIterator::<T>::new(pci_root)
196         .find(|t| DeviceType::Socket == t.device_type())
197         .map(VirtIOSocket::<T>::new)
198         .transpose()
199         .map_err(Error::VirtIOSocketCreationFailed)?
200         .ok_or(Error::MissingVirtIOSocketDevice)
201 }
202 
try_unshare_all_memory() -> Result<()>203 fn try_unshare_all_memory() -> Result<()> {
204     info!("Starting unsharing memory...");
205 
206     // No logging after unmapping UART.
207     if let Some(mmio_guard) = get_mmio_guard() {
208         mmio_guard.unmap(vmbase::console::BASE_ADDRESS)?;
209     }
210     // Unshares all memory and deactivates page table.
211     drop(MEMORY.lock().take());
212     Ok(())
213 }
214 
unshare_all_memory()215 fn unshare_all_memory() {
216     if let Err(e) = try_unshare_all_memory() {
217         error!("Failed to unshare the memory: {e}");
218     }
219 }
220 
221 /// Entry point for Rialto.
main(fdt_addr: u64, _a1: u64, _a2: u64, _a3: u64)222 pub fn main(fdt_addr: u64, _a1: u64, _a2: u64, _a3: u64) {
223     log::set_max_level(log::LevelFilter::Debug);
224     // SAFETY: `fdt_addr` is supposed to be a valid pointer and points to
225     // a valid `Fdt`.
226     match unsafe { try_main(fdt_addr as usize) } {
227         Ok(()) => unshare_all_memory(),
228         Err(e) => {
229             error!("Rialto failed with {e}");
230             unshare_all_memory();
231             reboot()
232         }
233     }
234 }
235 
236 main!(main);
237 configure_heap!(SIZE_128KB * 2);
238