blob: c4a3ae1a73451925854a21de02f35ec98214ab97 [file] [log] [blame]
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +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//! High-level FDT functions.
16
Jiyong Parkb87f3302023-03-21 10:03:11 +090017use crate::cstr;
Jiyong Park00ceff32023-03-13 05:43:23 +000018use crate::helpers::GUEST_PAGE_SIZE;
19use crate::RebootReason;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000020use core::ffi::CStr;
21use core::ops::Range;
Jiyong Park00ceff32023-03-13 05:43:23 +000022use fdtpci::PciMemoryFlags;
23use fdtpci::PciRangeType;
24use libfdt::AddressRange;
25use libfdt::CellIterator;
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +000026use libfdt::Fdt;
27use libfdt::FdtError;
Jiyong Park83316122023-03-21 09:39:39 +090028use log::debug;
Jiyong Park00ceff32023-03-13 05:43:23 +000029use log::error;
30use tinyvec::ArrayVec;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000031
Jiyong Park6a8789a2023-03-21 14:50:59 +090032/// Extract from /config the address range containing the pre-loaded kernel. Absence of /config is
33/// not an error.
34fn read_kernel_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
Jiyong Parkb87f3302023-03-21 10:03:11 +090035 let addr = cstr!("kernel-address");
36 let size = cstr!("kernel-size");
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +000037
Jiyong Parkb87f3302023-03-21 10:03:11 +090038 if let Some(config) = fdt.node(cstr!("/config"))? {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +000039 if let (Some(addr), Some(size)) = (config.getprop_u32(addr)?, config.getprop_u32(size)?) {
40 let addr = addr as usize;
41 let size = size as usize;
42
43 return Ok(Some(addr..(addr + size)));
44 }
45 }
46
47 Ok(None)
48}
49
Jiyong Park6a8789a2023-03-21 14:50:59 +090050/// Extract from /chosen the address range containing the pre-loaded ramdisk. Absence is not an
51/// error as there can be initrd-less VM.
52fn read_initrd_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
Jiyong Parkb87f3302023-03-21 10:03:11 +090053 let start = cstr!("linux,initrd-start");
54 let end = cstr!("linux,initrd-end");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000055
56 if let Some(chosen) = fdt.chosen()? {
57 if let (Some(start), Some(end)) = (chosen.getprop_u32(start)?, chosen.getprop_u32(end)?) {
58 return Ok(Some((start as usize)..(end as usize)));
59 }
60 }
61
62 Ok(None)
63}
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +000064
Jiyong Park6a8789a2023-03-21 14:50:59 +090065/// Read the first range in /memory node in DT
66fn read_memory_range_from(fdt: &Fdt) -> libfdt::Result<Range<usize>> {
67 fdt.memory()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
68}
Jiyong Park00ceff32023-03-13 05:43:23 +000069
Jiyong Park6a8789a2023-03-21 14:50:59 +090070/// Check if memory range is ok
71fn validate_memory_range(range: &Range<usize>) -> Result<(), RebootReason> {
72 let base = range.start;
Jiyong Park00ceff32023-03-13 05:43:23 +000073 if base as u64 != DeviceTreeInfo::RAM_BASE_ADDR {
74 error!("Memory base address {:#x} is not {:#x}", base, DeviceTreeInfo::RAM_BASE_ADDR);
75 return Err(RebootReason::InvalidFdt);
76 }
77
Jiyong Park6a8789a2023-03-21 14:50:59 +090078 let size = range.len();
Jiyong Park00ceff32023-03-13 05:43:23 +000079 if size % GUEST_PAGE_SIZE != 0 {
80 error!("Memory size {:#x} is not a multiple of page size {:#x}", size, GUEST_PAGE_SIZE);
81 return Err(RebootReason::InvalidFdt);
82 }
Jiyong Park00ceff32023-03-13 05:43:23 +000083
Jiyong Park6a8789a2023-03-21 14:50:59 +090084 if size == 0 {
85 error!("Memory size is 0");
86 return Err(RebootReason::InvalidFdt);
87 }
88 Ok(())
Jiyong Park00ceff32023-03-13 05:43:23 +000089}
90
Jiyong Park6a8789a2023-03-21 14:50:59 +090091/// Read the number of CPUs from DT
92fn read_num_cpus_from(fdt: &Fdt) -> libfdt::Result<usize> {
93 Ok(fdt.compatible_nodes(cstr!("arm,arm-v8"))?.count())
94}
95
96/// Validate number of CPUs
97fn validate_num_cpus(num_cpus: usize) -> Result<(), RebootReason> {
98 if num_cpus == 0 {
Jiyong Park00ceff32023-03-13 05:43:23 +000099 error!("Number of CPU can't be 0");
Jiyong Park6a8789a2023-03-21 14:50:59 +0900100 return Err(RebootReason::InvalidFdt);
101 }
102 Ok(())
Jiyong Park00ceff32023-03-13 05:43:23 +0000103}
104
105#[derive(Debug)]
106#[allow(dead_code)] // TODO: remove this
107struct PciInfo {
Jiyong Park6a8789a2023-03-21 14:50:59 +0900108 ranges: [PciAddrRange; 2],
109 irq_masks: ArrayVec<[PciIrqMask; PciInfo::MAX_IRQS]>,
110 irq_maps: ArrayVec<[PciIrqMap; PciInfo::MAX_IRQS]>,
Jiyong Park00ceff32023-03-13 05:43:23 +0000111}
112
Jiyong Park6a8789a2023-03-21 14:50:59 +0900113impl PciInfo {
114 const IRQ_MASK_CELLS: usize = 4;
115 const IRQ_MAP_CELLS: usize = 10;
116 const MAX_IRQS: usize = 8;
Jiyong Park00ceff32023-03-13 05:43:23 +0000117}
118
Jiyong Park6a8789a2023-03-21 14:50:59 +0900119type PciAddrRange = AddressRange<(u32, u64), u64, u64>;
120type PciIrqMask = [u32; PciInfo::IRQ_MASK_CELLS];
121type PciIrqMap = [u32; PciInfo::IRQ_MAP_CELLS];
Jiyong Park00ceff32023-03-13 05:43:23 +0000122
123/// Iterator that takes N cells as a chunk
124struct CellChunkIterator<'a, const N: usize> {
125 cells: CellIterator<'a>,
126}
127
128impl<'a, const N: usize> CellChunkIterator<'a, N> {
129 fn new(cells: CellIterator<'a>) -> Self {
130 Self { cells }
131 }
132}
133
134impl<'a, const N: usize> Iterator for CellChunkIterator<'a, N> {
135 type Item = [u32; N];
136 fn next(&mut self) -> Option<Self::Item> {
137 let mut ret: Self::Item = [0; N];
138 for i in ret.iter_mut() {
139 *i = self.cells.next()?;
140 }
141 Some(ret)
142 }
143}
144
Jiyong Park6a8789a2023-03-21 14:50:59 +0900145/// Read pci host controller ranges, irq maps, and irq map masks from DT
146fn read_pci_info_from(fdt: &Fdt) -> libfdt::Result<PciInfo> {
147 let node =
148 fdt.compatible_nodes(cstr!("pci-host-cam-generic"))?.next().ok_or(FdtError::NotFound)?;
149
150 let mut ranges = node.ranges::<(u32, u64), u64, u64>()?.ok_or(FdtError::NotFound)?;
151 let range0 = ranges.next().ok_or(FdtError::NotFound)?;
152 let range1 = ranges.next().ok_or(FdtError::NotFound)?;
153
154 let irq_masks = node.getprop_cells(cstr!("interrupt-map-mask"))?.ok_or(FdtError::NotFound)?;
155 let irq_masks = CellChunkIterator::<{ PciInfo::IRQ_MASK_CELLS }>::new(irq_masks);
156 let irq_masks: ArrayVec<[PciIrqMask; PciInfo::MAX_IRQS]> =
157 irq_masks.take(PciInfo::MAX_IRQS).collect();
158
159 let irq_maps = node.getprop_cells(cstr!("interrupt-map"))?.ok_or(FdtError::NotFound)?;
160 let irq_maps = CellChunkIterator::<{ PciInfo::IRQ_MAP_CELLS }>::new(irq_maps);
161 let irq_maps: ArrayVec<[PciIrqMap; PciInfo::MAX_IRQS]> =
162 irq_maps.take(PciInfo::MAX_IRQS).collect();
163
164 Ok(PciInfo { ranges: [range0, range1], irq_masks, irq_maps })
165}
166
167fn validate_pci_info(pci_info: &PciInfo) -> Result<(), RebootReason> {
168 for range in pci_info.ranges.iter() {
169 validate_pci_addr_range(range)?;
170 }
171 for irq_mask in pci_info.irq_masks.iter() {
172 validate_pci_irq_mask(irq_mask)?;
173 }
174 for (idx, irq_map) in pci_info.irq_maps.iter().enumerate() {
175 validate_pci_irq_map(irq_map, idx)?;
176 }
177 Ok(())
178}
179
180fn validate_pci_addr_range(range: &PciAddrRange) -> Result<(), RebootReason> {
181 let mem_flags = PciMemoryFlags(range.addr.0);
182 let range_type = mem_flags.range_type();
183 let prefetchable = mem_flags.prefetchable();
184 let bus_addr = range.addr.1;
185 let cpu_addr = range.parent_addr;
186 let size = range.size;
187
188 if range_type != PciRangeType::Memory64 {
189 error!("Invalid range type {:?} for bus address {:#x} in PCI node", range_type, bus_addr);
190 return Err(RebootReason::InvalidFdt);
191 }
192 if prefetchable {
193 error!("PCI bus address {:#x} in PCI node is prefetchable", bus_addr);
194 return Err(RebootReason::InvalidFdt);
195 }
196 // Enforce ID bus-to-cpu mappings, as used by crosvm.
197 if bus_addr != cpu_addr {
198 error!("PCI bus address: {:#x} is different from CPU address: {:#x}", bus_addr, cpu_addr);
199 return Err(RebootReason::InvalidFdt);
200 }
201
202 if bus_addr.checked_add(size).is_none() {
203 error!("PCI address range size {:#x} too big", size);
204 return Err(RebootReason::InvalidFdt);
205 }
206
207 Ok(())
208}
209
210fn validate_pci_irq_mask(irq_mask: &PciIrqMask) -> Result<(), RebootReason> {
Jiyong Park00ceff32023-03-13 05:43:23 +0000211 const IRQ_MASK_ADDR_HI: u32 = 0xf800;
212 const IRQ_MASK_ADDR_ME: u32 = 0x0;
213 const IRQ_MASK_ADDR_LO: u32 = 0x0;
214 const IRQ_MASK_ANY_IRQ: u32 = 0x7;
Jiyong Park6a8789a2023-03-21 14:50:59 +0900215 const EXPECTED: PciIrqMask =
Jiyong Park00ceff32023-03-13 05:43:23 +0000216 [IRQ_MASK_ADDR_HI, IRQ_MASK_ADDR_ME, IRQ_MASK_ADDR_LO, IRQ_MASK_ANY_IRQ];
Jiyong Park6a8789a2023-03-21 14:50:59 +0900217 if *irq_mask != EXPECTED {
218 error!("Invalid PCI irq mask {:#?}", irq_mask);
219 return Err(RebootReason::InvalidFdt);
Jiyong Park00ceff32023-03-13 05:43:23 +0000220 }
Jiyong Park6a8789a2023-03-21 14:50:59 +0900221 Ok(())
Jiyong Park00ceff32023-03-13 05:43:23 +0000222}
223
Jiyong Park6a8789a2023-03-21 14:50:59 +0900224fn validate_pci_irq_map(irq_map: &PciIrqMap, idx: usize) -> Result<(), RebootReason> {
Jiyong Park00ceff32023-03-13 05:43:23 +0000225 const PCI_DEVICE_IDX: usize = 11;
226 const PCI_IRQ_ADDR_ME: u32 = 0;
227 const PCI_IRQ_ADDR_LO: u32 = 0;
228 const PCI_IRQ_INTC: u32 = 1;
229 const AARCH64_IRQ_BASE: u32 = 4; // from external/crosvm/aarch64/src/lib.rs
230 const GIC_SPI: u32 = 0;
231 const IRQ_TYPE_LEVEL_HIGH: u32 = 4;
232
Jiyong Park6a8789a2023-03-21 14:50:59 +0900233 let pci_addr = (irq_map[0], irq_map[1], irq_map[2]);
234 let pci_irq_number = irq_map[3];
235 let _controller_phandle = irq_map[4]; // skipped.
236 let gic_addr = (irq_map[5], irq_map[6]); // address-cells is <2> for GIC
237 // interrupt-cells is <3> for GIC
238 let gic_peripheral_interrupt_type = irq_map[7];
239 let gic_irq_number = irq_map[8];
240 let gic_irq_type = irq_map[9];
Jiyong Park00ceff32023-03-13 05:43:23 +0000241
Jiyong Park6a8789a2023-03-21 14:50:59 +0900242 let phys_hi: u32 = (0x1 << PCI_DEVICE_IDX) * (idx + 1) as u32;
243 let expected_pci_addr = (phys_hi, PCI_IRQ_ADDR_ME, PCI_IRQ_ADDR_LO);
Jiyong Park00ceff32023-03-13 05:43:23 +0000244
Jiyong Park6a8789a2023-03-21 14:50:59 +0900245 if pci_addr != expected_pci_addr {
246 error!("PCI device address {:#x} {:#x} {:#x} in interrupt-map is different from expected address \
247 {:#x} {:#x} {:#x}",
248 pci_addr.0, pci_addr.1, pci_addr.2, expected_pci_addr.0, expected_pci_addr.1, expected_pci_addr.2);
249 return Err(RebootReason::InvalidFdt);
250 }
Jiyong Park00ceff32023-03-13 05:43:23 +0000251
Jiyong Park6a8789a2023-03-21 14:50:59 +0900252 if pci_irq_number != PCI_IRQ_INTC {
253 error!(
254 "PCI INT# {:#x} in interrupt-map is different from expected value {:#x}",
255 pci_irq_number, PCI_IRQ_INTC
256 );
257 return Err(RebootReason::InvalidFdt);
258 }
Jiyong Park00ceff32023-03-13 05:43:23 +0000259
Jiyong Park6a8789a2023-03-21 14:50:59 +0900260 if gic_addr != (0, 0) {
261 error!(
262 "GIC address {:#x} {:#x} in interrupt-map is different from expected address \
263 {:#x} {:#x}",
264 gic_addr.0, gic_addr.1, 0, 0
265 );
266 return Err(RebootReason::InvalidFdt);
267 }
268
269 if gic_peripheral_interrupt_type != GIC_SPI {
270 error!("GIC peripheral interrupt type {:#x} in interrupt-map is different from expected value \
271 {:#x}", gic_peripheral_interrupt_type, GIC_SPI);
272 return Err(RebootReason::InvalidFdt);
273 }
274
275 let irq_nr: u32 = AARCH64_IRQ_BASE + (idx as u32);
276 if gic_irq_number != irq_nr {
277 error!(
278 "GIC irq number {:#x} in interrupt-map is unexpected. Expected {:#x}",
279 gic_irq_number, irq_nr
280 );
281 return Err(RebootReason::InvalidFdt);
282 }
283
284 if gic_irq_type != IRQ_TYPE_LEVEL_HIGH {
285 error!(
286 "IRQ type in {:#x} is invalid. Must be LEVEL_HIGH {:#x}",
287 gic_irq_type, IRQ_TYPE_LEVEL_HIGH
288 );
289 return Err(RebootReason::InvalidFdt);
Jiyong Park00ceff32023-03-13 05:43:23 +0000290 }
291 Ok(())
292}
293
294#[derive(Default, Debug)]
295#[allow(dead_code)] // TODO: remove this
Jiyong Park6a8789a2023-03-21 14:50:59 +0900296struct SerialInfo {
297 addrs: ArrayVec<[u64; Self::MAX_SERIALS]>,
Jiyong Park00ceff32023-03-13 05:43:23 +0000298}
299
300impl SerialInfo {
Jiyong Park6a8789a2023-03-21 14:50:59 +0900301 const MAX_SERIALS: usize = 4;
Jiyong Park00ceff32023-03-13 05:43:23 +0000302}
303
Jiyong Park6a8789a2023-03-21 14:50:59 +0900304fn read_serial_info_from(fdt: &Fdt) -> libfdt::Result<SerialInfo> {
305 let mut addrs: ArrayVec<[u64; SerialInfo::MAX_SERIALS]> = Default::default();
306 for node in fdt.compatible_nodes(cstr!("ns16550a"))?.take(SerialInfo::MAX_SERIALS) {
307 let reg = node.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)?;
308 addrs.push(reg.addr);
Jiyong Park00ceff32023-03-13 05:43:23 +0000309 }
Jiyong Park6a8789a2023-03-21 14:50:59 +0900310 Ok(SerialInfo { addrs })
Jiyong Park00ceff32023-03-13 05:43:23 +0000311}
312
313#[derive(Debug)]
314#[allow(dead_code)] // TODO: remove this
Jiyong Park6a8789a2023-03-21 14:50:59 +0900315struct SwiotlbInfo {
Jiyong Park00ceff32023-03-13 05:43:23 +0000316 size: u64,
317 align: u64,
318}
319
Jiyong Park6a8789a2023-03-21 14:50:59 +0900320fn read_swiotlb_info_from(fdt: &Fdt) -> libfdt::Result<SwiotlbInfo> {
321 let node =
322 fdt.compatible_nodes(cstr!("restricted-dma-pool"))?.next().ok_or(FdtError::NotFound)?;
323 let size = node.getprop_u64(cstr!("size"))?.ok_or(FdtError::NotFound)?;
324 let align = node.getprop_u64(cstr!("alignment"))?.ok_or(FdtError::NotFound)?;
325 Ok(SwiotlbInfo { size, align })
326}
Jiyong Park00ceff32023-03-13 05:43:23 +0000327
Jiyong Park6a8789a2023-03-21 14:50:59 +0900328fn validate_swiotlb_info(swiotlb_info: &SwiotlbInfo) -> Result<(), RebootReason> {
329 let size = swiotlb_info.size;
330 let align = swiotlb_info.align;
Jiyong Park00ceff32023-03-13 05:43:23 +0000331
332 if size == 0 || (size % GUEST_PAGE_SIZE as u64) != 0 {
333 error!("Invalid swiotlb size {:#x}", size);
334 return Err(RebootReason::InvalidFdt);
335 }
336
337 if (align % GUEST_PAGE_SIZE as u64) != 0 {
338 error!("Invalid swiotlb alignment {:#x}", align);
339 return Err(RebootReason::InvalidFdt);
340 }
Jiyong Park6a8789a2023-03-21 14:50:59 +0900341 Ok(())
Jiyong Park00ceff32023-03-13 05:43:23 +0000342}
343
344#[derive(Debug)]
345#[allow(dead_code)] // TODO: remove this
Jiyong Park6a8789a2023-03-21 14:50:59 +0900346pub struct DeviceTreeInfo {
347 pub kernel_range: Option<Range<usize>>,
348 pub initrd_range: Option<Range<usize>>,
349 pub memory_range: Range<usize>,
350 num_cpus: usize,
Jiyong Park00ceff32023-03-13 05:43:23 +0000351 pci_info: PciInfo,
352 serial_info: SerialInfo,
353 swiotlb_info: SwiotlbInfo,
354}
355
356impl DeviceTreeInfo {
357 const RAM_BASE_ADDR: u64 = 0x8000_0000;
358}
359
Jiyong Park6a8789a2023-03-21 14:50:59 +0900360pub fn sanitize_device_tree(fdt: &mut libfdt::Fdt) -> Result<DeviceTreeInfo, RebootReason> {
Jiyong Park83316122023-03-21 09:39:39 +0900361 let info = parse_device_tree(fdt)?;
362 debug!("Device tree info: {:?}", info);
363
364 // TODO: replace fdt with the template DT
365 // TODO: patch the replaced fdt using info
Jiyong Park6a8789a2023-03-21 14:50:59 +0900366 Ok(info)
Jiyong Park83316122023-03-21 09:39:39 +0900367}
368
369fn parse_device_tree(fdt: &libfdt::Fdt) -> Result<DeviceTreeInfo, RebootReason> {
Jiyong Park6a8789a2023-03-21 14:50:59 +0900370 let kernel_range = read_kernel_range_from(fdt).map_err(|e| {
371 error!("Failed to read kernel range from DT: {e}");
372 RebootReason::InvalidFdt
373 })?;
374
375 let initrd_range = read_initrd_range_from(fdt).map_err(|e| {
376 error!("Failed to read initrd range from DT: {e}");
377 RebootReason::InvalidFdt
378 })?;
379
380 let memory_range = read_memory_range_from(fdt).map_err(|e| {
381 error!("Failed to read memory range from DT: {e}");
382 RebootReason::InvalidFdt
383 })?;
384 validate_memory_range(&memory_range)?;
385
386 let num_cpus = read_num_cpus_from(fdt).map_err(|e| {
387 error!("Failed to read num cpus from DT: {e}");
388 RebootReason::InvalidFdt
389 })?;
390 validate_num_cpus(num_cpus)?;
391
392 let pci_info = read_pci_info_from(fdt).map_err(|e| {
393 error!("Failed to read pci info from DT: {e}");
394 RebootReason::InvalidFdt
395 })?;
396 validate_pci_info(&pci_info)?;
397
398 let serial_info = read_serial_info_from(fdt).map_err(|e| {
399 error!("Failed to read serial info from DT: {e}");
400 RebootReason::InvalidFdt
401 })?;
402
403 let swiotlb_info = read_swiotlb_info_from(fdt).map_err(|e| {
404 error!("Failed to read swiotlb info from DT: {e}");
405 RebootReason::InvalidFdt
406 })?;
407 validate_swiotlb_info(&swiotlb_info)?;
408
Jiyong Park00ceff32023-03-13 05:43:23 +0000409 Ok(DeviceTreeInfo {
Jiyong Park6a8789a2023-03-21 14:50:59 +0900410 kernel_range,
411 initrd_range,
412 memory_range,
413 num_cpus,
414 pci_info,
415 serial_info,
416 swiotlb_info,
Jiyong Park00ceff32023-03-13 05:43:23 +0000417 })
418}
419
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000420/// Modifies the input DT according to the fields of the configuration.
421pub fn modify_for_next_stage(
422 fdt: &mut Fdt,
423 bcc: &[u8],
424 new_instance: bool,
425 strict_boot: bool,
426) -> libfdt::Result<()> {
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000427 fdt.unpack()?;
428
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000429 add_dice_node(fdt, bcc.as_ptr() as usize, bcc.len())?;
430
Jiyong Parkb87f3302023-03-21 10:03:11 +0900431 set_or_clear_chosen_flag(fdt, cstr!("avf,strict-boot"), strict_boot)?;
432 set_or_clear_chosen_flag(fdt, cstr!("avf,new-instance"), new_instance)?;
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000433
434 fdt.pack()?;
435
436 Ok(())
437}
438
439/// Add a "google,open-dice"-compatible reserved-memory node to the tree.
440fn add_dice_node(fdt: &mut Fdt, addr: usize, size: usize) -> libfdt::Result<()> {
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000441 // We reject DTs with missing reserved-memory node as validation should have checked that the
442 // "swiotlb" subnode (compatible = "restricted-dma-pool") was present.
Jiyong Parkb87f3302023-03-21 10:03:11 +0900443 let mut reserved_memory =
444 fdt.node_mut(cstr!("/reserved-memory"))?.ok_or(libfdt::FdtError::NotFound)?;
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000445
Jiyong Parkb87f3302023-03-21 10:03:11 +0900446 let mut dice = reserved_memory.add_subnode(cstr!("dice"))?;
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000447
Jiyong Parkb87f3302023-03-21 10:03:11 +0900448 dice.appendprop(cstr!("compatible"), b"google,open-dice\0")?;
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000449
Jiyong Parkb87f3302023-03-21 10:03:11 +0900450 dice.appendprop(cstr!("no-map"), &[])?;
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000451
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000452 let addr = addr.try_into().unwrap();
453 let size = size.try_into().unwrap();
Jiyong Parkb87f3302023-03-21 10:03:11 +0900454 dice.appendprop_addrrange(cstr!("reg"), addr, size)?;
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000455
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000456 Ok(())
457}
458
459fn set_or_clear_chosen_flag(fdt: &mut Fdt, flag: &CStr, value: bool) -> libfdt::Result<()> {
460 // TODO(b/249054080): Refactor to not panic if the DT doesn't contain a /chosen node.
461 let mut chosen = fdt.chosen_mut()?.unwrap();
462 if value {
463 chosen.setprop_empty(flag)?;
464 } else {
465 match chosen.delprop(flag) {
466 Ok(()) | Err(FdtError::NotFound) => (),
467 Err(e) => return Err(e),
468 }
469 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000470
471 Ok(())
472}