1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::collections::BTreeMap;
6 use std::fs::File;
7 use std::path::PathBuf;
8
9 use arch::CpuSet;
10 use arch::SERIAL_ADDR;
11 use cros_fdt::Error;
12 use cros_fdt::FdtWriter;
13 use cros_fdt::Result;
14 // This is a Battery related constant
15 use devices::bat::GOLDFISHBAT_MMIO_LEN;
16 use devices::pl030::PL030_AMBA_ID;
17 use devices::PciAddress;
18 use devices::PciInterruptPin;
19 use hypervisor::PsciVersion;
20 use hypervisor::VmAArch64;
21 use hypervisor::PSCI_0_2;
22 use hypervisor::PSCI_1_0;
23 use rand::rngs::OsRng;
24 use rand::RngCore;
25 use vm_memory::GuestAddress;
26 use vm_memory::GuestMemory;
27
28 // These are GIC address-space location constants.
29 use crate::AARCH64_GIC_CPUI_BASE;
30 use crate::AARCH64_GIC_CPUI_SIZE;
31 use crate::AARCH64_GIC_DIST_BASE;
32 use crate::AARCH64_GIC_DIST_SIZE;
33 use crate::AARCH64_GIC_REDIST_SIZE;
34 use crate::AARCH64_PMU_IRQ;
35 use crate::AARCH64_PROTECTED_VM_FW_START;
36 // These are RTC related constants
37 use crate::AARCH64_RTC_ADDR;
38 use crate::AARCH64_RTC_IRQ;
39 use crate::AARCH64_RTC_SIZE;
40 // These are serial device related constants.
41 use crate::AARCH64_SERIAL_1_3_IRQ;
42 use crate::AARCH64_SERIAL_2_4_IRQ;
43 use crate::AARCH64_SERIAL_SIZE;
44 use crate::AARCH64_SERIAL_SPEED;
45
46 // This is an arbitrary number to specify the node for the GIC.
47 // If we had a more complex interrupt architecture, then we'd need an enum for
48 // these.
49 const PHANDLE_GIC: u32 = 1;
50 const PHANDLE_RESTRICTED_DMA_POOL: u32 = 2;
51
52 // CPUs are assigned phandles starting with this number.
53 const PHANDLE_CPU0: u32 = 0x100;
54
55 // These are specified by the Linux GIC bindings
56 const GIC_FDT_IRQ_NUM_CELLS: u32 = 3;
57 const GIC_FDT_IRQ_TYPE_SPI: u32 = 0;
58 const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
59 const GIC_FDT_IRQ_PPI_CPU_SHIFT: u32 = 8;
60 const GIC_FDT_IRQ_PPI_CPU_MASK: u32 = 0xff << GIC_FDT_IRQ_PPI_CPU_SHIFT;
61 const IRQ_TYPE_EDGE_RISING: u32 = 0x00000001;
62 const IRQ_TYPE_LEVEL_HIGH: u32 = 0x00000004;
63 const IRQ_TYPE_LEVEL_LOW: u32 = 0x00000008;
64
create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemory) -> Result<()>65 fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemory) -> Result<()> {
66 let mut mem_reg_prop = Vec::new();
67 let mut previous_memory_region_end = None;
68 let mut regions = guest_mem.guest_memory_regions();
69 regions.sort();
70 for region in regions {
71 if region.0.offset() == AARCH64_PROTECTED_VM_FW_START {
72 continue;
73 }
74 // Merge with the previous region if possible.
75 if let Some(previous_end) = previous_memory_region_end {
76 if region.0 == previous_end {
77 *mem_reg_prop.last_mut().unwrap() += region.1 as u64;
78 previous_memory_region_end =
79 Some(previous_end.checked_add(region.1 as u64).unwrap());
80 continue;
81 }
82 assert!(region.0 > previous_end, "Memory regions overlap");
83 }
84
85 mem_reg_prop.push(region.0.offset());
86 mem_reg_prop.push(region.1 as u64);
87 previous_memory_region_end = Some(region.0.checked_add(region.1 as u64).unwrap());
88 }
89
90 let memory_node = fdt.begin_node("memory")?;
91 fdt.property_string("device_type", "memory")?;
92 fdt.property_array_u64("reg", &mem_reg_prop)?;
93 fdt.end_node(memory_node)?;
94
95 Ok(())
96 }
97
create_resv_memory_node( fdt: &mut FdtWriter, resv_addr_and_size: (Option<GuestAddress>, u64), ) -> Result<u32>98 fn create_resv_memory_node(
99 fdt: &mut FdtWriter,
100 resv_addr_and_size: (Option<GuestAddress>, u64),
101 ) -> Result<u32> {
102 let (resv_addr, resv_size) = resv_addr_and_size;
103
104 let resv_memory_node = fdt.begin_node("reserved-memory")?;
105 fdt.property_u32("#address-cells", 0x2)?;
106 fdt.property_u32("#size-cells", 0x2)?;
107 fdt.property_null("ranges")?;
108
109 let restricted_dma_pool = if let Some(resv_addr) = resv_addr {
110 let node = fdt.begin_node(&format!("restricted_dma_reserved@{:x}", resv_addr.0))?;
111 fdt.property_array_u64("reg", &[resv_addr.0, resv_size])?;
112 node
113 } else {
114 fdt.begin_node("restricted_dma_reserved")?
115 };
116 fdt.property_u32("phandle", PHANDLE_RESTRICTED_DMA_POOL)?;
117 fdt.property_string("compatible", "restricted-dma-pool")?;
118 fdt.property_u64("size", resv_size)?;
119 fdt.property_u64("alignment", base::pagesize() as u64)?;
120 fdt.end_node(restricted_dma_pool)?;
121
122 fdt.end_node(resv_memory_node)?;
123 Ok(PHANDLE_RESTRICTED_DMA_POOL)
124 }
125
create_cpu_nodes( fdt: &mut FdtWriter, num_cpus: u32, cpu_clusters: Vec<CpuSet>, cpu_capacity: BTreeMap<usize, u32>, ) -> Result<()>126 fn create_cpu_nodes(
127 fdt: &mut FdtWriter,
128 num_cpus: u32,
129 cpu_clusters: Vec<CpuSet>,
130 cpu_capacity: BTreeMap<usize, u32>,
131 ) -> Result<()> {
132 let cpus_node = fdt.begin_node("cpus")?;
133 fdt.property_u32("#address-cells", 0x1)?;
134 fdt.property_u32("#size-cells", 0x0)?;
135
136 for cpu_id in 0..num_cpus {
137 let cpu_name = format!("cpu@{:x}", cpu_id);
138 let cpu_node = fdt.begin_node(&cpu_name)?;
139 fdt.property_string("device_type", "cpu")?;
140 fdt.property_string("compatible", "arm,arm-v8")?;
141 if num_cpus > 1 {
142 fdt.property_string("enable-method", "psci")?;
143 }
144 fdt.property_u32("reg", cpu_id)?;
145 fdt.property_u32("phandle", PHANDLE_CPU0 + cpu_id)?;
146
147 if let Some(capacity) = cpu_capacity.get(&(cpu_id as usize)) {
148 fdt.property_u32("capacity-dmips-mhz", *capacity)?;
149 }
150
151 fdt.end_node(cpu_node)?;
152 }
153
154 if !cpu_clusters.is_empty() {
155 let cpu_map_node = fdt.begin_node("cpu-map")?;
156 for (cluster_idx, cpus) in cpu_clusters.iter().enumerate() {
157 let cluster_node = fdt.begin_node(&format!("cluster{}", cluster_idx))?;
158 for (core_idx, cpu_id) in cpus.iter().enumerate() {
159 let core_node = fdt.begin_node(&format!("core{}", core_idx))?;
160 fdt.property_u32("cpu", PHANDLE_CPU0 + *cpu_id as u32)?;
161 fdt.end_node(core_node)?;
162 }
163 fdt.end_node(cluster_node)?;
164 }
165 fdt.end_node(cpu_map_node)?;
166 }
167
168 fdt.end_node(cpus_node)?;
169 Ok(())
170 }
171
create_gic_node(fdt: &mut FdtWriter, is_gicv3: bool, num_cpus: u64) -> Result<()>172 fn create_gic_node(fdt: &mut FdtWriter, is_gicv3: bool, num_cpus: u64) -> Result<()> {
173 let mut gic_reg_prop = [AARCH64_GIC_DIST_BASE, AARCH64_GIC_DIST_SIZE, 0, 0];
174
175 let intc_node = fdt.begin_node("intc")?;
176 if is_gicv3 {
177 fdt.property_string("compatible", "arm,gic-v3")?;
178 gic_reg_prop[2] = AARCH64_GIC_DIST_BASE - (AARCH64_GIC_REDIST_SIZE * num_cpus);
179 gic_reg_prop[3] = AARCH64_GIC_REDIST_SIZE * num_cpus;
180 } else {
181 fdt.property_string("compatible", "arm,cortex-a15-gic")?;
182 gic_reg_prop[2] = AARCH64_GIC_CPUI_BASE;
183 gic_reg_prop[3] = AARCH64_GIC_CPUI_SIZE;
184 }
185 fdt.property_u32("#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS)?;
186 fdt.property_null("interrupt-controller")?;
187 fdt.property_array_u64("reg", &gic_reg_prop)?;
188 fdt.property_u32("phandle", PHANDLE_GIC)?;
189 fdt.property_u32("#address-cells", 2)?;
190 fdt.property_u32("#size-cells", 2)?;
191 fdt.end_node(intc_node)?;
192
193 Ok(())
194 }
195
create_timer_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()>196 fn create_timer_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()> {
197 // These are fixed interrupt numbers for the timer device.
198 let irqs = [13, 14, 11, 10];
199 let compatible = "arm,armv8-timer";
200 let cpu_mask: u32 =
201 (((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK;
202
203 let mut timer_reg_cells = Vec::new();
204 for &irq in &irqs {
205 timer_reg_cells.push(GIC_FDT_IRQ_TYPE_PPI);
206 timer_reg_cells.push(irq);
207 timer_reg_cells.push(cpu_mask | IRQ_TYPE_LEVEL_LOW);
208 }
209
210 let timer_node = fdt.begin_node("timer")?;
211 fdt.property_string("compatible", compatible)?;
212 fdt.property_array_u32("interrupts", &timer_reg_cells)?;
213 fdt.property_null("always-on")?;
214 fdt.end_node(timer_node)?;
215
216 Ok(())
217 }
218
create_pmu_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()>219 fn create_pmu_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()> {
220 let compatible = "arm,armv8-pmuv3";
221 let cpu_mask: u32 =
222 (((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK;
223 let irq = [
224 GIC_FDT_IRQ_TYPE_PPI,
225 AARCH64_PMU_IRQ,
226 cpu_mask | IRQ_TYPE_LEVEL_HIGH,
227 ];
228
229 let pmu_node = fdt.begin_node("pmu")?;
230 fdt.property_string("compatible", compatible)?;
231 fdt.property_array_u32("interrupts", &irq)?;
232 fdt.end_node(pmu_node)?;
233 Ok(())
234 }
235
create_serial_node(fdt: &mut FdtWriter, addr: u64, irq: u32) -> Result<()>236 fn create_serial_node(fdt: &mut FdtWriter, addr: u64, irq: u32) -> Result<()> {
237 let serial_reg_prop = [addr, AARCH64_SERIAL_SIZE];
238 let irq = [GIC_FDT_IRQ_TYPE_SPI, irq, IRQ_TYPE_EDGE_RISING];
239
240 let serial_node = fdt.begin_node(&format!("U6_16550A@{:x}", addr))?;
241 fdt.property_string("compatible", "ns16550a")?;
242 fdt.property_array_u64("reg", &serial_reg_prop)?;
243 fdt.property_u32("clock-frequency", AARCH64_SERIAL_SPEED)?;
244 fdt.property_array_u32("interrupts", &irq)?;
245 fdt.end_node(serial_node)?;
246
247 Ok(())
248 }
249
create_serial_nodes(fdt: &mut FdtWriter) -> Result<()>250 fn create_serial_nodes(fdt: &mut FdtWriter) -> Result<()> {
251 // Note that SERIAL_ADDR contains the I/O port addresses conventionally used
252 // for serial ports on x86. This uses the same addresses (but on the MMIO bus)
253 // to simplify the shared serial code.
254 create_serial_node(fdt, SERIAL_ADDR[0], AARCH64_SERIAL_1_3_IRQ)?;
255 create_serial_node(fdt, SERIAL_ADDR[1], AARCH64_SERIAL_2_4_IRQ)?;
256 create_serial_node(fdt, SERIAL_ADDR[2], AARCH64_SERIAL_1_3_IRQ)?;
257 create_serial_node(fdt, SERIAL_ADDR[3], AARCH64_SERIAL_2_4_IRQ)?;
258
259 Ok(())
260 }
261
psci_compatible(version: &PsciVersion) -> Vec<&str>262 fn psci_compatible(version: &PsciVersion) -> Vec<&str> {
263 // The PSCI kernel driver only supports compatible strings for the following
264 // backward-compatible versions.
265 let supported = [(PSCI_1_0, "arm,psci-1.0"), (PSCI_0_2, "arm,psci-0.2")];
266
267 let mut compatible: Vec<_> = supported
268 .iter()
269 .filter(|&(v, _)| *version >= *v)
270 .map(|&(_, c)| c)
271 .collect();
272
273 // The PSCI kernel driver also supports PSCI v0.1, which is NOT forward-compatible.
274 if compatible.is_empty() {
275 compatible = vec!["arm,psci"];
276 }
277
278 compatible
279 }
280
create_psci_node(fdt: &mut FdtWriter, version: &PsciVersion) -> Result<()>281 fn create_psci_node(fdt: &mut FdtWriter, version: &PsciVersion) -> Result<()> {
282 let compatible = psci_compatible(version);
283 let psci_node = fdt.begin_node("psci")?;
284 fdt.property_string_list("compatible", &compatible)?;
285 // Only support aarch64 guest
286 fdt.property_string("method", "hvc")?;
287 fdt.end_node(psci_node)?;
288
289 Ok(())
290 }
291
create_chosen_node( fdt: &mut FdtWriter, cmdline: &str, initrd: Option<(GuestAddress, usize)>, ) -> Result<()>292 fn create_chosen_node(
293 fdt: &mut FdtWriter,
294 cmdline: &str,
295 initrd: Option<(GuestAddress, usize)>,
296 ) -> Result<()> {
297 let chosen_node = fdt.begin_node("chosen")?;
298 fdt.property_u32("linux,pci-probe-only", 1)?;
299 fdt.property_string("bootargs", cmdline)?;
300 // Used by android bootloader for boot console output
301 fdt.property_string("stdout-path", &format!("/U6_16550A@{:x}", SERIAL_ADDR[0]))?;
302
303 let mut kaslr_seed_bytes = [0u8; 8];
304 OsRng.fill_bytes(&mut kaslr_seed_bytes);
305 let kaslr_seed = u64::from_le_bytes(kaslr_seed_bytes);
306 fdt.property_u64("kaslr-seed", kaslr_seed)?;
307
308 let mut rng_seed_bytes = [0u8; 256];
309 OsRng.fill_bytes(&mut rng_seed_bytes);
310 fdt.property("rng-seed", &rng_seed_bytes)?;
311
312 if let Some((initrd_addr, initrd_size)) = initrd {
313 let initrd_start = initrd_addr.offset() as u32;
314 let initrd_end = initrd_start + initrd_size as u32;
315 fdt.property_u32("linux,initrd-start", initrd_start)?;
316 fdt.property_u32("linux,initrd-end", initrd_end)?;
317 }
318 fdt.end_node(chosen_node)?;
319
320 Ok(())
321 }
322
create_config_node(fdt: &mut FdtWriter, (addr, size): (GuestAddress, usize)) -> Result<()>323 fn create_config_node(fdt: &mut FdtWriter, (addr, size): (GuestAddress, usize)) -> Result<()> {
324 let addr = addr
325 .offset()
326 .try_into()
327 .map_err(|_| Error::PropertyValueTooLarge)?;
328 let size = size.try_into().map_err(|_| Error::PropertyValueTooLarge)?;
329
330 let config_node = fdt.begin_node("config")?;
331 fdt.property_u32("kernel-address", addr)?;
332 fdt.property_u32("kernel-size", size)?;
333 fdt.end_node(config_node)?;
334
335 Ok(())
336 }
337
338 /// PCI host controller address range.
339 ///
340 /// This represents a single entry in the "ranges" property for a PCI host controller.
341 ///
342 /// See [PCI Bus Binding to Open Firmware](https://www.openfirmware.info/data/docs/bus.pci.pdf)
343 /// and https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt
344 /// for more information.
345 #[derive(Copy, Clone)]
346 pub struct PciRange {
347 pub space: PciAddressSpace,
348 pub bus_address: u64,
349 pub cpu_physical_address: u64,
350 pub size: u64,
351 pub prefetchable: bool,
352 }
353
354 /// PCI address space.
355 #[derive(Copy, Clone)]
356 #[allow(dead_code)]
357 pub enum PciAddressSpace {
358 /// PCI configuration space
359 Configuration = 0b00,
360 /// I/O space
361 Io = 0b01,
362 /// 32-bit memory space
363 Memory = 0b10,
364 /// 64-bit memory space
365 Memory64 = 0b11,
366 }
367
368 /// Location of memory-mapped PCI configuration space.
369 #[derive(Copy, Clone)]
370 pub struct PciConfigRegion {
371 /// Physical address of the base of the memory-mapped PCI configuration region.
372 pub base: u64,
373 /// Size of the PCI configuration region in bytes.
374 pub size: u64,
375 }
376
377 /// Location of memory-mapped vm watchdog
378 #[derive(Copy, Clone)]
379 pub struct VmWdtConfig {
380 /// Physical address of the base of the memory-mapped vm watchdog region.
381 pub base: u64,
382 /// Size of the vm watchdog region in bytes.
383 pub size: u64,
384 /// The internal clock frequency of the watchdog.
385 pub clock_hz: u32,
386 /// The expiration timeout measured in seconds.
387 pub timeout_sec: u32,
388 }
389
create_pci_nodes( fdt: &mut FdtWriter, pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>, cfg: PciConfigRegion, ranges: &[PciRange], dma_pool_phandle: Option<u32>, ) -> Result<()>390 fn create_pci_nodes(
391 fdt: &mut FdtWriter,
392 pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>,
393 cfg: PciConfigRegion,
394 ranges: &[PciRange],
395 dma_pool_phandle: Option<u32>,
396 ) -> Result<()> {
397 // Add devicetree nodes describing a PCI generic host controller.
398 // See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
399 // and "PCI Bus Binding to IEEE Std 1275-1994".
400 let ranges: Vec<u32> = ranges
401 .iter()
402 .flat_map(|r| {
403 let ss = r.space as u32;
404 let p = r.prefetchable as u32;
405 [
406 // BUS_ADDRESS(3) encoded as defined in OF PCI Bus Binding
407 (ss << 24) | (p << 30),
408 (r.bus_address >> 32) as u32,
409 r.bus_address as u32,
410 // CPU_PHYSICAL(2)
411 (r.cpu_physical_address >> 32) as u32,
412 r.cpu_physical_address as u32,
413 // SIZE(2)
414 (r.size >> 32) as u32,
415 r.size as u32,
416 ]
417 })
418 .collect();
419
420 let bus_range = [0, 0]; // Only bus 0
421 let reg = [cfg.base, cfg.size];
422
423 let mut interrupts: Vec<u32> = Vec::new();
424 let mut masks: Vec<u32> = Vec::new();
425
426 for (address, irq_num, irq_pin) in pci_irqs.iter() {
427 // PCI_DEVICE(3)
428 interrupts.push(address.to_config_address(0, 8));
429 interrupts.push(0);
430 interrupts.push(0);
431
432 // INT#(1)
433 interrupts.push(irq_pin.to_mask() + 1);
434
435 // CONTROLLER(PHANDLE)
436 interrupts.push(PHANDLE_GIC);
437 interrupts.push(0);
438 interrupts.push(0);
439
440 // CONTROLLER_DATA(3)
441 interrupts.push(GIC_FDT_IRQ_TYPE_SPI);
442 interrupts.push(*irq_num);
443 interrupts.push(IRQ_TYPE_LEVEL_HIGH);
444
445 // PCI_DEVICE(3)
446 masks.push(0xf800); // bits 11..15 (device)
447 masks.push(0);
448 masks.push(0);
449
450 // INT#(1)
451 masks.push(0x7); // allow INTA#-INTD# (1 | 2 | 3 | 4)
452 }
453
454 let pci_node = fdt.begin_node("pci")?;
455 fdt.property_string("compatible", "pci-host-cam-generic")?;
456 fdt.property_string("device_type", "pci")?;
457 fdt.property_array_u32("ranges", &ranges)?;
458 fdt.property_array_u32("bus-range", &bus_range)?;
459 fdt.property_u32("#address-cells", 3)?;
460 fdt.property_u32("#size-cells", 2)?;
461 fdt.property_array_u64("reg", ®)?;
462 fdt.property_u32("#interrupt-cells", 1)?;
463 fdt.property_array_u32("interrupt-map", &interrupts)?;
464 fdt.property_array_u32("interrupt-map-mask", &masks)?;
465 fdt.property_null("dma-coherent")?;
466 if let Some(dma_pool_phandle) = dma_pool_phandle {
467 fdt.property_u32("memory-region", dma_pool_phandle)?;
468 }
469 fdt.end_node(pci_node)?;
470
471 Ok(())
472 }
473
create_rtc_node(fdt: &mut FdtWriter) -> Result<()>474 fn create_rtc_node(fdt: &mut FdtWriter) -> Result<()> {
475 // the kernel driver for pl030 really really wants a clock node
476 // associated with an AMBA device or it will fail to probe, so we
477 // need to make up a clock node to associate with the pl030 rtc
478 // node and an associated handle with a unique phandle value.
479 const CLK_PHANDLE: u32 = 24;
480 let clock_node = fdt.begin_node("pclk@3M")?;
481 fdt.property_u32("#clock-cells", 0)?;
482 fdt.property_string("compatible", "fixed-clock")?;
483 fdt.property_u32("clock-frequency", 3141592)?;
484 fdt.property_u32("phandle", CLK_PHANDLE)?;
485 fdt.end_node(clock_node)?;
486
487 let rtc_name = format!("rtc@{:x}", AARCH64_RTC_ADDR);
488 let reg = [AARCH64_RTC_ADDR, AARCH64_RTC_SIZE];
489 let irq = [GIC_FDT_IRQ_TYPE_SPI, AARCH64_RTC_IRQ, IRQ_TYPE_LEVEL_HIGH];
490
491 let rtc_node = fdt.begin_node(&rtc_name)?;
492 fdt.property_string("compatible", "arm,primecell")?;
493 fdt.property_u32("arm,primecell-periphid", PL030_AMBA_ID)?;
494 fdt.property_array_u64("reg", ®)?;
495 fdt.property_array_u32("interrupts", &irq)?;
496 fdt.property_u32("clocks", CLK_PHANDLE)?;
497 fdt.property_string("clock-names", "apb_pclk")?;
498 fdt.end_node(rtc_node)?;
499 Ok(())
500 }
501
502 /// Create a flattened device tree node for Goldfish Battery device.
503 ///
504 /// # Arguments
505 ///
506 /// * `fdt` - A FdtWriter in which the node is created
507 /// * `mmio_base` - The MMIO base address of the battery
508 /// * `irq` - The IRQ number of the battery
create_battery_node(fdt: &mut FdtWriter, mmio_base: u64, irq: u32) -> Result<()>509 fn create_battery_node(fdt: &mut FdtWriter, mmio_base: u64, irq: u32) -> Result<()> {
510 let reg = [mmio_base, GOLDFISHBAT_MMIO_LEN];
511 let irqs = [GIC_FDT_IRQ_TYPE_SPI, irq, IRQ_TYPE_LEVEL_HIGH];
512 let bat_node = fdt.begin_node("goldfish_battery")?;
513 fdt.property_string("compatible", "google,goldfish-battery")?;
514 fdt.property_array_u64("reg", ®)?;
515 fdt.property_array_u32("interrupts", &irqs)?;
516 fdt.end_node(bat_node)?;
517 Ok(())
518 }
519
create_vmwdt_node(fdt: &mut FdtWriter, vmwdt_cfg: VmWdtConfig) -> Result<()>520 fn create_vmwdt_node(fdt: &mut FdtWriter, vmwdt_cfg: VmWdtConfig) -> Result<()> {
521 let vmwdt_name = format!("vmwdt@{:x}", vmwdt_cfg.base);
522 let reg = [vmwdt_cfg.base, vmwdt_cfg.size];
523 let vmwdt_node = fdt.begin_node(&vmwdt_name)?;
524 fdt.property_string("compatible", "qemu,vcpu-stall-detector")?;
525 fdt.property_array_u64("reg", ®)?;
526 fdt.property_u32("clock-frequency", vmwdt_cfg.clock_hz)?;
527 fdt.property_u32("timeout-sec", vmwdt_cfg.timeout_sec)?;
528 fdt.end_node(vmwdt_node)?;
529 Ok(())
530 }
531
532 /// Creates a flattened device tree containing all of the parameters for the
533 /// kernel and loads it into the guest memory at the specified offset.
534 ///
535 /// # Arguments
536 ///
537 /// * `fdt_max_size` - The amount of space reserved for the device tree
538 /// * `guest_mem` - The guest memory object
539 /// * `pci_irqs` - List of PCI device address to PCI interrupt number and pin mappings
540 /// * `pci_cfg` - Location of the memory-mapped PCI configuration space.
541 /// * `pci_ranges` - Memory ranges accessible via the PCI host controller.
542 /// * `num_cpus` - Number of virtual CPUs the guest will have
543 /// * `fdt_address` - The offset into physical memory for the device tree
544 /// * `cmdline` - The kernel commandline
545 /// * `initrd` - An optional tuple of initrd guest physical address and size
546 /// * `android_fstab` - An optional file holding Android fstab entries
547 /// * `is_gicv3` - True if gicv3, false if v2
548 /// * `psci_version` - the current PSCI version
549 /// * `swiotlb` - Reserve a memory pool for DMA. Tuple of base address and size.
550 /// * `bat_mmio_base_and_irq` - The battery base address and irq number
551 /// * `vmwdt_cfg` - The virtual watchdog configuration
552 /// * `dump_device_tree_blob` - Option path to write DTB to
553 /// * `vm_generator` - Callback to add additional nodes to DTB. create_vm uses Aarch64Vm::create_fdt
create_fdt( fdt_max_size: usize, guest_mem: &GuestMemory, pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>, pci_cfg: PciConfigRegion, pci_ranges: &[PciRange], num_cpus: u32, cpu_clusters: Vec<CpuSet>, cpu_capacity: BTreeMap<usize, u32>, fdt_address: GuestAddress, cmdline: &str, image: (GuestAddress, usize), initrd: Option<(GuestAddress, usize)>, android_fstab: Option<File>, is_gicv3: bool, use_pmu: bool, psci_version: PsciVersion, swiotlb: Option<(Option<GuestAddress>, u64)>, bat_mmio_base_and_irq: Option<(u64, u32)>, vmwdt_cfg: VmWdtConfig, dump_device_tree_blob: Option<PathBuf>, vm_generator: &impl Fn(&mut FdtWriter, &BTreeMap<&str, u32>) -> cros_fdt::Result<()>, ) -> Result<()>554 pub fn create_fdt(
555 fdt_max_size: usize,
556 guest_mem: &GuestMemory,
557 pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>,
558 pci_cfg: PciConfigRegion,
559 pci_ranges: &[PciRange],
560 num_cpus: u32,
561 cpu_clusters: Vec<CpuSet>,
562 cpu_capacity: BTreeMap<usize, u32>,
563 fdt_address: GuestAddress,
564 cmdline: &str,
565 image: (GuestAddress, usize),
566 initrd: Option<(GuestAddress, usize)>,
567 android_fstab: Option<File>,
568 is_gicv3: bool,
569 use_pmu: bool,
570 psci_version: PsciVersion,
571 swiotlb: Option<(Option<GuestAddress>, u64)>,
572 bat_mmio_base_and_irq: Option<(u64, u32)>,
573 vmwdt_cfg: VmWdtConfig,
574 dump_device_tree_blob: Option<PathBuf>,
575 vm_generator: &impl Fn(&mut FdtWriter, &BTreeMap<&str, u32>) -> cros_fdt::Result<()>,
576 ) -> Result<()> {
577 let mut fdt = FdtWriter::new(&[]);
578 let mut phandles = BTreeMap::new();
579
580 // The whole thing is put into one giant node with some top level properties
581 let root_node = fdt.begin_node("")?;
582 fdt.property_u32("interrupt-parent", PHANDLE_GIC)?;
583 phandles.insert("intc", PHANDLE_GIC);
584 fdt.property_string("compatible", "linux,dummy-virt")?;
585 fdt.property_u32("#address-cells", 0x2)?;
586 fdt.property_u32("#size-cells", 0x2)?;
587 if let Some(android_fstab) = android_fstab {
588 arch::android::create_android_fdt(&mut fdt, android_fstab)?;
589 }
590 create_chosen_node(&mut fdt, cmdline, initrd)?;
591 create_config_node(&mut fdt, image)?;
592 create_memory_node(&mut fdt, guest_mem)?;
593 let dma_pool_phandle = match swiotlb {
594 Some(x) => {
595 let phandle = create_resv_memory_node(&mut fdt, x)?;
596 phandles.insert("restricted_dma_reserved", phandle);
597 Some(phandle)
598 }
599 None => None,
600 };
601 create_cpu_nodes(&mut fdt, num_cpus, cpu_clusters, cpu_capacity)?;
602 create_gic_node(&mut fdt, is_gicv3, num_cpus as u64)?;
603 create_timer_node(&mut fdt, num_cpus)?;
604 if use_pmu {
605 create_pmu_node(&mut fdt, num_cpus)?;
606 }
607 create_serial_nodes(&mut fdt)?;
608 create_psci_node(&mut fdt, &psci_version)?;
609 create_pci_nodes(&mut fdt, pci_irqs, pci_cfg, pci_ranges, dma_pool_phandle)?;
610 create_rtc_node(&mut fdt)?;
611 if let Some((bat_mmio_base, bat_irq)) = bat_mmio_base_and_irq {
612 create_battery_node(&mut fdt, bat_mmio_base, bat_irq)?;
613 }
614 create_vmwdt_node(&mut fdt, vmwdt_cfg)?;
615 vm_generator(&mut fdt, &phandles)?;
616 // End giant node
617 fdt.end_node(root_node)?;
618
619 let fdt_final = fdt.finish()?;
620
621 if let Some(file_path) = dump_device_tree_blob {
622 std::fs::write(&file_path, &fdt_final)
623 .map_err(|e| Error::FdtDumpIoError(e, file_path.clone()))?;
624 }
625
626 if fdt_final.len() > fdt_max_size {
627 return Err(Error::TotalSizeTooLarge);
628 }
629
630 let written = guest_mem
631 .write_at_addr(fdt_final.as_slice(), fdt_address)
632 .map_err(|_| Error::FdtGuestMemoryWriteError)?;
633 if written < fdt_final.len() {
634 return Err(Error::FdtGuestMemoryWriteError);
635 }
636
637 Ok(())
638 }
639
640 #[cfg(test)]
641 mod tests {
642 use super::*;
643
644 #[test]
psci_compatible_v0_1()645 fn psci_compatible_v0_1() {
646 assert_eq!(
647 psci_compatible(&PsciVersion::new(0, 1).unwrap()),
648 vec!["arm,psci"]
649 );
650 }
651
652 #[test]
psci_compatible_v0_2()653 fn psci_compatible_v0_2() {
654 assert_eq!(
655 psci_compatible(&PsciVersion::new(0, 2).unwrap()),
656 vec!["arm,psci-0.2"]
657 );
658 }
659
660 #[test]
psci_compatible_v0_5()661 fn psci_compatible_v0_5() {
662 // Only the 0.2 version supported by the kernel should be added.
663 assert_eq!(
664 psci_compatible(&PsciVersion::new(0, 5).unwrap()),
665 vec!["arm,psci-0.2"]
666 );
667 }
668
669 #[test]
psci_compatible_v1_0()670 fn psci_compatible_v1_0() {
671 // Both 1.0 and 0.2 should be listed, in that order.
672 assert_eq!(
673 psci_compatible(&PsciVersion::new(1, 0).unwrap()),
674 vec!["arm,psci-1.0", "arm,psci-0.2"]
675 );
676 }
677
678 #[test]
psci_compatible_v1_5()679 fn psci_compatible_v1_5() {
680 // Only the 1.0 and 0.2 versions supported by the kernel should be listed.
681 assert_eq!(
682 psci_compatible(&PsciVersion::new(1, 5).unwrap()),
683 vec!["arm,psci-1.0", "arm,psci-0.2"]
684 );
685 }
686 }
687