blob: 793eaac1f866278447ed3039333730c62b7c6999 [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
17use core::ffi::CStr;
18use core::ops::Range;
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +000019use libfdt::Fdt;
20use libfdt::FdtError;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000021
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +000022/// Extract from /config the address range containing the pre-loaded kernel.
23pub fn kernel_range(fdt: &libfdt::Fdt) -> libfdt::Result<Option<Range<usize>>> {
24 let config = CStr::from_bytes_with_nul(b"/config\0").unwrap();
25 let addr = CStr::from_bytes_with_nul(b"kernel-address\0").unwrap();
26 let size = CStr::from_bytes_with_nul(b"kernel-size\0").unwrap();
27
28 if let Some(config) = fdt.node(config)? {
29 if let (Some(addr), Some(size)) = (config.getprop_u32(addr)?, config.getprop_u32(size)?) {
30 let addr = addr as usize;
31 let size = size as usize;
32
33 return Ok(Some(addr..(addr + size)));
34 }
35 }
36
37 Ok(None)
38}
39
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000040/// Extract from /chosen the address range containing the pre-loaded ramdisk.
41pub fn initrd_range(fdt: &libfdt::Fdt) -> libfdt::Result<Option<Range<usize>>> {
42 let start = CStr::from_bytes_with_nul(b"linux,initrd-start\0").unwrap();
43 let end = CStr::from_bytes_with_nul(b"linux,initrd-end\0").unwrap();
44
45 if let Some(chosen) = fdt.chosen()? {
46 if let (Some(start), Some(end)) = (chosen.getprop_u32(start)?, chosen.getprop_u32(end)?) {
47 return Ok(Some((start as usize)..(end as usize)));
48 }
49 }
50
51 Ok(None)
52}
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +000053
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +000054/// Modifies the input DT according to the fields of the configuration.
55pub fn modify_for_next_stage(
56 fdt: &mut Fdt,
57 bcc: &[u8],
58 new_instance: bool,
59 strict_boot: bool,
60) -> libfdt::Result<()> {
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +000061 fdt.unpack()?;
62
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +000063 add_dice_node(fdt, bcc.as_ptr() as usize, bcc.len())?;
64
65 set_or_clear_chosen_flag(
66 fdt,
67 CStr::from_bytes_with_nul(b"avf,strict-boot\0").unwrap(),
68 strict_boot,
69 )?;
70 set_or_clear_chosen_flag(
71 fdt,
72 CStr::from_bytes_with_nul(b"avf,new-instance\0").unwrap(),
73 new_instance,
74 )?;
75
76 fdt.pack()?;
77
78 Ok(())
79}
80
81/// Add a "google,open-dice"-compatible reserved-memory node to the tree.
82fn add_dice_node(fdt: &mut Fdt, addr: usize, size: usize) -> libfdt::Result<()> {
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +000083 let reserved_memory = CStr::from_bytes_with_nul(b"/reserved-memory\0").unwrap();
84 // We reject DTs with missing reserved-memory node as validation should have checked that the
85 // "swiotlb" subnode (compatible = "restricted-dma-pool") was present.
86 let mut reserved_memory = fdt.node_mut(reserved_memory)?.ok_or(libfdt::FdtError::NotFound)?;
87
88 let dice = CStr::from_bytes_with_nul(b"dice\0").unwrap();
89 let mut dice = reserved_memory.add_subnode(dice)?;
90
91 let compatible = CStr::from_bytes_with_nul(b"compatible\0").unwrap();
92 dice.appendprop(compatible, b"google,open-dice\0")?;
93
94 let no_map = CStr::from_bytes_with_nul(b"no-map\0").unwrap();
95 dice.appendprop(no_map, &[])?;
96
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +000097 let addr = addr.try_into().unwrap();
98 let size = size.try_into().unwrap();
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +000099 let reg = CStr::from_bytes_with_nul(b"reg\0").unwrap();
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000100 dice.appendprop_addrrange(reg, addr, size)?;
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000101
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000102 Ok(())
103}
104
105fn set_or_clear_chosen_flag(fdt: &mut Fdt, flag: &CStr, value: bool) -> libfdt::Result<()> {
106 // TODO(b/249054080): Refactor to not panic if the DT doesn't contain a /chosen node.
107 let mut chosen = fdt.chosen_mut()?.unwrap();
108 if value {
109 chosen.setprop_empty(flag)?;
110 } else {
111 match chosen.delprop(flag) {
112 Ok(()) | Err(FdtError::NotFound) => (),
113 Err(e) => return Err(e),
114 }
115 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000116
117 Ok(())
118}