├── .github └── workflows │ └── test.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── bl808.dtb ├── cv1812cp_milkv_duo256m_sd.dtb ├── hifive-unmatched-a00.dtb ├── hifive-unmatched-a00.rs ├── qemu-virt.dtb ├── qemu-virt.rs ├── re_encode.rs └── serialize.rs ├── rustfmt.toml ├── src ├── common.rs ├── de.rs ├── de_mut │ ├── cursor.rs │ ├── data.rs │ ├── matrix.rs │ ├── mod.rs │ ├── node.rs │ ├── node_seq.rs │ ├── reg.rs │ ├── str_seq.rs │ ├── struct_access.rs │ └── structs.rs ├── error.rs ├── lib.rs ├── ser │ ├── mod.rs │ ├── patch.rs │ ├── pointer.rs │ ├── serializer.rs │ └── string_block.rs ├── tag.rs ├── utils │ ├── chosen.rs │ └── mod.rs └── value │ ├── compatible.rs │ ├── cpu.rs │ ├── mod.rs │ ├── riscv_pmu.rs │ └── tree.rs └── tests ├── bl808.rs ├── hifive-unmatched-a00.rs └── qemu-virt.rs /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Cargo 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | # By default, RUSTFLAGS with “-D warnings” turns “asm_const” warnings into errors. 8 | RUSTFLAGS: 9 | 10 | jobs: 11 | fmt: 12 | name: Rustfmt all packages 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions-rust-lang/setup-rust-toolchain@v1 17 | with: 18 | components: rustfmt 19 | - name: Rustfmt Check 20 | uses: actions-rust-lang/rustfmt@v1 21 | 22 | test: 23 | name: Test 24 | needs: fmt 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | - uses: actions-rust-lang/setup-rust-toolchain@v1 29 | with: 30 | toolchain: nightly 31 | - name: Run tests 32 | run: cargo test 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | *.dts 4 | 5 | # Visual Studio Code configuration files 6 | .vscode/ 7 | 8 | *.dtb 9 | !examples/*.dtb 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde-device-tree" 3 | version = "0.0.1" 4 | authors = ["Luo Jia "] 5 | repository = "https://github.com/luojia65/serde-device-tree" 6 | documentation = "https://docs.rs/serde-device-tree" 7 | license = "MulanPSL-2.0" 8 | description = "A Device Tree blob serialization file format" 9 | readme = "README.md" 10 | keywords = ["serde", "serialization"] 11 | categories = ["no-std", "encoding"] 12 | edition = "2024" 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [dependencies] 17 | serde = { version = "1.0", default-features = false, features = ["derive"] } 18 | dyn_serde = { version = "1.0.2", default-features = false, optional = true } 19 | 20 | [features] 21 | default = ["std", "ser"] 22 | 23 | ser = ["dep:dyn_serde"] 24 | std = ["serde/std"] 25 | alloc = ["serde/alloc"] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 木兰宽松许可证, 第2版 2 | 3 | 2020年1月 http://license.coscl.org.cn/MulanPSL2 4 | 5 | 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: 6 | 7 | 0. 定义 8 | 9 | “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 10 | 11 | “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 12 | 13 | “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 14 | 15 | “法人实体”是指提交贡献的机构及其“关联实体”。 16 | 17 | “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 18 | 19 | 1. 授予版权许可 20 | 21 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 22 | 23 | 2. 授予专利许可 24 | 25 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 26 | 27 | 3. 无商标许可 28 | 29 | “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 30 | 31 | 4. 分发限制 32 | 33 | 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 34 | 35 | 5. 免责声明与责任限制 36 | 37 | “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 38 | 39 | 6. 语言 40 | 41 | “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 42 | 43 | 条款结束 44 | 45 | 如何将木兰宽松许可证,第2版,应用到您的软件 46 | 47 | 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: 48 | 49 | 1,请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; 50 | 51 | 2,请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; 52 | 53 | 3,请将如下声明文本放入每个源文件的头部注释中。 54 | 55 | Copyright (c) [Year] [name of copyright holder] [Software Name] is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. 56 | 57 | January 2020 http://license.coscl.org.cn/MulanPSL2 58 | 59 | Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: 60 | 61 | 0. Definition 62 | 63 | Software means the program and related documents which are licensed under this License and comprise all Contribution(s). 64 | 65 | Contribution means the copyrightable work licensed by a particular Contributor under this License. 66 | 67 | Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. 68 | 69 | Legal Entity means the entity making a Contribution and all its Affiliates. 70 | 71 | Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. 72 | 73 | 1. Grant of Copyright License 74 | 75 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. 76 | 77 | 2. Grant of Patent License 78 | 79 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. 80 | 81 | 3. No Trademark License 82 | 83 | No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. 84 | 85 | 4. Distribution Restriction 86 | 87 | You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. 88 | 89 | 5. Disclaimer of Warranty and Limitation of Liability 90 | 91 | THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 92 | 93 | 6. Language 94 | 95 | THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. 96 | 97 | END OF THE TERMS AND CONDITIONS 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serde_device_tree 2 | 3 | Use [serde](https://serde.rs) framework to deserialize Device Tree Blob binary files; no_std compatible. 4 | 5 | ## Use this library 6 | 7 | Run example: 8 | 9 | ``` 10 | cargo run --example hifive-unmatched-a00 11 | ``` 12 | 13 | You'll get following results: 14 | 15 | ``` 16 | Compiling serde_device_tree v0.1.0 (D:\RustSBI\serde_device_tree) 17 | Finished dev [unoptimized + debuginfo] target(s) in 0.92s 18 | Running `target\debug\examples\hifive-unmatched-a00.exe` 19 | #address_cells = 2 20 | #size_cells = 2 21 | model = SiFive HiFive Unmatched A00 22 | compatible = sifive,hifive-unmatched-a00sifive,fu740-c000sifive,fu740 23 | stdout = serial0 24 | cpu timebase frequency = 1000000 25 | cpu u_boot_dm_spl = true 26 | cpu cpu@0, compaible = sifive,bullet0riscv 27 | cpu cpu@1, compaible = sifive,bullet0riscv 28 | cpu cpu@2, compaible = sifive,bullet0riscv 29 | cpu cpu@3, compaible = sifive,bullet0riscv 30 | cpu cpu@4, compaible = sifive,bullet0riscv 31 | ``` 32 | -------------------------------------------------------------------------------- /examples/bl808.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustsbi/serde-device-tree/d4af62567b852c575ff64d65469eab85c91fbe10/examples/bl808.dtb -------------------------------------------------------------------------------- /examples/cv1812cp_milkv_duo256m_sd.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustsbi/serde-device-tree/d4af62567b852c575ff64d65469eab85c91fbe10/examples/cv1812cp_milkv_duo256m_sd.dtb -------------------------------------------------------------------------------- /examples/hifive-unmatched-a00.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustsbi/serde-device-tree/d4af62567b852c575ff64d65469eab85c91fbe10/examples/hifive-unmatched-a00.dtb -------------------------------------------------------------------------------- /examples/hifive-unmatched-a00.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | use alloc::collections::BTreeMap; 4 | use serde::Deserialize; 5 | use serde_device_tree::Compatible; 6 | 7 | #[derive(Debug, Deserialize)] 8 | struct Tree<'a> { 9 | #[serde(rename = "#address-cells")] 10 | num_address_cells: u32, 11 | #[serde(rename = "#size-cells")] 12 | num_size_cells: u32, 13 | model: &'a str, 14 | compatible: Compatible<'a>, 15 | chosen: Option>, 16 | cpus: Cpus<'a>, 17 | } 18 | 19 | #[derive(Debug, Deserialize)] 20 | #[serde(rename_all = "kebab-case")] 21 | struct Chosen<'a> { 22 | stdout_path: Option<&'a str>, 23 | } 24 | 25 | #[derive(Debug, Deserialize)] 26 | #[serde(rename_all = "kebab-case")] 27 | struct Cpus<'a> { 28 | timebase_frequency: u32, 29 | #[serde(rename = "u-boot,dm-spl")] 30 | u_boot_dm_spl: bool, 31 | #[serde(flatten, borrow)] 32 | cpu: BTreeMap<&'a str, MaybeCpu<'a>>, 33 | } 34 | 35 | #[derive(Debug, Deserialize)] 36 | #[serde(untagged)] 37 | enum MaybeCpu<'a> { 38 | Cpu(Cpu<'a>), 39 | #[allow(unused)] 40 | Bytes(&'a [u8]), 41 | } 42 | 43 | #[derive(Debug, Deserialize)] 44 | struct Cpu<'a> { 45 | #[serde(borrow)] 46 | compatible: Compatible<'a>, 47 | } 48 | 49 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("hifive-unmatched-a00.dtb"); 50 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 51 | 52 | #[repr(align(8))] 53 | struct AlignedBuffer { 54 | pub data: [u8; RAW_DEVICE_TREE.len()], 55 | } 56 | 57 | fn main() { 58 | let mut aligned_data: Box = Box::new(AlignedBuffer { 59 | data: [0; BUFFER_SIZE], 60 | }); 61 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 62 | let ptr = aligned_data.data.as_ptr(); 63 | let t: Tree = unsafe { serde_device_tree::from_raw(ptr) }.unwrap(); 64 | println!("#address_cells = {}", t.num_address_cells); 65 | println!("#size_cells = {}", t.num_size_cells); 66 | println!("model = {}", t.model); 67 | println!("compatible = {:?}", t.compatible); 68 | if let Some(chosen) = t.chosen { 69 | if let Some(stdout_path) = chosen.stdout_path { 70 | println!("stdout = {}", stdout_path); 71 | } else { 72 | println!("stdout not chosen"); 73 | } 74 | } 75 | println!("cpu timebase frequency = {}", t.cpus.timebase_frequency); 76 | println!("cpu u_boot_dm_spl = {}", t.cpus.u_boot_dm_spl); 77 | for (cpu_name, cpu) in t.cpus.cpu { 78 | if let MaybeCpu::Cpu(cpu) = cpu { 79 | println!("cpu {}, compaible = {:?}", cpu_name, cpu.compatible) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/qemu-virt.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustsbi/serde-device-tree/d4af62567b852c575ff64d65469eab85c91fbe10/examples/qemu-virt.dtb -------------------------------------------------------------------------------- /examples/qemu-virt.rs: -------------------------------------------------------------------------------- 1 | //! 这是一个 `from_raw_mut` 反序列化设备树的示例。不需要 `alloc`。 2 | // extern crate alloc; 3 | 4 | use serde::Deserialize; 5 | 6 | // - `DtbPtr`: 验证设备树首部正确性,后续也可借助这个类型传递设备树,多次解析不必重复验证。 7 | // - `Dtb`: 管理反序列化出的类型生命周期。 8 | // - `from_raw_mut`: 反序列化。 9 | // - `Reg`: 常见属性。其值解析方式由 `#address-cells` 和 `#size-cells` 决定。 10 | // - `NodeSeq`: name@... 区分的一组同级同类的连续节点,这个类型要求可变的内存。 11 | // - `StrSeq`: '\0' 分隔的一组字符串,设备树中一种常见的属性类型,这个类型要求可变的内存。 12 | use serde_device_tree::{ 13 | Dtb, DtbPtr, 14 | buildin::{Node, NodeSeq, Reg, StrSeq}, 15 | error::Error, 16 | from_raw_mut, 17 | }; 18 | 19 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("qemu-virt.dtb"); 20 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 21 | 22 | #[repr(align(8))] 23 | struct AlignedBuffer { 24 | pub data: [u8; RAW_DEVICE_TREE.len()], 25 | } 26 | 27 | fn main() -> Result<(), Error> { 28 | // 整个设备树二进制文件需要装载到一块可写的内存区域 29 | let mut aligned_data: Box = Box::new(AlignedBuffer { 30 | data: [0; BUFFER_SIZE], 31 | }); 32 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 33 | let mut slice = aligned_data.data.to_vec(); 34 | // 这一步验证了设备树首部的正确性,`DtbPtr` 类型可以安全地传递到任何地方, 35 | // 甚至跨地址空间(如果你知道偏移的话)。 36 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr())?; 37 | // 构造一个方便解析的 Dtb 结构,这个结构不再支持跨线程传递 38 | let dtb = Dtb::from(ptr).share(); 39 | 40 | // 实际使用中,将类型定义在专门的位置更合适, 41 | // 这里是为了阅读的顺序考虑。 42 | // 43 | // 关于 `#[derive(Deserialize)]`,看[这篇文档](https://serde.rs/derive.html)。 44 | // 关于 `rename` 等 Attribute,看[这篇文档](https://serde.rs/attributes.html)。 45 | // 46 | // 推荐用 `StrSeq<'a>` 替换所有 `&'a str`,即使肯定只有一个字符串。 47 | // 后者在 `derive` 时可能引发奇怪的生命周期问题。 48 | // 49 | // 许多外设可能有不止一个,用 @... 区分,用 `NodeSeq` 映射这类节点。 50 | // 注意!解析器要求这类节点必须连续出现。 51 | 52 | #[derive(Deserialize)] 53 | struct Tree<'a> { 54 | compatible: StrSeq<'a>, 55 | model: StrSeq<'a>, 56 | chosen: Option>, 57 | cpus: Cpus<'a>, 58 | memory: NodeSeq<'a>, 59 | soc: Node<'a>, 60 | } 61 | 62 | #[derive(Deserialize)] 63 | #[serde(rename_all = "kebab-case")] 64 | struct Chosen<'a> { 65 | stdout_path: Option>, 66 | } 67 | 68 | #[derive(Deserialize)] 69 | #[serde(rename_all = "kebab-case")] 70 | struct Cpus<'a> { 71 | timebase_frequency: u32, 72 | cpu: NodeSeq<'a>, 73 | } 74 | 75 | #[allow(dead_code)] 76 | #[derive(Deserialize, Debug)] 77 | struct Cpu<'a> { 78 | compatible: StrSeq<'a>, 79 | device_type: StrSeq<'a>, 80 | status: StrSeq<'a>, 81 | #[serde(rename = "riscv,isa")] 82 | isa: StrSeq<'a>, 83 | #[serde(rename = "mmu-type")] 84 | mmu: StrSeq<'a>, 85 | } 86 | 87 | #[derive(Deserialize)] 88 | struct Memory<'a> { 89 | device_type: StrSeq<'a>, 90 | reg: Reg<'a>, 91 | } 92 | 93 | #[allow(dead_code)] 94 | #[derive(Deserialize)] 95 | struct Soc<'a> { 96 | virtio_mmio: NodeSeq<'a>, 97 | } 98 | 99 | #[derive(Deserialize)] 100 | struct VirtIoMmio<'a> { 101 | reg: Reg<'a>, 102 | } 103 | 104 | { 105 | // 解析! 106 | let root: Node = from_raw_mut(&dtb).unwrap(); 107 | let t: Tree = root.deserialize(); 108 | 109 | println!("model = {:?}", t.model); 110 | println!("compatible = {:?}", t.compatible); 111 | if let Some(chosen) = t.chosen { 112 | if let Some(stdout_path) = chosen.stdout_path { 113 | println!("stdout = {:?}", stdout_path); 114 | } else { 115 | println!("stdout not chosen"); 116 | } 117 | } 118 | println!("cpu timebase frequency = {}", t.cpus.timebase_frequency); 119 | 120 | // 可以读取同类节点的数量 121 | println!("number of cpu = {}", t.cpus.cpu.len()); 122 | for cpu in t.cpus.cpu.iter() { 123 | println!("cpu@{}: {:?}", cpu.at(), cpu.deserialize::()); 124 | } 125 | 126 | for item in t.memory.iter() { 127 | let mem: Memory = item.deserialize(); 128 | println!( 129 | "memory@{}({:?}): {:#x?}", 130 | item.at(), 131 | mem.device_type, 132 | mem.reg 133 | ); 134 | } 135 | 136 | println!("{:?}", t.soc); 137 | for current_node in t.soc.nodes() { 138 | if current_node.get_parsed_name().0 == "virtio_mmio" { 139 | let mmio = current_node.deserialize::(); 140 | println!("{:?} {:?}", current_node.get_parsed_name(), mmio.reg); 141 | } 142 | } 143 | 144 | // 解析过程中,设备树的内容被修改了。 145 | // 因此若要以其他方式再次访问设备树,先将这次解析的结果释放。 146 | // assert_ne!(slice, RAW_DEVICE_TREE); 147 | } 148 | // 释放后,内存会恢复原状。 149 | assert_eq!(slice, RAW_DEVICE_TREE); 150 | 151 | Ok(()) 152 | } 153 | -------------------------------------------------------------------------------- /examples/re_encode.rs: -------------------------------------------------------------------------------- 1 | use serde_device_tree::ser::{patch::Patch, serializer::ValueType}; 2 | use serde_device_tree::{Dtb, DtbPtr, buildin::Node, error::Error, from_raw_mut}; 3 | 4 | use std::io::prelude::*; 5 | 6 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("qemu-virt.dtb"); 7 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 8 | 9 | #[repr(align(8))] 10 | struct AlignedBuffer { 11 | pub data: [u8; RAW_DEVICE_TREE.len()], 12 | } 13 | 14 | fn main() -> Result<(), Error> { 15 | let mut aligned_data: Box = Box::new(AlignedBuffer { 16 | data: [0; BUFFER_SIZE], 17 | }); 18 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 19 | let mut buf = [0u8; RAW_DEVICE_TREE.len() * 2]; 20 | let mut slice = aligned_data.data.to_vec(); 21 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr())?; 22 | let dtb = Dtb::from(ptr).share(); 23 | 24 | let root: Node = from_raw_mut(&dtb).unwrap(); 25 | let patch: Patch = Patch::new("/chosen/a", &"1", ValueType::Prop); 26 | serde_device_tree::ser::to_dtb(&root, &[patch], &mut buf).unwrap(); 27 | 28 | let mut file = std::fs::File::create("gen.dtb").unwrap(); 29 | file.write_all(&buf).unwrap(); 30 | 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /examples/serialize.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | use std::io::prelude::*; 3 | 4 | use serde_device_tree::ser::serializer::ValueType; 5 | 6 | const MAX_SIZE: usize = 256 + 32; 7 | 8 | fn main() { 9 | #[derive(Serialize)] 10 | struct Base { 11 | pub hello: u32, 12 | pub base1: Base1, 13 | pub hello2: u32, 14 | pub base2: Base1, 15 | } 16 | #[derive(Serialize)] 17 | struct Base1 { 18 | pub hello: &'static str, 19 | } 20 | let mut buf1 = [0u8; MAX_SIZE]; 21 | 22 | { 23 | let new_base = Base1 { hello: "added" }; 24 | let patch = 25 | serde_device_tree::ser::patch::Patch::new("/base3", &new_base as _, ValueType::Node); 26 | let list = [patch]; 27 | let base = Base { 28 | hello: 0xdeedbeef, 29 | base1: Base1 { 30 | hello: "Hello, World!", 31 | }, 32 | hello2: 0x11223344, 33 | base2: Base1 { hello: "Roger" }, 34 | }; 35 | serde_device_tree::ser::to_dtb(&base, &list, &mut buf1).unwrap(); 36 | } 37 | let mut file = std::fs::File::create("gen.dtb").unwrap(); 38 | file.write_all(&buf1).unwrap(); 39 | } 40 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # Use rustfmt to format code 2 | 3 | edition = "2024" 4 | # Empty file. 5 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Error; 2 | 3 | #[derive(Debug, Clone)] 4 | #[repr(C)] 5 | pub(crate) struct Header { 6 | pub magic: u32, 7 | pub total_size: u32, 8 | pub off_dt_struct: u32, 9 | pub off_dt_strings: u32, 10 | pub off_mem_rsvmap: u32, 11 | pub version: u32, 12 | pub last_comp_version: u32, 13 | pub boot_cpuid_phys: u32, 14 | pub size_dt_strings: u32, 15 | pub size_dt_struct: u32, 16 | } 17 | 18 | pub const DEVICE_TREE_MAGIC: u32 = 0xD00DFEED; 19 | const U32_LEN: u32 = core::mem::size_of::() as _; 20 | 21 | pub(crate) const ALIGN: usize = core::mem::align_of::(); 22 | pub(crate) const HEADER_LEN: u32 = core::mem::size_of::
() as _; 23 | pub(crate) const FDT_BEGIN_NODE: u32 = 0x1; 24 | pub(crate) const FDT_END_NODE: u32 = 0x2; 25 | pub(crate) const FDT_PROP: u32 = 0x3; 26 | pub(crate) const FDT_NOP: u32 = 0x4; 27 | pub(crate) const FDT_END: u32 = 0x9; 28 | pub(crate) const SUPPORTED_VERSION: u32 = 17; 29 | 30 | impl Header { 31 | pub fn verify(&self) -> Result<(), Error> { 32 | let header_base = self as *const _ as usize; 33 | // --- 34 | let magic = u32::from_be(self.magic); 35 | if magic != DEVICE_TREE_MAGIC { 36 | return Err(Error::invalid_magic(magic)); 37 | } 38 | // --- 39 | let last_comp_version = u32::from_be(self.last_comp_version); 40 | if last_comp_version > SUPPORTED_VERSION { 41 | let file_index = (&self.last_comp_version as *const _ as usize) - header_base; 42 | return Err(Error::incompatible_version( 43 | last_comp_version, 44 | SUPPORTED_VERSION, 45 | file_index, 46 | )); 47 | } 48 | // --- 49 | let total_size = u32::from_be(self.total_size); 50 | if total_size < HEADER_LEN { 51 | let file_index = (&self.total_size as *const _ as usize) - header_base; 52 | return Err(Error::header_too_short(total_size, HEADER_LEN, file_index)); 53 | } 54 | // --- 55 | let off_dt_struct = u32::from_be(self.off_dt_struct); 56 | if off_dt_struct < HEADER_LEN { 57 | let file_index = (&self.off_dt_struct as *const _ as usize) - header_base; 58 | return Err(Error::structure_index_underflow( 59 | off_dt_struct, 60 | HEADER_LEN, 61 | file_index, 62 | )); 63 | } 64 | let size_dt_struct = u32::from_be(self.size_dt_struct); 65 | if off_dt_struct + size_dt_struct > total_size { 66 | let file_index = (&self.size_dt_struct as *const _ as usize) - header_base; 67 | return Err(Error::structure_index_overflow( 68 | off_dt_struct + size_dt_struct, 69 | HEADER_LEN, 70 | file_index, 71 | )); 72 | } 73 | // --- 74 | let dt_struct = unsafe { 75 | core::slice::from_raw_parts( 76 | (header_base + off_dt_struct as usize) as *const u32, 77 | (size_dt_struct / U32_LEN) as usize, 78 | ) 79 | }; 80 | if u32::from_be(dt_struct[0]) != FDT_BEGIN_NODE { 81 | let file_index = dt_struct.as_ptr() as usize - header_base; 82 | return Err(Error::invalid_tag_id( 83 | u32::from_be(dt_struct[0]), 84 | file_index, 85 | )); 86 | } 87 | if u32::from_be(dt_struct[1]) != 0 { 88 | let file_index = dt_struct[1..].as_ptr() as usize - header_base; 89 | return Err(Error::invalid_tag_id( 90 | u32::from_be(dt_struct[1]), 91 | file_index, 92 | )); 93 | } 94 | let dt_struct_tail = &dt_struct[dt_struct.len() - 2..]; 95 | if u32::from_be(dt_struct_tail[0]) != FDT_END_NODE { 96 | let file_index = dt_struct_tail.as_ptr() as usize - header_base; 97 | return Err(Error::invalid_tag_id( 98 | u32::from_be(dt_struct_tail[0]), 99 | file_index, 100 | )); 101 | } 102 | if u32::from_be(dt_struct_tail[1]) != FDT_END { 103 | let file_index = dt_struct_tail[1..].as_ptr() as usize - header_base; 104 | return Err(Error::invalid_tag_id( 105 | u32::from_be(dt_struct_tail[1]), 106 | file_index, 107 | )); 108 | } 109 | // --- 110 | let off_dt_strings = u32::from_be(self.off_dt_strings); 111 | if off_dt_strings < HEADER_LEN { 112 | let file_index = (&self.off_dt_strings as *const _ as usize) - header_base; 113 | return Err(Error::string_index_underflow( 114 | off_dt_strings, 115 | HEADER_LEN, 116 | file_index, 117 | )); 118 | } 119 | let size_dt_strings = u32::from_be(self.size_dt_strings); 120 | if off_dt_struct + size_dt_strings > total_size { 121 | let file_index = (&self.size_dt_strings as *const _ as usize) - header_base; 122 | return Err(Error::string_index_overflow( 123 | off_dt_strings, 124 | HEADER_LEN, 125 | file_index, 126 | )); 127 | } 128 | // --- 129 | let off_mem_rsvmap = u32::from_be(self.off_mem_rsvmap); 130 | if off_mem_rsvmap < HEADER_LEN { 131 | let file_index = (&self.off_mem_rsvmap as *const _ as usize) - header_base; 132 | return Err(Error::mem_rsvmap_index_underflow( 133 | off_mem_rsvmap, 134 | HEADER_LEN, 135 | file_index, 136 | )); 137 | } 138 | Ok(()) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/de.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 HUST IoT Security Lab 2 | // serde_device_tree is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | //! Deserialize device tree data to a Rust data structure. 12 | 13 | use crate::{ 14 | common::*, 15 | error::{Error, Result}, 16 | tag::{Tag, Tags}, 17 | }; 18 | use core::iter::Peekable; 19 | use serde::de; 20 | 21 | /// Deserialize an instance of type `T` from raw pointer of device tree blob. 22 | /// 23 | /// This function is useful in developing device tree compatible firmware 24 | /// or operating system kernels to parse structure from previous bootloading 25 | /// stage. 26 | /// 27 | /// # Safety 28 | /// 29 | /// TODO 30 | /// 31 | /// # Example 32 | /// 33 | /// ``` 34 | /// # const RAW_DEVICE_TREE: &'static [u8] = include_bytes!("../examples/hifive-unmatched-a00.dtb"); 35 | /// # const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 36 | /// # #[repr(align(4))] 37 | /// # struct AlignedBuffer { 38 | /// # pub data: [u8; RAW_DEVICE_TREE.len()], 39 | /// # } 40 | /// # let mut aligned_data: Box = Box::new(AlignedBuffer { 41 | /// # data: [0; BUFFER_SIZE], 42 | /// # }); 43 | /// # aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 44 | /// # let fdt_ptr = aligned_data.data.as_ptr(); 45 | /// use serde::Deserialize; 46 | /// 47 | /// #[derive(Debug, Deserialize)] 48 | /// struct Tree<'a> { 49 | /// #[serde(borrow)] 50 | /// chosen: Option>, 51 | /// } 52 | /// 53 | /// #[derive(Debug, Deserialize)] 54 | /// #[serde(rename_all = "kebab-case")] 55 | /// struct Chosen<'a> { 56 | /// stdout_path: Option<&'a str>, 57 | /// } 58 | /// 59 | /// let tree: Tree = unsafe { serde_device_tree::from_raw(fdt_ptr as *const u8) } 60 | /// .expect("parse device tree"); 61 | /// if let Some(chosen) = tree.chosen { 62 | /// if let Some(stdout_path) = chosen.stdout_path { 63 | /// println!("stdout path: {}", stdout_path); 64 | /// } 65 | /// } 66 | /// ``` 67 | pub unsafe fn from_raw<'de, T>(ptr: *const u8) -> Result 68 | where 69 | T: de::Deserialize<'de>, 70 | { 71 | unsafe { 72 | // read header 73 | if (ptr as usize) & (ALIGN - 1) != 0 { 74 | return Err(Error::unaligned(ptr as usize)); 75 | } 76 | let header = &*(ptr as *const Header); 77 | header.verify()?; 78 | 79 | let total_size = u32::from_be(header.total_size); 80 | let raw_data_len = (total_size - HEADER_LEN) as usize; 81 | let ans_ptr = core::ptr::slice_from_raw_parts(ptr, raw_data_len); 82 | let ans_ptr = ans_ptr as *const DeviceTree; 83 | let device_tree: &DeviceTree = &*ans_ptr; 84 | let tags = device_tree.tags(); 85 | let mut d = Deserializer { 86 | tags: tags.peekable(), 87 | }; 88 | let ret = T::deserialize(&mut d)?; 89 | Ok(ret) 90 | } 91 | } 92 | 93 | #[derive(Debug)] 94 | struct DeviceTree { 95 | header: Header, 96 | data: [u8], 97 | } 98 | 99 | impl DeviceTree { 100 | pub fn tags(&self) -> Tags { 101 | let structure_addr = (u32::from_be(self.header.off_dt_struct) - HEADER_LEN) as usize; 102 | let structure_len = u32::from_be(self.header.size_dt_struct) as usize; 103 | let strings_addr = (u32::from_be(self.header.off_dt_strings) - HEADER_LEN) as usize; 104 | let strings_len = u32::from_be(self.header.size_dt_strings) as usize; 105 | Tags::new( 106 | &self.data[structure_addr..structure_addr + structure_len], 107 | &self.data[strings_addr..strings_addr + strings_len], 108 | structure_addr, 109 | ) 110 | } 111 | } 112 | 113 | #[derive(Debug, Clone)] 114 | pub struct Deserializer<'a> { 115 | tags: Peekable>, 116 | } 117 | 118 | impl<'a> Deserializer<'a> { 119 | fn next_tag(&mut self) -> Result, usize)>> { 120 | self.tags.next().transpose() 121 | } 122 | fn peek_tag(&mut self) -> Result>> { 123 | match self.tags.peek() { 124 | Some(Ok((t, _i))) => Ok(Some(*t)), 125 | Some(Err(e)) => Err(e.clone()), 126 | None => Ok(None), 127 | } 128 | } 129 | fn peek_tag_index(&mut self) -> Result, usize)>> { 130 | match self.tags.peek() { 131 | Some(Ok(t)) => Ok(Some(t)), 132 | Some(Err(e)) => Err(e.clone()), 133 | None => Ok(None), 134 | } 135 | } 136 | fn eat_tag(&mut self) -> Result<()> { 137 | match self.tags.next() { 138 | Some(Ok(_t)) => Ok(()), 139 | Some(Err(e)) => Err(e), 140 | None => Ok(()), 141 | } 142 | } 143 | } 144 | 145 | impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> { 146 | type Error = Error; 147 | 148 | fn deserialize_any(self, visitor: V) -> Result 149 | where 150 | V: de::Visitor<'de>, 151 | { 152 | match self.peek_tag()? { 153 | Some(Tag::Prop(_, value_slice)) => { 154 | if value_slice.is_empty() { 155 | self.deserialize_bool(visitor) 156 | } else if value_slice.len() == 4 { 157 | self.deserialize_u32(visitor) 158 | } else { 159 | self.deserialize_bytes(visitor) // by default, it's bytes 160 | } 161 | } 162 | Some(Tag::Begin(_name_slice)) => self.deserialize_map(visitor), 163 | Some(Tag::End) => todo!(), 164 | _ => todo!(), 165 | } 166 | } 167 | 168 | fn deserialize_bool(self, visitor: V) -> Result 169 | where 170 | V: de::Visitor<'de>, 171 | { 172 | match self.peek_tag_index()? { 173 | Some((Tag::Prop(value_slice, _name_slice), _file_index)) => { 174 | if value_slice.is_empty() { 175 | self.eat_tag()?; 176 | visitor.visit_bool(true) 177 | } else { 178 | panic!() 179 | } 180 | } 181 | _ => panic!(), 182 | } 183 | } 184 | 185 | fn deserialize_i8(self, visitor: V) -> Result 186 | where 187 | V: de::Visitor<'de>, 188 | { 189 | let _ = visitor; 190 | todo!() 191 | } 192 | 193 | fn deserialize_i16(self, visitor: V) -> Result 194 | where 195 | V: de::Visitor<'de>, 196 | { 197 | let _ = visitor; 198 | todo!() 199 | } 200 | 201 | fn deserialize_i32(self, visitor: V) -> Result 202 | where 203 | V: de::Visitor<'de>, 204 | { 205 | let _ = visitor; 206 | todo!() 207 | } 208 | 209 | fn deserialize_i64(self, visitor: V) -> Result 210 | where 211 | V: de::Visitor<'de>, 212 | { 213 | let _ = visitor; 214 | todo!() 215 | } 216 | 217 | fn deserialize_u8(self, visitor: V) -> Result 218 | where 219 | V: de::Visitor<'de>, 220 | { 221 | let _ = visitor; 222 | todo!() 223 | } 224 | 225 | fn deserialize_u16(self, visitor: V) -> Result 226 | where 227 | V: de::Visitor<'de>, 228 | { 229 | let _ = visitor; 230 | todo!() 231 | } 232 | 233 | fn deserialize_u32(self, visitor: V) -> Result 234 | where 235 | V: de::Visitor<'de>, 236 | { 237 | match self.peek_tag_index()? { 238 | Some((Tag::Prop(value_slice, _name_slice), file_index)) => { 239 | let value = match value_slice { 240 | [a, b, c, d] => u32::from_be_bytes([*a, *b, *c, *d]), 241 | _ => return Err(Error::invalid_serde_type_length(4, *file_index)), 242 | }; 243 | self.eat_tag()?; 244 | visitor.visit_u32(value) 245 | } 246 | _ => todo!(), 247 | } 248 | } 249 | 250 | fn deserialize_u64(self, visitor: V) -> Result 251 | where 252 | V: de::Visitor<'de>, 253 | { 254 | let _ = visitor; 255 | todo!() 256 | } 257 | 258 | fn deserialize_f32(self, visitor: V) -> Result 259 | where 260 | V: de::Visitor<'de>, 261 | { 262 | let _ = visitor; 263 | todo!() 264 | } 265 | 266 | fn deserialize_f64(self, visitor: V) -> Result 267 | where 268 | V: de::Visitor<'de>, 269 | { 270 | let _ = visitor; 271 | todo!() 272 | } 273 | 274 | fn deserialize_char(self, visitor: V) -> Result 275 | where 276 | V: de::Visitor<'de>, 277 | { 278 | let _ = visitor; 279 | todo!() 280 | } 281 | 282 | fn deserialize_str(self, visitor: V) -> Result 283 | where 284 | V: de::Visitor<'de>, 285 | { 286 | match self.peek_tag_index()? { 287 | Some((Tag::Prop(value_slice, _name_slice), file_index)) => { 288 | let s = 289 | core::str::from_utf8(value_slice).map_err(|e| Error::utf8(e, *file_index))?; 290 | let value = visitor.visit_borrowed_str(s)?; 291 | self.eat_tag()?; 292 | Ok(value) 293 | } 294 | _ => todo!(), 295 | } 296 | } 297 | 298 | fn deserialize_string(self, visitor: V) -> Result 299 | where 300 | V: de::Visitor<'de>, 301 | { 302 | let _ = visitor; 303 | todo!() 304 | } 305 | 306 | fn deserialize_bytes(self, visitor: V) -> Result 307 | where 308 | V: de::Visitor<'de>, 309 | { 310 | match self.peek_tag()? { 311 | Some(Tag::Prop(value_slice, _name_slice)) => { 312 | let value = visitor.visit_borrowed_bytes(value_slice)?; 313 | self.eat_tag()?; 314 | Ok(value) 315 | } 316 | _ => todo!(), 317 | } 318 | } 319 | 320 | fn deserialize_byte_buf(self, visitor: V) -> Result 321 | where 322 | V: de::Visitor<'de>, 323 | { 324 | let _ = visitor; 325 | todo!() 326 | } 327 | 328 | fn deserialize_option(self, visitor: V) -> Result 329 | where 330 | V: de::Visitor<'de>, 331 | { 332 | visitor.visit_some(self) 333 | } 334 | 335 | fn deserialize_unit(self, visitor: V) -> Result 336 | where 337 | V: de::Visitor<'de>, 338 | { 339 | let _ = visitor; 340 | todo!() 341 | } 342 | 343 | fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result 344 | where 345 | V: de::Visitor<'de>, 346 | { 347 | let _ = (name, visitor); 348 | todo!() 349 | } 350 | 351 | fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result 352 | where 353 | V: de::Visitor<'de>, 354 | { 355 | let _ = (name, visitor); 356 | todo!() 357 | } 358 | 359 | fn deserialize_seq(self, visitor: V) -> Result 360 | where 361 | V: de::Visitor<'de>, 362 | { 363 | let _ = visitor; 364 | todo!() 365 | } 366 | 367 | fn deserialize_tuple(self, len: usize, visitor: V) -> Result 368 | where 369 | V: de::Visitor<'de>, 370 | { 371 | let _ = (len, visitor); 372 | todo!() 373 | } 374 | 375 | fn deserialize_tuple_struct( 376 | self, 377 | name: &'static str, 378 | len: usize, 379 | visitor: V, 380 | ) -> Result 381 | where 382 | V: de::Visitor<'de>, 383 | { 384 | let _ = (name, len, visitor); 385 | todo!() 386 | } 387 | 388 | fn deserialize_map(self, visitor: V) -> Result 389 | where 390 | V: de::Visitor<'de>, 391 | { 392 | if let Some((Tag::Begin(_name_slice), _file_index)) = self.next_tag()? { 393 | let ret = visitor.visit_map(MapVisitor::new(self))?; 394 | if let Some((Tag::End, _file_index)) = self.next_tag()? { 395 | Ok(ret) 396 | } else { 397 | Err(Error::expected_struct_end()) 398 | } 399 | } else { 400 | Err(Error::expected_struct_begin()) 401 | } 402 | } 403 | 404 | fn deserialize_struct( 405 | self, 406 | name: &'static str, 407 | fields: &'static [&'static str], 408 | visitor: V, 409 | ) -> Result 410 | where 411 | V: de::Visitor<'de>, 412 | { 413 | let _ = (name, fields); 414 | self.deserialize_map(visitor) 415 | } 416 | 417 | fn deserialize_enum( 418 | self, 419 | name: &'static str, 420 | variants: &'static [&'static str], 421 | visitor: V, 422 | ) -> Result 423 | where 424 | V: de::Visitor<'de>, 425 | { 426 | let _ = (name, variants, visitor); 427 | todo!() 428 | } 429 | 430 | fn deserialize_identifier(self, visitor: V) -> Result 431 | where 432 | V: de::Visitor<'de>, 433 | { 434 | if let Some((Tag::Begin(name_slice), file_index)) = self.peek_tag_index()? { 435 | let s = core::str::from_utf8(name_slice).map_err(|e| Error::utf8(e, *file_index))?; 436 | visitor.visit_str(s) 437 | } else { 438 | todo!() 439 | } 440 | } 441 | 442 | fn deserialize_ignored_any(self, visitor: V) -> Result 443 | where 444 | V: de::Visitor<'de>, 445 | { 446 | if let Some(tag) = self.peek_tag()? { 447 | match tag { 448 | Tag::Begin(_) => { 449 | self.eat_tag()?; 450 | let mut depth = 0; 451 | while let Some((tag, _file_index)) = self.next_tag()? { 452 | match tag { 453 | Tag::Begin(_) => depth += 1, 454 | Tag::End => { 455 | if depth == 0 { 456 | break; 457 | } else { 458 | depth -= 1 459 | } 460 | } 461 | Tag::Prop(_, _) => {} 462 | } 463 | } 464 | } 465 | Tag::End => todo!(), 466 | Tag::Prop(_, _) => self.eat_tag()?, 467 | } 468 | } 469 | visitor.visit_unit() 470 | } 471 | } 472 | 473 | struct MapVisitor<'de, 'b> { 474 | de: &'b mut Deserializer<'de>, 475 | } 476 | 477 | impl<'de, 'b> MapVisitor<'de, 'b> { 478 | fn new(de: &'b mut Deserializer<'de>) -> Self { 479 | Self { de } 480 | } 481 | } 482 | 483 | impl<'de> de::MapAccess<'de> for MapVisitor<'de, '_> { 484 | type Error = Error; 485 | 486 | fn next_key_seed(&mut self, seed: K) -> Result> 487 | where 488 | K: de::DeserializeSeed<'de>, 489 | { 490 | match self.de.peek_tag()? { 491 | Some(Tag::Prop(_value_slice, name_slice)) => seed 492 | .deserialize(serde::de::value::BorrowedBytesDeserializer::new(name_slice)) 493 | .map(Some), 494 | Some(Tag::Begin(name_slice)) => seed 495 | .deserialize(serde::de::value::BorrowedBytesDeserializer::new(name_slice)) 496 | .map(Some), 497 | Some(Tag::End) => Ok(None), 498 | None => Err(Error::no_remaining_tags()), 499 | } 500 | } 501 | 502 | fn next_value_seed(&mut self, seed: V) -> Result 503 | where 504 | V: de::DeserializeSeed<'de>, 505 | { 506 | match self.de.peek_tag()? { 507 | Some(Tag::Prop(_value_slice, _name_slice)) => seed.deserialize(&mut *self.de), 508 | Some(Tag::Begin(_name_slice)) => seed.deserialize(&mut *self.de), 509 | Some(Tag::End) => panic!(), 510 | None => Err(Error::no_remaining_tags()), 511 | } 512 | } 513 | } 514 | 515 | #[cfg(test)] 516 | mod tests { 517 | #[cfg(feature = "alloc")] 518 | use alloc::format; 519 | #[cfg(any(feature = "std", feature = "alloc"))] 520 | use serde::Deserialize; 521 | #[cfg(feature = "std")] 522 | use std::format; 523 | 524 | #[cfg(any(feature = "std", feature = "alloc"))] 525 | #[test] 526 | fn error_invalid_magic() { 527 | const DEVICE_TREE: &[u8] = &[0x11, 0x22, 0x33, 0x44]; // not device tree blob format 528 | const DEVICE_TREE_LEN: usize = DEVICE_TREE.len(); 529 | #[repr(align(8))] 530 | struct AlignedBuffer { 531 | pub data: [u8; DEVICE_TREE_LEN], 532 | } 533 | let mut aligned_data: Box = Box::new(AlignedBuffer { 534 | data: [0; DEVICE_TREE_LEN], 535 | }); 536 | aligned_data.data[..DEVICE_TREE_LEN].clone_from_slice(DEVICE_TREE); 537 | let ptr = aligned_data.data.as_ptr(); 538 | 539 | #[derive(Debug, Deserialize)] 540 | struct Tree {} 541 | 542 | let ans: Result = unsafe { super::from_raw(ptr) }; 543 | let err = ans.unwrap_err(); 544 | assert_eq!( 545 | "Error(invalid magic, value: 287454020, index: 0)", 546 | format!("{}", err) 547 | ); 548 | } 549 | } 550 | -------------------------------------------------------------------------------- /src/de_mut/cursor.rs: -------------------------------------------------------------------------------- 1 | use super::{BLOCK_LEN, DtError, RefDtb, StructureBlock}; 2 | use core::marker::PhantomData; 3 | 4 | #[derive(Clone, Copy, Debug)] 5 | #[repr(C)] 6 | pub(super) struct AnyCursor(usize, PhantomData); 7 | 8 | pub(super) type BodyCursor = AnyCursor; 9 | pub(super) type TitleCursor = AnyCursor; 10 | pub(super) type PropCursor = AnyCursor<Prop>; 11 | 12 | pub(super) trait Type {} 13 | 14 | #[derive(Clone, Copy, Debug)] 15 | pub(super) struct Body {} 16 | #[derive(Clone, Copy, Debug)] 17 | pub(super) struct Title {} 18 | #[derive(Clone, Copy, Debug)] 19 | pub(super) struct Prop {} 20 | 21 | impl Type for Body {} 22 | impl Type for Title {} 23 | impl Type for Prop {} 24 | 25 | pub enum MoveResult { 26 | In, 27 | Out, 28 | Others, 29 | } 30 | 31 | #[derive(Clone, Copy, Debug)] 32 | pub(crate) struct MultiNodeCursor { 33 | pub start_cursor: BodyCursor, 34 | pub skip_cursor: BodyCursor, 35 | pub data_cursor: BodyCursor, 36 | #[allow(unused)] 37 | pub node_count: u32, 38 | } 39 | 40 | impl<T: Type> AnyCursor<T> { 41 | /// 移动 `n` 格。 42 | pub fn step_n(&mut self, len: usize) { 43 | self.0 += len; 44 | } 45 | 46 | /// 光标相对文件头的偏移。 47 | pub fn file_index_on(&self, dtb: RefDtb) -> usize { 48 | self.0 * BLOCK_LEN + dtb.borrow().off_dt_struct() 49 | } 50 | } 51 | 52 | impl BodyCursor { 53 | pub const ROOT: Self = Self(2, PhantomData); 54 | pub const STARTER: Self = Self(0, PhantomData); 55 | 56 | /// 移动到下一个项目。 57 | pub fn move_on(&mut self, dtb: RefDtb) -> Cursor { 58 | use StructureBlock as B; 59 | let structure = &dtb.borrow().structure; 60 | loop { 61 | match structure[self.0] { 62 | B::NODE_BEGIN => break Cursor::title(self.0), 63 | B::NODE_END => break Cursor::end(), 64 | B::PROP => break Cursor::prop(self.0), 65 | B::NOP => self.0 += 1, 66 | _ => todo!(), 67 | } 68 | } 69 | } 70 | 71 | /// 如果设备树已完全解析,返回 `true`。 72 | pub fn is_complete_on(&self, dtb: RefDtb) -> bool { 73 | self.0 + 1 == dtb.borrow().structure.len() 74 | } 75 | 76 | /// 跳过当前所在的字符串。 77 | pub fn skip_str_on(&mut self, dtb: RefDtb) { 78 | while let Some(block) = &dtb.borrow().structure.get(self.0) { 79 | self.0 += 1; 80 | if block.is_end_of_str() { 81 | return; 82 | } 83 | } 84 | todo!() 85 | } 86 | 87 | /// 移动指针至下一块 88 | pub fn move_next(&mut self, dtb: RefDtb) -> MoveResult { 89 | use StructureBlock as B; 90 | let structure = &dtb.borrow().structure; 91 | match structure[self.0] { 92 | // 下陷一级 93 | B::NODE_BEGIN => { 94 | self.0 += 1; 95 | self.skip_str_on(dtb); 96 | MoveResult::In 97 | } 98 | // 上浮一级 99 | B::NODE_END => { 100 | self.0 += 1; 101 | MoveResult::Out 102 | } 103 | // 属性项 104 | B::PROP => { 105 | if let [_, len_data, _, ..] = &structure[self.0..] { 106 | self.0 += 3 + align(len_data.as_usize(), BLOCK_LEN); 107 | } else { 108 | todo!() 109 | } 110 | MoveResult::Others 111 | } 112 | // 空白项 113 | B::NOP => { 114 | self.0 += 1; 115 | MoveResult::Others 116 | } 117 | _ => todo!("unknown block {}", structure[self.0]), 118 | } 119 | } 120 | 121 | /// 离开当前子树。 122 | pub fn escape_from(&mut self, dtb: RefDtb) { 123 | let mut level = 1; 124 | loop { 125 | match self.move_next(dtb) { 126 | MoveResult::In => level += 1, 127 | MoveResult::Out => { 128 | if level == 1 { 129 | break; 130 | } 131 | level -= 1; 132 | } 133 | _ => {} 134 | } 135 | } 136 | } 137 | } 138 | 139 | impl TitleCursor { 140 | /// 切分节点名。 141 | pub fn split_on<'de>(&self, dtb: RefDtb<'de>) -> (&'de str, BodyCursor) { 142 | let mut index = self.0 + 1; 143 | let mut len = 0; 144 | 145 | let structure = &dtb.borrow().structure; 146 | while let Some(block) = structure.get(index) { 147 | index += 1; 148 | if block.is_end_of_str() { 149 | let end = block.str_end(); 150 | len += end; 151 | let s = structure[self.0 + 1].lead_str(len); 152 | return (s, AnyCursor(index, PhantomData)); 153 | } else { 154 | len += 4; 155 | } 156 | } 157 | todo!() 158 | } 159 | 160 | /// 生成组光标。 161 | pub fn take_group_on(&self, dtb: RefDtb, name: &str) -> MultiNodeCursor { 162 | let name_bytes = name.as_bytes(); 163 | let name_skip = align(name_bytes.len() + 1, BLOCK_LEN); 164 | let group = AnyCursor::<Body>(self.0, PhantomData); 165 | 166 | let title_body = AnyCursor::<Body>(self.0 + 1 + name_skip, PhantomData); 167 | let mut body = title_body; 168 | let mut len = 1; 169 | 170 | let structure = &dtb.borrow().structure; 171 | loop { 172 | body.skip_str_on(dtb); 173 | body.escape_from(dtb); 174 | if let Cursor::Title(c) = body.move_on(dtb) { 175 | let s = structure[c.0 + 1].lead_slice(name_bytes.len() + 1); 176 | if let [name @ .., b'@'] = s { 177 | if name == name_bytes { 178 | body.0 += 1 + name_skip; 179 | len += 1; 180 | continue; 181 | } 182 | } 183 | } 184 | break; 185 | } 186 | MultiNodeCursor { 187 | start_cursor: group, 188 | skip_cursor: body, 189 | data_cursor: title_body, 190 | node_count: len, 191 | } 192 | } 193 | 194 | /// 生成节点光标。 195 | pub fn take_node_on(&self, dtb: RefDtb, name: &str) -> MultiNodeCursor { 196 | let name_bytes = name.as_bytes(); 197 | let name_skip = align(name_bytes.len() + 1, BLOCK_LEN); 198 | let origin = AnyCursor::<Body>(self.0, PhantomData); 199 | let node = AnyCursor::<Body>(self.0 + 1 + name_skip, PhantomData); 200 | 201 | let mut body = AnyCursor::<Body>(self.0 + 1 + name_skip, PhantomData); 202 | 203 | body.escape_from(dtb); 204 | MultiNodeCursor { 205 | start_cursor: origin, 206 | skip_cursor: body, 207 | data_cursor: node, 208 | node_count: 1, 209 | } 210 | } 211 | } 212 | 213 | impl PropCursor { 214 | pub fn name_on<'a>(&self, dtb: RefDtb<'a>) -> (&'a str, BodyCursor) { 215 | let dtb = dtb.borrow(); 216 | if let [_, len_data, off_name, ..] = &dtb.structure[self.0..] { 217 | use core::{slice, str}; 218 | 219 | let off_name = off_name.as_usize(); 220 | let s = &dtb.strings[off_name..]; 221 | let len = s.iter().take_while(|b| **b != b'\0').count(); 222 | ( 223 | unsafe { str::from_utf8_unchecked(slice::from_raw_parts(s.as_ptr(), len)) }, 224 | AnyCursor( 225 | self.0 + 3 + align(len_data.as_usize(), BLOCK_LEN), 226 | PhantomData, 227 | ), 228 | ) 229 | } else { 230 | todo!() 231 | } 232 | } 233 | 234 | pub fn data_on<'a>(&self, dtb: RefDtb<'a>) -> &'a [u8] { 235 | if let [_, len_data, _, data @ ..] = &dtb.borrow().structure[self.0..] { 236 | data[0].lead_slice(len_data.as_usize()) 237 | } else { 238 | todo!() 239 | } 240 | } 241 | 242 | pub fn map_on<T>(&self, dtb: RefDtb<'_>, f: impl FnOnce(&[u8]) -> T) -> T { 243 | if let [_, len_data, _, data @ ..] = &dtb.borrow().structure[self.0..] { 244 | f(data[0].lead_slice(len_data.as_usize())) 245 | } else { 246 | todo!() 247 | } 248 | } 249 | 250 | pub fn map_u32_on(&self, dtb: RefDtb<'_>) -> Result<u32, DtError> { 251 | let structure = &dtb.borrow().structure[self.0..]; 252 | if let [_, len_data, _, data @ ..] = structure { 253 | if len_data.as_usize() == BLOCK_LEN { 254 | Ok(u32::from_be(data[0].0)) 255 | } else { 256 | Err(DtError::buildin_type_parsed_error( 257 | "u32", 258 | self.file_index_on(dtb), 259 | )) 260 | } 261 | } else { 262 | Err(DtError::slice_eof_unpexpected( 263 | (4 * BLOCK_LEN) as _, 264 | (4 * structure.len()) as _, 265 | self.file_index_on(dtb), 266 | )) 267 | } 268 | } 269 | } 270 | 271 | #[derive(Debug)] 272 | pub(super) enum Cursor { 273 | Title(TitleCursor), 274 | Prop(PropCursor), 275 | End, 276 | } 277 | 278 | impl Cursor { 279 | #[inline] 280 | const fn title(c: usize) -> Self { 281 | Self::Title(AnyCursor(c, PhantomData)) 282 | } 283 | 284 | #[inline] 285 | const fn prop(c: usize) -> Self { 286 | Self::Prop(AnyCursor(c, PhantomData)) 287 | } 288 | 289 | #[inline] 290 | const fn end() -> Self { 291 | Self::End 292 | } 293 | } 294 | 295 | #[inline] 296 | const fn align(len: usize, align: usize) -> usize { 297 | len.div_ceil(align) 298 | } 299 | -------------------------------------------------------------------------------- /src/de_mut/data.rs: -------------------------------------------------------------------------------- 1 | use super::cursor::MultiNodeCursor; 2 | use super::{BodyCursor, Cursor}; 3 | use super::{DtError, PropCursor, RefDtb, RegConfig}; 4 | 5 | use core::marker::PhantomData; 6 | use serde::{Deserialize, de}; 7 | 8 | #[derive(Clone, Copy, Debug)] 9 | pub(super) enum ValueCursor { 10 | Body(BodyCursor), 11 | Prop(BodyCursor, PropCursor), 12 | Node(MultiNodeCursor), 13 | NodeIn(MultiNodeCursor), 14 | } 15 | 16 | #[derive(Clone, Copy)] 17 | pub(super) struct ValueDeserializer<'de> { 18 | pub dtb: RefDtb<'de>, 19 | pub reg: RegConfig, 20 | pub cursor: ValueCursor, 21 | } 22 | 23 | impl<'de> Deserialize<'de> for ValueDeserializer<'_> { 24 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 25 | where 26 | D: serde::Deserializer<'de>, 27 | { 28 | struct Visitor<'de, 'b> { 29 | marker: PhantomData<ValueDeserializer<'b>>, 30 | lifetime: PhantomData<&'de ()>, 31 | } 32 | impl<'de, 'b> de::Visitor<'de> for Visitor<'de, 'b> { 33 | type Value = ValueDeserializer<'b>; 34 | 35 | fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { 36 | write!(formatter, "struct ValueDeserializer") 37 | } 38 | 39 | fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> 40 | where 41 | D: de::Deserializer<'de>, 42 | { 43 | Ok(unsafe { 44 | *(*(core::ptr::addr_of!(deserializer) as *const _ as *const &ValueDeserializer)) 45 | }) 46 | } 47 | } 48 | 49 | serde::Deserializer::deserialize_newtype_struct( 50 | deserializer, 51 | super::VALUE_DESERIALIZER_NAME, 52 | Visitor { 53 | marker: PhantomData, 54 | lifetime: PhantomData, 55 | }, 56 | ) 57 | } 58 | } 59 | 60 | impl<'de> de::Deserializer<'de> for &mut ValueDeserializer<'de> { 61 | type Error = DtError; 62 | 63 | fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 64 | where 65 | V: de::Visitor<'de>, 66 | { 67 | unimplemented!("any") 68 | } 69 | 70 | fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> 71 | where 72 | V: de::Visitor<'de>, 73 | { 74 | if let ValueCursor::Prop(_, cursor) = self.cursor { 75 | let val = cursor.map_on(self.dtb, |data| { 76 | if data.is_empty() { 77 | true 78 | } else { 79 | todo!("&[u8] -> bool") 80 | } 81 | }); 82 | return visitor.visit_bool(val); 83 | } 84 | unreachable!("Node -> bool"); 85 | } 86 | 87 | fn deserialize_i8<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 88 | where 89 | V: de::Visitor<'de>, 90 | { 91 | unreachable!("i8") 92 | } 93 | 94 | fn deserialize_i16<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 95 | where 96 | V: de::Visitor<'de>, 97 | { 98 | unreachable!("i16") 99 | } 100 | 101 | fn deserialize_i32<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 102 | where 103 | V: de::Visitor<'de>, 104 | { 105 | unreachable!("i32") 106 | } 107 | 108 | fn deserialize_i64<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 109 | where 110 | V: de::Visitor<'de>, 111 | { 112 | unreachable!("i64") 113 | } 114 | 115 | fn deserialize_u8<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 116 | where 117 | V: de::Visitor<'de>, 118 | { 119 | unreachable!("u8") 120 | } 121 | 122 | fn deserialize_u16<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 123 | where 124 | V: de::Visitor<'de>, 125 | { 126 | unreachable!("u16") 127 | } 128 | 129 | fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error> 130 | where 131 | V: de::Visitor<'de>, 132 | { 133 | if let ValueCursor::Prop(_, cursor) = self.cursor { 134 | return visitor.visit_u32(cursor.map_u32_on(self.dtb)?); 135 | } 136 | unreachable!("node -> u32"); 137 | } 138 | 139 | fn deserialize_u64<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 140 | where 141 | V: de::Visitor<'de>, 142 | { 143 | unreachable!("u64") 144 | } 145 | 146 | fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 147 | where 148 | V: de::Visitor<'de>, 149 | { 150 | unreachable!("f32") 151 | } 152 | 153 | fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 154 | where 155 | V: de::Visitor<'de>, 156 | { 157 | unreachable!("f64") 158 | } 159 | 160 | fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 161 | where 162 | V: de::Visitor<'de>, 163 | { 164 | unreachable!("char") 165 | } 166 | 167 | fn deserialize_str<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 168 | where 169 | V: de::Visitor<'de>, 170 | { 171 | unreachable!("str"); 172 | } 173 | 174 | fn deserialize_string<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 175 | where 176 | V: de::Visitor<'de>, 177 | { 178 | unreachable!("string") 179 | } 180 | 181 | fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> 182 | where 183 | V: de::Visitor<'de>, 184 | { 185 | if let ValueCursor::Prop(_, cursor) = self.cursor { 186 | let data = cursor.data_on(self.dtb); 187 | return visitor.visit_borrowed_bytes(data); 188 | } 189 | unreachable!("node -> bytes"); 190 | } 191 | 192 | fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 193 | where 194 | V: de::Visitor<'de>, 195 | { 196 | unreachable!("byte_buf") 197 | } 198 | 199 | fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> 200 | where 201 | V: de::Visitor<'de>, 202 | { 203 | match self.cursor { 204 | ValueCursor::Prop(_, cursor) => { 205 | let data = cursor.data_on(self.dtb); 206 | if data.is_empty() { 207 | visitor.visit_none() 208 | } else { 209 | visitor.visit_some(self) 210 | } 211 | } 212 | ValueCursor::NodeIn(_) => visitor.visit_some(self), 213 | ValueCursor::Body(_) => visitor.visit_some(self), 214 | ValueCursor::Node(_) => unreachable!("Node to option(NodeIn instead)"), 215 | } 216 | } 217 | 218 | fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> 219 | where 220 | V: de::Visitor<'de>, 221 | { 222 | visitor.visit_unit() 223 | } 224 | 225 | fn deserialize_unit_struct<V>( 226 | self, 227 | _name: &'static str, 228 | visitor: V, 229 | ) -> Result<V::Value, Self::Error> 230 | where 231 | V: de::Visitor<'de>, 232 | { 233 | visitor.visit_unit() 234 | } 235 | 236 | fn deserialize_newtype_struct<V>( 237 | self, 238 | name: &'static str, 239 | visitor: V, 240 | ) -> Result<V::Value, Self::Error> 241 | where 242 | V: de::Visitor<'de>, 243 | { 244 | if name == super::VALUE_DESERIALIZER_NAME { 245 | return visitor.visit_newtype_struct(self); 246 | } 247 | unreachable!("unknown newtype struct"); 248 | } 249 | 250 | fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> 251 | where 252 | V: de::Visitor<'de>, 253 | { 254 | use super::{StructAccess, StructAccessType, Temp}; 255 | match self.cursor { 256 | ValueCursor::NodeIn(result) => { 257 | let mut start_cursor = result.start_cursor; 258 | match start_cursor.move_on(self.dtb) { 259 | Cursor::Title(c) => { 260 | let (name, _) = c.split_on(self.dtb); 261 | 262 | let pre_len = name.as_bytes().iter().take_while(|b| **b != b'@').count(); 263 | let name_bytes = &name.as_bytes()[..pre_len]; 264 | let name = unsafe { core::str::from_utf8_unchecked(name_bytes) }; 265 | 266 | let de = self; 267 | de.cursor = ValueCursor::Body(start_cursor); 268 | 269 | visitor.visit_seq(StructAccess { 270 | access_type: StructAccessType::Seq(name), 271 | temp: Temp::Uninit, 272 | de, 273 | }) 274 | } 275 | _ => unreachable!("seq request on a none seq cursor"), 276 | } 277 | } 278 | _ => unreachable!("Seq request on a not-node cursor"), 279 | } 280 | } 281 | 282 | fn deserialize_tuple<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error> 283 | where 284 | V: de::Visitor<'de>, 285 | { 286 | unreachable!("tuple") 287 | } 288 | 289 | fn deserialize_tuple_struct<V>( 290 | self, 291 | _name: &'static str, 292 | _len: usize, 293 | _visitor: V, 294 | ) -> Result<V::Value, Self::Error> 295 | where 296 | V: de::Visitor<'de>, 297 | { 298 | unreachable!("tuple_struct") 299 | } 300 | 301 | fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> 302 | where 303 | V: de::Visitor<'de>, 304 | { 305 | use super::{StructAccess, StructAccessType, Temp}; 306 | match self.cursor { 307 | ValueCursor::NodeIn(_) => visitor.visit_map(StructAccess { 308 | access_type: StructAccessType::Map(false), 309 | temp: Temp::Uninit, 310 | de: self, 311 | }), 312 | ValueCursor::Body(_) => visitor.visit_map(StructAccess { 313 | access_type: StructAccessType::Map(false), 314 | temp: Temp::Uninit, 315 | de: self, 316 | }), 317 | ValueCursor::Prop(_, _) => unreachable!("Prop -> map"), 318 | ValueCursor::Node(_) => unreachable!("Node -> map (Use NodeIn instead)"), 319 | } 320 | } 321 | 322 | fn deserialize_struct<V>( 323 | self, 324 | _name: &'static str, 325 | fields: &'static [&'static str], 326 | visitor: V, 327 | ) -> Result<V::Value, Self::Error> 328 | where 329 | V: de::Visitor<'de>, 330 | { 331 | use super::{StructAccess, StructAccessType, Temp}; 332 | match self.cursor { 333 | ValueCursor::NodeIn(_) => visitor.visit_map(StructAccess { 334 | access_type: StructAccessType::Struct(fields), 335 | temp: Temp::Uninit, 336 | de: self, 337 | }), 338 | ValueCursor::Body(_) => visitor.visit_map(StructAccess { 339 | access_type: StructAccessType::Struct(fields), 340 | temp: Temp::Uninit, 341 | de: self, 342 | }), 343 | ValueCursor::Prop(_, _) => unreachable!("Prop -> struct {_name}"), 344 | ValueCursor::Node(_) => unreachable!("Node -> struct {_name} (Use NodeIn instead)"), 345 | } 346 | } 347 | 348 | fn deserialize_enum<V>( 349 | self, 350 | _name: &'static str, 351 | _variants: &'static [&'static str], 352 | _visitor: V, 353 | ) -> Result<V::Value, Self::Error> 354 | where 355 | V: de::Visitor<'de>, 356 | { 357 | unreachable!("enum") 358 | } 359 | 360 | fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 361 | where 362 | V: de::Visitor<'de>, 363 | { 364 | unreachable!("identifier") 365 | } 366 | 367 | fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error> 368 | where 369 | V: de::Visitor<'de>, 370 | { 371 | unreachable!("ignored_any") 372 | } 373 | } 374 | 375 | impl ValueDeserializer<'_> { 376 | #[inline] 377 | pub fn move_on(&mut self) -> super::Cursor { 378 | if let ValueCursor::Body(ref mut cursor) = self.cursor { 379 | return cursor.move_on(self.dtb); 380 | }; 381 | unreachable!("move_on prop cursor"); 382 | } 383 | #[inline] 384 | pub fn step_n(&mut self, n: usize) { 385 | if let ValueCursor::Body(ref mut cursor) = self.cursor { 386 | return cursor.step_n(n); 387 | }; 388 | unreachable!("step_n prop cursor"); 389 | } 390 | #[inline] 391 | pub fn is_complete_on(&self) -> bool { 392 | if let ValueCursor::Body(cursor) = self.cursor { 393 | return cursor.is_complete_on(self.dtb); 394 | }; 395 | unreachable!("is_complete_on prop cursor"); 396 | } 397 | #[inline] 398 | pub fn file_index_on(&self) -> usize { 399 | if let ValueCursor::Body(cursor) = self.cursor { 400 | return cursor.file_index_on(self.dtb); 401 | }; 402 | unreachable!("file_index_on prop cursor"); 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /src/de_mut/matrix.rs: -------------------------------------------------------------------------------- 1 | use crate::de_mut::ValueCursor; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | pub struct Matrix<'de, const T: usize> { 5 | data: &'de [u32], 6 | } 7 | 8 | pub struct MatrixItem<'de, const T: usize> { 9 | offset: usize, 10 | data: &'de [u32], 11 | } 12 | 13 | impl<'de, const T: usize> Matrix<'de, T> { 14 | #[inline(always)] 15 | pub fn get_block_size() -> usize { 16 | // Block size in bytes. 17 | T * 4 18 | } 19 | 20 | #[inline(always)] 21 | pub fn iter(&self) -> MatrixItem<'de, T> { 22 | MatrixItem { 23 | offset: 0, 24 | data: self.data, 25 | } 26 | } 27 | 28 | #[inline(always)] 29 | pub fn len(&self) -> usize { 30 | self.data.len() / T 31 | } 32 | 33 | #[inline(always)] 34 | pub fn is_empty(&self) -> bool { 35 | self.data.len() != 0 36 | } 37 | 38 | #[inline(always)] 39 | pub fn get(&self, i: usize) -> &'de [u32] { 40 | &self.data[i * T..(i + 1) * T] 41 | } 42 | } 43 | 44 | impl<'de, const T: usize> Iterator for MatrixItem<'de, T> { 45 | type Item = &'de [u32]; 46 | 47 | #[inline(always)] 48 | fn next(&mut self) -> Option<Self::Item> { 49 | if self.data.len() <= self.offset { 50 | return None; 51 | } 52 | let result = &self.data[self.offset..self.offset + T]; 53 | self.offset += T; 54 | Some(result) 55 | } 56 | } 57 | 58 | impl<'de, const T: usize> Deserialize<'de> for Matrix<'_, T> { 59 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 60 | where 61 | D: serde::Deserializer<'de>, 62 | { 63 | let value_deserialzer = super::ValueDeserializer::deserialize(deserializer)?; 64 | let data = match value_deserialzer.cursor { 65 | ValueCursor::Prop(_, cursor) => cursor.data_on(value_deserialzer.dtb), 66 | _ => unreachable!(), 67 | }; 68 | if data.len() % Self::get_block_size() != 0 { 69 | panic!("unaligned matrix"); 70 | } 71 | let (prefix, data, suffix) = unsafe { data.align_to::<u32>() }; 72 | if !prefix.is_empty() || !suffix.is_empty() { 73 | panic!("Not support unaligned data"); 74 | } 75 | 76 | Ok(Self { data }) 77 | } 78 | } 79 | 80 | impl<const T: usize> Serialize for Matrix<'_, T> { 81 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 82 | where 83 | S: serde::Serializer, 84 | { 85 | use serde::ser::SerializeSeq; 86 | let mut seq = serializer.serialize_seq(Some(self.data.len()))?; 87 | for x in self.data { 88 | seq.serialize_element(x)?; 89 | } 90 | seq.end() 91 | } 92 | } 93 | 94 | #[cfg(test)] 95 | mod tests { 96 | use super::Matrix; 97 | use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; 98 | use serde::Serialize; 99 | 100 | const MAX_SIZE: usize = 256; 101 | #[test] 102 | fn base_ser_test() { 103 | #[derive(Serialize)] 104 | struct Base { 105 | pub hello: [u32; 16], 106 | } 107 | let array: [u32; 16] = [0xdeadbeef; 16]; 108 | let mut buf1 = [0u8; MAX_SIZE]; 109 | 110 | { 111 | let base = Base { hello: array }; 112 | crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); 113 | } 114 | 115 | let ptr = DtbPtr::from_raw(buf1.as_mut_ptr()).unwrap(); 116 | let dtb = Dtb::from(ptr).share(); 117 | let node: Node = from_raw_mut(&dtb).unwrap(); 118 | let matrix = node.get_prop("hello").unwrap().deserialize::<Matrix<4>>(); 119 | let mut count = 0; 120 | for x in matrix.iter() { 121 | for y in x { 122 | count += 1; 123 | assert_eq!(u32::from_be(*y), 0xdeadbeef); 124 | } 125 | } 126 | assert_eq!(count, 16); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/de_mut/mod.rs: -------------------------------------------------------------------------------- 1 | //! Deserialize device tree data to a Rust data structure, 2 | //! the memory region contains dtb file should be mutable. 3 | 4 | use crate::error::Error as DtError; 5 | use serde::de; 6 | 7 | mod cursor; 8 | mod data; 9 | // mod group; 10 | mod matrix; 11 | pub(crate) mod node; 12 | mod node_seq; 13 | mod reg; 14 | mod str_seq; 15 | // mod r#struct; 16 | mod struct_access; 17 | mod structs; 18 | 19 | const VALUE_DESERIALIZER_NAME: &str = "$serde_device_tree$de_mut$ValueDeserializer"; 20 | pub(crate) const NODE_NAME: &str = "$serde_device_tree$de_mut$Node"; 21 | pub(crate) const NODE_NODE_ITEM_NAME: &str = "$serde_device_tree$de_mut$Node$NodeItem"; 22 | // pub(crate) const NODE_PROP_ITEM_NAME: &str = "$serde_device_tree$de_mut$Node$PropItem"; 23 | 24 | pub use structs::{Dtb, DtbPtr}; 25 | pub mod buildin { 26 | pub use super::{matrix::Matrix, node::Node, node_seq::NodeSeq, reg::Reg, str_seq::StrSeq}; 27 | } 28 | 29 | use cursor::{BodyCursor, Cursor, MultiNodeCursor, PropCursor}; 30 | use data::{ValueCursor, ValueDeserializer}; 31 | use reg::RegConfig; 32 | use struct_access::{StructAccess, StructAccessType, Temp}; 33 | use structs::{BLOCK_LEN, RefDtb, StructureBlock}; 34 | 35 | /// 从 [`RefDtb`] 反序列化一个描述设备树的 `T` 类型实例。 36 | /// 37 | /// 这个函数在没有堆的环境中执行, 38 | /// 因此可以在操作系统启动的极早期或无动态分配的嵌入式系统中使用。 39 | pub fn from_raw_mut<'de, T>(dtb: RefDtb<'de>) -> Result<T, DtError> 40 | where 41 | T: de::Deserialize<'de>, 42 | { 43 | // 根节点的名字固定为空字符串, 44 | // 从一个跳过根节点名字的光标初始化解析器。 45 | let mut d = ValueDeserializer { 46 | dtb, 47 | reg: RegConfig::DEFAULT, 48 | cursor: ValueCursor::NodeIn(MultiNodeCursor { 49 | start_cursor: BodyCursor::STARTER, 50 | skip_cursor: BodyCursor::ROOT, // This item will never be used. 51 | data_cursor: BodyCursor::ROOT, 52 | node_count: 1, 53 | }), 54 | }; 55 | T::deserialize(&mut d).and_then(|t| { 56 | // 解析必须完成 57 | if d.is_complete_on() { 58 | Ok(t) 59 | } else { 60 | Err(DtError::deserialize_not_complete(d.file_index_on())) 61 | } 62 | }) 63 | } 64 | -------------------------------------------------------------------------------- /src/de_mut/node.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | BodyCursor, Cursor, MultiNodeCursor, PropCursor, RefDtb, RegConfig, ValueCursor, 3 | ValueDeserializer, 4 | }; 5 | use core::fmt::Debug; 6 | use core::marker::PhantomData; 7 | use serde::de::MapAccess; 8 | use serde::{Deserialize, Serialize, de}; 9 | 10 | // TODO: Spec 2.3.5 said that we should not inherited from ancestors and the size-cell & 11 | // address-cells should only used for current node's children. 12 | #[allow(unused)] 13 | #[derive(Clone)] 14 | pub struct Node<'de> { 15 | dtb: RefDtb<'de>, 16 | reg: RegConfig, 17 | cursor: BodyCursor, 18 | props_start: Option<BodyCursor>, 19 | nodes_start: Option<BodyCursor>, 20 | } 21 | 22 | /// 节点迭代器。 23 | pub struct NodeIter<'de, 'b> { 24 | node: &'b Node<'de>, 25 | cursor: Option<BodyCursor>, 26 | i: usize, 27 | } 28 | 29 | /// 节点对象。 30 | pub struct NodeItem<'de> { 31 | dtb: RefDtb<'de>, 32 | reg: RegConfig, 33 | node: MultiNodeCursor, 34 | name: &'de str, 35 | } 36 | 37 | /// 属性迭代器。 38 | pub struct PropIter<'de, 'b> { 39 | node: &'b Node<'de>, 40 | cursor: Option<BodyCursor>, 41 | i: usize, 42 | } 43 | 44 | /// 属性对象。 45 | #[allow(unused)] 46 | pub struct PropItem<'de> { 47 | dtb: RefDtb<'de>, 48 | reg: RegConfig, 49 | body: BodyCursor, 50 | prop: PropCursor, 51 | name: &'de str, 52 | } 53 | 54 | impl<'de> Node<'de> { 55 | pub fn deserialize<T: Deserialize<'de>>(&self) -> T { 56 | use super::ValueCursor; 57 | let result = match self.cursor.clone().move_on(self.dtb) { 58 | Cursor::Title(c) => { 59 | let (name, _) = c.split_on(self.dtb); 60 | 61 | c.take_node_on(self.dtb, name) 62 | } 63 | _ => unreachable!("Node's cursor should on its start"), 64 | }; 65 | T::deserialize(&mut ValueDeserializer { 66 | dtb: self.dtb, 67 | reg: self.reg, 68 | cursor: ValueCursor::NodeIn(result), 69 | }) 70 | .unwrap() 71 | } 72 | // TODO: Maybe use BTreeMap when have alloc 73 | /// 获得节点迭代器。 74 | pub fn nodes<'b>(&'b self) -> NodeIter<'de, 'b> { 75 | NodeIter { 76 | node: self, 77 | cursor: self.nodes_start, 78 | i: 0, 79 | } 80 | } 81 | 82 | /// 获得属性迭代器。 83 | pub fn props<'b>(&'b self) -> PropIter<'de, 'b> { 84 | PropIter { 85 | node: self, 86 | cursor: self.props_start, 87 | i: 0, 88 | } 89 | } 90 | 91 | /// 尝试获得指定属性 92 | pub fn get_prop<'b>(&'b self, name: &str) -> Option<PropItem<'b>> { 93 | self.props().find(|prop| prop.get_name() == name) 94 | } 95 | 96 | pub fn name(&self) -> &'de str { 97 | let cursor = self.cursor.clone().move_on(self.dtb); 98 | if let Cursor::Title(c) = cursor { 99 | let (name, _) = c.split_on(self.dtb); 100 | name 101 | } else { 102 | todo!(); 103 | } 104 | } 105 | } 106 | 107 | impl Debug for Node<'_> { 108 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 109 | let props = self.props(); 110 | write!(f, "Props: [")?; 111 | let mut first_written = true; 112 | for prop in props { 113 | if first_written { 114 | write!(f, "\"{}\"", prop.get_name())?; 115 | first_written = false; 116 | } else { 117 | write!(f, ",\"{}\"", prop.get_name())?; 118 | } 119 | } 120 | writeln!(f, "]")?; 121 | 122 | let children = self.nodes(); 123 | write!(f, "Children: [")?; 124 | let mut first_written = true; 125 | for child in children { 126 | if first_written { 127 | write!(f, "\"{}\"", child.get_full_name())?; 128 | first_written = false; 129 | } else { 130 | write!(f, ",\"{}\"", child.get_full_name())?; 131 | } 132 | } 133 | writeln!(f, "]")?; 134 | 135 | Ok(()) 136 | } 137 | } 138 | 139 | impl<'de> Iterator for NodeIter<'de, '_> { 140 | type Item = NodeItem<'de>; 141 | 142 | fn next(&mut self) -> Option<Self::Item> { 143 | if let Some(ref mut cursor) = self.cursor { 144 | self.i += 1; 145 | let dtb = self.node.dtb; 146 | if let Cursor::Title(c) = cursor.move_on(dtb) { 147 | let (name, _) = c.split_on(dtb); 148 | let node_cursor = c.take_node_on(dtb, name); 149 | let res = Some(Self::Item { 150 | dtb, 151 | reg: self.node.reg, 152 | node: node_cursor, 153 | name, 154 | }); 155 | *cursor = node_cursor.skip_cursor; 156 | res 157 | } else { 158 | None 159 | } 160 | } else { 161 | None 162 | } 163 | } 164 | } 165 | 166 | impl<'de> Iterator for PropIter<'de, '_> { 167 | type Item = PropItem<'de>; 168 | 169 | fn next(&mut self) -> Option<Self::Item> { 170 | if let Some(ref mut cursor) = self.cursor { 171 | self.i += 1; 172 | let dtb = self.node.dtb; 173 | if let Cursor::Prop(c) = cursor.move_on(dtb) { 174 | let (name, next) = c.name_on(dtb); 175 | let res = Some(Self::Item { 176 | dtb, 177 | body: *cursor, 178 | reg: self.node.reg, 179 | prop: c, 180 | name, 181 | }); 182 | *cursor = next; 183 | res 184 | } else { 185 | None 186 | } 187 | } else { 188 | None 189 | } 190 | } 191 | } 192 | 193 | impl<'de> Deserialize<'de> for Node<'_> { 194 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 195 | where 196 | D: serde::Deserializer<'de>, 197 | { 198 | struct Visitor<'de, 'b> { 199 | marker: PhantomData<Node<'b>>, 200 | lifetime: PhantomData<&'de ()>, 201 | } 202 | impl<'de, 'b> de::Visitor<'de> for Visitor<'de, 'b> { 203 | type Value = Node<'b>; 204 | 205 | fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { 206 | write!(formatter, "struct Node") 207 | } 208 | fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error> 209 | where 210 | M: MapAccess<'de>, 211 | { 212 | // While there are entries remaining in the input, add them 213 | // into our map. 214 | let mut dtb: Option<RefDtb<'b>> = None; 215 | let mut reg: Option<RegConfig> = None; 216 | let mut props_start: Option<BodyCursor> = None; 217 | let mut nodes_start: Option<BodyCursor> = None; 218 | let mut self_cursor: Option<BodyCursor> = None; 219 | while let Some((key, value)) = access.next_entry::<&str, ValueDeserializer<'b>>()? { 220 | dtb = Some(value.dtb); 221 | reg = Some(value.reg); 222 | if key == "/" { 223 | self_cursor = match value.cursor { 224 | ValueCursor::NodeIn(result) => Some(result.start_cursor), 225 | _ => { 226 | unreachable!("root of NodeSeq shouble be NodeIn cursor") 227 | } 228 | }; 229 | continue; 230 | } 231 | match value.cursor { 232 | ValueCursor::Prop(cursor, _) => { 233 | if props_start.is_none() { 234 | props_start = Some(cursor); 235 | } 236 | } 237 | ValueCursor::NodeIn(cursor) => { 238 | if nodes_start.is_none() { 239 | nodes_start = Some(cursor.start_cursor); 240 | } 241 | } 242 | _ => unreachable!("unparsed(body) cursor"), 243 | } 244 | } 245 | 246 | Ok(Node { 247 | dtb: dtb.unwrap(), 248 | reg: reg.unwrap(), 249 | cursor: self_cursor.unwrap(), 250 | nodes_start, 251 | props_start, 252 | }) 253 | } 254 | } 255 | 256 | serde::Deserializer::deserialize_map( 257 | deserializer, 258 | Visitor { 259 | marker: PhantomData, 260 | lifetime: PhantomData, 261 | }, 262 | ) 263 | } 264 | } 265 | 266 | impl<'de> NodeItem<'de> { 267 | /// 反序列化一个节点的内容。 268 | pub fn deserialize<T: Deserialize<'de>>(&self) -> T { 269 | T::deserialize(&mut ValueDeserializer { 270 | dtb: self.dtb, 271 | reg: self.reg, 272 | cursor: ValueCursor::NodeIn(self.node), 273 | }) 274 | .unwrap() 275 | } 276 | 277 | pub fn get_parsed_name(&self) -> (&str, Option<&str>) { 278 | if self.name.contains("@") { 279 | let pre_len = self 280 | .name 281 | .as_bytes() 282 | .iter() 283 | .take_while(|b| **b != b'@') 284 | .count(); 285 | let (node_name, raw_unit_address) = self.name.split_at(pre_len); 286 | // Remove @ prefix 287 | let unit_address = raw_unit_address.split_at(1).1; 288 | (node_name, Some(unit_address)) 289 | } else { 290 | (self.name, None) 291 | } 292 | } 293 | 294 | pub fn get_full_name(&self) -> &'de str { 295 | self.name 296 | } 297 | } 298 | 299 | impl<'de> PropItem<'de> { 300 | pub fn get_name(&self) -> &'de str { 301 | self.name 302 | } 303 | pub fn deserialize<T: Deserialize<'de>>(&self) -> T { 304 | use super::ValueCursor; 305 | T::deserialize(&mut ValueDeserializer { 306 | dtb: self.dtb, 307 | reg: self.reg, 308 | cursor: ValueCursor::Prop(self.body, self.prop), 309 | }) 310 | .unwrap() 311 | } 312 | } 313 | impl Serialize for NodeItem<'_> { 314 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 315 | where 316 | S: serde::Serializer, 317 | { 318 | serializer.serialize_newtype_struct(crate::de_mut::NODE_NODE_ITEM_NAME, self) 319 | } 320 | } 321 | 322 | impl Serialize for PropItem<'_> { 323 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 324 | where 325 | S: serde::Serializer, 326 | { 327 | serializer.serialize_bytes(self.prop.data_on(self.dtb)) 328 | } 329 | } 330 | 331 | impl Serialize for Node<'_> { 332 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 333 | where 334 | S: serde::Serializer, 335 | { 336 | use serde::ser::SerializeMap; 337 | let mut map = serializer.serialize_map(None)?; 338 | for prop in self.props() { 339 | map.serialize_entry(prop.get_name(), &prop)?; 340 | } 341 | for node in self.nodes() { 342 | map.serialize_entry(node.get_full_name(), &node.deserialize::<Node>())?; 343 | } 344 | map.end() 345 | } 346 | } 347 | 348 | #[cfg(test)] 349 | mod tests { 350 | use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; 351 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/hifive-unmatched-a00.dtb"); 352 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 353 | #[repr(align(8))] 354 | struct AlignedBuffer { 355 | pub data: [u8; RAW_DEVICE_TREE.len()], 356 | } 357 | #[test] 358 | fn test_find_prop() { 359 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 360 | data: [0; BUFFER_SIZE], 361 | }); 362 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 363 | let mut slice = aligned_data.data.to_vec(); 364 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); 365 | let dtb = Dtb::from(ptr).share(); 366 | 367 | let node: Node = from_raw_mut(&dtb).unwrap(); 368 | let prop = node.get_prop("compatible"); 369 | assert!(prop.is_some()); 370 | } 371 | } 372 | -------------------------------------------------------------------------------- /src/de_mut/node_seq.rs: -------------------------------------------------------------------------------- 1 | use super::{BodyCursor, Cursor, RefDtb, RegConfig, ValueCursor, ValueDeserializer}; 2 | use core::{fmt::Debug, marker::PhantomData}; 3 | use serde::de::SeqAccess; 4 | use serde::{Deserialize, de}; 5 | 6 | /// 一组名字以 `@...` 区分,同类、同级且连续的节点的映射。 7 | /// 8 | /// 在解析前,无法得知这种节点的数量,因此也无法为它们分配足够的空间, 9 | /// 因此这些节点将延迟解析。 10 | /// 迭代 `NodeSeq` 可获得一系列 [`NodeSeqItem`],再调用 `deserialize` 方法分别解析每个节点。 11 | pub struct NodeSeq<'de> { 12 | name: &'de str, 13 | count: usize, 14 | starter: ValueDeserializer<'de>, 15 | } 16 | 17 | /// 连续节点迭代器。 18 | pub struct NodeSeqIter<'de, 'b> { 19 | seq: &'b NodeSeq<'de>, 20 | de: ValueDeserializer<'de>, 21 | i: usize, 22 | } 23 | 24 | /// 连续节点对象。 25 | pub struct NodeSeqItem<'de> { 26 | dtb: RefDtb<'de>, 27 | reg: RegConfig, 28 | body: BodyCursor, 29 | at: &'de str, 30 | } 31 | 32 | impl<'de> Deserialize<'de> for NodeSeq<'_> { 33 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 34 | where 35 | D: serde::Deserializer<'de>, 36 | { 37 | struct Visitor<'de, 'b> { 38 | marker: PhantomData<NodeSeq<'b>>, 39 | lifetime: PhantomData<&'de ()>, 40 | } 41 | impl<'de, 'b> de::Visitor<'de> for Visitor<'de, 'b> { 42 | type Value = NodeSeq<'b>; 43 | 44 | fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { 45 | write!(formatter, "struct ValueDeserializer") 46 | } 47 | 48 | fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> 49 | where 50 | A: SeqAccess<'de>, 51 | { 52 | let mut starter: Option<ValueDeserializer> = None; 53 | let mut count = 0; 54 | while let Some(node) = seq.next_element()? { 55 | if starter.is_none() { 56 | starter = Some(node); 57 | } 58 | count += 1 59 | } 60 | let mut starter = starter.unwrap(); 61 | 62 | match starter.move_on() { 63 | Cursor::Title(c) => { 64 | let (name, _) = c.split_on(starter.dtb); 65 | 66 | let (name, _) = name.split_once('@').unwrap_or((name, "")); 67 | Ok(NodeSeq { 68 | name, 69 | count, 70 | starter, 71 | }) 72 | } 73 | _ => unreachable!("NodeSeq should be inited by a node"), 74 | } 75 | } 76 | } 77 | 78 | serde::Deserializer::deserialize_seq( 79 | deserializer, 80 | Visitor { 81 | marker: PhantomData, 82 | lifetime: PhantomData, 83 | }, 84 | ) 85 | } 86 | } 87 | 88 | impl<'de> NodeSeq<'de> { 89 | /// 连续节点总数。 90 | pub const fn len(&self) -> usize { 91 | self.count 92 | } 93 | 94 | /// 如果连续节点数量为零,返回 true。但连续节点数量不可能为零。 95 | pub const fn is_empty(&self) -> bool { 96 | false 97 | } 98 | 99 | /// 获得节点迭代器。 100 | pub const fn iter<'b>(&'b self) -> NodeSeqIter<'de, 'b> { 101 | NodeSeqIter { 102 | seq: self, 103 | de: self.starter, 104 | i: 0, 105 | } 106 | } 107 | } 108 | 109 | impl Debug for NodeSeq<'_> { 110 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 111 | let mut iter = self.iter(); 112 | if let Some(s) = iter.next() { 113 | write!(f, "[@{}", s.at)?; 114 | for s in iter { 115 | write!(f, ", @{}", s.at)?; 116 | } 117 | write!(f, "]") 118 | } else { 119 | unreachable!("NodeSeq contains at least one node.") 120 | } 121 | } 122 | } 123 | 124 | impl<'de> Iterator for NodeSeqIter<'de, '_> { 125 | type Item = NodeSeqItem<'de>; 126 | 127 | fn next(&mut self) -> Option<Self::Item> { 128 | if self.i >= self.seq.len() { 129 | None 130 | } else { 131 | self.i += 1; 132 | match self.de.move_on() { 133 | // 子节点名字 134 | Cursor::Title(c) => { 135 | let (full_name, _) = c.split_on(self.de.dtb); 136 | let node_reuslt = c.take_node_on(self.de.dtb, full_name); 137 | 138 | let (pre_name, suf_name) = full_name.split_once('@').unwrap_or((full_name, "")); 139 | if self.seq.name != pre_name { 140 | return None; 141 | } 142 | 143 | self.de.cursor = ValueCursor::Body(node_reuslt.skip_cursor); 144 | 145 | Some(Self::Item { 146 | dtb: self.de.dtb, 147 | reg: self.de.reg, 148 | body: node_reuslt.data_cursor, 149 | at: suf_name, 150 | }) 151 | } 152 | _ => None, 153 | } 154 | } 155 | } 156 | } 157 | 158 | impl NodeSeqItem<'_> { 159 | /// 获得区分节点的序号。 160 | pub fn at(&self) -> &str { 161 | self.at 162 | } 163 | } 164 | 165 | impl<'de> NodeSeqItem<'de> { 166 | /// 反序列化一个节点的内容。 167 | pub fn deserialize<T: Deserialize<'de>>(&self) -> T { 168 | T::deserialize(&mut ValueDeserializer { 169 | dtb: self.dtb, 170 | reg: self.reg, 171 | cursor: ValueCursor::Body(self.body), 172 | }) 173 | .unwrap() 174 | } 175 | } 176 | 177 | #[cfg(test)] 178 | mod tests { 179 | use crate::buildin::{NodeSeq, Reg}; 180 | use crate::{Dtb, DtbPtr, from_raw_mut}; 181 | use serde::Deserialize; 182 | 183 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/bl808.dtb"); 184 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 185 | const RAW_DEVICE_TREE_QEMU: &[u8] = include_bytes!("../../examples/qemu-virt.dtb"); 186 | const BUFFER_SIZE_QEMU: usize = RAW_DEVICE_TREE_QEMU.len(); 187 | #[derive(Deserialize)] 188 | pub struct Tree<'a> { 189 | /// Memory information. 190 | pub memory: NodeSeq<'a>, 191 | } 192 | /// Memory range. 193 | #[derive(Deserialize)] 194 | #[serde(rename_all = "kebab-case")] 195 | pub struct Memory<'a> { 196 | pub reg: Reg<'a>, 197 | } 198 | #[test] 199 | fn test_nodeseq_without_at() { 200 | #[repr(align(8))] 201 | struct AlignedBuffer { 202 | pub data: [u8; RAW_DEVICE_TREE.len()], 203 | } 204 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 205 | data: [0; BUFFER_SIZE], 206 | }); 207 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 208 | let mut slice = aligned_data.data.to_vec(); 209 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); 210 | let dtb = Dtb::from(ptr).share(); 211 | 212 | let t: Tree = from_raw_mut(&dtb).unwrap(); 213 | assert_eq!(t.memory.len(), 1); 214 | let range = t 215 | .memory 216 | .iter() 217 | .next() 218 | .unwrap() 219 | .deserialize::<Memory>() 220 | .reg 221 | .iter() 222 | .next() 223 | .unwrap() 224 | .0; 225 | assert_eq!(range, 1342177280..1408237568); 226 | } 227 | #[test] 228 | fn test_nodeseq_with_at() { 229 | #[repr(align(8))] 230 | struct AlignedBuffer { 231 | pub data: [u8; RAW_DEVICE_TREE_QEMU.len()], 232 | } 233 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 234 | data: [0; BUFFER_SIZE_QEMU], 235 | }); 236 | aligned_data.data[..BUFFER_SIZE_QEMU].clone_from_slice(RAW_DEVICE_TREE_QEMU); 237 | let mut slice = aligned_data.data.to_vec(); 238 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); 239 | let dtb = Dtb::from(ptr).share(); 240 | 241 | let t: Tree = from_raw_mut(&dtb).unwrap(); 242 | assert_eq!(t.memory.len(), 1); 243 | let range = t 244 | .memory 245 | .iter() 246 | .next() 247 | .unwrap() 248 | .deserialize::<Memory>() 249 | .reg 250 | .iter() 251 | .next() 252 | .unwrap() 253 | .0; 254 | assert_eq!(range, 2147483648..6442450944); 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/de_mut/reg.rs: -------------------------------------------------------------------------------- 1 | use super::{BLOCK_LEN, PropCursor, RefDtb, ValueCursor}; 2 | use core::{fmt::Debug, ops::Range}; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | /// 节点地址空间。 6 | pub struct Reg<'de>(Inner<'de>); 7 | 8 | pub(super) struct Inner<'de> { 9 | pub dtb: RefDtb<'de>, 10 | pub cursor: PropCursor, 11 | pub reg: RegConfig, 12 | } 13 | 14 | /// 地址段迭代器。 15 | pub struct RegIter<'de> { 16 | data: &'de [u8], 17 | config: RegConfig, 18 | } 19 | 20 | #[derive(Clone, Debug)] 21 | pub struct RegRegion(pub Range<usize>); 22 | 23 | /// 节点地址空间格式。 24 | #[derive(Clone, Copy, Debug)] 25 | #[repr(C)] 26 | pub(super) struct RegConfig { 27 | pub address_cells: usize, 28 | pub size_cells: usize, 29 | } 30 | 31 | impl RegConfig { 32 | pub const DEFAULT: Self = Self { 33 | address_cells: 2, 34 | size_cells: 1, 35 | }; 36 | } 37 | 38 | impl<'de> Deserialize<'de> for Reg<'_> { 39 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 40 | where 41 | D: serde::Deserializer<'de>, 42 | { 43 | let value_deserialzer = super::ValueDeserializer::deserialize(deserializer)?; 44 | 45 | let inner = Inner { 46 | dtb: value_deserialzer.dtb, 47 | reg: value_deserialzer.reg, 48 | cursor: match value_deserialzer.cursor { 49 | ValueCursor::Prop(_, cursor) => cursor, 50 | _ => { 51 | unreachable!("Reg Deserialize should only be called by prop cursor") 52 | } 53 | }, 54 | }; 55 | 56 | Ok(Self(inner)) 57 | } 58 | } 59 | 60 | impl Reg<'_> { 61 | pub fn iter(&self) -> RegIter { 62 | RegIter { 63 | data: self.0.cursor.data_on(self.0.dtb), 64 | config: self.0.reg, 65 | } 66 | } 67 | } 68 | 69 | impl Debug for Reg<'_> { 70 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 71 | let mut iter = self.iter(); 72 | if let Some(s) = iter.next() { 73 | write!(f, "[{:#x?}", s.0)?; 74 | for s in iter { 75 | write!(f, ", {:#x?}", s.0)?; 76 | } 77 | write!(f, "]") 78 | } else { 79 | write!(f, "[]") 80 | } 81 | } 82 | } 83 | 84 | impl Iterator for RegIter<'_> { 85 | type Item = RegRegion; 86 | 87 | fn next(&mut self) -> Option<Self::Item> { 88 | let len = BLOCK_LEN * (self.config.address_cells + self.config.size_cells); 89 | if self.data.len() >= len { 90 | let (current_block, data) = self.data.split_at(len); 91 | self.data = data; 92 | let mut base = 0; 93 | let mut len = 0; 94 | let mut block_id = 0; 95 | for _ in 0..self.config.address_cells { 96 | base = (base << 32) 97 | | u32::from_be_bytes( 98 | current_block[block_id * 4..(block_id + 1) * 4] 99 | .try_into() 100 | .unwrap(), 101 | ) as usize; 102 | block_id += 1; 103 | } 104 | for _ in 0..self.config.size_cells { 105 | len = (len << 32) 106 | | u32::from_be_bytes( 107 | current_block[block_id * 4..(block_id + 1) * 4] 108 | .try_into() 109 | .unwrap(), 110 | ) as usize; 111 | block_id += 1; 112 | } 113 | Some(RegRegion(base..base + len)) 114 | } else { 115 | None 116 | } 117 | } 118 | } 119 | 120 | impl Serialize for Reg<'_> { 121 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 122 | where 123 | S: serde::Serializer, 124 | { 125 | // Pass bytes directly for Reg. 126 | serializer.serialize_bytes(self.0.cursor.data_on(self.0.dtb)) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/de_mut/str_seq.rs: -------------------------------------------------------------------------------- 1 | use super::{PropCursor, RefDtb, ValueCursor}; 2 | use core::fmt::Debug; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | /// 一组 '\0' 分隔字符串的映射。 6 | /// 7 | /// `compatible = "sifive,clint0","riscv,clint0";` 8 | /// 这样的一条属性会被编译为两个连续的 '\0' 结尾字符串。 9 | /// `StrSeq` 可以自动将它们分开。 10 | /// 11 | /// `iter` 方法会创建一个迭代器,用于依次访问这些字符串。 12 | /// 根据实现,迭代器会以从右到左的顺序返回这些字符串。 13 | /// 14 | /// 构建时,所有字符串被遍历,所有分隔位置被记录下来。 15 | /// 这需要修改 DTB 上字符串所在位置的内存,因此需要这块内存的写权限。 16 | /// 如果要以其他方式解析 DTB,先将 `StrSeq` 释放,否则可能引发错误。 17 | pub struct StrSeq<'de>(Inner<'de>); 18 | 19 | pub(super) struct Inner<'de> { 20 | pub dtb: RefDtb<'de>, 21 | pub cursor: PropCursor, 22 | } 23 | 24 | /// '\0' 分隔字符串组迭代器。 25 | pub struct StrSeqIter<'de> { 26 | data: &'de [u8], 27 | } 28 | 29 | impl<'de> Deserialize<'de> for StrSeq<'_> { 30 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 31 | where 32 | D: serde::Deserializer<'de>, 33 | { 34 | let value_deserialzer = super::ValueDeserializer::deserialize(deserializer)?; 35 | 36 | let inner = Inner { 37 | dtb: value_deserialzer.dtb, 38 | cursor: match value_deserialzer.cursor { 39 | ValueCursor::Prop(_, cursor) => cursor, 40 | _ => { 41 | unreachable!("StrSeq Deserialize should only be called by prop cursor") 42 | } 43 | }, 44 | }; 45 | 46 | Ok(Self(inner)) 47 | } 48 | } 49 | 50 | impl<'de> StrSeq<'de> { 51 | /// 构造一个可访问每个字符串的迭代器。 52 | pub fn iter<'b>(&'b self) -> StrSeqIter<'de> { 53 | StrSeqIter { 54 | data: self.0.cursor.data_on(self.0.dtb), 55 | } 56 | } 57 | } 58 | 59 | impl Debug for StrSeq<'_> { 60 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 61 | let mut iter = self.iter(); 62 | if let Some(s) = iter.next() { 63 | write!(f, "[\"{s}\"",)?; 64 | for s in iter { 65 | write!(f, ", \"{s}\"")?; 66 | } 67 | write!(f, "]") 68 | } else { 69 | write!(f, "[]") 70 | } 71 | } 72 | } 73 | 74 | impl<'de> Iterator for StrSeqIter<'de> { 75 | type Item = &'de str; 76 | 77 | fn next(&mut self) -> Option<Self::Item> { 78 | if self.data.is_empty() { 79 | None 80 | } else { 81 | let pos = self 82 | .data 83 | .iter() 84 | .position(|&x| x == b'\0') 85 | .unwrap_or(self.data.len()); 86 | let (a, b) = self.data.split_at(pos + 1); 87 | self.data = b; 88 | // Remove \0 at end 89 | Some(unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) }) 90 | } 91 | } 92 | } 93 | 94 | impl Serialize for StrSeq<'_> { 95 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 96 | where 97 | S: serde::Serializer, 98 | { 99 | // Pass bytes directly for StrSeq. 100 | serializer.serialize_bytes(self.0.cursor.data_on(self.0.dtb)) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/de_mut/struct_access.rs: -------------------------------------------------------------------------------- 1 | use super::cursor::MultiNodeCursor; 2 | use super::{BodyCursor, Cursor, PropCursor, ValueCursor, ValueDeserializer}; 3 | use crate::error::Error as DtError; 4 | use serde::de; 5 | 6 | // For map type, we should send root item to trans dtb and reg 7 | pub enum StructAccessType<'de> { 8 | Map(bool), 9 | Seq(&'de str), 10 | Struct(&'static [&'static str]), 11 | } 12 | 13 | /// 结构体解析状态。 14 | pub struct StructAccess<'de, 'b> { 15 | pub access_type: StructAccessType<'de>, 16 | pub temp: Temp, 17 | pub de: &'b mut ValueDeserializer<'de>, 18 | } 19 | 20 | /// 用于跨键-值传递的临时变量。 21 | /// 22 | /// 解析键(名字)时将确定值类型,保存 `Temp` 类型的状态。 23 | /// 根据状态分发值解析器。 24 | pub enum Temp { 25 | Uninit, 26 | Nodes(MultiNodeCursor), 27 | Prop(BodyCursor, PropCursor), 28 | } 29 | 30 | impl<'de> de::MapAccess<'de> for StructAccess<'de, '_> { 31 | type Error = DtError; 32 | 33 | fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> 34 | where 35 | K: de::DeserializeSeed<'de>, 36 | { 37 | if let StructAccessType::Map(flag) = self.access_type { 38 | if !flag { 39 | return seed 40 | .deserialize(de::value::BorrowedStrDeserializer::new("/")) 41 | .map(Some); 42 | } 43 | } 44 | let check_contains = |name: &str| -> bool { 45 | match self.access_type { 46 | StructAccessType::Struct(fields) => fields.contains(&name), 47 | _ => true, 48 | } 49 | }; 50 | let origin_cursor = match self.de.cursor { 51 | ValueCursor::Body(cursor) => cursor, 52 | ValueCursor::Node(result) => result.skip_cursor, 53 | ValueCursor::NodeIn(result) => result.data_cursor, 54 | _ => unreachable!("map access's cursor should always be body cursor"), 55 | }; 56 | self.de.cursor = ValueCursor::Body(origin_cursor); 57 | let name = loop { 58 | let origin_cursor = match self.de.cursor { 59 | ValueCursor::Body(cursor) => cursor, 60 | ValueCursor::Node(result) => result.skip_cursor, 61 | _ => unreachable!("map access's cursor should always be body cursor"), 62 | }; 63 | self.de.cursor = ValueCursor::Body(origin_cursor); 64 | match self.de.move_on() { 65 | // 子节点名字 66 | Cursor::Title(c) => { 67 | let (name, _) = c.split_on(self.de.dtb); 68 | 69 | let (pre_name, _) = name.split_once('@').unwrap_or((name, "")); 70 | // 子节点名字不带 @ 或正在解析 Node 类型 71 | if pre_name == name || check_contains(name) { 72 | let take_result = c.take_node_on(self.de.dtb, name); 73 | self.de.cursor = ValueCursor::Node(take_result); 74 | if check_contains(name) { 75 | self.temp = Temp::Nodes(take_result); 76 | break name; 77 | } 78 | } 79 | // @ 之前的部分是真正的名字,用这个名字搜索连续的一组 80 | else { 81 | let take_result = c.take_group_on(self.de.dtb, pre_name); 82 | self.de.cursor = ValueCursor::Node(take_result); 83 | if check_contains(pre_name) { 84 | self.temp = Temp::Nodes(take_result); 85 | break pre_name; 86 | } 87 | } 88 | } 89 | // 属性条目 90 | Cursor::Prop(c) => { 91 | let (name, next) = c.name_on(self.de.dtb); 92 | self.de.cursor = ValueCursor::Body(next); 93 | match name { 94 | "#address-cells" => { 95 | self.de.reg.address_cells = c.map_u32_on(self.de.dtb)? as usize; 96 | } 97 | "#size-cells" => { 98 | self.de.reg.size_cells = c.map_u32_on(self.de.dtb)? as usize; 99 | } 100 | _ => {} 101 | } 102 | if check_contains(name) { 103 | self.temp = Temp::Prop(origin_cursor, c); 104 | break name; 105 | } 106 | } 107 | // 截止符,结构体解析完成 108 | Cursor::End => { 109 | self.de.step_n(1); 110 | return Ok(None); 111 | } 112 | } 113 | }; 114 | seed.deserialize(de::value::BorrowedStrDeserializer::new(name)) 115 | .map(Some) 116 | } 117 | 118 | fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error> 119 | where 120 | V: de::DeserializeSeed<'de>, 121 | { 122 | if let StructAccessType::Map(ref mut flag) = self.access_type { 123 | if !*flag { 124 | *flag = true; 125 | return seed.deserialize(&mut ValueDeserializer { 126 | dtb: self.de.dtb, 127 | reg: self.de.reg, 128 | cursor: self.de.cursor, 129 | }); 130 | } 131 | } 132 | match self.temp { 133 | Temp::Nodes(ref result) => { 134 | // 键是独立节点名字,递归 135 | match self.access_type { 136 | StructAccessType::Map(_) => seed.deserialize(&mut ValueDeserializer { 137 | dtb: self.de.dtb, 138 | reg: self.de.reg, 139 | cursor: ValueCursor::NodeIn(*result), 140 | }), 141 | StructAccessType::Struct(_) => seed.deserialize(&mut ValueDeserializer { 142 | dtb: self.de.dtb, 143 | reg: self.de.reg, 144 | cursor: ValueCursor::NodeIn(*result), 145 | }), 146 | _ => unreachable!(), 147 | } 148 | } 149 | Temp::Prop(origin_cursor, cursor) => { 150 | // 键是属性名字,构造属性反序列化器 151 | seed.deserialize(&mut ValueDeserializer { 152 | dtb: self.de.dtb, 153 | reg: self.de.reg, 154 | cursor: ValueCursor::Prop(origin_cursor, cursor), 155 | }) 156 | } 157 | Temp::Uninit => { 158 | unreachable!("find uninited result") 159 | } 160 | } 161 | } 162 | } 163 | 164 | impl<'de> de::SeqAccess<'de> for StructAccess<'de, '_> { 165 | type Error = DtError; 166 | 167 | fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> 168 | where 169 | K: de::DeserializeSeed<'de>, 170 | { 171 | if let StructAccessType::Seq(pre_name) = self.access_type { 172 | match self.de.move_on() { 173 | // 子节点名字 174 | Cursor::Title(c) => { 175 | let (name, _) = c.split_on(self.de.dtb); 176 | let next = c.take_node_on(self.de.dtb, name).skip_cursor; 177 | let prev_cursor = match self.de.cursor { 178 | ValueCursor::Body(cursor) => cursor, 179 | _ => unreachable!(), 180 | }; 181 | 182 | let pre_len = name.as_bytes().iter().take_while(|b| **b != b'@').count(); 183 | let name_bytes = &name.as_bytes()[..pre_len]; 184 | let name = unsafe { core::str::from_utf8_unchecked(name_bytes) }; 185 | if pre_name != name { 186 | return Ok(None); 187 | } 188 | self.de.cursor = ValueCursor::Body(next); 189 | seed.deserialize(&mut ValueDeserializer { 190 | dtb: self.de.dtb, 191 | reg: self.de.reg, 192 | cursor: ValueCursor::Body(prev_cursor), 193 | }) 194 | .map(Some) 195 | } 196 | _ => Ok(None), 197 | } 198 | } else { 199 | unreachable!("SeqAccess should only be accessed by seq"); 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/de_mut/structs.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | common::{ALIGN, Header}, 3 | error::Error as DtError, 4 | }; 5 | use core::{cell::RefCell, fmt::Display}; 6 | 7 | /// 设备树指针。 8 | /// 9 | /// 用于构造设备树或跨虚存传递。 10 | #[repr(transparent)] 11 | pub struct DtbPtr(usize); 12 | 13 | impl TryFrom<usize> for DtbPtr { 14 | type Error = DtError; 15 | 16 | fn try_from(value: usize) -> Result<Self, Self::Error> { 17 | Self::from_raw(value as _) 18 | } 19 | } 20 | 21 | impl DtbPtr { 22 | const fn get_header(ptr: &*mut u8) -> &Header { 23 | unsafe { &*(*ptr as *const Header) } 24 | } 25 | 26 | /// 验证指针指向的设备树,并构造 `DtbPtr`。 27 | pub fn from_raw(ptr: *mut u8) -> Result<Self, DtError> { 28 | if (ptr as usize) & (ALIGN - 1) != 0 { 29 | Err(DtError::unaligned(ptr as _)) 30 | } else { 31 | { Self::get_header(&ptr) }.verify().map(|_| Self(ptr as _)) 32 | } 33 | } 34 | 35 | /// 计算能容纳整个设备树的最小对齐。 36 | pub const fn align(&self) -> usize { 37 | let ptr = self.0 as *mut u8; 38 | let header = Self::get_header(&ptr); 39 | let len = u32::from_be(header.total_size) as usize; 40 | let mut res = ALIGN; 41 | while res < len { 42 | res <<= 1; 43 | } 44 | res 45 | } 46 | } 47 | 48 | /// 对齐到 4 字节的设备树结构块。 49 | #[derive(PartialEq, Eq)] 50 | #[repr(transparent)] 51 | pub(super) struct StructureBlock(pub u32); 52 | 53 | /// 结构块长度。 54 | pub(super) const BLOCK_LEN: usize = core::mem::size_of::<StructureBlock>(); 55 | 56 | impl Display for StructureBlock { 57 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 58 | write!(f, "{:?}", u32::to_be_bytes(self.0)) 59 | } 60 | } 61 | 62 | impl StructureBlock { 63 | /// 节点起始符。 64 | pub const NODE_BEGIN: Self = Self(1u32.to_be()); 65 | /// 节点终止符。 66 | pub const NODE_END: Self = Self(2u32.to_be()); 67 | /// 属性起始符。 68 | pub const PROP: Self = Self(3u32.to_be()); 69 | /// 块占位符。 70 | pub const NOP: Self = Self(4u32.to_be()); 71 | /// 结构区终止符。 72 | #[allow(unused)] 73 | pub const END: Self = Self(9u32.to_be()); 74 | 75 | /// 一个 '\0' 结尾字符串结束于此块。 76 | pub const fn is_end_of_str(&self) -> bool { 77 | matches!(self.0.to_ne_bytes(), [_, _, _, 0]) 78 | } 79 | 80 | /// '\0' 结尾字符串的实际结尾。 81 | pub fn str_end(&self) -> usize { 82 | match self.0.to_ne_bytes() { 83 | [0, _, _, _] => 0, 84 | [_, 0, _, _] => 1, 85 | [_, _, 0, _] => 2, 86 | [_, _, _, _] => 3, 87 | } 88 | } 89 | 90 | /// 转换为描述字节长度或偏移的数值。 91 | pub const fn as_usize(&self) -> usize { 92 | u32::from_be(self.0) as _ 93 | } 94 | 95 | /// 构造字节切片。 96 | /// 97 | /// ### Safety 98 | /// 99 | /// 保证 当前位置 + 长度 不会超过文件大小。 100 | pub fn lead_slice<'a>(&self, len: usize) -> &'a [u8] { 101 | unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, len) } 102 | } 103 | pub fn lead_str<'a>(&self, len: usize) -> &'a str { 104 | let slice = self.lead_slice(len); 105 | unsafe { core::str::from_utf8_unchecked(slice) } 106 | } 107 | } 108 | 109 | /// 设备树的映射形式。 110 | pub struct Dtb { 111 | ptr: *const u8, 112 | pub(super) structure: &'static mut [StructureBlock], 113 | pub(super) strings: &'static [u8], 114 | } 115 | 116 | impl From<Dtb> for DtbPtr { 117 | fn from(dtb: Dtb) -> Self { 118 | Self(dtb.ptr as _) 119 | } 120 | } 121 | 122 | impl From<DtbPtr> for Dtb { 123 | fn from(ptr: DtbPtr) -> Self { 124 | let header = unsafe { &*(ptr.0 as *const Header) }; 125 | 126 | let off_structure = u32::from_be(header.off_dt_struct); 127 | let len_structure = u32::from_be(header.size_dt_struct); 128 | let off_strings = u32::from_be(header.off_dt_strings); 129 | let len_strings = u32::from_be(header.size_dt_strings); 130 | 131 | let ptr_structure = off_structure as usize + ptr.0; 132 | let len_structure = len_structure as usize; 133 | let ptr_strings = off_strings as usize + ptr.0; 134 | let len_strings = len_strings as usize; 135 | 136 | unsafe { 137 | Self { 138 | ptr: ptr.0 as _, 139 | structure: core::slice::from_raw_parts_mut( 140 | ptr_structure as *mut StructureBlock, 141 | len_structure / core::mem::size_of::<StructureBlock>(), 142 | ), 143 | strings: core::slice::from_raw_parts(ptr_strings as _, len_strings), 144 | } 145 | } 146 | } 147 | } 148 | 149 | impl Dtb { 150 | /// 构造一个可安全共享的设备树映射。 151 | pub fn share(self) -> RefCell<Self> { 152 | RefCell::new(self) 153 | } 154 | 155 | /// 获取结构块的相对偏移。 156 | pub fn off_dt_struct(&self) -> usize { 157 | u32::from_be(unsafe { &*(self.ptr as *const Header) }.off_dt_struct) as _ 158 | } 159 | } 160 | 161 | pub(super) type RefDtb<'a> = &'a RefCell<Dtb>; 162 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 HUST IoT Security Lab 2 | // serde_device_tree is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | //! When serializing or deserializing device tree goes wrong. 12 | 13 | #[cfg(feature = "alloc")] 14 | use alloc::{format, string::String}; 15 | use core::fmt; 16 | 17 | use crate::common::ALIGN; 18 | 19 | /// Represents all possible errors that can occur when serializing or deserializing device tree data. 20 | #[derive(Clone, Debug)] 21 | pub enum Error { 22 | Typed { 23 | error_type: ErrorType, 24 | file_index: usize, 25 | }, 26 | #[cfg(feature = "alloc")] 27 | Custom(String), 28 | #[cfg(not(feature = "alloc"))] 29 | Custom, 30 | } 31 | 32 | /// All error types that would occur from device tree serializing and deserializing. 33 | #[derive(Debug, Clone, Copy)] 34 | pub enum ErrorType { 35 | Unaligned { 36 | ptr_value: usize, 37 | align: usize, 38 | }, 39 | InvalidMagic { 40 | wrong_magic: u32, 41 | }, 42 | IncompatibleVersion { 43 | last_comp_version: u32, 44 | library_supported_version: u32, 45 | }, 46 | HeaderTooShort { 47 | header_length: u32, 48 | at_least_length: u32, 49 | }, 50 | StructureIndex { 51 | current_index: u32, 52 | bound_index: u32, 53 | structure_or_string: bool, 54 | overflow_or_underflow: bool, 55 | }, 56 | U32IndexSpace { 57 | current_index: u32, 58 | }, 59 | StringEofUnexpected, 60 | SliceEofUnexpected { 61 | expected_length: u32, 62 | remaining_length: u32, 63 | }, 64 | TableStringOffset { 65 | given_offset: u32, 66 | bound_offset: u32, 67 | }, 68 | TagEofUnexpected { 69 | current_index: u32, 70 | bound_index: u32, 71 | }, 72 | InvalidTagId { 73 | wrong_id: u32, 74 | }, 75 | ExpectStructBegin, 76 | ExpectStructEnd, 77 | NoRemainingTags, 78 | InvalidSerdeTypeLength { 79 | expected_length: u8, 80 | }, 81 | DeserializeNotComplete, 82 | BuildInTypeParseFailed { 83 | expected: &'static str, 84 | }, 85 | Utf8(core::str::Utf8Error), 86 | } 87 | 88 | impl Error { 89 | #[inline] 90 | pub const fn unaligned(ptr_value: usize) -> Error { 91 | Error::Typed { 92 | error_type: ErrorType::Unaligned { 93 | ptr_value, 94 | align: ALIGN, 95 | }, 96 | file_index: 0, 97 | } 98 | } 99 | #[inline] 100 | pub const fn invalid_magic(wrong_magic: u32) -> Error { 101 | Error::Typed { 102 | error_type: ErrorType::InvalidMagic { wrong_magic }, 103 | file_index: 0, 104 | } 105 | } 106 | #[inline] 107 | pub const fn incompatible_version( 108 | last_comp_version: u32, 109 | library_supported_version: u32, 110 | file_index: usize, 111 | ) -> Error { 112 | Error::Typed { 113 | error_type: ErrorType::IncompatibleVersion { 114 | last_comp_version, 115 | library_supported_version, 116 | }, 117 | file_index, 118 | } 119 | } 120 | #[inline] 121 | pub fn header_too_short(header_length: u32, at_least_length: u32, file_index: usize) -> Error { 122 | Error::Typed { 123 | error_type: ErrorType::HeaderTooShort { 124 | header_length, 125 | at_least_length, 126 | }, 127 | file_index, 128 | } 129 | } 130 | #[inline] 131 | pub fn u32_index_space_overflow(current_index: u32, file_index: usize) -> Error { 132 | Error::Typed { 133 | error_type: ErrorType::U32IndexSpace { current_index }, 134 | file_index, 135 | } 136 | } 137 | #[inline] 138 | pub fn structure_index_underflow( 139 | begin_index: u32, 140 | at_least_index: u32, 141 | file_index: usize, 142 | ) -> Error { 143 | Error::Typed { 144 | error_type: ErrorType::StructureIndex { 145 | current_index: begin_index, 146 | bound_index: at_least_index, 147 | structure_or_string: true, 148 | overflow_or_underflow: false, 149 | }, 150 | file_index, 151 | } 152 | } 153 | #[inline] 154 | pub fn structure_index_overflow( 155 | end_index: u32, 156 | at_most_index: u32, 157 | file_index: usize, 158 | ) -> Error { 159 | Error::Typed { 160 | error_type: ErrorType::StructureIndex { 161 | current_index: end_index, 162 | bound_index: at_most_index, 163 | structure_or_string: true, 164 | overflow_or_underflow: true, 165 | }, 166 | file_index, 167 | } 168 | } 169 | #[inline] 170 | pub fn string_index_underflow( 171 | begin_index: u32, 172 | at_least_index: u32, 173 | file_index: usize, 174 | ) -> Error { 175 | Error::Typed { 176 | error_type: ErrorType::StructureIndex { 177 | current_index: begin_index, 178 | bound_index: at_least_index, 179 | structure_or_string: false, 180 | overflow_or_underflow: false, 181 | }, 182 | file_index, 183 | } 184 | } 185 | #[inline] 186 | pub fn string_index_overflow(end_index: u32, at_most_index: u32, file_index: usize) -> Error { 187 | Error::Typed { 188 | error_type: ErrorType::StructureIndex { 189 | current_index: end_index, 190 | bound_index: at_most_index, 191 | structure_or_string: false, 192 | overflow_or_underflow: true, 193 | }, 194 | file_index, 195 | } 196 | } 197 | #[inline] 198 | pub fn mem_rsvmap_index_underflow( 199 | begin_index: u32, 200 | at_least_index: u32, 201 | file_index: usize, 202 | ) -> Error { 203 | Error::Typed { 204 | error_type: ErrorType::StructureIndex { 205 | current_index: begin_index, 206 | bound_index: at_least_index, 207 | structure_or_string: false, 208 | overflow_or_underflow: false, 209 | }, 210 | file_index, 211 | } 212 | } 213 | #[inline] 214 | pub fn string_eof_unpexpected(file_index: usize) -> Error { 215 | Error::Typed { 216 | error_type: ErrorType::StringEofUnexpected, 217 | file_index, 218 | } 219 | } 220 | #[inline] 221 | pub fn slice_eof_unpexpected( 222 | expected_length: u32, 223 | remaining_length: u32, 224 | file_index: usize, 225 | ) -> Error { 226 | Error::Typed { 227 | error_type: ErrorType::SliceEofUnexpected { 228 | expected_length, 229 | remaining_length, 230 | }, 231 | file_index, 232 | } 233 | } 234 | #[inline] 235 | pub fn table_string_offset(given_offset: u32, bound_offset: u32, file_index: usize) -> Error { 236 | Error::Typed { 237 | error_type: ErrorType::TableStringOffset { 238 | given_offset, 239 | bound_offset, 240 | }, 241 | file_index, 242 | } 243 | } 244 | #[inline] 245 | pub fn tag_eof_unexpected(current_index: u32, bound_index: u32, file_index: usize) -> Error { 246 | Error::Typed { 247 | error_type: ErrorType::TagEofUnexpected { 248 | current_index, 249 | bound_index, 250 | }, 251 | file_index, 252 | } 253 | } 254 | #[inline] 255 | pub fn invalid_tag_id(wrong_id: u32, file_index: usize) -> Error { 256 | Error::Typed { 257 | error_type: ErrorType::InvalidTagId { wrong_id }, 258 | file_index, 259 | } 260 | } 261 | #[inline] 262 | pub fn invalid_serde_type_length(expected_length: u8, file_index: usize) -> Error { 263 | Error::Typed { 264 | error_type: ErrorType::InvalidSerdeTypeLength { expected_length }, 265 | file_index, 266 | } 267 | } 268 | #[inline] 269 | pub fn deserialize_not_complete(file_index: usize) -> Error { 270 | Error::Typed { 271 | error_type: ErrorType::DeserializeNotComplete, 272 | file_index, 273 | } 274 | } 275 | #[inline] 276 | pub fn buildin_type_parsed_error(expected: &'static str, file_index: usize) -> Error { 277 | Error::Typed { 278 | error_type: ErrorType::BuildInTypeParseFailed { expected }, 279 | file_index, 280 | } 281 | } 282 | #[inline] 283 | pub fn utf8(error: core::str::Utf8Error, file_index: usize) -> Error { 284 | Error::Typed { 285 | error_type: ErrorType::Utf8(error), 286 | file_index, 287 | } 288 | } 289 | #[inline] 290 | pub fn expected_struct_begin() -> Error { 291 | Error::Typed { 292 | error_type: ErrorType::ExpectStructBegin, 293 | file_index: 0, 294 | } 295 | } 296 | #[inline] 297 | pub fn expected_struct_end() -> Error { 298 | Error::Typed { 299 | error_type: ErrorType::ExpectStructEnd, 300 | file_index: 0, 301 | } 302 | } 303 | #[inline] 304 | pub fn no_remaining_tags() -> Error { 305 | Error::Typed { 306 | error_type: ErrorType::NoRemainingTags, 307 | file_index: 0, 308 | } 309 | } 310 | } 311 | 312 | /// Alias for a Result with the error type `serde_device_tree:::Error`. 313 | pub type Result<T> = core::result::Result<T, Error>; 314 | 315 | impl serde::de::Error for Error { 316 | fn custom<T>(_msg: T) -> Self 317 | where 318 | T: fmt::Display, 319 | { 320 | #[cfg(feature = "alloc")] 321 | { 322 | Self::Custom(format!("{}", _msg)) 323 | } 324 | 325 | #[cfg(not(feature = "alloc"))] 326 | { 327 | Self::Custom 328 | } 329 | } 330 | } 331 | 332 | #[cfg(feature = "std")] 333 | impl std::error::Error for Error {} 334 | 335 | impl fmt::Display for Error { 336 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 337 | match self { 338 | Error::Typed { 339 | error_type: ErrorType::InvalidMagic { wrong_magic }, 340 | file_index, 341 | } => write!( 342 | f, 343 | "Error(invalid magic, value: {}, index: {})", 344 | wrong_magic, file_index 345 | ), 346 | // todo: format other error types 347 | others => write!(f, "{:?}", others), 348 | } 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 HUST IoT Security Lab 2 | // serde_device_tree is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | //! This library contains two device tree blob deserializers, 12 | //! one with no-std support, 13 | //! the other one doesn't even need alloc. 14 | 15 | #![cfg_attr(not(feature = "std"), no_std)] 16 | 17 | #[cfg(feature = "alloc")] 18 | extern crate alloc; 19 | 20 | pub mod de; 21 | pub mod error; 22 | #[cfg(feature = "ser")] 23 | pub mod ser; 24 | pub mod utils; 25 | pub mod value; 26 | 27 | mod common; 28 | mod de_mut; 29 | mod tag; 30 | 31 | pub use value::compatible::Compatible; 32 | 33 | #[doc(inline)] 34 | pub use de::from_raw; 35 | 36 | #[doc(inline)] 37 | pub use de_mut::{Dtb, DtbPtr, buildin, from_raw_mut}; 38 | 39 | #[doc(inline)] 40 | pub use error::Result; 41 | -------------------------------------------------------------------------------- /src/ser/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod patch; 2 | pub mod pointer; 3 | pub mod serializer; 4 | pub mod string_block; 5 | 6 | use crate::common::*; 7 | use crate::ser::patch::Patch; 8 | 9 | // TODO: set reverse map 10 | const RSVMAP_LEN: usize = 16; 11 | 12 | /// Serialize the data to dtb, with a list fof Patch, write to the `writer`. 13 | /// 14 | /// We do run-twice on convert, first time to generate string block, second time todo real 15 | /// structure. 16 | pub fn to_dtb<'se, T>(data: &T, list: &'se [Patch<'se>], writer: &'se mut [u8]) -> Result<(), Error> 17 | where 18 | T: serde::ser::Serialize, 19 | { 20 | writer.iter_mut().for_each(|x| *x = 0); 21 | 22 | let mut offset: usize = 0; 23 | { 24 | let mut dst = crate::ser::pointer::Pointer::new(None); 25 | let mut patch_list = crate::ser::patch::PatchList::new(list); 26 | let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset); 27 | let mut ser = 28 | crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list); 29 | let ser = crate::ser::serializer::Serializer::new(&mut ser); 30 | data.serialize(ser)?; 31 | }; 32 | list.iter().for_each(|patch| patch.init()); 33 | // Write from bottom to top, to avoid overlap. 34 | for i in (0..offset).rev() { 35 | writer[writer.len() - offset + i] = writer[i]; 36 | writer[i] = 0; 37 | } 38 | // TODO: make sure no out of bound. 39 | 40 | let writer_len = writer.len(); 41 | let (data_block, string_block) = writer.split_at_mut(writer.len() - offset); 42 | let (header, data_block) = data_block.split_at_mut(HEADER_LEN as usize + RSVMAP_LEN); 43 | let struct_len = { 44 | let mut patch_list = crate::ser::patch::PatchList::new(list); 45 | let mut block = crate::ser::string_block::StringBlock::new(string_block, &mut offset); 46 | let mut dst = crate::ser::pointer::Pointer::new(Some(data_block)); 47 | let mut ser = 48 | crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list); 49 | let ser = crate::ser::serializer::Serializer::new(&mut ser); 50 | data.serialize(ser)? 51 | } 52 | .1; 53 | // Make header 54 | { 55 | let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) }; 56 | header.magic = u32::from_be(DEVICE_TREE_MAGIC); 57 | header.total_size = u32::from_be(writer_len as u32); 58 | header.off_dt_struct = u32::from_be(HEADER_LEN + RSVMAP_LEN as u32); 59 | header.off_dt_strings = u32::from_be((writer_len - offset) as u32); 60 | header.off_mem_rsvmap = u32::from_be(HEADER_LEN); 61 | header.version = u32::from_be(SUPPORTED_VERSION); 62 | header.last_comp_version = u32::from_be(SUPPORTED_VERSION); // TODO: maybe 16 63 | header.boot_cpuid_phys = 0; // TODO: wtf is this prop 64 | header.size_dt_strings = u32::from_be(offset as u32); 65 | header.size_dt_struct = u32::from_be(struct_len as u32); 66 | } 67 | Ok(()) 68 | } 69 | 70 | #[derive(Debug)] 71 | pub enum Error { 72 | Unknown, 73 | } 74 | 75 | impl core::fmt::Display for Error { 76 | fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 77 | write!(formatter, "{:?}", self) 78 | } 79 | } 80 | 81 | impl core::error::Error for Error {} 82 | 83 | impl serde::ser::Error for Error { 84 | fn custom<T>(_msg: T) -> Self 85 | where 86 | T: core::fmt::Display, 87 | { 88 | Self::Unknown 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/ser/patch.rs: -------------------------------------------------------------------------------- 1 | use super::serializer::Serializer; 2 | use super::serializer::ValueType; 3 | use core::cell::Cell; 4 | 5 | /// Since this crate is mostly work with `noalloc`, we use `Patch` and `PatchList` for change or 6 | /// add on a dtb. 7 | pub struct Patch<'se> { 8 | name: &'se str, 9 | pub data: &'se dyn dyn_serde::Serialize, 10 | pub patch_type: ValueType, 11 | 12 | /// This patch match how many item between its path and serializer. 13 | matched_depth: Cell<usize>, 14 | /// Show this patch have been parsed. 15 | parsed: Cell<bool>, 16 | } 17 | 18 | impl core::fmt::Debug for Patch<'_> { 19 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 20 | f.debug_struct("") 21 | .field("name", &self.name) 22 | .field("patch_type", &self.patch_type) 23 | .field("matched_depth", &self.matched_depth) 24 | .field("parsed", &self.parsed) 25 | .finish() 26 | } 27 | } 28 | 29 | impl<'se> Patch<'se> { 30 | #[inline(always)] 31 | pub fn new( 32 | name: &'se str, 33 | data: &'se dyn dyn_serde::Serialize, 34 | patch_type: ValueType, 35 | ) -> Patch<'se> { 36 | Patch { 37 | name, 38 | data, 39 | patch_type, 40 | matched_depth: Cell::new(1), 41 | parsed: Cell::new(false), 42 | } 43 | } 44 | 45 | #[inline(always)] 46 | /// Reset the status of patch. 47 | pub fn init(&self) { 48 | self.matched_depth.set(1); 49 | self.parsed.set(false); 50 | } 51 | 52 | #[inline(always)] 53 | pub fn get_depth(&self) -> usize { 54 | self.name.split('/').count() - 1 55 | } 56 | 57 | #[inline(always)] 58 | pub fn get_depth_path(&self, x: usize) -> &'se str { 59 | self.name.split('/').nth(x - 1).unwrap_or_default() 60 | } 61 | 62 | // I hope to impl serde::ser::Serializer, but erase_serialize's return value is different from 63 | // normal serialize, so we do this. 64 | /// Serialize this patch with serializer. 65 | #[inline(always)] 66 | pub fn serialize(&self, serializer: Serializer<'_, 'se>) { 67 | self.parsed.set(true); 68 | self.data 69 | .serialize_dyn(&mut <dyn dyn_serde::Serializer>::new(serializer)) 70 | .unwrap(); 71 | } 72 | } 73 | 74 | /// Here is a list of `Patch`, and have some methods for update `Patch` status. 75 | #[derive(Debug)] 76 | pub struct PatchList<'se> { 77 | list: &'se [Patch<'se>], 78 | } 79 | 80 | impl<'se> PatchList<'se> { 81 | #[inline(always)] 82 | pub fn new(list: &'se [Patch<'se>]) -> PatchList<'se> { 83 | list.iter().for_each(|x| x.init()); 84 | PatchList { list } 85 | } 86 | 87 | #[inline(always)] 88 | pub fn step_forward(&self, name: &str, depth: usize) -> Option<&'se Patch<'se>> { 89 | let mut matched_patch = None; 90 | self.list.iter().for_each(|patch| { 91 | if patch.matched_depth.get() == depth - 1 && patch.get_depth_path(depth) == name { 92 | patch.matched_depth.set(patch.matched_depth.get() + 1); 93 | if patch.get_depth() == depth { 94 | if matched_patch.is_some() { 95 | panic!("More than one replace data on a same path"); 96 | } 97 | matched_patch = Some(patch); 98 | } 99 | } 100 | }); 101 | matched_patch 102 | } 103 | 104 | #[inline(always)] 105 | pub fn step_back(&self, depth: usize) { 106 | self.list.iter().for_each(|patch| { 107 | if patch.matched_depth.get() == depth { 108 | patch.matched_depth.set(patch.matched_depth.get() - 1); 109 | } 110 | }); 111 | } 112 | 113 | #[inline(always)] 114 | /// Return a list which is on this level, but haven't been parsed, which usually means this 115 | /// patch is for adding. 116 | pub fn add_list(&self, depth: usize) -> impl Iterator<Item = &'se Patch<'se>> + use<'se> { 117 | self.list.iter().filter(move |x| { 118 | x.matched_depth.get() == depth && x.get_depth() == depth + 1 && !x.parsed.get() 119 | }) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/ser/pointer.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | 3 | pub struct Pointer<'se> { 4 | offset: usize, 5 | data: Option<&'se mut [u8]>, 6 | } 7 | 8 | impl<'se> Pointer<'se> { 9 | #[inline(always)] 10 | pub fn new(dst: Option<&'se mut [u8]>) -> Pointer<'se> { 11 | Pointer { 12 | offset: 0, 13 | data: dst, 14 | } 15 | } 16 | 17 | #[inline(always)] 18 | pub fn update_data(&mut self, data: Option<&'se mut [u8]>) { 19 | self.data = data; 20 | } 21 | 22 | #[inline(always)] 23 | pub fn get_offset(&self) -> usize { 24 | self.offset 25 | } 26 | 27 | #[inline(always)] 28 | pub fn write_to_offset_u32(&mut self, offset: usize, value: u32) { 29 | if let Some(ref mut data) = self.data { 30 | data[offset..offset + 4].copy_from_slice(&u32::to_be_bytes(value)) 31 | } 32 | } 33 | 34 | /// Create a PROP header with nop padding, return the offset of `FDT_PROP` token. 35 | #[inline(always)] 36 | pub fn step_by_prop(&mut self) -> usize { 37 | self.step_by_u32(FDT_PROP); 38 | let offset = self.offset; 39 | // Put 2 nop as `name` and `nameoff`. 40 | self.step_by_u32(FDT_NOP); // When create prop header, we do not know how long of the prop value. 41 | self.step_by_u32(FDT_NOP); // We can not assume this is a prop, so nop for default. 42 | offset 43 | } 44 | 45 | #[inline(always)] 46 | pub fn step_by_len(&mut self, len: usize) { 47 | self.offset += len 48 | } 49 | 50 | #[inline(always)] 51 | pub fn step_by_u32(&mut self, value: u32) { 52 | if let Some(ref mut data) = self.data { 53 | data[self.offset..self.offset + 4].copy_from_slice(&u32::to_be_bytes(value)) 54 | } 55 | self.step_by_len(4); 56 | } 57 | 58 | #[inline(always)] 59 | pub fn step_by_u8(&mut self, value: u8) { 60 | if let Some(ref mut data) = self.data { 61 | data[self.offset] = value 62 | } 63 | self.step_by_len(1); 64 | } 65 | 66 | #[inline(always)] 67 | pub fn step_align(&mut self) { 68 | while self.offset % 4 != 0 { 69 | if let Some(ref mut data) = self.data { 70 | data[self.offset] = 0 71 | } 72 | self.offset += 1; 73 | } 74 | } 75 | 76 | #[inline(always)] 77 | pub fn step_by_name(&mut self, name: &str) { 78 | name.bytes().for_each(|x| { 79 | self.step_by_u8(x); 80 | }); 81 | self.step_by_u8(0); 82 | self.step_align(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/ser/serializer.rs: -------------------------------------------------------------------------------- 1 | use super::patch::{Patch, PatchList}; 2 | use super::pointer::Pointer; 3 | use super::string_block::StringBlock; 4 | use crate::common::*; 5 | use crate::ser::Error; 6 | 7 | // The enum for current parsing type. 8 | #[derive(Clone, Copy, Debug)] 9 | pub enum ValueType { 10 | Node, 11 | Prop, 12 | } 13 | 14 | /// SerializerInner 15 | /// - `dst`: Pointer of distance &[u8] and the ref of &[u8]. 16 | pub struct SerializerInner<'se> { 17 | pub dst: &'se mut Pointer<'se>, 18 | string_block: &'se mut StringBlock<'se>, 19 | patch_list: &'se mut PatchList<'se>, 20 | } 21 | 22 | /// Serializer 23 | /// - `ser`: all mutable reference of result. 24 | pub struct Serializer<'a, 'se> { 25 | pub ser: &'a mut SerializerInner<'se>, 26 | 27 | prop_token_offset: usize, 28 | overwrite_patch: Option<&'se Patch<'se>>, 29 | current_name: &'se str, 30 | current_dep: usize, 31 | } 32 | 33 | impl<'se> SerializerInner<'se> { 34 | #[inline(always)] 35 | pub fn new( 36 | dst: &'se mut Pointer<'se>, 37 | string_block: &'se mut StringBlock<'se>, 38 | patch_list: &'se mut PatchList<'se>, 39 | ) -> Self { 40 | Self { 41 | dst, 42 | string_block, 43 | patch_list, 44 | } 45 | } 46 | } 47 | 48 | impl<'a, 'se> Serializer<'a, 'se> { 49 | #[inline(always)] 50 | pub fn new(inner: &'a mut SerializerInner<'se>) -> Self { 51 | Serializer { 52 | ser: inner, 53 | 54 | current_dep: 0, 55 | current_name: "", 56 | prop_token_offset: 0, 57 | overwrite_patch: None, 58 | } 59 | } 60 | 61 | #[inline(always)] 62 | pub fn get_next(self) -> Serializer<'a, 'se> { 63 | Serializer { 64 | ser: self.ser, 65 | current_dep: self.current_dep + 1, 66 | current_name: self.current_name, 67 | prop_token_offset: 0, 68 | overwrite_patch: None, 69 | } 70 | } 71 | 72 | #[inline(always)] 73 | pub fn get_next_ref<'b>(&'b mut self) -> Serializer<'b, 'se> { 74 | Serializer { 75 | ser: self.ser, 76 | current_dep: self.current_dep + 1, 77 | current_name: self.current_name, 78 | prop_token_offset: 0, 79 | overwrite_patch: None, 80 | } 81 | } 82 | } 83 | 84 | trait SerializeDynamicField<'se> { 85 | fn start_node(&mut self) -> Result<(), Error>; 86 | fn end_node(&mut self) -> Result<(), Error>; 87 | fn serialize_field_meta(&mut self, key: &'se str) -> Result<(), Error>; 88 | fn serialize_field_data<T>(&mut self, value: &T) -> Result<(), Error> 89 | where 90 | T: serde::ser::Serialize + ?Sized; 91 | fn serialize_dynamic_field<T>(&mut self, key: &'se str, value: &T) -> Result<(), Error> 92 | where 93 | T: serde::ser::Serialize + ?Sized; 94 | } 95 | 96 | impl<'se> SerializeDynamicField<'se> for Serializer<'_, 'se> { 97 | fn start_node(&mut self) -> Result<(), Error> { 98 | self.ser.dst.step_by_u32(FDT_BEGIN_NODE); 99 | if self.current_dep == 1 { 100 | // The name of root node should be empty. 101 | self.ser.dst.step_by_u32(0); 102 | } else { 103 | self.ser.dst.step_by_name(self.current_name); 104 | } 105 | self.ser.dst.step_align(); 106 | 107 | Ok(()) 108 | } 109 | fn end_node(&mut self) -> Result<(), Error> { 110 | for patch in self.ser.patch_list.add_list(self.current_dep) { 111 | let key = patch.get_depth_path(self.current_dep + 1); 112 | self.serialize_dynamic_field(key, patch.data)?; 113 | } 114 | self.ser.dst.step_by_u32(FDT_END_NODE); 115 | if self.current_dep == 1 { 116 | self.ser.dst.step_by_u32(FDT_END); 117 | } 118 | 119 | Ok(()) 120 | } 121 | fn serialize_field_meta(&mut self, key: &'se str) -> Result<(), Error> { 122 | self.prop_token_offset = self.ser.dst.step_by_prop(); 123 | self.current_name = key; 124 | self.overwrite_patch = self.ser.patch_list.step_forward(key, self.current_dep); 125 | 126 | Ok(()) 127 | } 128 | fn serialize_field_data<T>(&mut self, value: &T) -> Result<(), Error> 129 | where 130 | T: serde::ser::Serialize + ?Sized, 131 | { 132 | let value_type = match self.overwrite_patch { 133 | Some(data) => { 134 | let ser = self.get_next_ref(); 135 | data.serialize(ser); 136 | data.patch_type 137 | } 138 | None => { 139 | let ser = self.get_next_ref(); 140 | value.serialize(ser)?.0 141 | } 142 | }; 143 | 144 | // We now know how long the prop value. 145 | // TODO: make we have some better way than put nop, like move this block ahead. 146 | if let ValueType::Node = value_type { 147 | self.ser 148 | .dst 149 | .write_to_offset_u32(self.prop_token_offset - 4, FDT_NOP); 150 | } else { 151 | self.ser.dst.write_to_offset_u32( 152 | self.prop_token_offset, 153 | (self.ser.dst.get_offset() - self.prop_token_offset - 8) as u32, 154 | ); 155 | self.ser.dst.write_to_offset_u32( 156 | self.prop_token_offset + 4, 157 | self.ser.string_block.find_or_insert(self.current_name) as u32, 158 | ); 159 | } 160 | 161 | self.ser.dst.step_align(); 162 | 163 | self.ser.patch_list.step_back(self.current_dep); 164 | 165 | Ok(()) 166 | } 167 | fn serialize_dynamic_field<T>(&mut self, key: &'se str, value: &T) -> Result<(), Error> 168 | where 169 | T: serde::ser::Serialize + ?Sized, 170 | { 171 | self.serialize_field_meta(key)?; 172 | self.serialize_field_data(value)?; 173 | Ok(()) 174 | } 175 | } 176 | 177 | impl serde::ser::SerializeMap for Serializer<'_, '_> { 178 | type Ok = (ValueType, usize); 179 | type Error = Error; 180 | fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error> 181 | where 182 | K: ?Sized + serde::ser::Serialize, 183 | V: ?Sized + serde::ser::Serialize, 184 | { 185 | if core::any::type_name::<K>() != "str" { 186 | panic!( 187 | "map key must be a str, but here is {}", 188 | core::any::type_name::<K>() 189 | ); 190 | } 191 | let key = unsafe { *(core::ptr::addr_of!(key) as *const &str) }; 192 | let mut ser = self.get_next_ref(); 193 | ser.serialize_field_meta(key)?; 194 | ser.serialize_field_data(value)?; 195 | Ok(()) 196 | } 197 | 198 | fn serialize_key<T>(&mut self, _input: &T) -> Result<(), Self::Error> 199 | where 200 | T: serde::ser::Serialize + ?Sized, 201 | { 202 | todo!("only support serialize_entry") 203 | } 204 | 205 | fn serialize_value<T>(&mut self, _value: &T) -> Result<(), Self::Error> 206 | where 207 | T: serde::ser::Serialize + ?Sized, 208 | { 209 | todo!("only support serialize_entry") 210 | } 211 | 212 | fn end(mut self) -> Result<Self::Ok, Self::Error> { 213 | self.end_node()?; 214 | Ok((ValueType::Node, self.ser.dst.get_offset())) 215 | } 216 | } 217 | 218 | impl serde::ser::SerializeStruct for Serializer<'_, '_> { 219 | type Ok = (ValueType, usize); 220 | type Error = Error; 221 | 222 | fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> 223 | where 224 | T: serde::ser::Serialize + ?Sized, 225 | { 226 | let mut ser = self.get_next_ref(); 227 | ser.serialize_dynamic_field(key, value)?; 228 | 229 | Ok(()) 230 | } 231 | 232 | fn end(mut self) -> Result<Self::Ok, Self::Error> { 233 | self.end_node()?; 234 | Ok((ValueType::Node, self.ser.dst.get_offset())) 235 | } 236 | } 237 | 238 | impl serde::ser::SerializeStructVariant for Serializer<'_, '_> { 239 | type Ok = (ValueType, usize); 240 | type Error = Error; 241 | 242 | fn serialize_field<T>(&mut self, _key: &'static str, _value: &T) -> Result<(), Self::Error> 243 | where 244 | T: serde::ser::Serialize + ?Sized, 245 | { 246 | todo!("struct_field"); 247 | } 248 | 249 | fn end(self) -> Result<Self::Ok, Self::Error> { 250 | todo!("struct_end"); 251 | } 252 | } 253 | 254 | impl serde::ser::SerializeSeq for Serializer<'_, '_> { 255 | type Ok = (ValueType, usize); 256 | type Error = Error; 257 | // TODO: make sure there are no node seq serialize over this function. 258 | fn serialize_element<T>(&mut self, value: &T) -> Result<(), Error> 259 | where 260 | T: ?Sized + serde::ser::Serialize, 261 | { 262 | value.serialize(self.get_next_ref())?; 263 | Ok(()) 264 | } 265 | 266 | fn end(self) -> Result<Self::Ok, Error> { 267 | // We think all seq we met is a prop. 268 | Ok((ValueType::Prop, self.ser.dst.get_offset())) 269 | } 270 | } 271 | 272 | impl serde::ser::SerializeTuple for Serializer<'_, '_> { 273 | type Ok = (ValueType, usize); 274 | type Error = Error; 275 | 276 | fn serialize_element<T>(&mut self, value: &T) -> Result<(), Error> 277 | where 278 | T: ?Sized + serde::ser::Serialize, 279 | { 280 | value.serialize(self.get_next_ref())?; 281 | Ok(()) 282 | } 283 | 284 | fn end(self) -> Result<Self::Ok, Error> { 285 | Ok((ValueType::Prop, self.ser.dst.get_offset())) 286 | } 287 | } 288 | 289 | impl serde::ser::SerializeTupleVariant for Serializer<'_, '_> { 290 | type Ok = (ValueType, usize); 291 | type Error = Error; 292 | 293 | fn serialize_field<T>(&mut self, _value: &T) -> Result<(), Self::Error> 294 | where 295 | T: serde::ser::Serialize + ?Sized, 296 | { 297 | todo!("tuple_variant_field"); 298 | } 299 | 300 | fn end(self) -> Result<Self::Ok, Error> { 301 | todo!("tuple_variant_end"); 302 | } 303 | } 304 | 305 | impl serde::ser::SerializeTupleStruct for Serializer<'_, '_> { 306 | type Ok = (ValueType, usize); 307 | type Error = Error; 308 | 309 | fn serialize_field<T>(&mut self, _value: &T) -> Result<(), Self::Error> 310 | where 311 | T: serde::ser::Serialize + ?Sized, 312 | { 313 | todo!("tuple_struct_field"); 314 | } 315 | 316 | fn end(self) -> Result<Self::Ok, Error> { 317 | todo!("tuple_struct_end"); 318 | } 319 | } 320 | 321 | impl<'se> serde::ser::Serializer for Serializer<'_, 'se> { 322 | type Ok = (ValueType, usize); 323 | type Error = Error; 324 | type SerializeSeq = Self; 325 | type SerializeMap = Self; 326 | type SerializeStruct = Self; 327 | type SerializeTuple = Self; 328 | type SerializeTupleStruct = Self; 329 | type SerializeTupleVariant = Self; 330 | type SerializeStructVariant = Self; 331 | 332 | fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> { 333 | todo!("bool"); 334 | } 335 | 336 | fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> { 337 | todo!("i8"); 338 | } 339 | 340 | fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> { 341 | todo!("i16"); 342 | } 343 | 344 | fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> { 345 | todo!("i32"); 346 | } 347 | 348 | fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> { 349 | todo!("i64"); 350 | } 351 | 352 | fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> { 353 | todo!("u8"); 354 | } 355 | 356 | fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> { 357 | todo!("u16"); 358 | } 359 | 360 | fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> { 361 | self.ser.dst.step_by_u32(v); 362 | Ok((ValueType::Prop, self.ser.dst.get_offset())) 363 | } 364 | 365 | fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> { 366 | todo!("u64"); 367 | } 368 | 369 | fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> { 370 | todo!("f32"); 371 | } 372 | 373 | fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> { 374 | todo!("f64"); 375 | } 376 | 377 | fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> { 378 | todo!("char"); 379 | } 380 | 381 | fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> { 382 | v.bytes().for_each(|x| { 383 | self.ser.dst.step_by_u8(x); 384 | }); 385 | self.ser.dst.step_by_u8(0); 386 | Ok((ValueType::Prop, self.ser.dst.get_offset())) 387 | } 388 | 389 | fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> { 390 | v.iter().for_each(|x| self.ser.dst.step_by_u8(*x)); 391 | Ok((ValueType::Prop, self.ser.dst.get_offset())) 392 | } 393 | 394 | fn serialize_none(self) -> Result<Self::Ok, Self::Error> { 395 | todo!("none"); 396 | } 397 | 398 | fn serialize_some<T>(self, _v: &T) -> Result<Self::Ok, Self::Error> 399 | where 400 | T: serde::ser::Serialize + ?Sized, 401 | { 402 | todo!("some"); 403 | } 404 | 405 | fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { 406 | todo!("unit"); 407 | } 408 | 409 | fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { 410 | todo!("unit struct"); 411 | } 412 | 413 | fn serialize_unit_variant( 414 | self, 415 | _name: &'static str, 416 | _variant_index: u32, 417 | _variant: &'static str, 418 | ) -> Result<Self::Ok, Self::Error> { 419 | todo!("unit struct variant"); 420 | } 421 | 422 | fn serialize_newtype_struct<T>(self, name: &'static str, v: &T) -> Result<Self::Ok, Self::Error> 423 | where 424 | T: serde::ser::Serialize + ?Sized, 425 | { 426 | use crate::de_mut::node::{Node, NodeItem}; 427 | use crate::de_mut::{NODE_NAME, NODE_NODE_ITEM_NAME}; 428 | use core::ptr::addr_of; 429 | match name { 430 | NODE_NODE_ITEM_NAME => { 431 | let v = unsafe { &*(addr_of!(v) as *const &NodeItem<'se>) }; 432 | self.serialize_newtype_struct(NODE_NAME, &v.deserialize::<Node>()) 433 | } 434 | _ => todo!(), 435 | } 436 | } 437 | 438 | fn serialize_newtype_variant<T>( 439 | self, 440 | _name: &'static str, 441 | _variant_index: u32, 442 | _variant: &'static str, 443 | _value: &T, 444 | ) -> Result<Self::Ok, Self::Error> 445 | where 446 | T: serde::ser::Serialize + ?Sized, 447 | { 448 | todo!("newtype struct variant"); 449 | } 450 | 451 | fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { 452 | Ok(self) 453 | } 454 | 455 | fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> { 456 | self.serialize_seq(Some(len)) 457 | } 458 | 459 | fn serialize_tuple_struct( 460 | self, 461 | _name: &'static str, 462 | _len: usize, 463 | ) -> Result<Self::SerializeTupleStruct, Self::Error> { 464 | todo!("tuple struct"); 465 | } 466 | 467 | fn serialize_tuple_variant( 468 | self, 469 | _name: &'static str, 470 | _variant_index: u32, 471 | _variant: &'static str, 472 | _len: usize, 473 | ) -> Result<Self::SerializeTupleVariant, Self::Error> { 474 | todo!("tuple variant"); 475 | } 476 | 477 | fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { 478 | let mut ser = self.get_next(); 479 | ser.start_node()?; 480 | Ok(ser) 481 | } 482 | 483 | fn serialize_struct( 484 | self, 485 | _name: &'static str, 486 | _len: usize, 487 | ) -> Result<Self::SerializeStruct, Self::Error> { 488 | let mut ser = self.get_next(); 489 | ser.start_node()?; 490 | Ok(ser) 491 | } 492 | 493 | fn serialize_struct_variant( 494 | self, 495 | _name: &'static str, 496 | _variant_index: u32, 497 | _variant: &'static str, 498 | _len: usize, 499 | ) -> Result<Self::SerializeStructVariant, Self::Error> { 500 | todo!("struct variant"); 501 | } 502 | 503 | #[cfg(not(feature = "std"))] 504 | fn collect_str<T>(self, _value: &T) -> Result<Self::Ok, Self::Error> 505 | where 506 | T: ?Sized + core::fmt::Display, 507 | { 508 | todo!() 509 | } 510 | } 511 | 512 | #[cfg(test)] 513 | mod tests { 514 | use serde::Serialize; 515 | const MAX_SIZE: usize = 256 + 32; 516 | #[test] 517 | fn base_ser_test() { 518 | #[derive(Serialize)] 519 | struct Base { 520 | pub hello: u32, 521 | } 522 | let mut buf1 = [0u8; MAX_SIZE]; 523 | 524 | { 525 | let base = Base { hello: 0xdeedbeef }; 526 | crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); 527 | } 528 | // TODO: check buf1 buf2 529 | } 530 | #[test] 531 | fn rev_ser_test() { 532 | #[derive(Serialize)] 533 | struct Base { 534 | pub hello: u32, 535 | pub base1: Base1, 536 | } 537 | #[derive(Serialize)] 538 | struct Base1 { 539 | pub hello: u32, 540 | } 541 | let mut buf1 = [0u8; MAX_SIZE]; 542 | 543 | { 544 | let base = Base { 545 | hello: 0xdeedbeef, 546 | base1: Base1 { hello: 0x10000001 }, 547 | }; 548 | crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); 549 | } 550 | // TODO: check buf1 buf2 551 | // println!("{:x?} {:x?}", buf1, buf2); 552 | // assert!(false); 553 | } 554 | #[test] 555 | fn rev_str_ser_test() { 556 | #[derive(Serialize)] 557 | struct Base { 558 | pub hello: u32, 559 | pub base1: Base1, 560 | } 561 | #[derive(Serialize)] 562 | struct Base1 { 563 | pub hello: &'static str, 564 | } 565 | let mut buf1 = [0u8; MAX_SIZE]; 566 | 567 | { 568 | let base = Base { 569 | hello: 0xdeedbeef, 570 | base1: Base1 { 571 | hello: "Hello, World!", 572 | }, 573 | }; 574 | crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); 575 | } 576 | // TODO: check buf1 buf2 577 | // println!("{:x?} {:x?}", buf1, buf2); 578 | // assert!(false); 579 | } 580 | #[test] 581 | fn seq_str_ser_test() { 582 | #[derive(Serialize)] 583 | struct Base { 584 | pub hello: u32, 585 | pub base1: [&'static str; 3], 586 | } 587 | let mut buf1 = [0u8; MAX_SIZE]; 588 | 589 | { 590 | let base = Base { 591 | hello: 0xdeedbeef, 592 | base1: ["Hello", "World!", "Again"], 593 | }; 594 | crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); 595 | } 596 | // TODO: check buf1 buf2 597 | // println!("{:x?} {:x?}", buf1, buf2); 598 | // assert!(false); 599 | } 600 | #[test] 601 | fn node_prop_ser_test() { 602 | #[derive(Serialize)] 603 | struct Base { 604 | pub hello: u32, 605 | pub base1: Base1, 606 | pub hello2: u32, 607 | pub base2: Base1, 608 | } 609 | #[derive(Serialize)] 610 | struct Base1 { 611 | pub hello: &'static str, 612 | } 613 | let mut buf1 = [0u8; MAX_SIZE]; 614 | 615 | { 616 | let base = Base { 617 | hello: 0xdeedbeef, 618 | base1: Base1 { 619 | hello: "Hello, World!", 620 | }, 621 | hello2: 0x11223344, 622 | base2: Base1 { hello: "Roger" }, 623 | }; 624 | crate::ser::to_dtb(&base, &[], &mut buf1).unwrap(); 625 | } 626 | // TODO: check buf1 buf2 627 | // println!("{:x?} {:x?}", buf1, buf2); 628 | // assert!(false); 629 | } 630 | #[test] 631 | fn replace_prop_ser_test() { 632 | #[derive(Serialize)] 633 | struct Base { 634 | pub hello: u32, 635 | pub base1: Base1, 636 | pub hello2: u32, 637 | pub base2: Base1, 638 | } 639 | #[derive(Serialize)] 640 | struct Base1 { 641 | pub hello: &'static str, 642 | } 643 | let mut buf1 = [0u8; MAX_SIZE]; 644 | 645 | { 646 | let number = 0x55667788u32; 647 | let patch = crate::ser::patch::Patch::new( 648 | "/hello", 649 | &number as _, 650 | crate::ser::serializer::ValueType::Prop, 651 | ); 652 | let list = [patch]; 653 | let base = Base { 654 | hello: 0xdeedbeef, 655 | base1: Base1 { 656 | hello: "Hello, World!", 657 | }, 658 | hello2: 0x11223344, 659 | base2: Base1 { hello: "Roger" }, 660 | }; 661 | crate::ser::to_dtb(&base, &list, &mut buf1).unwrap(); 662 | } 663 | // TODO: check buf1 buf2 664 | // println!("{:x?} {:x?}", buf1, buf2); 665 | // assert!(false); 666 | } 667 | #[test] 668 | fn replace_node_ser_test() { 669 | #[derive(Serialize)] 670 | struct Base { 671 | pub hello: u32, 672 | pub base1: Base1, 673 | pub hello2: u32, 674 | pub base2: Base1, 675 | } 676 | #[derive(Serialize)] 677 | struct Base1 { 678 | pub hello: &'static str, 679 | } 680 | let mut buf1 = [0u8; MAX_SIZE]; 681 | 682 | { 683 | let new_base = Base1 { 684 | hello: "replacement", 685 | }; 686 | let patch = crate::ser::patch::Patch::new( 687 | "/hello", 688 | &new_base as _, 689 | crate::ser::serializer::ValueType::Node, 690 | ); 691 | let list = [patch]; 692 | let base = Base { 693 | hello: 0xdeedbeef, 694 | base1: Base1 { 695 | hello: "Hello, World!", 696 | }, 697 | hello2: 0x11223344, 698 | base2: Base1 { hello: "Roger" }, 699 | }; 700 | crate::ser::to_dtb(&base, &list, &mut buf1).unwrap(); 701 | } 702 | // TODO: check buf1 buf2 703 | // println!("{:x?} {:x?}", buf1, buf2); 704 | // assert!(false); 705 | } 706 | #[test] 707 | fn add_node_ser_test() { 708 | #[derive(Serialize)] 709 | struct Base { 710 | pub hello: u32, 711 | pub base1: Base1, 712 | pub hello2: u32, 713 | pub base2: Base1, 714 | } 715 | #[derive(Serialize)] 716 | struct Base1 { 717 | pub hello: &'static str, 718 | } 719 | let mut buf1 = [0u8; MAX_SIZE]; 720 | 721 | { 722 | let new_base = Base1 { hello: "added" }; 723 | let patch = crate::ser::patch::Patch::new( 724 | "/base3", 725 | &new_base as _, 726 | crate::ser::serializer::ValueType::Node, 727 | ); 728 | let list = [patch]; 729 | let base = Base { 730 | hello: 0xdeedbeef, 731 | base1: Base1 { 732 | hello: "Hello, World!", 733 | }, 734 | hello2: 0x11223344, 735 | base2: Base1 { hello: "Roger" }, 736 | }; 737 | crate::ser::to_dtb(&base, &list, &mut buf1).unwrap(); 738 | } 739 | // TODO: check buf1 buf2 740 | // println!("{:x?}", buf1); 741 | // assert!(false); 742 | } 743 | } 744 | -------------------------------------------------------------------------------- /src/ser/string_block.rs: -------------------------------------------------------------------------------- 1 | /// StringBlock 2 | /// As spec said, dtb have a block called string block for saving prop names. 3 | pub struct StringBlock<'se> { 4 | end: &'se mut usize, 5 | data: &'se mut [u8], 6 | } 7 | 8 | impl<'se> StringBlock<'se> { 9 | /// Make a new string block. 10 | /// 11 | /// For get how long is string block, we make `end` as a mut ref. 12 | #[inline(always)] 13 | pub fn new(dst: &'se mut [u8], end: &'se mut usize) -> StringBlock<'se> { 14 | StringBlock { data: dst, end } 15 | } 16 | 17 | // TODO: show as error 18 | /// Assume the passing `offset` is the start of a string, and return this string. 19 | /// Return (Result String, End Offset). 20 | /// 21 | /// Will panic when len > end. 22 | #[inline(always)] 23 | pub fn get_str_by_offset(&self, offset: usize) -> (&str, usize) { 24 | if offset > *self.end { 25 | panic!("invalid read"); 26 | } 27 | let current_slice = &self.data[offset..]; 28 | let pos = current_slice 29 | .iter() 30 | .position(|&x| x == b'\0') 31 | .unwrap_or(self.data.len()); 32 | let (a, _) = current_slice.split_at(pos + 1); 33 | let result = unsafe { core::str::from_utf8_unchecked(&a[..a.len() - 1]) }; 34 | (result, pos + offset + 1) 35 | } 36 | 37 | #[inline(always)] 38 | fn insert_u8(&mut self, data: u8) { 39 | self.data[*self.end] = data; 40 | *self.end += 1; 41 | } 42 | 43 | /// Return the start offset of inserted string. 44 | #[inline(always)] 45 | pub fn insert_str(&mut self, name: &str) -> usize { 46 | let result = *self.end; 47 | name.bytes().for_each(|x| { 48 | self.insert_u8(x); 49 | }); 50 | self.insert_u8(0); 51 | result 52 | } 53 | 54 | /// Find a string. If not found, insert it. 55 | #[inline(always)] 56 | pub fn find_or_insert(&mut self, name: &str) -> usize { 57 | let mut current_pos = 0; 58 | while current_pos < *self.end { 59 | let (result, new_pos) = self.get_str_by_offset(current_pos); 60 | if result == name { 61 | return current_pos; 62 | } 63 | current_pos = new_pos; 64 | } 65 | 66 | self.insert_str(name) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/tag.rs: -------------------------------------------------------------------------------- 1 | use crate::common::{FDT_BEGIN_NODE, FDT_END, FDT_END_NODE, FDT_NOP, FDT_PROP}; 2 | use crate::error::{Error, Result}; 3 | 4 | #[derive(Debug, Clone)] 5 | pub struct Tags<'a> { 6 | structure: &'a [u8], 7 | string_table: &'a [u8], 8 | cur: usize, 9 | offset_from_file_begin: usize, 10 | } 11 | 12 | impl<'a> Tags<'a> { 13 | pub fn new(structure: &'a [u8], string_table: &'a [u8], offset_from_file_begin: usize) -> Self { 14 | Tags { 15 | structure, 16 | string_table, 17 | cur: 0, 18 | offset_from_file_begin, 19 | } 20 | } 21 | } 22 | 23 | #[inline] 24 | fn align_up_u32(val: usize) -> usize { 25 | val + (4 - (val % 4)) % 4 26 | } 27 | 28 | impl<'a> Tags<'a> { 29 | #[inline] 30 | fn file_index(&self) -> usize { 31 | self.cur + self.offset_from_file_begin 32 | } 33 | #[inline] 34 | fn read_cur_u32(&mut self) -> Result<u32> { 35 | if self.cur >= (u32::MAX - 4) as usize { 36 | return Err(Error::u32_index_space_overflow( 37 | self.cur as u32, 38 | self.file_index(), 39 | )); 40 | } 41 | let ans = u32::from_be_bytes([ 42 | self.structure[self.cur], 43 | self.structure[self.cur + 1], 44 | self.structure[self.cur + 2], 45 | self.structure[self.cur + 3], 46 | ]); 47 | self.cur += 4; 48 | Ok(ans) 49 | } 50 | #[inline] 51 | fn read_string0_align(&mut self) -> Result<&'a [u8]> { 52 | let begin = self.cur; 53 | while self.cur < self.structure.len() { 54 | if self.structure[self.cur] == b'\0' { 55 | let end = self.cur; 56 | self.cur = align_up_u32(end + 1); 57 | return Ok(&self.structure[begin..end]); 58 | } 59 | self.cur += 1; 60 | } 61 | Err(Error::string_eof_unpexpected(self.file_index())) 62 | } 63 | #[inline] 64 | fn read_slice_align(&mut self, len: u32) -> Result<&'a [u8]> { 65 | let begin = self.cur; 66 | let end = self.cur + len as usize; 67 | if end > self.structure.len() { 68 | let remaining_length = self.structure.len() as u32 - begin as u32; 69 | return Err(Error::slice_eof_unpexpected( 70 | len, 71 | remaining_length, 72 | self.file_index(), 73 | )); 74 | } 75 | self.cur = align_up_u32(end); 76 | Ok(&self.structure[begin..end]) 77 | } 78 | #[inline] 79 | fn read_table_string(&mut self, pos: u32) -> Result<&'a [u8]> { 80 | let begin = pos as usize; 81 | if begin >= self.string_table.len() { 82 | let bound_offset = self.string_table.len() as u32; 83 | return Err(Error::table_string_offset( 84 | pos, 85 | bound_offset, 86 | self.file_index(), 87 | )); 88 | } 89 | let mut cur = begin; 90 | while cur < self.string_table.len() { 91 | if self.string_table[cur] == b'\0' { 92 | return Ok(&self.string_table[begin..cur]); 93 | } 94 | cur += 1; 95 | } 96 | Err(Error::table_string_offset( 97 | pos, 98 | cur as u32, 99 | self.file_index(), 100 | )) 101 | } 102 | // caller must ensure in FDT_PROP context. returns (val, prop_name). 103 | #[inline] 104 | fn read_tag_prop(&mut self) -> Result<(&'a [u8], &'a [u8])> { 105 | let val_size = self.read_cur_u32()?; 106 | let name_offset = self.read_cur_u32()?; 107 | // get value slice 108 | let val = self.read_slice_align(val_size)?; 109 | // lookup name in strings table 110 | let prop_name = self.read_table_string(name_offset)?; 111 | Ok((val, prop_name)) 112 | } 113 | } 114 | 115 | impl<'a> Iterator for Tags<'a> { 116 | type Item = Result<(Tag<'a>, usize)>; // Tag, byte index from file begin 117 | fn next(&mut self) -> Option<Self::Item> { 118 | if self.cur > self.structure.len() - core::mem::size_of::<u32>() { 119 | return Some(Err(Error::tag_eof_unexpected( 120 | self.cur as u32, 121 | self.structure.len() as u32, 122 | self.file_index(), 123 | ))); 124 | } 125 | let ans = loop { 126 | match self.read_cur_u32() { 127 | // begin of structure tag 128 | Ok(FDT_BEGIN_NODE) => break self.read_string0_align().map(Tag::Begin), 129 | Ok(FDT_PROP) => break self.read_tag_prop().map(|(a, b)| Tag::Prop(a, b)), 130 | Ok(FDT_END_NODE) => break Ok(Tag::End), 131 | Ok(FDT_NOP) => self.cur += 4, 132 | Ok(FDT_END) => return None, 133 | Ok(invalid) => break Err(Error::invalid_tag_id(invalid, self.file_index())), 134 | Err(e) => break Err(e), 135 | } 136 | }; 137 | match ans { 138 | Ok(tag) => Some(Ok((tag, self.file_index()))), 139 | Err(e) => Some(Err(e)), 140 | } 141 | } 142 | } 143 | 144 | #[derive(Clone, Copy, Debug)] 145 | pub enum Tag<'a> { 146 | Begin(&'a [u8]), 147 | Prop(&'a [u8], &'a [u8]), 148 | End, 149 | } 150 | -------------------------------------------------------------------------------- /src/utils/chosen.rs: -------------------------------------------------------------------------------- 1 | use crate::buildin::{Node, StrSeq}; 2 | 3 | impl<'de> Node<'de> { 4 | /// Get node /chosen 5 | #[inline] 6 | pub fn chosen<'b>(&'b self) -> Option<Node<'de>> { 7 | self.find("/chosen") 8 | } 9 | /// Get /chosen/stdin-path 10 | pub fn chosen_stdin_path(&self) -> Option<&'de str> { 11 | let result = self 12 | .chosen()? 13 | .get_prop("stdin-path")? 14 | .deserialize::<StrSeq>() 15 | .iter() 16 | .next()?; 17 | if let Some(pos) = result.find(':') { 18 | Some(result.split_at(pos).0) 19 | } else { 20 | Some(result) 21 | } 22 | } 23 | /// Get /chosen/stdout-path 24 | pub fn chosen_stdout_path(&self) -> Option<&'de str> { 25 | let result = self 26 | .chosen()? 27 | .get_prop("stdout-path")? 28 | .deserialize::<StrSeq>() 29 | .iter() 30 | .next()?; 31 | if let Some(pos) = result.find(':') { 32 | Some(result.split_at(pos).0) 33 | } else { 34 | Some(result) 35 | } 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; 42 | 43 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/bl808.dtb"); 44 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 45 | #[test] 46 | fn test_chosen_stdout() { 47 | #[repr(align(8))] 48 | struct AlignedBuffer { 49 | pub data: [u8; RAW_DEVICE_TREE.len()], 50 | } 51 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 52 | data: [0; BUFFER_SIZE], 53 | }); 54 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 55 | let mut slice = aligned_data.data.to_vec(); 56 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); 57 | let dtb = Dtb::from(ptr).share(); 58 | 59 | let node: Node = from_raw_mut(&dtb).unwrap(); 60 | assert!(node.chosen().is_some()); 61 | assert_eq!(node.chosen_stdout_path(), Some("serial3")); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod chosen; 2 | 3 | use crate::buildin::{Node, StrSeq}; 4 | 5 | impl<'de> Node<'de> { 6 | /// Try to get a node by a full-path. 7 | fn raw_find<'b>(&'b self, path: &str) -> Option<Node<'de>> { 8 | // Direct return root node 9 | let mut current_node = Some(self.clone()); 10 | if path == "/" { 11 | return current_node; 12 | } 13 | let (root, path) = path.split_at(1); 14 | if root != "/" { 15 | return None; 16 | } 17 | // Split path with / and find each level 18 | for current_name in path.split('/') { 19 | let node = match current_node.clone() { 20 | Some(node) => node, 21 | None => break, 22 | }; 23 | let next_node_iter = node.nodes().find(|x| x.get_full_name() == current_name); 24 | match next_node_iter { 25 | None => current_node = None, 26 | Some(iter) => { 27 | let next_node = iter.deserialize::<Node>(); 28 | current_node = Some(next_node); 29 | } 30 | } 31 | } 32 | current_node 33 | } 34 | /// Try to get a node by path. 35 | pub fn find<'b>(&'b self, path: &str) -> Option<Node<'de>> { 36 | // Direct return root node 37 | let current_node = Some(self.clone()); 38 | if path == "/" { 39 | return current_node; 40 | } 41 | let (root, _) = path.split_at(1); 42 | if root != "/" { 43 | // Path name does not start with `/`, Check if the aliases. 44 | if let Some(aliases) = self.raw_find("/aliases") { 45 | if let Some(full_path) = aliases.get_prop(path) { 46 | // As spec 3.3 said, this prop value should be one string, 47 | // which is a full path ref to a node. 48 | let full_path = full_path.deserialize::<StrSeq>(); 49 | return self.raw_find(full_path.iter().next().unwrap()); 50 | } 51 | } 52 | return None; 53 | } 54 | self.raw_find(path) 55 | } 56 | 57 | /// use depth-first search to traversal the tree, and exec func for each node 58 | pub fn search<F>(&self, func: &mut F) 59 | where 60 | F: FnMut(&Node), 61 | { 62 | func(self); 63 | for node in self.nodes() { 64 | let node = node.deserialize::<Node>(); 65 | node.search(func); 66 | } 67 | } 68 | } 69 | 70 | #[cfg(test)] 71 | mod tests { 72 | use crate::{ 73 | Dtb, DtbPtr, 74 | buildin::{Node, StrSeq}, 75 | from_raw_mut, 76 | }; 77 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/hifive-unmatched-a00.dtb"); 78 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 79 | 80 | const RAW_DEVICE_TREE_WITH_ALIASES: &[u8] = 81 | include_bytes!("../../examples/cv1812cp_milkv_duo256m_sd.dtb"); 82 | const BUFFER_SIZE_WITH_ALIASES: usize = RAW_DEVICE_TREE_WITH_ALIASES.len(); 83 | #[test] 84 | fn test_search() { 85 | #[repr(align(8))] 86 | struct AlignedBuffer { 87 | pub data: [u8; RAW_DEVICE_TREE.len()], 88 | } 89 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 90 | data: [0; BUFFER_SIZE], 91 | }); 92 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 93 | let mut slice = aligned_data.data.to_vec(); 94 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); 95 | let dtb = Dtb::from(ptr).share(); 96 | 97 | let node: Node = from_raw_mut(&dtb).unwrap(); 98 | let mut count = 0; 99 | let mut closure = |_node: &Node| count += 1; 100 | node.search(&mut closure); 101 | assert_eq!(count, 70); 102 | } 103 | #[test] 104 | fn test_find() { 105 | #[repr(align(8))] 106 | struct AlignedBuffer { 107 | pub data: [u8; RAW_DEVICE_TREE_WITH_ALIASES.len()], 108 | } 109 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 110 | data: [0; BUFFER_SIZE_WITH_ALIASES], 111 | }); 112 | aligned_data.data[..BUFFER_SIZE_WITH_ALIASES] 113 | .clone_from_slice(RAW_DEVICE_TREE_WITH_ALIASES); 114 | let mut slice = aligned_data.data.to_vec(); 115 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); 116 | let dtb = Dtb::from(ptr).share(); 117 | 118 | let node: Node = from_raw_mut(&dtb).unwrap(); 119 | let chosen = node.find("/chosen").unwrap(); 120 | let result = chosen.props().find(|prop| prop.get_name() == "stdout-path"); 121 | match result { 122 | Some(iter) => { 123 | let stdout_path = String::from(iter.deserialize::<StrSeq>().iter().next().unwrap()); 124 | if stdout_path != "serial0" { 125 | panic!("wrong /chosen/stdout-path value"); 126 | } 127 | match node.find(&stdout_path) { 128 | Some(_) => (), 129 | None => panic!("unable to find stdout-path node."), 130 | } 131 | } 132 | None => panic!("failed to find /chosen/stdout-path"), 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/value/compatible.rs: -------------------------------------------------------------------------------- 1 | use core::{fmt, marker::PhantomData}; 2 | use serde::{Deserialize, de::Visitor}; 3 | 4 | /// Field representing compatability of a certain device in the tree. 5 | /// 6 | /// This structure is represented in a list of string that is separated with Unicode `NUL` character. 7 | pub struct Compatible<'a> { 8 | data: &'a [u8], 9 | } 10 | 11 | impl<'a> Compatible<'a> { 12 | pub fn iter(&self) -> Iter<'a> { 13 | Iter { 14 | remaining: self.data, 15 | } 16 | } 17 | } 18 | 19 | impl<'de: 'a, 'a> Deserialize<'de> for Compatible<'a> { 20 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 21 | where 22 | D: serde::Deserializer<'de>, 23 | { 24 | struct StrListVisitor<'de, 'a>(PhantomData<&'de ()>, PhantomData<Compatible<'a>>); 25 | impl<'de: 'a, 'a> Visitor<'de> for StrListVisitor<'de, 'a> { 26 | type Value = Compatible<'a>; 27 | 28 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 29 | write!(formatter, "string list") 30 | } 31 | 32 | fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E> 33 | where 34 | E: serde::de::Error, 35 | { 36 | // no UTF-8 checks 37 | Ok(Compatible { data: v }) 38 | } 39 | } 40 | deserializer.deserialize_bytes(StrListVisitor(PhantomData, PhantomData)) 41 | } 42 | } 43 | 44 | impl fmt::Debug for Compatible<'_> { 45 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 46 | let mut list = f.debug_list(); 47 | for slice in self.iter() { 48 | match core::str::from_utf8(slice) { 49 | Ok(string) => list.entry(&string), 50 | Err(_error) => list.entry(&slice), 51 | }; 52 | } 53 | list.finish() 54 | } 55 | } 56 | 57 | pub struct Iter<'a> { 58 | remaining: &'a [u8], 59 | } 60 | 61 | impl<'a> Iterator for Iter<'a> { 62 | type Item = &'a [u8]; 63 | 64 | fn next(&mut self) -> Option<Self::Item> { 65 | if self.remaining.is_empty() { 66 | return None; 67 | } 68 | let mut idx = 0; 69 | while let Some(byte) = self.remaining.get(idx) { 70 | if byte == &b'\0' { 71 | break; 72 | } 73 | idx += 1; 74 | } 75 | let (ans, rest) = self.remaining.split_at(idx); 76 | if let [0, ..] = rest { 77 | // skip '\0' 78 | self.remaining = &rest[1..]; 79 | } 80 | Some(ans) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/value/cpu.rs: -------------------------------------------------------------------------------- 1 | // /// ISA independent processor description. 2 | // pub struct CpuMut<'a> { 3 | // memory: &'a mut [u8], 4 | // } 5 | -------------------------------------------------------------------------------- /src/value/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod compatible; 2 | pub mod cpu; 3 | pub mod riscv_pmu; 4 | mod tree; 5 | -------------------------------------------------------------------------------- /src/value/riscv_pmu.rs: -------------------------------------------------------------------------------- 1 | /// This module implement prop value described in 2 | /// https://www.kernel.org/doc/Documentation/devicetree/bindings/perf/riscv%2Cpmu.yaml 3 | use crate::buildin::*; 4 | 5 | use serde::{Deserialize, Serialize}; 6 | 7 | use core::ops::RangeInclusive; 8 | 9 | #[repr(transparent)] 10 | #[derive(Deserialize, Serialize)] 11 | #[serde(transparent)] 12 | pub struct EventToMhpmevent<'a>(Matrix<'a, 3>); 13 | 14 | #[repr(transparent)] 15 | #[derive(Deserialize, Serialize)] 16 | #[serde(transparent)] 17 | pub struct EventToMhpmcounters<'a>(Matrix<'a, 3>); 18 | 19 | #[repr(transparent)] 20 | #[derive(Deserialize, Serialize)] 21 | #[serde(transparent)] 22 | pub struct RawEventToMhpcounters<'a>(Matrix<'a, 5>); 23 | 24 | impl EventToMhpmevent<'_> { 25 | #[inline(always)] 26 | pub fn len(&self) -> usize { 27 | self.0.len() 28 | } 29 | 30 | #[inline(always)] 31 | pub fn is_empty(&self) -> bool { 32 | self.0.is_empty() 33 | } 34 | 35 | #[inline(always)] 36 | pub fn get_event_id(&self, i: usize) -> u32 { 37 | u32::from_be(self.0.get(i)[0]) 38 | } 39 | 40 | #[inline(always)] 41 | pub fn get_selector_value(&self, i: usize) -> u64 { 42 | let current = self.0.get(i); 43 | ((u32::from_be(current[1]) as u64) << 32) | (u32::from_be(current[2]) as u64) 44 | } 45 | } 46 | 47 | impl EventToMhpmcounters<'_> { 48 | #[inline(always)] 49 | pub fn len(&self) -> usize { 50 | self.0.len() 51 | } 52 | 53 | #[inline(always)] 54 | pub fn is_empty(&self) -> bool { 55 | self.0.is_empty() 56 | } 57 | 58 | #[inline(always)] 59 | pub fn get_event_idx_range(&self, i: usize) -> RangeInclusive<u32> { 60 | let current = self.0.get(i); 61 | u32::from_be(current[0])..=u32::from_be(current[1]) 62 | } 63 | 64 | #[inline(always)] 65 | pub fn get_counter_bitmap(&self, i: usize) -> u32 { 66 | let current = self.0.get(i); 67 | u32::from_be(current[2]) 68 | } 69 | } 70 | 71 | impl RawEventToMhpcounters<'_> { 72 | #[inline(always)] 73 | pub fn len(&self) -> usize { 74 | self.0.len() 75 | } 76 | 77 | #[inline(always)] 78 | pub fn is_empty(&self) -> bool { 79 | self.0.is_empty() 80 | } 81 | 82 | #[inline(always)] 83 | pub fn get_event_idx_base(&self, i: usize) -> u64 { 84 | let current = self.0.get(i); 85 | ((u32::from_be(current[0]) as u64) << 32) | (u32::from_be(current[1]) as u64) 86 | } 87 | 88 | #[inline(always)] 89 | pub fn get_event_idx_mask(&self, i: usize) -> u64 { 90 | let current = self.0.get(i); 91 | ((u32::from_be(current[2]) as u64) << 32) | (u32::from_be(current[3]) as u64) 92 | } 93 | 94 | #[inline(always)] 95 | pub fn get_counter_bitmap(&self, i: usize) -> u32 { 96 | let current = self.0.get(i); 97 | u32::from_be(current[4]) 98 | } 99 | } 100 | 101 | #[cfg(test)] 102 | mod tests { 103 | use super::EventToMhpmcounters; 104 | use crate::{Dtb, DtbPtr, buildin::Node, from_raw_mut}; 105 | 106 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../../examples/qemu-virt.dtb"); 107 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 108 | #[test] 109 | fn test_chosen_stdout() { 110 | #[repr(align(8))] 111 | struct AlignedBuffer { 112 | pub data: [u8; RAW_DEVICE_TREE.len()], 113 | } 114 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 115 | data: [0; BUFFER_SIZE], 116 | }); 117 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 118 | let mut slice = aligned_data.data.to_vec(); 119 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr()).unwrap(); 120 | let dtb = Dtb::from(ptr).share(); 121 | 122 | let node: Node = from_raw_mut(&dtb).unwrap(); 123 | let result = node 124 | .find("/pmu") 125 | .unwrap() 126 | .get_prop("riscv,event-to-mhpmcounters") 127 | .unwrap() 128 | .deserialize::<EventToMhpmcounters>(); 129 | assert_eq!(result.len(), 5); 130 | assert_eq!(result.get_event_idx_range(0), 1..=1); 131 | assert_eq!(result.get_counter_bitmap(0), 0x7fff9); 132 | assert_eq!(result.get_event_idx_range(1), 2..=2); 133 | assert_eq!(result.get_counter_bitmap(1), 0x7fffc); 134 | assert_eq!(result.get_event_idx_range(2), 0x10019..=0x10019); 135 | assert_eq!(result.get_counter_bitmap(2), 0x7fff8); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/value/tree.rs: -------------------------------------------------------------------------------- 1 | // TODO reference to a device tree 2 | -------------------------------------------------------------------------------- /tests/bl808.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | use serde_device_tree::{Dtb, DtbPtr, buildin::NodeSeq, error::Error, from_raw_mut}; 4 | 5 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../examples/bl808.dtb"); 6 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 7 | 8 | #[repr(align(8))] 9 | struct AlignedBuffer { 10 | pub data: [u8; RAW_DEVICE_TREE.len()], 11 | } 12 | 13 | /// Root device tree structure containing system information. 14 | #[derive(Deserialize)] 15 | pub struct Tree<'a> { 16 | /// Memory information. 17 | pub memory: NodeSeq<'a>, 18 | } 19 | 20 | #[test] 21 | fn bl808() -> Result<(), Error> { 22 | // 整个设备树二进制文件需要装载到一块可写的内存区域 23 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 24 | data: [0; BUFFER_SIZE], 25 | }); 26 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 27 | let mut slice = aligned_data.data.to_vec(); 28 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr())?; 29 | let dtb = Dtb::from(ptr).share(); 30 | 31 | let _: Tree = from_raw_mut(&dtb).unwrap(); 32 | 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /tests/hifive-unmatched-a00.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use serde_device_tree::Compatible; 3 | 4 | #[derive(Debug, Deserialize)] 5 | struct Tree<'a> { 6 | #[serde(rename = "#address-cells")] 7 | num_address_cells: u32, 8 | #[serde(rename = "#size-cells")] 9 | num_size_cells: u32, 10 | model: &'a str, 11 | #[allow(unused)] 12 | compatible: Compatible<'a>, 13 | chosen: Option<Chosen<'a>>, 14 | cpus: Cpus, 15 | } 16 | 17 | #[derive(Debug, Deserialize)] 18 | #[serde(rename_all = "kebab-case")] 19 | struct Chosen<'a> { 20 | stdout_path: Option<&'a str>, 21 | } 22 | 23 | #[derive(Debug, Deserialize)] 24 | #[serde(rename_all = "kebab-case")] 25 | struct Cpus { 26 | timebase_frequency: u32, 27 | #[serde(rename = "u-boot,dm-spl")] 28 | u_boot_dm_spl: bool, 29 | } 30 | 31 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../examples/hifive-unmatched-a00.dtb"); 32 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 33 | 34 | #[repr(align(4))] 35 | struct AlignedBuffer { 36 | pub data: [u8; RAW_DEVICE_TREE.len()], 37 | } 38 | 39 | #[test] 40 | fn hifive_unmatched() { 41 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 42 | data: [0; BUFFER_SIZE], 43 | }); 44 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 45 | let ptr = aligned_data.data.as_ptr(); 46 | let t: Tree = unsafe { serde_device_tree::from_raw(ptr) }.unwrap(); 47 | assert_eq!(t.num_address_cells, 2); 48 | assert_eq!(t.num_size_cells, 2); 49 | assert_eq!(t.model, "SiFive HiFive Unmatched A00\0"); 50 | if let Some(chosen) = t.chosen { 51 | if let Some(stdout_path) = chosen.stdout_path { 52 | assert_eq!(stdout_path, "serial0\0"); 53 | } else { 54 | panic!("Failed to find chosen/stdout_path"); 55 | } 56 | } 57 | assert_eq!(t.cpus.timebase_frequency, 1000000); 58 | assert!(t.cpus.u_boot_dm_spl); 59 | } 60 | -------------------------------------------------------------------------------- /tests/qemu-virt.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | use serde_device_tree::{ 4 | Dtb, DtbPtr, 5 | buildin::{NodeSeq, Reg}, 6 | error::Error, 7 | from_raw_mut, 8 | }; 9 | 10 | const RAW_DEVICE_TREE: &[u8] = include_bytes!("../examples/qemu-virt.dtb"); 11 | const BUFFER_SIZE: usize = RAW_DEVICE_TREE.len(); 12 | 13 | #[repr(align(8))] 14 | struct AlignedBuffer { 15 | pub data: [u8; RAW_DEVICE_TREE.len()], 16 | } 17 | 18 | #[derive(Deserialize)] 19 | struct Tree<'a> { 20 | soc: Soc<'a>, 21 | } 22 | 23 | #[allow(dead_code)] 24 | #[derive(Deserialize)] 25 | struct Soc<'a> { 26 | virtio_mmio: NodeSeq<'a>, 27 | } 28 | 29 | #[derive(Deserialize)] 30 | #[allow(unused)] 31 | struct VirtIoMmio<'a> { 32 | reg: Reg<'a>, 33 | } 34 | 35 | #[test] 36 | fn qemu_virt() -> Result<(), Error> { 37 | // 整个设备树二进制文件需要装载到一块可写的内存区域 38 | let mut aligned_data: Box<AlignedBuffer> = Box::new(AlignedBuffer { 39 | data: [0; BUFFER_SIZE], 40 | }); 41 | aligned_data.data[..BUFFER_SIZE].clone_from_slice(RAW_DEVICE_TREE); 42 | let mut slice = aligned_data.data.to_vec(); 43 | let ptr = DtbPtr::from_raw(slice.as_mut_ptr())?; 44 | let dtb = Dtb::from(ptr).share(); 45 | 46 | let t: Tree = from_raw_mut(&dtb).unwrap(); 47 | 48 | assert_eq!(t.soc.virtio_mmio.len(), 8); 49 | assert_eq!(slice, RAW_DEVICE_TREE); 50 | 51 | Ok(()) 52 | } 53 | --------------------------------------------------------------------------------