blob: c7ef061adef5c1c667e9d549ef0cefd7179d5790 [file] [log] [blame]
Andrew Walbraneef98202022-04-27 16:23:06 +00001// 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
20mod exceptions;
Andrew Walbran153aad92022-06-28 15:51:13 +000021mod layout;
Andrew Walbran8217d062022-11-22 16:56:18 +000022mod pci;
Andrew Walbraneef98202022-04-27 16:23:06 +000023
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000024extern crate alloc;
25
Pierre-Clément Tosi1ea25a62024-11-02 12:54:40 +000026use crate::layout::{boot_stack_range, print_addresses};
27use crate::pci::{check_pci, get_bar_region, get_cam_region};
Pierre-Clément Tosi9d9cf182024-08-07 16:28:53 +010028use aarch64_paging::paging::VirtualAddress;
Alice Wangcee2c652023-07-05 09:16:52 +000029use aarch64_paging::MapError;
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000030use alloc::{vec, vec::Vec};
Pierre-Clément Tosi5c4bef62024-08-13 22:07:55 +010031use core::mem;
Chariseee5b78342024-04-08 17:59:31 +000032use core::ptr::addr_of_mut;
Pierre-Clément Tosi1bf532b2023-11-13 11:06:20 +000033use cstr::cstr;
David Brazdil1baa9a92022-06-28 14:47:50 +010034use libfdt::Fdt;
Jakob Vukalovicef996292023-04-13 14:28:34 +000035use log::{debug, error, info, trace, warn, LevelFilter};
Alice Wanga3931aa2023-07-05 12:52:09 +000036use vmbase::{
Pierre-Clément Tosif2c19d42024-10-01 17:42:04 +010037 bionic, configure_heap,
38 fdt::pci::PciInfo,
39 generate_image_header,
Pierre-Clément Tosi1ea25a62024-11-02 12:54:40 +000040 layout::{console_uart_page, crosvm::FDT_MAX_SIZE, rodata_range, scratch_range, text_range},
Pierre-Clément Tosi67108c32023-06-30 11:04:02 +000041 linker, logger, main,
Alice Wangcee2c652023-07-05 09:16:52 +000042 memory::{PageTable, SIZE_64KB},
Alice Wanga3931aa2023-07-05 12:52:09 +000043};
Andrew Walbraneef98202022-04-27 16:23:06 +000044
Andrew Walbran5d4e1c92022-04-12 14:30:54 +000045static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
46static mut ZEROED_DATA: [u32; 10] = [0; 10];
47static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
48
Pierre-Clément Tosi1f7c5232024-08-13 19:51:25 +010049generate_image_header!();
Andrew Walbraneef98202022-04-27 16:23:06 +000050main!(main);
Pierre-Clément Tosi6a4808c2023-06-29 09:19:38 +000051configure_heap!(SIZE_64KB);
Andrew Walbraneef98202022-04-27 16:23:06 +000052
Pierre-Clément Tosi5c4bef62024-08-13 22:07:55 +010053fn init_page_table(page_table: &mut PageTable) -> Result<(), MapError> {
Pierre-Clément Tosi1ea25a62024-11-02 12:54:40 +000054 page_table.map_device(&console_uart_page().into())?;
Alice Wangcee2c652023-07-05 09:16:52 +000055 page_table.map_code(&text_range().into())?;
56 page_table.map_rodata(&rodata_range().into())?;
57 page_table.map_data(&scratch_range().into())?;
58 page_table.map_data(&boot_stack_range().into())?;
Alice Wangcee2c652023-07-05 09:16:52 +000059
60 info!("Activating IdMap...");
61 // SAFETY: page_table duplicates the static mappings for everything that the Rust code is
62 // aware of so activating it shouldn't have any visible effect.
63 unsafe {
64 page_table.activate();
65 }
66 info!("Activated.");
67
68 Ok(())
69}
70
Andrew Walbraneef98202022-04-27 16:23:06 +000071/// Entry point for VM bootloader.
Andrew Walbrane03395a2022-04-29 15:15:49 +000072pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
Pierre-Clément Tosid3305482023-06-29 15:03:48 +000073 log::set_max_level(LevelFilter::Debug);
David Brazdilb41aa8f2022-07-05 12:41:00 +010074
Jakob Vukalovicef996292023-04-13 14:28:34 +000075 info!("Hello world");
David Brazdilb41aa8f2022-07-05 12:41:00 +010076 info!("x0={:#018x}, x1={:#018x}, x2={:#018x}, x3={:#018x}", arg0, arg1, arg2, arg3);
Andrew Walbran6261cf42022-04-12 13:26:52 +000077 print_addresses();
Andrew Walbran5d4e1c92022-04-12 14:30:54 +000078 check_data();
David Brazdila51c6f02022-10-12 09:51:48 +000079 check_stack_guard();
Andrew Walbran8217d062022-11-22 16:56:18 +000080
Pierre-Clément Tosi3d1c2e42024-08-13 22:29:46 +010081 let mut page_table = PageTable::default();
82 init_page_table(&mut page_table).unwrap();
83
Andrew Walbran8217d062022-11-22 16:56:18 +000084 info!("Checking FDT...");
Pierre-Clément Tosi9d9cf182024-08-07 16:28:53 +010085 let fdt_addr = usize::try_from(arg0).unwrap();
Andrew Walbran47842802023-07-05 16:56:08 +000086 // SAFETY: The DTB range is valid, writable memory, and we don't construct any aliases to it.
Pierre-Clément Tosi9d9cf182024-08-07 16:28:53 +010087 let fdt = unsafe { core::slice::from_raw_parts_mut(fdt_addr as *mut u8, FDT_MAX_SIZE) };
88 let fdt_region = (VirtualAddress(fdt_addr)..VirtualAddress(fdt_addr + fdt.len())).into();
Pierre-Clément Tosi3d1c2e42024-08-13 22:29:46 +010089 page_table.map_data(&fdt_region).unwrap();
Andrew Walbran8217d062022-11-22 16:56:18 +000090 let fdt = Fdt::from_mut_slice(fdt).unwrap();
91 info!("FDT passed verification.");
92 check_fdt(fdt);
93
Andrew Walbran730375d2022-12-21 14:04:34 +000094 let pci_info = PciInfo::from_fdt(fdt).unwrap();
95 debug!("Found PCI CAM at {:#x}-{:#x}", pci_info.cam_range.start, pci_info.cam_range.end);
Andrew Walbran8217d062022-11-22 16:56:18 +000096
97 modify_fdt(fdt);
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000098
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000099 check_alloc();
Andrew Walbran13564542022-04-20 16:29:45 +0000100
Pierre-Clément Tosi1ea25a62024-11-02 12:54:40 +0000101 let cam_region = get_cam_region(&pci_info);
102 page_table.map_device(&cam_region).unwrap();
Pierre-Clément Tosi3d1c2e42024-08-13 22:29:46 +0100103 let bar_region = get_bar_region(&pci_info);
Pierre-Clément Tosi1ea25a62024-11-02 12:54:40 +0000104 page_table.map_device(&bar_region).unwrap();
Andrew Walbran13564542022-04-20 16:29:45 +0000105
106 check_data();
David Brazdil9a83e612022-09-27 17:38:10 +0000107 check_dice();
Andrew Walbran8217d062022-11-22 16:56:18 +0000108
Andrew Walbran47842802023-07-05 16:56:08 +0000109 // SAFETY: This is the only place where `make_pci_root` is called.
Andrew Walbran730375d2022-12-21 14:04:34 +0000110 let mut pci_root = unsafe { pci_info.make_pci_root() };
111 check_pci(&mut pci_root);
Jakob Vukalovicef996292023-04-13 14:28:34 +0000112
113 emit_suppressed_log();
Pierre-Clément Tosi3d1c2e42024-08-13 22:29:46 +0100114
115 info!("De-activating IdMap...");
116 mem::drop(page_table); // Release PageTable and switch back to idmap.S
117 info!("De-activated.");
Andrew Walbran13564542022-04-20 16:29:45 +0000118}
119
David Brazdila51c6f02022-10-12 09:51:48 +0000120fn check_stack_guard() {
David Brazdila51c6f02022-10-12 09:51:48 +0000121 info!("Testing stack guard");
Pierre-Clément Tosi67108c32023-06-30 11:04:02 +0000122 // SAFETY: No concurrency issue should occur when running these tests.
123 let stack_guard = unsafe { bionic::TLS.stack_guard };
124 assert_ne!(stack_guard, 0);
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +0000125 // Check that a NULL-terminating value is added for C functions consuming strings from stack.
126 assert_eq!(stack_guard.to_ne_bytes().last(), Some(&0));
Pierre-Clément Tosi67108c32023-06-30 11:04:02 +0000127 // Check that the TLS and guard are properly accessible from the dedicated register.
128 assert_eq!(stack_guard, bionic::__get_tls().stack_guard);
129 // Check that the LLVM __stack_chk_guard alias is also properly set up.
130 assert_eq!(
131 stack_guard,
132 // SAFETY: No concurrency issue should occur when running these tests.
133 unsafe { linker::__stack_chk_guard },
134 );
David Brazdila51c6f02022-10-12 09:51:48 +0000135}
136
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000137fn check_data() {
Pierre-Clément Tosi581e9b62022-10-27 16:21:13 +0100138 info!("INITIALISED_DATA: {:?}", INITIALISED_DATA.as_ptr());
Andrew Walbran47842802023-07-05 16:56:08 +0000139 // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000140 info!("ZEROED_DATA: {:?}", unsafe { ZEROED_DATA.as_ptr() });
Andrew Walbran47842802023-07-05 16:56:08 +0000141 // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000142 info!("MUTABLE_DATA: {:?}", unsafe { MUTABLE_DATA.as_ptr() });
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000143
144 assert_eq!(INITIALISED_DATA[0], 1);
145 assert_eq!(INITIALISED_DATA[1], 2);
146 assert_eq!(INITIALISED_DATA[2], 3);
147 assert_eq!(INITIALISED_DATA[3], 4);
148
Andrew Walbran47842802023-07-05 16:56:08 +0000149 // SAFETY: Nowhere else in the program accesses this static mutable variable, so there is no
150 // chance of concurrent access.
Chariseee5b78342024-04-08 17:59:31 +0000151 let zeroed_data = unsafe { &mut *addr_of_mut!(ZEROED_DATA) };
Andrew Walbran47842802023-07-05 16:56:08 +0000152 // SAFETY: Nowhere else in the program accesses this static mutable variable, so there is no
153 // chance of concurrent access.
Chariseeb59cda42024-04-12 19:13:36 +0000154 let mutable_data = unsafe { &mut *addr_of_mut!(MUTABLE_DATA) };
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000155
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000156 for element in zeroed_data.iter() {
157 assert_eq!(*element, 0);
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000158 }
Chariseee5b78342024-04-08 17:59:31 +0000159
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000160 zeroed_data[0] = 13;
161 assert_eq!(zeroed_data[0], 13);
162 zeroed_data[0] = 0;
163 assert_eq!(zeroed_data[0], 0);
164
165 assert_eq!(mutable_data[0], 1);
166 assert_eq!(mutable_data[1], 2);
167 assert_eq!(mutable_data[2], 3);
168 assert_eq!(mutable_data[3], 4);
169 mutable_data[0] += 41;
170 assert_eq!(mutable_data[0], 42);
171 mutable_data[0] -= 41;
172 assert_eq!(mutable_data[0], 1);
173
David Brazdilb41aa8f2022-07-05 12:41:00 +0100174 info!("Data looks good");
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000175}
176
Andrew Walbran8217d062022-11-22 16:56:18 +0000177fn check_fdt(reader: &Fdt) {
Alice Wang2422bdc2023-06-12 08:37:55 +0000178 for reg in reader.memory().unwrap() {
David Brazdil1baa9a92022-06-28 14:47:50 +0100179 info!("memory @ {reg:#x?}");
180 }
181
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000182 let compatible = cstr!("ns16550a");
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000183
184 for c in reader.compatible_nodes(compatible).unwrap() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000185 let reg = c.reg().unwrap().unwrap().next().unwrap();
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000186 info!("node compatible with '{}' at {reg:?}", compatible.to_str().unwrap());
187 }
Andrew Walbran8217d062022-11-22 16:56:18 +0000188}
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000189
Andrew Walbran8217d062022-11-22 16:56:18 +0000190fn modify_fdt(writer: &mut Fdt) {
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000191 writer.unpack().unwrap();
192 info!("FDT successfully unpacked.");
193
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000194 let path = cstr!("/memory");
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +0000195 let node = writer.node_mut(path).unwrap().unwrap();
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000196 let name = cstr!("child");
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000197 let mut child = node.add_subnode(name).unwrap();
198 info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
199
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000200 let name = cstr!("str-property");
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000201 child.appendprop(name, b"property-value\0").unwrap();
202 info!("Appended property '{}'.", name.to_str().unwrap());
203
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000204 let name = cstr!("pair-property");
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000205 let addr = 0x0123_4567u64;
206 let size = 0x89ab_cdefu64;
207 child.appendprop_addrrange(name, addr, size).unwrap();
208 info!("Appended property '{}'.", name.to_str().unwrap());
209
210 let writer = child.fdt();
211 writer.pack().unwrap();
212 info!("FDT successfully packed.");
213
David Brazdil1baa9a92022-06-28 14:47:50 +0100214 info!("FDT checks done.");
215}
216
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000217fn check_alloc() {
David Brazdilb41aa8f2022-07-05 12:41:00 +0100218 info!("Allocating a Vec...");
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000219 let mut vector: Vec<u32> = vec![1, 2, 3, 4];
220 assert_eq!(vector[0], 1);
221 assert_eq!(vector[1], 2);
222 assert_eq!(vector[2], 3);
223 assert_eq!(vector[3], 4);
224 vector[2] = 42;
225 assert_eq!(vector[2], 42);
David Brazdilb41aa8f2022-07-05 12:41:00 +0100226 info!("Vec seems to work.");
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000227}
David Brazdil9a83e612022-09-27 17:38:10 +0000228
229fn check_dice() {
230 info!("Testing DICE integration...");
Alice Wangcb9d2f92023-02-06 10:29:00 +0000231 let hash = diced_open_dice::hash("hello world".as_bytes()).expect("DiceHash failed");
David Brazdil9a83e612022-09-27 17:38:10 +0000232 assert_eq!(
233 hash,
234 [
235 0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
236 0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
237 0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
238 0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
239 0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f
240 ]
241 );
242}
Jakob Vukalovicef996292023-04-13 14:28:34 +0000243
244macro_rules! log_all_levels {
245 ($msg:literal) => {{
246 error!($msg);
247 warn!($msg);
248 info!($msg);
249 debug!($msg);
250 trace!($msg);
251 }};
252}
253
254fn emit_suppressed_log() {
255 {
256 let _guard = logger::suppress();
257 log_all_levels!("Suppressed message");
258 }
259 log_all_levels!("Unsuppressed message");
260}