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