blob: 888f27300107bd022ecbec1859d76a164b72178b [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]
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000019#![feature(default_alloc_error_handler)]
Andrew Walbraneef98202022-04-27 16:23:06 +000020
21mod exceptions;
Andrew Walbran153aad92022-06-28 15:51:13 +000022mod layout;
Andrew Walbran8217d062022-11-22 16:56:18 +000023mod pci;
Andrew Walbraneef98202022-04-27 16:23:06 +000024
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000025extern crate alloc;
26
Andrew Walbran153aad92022-06-28 15:51:13 +000027use crate::layout::{
David Brazdila51c6f02022-10-12 09:51:48 +000028 bionic_tls, dtb_range, print_addresses, rodata_range, stack_chk_guard, text_range,
29 writable_region, DEVICE_REGION,
Andrew Walbran13564542022-04-20 16:29:45 +000030};
Andrew Walbran8217d062022-11-22 16:56:18 +000031use crate::pci::{check_pci, pci_node, PciMemory32Allocator};
32use aarch64_paging::{idmap::IdMap, paging::Attributes};
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000033use alloc::{vec, vec::Vec};
34use buddy_system_allocator::LockedHeap;
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +000035use core::ffi::CStr;
David Brazdil1baa9a92022-06-28 14:47:50 +010036use libfdt::Fdt;
Andrew Walbran4a59a172022-11-22 17:35:27 +000037use log::{debug, info, trace, LevelFilter};
David Brazdilb41aa8f2022-07-05 12:41:00 +010038use vmbase::{logger, main, println};
Andrew Walbraneef98202022-04-27 16:23:06 +000039
Andrew Walbran8217d062022-11-22 16:56:18 +000040/// PCI MMIO configuration region size.
41const AARCH64_PCI_CFG_SIZE: u64 = 0x1000000;
42
Andrew Walbran5d4e1c92022-04-12 14:30:54 +000043static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
44static mut ZEROED_DATA: [u32; 10] = [0; 10];
45static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
46
Andrew Walbran13564542022-04-20 16:29:45 +000047const ASID: usize = 1;
48const ROOT_LEVEL: usize = 1;
49
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000050#[global_allocator]
51static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();
52
53static mut HEAP: [u8; 65536] = [0; 65536];
54
Andrew Walbraneef98202022-04-27 16:23:06 +000055main!(main);
56
57/// Entry point for VM bootloader.
Andrew Walbrane03395a2022-04-29 15:15:49 +000058pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
David Brazdilb41aa8f2022-07-05 12:41:00 +010059 logger::init(LevelFilter::Debug).unwrap();
60
Andrew Walbraneef98202022-04-27 16:23:06 +000061 println!("Hello world");
David Brazdilb41aa8f2022-07-05 12:41:00 +010062 info!("x0={:#018x}, x1={:#018x}, x2={:#018x}, x3={:#018x}", arg0, arg1, arg2, arg3);
Andrew Walbran6261cf42022-04-12 13:26:52 +000063 print_addresses();
Andrew Walbran153aad92022-06-28 15:51:13 +000064 assert_eq!(arg0, dtb_range().start.0 as u64);
Andrew Walbran5d4e1c92022-04-12 14:30:54 +000065 check_data();
David Brazdila51c6f02022-10-12 09:51:48 +000066 check_stack_guard();
Andrew Walbran8217d062022-11-22 16:56:18 +000067
68 info!("Checking FDT...");
69 let fdt = dtb_range();
70 let fdt =
71 unsafe { core::slice::from_raw_parts_mut(fdt.start.0 as *mut u8, fdt.end.0 - fdt.start.0) };
72 let fdt = Fdt::from_mut_slice(fdt).unwrap();
73 info!("FDT passed verification.");
74 check_fdt(fdt);
75
76 let pci_node = pci_node(fdt);
77 // Parse reg property to find CAM.
78 let pci_reg = pci_node.reg().unwrap().unwrap().next().unwrap();
79 debug!("Found PCI CAM at {:#x}-{:#x}", pci_reg.addr, pci_reg.addr + pci_reg.size.unwrap());
80 // Check that the CAM is the size we expect, so we don't later try accessing it beyond its
81 // bounds. If it is a different size then something is very wrong and we shouldn't continue to
82 // access it; maybe there is some new version of PCI we don't know about.
83 assert_eq!(pci_reg.size.unwrap(), AARCH64_PCI_CFG_SIZE);
84 // Parse ranges property to find memory ranges from which to allocate PCI BARs.
Andrew Walbran0a8dac72022-12-21 13:49:06 +000085 let pci_allocator = PciMemory32Allocator::for_pci_ranges(&pci_node);
Andrew Walbran8217d062022-11-22 16:56:18 +000086
87 modify_fdt(fdt);
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000088
89 unsafe {
Pierre-Clément Tosi581e9b62022-10-27 16:21:13 +010090 HEAP_ALLOCATOR.lock().init(HEAP.as_mut_ptr() as usize, HEAP.len());
Andrew Walbranf7b6dc82022-04-20 16:24:30 +000091 }
92
93 check_alloc();
Andrew Walbran13564542022-04-20 16:29:45 +000094
95 let mut idmap = IdMap::new(ASID, ROOT_LEVEL);
96 idmap.map_range(&DEVICE_REGION, Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER).unwrap();
97 idmap
98 .map_range(
Andrew Walbran153aad92022-06-28 15:51:13 +000099 &text_range().into(),
Andrew Walbran13564542022-04-20 16:29:45 +0000100 Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,
101 )
102 .unwrap();
103 idmap
104 .map_range(
Andrew Walbran153aad92022-06-28 15:51:13 +0000105 &rodata_range().into(),
Andrew Walbran13564542022-04-20 16:29:45 +0000106 Attributes::NORMAL
107 | Attributes::NON_GLOBAL
108 | Attributes::READ_ONLY
109 | Attributes::EXECUTE_NEVER,
110 )
111 .unwrap();
112 idmap
113 .map_range(
114 &writable_region(),
115 Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::EXECUTE_NEVER,
116 )
117 .unwrap();
Andrew Walbran8217d062022-11-22 16:56:18 +0000118 idmap
119 .map_range(
120 &dtb_range().into(),
121 Attributes::NORMAL
122 | Attributes::NON_GLOBAL
123 | Attributes::READ_ONLY
124 | Attributes::EXECUTE_NEVER,
125 )
126 .unwrap();
127 idmap
128 .map_range(
129 &pci_allocator.get_region(),
130 Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER,
131 )
132 .unwrap();
Andrew Walbran13564542022-04-20 16:29:45 +0000133
David Brazdilb41aa8f2022-07-05 12:41:00 +0100134 info!("Activating IdMap...");
Andrew Walbran4a59a172022-11-22 17:35:27 +0000135 trace!("{:?}", idmap);
Andrew Walbran13564542022-04-20 16:29:45 +0000136 idmap.activate();
David Brazdilb41aa8f2022-07-05 12:41:00 +0100137 info!("Activated.");
Andrew Walbran13564542022-04-20 16:29:45 +0000138
139 check_data();
David Brazdil9a83e612022-09-27 17:38:10 +0000140 check_dice();
Andrew Walbran8217d062022-11-22 16:56:18 +0000141
Andrew Walbran0a8dac72022-12-21 13:49:06 +0000142 check_pci(pci_reg);
Andrew Walbran13564542022-04-20 16:29:45 +0000143}
144
David Brazdila51c6f02022-10-12 09:51:48 +0000145fn check_stack_guard() {
146 const BIONIC_TLS_STACK_GRD_OFF: usize = 40;
147
148 info!("Testing stack guard");
149 assert_eq!(bionic_tls(BIONIC_TLS_STACK_GRD_OFF), stack_chk_guard());
150}
151
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000152fn check_data() {
Pierre-Clément Tosi581e9b62022-10-27 16:21:13 +0100153 info!("INITIALISED_DATA: {:?}", INITIALISED_DATA.as_ptr());
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000154 unsafe {
Pierre-Clément Tosi581e9b62022-10-27 16:21:13 +0100155 info!("ZEROED_DATA: {:?}", ZEROED_DATA.as_ptr());
156 info!("MUTABLE_DATA: {:?}", MUTABLE_DATA.as_ptr());
157 info!("HEAP: {:?}", HEAP.as_ptr());
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000158 }
159
160 assert_eq!(INITIALISED_DATA[0], 1);
161 assert_eq!(INITIALISED_DATA[1], 2);
162 assert_eq!(INITIALISED_DATA[2], 3);
163 assert_eq!(INITIALISED_DATA[3], 4);
164
165 unsafe {
166 for element in ZEROED_DATA.iter() {
167 assert_eq!(*element, 0);
168 }
169 ZEROED_DATA[0] = 13;
170 assert_eq!(ZEROED_DATA[0], 13);
171 ZEROED_DATA[0] = 0;
172 assert_eq!(ZEROED_DATA[0], 0);
173
174 assert_eq!(MUTABLE_DATA[0], 1);
175 assert_eq!(MUTABLE_DATA[1], 2);
176 assert_eq!(MUTABLE_DATA[2], 3);
177 assert_eq!(MUTABLE_DATA[3], 4);
178 MUTABLE_DATA[0] += 41;
179 assert_eq!(MUTABLE_DATA[0], 42);
Andrew Walbran13564542022-04-20 16:29:45 +0000180 MUTABLE_DATA[0] -= 41;
181 assert_eq!(MUTABLE_DATA[0], 1);
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000182 }
David Brazdilb41aa8f2022-07-05 12:41:00 +0100183 info!("Data looks good");
Andrew Walbran5d4e1c92022-04-12 14:30:54 +0000184}
185
Andrew Walbran8217d062022-11-22 16:56:18 +0000186fn check_fdt(reader: &Fdt) {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000187 for reg in reader.memory().unwrap().unwrap() {
David Brazdil1baa9a92022-06-28 14:47:50 +0100188 info!("memory @ {reg:#x?}");
189 }
190
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000191 let compatible = CStr::from_bytes_with_nul(b"ns16550a\0").unwrap();
192
193 for c in reader.compatible_nodes(compatible).unwrap() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000194 let reg = c.reg().unwrap().unwrap().next().unwrap();
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000195 info!("node compatible with '{}' at {reg:?}", compatible.to_str().unwrap());
196 }
Andrew Walbran8217d062022-11-22 16:56:18 +0000197}
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000198
Andrew Walbran8217d062022-11-22 16:56:18 +0000199fn modify_fdt(writer: &mut Fdt) {
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000200 writer.unpack().unwrap();
201 info!("FDT successfully unpacked.");
202
203 let path = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000204 let mut node = writer.node_mut(path).unwrap().unwrap();
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000205 let name = CStr::from_bytes_with_nul(b"child\0").unwrap();
206 let mut child = node.add_subnode(name).unwrap();
207 info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
208
209 let name = CStr::from_bytes_with_nul(b"str-property\0").unwrap();
210 child.appendprop(name, b"property-value\0").unwrap();
211 info!("Appended property '{}'.", name.to_str().unwrap());
212
213 let name = CStr::from_bytes_with_nul(b"pair-property\0").unwrap();
214 let addr = 0x0123_4567u64;
215 let size = 0x89ab_cdefu64;
216 child.appendprop_addrrange(name, addr, size).unwrap();
217 info!("Appended property '{}'.", name.to_str().unwrap());
218
219 let writer = child.fdt();
220 writer.pack().unwrap();
221 info!("FDT successfully packed.");
222
David Brazdil1baa9a92022-06-28 14:47:50 +0100223 info!("FDT checks done.");
224}
225
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000226fn check_alloc() {
David Brazdilb41aa8f2022-07-05 12:41:00 +0100227 info!("Allocating a Vec...");
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000228 let mut vector: Vec<u32> = vec![1, 2, 3, 4];
229 assert_eq!(vector[0], 1);
230 assert_eq!(vector[1], 2);
231 assert_eq!(vector[2], 3);
232 assert_eq!(vector[3], 4);
233 vector[2] = 42;
234 assert_eq!(vector[2], 42);
David Brazdilb41aa8f2022-07-05 12:41:00 +0100235 info!("Vec seems to work.");
Andrew Walbranf7b6dc82022-04-20 16:24:30 +0000236}
David Brazdil9a83e612022-09-27 17:38:10 +0000237
238fn check_dice() {
239 info!("Testing DICE integration...");
240 let hash = dice::hash("hello world".as_bytes()).expect("DiceHash failed");
241 assert_eq!(
242 hash,
243 [
244 0x30, 0x9e, 0xcc, 0x48, 0x9c, 0x12, 0xd6, 0xeb, 0x4c, 0xc4, 0x0f, 0x50, 0xc9, 0x02,
245 0xf2, 0xb4, 0xd0, 0xed, 0x77, 0xee, 0x51, 0x1a, 0x7c, 0x7a, 0x9b, 0xcd, 0x3c, 0xa8,
246 0x6d, 0x4c, 0xd8, 0x6f, 0x98, 0x9d, 0xd3, 0x5b, 0xc5, 0xff, 0x49, 0x96, 0x70, 0xda,
247 0x34, 0x25, 0x5b, 0x45, 0xb0, 0xcf, 0xd8, 0x30, 0xe8, 0x1f, 0x60, 0x5d, 0xcf, 0x7d,
248 0xc5, 0x54, 0x2e, 0x93, 0xae, 0x9c, 0xd7, 0x6f
249 ]
250 );
251}