• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
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::fs::File;
6 use std::io::Read;
7 
8 use arch::fdt::{Error, FdtWriter, Result};
9 use arch::SERIAL_ADDR;
10 use devices::{PciAddress, PciInterruptPin};
11 use hypervisor::PsciVersion;
12 use vm_memory::{GuestAddress, GuestMemory};
13 
14 // This is the start of DRAM in the physical address space.
15 use crate::AARCH64_PHYS_MEM_START;
16 
17 // These are GIC address-space location constants.
18 use crate::AARCH64_GIC_CPUI_BASE;
19 use crate::AARCH64_GIC_CPUI_SIZE;
20 use crate::AARCH64_GIC_DIST_BASE;
21 use crate::AARCH64_GIC_DIST_SIZE;
22 use crate::AARCH64_GIC_REDIST_SIZE;
23 
24 // These are RTC related constants
25 use crate::AARCH64_RTC_ADDR;
26 use crate::AARCH64_RTC_IRQ;
27 use crate::AARCH64_RTC_SIZE;
28 use devices::pl030::PL030_AMBA_ID;
29 
30 // These are serial device related constants.
31 use crate::AARCH64_SERIAL_1_3_IRQ;
32 use crate::AARCH64_SERIAL_2_4_IRQ;
33 use crate::AARCH64_SERIAL_SIZE;
34 use crate::AARCH64_SERIAL_SPEED;
35 
36 // These are related to guest virtio devices.
37 use crate::AARCH64_MMIO_BASE;
38 use crate::AARCH64_MMIO_SIZE;
39 use crate::AARCH64_PCI_CFG_BASE;
40 use crate::AARCH64_PCI_CFG_SIZE;
41 
42 use crate::AARCH64_PMU_IRQ;
43 
44 // This is an arbitrary number to specify the node for the GIC.
45 // If we had a more complex interrupt architecture, then we'd need an enum for
46 // these.
47 const PHANDLE_GIC: u32 = 1;
48 
49 // These are specified by the Linux GIC bindings
50 const GIC_FDT_IRQ_NUM_CELLS: u32 = 3;
51 const GIC_FDT_IRQ_TYPE_SPI: u32 = 0;
52 const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
53 const GIC_FDT_IRQ_PPI_CPU_SHIFT: u32 = 8;
54 const GIC_FDT_IRQ_PPI_CPU_MASK: u32 = 0xff << GIC_FDT_IRQ_PPI_CPU_SHIFT;
55 const IRQ_TYPE_EDGE_RISING: u32 = 0x00000001;
56 const IRQ_TYPE_LEVEL_HIGH: u32 = 0x00000004;
57 const IRQ_TYPE_LEVEL_LOW: u32 = 0x00000008;
58 
create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemory) -> Result<()>59 fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemory) -> Result<()> {
60     let mem_size = guest_mem.memory_size();
61     let mem_reg_prop = [AARCH64_PHYS_MEM_START, mem_size];
62 
63     let memory_node = fdt.begin_node("memory")?;
64     fdt.property_string("device_type", "memory")?;
65     fdt.property_array_u64("reg", &mem_reg_prop)?;
66     fdt.end_node(memory_node)?;
67     Ok(())
68 }
69 
create_cpu_nodes(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()>70 fn create_cpu_nodes(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()> {
71     let cpus_node = fdt.begin_node("cpus")?;
72     fdt.property_u32("#address-cells", 0x1)?;
73     fdt.property_u32("#size-cells", 0x0)?;
74 
75     for cpu_id in 0..num_cpus {
76         let cpu_name = format!("cpu@{:x}", cpu_id);
77         let cpu_node = fdt.begin_node(&cpu_name)?;
78         fdt.property_string("device_type", "cpu")?;
79         fdt.property_string("compatible", "arm,arm-v8")?;
80         if num_cpus > 1 {
81             fdt.property_string("enable-method", "psci")?;
82         }
83         fdt.property_u32("reg", cpu_id)?;
84         fdt.end_node(cpu_node)?;
85     }
86     fdt.end_node(cpus_node)?;
87     Ok(())
88 }
89 
create_gic_node(fdt: &mut FdtWriter, is_gicv3: bool, num_cpus: u64) -> Result<()>90 fn create_gic_node(fdt: &mut FdtWriter, is_gicv3: bool, num_cpus: u64) -> Result<()> {
91     let mut gic_reg_prop = [AARCH64_GIC_DIST_BASE, AARCH64_GIC_DIST_SIZE, 0, 0];
92 
93     let intc_node = fdt.begin_node("intc")?;
94     if is_gicv3 {
95         fdt.property_string("compatible", "arm,gic-v3")?;
96         gic_reg_prop[2] = AARCH64_GIC_DIST_BASE - (AARCH64_GIC_REDIST_SIZE * num_cpus);
97         gic_reg_prop[3] = AARCH64_GIC_REDIST_SIZE * num_cpus;
98     } else {
99         fdt.property_string("compatible", "arm,cortex-a15-gic")?;
100         gic_reg_prop[2] = AARCH64_GIC_CPUI_BASE;
101         gic_reg_prop[3] = AARCH64_GIC_CPUI_SIZE;
102     }
103     fdt.property_u32("#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS)?;
104     fdt.property_null("interrupt-controller")?;
105     fdt.property_array_u64("reg", &gic_reg_prop)?;
106     fdt.property_u32("phandle", PHANDLE_GIC)?;
107     fdt.property_u32("#address-cells", 2)?;
108     fdt.property_u32("#size-cells", 2)?;
109     fdt.end_node(intc_node)?;
110 
111     Ok(())
112 }
113 
create_timer_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()>114 fn create_timer_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()> {
115     // These are fixed interrupt numbers for the timer device.
116     let irqs = [13, 14, 11, 10];
117     let compatible = "arm,armv8-timer";
118     let cpu_mask: u32 =
119         (((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK;
120 
121     let mut timer_reg_cells = Vec::new();
122     for &irq in &irqs {
123         timer_reg_cells.push(GIC_FDT_IRQ_TYPE_PPI);
124         timer_reg_cells.push(irq);
125         timer_reg_cells.push(cpu_mask | IRQ_TYPE_LEVEL_LOW);
126     }
127 
128     let timer_node = fdt.begin_node("timer")?;
129     fdt.property_string("compatible", compatible)?;
130     fdt.property_array_u32("interrupts", &timer_reg_cells)?;
131     fdt.property_null("always-on")?;
132     fdt.end_node(timer_node)?;
133 
134     Ok(())
135 }
136 
create_pmu_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()>137 fn create_pmu_node(fdt: &mut FdtWriter, num_cpus: u32) -> Result<()> {
138     let compatible = "arm,armv8-pmuv3";
139     let cpu_mask: u32 =
140         (((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK;
141     let irq = [
142         GIC_FDT_IRQ_TYPE_PPI,
143         AARCH64_PMU_IRQ,
144         cpu_mask | IRQ_TYPE_LEVEL_HIGH,
145     ];
146 
147     let pmu_node = fdt.begin_node("pmu")?;
148     fdt.property_string("compatible", compatible)?;
149     fdt.property_array_u32("interrupts", &irq)?;
150     fdt.end_node(pmu_node)?;
151     Ok(())
152 }
153 
create_serial_node(fdt: &mut FdtWriter, addr: u64, irq: u32) -> Result<()>154 fn create_serial_node(fdt: &mut FdtWriter, addr: u64, irq: u32) -> Result<()> {
155     let serial_reg_prop = [addr, AARCH64_SERIAL_SIZE];
156     let irq = [GIC_FDT_IRQ_TYPE_SPI, irq, IRQ_TYPE_EDGE_RISING];
157 
158     let serial_node = fdt.begin_node(&format!("U6_16550A@{:x}", addr))?;
159     fdt.property_string("compatible", "ns16550a")?;
160     fdt.property_array_u64("reg", &serial_reg_prop)?;
161     fdt.property_u32("clock-frequency", AARCH64_SERIAL_SPEED)?;
162     fdt.property_array_u32("interrupts", &irq)?;
163     fdt.end_node(serial_node)?;
164 
165     Ok(())
166 }
167 
create_serial_nodes(fdt: &mut FdtWriter) -> Result<()>168 fn create_serial_nodes(fdt: &mut FdtWriter) -> Result<()> {
169     // Note that SERIAL_ADDR contains the I/O port addresses conventionally used
170     // for serial ports on x86. This uses the same addresses (but on the MMIO bus)
171     // to simplify the shared serial code.
172     create_serial_node(fdt, SERIAL_ADDR[0], AARCH64_SERIAL_1_3_IRQ)?;
173     create_serial_node(fdt, SERIAL_ADDR[1], AARCH64_SERIAL_2_4_IRQ)?;
174     create_serial_node(fdt, SERIAL_ADDR[2], AARCH64_SERIAL_1_3_IRQ)?;
175     create_serial_node(fdt, SERIAL_ADDR[3], AARCH64_SERIAL_2_4_IRQ)?;
176 
177     Ok(())
178 }
179 
create_psci_node(fdt: &mut FdtWriter, version: &PsciVersion) -> Result<()>180 fn create_psci_node(fdt: &mut FdtWriter, version: &PsciVersion) -> Result<()> {
181     let mut compatible = vec![format!("arm,psci-{}.{}", version.major, version.minor)];
182     if version.major == 1 {
183         // Put `psci-0.2` as well because PSCI 1.0 is compatible with PSCI 0.2.
184         compatible.push(format!("arm,psci-0.2"))
185     };
186 
187     let psci_node = fdt.begin_node("psci")?;
188     fdt.property_string_list("compatible", compatible)?;
189     // Only support aarch64 guest
190     fdt.property_string("method", "hvc")?;
191     fdt.end_node(psci_node)?;
192 
193     Ok(())
194 }
195 
create_chosen_node( fdt: &mut FdtWriter, cmdline: &str, initrd: Option<(GuestAddress, usize)>, ) -> Result<()>196 fn create_chosen_node(
197     fdt: &mut FdtWriter,
198     cmdline: &str,
199     initrd: Option<(GuestAddress, usize)>,
200 ) -> Result<()> {
201     let chosen_node = fdt.begin_node("chosen")?;
202     fdt.property_u32("linux,pci-probe-only", 1)?;
203     fdt.property_string("bootargs", cmdline)?;
204     // Used by android bootloader for boot console output
205     fdt.property_string("stdout-path", &format!("/U6_16550A@{:x}", SERIAL_ADDR[0]))?;
206 
207     let mut random_file = File::open("/dev/urandom").map_err(Error::FdtIoError)?;
208     let mut kaslr_seed_bytes = [0u8; 8];
209     random_file
210         .read_exact(&mut kaslr_seed_bytes)
211         .map_err(Error::FdtIoError)?;
212     let kaslr_seed = u64::from_le_bytes(kaslr_seed_bytes);
213     fdt.property_u64("kaslr-seed", kaslr_seed)?;
214 
215     let mut rng_seed_bytes = [0u8; 256];
216     random_file
217         .read_exact(&mut rng_seed_bytes)
218         .map_err(Error::FdtIoError)?;
219     fdt.property("rng-seed", &rng_seed_bytes)?;
220 
221     if let Some((initrd_addr, initrd_size)) = initrd {
222         let initrd_start = initrd_addr.offset() as u32;
223         let initrd_end = initrd_start + initrd_size as u32;
224         fdt.property_u32("linux,initrd-start", initrd_start)?;
225         fdt.property_u32("linux,initrd-end", initrd_end)?;
226     }
227     fdt.end_node(chosen_node)?;
228 
229     Ok(())
230 }
231 
create_pci_nodes( fdt: &mut FdtWriter, pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>, pci_device_base: u64, pci_device_size: u64, ) -> Result<()>232 fn create_pci_nodes(
233     fdt: &mut FdtWriter,
234     pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>,
235     pci_device_base: u64,
236     pci_device_size: u64,
237 ) -> Result<()> {
238     // Add devicetree nodes describing a PCI generic host controller.
239     // See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
240     // and "PCI Bus Binding to IEEE Std 1275-1994".
241     let ranges = [
242         // mmio addresses
243         0x3000000,                        // (ss = 11: 64-bit memory space)
244         (AARCH64_MMIO_BASE >> 32) as u32, // PCI address
245         AARCH64_MMIO_BASE as u32,
246         (AARCH64_MMIO_BASE >> 32) as u32, // CPU address
247         AARCH64_MMIO_BASE as u32,
248         (AARCH64_MMIO_SIZE >> 32) as u32, // size
249         AARCH64_MMIO_SIZE as u32,
250         // device addresses
251         0x3000000,                      // (ss = 11: 64-bit memory space)
252         (pci_device_base >> 32) as u32, // PCI address
253         pci_device_base as u32,
254         (pci_device_base >> 32) as u32, // CPU address
255         pci_device_base as u32,
256         (pci_device_size >> 32) as u32, // size
257         pci_device_size as u32,
258     ];
259     let bus_range = [0, 0]; // Only bus 0
260     let reg = [AARCH64_PCI_CFG_BASE, AARCH64_PCI_CFG_SIZE];
261 
262     let mut interrupts: Vec<u32> = Vec::new();
263     let mut masks: Vec<u32> = Vec::new();
264 
265     for (address, irq_num, irq_pin) in pci_irqs.iter() {
266         // PCI_DEVICE(3)
267         interrupts.push(address.to_config_address(0));
268         interrupts.push(0);
269         interrupts.push(0);
270 
271         // INT#(1)
272         interrupts.push(irq_pin.to_mask() + 1);
273 
274         // CONTROLLER(PHANDLE)
275         interrupts.push(PHANDLE_GIC);
276         interrupts.push(0);
277         interrupts.push(0);
278 
279         // CONTROLLER_DATA(3)
280         interrupts.push(GIC_FDT_IRQ_TYPE_SPI);
281         interrupts.push(*irq_num);
282         interrupts.push(IRQ_TYPE_LEVEL_HIGH);
283 
284         // PCI_DEVICE(3)
285         masks.push(0xf800); // bits 11..15 (device)
286         masks.push(0);
287         masks.push(0);
288 
289         // INT#(1)
290         masks.push(0x7); // allow INTA#-INTD# (1 | 2 | 3 | 4)
291     }
292 
293     let pci_node = fdt.begin_node("pci")?;
294     fdt.property_string("compatible", "pci-host-cam-generic")?;
295     fdt.property_string("device_type", "pci")?;
296     fdt.property_array_u32("ranges", &ranges)?;
297     fdt.property_array_u32("bus-range", &bus_range)?;
298     fdt.property_u32("#address-cells", 3)?;
299     fdt.property_u32("#size-cells", 2)?;
300     fdt.property_array_u64("reg", &reg)?;
301     fdt.property_u32("#interrupt-cells", 1)?;
302     fdt.property_array_u32("interrupt-map", &interrupts)?;
303     fdt.property_array_u32("interrupt-map-mask", &masks)?;
304     fdt.property_null("dma-coherent")?;
305     fdt.end_node(pci_node)?;
306 
307     Ok(())
308 }
309 
create_rtc_node(fdt: &mut FdtWriter) -> Result<()>310 fn create_rtc_node(fdt: &mut FdtWriter) -> Result<()> {
311     // the kernel driver for pl030 really really wants a clock node
312     // associated with an AMBA device or it will fail to probe, so we
313     // need to make up a clock node to associate with the pl030 rtc
314     // node and an associated handle with a unique phandle value.
315     const CLK_PHANDLE: u32 = 24;
316     let clock_node = fdt.begin_node("pclk@3M")?;
317     fdt.property_u32("#clock-cells", 0)?;
318     fdt.property_string("compatible", "fixed-clock")?;
319     fdt.property_u32("clock-frequency", 3141592)?;
320     fdt.property_u32("phandle", CLK_PHANDLE)?;
321     fdt.end_node(clock_node)?;
322 
323     let rtc_name = format!("rtc@{:x}", AARCH64_RTC_ADDR);
324     let reg = [AARCH64_RTC_ADDR, AARCH64_RTC_SIZE];
325     let irq = [GIC_FDT_IRQ_TYPE_SPI, AARCH64_RTC_IRQ, IRQ_TYPE_LEVEL_HIGH];
326 
327     let rtc_node = fdt.begin_node(&rtc_name)?;
328     fdt.property_string("compatible", "arm,primecell")?;
329     fdt.property_u32("arm,primecell-periphid", PL030_AMBA_ID)?;
330     fdt.property_array_u64("reg", &reg)?;
331     fdt.property_array_u32("interrupts", &irq)?;
332     fdt.property_u32("clocks", CLK_PHANDLE)?;
333     fdt.property_string("clock-names", "apb_pclk")?;
334     fdt.end_node(rtc_node)?;
335     Ok(())
336 }
337 
338 /// Creates a flattened device tree containing all of the parameters for the
339 /// kernel and loads it into the guest memory at the specified offset.
340 ///
341 /// # Arguments
342 ///
343 /// * `fdt_max_size` - The amount of space reserved for the device tree
344 /// * `guest_mem` - The guest memory object
345 /// * `pci_irqs` - List of PCI device address to PCI interrupt number and pin mappings
346 /// * `num_cpus` - Number of virtual CPUs the guest will have
347 /// * `fdt_load_offset` - The offset into physical memory for the device tree
348 /// * `pci_device_base` - The offset into physical memory for PCI device memory
349 /// * `pci_device_size` - The size of PCI device memory
350 /// * `cmdline` - The kernel commandline
351 /// * `initrd` - An optional tuple of initrd guest physical address and size
352 /// * `android_fstab` - An optional file holding Android fstab entries
353 /// * `is_gicv3` - True if gicv3, false if v2
354 /// * `psci_version` - the current PSCI version
create_fdt( fdt_max_size: usize, guest_mem: &GuestMemory, pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>, num_cpus: u32, fdt_load_offset: u64, pci_device_base: u64, pci_device_size: u64, cmdline: &str, initrd: Option<(GuestAddress, usize)>, android_fstab: Option<File>, is_gicv3: bool, use_pmu: bool, psci_version: PsciVersion, ) -> Result<()>355 pub fn create_fdt(
356     fdt_max_size: usize,
357     guest_mem: &GuestMemory,
358     pci_irqs: Vec<(PciAddress, u32, PciInterruptPin)>,
359     num_cpus: u32,
360     fdt_load_offset: u64,
361     pci_device_base: u64,
362     pci_device_size: u64,
363     cmdline: &str,
364     initrd: Option<(GuestAddress, usize)>,
365     android_fstab: Option<File>,
366     is_gicv3: bool,
367     use_pmu: bool,
368     psci_version: PsciVersion,
369 ) -> Result<()> {
370     let mut fdt = FdtWriter::new(&[]);
371 
372     // The whole thing is put into one giant node with some top level properties
373     let root_node = fdt.begin_node("")?;
374     fdt.property_u32("interrupt-parent", PHANDLE_GIC)?;
375     fdt.property_string("compatible", "linux,dummy-virt")?;
376     fdt.property_u32("#address-cells", 0x2)?;
377     fdt.property_u32("#size-cells", 0x2)?;
378     if let Some(android_fstab) = android_fstab {
379         arch::android::create_android_fdt(&mut fdt, android_fstab)?;
380     }
381     create_chosen_node(&mut fdt, cmdline, initrd)?;
382     create_memory_node(&mut fdt, guest_mem)?;
383     create_cpu_nodes(&mut fdt, num_cpus)?;
384     create_gic_node(&mut fdt, is_gicv3, num_cpus as u64)?;
385     create_timer_node(&mut fdt, num_cpus)?;
386     if use_pmu {
387         create_pmu_node(&mut fdt, num_cpus)?;
388     }
389     create_serial_nodes(&mut fdt)?;
390     create_psci_node(&mut fdt, &psci_version)?;
391     create_pci_nodes(&mut fdt, pci_irqs, pci_device_base, pci_device_size)?;
392     create_rtc_node(&mut fdt)?;
393     // End giant node
394     fdt.end_node(root_node)?;
395 
396     let fdt_final = fdt.finish(fdt_max_size)?;
397 
398     let fdt_address = GuestAddress(AARCH64_PHYS_MEM_START + fdt_load_offset);
399     let written = guest_mem
400         .write_at_addr(fdt_final.as_slice(), fdt_address)
401         .map_err(|_| Error::FdtGuestMemoryWriteError)?;
402     if written < fdt_max_size {
403         return Err(Error::FdtGuestMemoryWriteError);
404     }
405     Ok(())
406 }
407