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 libfdt::Fdt;
30 use log::{debug, error, info, trace, warn, LevelFilter};
31 use spin::mutex::SpinMutex;
32 use vmbase::{
33 arch::linker,
34 bionic, configure_heap,
35 fdt::pci::PciInfo,
36 generate_image_header,
37 layout::crosvm::FDT_MAX_SIZE,
38 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 ZEROED_DATA: SpinMutex<[u32; 10]> = SpinMutex::new([0; 10]);
44 static MUTABLE_DATA: SpinMutex<[u32; 4]> = SpinMutex::new([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
108 assert_eq!(INITIALISED_DATA[0], 1);
109 assert_eq!(INITIALISED_DATA[1], 2);
110 assert_eq!(INITIALISED_DATA[2], 3);
111 assert_eq!(INITIALISED_DATA[3], 4);
112
113 let zeroed_data = &mut *ZEROED_DATA.lock();
114 let mutable_data = &mut *MUTABLE_DATA.lock();
115 info!("ZEROED_DATA: {:?}", zeroed_data.as_ptr());
116 info!("MUTABLE_DATA: {:?}", mutable_data.as_ptr());
117
118 for element in zeroed_data.iter() {
119 assert_eq!(*element, 0);
120 }
121
122 zeroed_data[0] = 13;
123 assert_eq!(zeroed_data[0], 13);
124 zeroed_data[0] = 0;
125 assert_eq!(zeroed_data[0], 0);
126
127 assert_eq!(mutable_data[0], 1);
128 assert_eq!(mutable_data[1], 2);
129 assert_eq!(mutable_data[2], 3);
130 assert_eq!(mutable_data[3], 4);
131 mutable_data[0] += 41;
132 assert_eq!(mutable_data[0], 42);
133 mutable_data[0] -= 41;
134 assert_eq!(mutable_data[0], 1);
135
136 info!("Data looks good");
137 }
138
check_fdt(reader: &Fdt)139 fn check_fdt(reader: &Fdt) {
140 for reg in reader.memory().unwrap() {
141 info!("memory @ {reg:#x?}");
142 }
143
144 let compatible = c"ns16550a";
145
146 for c in reader.compatible_nodes(compatible).unwrap() {
147 let reg = c.reg().unwrap().unwrap().next().unwrap();
148 info!("node compatible with '{}' at {reg:?}", compatible.to_str().unwrap());
149 }
150 }
151
modify_fdt(writer: &mut Fdt)152 fn modify_fdt(writer: &mut Fdt) {
153 writer.unpack().unwrap();
154 info!("FDT successfully unpacked.");
155
156 let path = c"/memory";
157 let node = writer.node_mut(path).unwrap().unwrap();
158 let name = c"child";
159 let mut child = node.add_subnode(name).unwrap();
160 info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
161
162 let name = c"str-property";
163 child.appendprop(name, b"property-value\0").unwrap();
164 info!("Appended property '{}'.", name.to_str().unwrap());
165
166 let name = c"pair-property";
167 let addr = 0x0123_4567u64;
168 let size = 0x89ab_cdefu64;
169 child.appendprop_addrrange(name, addr, size).unwrap();
170 info!("Appended property '{}'.", name.to_str().unwrap());
171
172 let writer = child.fdt();
173 writer.pack().unwrap();
174 info!("FDT successfully packed.");
175
176 info!("FDT checks done.");
177 }
178
check_alloc()179 fn check_alloc() {
180 info!("Allocating a Vec...");
181 let mut vector: Vec<u32> = vec![1, 2, 3, 4];
182 assert_eq!(vector[0], 1);
183 assert_eq!(vector[1], 2);
184 assert_eq!(vector[2], 3);
185 assert_eq!(vector[3], 4);
186 vector[2] = 42;
187 assert_eq!(vector[2], 42);
188 info!("Vec seems to work.");
189 }
190
check_dice()191 fn check_dice() {
192 info!("Testing DICE integration...");
193 let hash = diced_open_dice::hash("hello world".as_bytes()).expect("DiceHash failed");
194 assert_eq!(
195 hash,
196 [
197 0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
198 0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
199 0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
200 0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
201 0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f
202 ]
203 );
204 }
205
206 macro_rules! log_all_levels {
207 ($msg:literal) => {{
208 error!($msg);
209 warn!($msg);
210 info!($msg);
211 debug!($msg);
212 trace!($msg);
213 }};
214 }
215
emit_suppressed_log()216 fn emit_suppressed_log() {
217 {
218 let _guard = logger::suppress();
219 log_all_levels!("Suppressed message");
220 }
221 log_all_levels!("Unsuppressed message");
222 }
223