blob: 7a3f427d6caa4e9123768d957a4abca74c5b3a83 [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 Tosi67108c32023-06-30 11:04:02 +000026use crate::layout::{boot_stack_range, print_addresses, DEVICE_REGION};
Andrew Walbran730375d2022-12-21 14:04:34 +000027use crate::pci::{check_pci, get_bar_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;
Andrew Walbran730375d2022-12-21 14:04:34 +000034use fdtpci::PciInfo;
David Brazdil1baa9a92022-06-28 14:47:50 +010035use libfdt::Fdt;
Jakob Vukalovicef996292023-04-13 14:28:34 +000036use log::{debug, error, info, trace, warn, LevelFilter};
Alice Wanga3931aa2023-07-05 12:52:09 +000037use vmbase::{
Pierre-Clément Tosi1f7c5232024-08-13 19:51:25 +010038 bionic, configure_heap, generate_image_header,
Pierre-Clément Tosi3d1c2e42024-08-13 22:29:46 +010039 layout::{crosvm::FDT_MAX_SIZE, rodata_range, scratch_range, text_range},
Pierre-Clément Tosi67108c32023-06-30 11:04:02 +000040 linker, logger, main,
Alice Wangcee2c652023-07-05 09:16:52 +000041 memory::{PageTable, SIZE_64KB},
Pierre-Clément Tosi3d1c2e42024-08-13 22:29:46 +010042 util::RangeExt as _,
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> {
Alice Wangcee2c652023-07-05 09:16:52 +000054 page_table.map_device(&DEVICE_REGION)?;
55 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 Tosi3d1c2e42024-08-13 22:29:46 +0100101 let bar_region = get_bar_region(&pci_info);
102 if bar_region.is_within(&DEVICE_REGION) {
103 // Avoid a MapError::BreakBeforeMakeViolation.
104 info!("BAR region is within already mapped device region: skipping page table ops.");
105 } else {
106 page_table.map_device(&bar_region).unwrap();
107 }
Andrew Walbran13564542022-04-20 16:29:45 +0000108
109 check_data();
David Brazdil9a83e612022-09-27 17:38:10 +0000110 check_dice();
Andrew Walbran8217d062022-11-22 16:56:18 +0000111
Andrew Walbran47842802023-07-05 16:56:08 +0000112 // SAFETY: This is the only place where `make_pci_root` is called.
Andrew Walbran730375d2022-12-21 14:04:34 +0000113 let mut pci_root = unsafe { pci_info.make_pci_root() };
114 check_pci(&mut pci_root);
Jakob Vukalovicef996292023-04-13 14:28:34 +0000115
116 emit_suppressed_log();
Pierre-Clément Tosi3d1c2e42024-08-13 22:29:46 +0100117
118 info!("De-activating IdMap...");
119 mem::drop(page_table); // Release PageTable and switch back to idmap.S
120 info!("De-activated.");
Andrew Walbran13564542022-04-20 16:29:45 +0000121}
122
David Brazdila51c6f02022-10-12 09:51:48 +0000123fn check_stack_guard() {
David Brazdila51c6f02022-10-12 09:51:48 +0000124 info!("Testing stack guard");
Pierre-Clément Tosi67108c32023-06-30 11:04:02 +0000125 // SAFETY: No concurrency issue should occur when running these tests.
126 let stack_guard = unsafe { bionic::TLS.stack_guard };
127 assert_ne!(stack_guard, 0);
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +0000128 // Check that a NULL-terminating value is added for C functions consuming strings from stack.
129 assert_eq!(stack_guard.to_ne_bytes().last(), Some(&0));
Pierre-Clément Tosi67108c32023-06-30 11:04:02 +0000130 // Check that the TLS and guard are properly accessible from the dedicated register.
131 assert_eq!(stack_guard, bionic::__get_tls().stack_guard);
132 // Check that the LLVM __stack_chk_guard alias is also properly set up.
133 assert_eq!(
134 stack_guard,
135 // SAFETY: No concurrency issue should occur when running these tests.
136 unsafe { linker::__stack_chk_guard },
137 );
David Brazdila51c6f02022-10-12 09:51:48 +0000138}
139
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000140fn check_data() {
Pierre-Clément Tosi581e9b62022-10-27 16:21:13 +0100141 info!("INITIALISED_DATA: {:?}", INITIALISED_DATA.as_ptr());
Andrew Walbran47842802023-07-05 16:56:08 +0000142 // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000143 info!("ZEROED_DATA: {:?}", unsafe { ZEROED_DATA.as_ptr() });
Andrew Walbran47842802023-07-05 16:56:08 +0000144 // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000145 info!("MUTABLE_DATA: {:?}", unsafe { MUTABLE_DATA.as_ptr() });
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000146
147 assert_eq!(INITIALISED_DATA[0], 1);
148 assert_eq!(INITIALISED_DATA[1], 2);
149 assert_eq!(INITIALISED_DATA[2], 3);
150 assert_eq!(INITIALISED_DATA[3], 4);
151
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.
Chariseee5b78342024-04-08 17:59:31 +0000154 let zeroed_data = unsafe { &mut *addr_of_mut!(ZEROED_DATA) };
Andrew Walbran47842802023-07-05 16:56:08 +0000155 // SAFETY: Nowhere else in the program accesses this static mutable variable, so there is no
156 // chance of concurrent access.
Chariseeb59cda42024-04-12 19:13:36 +0000157 let mutable_data = unsafe { &mut *addr_of_mut!(MUTABLE_DATA) };
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000158
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000159 for element in zeroed_data.iter() {
160 assert_eq!(*element, 0);
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000161 }
Chariseee5b78342024-04-08 17:59:31 +0000162
Pierre-Clément Tosi70b580c2023-07-07 16:26:45 +0000163 zeroed_data[0] = 13;
164 assert_eq!(zeroed_data[0], 13);
165 zeroed_data[0] = 0;
166 assert_eq!(zeroed_data[0], 0);
167
168 assert_eq!(mutable_data[0], 1);
169 assert_eq!(mutable_data[1], 2);
170 assert_eq!(mutable_data[2], 3);
171 assert_eq!(mutable_data[3], 4);
172 mutable_data[0] += 41;
173 assert_eq!(mutable_data[0], 42);
174 mutable_data[0] -= 41;
175 assert_eq!(mutable_data[0], 1);
176
David Brazdilb41aa8f2022-07-05 12:41:00 +0100177 info!("Data looks good");
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000178}
179
Andrew Walbran8217d062022-11-22 16:56:18 +0000180fn check_fdt(reader: &Fdt) {
Alice Wang2422bdc2023-06-12 08:37:55 +0000181 for reg in reader.memory().unwrap() {
David Brazdil1baa9a92022-06-28 14:47:50 +0100182 info!("memory @ {reg:#x?}");
183 }
184
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000185 let compatible = cstr!("ns16550a");
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000186
187 for c in reader.compatible_nodes(compatible).unwrap() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000188 let reg = c.reg().unwrap().unwrap().next().unwrap();
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000189 info!("node compatible with '{}' at {reg:?}", compatible.to_str().unwrap());
190 }
Andrew Walbran8217d062022-11-22 16:56:18 +0000191}
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000192
Andrew Walbran8217d062022-11-22 16:56:18 +0000193fn modify_fdt(writer: &mut Fdt) {
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000194 writer.unpack().unwrap();
195 info!("FDT successfully unpacked.");
196
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000197 let path = cstr!("/memory");
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +0000198 let node = writer.node_mut(path).unwrap().unwrap();
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000199 let name = cstr!("child");
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000200 let mut child = node.add_subnode(name).unwrap();
201 info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
202
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000203 let name = cstr!("str-property");
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000204 child.appendprop(name, b"property-value\0").unwrap();
205 info!("Appended property '{}'.", name.to_str().unwrap());
206
Pierre-Clément Tosi8ecc78b2023-06-13 12:41:13 +0000207 let name = cstr!("pair-property");
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000208 let addr = 0x0123_4567u64;
209 let size = 0x89ab_cdefu64;
210 child.appendprop_addrrange(name, addr, size).unwrap();
211 info!("Appended property '{}'.", name.to_str().unwrap());
212
213 let writer = child.fdt();
214 writer.pack().unwrap();
215 info!("FDT successfully packed.");
216
David Brazdil1baa9a92022-06-28 14:47:50 +0100217 info!("FDT checks done.");
218}
219
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000220fn check_alloc() {
David Brazdilb41aa8f2022-07-05 12:41:00 +0100221 info!("Allocating a Vec...");
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000222 let mut vector: Vec<u32> = vec![1, 2, 3, 4];
223 assert_eq!(vector[0], 1);
224 assert_eq!(vector[1], 2);
225 assert_eq!(vector[2], 3);
226 assert_eq!(vector[3], 4);
227 vector[2] = 42;
228 assert_eq!(vector[2], 42);
David Brazdilb41aa8f2022-07-05 12:41:00 +0100229 info!("Vec seems to work.");
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000230}
David Brazdil9a83e612022-09-27 17:38:10 +0000231
232fn check_dice() {
233 info!("Testing DICE integration...");
Alice Wangcb9d2f92023-02-06 10:29:00 +0000234 let hash = diced_open_dice::hash("hello world".as_bytes()).expect("DiceHash failed");
David Brazdil9a83e612022-09-27 17:38:10 +0000235 assert_eq!(
236 hash,
237 [
238 0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
239 0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
240 0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
241 0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
242 0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f
243 ]
244 );
245}
Jakob Vukalovicef996292023-04-13 14:28:34 +0000246
247macro_rules! log_all_levels {
248 ($msg:literal) => {{
249 error!($msg);
250 warn!($msg);
251 info!($msg);
252 debug!($msg);
253 trace!($msg);
254 }};
255}
256
257fn emit_suppressed_log() {
258 {
259 let _guard = logger::suppress();
260 log_all_levels!("Suppressed message");
261 }
262 log_all_levels!("Unsuppressed message");
263}