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