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