• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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