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