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::{
27 bionic_tls, boot_stack_range, dtb_range, print_addresses, rodata_range, scratch_range,
28 stack_chk_guard, text_range, DEVICE_REGION,
29 };
30 use crate::pci::{check_pci, get_bar_region};
31 use aarch64_paging::{idmap::IdMap, paging::Attributes};
32 use alloc::{vec, vec::Vec};
33 use buddy_system_allocator::LockedHeap;
34 use core::ffi::CStr;
35 use fdtpci::PciInfo;
36 use libfdt::Fdt;
37 use log::{debug, error, info, trace, warn, LevelFilter};
38 use vmbase::{logger, main};
39
40 static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
41 static mut ZEROED_DATA: [u32; 10] = [0; 10];
42 static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
43
44 const ASID: usize = 1;
45 const ROOT_LEVEL: usize = 1;
46
47 #[global_allocator]
48 static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();
49
50 static mut HEAP: [u8; 65536] = [0; 65536];
51
52 main!(main);
53
54 /// Entry point for VM bootloader.
main(arg0: u64, arg1: u64, arg2: u64, arg3: u64)55 pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
56 logger::init(LevelFilter::Debug).unwrap();
57
58 info!("Hello world");
59 info!("x0={:#018x}, x1={:#018x}, x2={:#018x}, x3={:#018x}", arg0, arg1, arg2, arg3);
60 print_addresses();
61 assert_eq!(arg0, dtb_range().start.0 as u64);
62 check_data();
63 check_stack_guard();
64
65 info!("Checking FDT...");
66 let fdt = dtb_range();
67 let fdt =
68 unsafe { core::slice::from_raw_parts_mut(fdt.start.0 as *mut u8, fdt.end.0 - fdt.start.0) };
69 let fdt = Fdt::from_mut_slice(fdt).unwrap();
70 info!("FDT passed verification.");
71 check_fdt(fdt);
72
73 let pci_info = PciInfo::from_fdt(fdt).unwrap();
74 debug!("Found PCI CAM at {:#x}-{:#x}", pci_info.cam_range.start, pci_info.cam_range.end);
75
76 modify_fdt(fdt);
77
78 unsafe {
79 HEAP_ALLOCATOR.lock().init(HEAP.as_mut_ptr() as usize, HEAP.len());
80 }
81
82 check_alloc();
83
84 let mut idmap = IdMap::new(ASID, ROOT_LEVEL);
85 idmap.map_range(&DEVICE_REGION, Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER).unwrap();
86 idmap
87 .map_range(
88 &text_range().into(),
89 Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,
90 )
91 .unwrap();
92 idmap
93 .map_range(
94 &rodata_range().into(),
95 Attributes::NORMAL
96 | Attributes::NON_GLOBAL
97 | Attributes::READ_ONLY
98 | Attributes::EXECUTE_NEVER,
99 )
100 .unwrap();
101 idmap
102 .map_range(
103 &scratch_range().into(),
104 Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::EXECUTE_NEVER,
105 )
106 .unwrap();
107 idmap
108 .map_range(
109 &boot_stack_range().into(),
110 Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::EXECUTE_NEVER,
111 )
112 .unwrap();
113 idmap
114 .map_range(
115 &dtb_range().into(),
116 Attributes::NORMAL
117 | Attributes::NON_GLOBAL
118 | Attributes::READ_ONLY
119 | Attributes::EXECUTE_NEVER,
120 )
121 .unwrap();
122 idmap
123 .map_range(&get_bar_region(&pci_info), Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER)
124 .unwrap();
125
126 info!("Activating IdMap...");
127 trace!("{:?}", idmap);
128 idmap.activate();
129 info!("Activated.");
130
131 check_data();
132 check_dice();
133
134 let mut pci_root = unsafe { pci_info.make_pci_root() };
135 check_pci(&mut pci_root);
136
137 emit_suppressed_log();
138 }
139
check_stack_guard()140 fn check_stack_guard() {
141 const BIONIC_TLS_STACK_GRD_OFF: usize = 40;
142
143 info!("Testing stack guard");
144 assert_eq!(bionic_tls(BIONIC_TLS_STACK_GRD_OFF), stack_chk_guard());
145 }
146
check_data()147 fn check_data() {
148 info!("INITIALISED_DATA: {:?}", INITIALISED_DATA.as_ptr());
149 unsafe {
150 info!("ZEROED_DATA: {:?}", ZEROED_DATA.as_ptr());
151 info!("MUTABLE_DATA: {:?}", MUTABLE_DATA.as_ptr());
152 info!("HEAP: {:?}", HEAP.as_ptr());
153 }
154
155 assert_eq!(INITIALISED_DATA[0], 1);
156 assert_eq!(INITIALISED_DATA[1], 2);
157 assert_eq!(INITIALISED_DATA[2], 3);
158 assert_eq!(INITIALISED_DATA[3], 4);
159
160 unsafe {
161 for element in ZEROED_DATA.iter() {
162 assert_eq!(*element, 0);
163 }
164 ZEROED_DATA[0] = 13;
165 assert_eq!(ZEROED_DATA[0], 13);
166 ZEROED_DATA[0] = 0;
167 assert_eq!(ZEROED_DATA[0], 0);
168
169 assert_eq!(MUTABLE_DATA[0], 1);
170 assert_eq!(MUTABLE_DATA[1], 2);
171 assert_eq!(MUTABLE_DATA[2], 3);
172 assert_eq!(MUTABLE_DATA[3], 4);
173 MUTABLE_DATA[0] += 41;
174 assert_eq!(MUTABLE_DATA[0], 42);
175 MUTABLE_DATA[0] -= 41;
176 assert_eq!(MUTABLE_DATA[0], 1);
177 }
178 info!("Data looks good");
179 }
180
check_fdt(reader: &Fdt)181 fn check_fdt(reader: &Fdt) {
182 for reg in reader.memory().unwrap().unwrap() {
183 info!("memory @ {reg:#x?}");
184 }
185
186 let compatible = CStr::from_bytes_with_nul(b"ns16550a\0").unwrap();
187
188 for c in reader.compatible_nodes(compatible).unwrap() {
189 let reg = c.reg().unwrap().unwrap().next().unwrap();
190 info!("node compatible with '{}' at {reg:?}", compatible.to_str().unwrap());
191 }
192 }
193
modify_fdt(writer: &mut Fdt)194 fn modify_fdt(writer: &mut Fdt) {
195 writer.unpack().unwrap();
196 info!("FDT successfully unpacked.");
197
198 let path = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
199 let mut node = writer.node_mut(path).unwrap().unwrap();
200 let name = CStr::from_bytes_with_nul(b"child\0").unwrap();
201 let mut child = node.add_subnode(name).unwrap();
202 info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
203
204 let name = CStr::from_bytes_with_nul(b"str-property\0").unwrap();
205 child.appendprop(name, b"property-value\0").unwrap();
206 info!("Appended property '{}'.", name.to_str().unwrap());
207
208 let name = CStr::from_bytes_with_nul(b"pair-property\0").unwrap();
209 let addr = 0x0123_4567u64;
210 let size = 0x89ab_cdefu64;
211 child.appendprop_addrrange(name, addr, size).unwrap();
212 info!("Appended property '{}'.", name.to_str().unwrap());
213
214 let writer = child.fdt();
215 writer.pack().unwrap();
216 info!("FDT successfully packed.");
217
218 info!("FDT checks done.");
219 }
220
check_alloc()221 fn check_alloc() {
222 info!("Allocating a Vec...");
223 let mut vector: Vec<u32> = vec![1, 2, 3, 4];
224 assert_eq!(vector[0], 1);
225 assert_eq!(vector[1], 2);
226 assert_eq!(vector[2], 3);
227 assert_eq!(vector[3], 4);
228 vector[2] = 42;
229 assert_eq!(vector[2], 42);
230 info!("Vec seems to work.");
231 }
232
check_dice()233 fn check_dice() {
234 info!("Testing DICE integration...");
235 let hash = diced_open_dice::hash("hello world".as_bytes()).expect("DiceHash failed");
236 assert_eq!(
237 hash,
238 [
239 0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
240 0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
241 0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
242 0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
243 0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f
244 ]
245 );
246 }
247
248 macro_rules! log_all_levels {
249 ($msg:literal) => {{
250 error!($msg);
251 warn!($msg);
252 info!($msg);
253 debug!($msg);
254 trace!($msg);
255 }};
256 }
257
emit_suppressed_log()258 fn emit_suppressed_log() {
259 {
260 let _guard = logger::suppress();
261 log_all_levels!("Suppressed message");
262 }
263 log_all_levels!("Unsuppressed message");
264 }
265