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 //! VM bootloader example.
16 
17 #![no_main]
18 #![no_std]
19 
20 mod exceptions;
21 mod layout;
22 mod pci;
23 
24 extern crate alloc;
25 
26 use crate::layout::print_addresses;
27 use crate::pci::check_pci;
28 use alloc::{vec, vec::Vec};
29 use core::ptr::addr_of_mut;
30 use cstr::cstr;
31 use libfdt::Fdt;
32 use log::{debug, error, info, trace, warn, LevelFilter};
33 use vmbase::{
34     bionic, configure_heap,
35     fdt::pci::PciInfo,
36     generate_image_header,
37     layout::crosvm::FDT_MAX_SIZE,
38     linker, logger, main,
39     memory::{deactivate_dynamic_page_tables, map_data, SIZE_64KB},
40 };
41 
42 static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
43 static mut ZEROED_DATA: [u32; 10] = [0; 10];
44 static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
45 
46 generate_image_header!();
47 main!(main);
48 configure_heap!(SIZE_64KB);
49 
50 /// Entry point for VM bootloader.
main(arg0: u64, arg1: u64, arg2: u64, arg3: u64)51 pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
52     log::set_max_level(LevelFilter::Debug);
53 
54     info!("Hello world");
55     info!("x0={:#018x}, x1={:#018x}, x2={:#018x}, x3={:#018x}", arg0, arg1, arg2, arg3);
56     print_addresses();
57     check_data();
58     check_stack_guard();
59 
60     info!("Checking FDT...");
61     let fdt_addr = usize::try_from(arg0).unwrap();
62     // SAFETY: The DTB range is valid, writable memory, and we don't construct any aliases to it.
63     let fdt = unsafe { core::slice::from_raw_parts_mut(fdt_addr as *mut u8, FDT_MAX_SIZE) };
64     map_data(fdt_addr, FDT_MAX_SIZE.try_into().unwrap()).unwrap();
65     let fdt = Fdt::from_mut_slice(fdt).unwrap();
66     info!("FDT passed verification.");
67     check_fdt(fdt);
68 
69     let pci_info = PciInfo::from_fdt(fdt).unwrap();
70     debug!("Found PCI CAM at {:#x}-{:#x}", pci_info.cam_range.start, pci_info.cam_range.end);
71 
72     modify_fdt(fdt);
73 
74     check_alloc();
75     check_data();
76     check_dice();
77 
78     let mut pci_root = vmbase::virtio::pci::initialize(pci_info).unwrap();
79     check_pci(&mut pci_root);
80 
81     emit_suppressed_log();
82 
83     info!("De-activating IdMap...");
84     deactivate_dynamic_page_tables();
85     info!("De-activated.");
86 }
87 
check_stack_guard()88 fn check_stack_guard() {
89     info!("Testing stack guard");
90     // SAFETY: No concurrency issue should occur when running these tests.
91     let stack_guard = unsafe { bionic::TLS.stack_guard };
92     assert_ne!(stack_guard, 0);
93     // Check that a NULL-terminating value is added for C functions consuming strings from stack.
94     assert_eq!(stack_guard.to_ne_bytes().last(), Some(&0));
95     // Check that the TLS and guard are properly accessible from the dedicated register.
96     assert_eq!(stack_guard, bionic::__get_tls().stack_guard);
97     // Check that the LLVM __stack_chk_guard alias is also properly set up.
98     assert_eq!(
99         stack_guard,
100         // SAFETY: No concurrency issue should occur when running these tests.
101         unsafe { linker::__stack_chk_guard },
102     );
103 }
104 
check_data()105 fn check_data() {
106     info!("INITIALISED_DATA: {:?}", INITIALISED_DATA.as_ptr());
107     // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
108     info!("ZEROED_DATA: {:?}", unsafe { ZEROED_DATA.as_ptr() });
109     // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
110     info!("MUTABLE_DATA: {:?}", unsafe { MUTABLE_DATA.as_ptr() });
111 
112     assert_eq!(INITIALISED_DATA[0], 1);
113     assert_eq!(INITIALISED_DATA[1], 2);
114     assert_eq!(INITIALISED_DATA[2], 3);
115     assert_eq!(INITIALISED_DATA[3], 4);
116 
117     // SAFETY: Nowhere else in the program accesses this static mutable variable, so there is no
118     // chance of concurrent access.
119     let zeroed_data = unsafe { &mut *addr_of_mut!(ZEROED_DATA) };
120     // SAFETY: Nowhere else in the program accesses this static mutable variable, so there is no
121     // chance of concurrent access.
122     let mutable_data = unsafe { &mut *addr_of_mut!(MUTABLE_DATA) };
123 
124     for element in zeroed_data.iter() {
125         assert_eq!(*element, 0);
126     }
127 
128     zeroed_data[0] = 13;
129     assert_eq!(zeroed_data[0], 13);
130     zeroed_data[0] = 0;
131     assert_eq!(zeroed_data[0], 0);
132 
133     assert_eq!(mutable_data[0], 1);
134     assert_eq!(mutable_data[1], 2);
135     assert_eq!(mutable_data[2], 3);
136     assert_eq!(mutable_data[3], 4);
137     mutable_data[0] += 41;
138     assert_eq!(mutable_data[0], 42);
139     mutable_data[0] -= 41;
140     assert_eq!(mutable_data[0], 1);
141 
142     info!("Data looks good");
143 }
144 
check_fdt(reader: &Fdt)145 fn check_fdt(reader: &Fdt) {
146     for reg in reader.memory().unwrap() {
147         info!("memory @ {reg:#x?}");
148     }
149 
150     let compatible = cstr!("ns16550a");
151 
152     for c in reader.compatible_nodes(compatible).unwrap() {
153         let reg = c.reg().unwrap().unwrap().next().unwrap();
154         info!("node compatible with '{}' at {reg:?}", compatible.to_str().unwrap());
155     }
156 }
157 
modify_fdt(writer: &mut Fdt)158 fn modify_fdt(writer: &mut Fdt) {
159     writer.unpack().unwrap();
160     info!("FDT successfully unpacked.");
161 
162     let path = cstr!("/memory");
163     let node = writer.node_mut(path).unwrap().unwrap();
164     let name = cstr!("child");
165     let mut child = node.add_subnode(name).unwrap();
166     info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
167 
168     let name = cstr!("str-property");
169     child.appendprop(name, b"property-value\0").unwrap();
170     info!("Appended property '{}'.", name.to_str().unwrap());
171 
172     let name = cstr!("pair-property");
173     let addr = 0x0123_4567u64;
174     let size = 0x89ab_cdefu64;
175     child.appendprop_addrrange(name, addr, size).unwrap();
176     info!("Appended property '{}'.", name.to_str().unwrap());
177 
178     let writer = child.fdt();
179     writer.pack().unwrap();
180     info!("FDT successfully packed.");
181 
182     info!("FDT checks done.");
183 }
184 
check_alloc()185 fn check_alloc() {
186     info!("Allocating a Vec...");
187     let mut vector: Vec<u32> = vec![1, 2, 3, 4];
188     assert_eq!(vector[0], 1);
189     assert_eq!(vector[1], 2);
190     assert_eq!(vector[2], 3);
191     assert_eq!(vector[3], 4);
192     vector[2] = 42;
193     assert_eq!(vector[2], 42);
194     info!("Vec seems to work.");
195 }
196 
check_dice()197 fn check_dice() {
198     info!("Testing DICE integration...");
199     let hash = diced_open_dice::hash("hello world".as_bytes()).expect("DiceHash failed");
200     assert_eq!(
201         hash,
202         [
203             0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
204             0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
205             0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
206             0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
207             0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f
208         ]
209     );
210 }
211 
212 macro_rules! log_all_levels {
213     ($msg:literal) => {{
214         error!($msg);
215         warn!($msg);
216         info!($msg);
217         debug!($msg);
218         trace!($msg);
219     }};
220 }
221 
emit_suppressed_log()222 fn emit_suppressed_log() {
223     {
224         let _guard = logger::suppress();
225         log_all_levels!("Suppressed message");
226     }
227     log_all_levels!("Unsuppressed message");
228 }
229