diff --git a/0011-util-fdt-implement-basic-fdt-API.patch b/0011-util-fdt-implement-basic-fdt-API.patch new file mode 100644 index 0000000000000000000000000000000000000000..62a2e54a1b67dceecde6e9fa2f4ba29bcae7ba62 --- /dev/null +++ b/0011-util-fdt-implement-basic-fdt-API.patch @@ -0,0 +1,908 @@ +From 792248c876ba6f3ef4fa1e6c05c7e9a157ec5528 Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Wed, 23 Jun 2021 14:46:57 +0800 +Subject: [PATCH 1/5] util/fdt: implement basic fdt API + +This series of patches is for rust update to version >= 1.47. +Because the higher version of rust compile Stratovirt with +aarch64-unkonwn-linux-musl target, will get error like below: + +``` + note: /usr/lib/gcc/aarch64-linux-gnu/libfdt.a(fdt_sw.o): In function `fdt_property': + (.text+0x4d4): undefined reference to `__stack_chk_guard' + (.text+0x4e0): undefined reference to `__stack_chk_guard' + (.text+0x518): undefined reference to `__stack_chk_guard' + (.text+0x530): undefined reference to `__stack_chk_fail' +``` + +Rust community recommand to use vm-fdt(https://github.com/rust-vmm/vm-fdt) +to fix this problem. But this project is not released to crate.io for now. +So add basic implementation of fdt API. + +Signed-off-by: Jiajie Li +--- + Cargo.lock | 295 ++++++++++++++++++++++++----------------------- + util/Cargo.toml | 1 + + util/src/fdt.rs | 300 ++++++++++++++++++++++++++++++++++++++++++++++++ + util/src/lib.rs | 26 +++++ + 4 files changed, 474 insertions(+), 148 deletions(-) + create mode 100644 util/src/fdt.rs + +diff --git a/Cargo.lock b/Cargo.lock +index bf866cf..3bd4bdf 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -4,364 +4,363 @@ + name = "StratoVirt" + version = "0.3.0" + dependencies = [ +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "machine_manager 0.3.0", +- "micro_vm 0.3.0", +- "util 0.3.0", +- "virtio 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "error-chain", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "machine_manager", ++ "micro_vm", ++ "util", ++ "virtio", ++ "vmm-sys-util", + ] + + [[package]] + name = "addr2line" + version = "0.12.1" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" + dependencies = [ +- "gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "gimli", + ] + + [[package]] + name = "address_space" + version = "0.3.0" + dependencies = [ +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "machine_manager 0.3.0", +- "util 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "error-chain", ++ "kvm-bindings", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "machine_manager", ++ "util", ++ "vmm-sys-util", + ] + + [[package]] + name = "adler32" + version = "1.1.0" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" + + [[package]] + name = "backtrace" + version = "0.3.49" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" + dependencies = [ +- "addr2line 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "miniz_oxide 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +- "object 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ++ "addr2line", ++ "cfg-if", ++ "libc", ++ "miniz_oxide", ++ "object", ++ "rustc-demangle", + ] + + [[package]] + name = "bitflags" + version = "1.2.1" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + + [[package]] + name = "boot_loader" + version = "0.3.0" + dependencies = [ +- "address_space 0.3.0", +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "util 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "address_space", ++ "error-chain", ++ "kvm-bindings", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "util", ++ "vmm-sys-util", + ] + + [[package]] + name = "byteorder" + version = "1.3.4" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + + [[package]] + name = "cfg-if" + version = "0.1.10" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + + [[package]] + name = "cpu" + version = "0.3.0" + dependencies = [ +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "machine_manager 0.3.0", +- "util 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "error-chain", ++ "kvm-bindings", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "machine_manager", ++ "util", ++ "vmm-sys-util", + ] + + [[package]] + name = "devices" + version = "0.3.0" + dependencies = [ +- "address_space 0.3.0", +- "boot_loader 0.3.0", +- "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "machine_manager 0.3.0", +- "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +- "sysbus 0.3.0", +- "util 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "address_space", ++ "boot_loader", ++ "byteorder", ++ "error-chain", ++ "kvm-bindings", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "machine_manager", ++ "serde", ++ "sysbus", ++ "util", ++ "vmm-sys-util", + ] + + [[package]] + name = "error-chain" + version = "0.12.4" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" + dependencies = [ +- "backtrace 0.3.49 (registry+https://github.com/rust-lang/crates.io-index)", +- "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ++ "backtrace", ++ "version_check", + ] + + [[package]] + name = "gimli" + version = "0.21.0" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" + + [[package]] + name = "itoa" + version = "0.4.5" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + + [[package]] + name = "kvm-bindings" + version = "0.3.0" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8f1c07667561c3d12d77342baf28ca5d0f8c3ea2160778485640ec84a4571da2" + dependencies = [ +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "vmm-sys-util", + ] + + [[package]] + name = "kvm-ioctls" + version = "0.6.0" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "158d15da895bddca8223fa31dc9e8b9317bdc2fbc4635dea8dd575fc40dae37f" + dependencies = [ +- "kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "kvm-bindings", ++ "libc", ++ "vmm-sys-util", + ] + + [[package]] + name = "libc" + version = "0.2.71" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + + [[package]] + name = "log" + version = "0.4.8" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" + dependencies = [ +- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ++ "cfg-if", + ] + + [[package]] + name = "machine_manager" + version = "0.3.0" + dependencies = [ +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", +- "util 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "error-chain", ++ "libc", ++ "log", ++ "serde", ++ "serde_json", ++ "util", ++ "vmm-sys-util", + ] + + [[package]] + name = "micro_vm" + version = "0.3.0" + dependencies = [ +- "address_space 0.3.0", +- "boot_loader 0.3.0", +- "cpu 0.3.0", +- "devices 0.3.0", +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "machine_manager 0.3.0", +- "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", +- "sysbus 0.3.0", +- "util 0.3.0", +- "virtio 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "address_space", ++ "boot_loader", ++ "cpu", ++ "devices", ++ "error-chain", ++ "kvm-bindings", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "machine_manager", ++ "serde", ++ "serde_json", ++ "sysbus", ++ "util", ++ "virtio", ++ "vmm-sys-util", + ] + + [[package]] + name = "miniz_oxide" + version = "0.3.7" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" + dependencies = [ +- "adler32 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "adler32", + ] + + [[package]] + name = "object" + version = "0.20.0" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" + + [[package]] + name = "proc-macro2" + version = "1.0.18" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" + dependencies = [ +- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "unicode-xid", + ] + + [[package]] + name = "quote" + version = "1.0.7" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" + dependencies = [ +- "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ++ "proc-macro2", + ] + + [[package]] + name = "rustc-demangle" + version = "0.1.16" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + + [[package]] + name = "ryu" + version = "1.0.5" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + + [[package]] + name = "serde" + version = "1.0.114" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" + dependencies = [ +- "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", ++ "serde_derive", + ] + + [[package]] + name = "serde_derive" + version = "1.0.114" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" + dependencies = [ +- "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +- "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +- "syn 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ++ "proc-macro2", ++ "quote", ++ "syn", + ] + + [[package]] + name = "serde_json" + version = "1.0.55" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" + dependencies = [ +- "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +- "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", ++ "itoa", ++ "ryu", ++ "serde", + ] + + [[package]] + name = "syn" + version = "1.0.37" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "239f255b9e3429350f188c27b807fc9920a15eb9145230ff1a7d054c08fec319" + dependencies = [ +- "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +- "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "proc-macro2", ++ "quote", ++ "unicode-xid", + ] + + [[package]] + name = "sysbus" + version = "0.3.0" + dependencies = [ +- "address_space 0.3.0", +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "address_space", ++ "error-chain", ++ "kvm-ioctls", ++ "log", ++ "vmm-sys-util", + ] + + [[package]] + name = "unicode-xid" + version = "0.2.0" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + + [[package]] + name = "util" + version = "0.3.0" + dependencies = [ +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "byteorder", ++ "error-chain", ++ "kvm-bindings", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "vmm-sys-util", + ] + + [[package]] + name = "version_check" + version = "0.9.2" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + + [[package]] + name = "virtio" + version = "0.3.0" + dependencies = [ +- "address_space 0.3.0", +- "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "machine_manager 0.3.0", +- "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", +- "sysbus 0.3.0", +- "util 0.3.0", +- "vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "address_space", ++ "byteorder", ++ "error-chain", ++ "kvm-ioctls", ++ "libc", ++ "log", ++ "machine_manager", ++ "serde_json", ++ "sysbus", ++ "util", ++ "vmm-sys-util", + ] + + [[package]] + name = "vmm-sys-util" + version = "0.7.0" + source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d1cdd1d72e262bbfb014de65ada24c1ac50e10a2e3b1e8ec052df188c2ee5dfa" + dependencies = [ +- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", ++ "bitflags", ++ "libc", + ] +- +-[metadata] +-"checksum addr2line 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" +-"checksum adler32 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" +-"checksum backtrace 0.3.49 (registry+https://github.com/rust-lang/crates.io-index)" = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" +-"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +-"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +-"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +-"checksum error-chain 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +-"checksum gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" +-"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +-"checksum kvm-bindings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1c07667561c3d12d77342baf28ca5d0f8c3ea2160778485640ec84a4571da2" +-"checksum kvm-ioctls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "158d15da895bddca8223fa31dc9e8b9317bdc2fbc4635dea8dd575fc40dae37f" +-"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +-"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +-"checksum miniz_oxide 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +-"checksum object 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +-"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +-"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +-"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +-"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +-"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +-"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +-"checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" +-"checksum syn 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "239f255b9e3429350f188c27b807fc9920a15eb9145230ff1a7d054c08fec319" +-"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +-"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +-"checksum vmm-sys-util 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d1cdd1d72e262bbfb014de65ada24c1ac50e10a2e3b1e8ec052df188c2ee5dfa" +diff --git a/util/Cargo.toml b/util/Cargo.toml +index 21d9764..a4a7f97 100644 +--- a/util/Cargo.toml ++++ b/util/Cargo.toml +@@ -14,3 +14,4 @@ kvm-ioctls = "0.6.0" + libc = "0.2.71" + log = { version = "0.4.8", features = ["std"]} + vmm-sys-util = "0.7.0" ++byteorder = "1.3.4" +diff --git a/util/src/fdt.rs b/util/src/fdt.rs +new file mode 100644 +index 0000000..2fdab44 +--- /dev/null ++++ b/util/src/fdt.rs +@@ -0,0 +1,300 @@ ++// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved. ++// ++// StratoVirt 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. ++ ++use std::mem::size_of; ++ ++use crate::errors::{ErrorKind, Result, ResultExt}; ++use byteorder::{BigEndian, ByteOrder}; ++ ++pub const CLK_PHANDLE: u32 = 1; ++pub const GIC_PHANDLE: u32 = 2; ++pub const GIC_ITS_PHANDLE: u32 = 3; ++pub const CPU_PHANDLE_START: u32 = 10; ++ ++pub const GIC_FDT_IRQ_TYPE_SPI: u32 = 0; ++pub const GIC_FDT_IRQ_TYPE_PPI: u32 = 1; ++pub const IRQ_TYPE_EDGE_RISING: u32 = 1; ++pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4; ++ ++pub const FDT_MAX_SIZE: u32 = 0x1_0000; ++ ++// Magic number in fdt header(big-endian). ++const FDT_MAGIC: u32 = 0xd00dfeed; ++// Fdt Header default information. ++const FDT_HEADER_SIZE: usize = 40; ++const FDT_VERSION: u32 = 17; ++const FDT_LAST_COMP_VERSION: u32 = 16; ++// Beginning token type of structure block. ++const FDT_BEGIN_NODE: u32 = 0x00000001; ++const FDT_END_NODE: u32 = 0x00000002; ++const FDT_PROP: u32 = 0x00000003; ++const FDT_END: u32 = 0x00000009; ++// Memory reservation block alignment. ++const MEM_RESERVE_ALIGNMENT: usize = 8; ++// Structure block alignment. ++const STRUCTURE_BLOCK_ALIGNMENT: usize = 4; ++ ++/// FdtBuilder structure. ++pub struct FdtBuilder { ++ /// The header of flattened device tree. ++ fdt_header: Vec, ++ /// The memory reservation block of flattened device tree. ++ /// It provides the client program with a list of areas ++ /// in physical memory which are reserved. ++ mem_reserve: Vec, ++ /// The structure block of flattened device tree. ++ /// It describes the structure and contents of the tree. ++ structure_blk: Vec, ++ /// The strings block of flattened device tree. ++ /// It contains strings representing all the property names used in the tree. ++ strings_blk: Vec, ++ /// The physical ID of the system’s boot CPU. ++ boot_cpuid_phys: u32, ++ /// The depth of nested node. ++ subnode_depth: u32, ++ /// Is there a open node or not. ++ begin_node: bool, ++} ++ ++/// FdtReserveEntry structure. ++#[derive(Clone, Debug)] ++pub struct FdtReserveEntry { ++ /// The address of reserved memory. ++ /// On 32-bit CPUs the upper 32-bits of the value are ignored. ++ address: u64, ++ /// The size of reserved memory. ++ size: u64, ++} ++ ++fn check_mem_reserve_overlap(mem_reservations: &[FdtReserveEntry]) -> bool { ++ if mem_reservations.len() <= 1 { ++ return true; ++ } ++ ++ let mut mem_reser = mem_reservations.to_vec(); ++ mem_reser.sort_by_key(|m| m.address); ++ ++ for i in 0..(mem_reser.len() - 1) { ++ if mem_reser[i].address + mem_reser[i].size > mem_reser[i + 1].address { ++ return false; ++ } ++ } ++ true ++} ++ ++// If there is null character in string, return false. ++fn check_string_legality(s: &str) -> bool { ++ !s.contains('\0') ++} ++ ++impl Default for FdtBuilder { ++ fn default() -> Self { ++ Self { ++ fdt_header: vec![0_u8; FDT_HEADER_SIZE], ++ mem_reserve: Vec::new(), ++ structure_blk: Vec::new(), ++ strings_blk: Vec::new(), ++ boot_cpuid_phys: 0, ++ subnode_depth: 0, ++ begin_node: false, ++ } ++ } ++} ++ ++impl FdtBuilder { ++ pub fn new() -> Self { ++ FdtBuilder::default() ++ } ++ ++ pub fn finish(mut self) -> Result> { ++ if self.subnode_depth > 0 { ++ return Err(ErrorKind::NodeUnclosed(self.subnode_depth).into()); ++ } ++ self.structure_blk ++ .extend_from_slice(&FDT_END.to_be_bytes()[..]); ++ ++ // According to the spec, mem_reserve blocks shall be ended ++ // with an entry where both address and size are equal to 0. ++ self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); ++ self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); ++ ++ // Fill fdt header. ++ let total_size = FDT_HEADER_SIZE ++ + self.mem_reserve.len() ++ + self.structure_blk.len() ++ + self.strings_blk.len(); ++ let off_dt_struct = FDT_HEADER_SIZE + self.mem_reserve.len(); ++ let off_dt_strings = FDT_HEADER_SIZE + self.mem_reserve.len() + self.structure_blk.len(); ++ let off_mem_rsvmap = FDT_HEADER_SIZE; ++ ++ BigEndian::write_u32(&mut self.fdt_header[0..4], FDT_MAGIC); ++ BigEndian::write_u32(&mut self.fdt_header[4..8], total_size as u32); ++ BigEndian::write_u32(&mut self.fdt_header[8..12], off_dt_struct as u32); ++ BigEndian::write_u32(&mut self.fdt_header[12..16], off_dt_strings as u32); ++ BigEndian::write_u32(&mut self.fdt_header[16..20], off_mem_rsvmap as u32); ++ BigEndian::write_u32(&mut self.fdt_header[20..24], FDT_VERSION); ++ BigEndian::write_u32(&mut self.fdt_header[24..28], FDT_LAST_COMP_VERSION); ++ BigEndian::write_u32(&mut self.fdt_header[28..32], self.boot_cpuid_phys); ++ BigEndian::write_u32(&mut self.fdt_header[32..36], self.strings_blk.len() as u32); ++ BigEndian::write_u32( ++ &mut self.fdt_header[36..40], ++ self.structure_blk.len() as u32, ++ ); ++ ++ self.fdt_header.extend_from_slice(&self.mem_reserve); ++ self.fdt_header.extend_from_slice(&self.structure_blk); ++ self.fdt_header.extend_from_slice(&self.strings_blk); ++ Ok(self.fdt_header) ++ } ++ ++ pub fn add_mem_reserve(&mut self, mem_reservations: &[FdtReserveEntry]) -> Result<()> { ++ if !check_mem_reserve_overlap(mem_reservations) { ++ return Err(ErrorKind::MemReserveOverlap.into()); ++ } ++ ++ for mem_reser in mem_reservations { ++ self.mem_reserve ++ .extend_from_slice(&mem_reser.address.to_be_bytes()); ++ self.mem_reserve ++ .extend_from_slice(&mem_reser.size.to_be_bytes()); ++ } ++ self.align_structure_blk(MEM_RESERVE_ALIGNMENT); ++ ++ Ok(()) ++ } ++ ++ pub fn begin_node(&mut self, node_name: &str) -> Result { ++ if !check_string_legality(node_name) { ++ return Err(ErrorKind::IllegalString(node_name.to_string()).into()); ++ } ++ ++ self.structure_blk ++ .extend_from_slice(&FDT_BEGIN_NODE.to_be_bytes()[..]); ++ if node_name.is_empty() { ++ self.structure_blk ++ .extend_from_slice(&0_u32.to_be_bytes()[..]); ++ } else { ++ let mut val_array = node_name.as_bytes().to_vec(); ++ // The node’s name string should end with null('\0'). ++ val_array.push(0x0_u8); ++ self.structure_blk.extend_from_slice(&val_array); ++ } ++ self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); ++ self.subnode_depth += 1; ++ self.begin_node = true; ++ Ok(self.subnode_depth) ++ } ++ ++ pub fn end_node(&mut self, begin_node_depth: u32) -> Result<()> { ++ if begin_node_depth != self.subnode_depth { ++ return Err(ErrorKind::NodeDepthMismatch(begin_node_depth, self.subnode_depth).into()); ++ } ++ ++ self.structure_blk ++ .extend_from_slice(&FDT_END_NODE.to_be_bytes()[..]); ++ self.subnode_depth -= 1; ++ self.begin_node = false; ++ Ok(()) ++ } ++ ++ pub fn set_boot_cpuid_phys(&mut self, boot_cpuid: u32) { ++ self.boot_cpuid_phys = boot_cpuid; ++ } ++ ++ pub fn set_property_string(&mut self, prop: &str, val: &str) -> Result<()> { ++ let mut val_array = val.as_bytes().to_vec(); ++ // The string property should end with null('\0'). ++ val_array.push(0x0_u8); ++ self.set_property(prop, &val_array) ++ .chain_err(|| ErrorKind::SetPropertyErr("string".to_string())) ++ } ++ ++ pub fn set_property_u32(&mut self, prop: &str, val: u32) -> Result<()> { ++ self.set_property(prop, &val.to_be_bytes()[..]) ++ .chain_err(|| ErrorKind::SetPropertyErr("u32".to_string())) ++ } ++ ++ pub fn set_property_u64(&mut self, prop: &str, val: u64) -> Result<()> { ++ self.set_property(prop, &val.to_be_bytes()[..]) ++ .chain_err(|| ErrorKind::SetPropertyErr("u64".to_string())) ++ } ++ ++ pub fn set_property_array_u32(&mut self, prop: &str, array: &[u32]) -> Result<()> { ++ let mut prop_array = Vec::with_capacity(array.len() * size_of::()); ++ for element in array { ++ prop_array.extend_from_slice(&element.to_be_bytes()[..]); ++ } ++ self.set_property(prop, &prop_array) ++ .chain_err(|| ErrorKind::SetPropertyErr("u32 array".to_string())) ++ } ++ ++ pub fn set_property_array_u64(&mut self, prop: &str, array: &[u64]) -> Result<()> { ++ let mut prop_array = Vec::with_capacity(array.len() * size_of::()); ++ for element in array { ++ prop_array.extend_from_slice(&element.to_be_bytes()[..]); ++ } ++ self.set_property(prop, &prop_array) ++ .chain_err(|| ErrorKind::SetPropertyErr("u64 array".to_string())) ++ } ++ ++ pub fn set_property(&mut self, property_name: &str, property_val: &[u8]) -> Result<()> { ++ if !check_string_legality(property_name) { ++ return Err(ErrorKind::IllegalString(property_name.to_string()).into()); ++ } ++ ++ if !self.begin_node { ++ return Err(ErrorKind::IllegelPropertyPos.into()); ++ } ++ ++ let len = property_val.len() as u32; ++ let nameoff = self.strings_blk.len() as u32; ++ self.structure_blk ++ .extend_from_slice(&FDT_PROP.to_be_bytes()[..]); ++ self.structure_blk.extend_from_slice(&len.to_be_bytes()[..]); ++ self.structure_blk ++ .extend_from_slice(&nameoff.to_be_bytes()[..]); ++ self.structure_blk.extend_from_slice(property_val); ++ self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); ++ ++ self.strings_blk.extend_from_slice(property_name.as_bytes()); ++ // These strings in strings block should end with null('\0'). ++ self.strings_blk.extend_from_slice("\0".as_bytes()); ++ ++ Ok(()) ++ } ++ ++ fn align_structure_blk(&mut self, alignment: usize) { ++ let remainder = self.structure_blk.len() % alignment; ++ if remainder != 0 { ++ self.structure_blk ++ .extend(vec![0_u8; (alignment - remainder) as usize]); ++ } ++ } ++} ++ ++/// Trait for devices to be added to the Flattened Device Tree. ++#[allow(clippy::upper_case_acronyms)] ++pub trait CompileFDT { ++ /// function to generate fdt node ++ /// ++ /// # Arguments ++ /// ++ /// * `fdt` - the FdtBuilder to be filled. ++ fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()>; ++} ++ ++pub fn dump_dtb(fdt: &[u8], file_path: &str) { ++ use std::fs::File; ++ use std::io::Write; ++ let mut f = File::create(file_path).unwrap(); ++ f.write_all(fdt).expect("Unable to write data"); ++} +diff --git a/util/src/lib.rs b/util/src/lib.rs +index a5feaef..d135c74 100644 +--- a/util/src/lib.rs ++++ b/util/src/lib.rs +@@ -28,6 +28,8 @@ pub mod checksum; + pub mod daemonize; + #[cfg(target_arch = "aarch64")] + pub mod device_tree; ++#[cfg(target_arch = "aarch64")] ++pub mod fdt; + pub mod leak_bucket; + mod link_list; + pub mod loop_context; +@@ -131,6 +133,30 @@ pub mod errors { + description("Index out of bound of array") + display("Index :{} out of bound :{}", index, bound) + } ++ NodeDepthMismatch(target_dep: u32, real_dep: u32) { ++ description("Fdt structure nested node depth mismatch") ++ display("Desired node depth :{}, current node depth :{}", target_dep, real_dep) ++ } ++ NodeUnclosed(unclose: u32) { ++ description("Fdt structure block node unclose") ++ display("Still have {} node open when terminating the fdt", unclose) ++ } ++ IllegelPropertyPos { ++ description("Cann't add property outside the node") ++ display("Failed to add property because there is no open node") ++ } ++ IllegalString(s: String) { ++ description("The string for fdt should not contain null") ++ display("Failed to add string to fdt because of null character inside \"{}\"", s) ++ } ++ MemReserveOverlap { ++ description("The mem reserve entry should not overlap") ++ display("Failed to add overlapped mem reserve entries to fdt") ++ } ++ SetPropertyErr(s: String) { ++ description("Cann't set property for fdt node") ++ display("Failed to set {} property", s) ++ } + } + } + } +-- +2.31.1 + diff --git a/0012-devices-gicv3-use-mod-fdt-instead-of-device_tree.patch b/0012-devices-gicv3-use-mod-fdt-instead-of-device_tree.patch new file mode 100644 index 0000000000000000000000000000000000000000..dd1ae4ddb071028b9f11b4b63fb3223ddf60d419 --- /dev/null +++ b/0012-devices-gicv3-use-mod-fdt-instead-of-device_tree.patch @@ -0,0 +1,132 @@ +From bc7aa4bcc37cfd5244697e81af7555fa781249bb Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Wed, 23 Jun 2021 15:06:21 +0800 +Subject: [PATCH 2/5] devices/gicv3: use mod fdt instead of device_tree + +Use fdt API provided by mod fdt, instead of mod device_tree +which is a wrapper around libfdt. + +Signed-off-by: Jiajie Li +--- + .../src/interrupt_controller/aarch64/gicv3.rs | 50 +++++++++---------- + .../src/interrupt_controller/aarch64/mod.rs | 11 ++-- + 2 files changed, 31 insertions(+), 30 deletions(-) + +diff --git a/devices/src/interrupt_controller/aarch64/gicv3.rs b/devices/src/interrupt_controller/aarch64/gicv3.rs +index 235bf37..a39a3d5 100644 +--- a/devices/src/interrupt_controller/aarch64/gicv3.rs ++++ b/devices/src/interrupt_controller/aarch64/gicv3.rs +@@ -14,7 +14,7 @@ use std::sync::{Arc, Mutex}; + + use kvm_ioctls::{DeviceFd, VmFd}; + use machine_manager::machine::{KvmVmState, MachineLifecycle}; +-use util::device_tree; ++use util::fdt::{self, FdtBuilder}; + + use super::{GICConfig, GICDevice, UtilResult}; + use crate::errors::{ErrorKind, Result, ResultExt}; +@@ -379,7 +379,7 @@ impl GICDevice for GICv3 { + Ok(()) + } + +- fn generate_fdt(&self, fdt: &mut Vec) -> UtilResult<()> { ++ fn generate_fdt(&self, fdt: &mut FdtBuilder) -> UtilResult<()> { + let redist_count = self.redist_regions.len() as u32; + let mut gic_reg = vec![self.dist_base, self.dist_size]; + +@@ -388,34 +388,32 @@ impl GICDevice for GICv3 { + gic_reg.push(redist.size); + } + +- let node = "/intc"; +- device_tree::add_sub_node(fdt, node)?; +- device_tree::set_property_string(fdt, node, "compatible", "arm,gic-v3")?; +- device_tree::set_property(fdt, node, "interrupt-controller", None)?; +- device_tree::set_property_u32(fdt, node, "#interrupt-cells", 0x3)?; +- device_tree::set_property_u32(fdt, node, "phandle", device_tree::GIC_PHANDLE)?; +- device_tree::set_property_u32(fdt, node, "#address-cells", 0x2)?; +- device_tree::set_property_u32(fdt, node, "#size-cells", 0x2)?; +- device_tree::set_property_u32(fdt, node, "#redistributor-regions", redist_count)?; +- device_tree::set_property_array_u64(fdt, node, "reg", &gic_reg)?; +- +- let gic_intr = [ +- device_tree::GIC_FDT_IRQ_TYPE_PPI, +- 0x9, +- device_tree::IRQ_TYPE_LEVEL_HIGH, +- ]; +- device_tree::set_property_array_u32(fdt, node, "interrupts", &gic_intr)?; ++ let node = "intc"; ++ let intc_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_string("compatible", "arm,gic-v3")?; ++ fdt.set_property("interrupt-controller", &Vec::new())?; ++ fdt.set_property_u32("#interrupt-cells", 0x3)?; ++ fdt.set_property_u32("phandle", fdt::GIC_PHANDLE)?; ++ fdt.set_property_u32("#address-cells", 0x2)?; ++ fdt.set_property_u32("#size-cells", 0x2)?; ++ fdt.set_property_u32("#redistributor-regions", redist_count)?; ++ fdt.set_property_array_u64("reg", &gic_reg)?; ++ ++ let gic_intr = [fdt::GIC_FDT_IRQ_TYPE_PPI, 0x9, fdt::IRQ_TYPE_LEVEL_HIGH]; ++ fdt.set_property_array_u32("interrupts", &gic_intr)?; + + if let Some(its) = &self.its_dev { +- device_tree::set_property(fdt, node, "ranges", None)?; ++ fdt.set_property("ranges", &Vec::new())?; + let its_reg = [its.msi_base, its.msi_size]; +- let node = "/intc/its"; +- device_tree::add_sub_node(fdt, node)?; +- device_tree::set_property_string(fdt, node, "compatible", "arm,gic-v3-its")?; +- device_tree::set_property(fdt, node, "msi-controller", None)?; +- device_tree::set_property_u32(fdt, node, "phandle", device_tree::GIC_ITS_PHANDLE)?; +- device_tree::set_property_array_u64(fdt, node, "reg", &its_reg)?; ++ let node = "its"; ++ let its_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_string("compatible", "arm,gic-v3-its")?; ++ fdt.set_property("msi-controller", &Vec::new())?; ++ fdt.set_property_u32("phandle", fdt::GIC_ITS_PHANDLE)?; ++ fdt.set_property_array_u64("reg", &its_reg)?; ++ fdt.end_node(its_node_dep)?; + } ++ fdt.end_node(intc_node_dep)?; + + Ok(()) + } +diff --git a/devices/src/interrupt_controller/aarch64/mod.rs b/devices/src/interrupt_controller/aarch64/mod.rs +index d2a1b50..f1b40cf 100644 +--- a/devices/src/interrupt_controller/aarch64/mod.rs ++++ b/devices/src/interrupt_controller/aarch64/mod.rs +@@ -18,7 +18,10 @@ use std::sync::Arc; + + use kvm_ioctls::VmFd; + use machine_manager::machine::{KvmVmState, MachineLifecycle}; +-use util::{device_tree, errors::Result as UtilResult}; ++use util::{ ++ errors::Result as UtilResult, ++ fdt::{self, FdtBuilder}, ++}; + + use crate::errors::{ErrorKind, Result, ResultExt}; + +@@ -88,7 +91,7 @@ pub trait GICDevice: MachineLifecycle { + /// # Arguments + /// + /// * `fdt` - Device tree presented by bytes. +- fn generate_fdt(&self, fdt: &mut Vec) -> UtilResult<()>; ++ fn generate_fdt(&self, fdt: &mut FdtBuilder) -> UtilResult<()>; + } + + /// A wrapper around creating and using a kvm-based interrupt controller. +@@ -121,8 +124,8 @@ impl InterruptController { + } + } + +-impl device_tree::CompileFDT for InterruptController { +- fn generate_fdt_node(&self, fdt: &mut Vec) -> UtilResult<()> { ++impl fdt::CompileFDT for InterruptController { ++ fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> UtilResult<()> { + self.gic.generate_fdt(fdt)?; + Ok(()) + } +-- +2.31.1 + diff --git a/0013-machine-micro_vm-use-fdt-API-of-mod-fdt-instead-of-d.patch b/0013-machine-micro_vm-use-fdt-API-of-mod-fdt-instead-of-d.patch new file mode 100644 index 0000000000000000000000000000000000000000..f482e6034a5d52b20ae8d34f3e41262f6406e412 --- /dev/null +++ b/0013-machine-micro_vm-use-fdt-API-of-mod-fdt-instead-of-d.patch @@ -0,0 +1,453 @@ +From 999b6194eff54881f3ce4181f2355113fc72435b Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Wed, 23 Jun 2021 15:20:54 +0800 +Subject: [PATCH 3/5] machine/micro_vm: use fdt API of mod fdt instead of + device_tree + +Use fdt API provided by mod fdt, instead of mod device_tree +which is a wrapper around libfdt. + +Signed-off-by: Jiajie Li +--- + micro_vm/src/lib.rs | 291 ++++++++++++++++++++++---------------------- + 1 file changed, 143 insertions(+), 148 deletions(-) + +diff --git a/micro_vm/src/lib.rs b/micro_vm/src/lib.rs +index 7188f21..dd6cf97 100644 +--- a/micro_vm/src/lib.rs ++++ b/micro_vm/src/lib.rs +@@ -111,7 +111,7 @@ use sysbus::{SysBusDevType, SysRes}; + #[cfg(target_arch = "aarch64")] + use util::device_tree; + #[cfg(target_arch = "aarch64")] +-use util::device_tree::CompileFDT; ++use util::fdt::{self, CompileFDT, FdtBuilder}; + use util::loop_context::{ + EventLoopManager, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, + }; +@@ -628,12 +628,13 @@ impl LightMachine { + drop(boot_source); + #[cfg(target_arch = "aarch64")] + { +- let mut fdt = vec![0; device_tree::FDT_MAX_SIZE as usize]; +- vm.generate_fdt_node(&mut fdt)?; ++ let mut fdt_helper = FdtBuilder::new(); ++ vm.generate_fdt_node(&mut fdt_helper)?; ++ let fdt_vec = fdt_helper.finish()?; + vm.sys_mem.write( +- &mut fdt.as_slice(), ++ &mut fdt_vec.as_slice(), + GuestAddress(boot_config.fdt_addr as u64), +- fdt.len() as u64, ++ fdt_vec.len() as u64, + )?; + } + vm.register_power_event()?; +@@ -1477,23 +1478,23 @@ impl EventLoopManager for LightMachine { + // * `dev_info` - Device resource info of serial device. + // * `fdt` - Flatted device-tree blob where serial node will be filled into. + #[cfg(target_arch = "aarch64")] +-fn generate_serial_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Result<()> { +- let node = format!("/uart@{:x}", res.region_base); +- device_tree::add_sub_node(fdt, &node)?; +- device_tree::set_property_string(fdt, &node, "compatible", "ns16550a")?; +- device_tree::set_property_string(fdt, &node, "clock-names", "apb_pclk")?; +- device_tree::set_property_u32(fdt, &node, "clocks", device_tree::CLK_PHANDLE)?; +- device_tree::set_property_array_u64(fdt, &node, "reg", &[res.region_base, res.region_size])?; +- device_tree::set_property_array_u32( +- fdt, +- &node, ++fn generate_serial_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors::Result<()> { ++ let node = format!("uart@{:x}", res.region_base); ++ let serial_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_string("compatible", "ns16550a")?; ++ fdt.set_property_string("clock-names", "apb_pclk")?; ++ fdt.set_property_u32("clocks", fdt::CLK_PHANDLE)?; ++ fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; ++ fdt.set_property_array_u32( + "interrupts", + &[ +- device_tree::GIC_FDT_IRQ_TYPE_SPI, ++ fdt::GIC_FDT_IRQ_TYPE_SPI, + res.irq as u32, +- device_tree::IRQ_TYPE_EDGE_RISING, ++ fdt::IRQ_TYPE_EDGE_RISING, + ], + )?; ++ fdt.end_node(serial_node_dep)?; ++ + Ok(()) + } + +@@ -1504,23 +1505,23 @@ fn generate_serial_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors: + // * `dev_info` - Device resource info of RTC device. + // * `fdt` - Flatted device-tree blob where RTC node will be filled into. + #[cfg(target_arch = "aarch64")] +-fn generate_rtc_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Result<()> { +- let node = format!("/pl031@{:x}", res.region_base); +- device_tree::add_sub_node(fdt, &node)?; +- device_tree::set_property_string(fdt, &node, "compatible", "arm,pl031\0arm,primecell\0")?; +- device_tree::set_property_string(fdt, &node, "clock-names", "apb_pclk")?; +- device_tree::set_property_u32(fdt, &node, "clocks", device_tree::CLK_PHANDLE)?; +- device_tree::set_property_array_u64(fdt, &node, "reg", &[res.region_base, res.region_size])?; +- device_tree::set_property_array_u32( +- fdt, +- &node, ++fn generate_rtc_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors::Result<()> { ++ let node = format!("pl031@{:x}", res.region_base); ++ let rtc_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_string("compatible", "arm,pl031\0arm,primecell\0")?; ++ fdt.set_property_string("clock-names", "apb_pclk")?; ++ fdt.set_property_u32("clocks", fdt::CLK_PHANDLE)?; ++ fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; ++ fdt.set_property_array_u32( + "interrupts", + &[ +- device_tree::GIC_FDT_IRQ_TYPE_SPI, ++ fdt::GIC_FDT_IRQ_TYPE_SPI, + res.irq as u32, +- device_tree::IRQ_TYPE_LEVEL_HIGH, ++ fdt::IRQ_TYPE_LEVEL_HIGH, + ], + )?; ++ fdt.end_node(rtc_node_dep)?; ++ + Ok(()) + } + +@@ -1531,22 +1532,21 @@ fn generate_rtc_device_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Re + // * `dev_info` - Device resource info of Virtio-Mmio device. + // * `fdt` - Flatted device-tree blob where node will be filled into. + #[cfg(target_arch = "aarch64")] +-fn generate_virtio_devices_node(fdt: &mut Vec, res: &SysRes) -> util::errors::Result<()> { +- let node = format!("/virtio_mmio@{:x}", res.region_base); +- device_tree::add_sub_node(fdt, &node)?; +- device_tree::set_property_string(fdt, &node, "compatible", "virtio,mmio")?; +- device_tree::set_property_u32(fdt, &node, "interrupt-parent", device_tree::GIC_PHANDLE)?; +- device_tree::set_property_array_u64(fdt, &node, "reg", &[res.region_base, res.region_size])?; +- device_tree::set_property_array_u32( +- fdt, +- &node, ++fn generate_virtio_devices_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors::Result<()> { ++ let node = format!("virtio_mmio@{:x}", res.region_base); ++ let virtio_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_string("compatible", "virtio,mmio")?; ++ fdt.set_property_u32("interrupt-parent", fdt::GIC_PHANDLE)?; ++ fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; ++ fdt.set_property_array_u32( + "interrupts", + &[ +- device_tree::GIC_FDT_IRQ_TYPE_SPI, ++ fdt::GIC_FDT_IRQ_TYPE_SPI, + res.irq as u32, +- device_tree::IRQ_TYPE_EDGE_RISING, ++ fdt::IRQ_TYPE_EDGE_RISING, + ], + )?; ++ fdt.end_node(virtio_node_dep)?; + Ok(()) + } + +@@ -1555,73 +1555,72 @@ fn generate_virtio_devices_node(fdt: &mut Vec, res: &SysRes) -> util::errors + #[cfg(target_arch = "aarch64")] + trait CompileFDTHelper { + /// Function that helps to generate cpu nodes. +- fn generate_cpu_nodes(&self, fdt: &mut Vec) -> util::errors::Result<()>; ++ fn generate_cpu_nodes(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; + /// Function that helps to generate memory nodes. +- fn generate_memory_node(&self, fdt: &mut Vec) -> util::errors::Result<()>; ++ fn generate_memory_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; + /// Function that helps to generate Virtio-mmio devices' nodes. +- fn generate_devices_node(&self, fdt: &mut Vec) -> util::errors::Result<()>; ++ fn generate_devices_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; + /// Function that helps to generate the chosen node. +- fn generate_chosen_node(&self, fdt: &mut Vec) -> util::errors::Result<()>; ++ fn generate_chosen_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()>; + } + + #[cfg(target_arch = "aarch64")] + impl CompileFDTHelper for LightMachine { +- fn generate_cpu_nodes(&self, fdt: &mut Vec) -> util::errors::Result<()> { +- let node = "/cpus"; ++ fn generate_cpu_nodes(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { ++ let node = "cpus"; + +- device_tree::add_sub_node(fdt, node)?; +- device_tree::set_property_u32(fdt, node, "#address-cells", 0x02)?; +- device_tree::set_property_u32(fdt, node, "#size-cells", 0x0)?; ++ let cpus_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_u32("#address-cells", 0x02)?; ++ fdt.set_property_u32("#size-cells", 0x0)?; + + // Generate CPU topology + if self.cpu_topo.max_cpus > 0 && self.cpu_topo.max_cpus % 8 == 0 { +- device_tree::add_sub_node(fdt, "/cpus/cpu-map")?; ++ let cpu_map_node_dep = fdt.begin_node("cpu-map")?; + + let sockets = self.cpu_topo.max_cpus / 8; + for cluster in 0..u32::from(sockets) { +- let clster = format!("/cpus/cpu-map/cluster{}", cluster); +- device_tree::add_sub_node(fdt, &clster)?; ++ let clster = format!("cluster{}", cluster); ++ let cluster_node_dep = fdt.begin_node(&clster)?; + + for i in 0..2_u32 { +- let sub_cluster = format!("{}/cluster{}", clster, i); +- device_tree::add_sub_node(fdt, &sub_cluster)?; +- +- let core0 = format!("{}/core0", sub_cluster); +- device_tree::add_sub_node(fdt, &core0)?; +- let thread0 = format!("{}/thread0", core0); +- device_tree::add_sub_node(fdt, &thread0)?; +- device_tree::set_property_u32(fdt, &thread0, "cpu", cluster * 8 + i * 4 + 10)?; +- +- let thread1 = format!("{}/thread1", core0); +- device_tree::add_sub_node(fdt, &thread1)?; +- device_tree::set_property_u32( +- fdt, +- &thread1, +- "cpu", +- cluster * 8 + i * 4 + 10 + 1, +- )?; +- +- let core1 = format!("{}/core1", sub_cluster); +- device_tree::add_sub_node(fdt, &core1)?; +- let thread0 = format!("{}/thread0", core1); +- device_tree::add_sub_node(fdt, &thread0)?; +- device_tree::set_property_u32( +- fdt, +- &thread0, +- "cpu", +- cluster * 8 + i * 4 + 10 + 2, +- )?; +- +- let thread1 = format!("{}/thread1", core1); +- device_tree::add_sub_node(fdt, &thread1)?; +- device_tree::set_property_u32( +- fdt, +- &thread1, +- "cpu", +- cluster * 8 + i * 4 + 10 + 3, +- )?; ++ let sub_cluster = format!("cluster{}", i); ++ let sub_cluster_node_dep = fdt.begin_node(&sub_cluster)?; ++ ++ let core0 = "core0".to_string(); ++ let core0_node_dep = fdt.begin_node(&core0)?; ++ ++ let thread0 = "thread0".to_string(); ++ let thread0_node_dep = fdt.begin_node(&thread0)?; ++ fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10)?; ++ fdt.end_node(thread0_node_dep)?; ++ ++ let thread1 = "thread1".to_string(); ++ let thread1_node_dep = fdt.begin_node(&thread1)?; ++ fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10 + 1)?; ++ fdt.end_node(thread1_node_dep)?; ++ ++ fdt.end_node(core0_node_dep)?; ++ ++ let core1 = "core1".to_string(); ++ let core1_node_dep = fdt.begin_node(&core1)?; ++ ++ let thread0 = "thread0".to_string(); ++ let thread0_node_dep = fdt.begin_node(&thread0)?; ++ fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10 + 2)?; ++ fdt.end_node(thread0_node_dep)?; ++ ++ let thread1 = "thread1".to_string(); ++ let thread1_node_dep = fdt.begin_node(&thread1)?; ++ fdt.set_property_u32("cpu", cluster * 8 + i * 4 + 10 + 3)?; ++ fdt.end_node(thread1_node_dep)?; ++ ++ fdt.end_node(core1_node_dep)?; ++ ++ fdt.end_node(sub_cluster_node_dep)?; + } ++ fdt.end_node(cluster_node_dep)?; + } ++ fdt.end_node(cpu_map_node_dep)?; + } + + let cpu_list = self.cpus.lock().unwrap(); +@@ -1632,68 +1631,69 @@ impl CompileFDTHelper for LightMachine { + .unwrap() + .get_mpidr(cpu_list[cpu_index as usize].fd()); + +- let node = format!("/cpus/cpu@{:x}", mpidr); +- device_tree::add_sub_node(fdt, &node)?; +- device_tree::set_property_u32( +- fdt, +- &node, +- "phandle", +- u32::from(cpu_index) + device_tree::CPU_PHANDLE_START, +- )?; +- device_tree::set_property_string(fdt, &node, "device_type", "cpu")?; +- device_tree::set_property_string(fdt, &node, "compatible", "arm,arm-v8")?; ++ let node = format!("cpu@{:x}", mpidr); ++ let mpidr_node_dep = fdt.begin_node(&node)?; ++ fdt.set_property_u32("phandle", u32::from(cpu_index) + fdt::CPU_PHANDLE_START)?; ++ fdt.set_property_string("device_type", "cpu")?; ++ fdt.set_property_string("compatible", "arm,arm-v8")?; + if self.cpu_topo.max_cpus > 1 { +- device_tree::set_property_string(fdt, &node, "enable-method", "psci")?; ++ fdt.set_property_string("enable-method", "psci")?; + } +- device_tree::set_property_u64(fdt, &node, "reg", mpidr & 0x007F_FFFF)?; ++ fdt.set_property_u64("reg", mpidr & 0x007F_FFFF)?; ++ fdt.end_node(mpidr_node_dep)?; + } + ++ fdt.end_node(cpus_node_dep)?; ++ + Ok(()) + } + +- fn generate_memory_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { ++ fn generate_memory_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { + let mem_base = MEM_LAYOUT[LayoutEntryType::Mem as usize].0; + let mem_size = self.sys_mem.memory_end_address().raw_value() + - MEM_LAYOUT[LayoutEntryType::Mem as usize].0; +- let node = "/memory"; +- device_tree::add_sub_node(fdt, node)?; +- device_tree::set_property_string(fdt, node, "device_type", "memory")?; +- device_tree::set_property_array_u64(fdt, node, "reg", &[mem_base, mem_size as u64])?; ++ let node = "memory"; ++ let memory_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_string("device_type", "memory")?; ++ fdt.set_property_array_u64("reg", &[mem_base, mem_size as u64])?; ++ fdt.end_node(memory_node_dep)?; + + Ok(()) + } + +- fn generate_devices_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { ++ fn generate_devices_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { + // timer + let mut cells: Vec = Vec::new(); + for &irq in [13, 14, 11, 10].iter() { +- cells.push(device_tree::GIC_FDT_IRQ_TYPE_PPI); ++ cells.push(fdt::GIC_FDT_IRQ_TYPE_PPI); + cells.push(irq); +- cells.push(device_tree::IRQ_TYPE_LEVEL_HIGH); ++ cells.push(fdt::IRQ_TYPE_LEVEL_HIGH); + } +- let node = "/timer"; +- device_tree::add_sub_node(fdt, node)?; +- device_tree::set_property_string(fdt, node, "compatible", "arm,armv8-timer")?; +- device_tree::set_property(fdt, node, "always-on", None)?; +- device_tree::set_property_array_u32(fdt, node, "interrupts", &cells)?; ++ let node = "timer"; ++ let timer_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_string("compatible", "arm,armv8-timer")?; ++ fdt.set_property("always-on", &Vec::new())?; ++ fdt.set_property_array_u32("interrupts", &cells)?; ++ fdt.end_node(timer_node_dep)?; + + // clock +- let node = "/apb-pclk"; +- device_tree::add_sub_node(fdt, node)?; +- device_tree::set_property_string(fdt, node, "compatible", "fixed-clock")?; +- device_tree::set_property_string(fdt, node, "clock-output-names", "clk24mhz")?; +- device_tree::set_property_u32(fdt, node, "#clock-cells", 0x0)?; +- device_tree::set_property_u32(fdt, node, "clock-frequency", 24_000_000)?; +- device_tree::set_property_u32(fdt, node, "phandle", device_tree::CLK_PHANDLE)?; ++ let node = "apb-pclk"; ++ let clock_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_string("compatible", "fixed-clock")?; ++ fdt.set_property_string("clock-output-names", "clk24mhz")?; ++ fdt.set_property_u32("#clock-cells", 0x0)?; ++ fdt.set_property_u32("clock-frequency", 24_000_000)?; ++ fdt.set_property_u32("phandle", fdt::CLK_PHANDLE)?; ++ fdt.end_node(clock_node_dep)?; + + // psci +- let node = "/psci"; +- device_tree::add_sub_node(fdt, node)?; +- device_tree::set_property_string(fdt, node, "compatible", "arm,psci-0.2")?; +- device_tree::set_property_string(fdt, node, "method", "hvc")?; ++ let node = "psci"; ++ let psci_node_dep = fdt.begin_node(node)?; ++ fdt.set_property_string("compatible", "arm,psci-0.2")?; ++ fdt.set_property_string("method", "hvc")?; ++ fdt.end_node(psci_node_dep)?; + +- // Reversing vector is needed because FDT node is added in reverse. +- for dev in self.sysbus.devices.iter().rev() { ++ for dev in self.sysbus.devices.iter() { + let mut locked_dev = dev.lock().unwrap(); + let dev_type = locked_dev.get_type(); + let sys_res = locked_dev.get_sys_resource(); +@@ -1707,46 +1707,39 @@ impl CompileFDTHelper for LightMachine { + Ok(()) + } + +- fn generate_chosen_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { +- let node = "/chosen"; +- ++ fn generate_chosen_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { ++ let node = "chosen"; + let boot_source = self.boot_source.lock().unwrap(); + +- device_tree::add_sub_node(fdt, node)?; ++ let chosen_node_dep = fdt.begin_node(node)?; + let cmdline = &boot_source.kernel_cmdline.to_string(); +- device_tree::set_property_string(fdt, node, "bootargs", cmdline.as_str())?; ++ fdt.set_property_string("bootargs", cmdline.as_str())?; + + match &boot_source.initrd { + Some(initrd) => { +- device_tree::set_property_u64( +- fdt, +- node, +- "linux,initrd-start", +- *initrd.initrd_addr.lock().unwrap(), +- )?; +- device_tree::set_property_u64( +- fdt, +- node, ++ fdt.set_property_u64("linux,initrd-start", *initrd.initrd_addr.lock().unwrap())?; ++ fdt.set_property_u64( + "linux,initrd-end", + *initrd.initrd_addr.lock().unwrap() + initrd.initrd_size, + )?; + } + None => {} + } ++ fdt.end_node(chosen_node_dep)?; + + Ok(()) + } + } + + #[cfg(target_arch = "aarch64")] +-impl device_tree::CompileFDT for LightMachine { +- fn generate_fdt_node(&self, fdt: &mut Vec) -> util::errors::Result<()> { +- device_tree::create_device_tree(fdt)?; ++impl fdt::CompileFDT for LightMachine { ++ fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { ++ let node_dep = fdt.begin_node("")?; + +- device_tree::set_property_string(fdt, "/", "compatible", "linux,dummy-virt")?; +- device_tree::set_property_u32(fdt, "/", "#address-cells", 0x2)?; +- device_tree::set_property_u32(fdt, "/", "#size-cells", 0x2)?; +- device_tree::set_property_u32(fdt, "/", "interrupt-parent", device_tree::GIC_PHANDLE)?; ++ fdt.set_property_string("compatible", "linux,dummy-virt")?; ++ fdt.set_property_u32("#address-cells", 0x2)?; ++ fdt.set_property_u32("#size-cells", 0x2)?; ++ fdt.set_property_u32("interrupt-parent", fdt::GIC_PHANDLE)?; + + self.generate_cpu_nodes(fdt)?; + self.generate_memory_node(fdt)?; +@@ -1754,6 +1747,8 @@ impl device_tree::CompileFDT for LightMachine { + self.generate_chosen_node(fdt)?; + self.irq_chip.as_ref().unwrap().generate_fdt_node(fdt)?; + ++ fdt.end_node(node_dep)?; ++ + Ok(()) + } + } +-- +2.31.1 + diff --git a/0014-Replace-mod-device_tree-with-mod-fdt.patch b/0014-Replace-mod-device_tree-with-mod-fdt.patch new file mode 100644 index 0000000000000000000000000000000000000000..8e54f4dc06c96274dc67356728273e08d1ce7de1 --- /dev/null +++ b/0014-Replace-mod-device_tree-with-mod-fdt.patch @@ -0,0 +1,1001 @@ +From e1d0d0ef1d7de4454653a907e7f27e0c7f0185db Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Wed, 23 Jun 2021 15:24:37 +0800 +Subject: [PATCH 4/5] Replace mod device_tree with mod fdt + +Delete mod device_tree and replace the dependency +on the mod device_tree with mod fdt. What's more, +remove the compile parameter "link-arg=-lfdt" in +config to get rid of libfdt. + +Signed-off-by: Jiajie Li +--- + .cargo/config | 1 - + .../src/interrupt_controller/aarch64/gicv3.rs | 12 +- + .../src/interrupt_controller/aarch64/mod.rs | 4 +- + machine_manager/src/config/mod.rs | 4 +- + micro_vm/src/lib.rs | 37 +- + util/src/device_tree.rs | 386 +++++++++++------- + util/src/fdt.rs | 300 -------------- + util/src/lib.rs | 2 - + 8 files changed, 264 insertions(+), 482 deletions(-) + delete mode 100644 util/src/fdt.rs + +diff --git a/.cargo/config b/.cargo/config +index 0b1372f..2105adb 100644 +--- a/.cargo/config ++++ b/.cargo/config +@@ -15,5 +15,4 @@ + [target.'cfg(any(target_arch="aarch64"))'] + rustflags = [ + "-C", "link-arg=-lgcc", +- "-C", "link-arg=-lfdt", + ] +diff --git a/devices/src/interrupt_controller/aarch64/gicv3.rs b/devices/src/interrupt_controller/aarch64/gicv3.rs +index a39a3d5..08f2fd5 100644 +--- a/devices/src/interrupt_controller/aarch64/gicv3.rs ++++ b/devices/src/interrupt_controller/aarch64/gicv3.rs +@@ -14,7 +14,7 @@ use std::sync::{Arc, Mutex}; + + use kvm_ioctls::{DeviceFd, VmFd}; + use machine_manager::machine::{KvmVmState, MachineLifecycle}; +-use util::fdt::{self, FdtBuilder}; ++use util::device_tree::{self, FdtBuilder}; + + use super::{GICConfig, GICDevice, UtilResult}; + use crate::errors::{ErrorKind, Result, ResultExt}; +@@ -393,13 +393,17 @@ impl GICDevice for GICv3 { + fdt.set_property_string("compatible", "arm,gic-v3")?; + fdt.set_property("interrupt-controller", &Vec::new())?; + fdt.set_property_u32("#interrupt-cells", 0x3)?; +- fdt.set_property_u32("phandle", fdt::GIC_PHANDLE)?; ++ fdt.set_property_u32("phandle", device_tree::GIC_PHANDLE)?; + fdt.set_property_u32("#address-cells", 0x2)?; + fdt.set_property_u32("#size-cells", 0x2)?; + fdt.set_property_u32("#redistributor-regions", redist_count)?; + fdt.set_property_array_u64("reg", &gic_reg)?; + +- let gic_intr = [fdt::GIC_FDT_IRQ_TYPE_PPI, 0x9, fdt::IRQ_TYPE_LEVEL_HIGH]; ++ let gic_intr = [ ++ device_tree::GIC_FDT_IRQ_TYPE_PPI, ++ 0x9, ++ device_tree::IRQ_TYPE_LEVEL_HIGH, ++ ]; + fdt.set_property_array_u32("interrupts", &gic_intr)?; + + if let Some(its) = &self.its_dev { +@@ -409,7 +413,7 @@ impl GICDevice for GICv3 { + let its_node_dep = fdt.begin_node(node)?; + fdt.set_property_string("compatible", "arm,gic-v3-its")?; + fdt.set_property("msi-controller", &Vec::new())?; +- fdt.set_property_u32("phandle", fdt::GIC_ITS_PHANDLE)?; ++ fdt.set_property_u32("phandle", device_tree::GIC_ITS_PHANDLE)?; + fdt.set_property_array_u64("reg", &its_reg)?; + fdt.end_node(its_node_dep)?; + } +diff --git a/devices/src/interrupt_controller/aarch64/mod.rs b/devices/src/interrupt_controller/aarch64/mod.rs +index f1b40cf..ba44eb5 100644 +--- a/devices/src/interrupt_controller/aarch64/mod.rs ++++ b/devices/src/interrupt_controller/aarch64/mod.rs +@@ -19,8 +19,8 @@ use std::sync::Arc; + use kvm_ioctls::VmFd; + use machine_manager::machine::{KvmVmState, MachineLifecycle}; + use util::{ ++ device_tree::{self, FdtBuilder}, + errors::Result as UtilResult, +- fdt::{self, FdtBuilder}, + }; + + use crate::errors::{ErrorKind, Result, ResultExt}; +@@ -124,7 +124,7 @@ impl InterruptController { + } + } + +-impl fdt::CompileFDT for InterruptController { ++impl device_tree::CompileFDT for InterruptController { + fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> UtilResult<()> { + self.gic.generate_fdt(fdt)?; + Ok(()) +diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs +index 0922943..b83b9b4 100644 +--- a/machine_manager/src/config/mod.rs ++++ b/machine_manager/src/config/mod.rs +@@ -29,7 +29,7 @@ use std::str::FromStr; + use serde::{Deserialize, Serialize}; + + #[cfg(target_arch = "aarch64")] +-use util::device_tree; ++use util::device_tree::{self, FdtBuilder}; + + pub use self::errors::{ErrorKind, Result}; + pub use balloon::*; +@@ -238,7 +238,7 @@ impl VmConfig { + + #[cfg(target_arch = "aarch64")] + impl device_tree::CompileFDT for VmConfig { +- fn generate_fdt_node(&self, _fdt: &mut Vec) -> util::errors::Result<()> { ++ fn generate_fdt_node(&self, _fdt: &mut FdtBuilder) -> util::errors::Result<()> { + Ok(()) + } + } +diff --git a/micro_vm/src/lib.rs b/micro_vm/src/lib.rs +index dd6cf97..5cf7226 100644 +--- a/micro_vm/src/lib.rs ++++ b/micro_vm/src/lib.rs +@@ -109,9 +109,7 @@ use sysbus::SysBus; + #[cfg(target_arch = "aarch64")] + use sysbus::{SysBusDevType, SysRes}; + #[cfg(target_arch = "aarch64")] +-use util::device_tree; +-#[cfg(target_arch = "aarch64")] +-use util::fdt::{self, CompileFDT, FdtBuilder}; ++use util::device_tree::{self, CompileFDT, FdtBuilder}; + use util::loop_context::{ + EventLoopManager, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, + }; +@@ -1483,14 +1481,14 @@ fn generate_serial_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::erro + let serial_node_dep = fdt.begin_node(&node)?; + fdt.set_property_string("compatible", "ns16550a")?; + fdt.set_property_string("clock-names", "apb_pclk")?; +- fdt.set_property_u32("clocks", fdt::CLK_PHANDLE)?; ++ fdt.set_property_u32("clocks", device_tree::CLK_PHANDLE)?; + fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; + fdt.set_property_array_u32( + "interrupts", + &[ +- fdt::GIC_FDT_IRQ_TYPE_SPI, ++ device_tree::GIC_FDT_IRQ_TYPE_SPI, + res.irq as u32, +- fdt::IRQ_TYPE_EDGE_RISING, ++ device_tree::IRQ_TYPE_EDGE_RISING, + ], + )?; + fdt.end_node(serial_node_dep)?; +@@ -1510,14 +1508,14 @@ fn generate_rtc_device_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::errors: + let rtc_node_dep = fdt.begin_node(&node)?; + fdt.set_property_string("compatible", "arm,pl031\0arm,primecell\0")?; + fdt.set_property_string("clock-names", "apb_pclk")?; +- fdt.set_property_u32("clocks", fdt::CLK_PHANDLE)?; ++ fdt.set_property_u32("clocks", device_tree::CLK_PHANDLE)?; + fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; + fdt.set_property_array_u32( + "interrupts", + &[ +- fdt::GIC_FDT_IRQ_TYPE_SPI, ++ device_tree::GIC_FDT_IRQ_TYPE_SPI, + res.irq as u32, +- fdt::IRQ_TYPE_LEVEL_HIGH, ++ device_tree::IRQ_TYPE_LEVEL_HIGH, + ], + )?; + fdt.end_node(rtc_node_dep)?; +@@ -1536,14 +1534,14 @@ fn generate_virtio_devices_node(fdt: &mut FdtBuilder, res: &SysRes) -> util::err + let node = format!("virtio_mmio@{:x}", res.region_base); + let virtio_node_dep = fdt.begin_node(&node)?; + fdt.set_property_string("compatible", "virtio,mmio")?; +- fdt.set_property_u32("interrupt-parent", fdt::GIC_PHANDLE)?; ++ fdt.set_property_u32("interrupt-parent", device_tree::GIC_PHANDLE)?; + fdt.set_property_array_u64("reg", &[res.region_base, res.region_size])?; + fdt.set_property_array_u32( + "interrupts", + &[ +- fdt::GIC_FDT_IRQ_TYPE_SPI, ++ device_tree::GIC_FDT_IRQ_TYPE_SPI, + res.irq as u32, +- fdt::IRQ_TYPE_EDGE_RISING, ++ device_tree::IRQ_TYPE_EDGE_RISING, + ], + )?; + fdt.end_node(virtio_node_dep)?; +@@ -1633,7 +1631,10 @@ impl CompileFDTHelper for LightMachine { + + let node = format!("cpu@{:x}", mpidr); + let mpidr_node_dep = fdt.begin_node(&node)?; +- fdt.set_property_u32("phandle", u32::from(cpu_index) + fdt::CPU_PHANDLE_START)?; ++ fdt.set_property_u32( ++ "phandle", ++ u32::from(cpu_index) + device_tree::CPU_PHANDLE_START, ++ )?; + fdt.set_property_string("device_type", "cpu")?; + fdt.set_property_string("compatible", "arm,arm-v8")?; + if self.cpu_topo.max_cpus > 1 { +@@ -1665,9 +1666,9 @@ impl CompileFDTHelper for LightMachine { + // timer + let mut cells: Vec = Vec::new(); + for &irq in [13, 14, 11, 10].iter() { +- cells.push(fdt::GIC_FDT_IRQ_TYPE_PPI); ++ cells.push(device_tree::GIC_FDT_IRQ_TYPE_PPI); + cells.push(irq); +- cells.push(fdt::IRQ_TYPE_LEVEL_HIGH); ++ cells.push(device_tree::IRQ_TYPE_LEVEL_HIGH); + } + let node = "timer"; + let timer_node_dep = fdt.begin_node(node)?; +@@ -1683,7 +1684,7 @@ impl CompileFDTHelper for LightMachine { + fdt.set_property_string("clock-output-names", "clk24mhz")?; + fdt.set_property_u32("#clock-cells", 0x0)?; + fdt.set_property_u32("clock-frequency", 24_000_000)?; +- fdt.set_property_u32("phandle", fdt::CLK_PHANDLE)?; ++ fdt.set_property_u32("phandle", device_tree::CLK_PHANDLE)?; + fdt.end_node(clock_node_dep)?; + + // psci +@@ -1732,14 +1733,14 @@ impl CompileFDTHelper for LightMachine { + } + + #[cfg(target_arch = "aarch64")] +-impl fdt::CompileFDT for LightMachine { ++impl device_tree::CompileFDT for LightMachine { + fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> { + let node_dep = fdt.begin_node("")?; + + fdt.set_property_string("compatible", "linux,dummy-virt")?; + fdt.set_property_u32("#address-cells", 0x2)?; + fdt.set_property_u32("#size-cells", 0x2)?; +- fdt.set_property_u32("interrupt-parent", fdt::GIC_PHANDLE)?; ++ fdt.set_property_u32("interrupt-parent", device_tree::GIC_PHANDLE)?; + + self.generate_cpu_nodes(fdt)?; + self.generate_memory_node(fdt)?; +diff --git a/util/src/device_tree.rs b/util/src/device_tree.rs +index 120fd7c..2fdab44 100644 +--- a/util/src/device_tree.rs ++++ b/util/src/device_tree.rs +@@ -10,9 +10,10 @@ + // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + // See the Mulan PSL v2 for more details. + +-use super::errors::Result; +-use libc::{c_char, c_int, c_void}; +-use std::ffi::CString; ++use std::mem::size_of; ++ ++use crate::errors::{ErrorKind, Result, ResultExt}; ++use byteorder::{BigEndian, ByteOrder}; + + pub const CLK_PHANDLE: u32 = 1; + pub const GIC_PHANDLE: u32 = 2; +@@ -26,185 +27,257 @@ pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4; + + pub const FDT_MAX_SIZE: u32 = 0x1_0000; + +-extern "C" { +- fn fdt_create(buf: *mut c_void, bufsize: c_int) -> c_int; +- fn fdt_finish_reservemap(fdt: *mut c_void) -> c_int; +- fn fdt_begin_node(fdt: *mut c_void, name: *const c_char) -> c_int; +- fn fdt_end_node(fdt: *mut c_void) -> c_int; +- fn fdt_finish(fdt: *const c_void) -> c_int; +- fn fdt_open_into(fdt: *const c_void, buf: *mut c_void, size: c_int) -> c_int; +- +- fn fdt_path_offset(fdt: *const c_void, path: *const c_char) -> c_int; +- fn fdt_add_subnode(fdt: *mut c_void, offset: c_int, name: *const c_char) -> c_int; +- fn fdt_setprop( +- fdt: *mut c_void, +- offset: c_int, +- name: *const c_char, +- val: *const c_void, +- len: c_int, +- ) -> c_int; ++// Magic number in fdt header(big-endian). ++const FDT_MAGIC: u32 = 0xd00dfeed; ++// Fdt Header default information. ++const FDT_HEADER_SIZE: usize = 40; ++const FDT_VERSION: u32 = 17; ++const FDT_LAST_COMP_VERSION: u32 = 16; ++// Beginning token type of structure block. ++const FDT_BEGIN_NODE: u32 = 0x00000001; ++const FDT_END_NODE: u32 = 0x00000002; ++const FDT_PROP: u32 = 0x00000003; ++const FDT_END: u32 = 0x00000009; ++// Memory reservation block alignment. ++const MEM_RESERVE_ALIGNMENT: usize = 8; ++// Structure block alignment. ++const STRUCTURE_BLOCK_ALIGNMENT: usize = 4; ++ ++/// FdtBuilder structure. ++pub struct FdtBuilder { ++ /// The header of flattened device tree. ++ fdt_header: Vec, ++ /// The memory reservation block of flattened device tree. ++ /// It provides the client program with a list of areas ++ /// in physical memory which are reserved. ++ mem_reserve: Vec, ++ /// The structure block of flattened device tree. ++ /// It describes the structure and contents of the tree. ++ structure_blk: Vec, ++ /// The strings block of flattened device tree. ++ /// It contains strings representing all the property names used in the tree. ++ strings_blk: Vec, ++ /// The physical ID of the system’s boot CPU. ++ boot_cpuid_phys: u32, ++ /// The depth of nested node. ++ subnode_depth: u32, ++ /// Is there a open node or not. ++ begin_node: bool, + } + +-pub fn create_device_tree(fdt: &mut Vec) -> Result<()> { +- let mut ret = unsafe { fdt_create(fdt.as_mut_ptr() as *mut c_void, FDT_MAX_SIZE as c_int) }; +- if ret < 0 { +- bail!("Failed to fdt_create, return {}.", ret); ++/// FdtReserveEntry structure. ++#[derive(Clone, Debug)] ++pub struct FdtReserveEntry { ++ /// The address of reserved memory. ++ /// On 32-bit CPUs the upper 32-bits of the value are ignored. ++ address: u64, ++ /// The size of reserved memory. ++ size: u64, ++} ++ ++fn check_mem_reserve_overlap(mem_reservations: &[FdtReserveEntry]) -> bool { ++ if mem_reservations.len() <= 1 { ++ return true; + } + +- ret = unsafe { fdt_finish_reservemap(fdt.as_mut_ptr() as *mut c_void) }; +- if ret < 0 { +- bail!("Failed to fdt_finish_reservemap, return {}.", ret); ++ let mut mem_reser = mem_reservations.to_vec(); ++ mem_reser.sort_by_key(|m| m.address); ++ ++ for i in 0..(mem_reser.len() - 1) { ++ if mem_reser[i].address + mem_reser[i].size > mem_reser[i + 1].address { ++ return false; ++ } + } ++ true ++} ++ ++// If there is null character in string, return false. ++fn check_string_legality(s: &str) -> bool { ++ !s.contains('\0') ++} + +- let c_str = CString::new("").unwrap(); +- ret = unsafe { fdt_begin_node(fdt.as_mut_ptr() as *mut c_void, c_str.as_ptr()) }; +- if ret < 0 { +- bail!("Failed to fdt_begin_node, return {}.", ret); ++impl Default for FdtBuilder { ++ fn default() -> Self { ++ Self { ++ fdt_header: vec![0_u8; FDT_HEADER_SIZE], ++ mem_reserve: Vec::new(), ++ structure_blk: Vec::new(), ++ strings_blk: Vec::new(), ++ boot_cpuid_phys: 0, ++ subnode_depth: 0, ++ begin_node: false, ++ } + } ++} + +- ret = unsafe { fdt_end_node(fdt.as_mut_ptr() as *mut c_void) }; +- if ret < 0 { +- bail!("Failed to fdt_end_node, return {}.", ret); ++impl FdtBuilder { ++ pub fn new() -> Self { ++ FdtBuilder::default() + } + +- ret = unsafe { fdt_finish(fdt.as_mut_ptr() as *mut c_void) }; +- if ret < 0 { +- bail!("Failed to fdt_finish, return {}.", ret); ++ pub fn finish(mut self) -> Result> { ++ if self.subnode_depth > 0 { ++ return Err(ErrorKind::NodeUnclosed(self.subnode_depth).into()); ++ } ++ self.structure_blk ++ .extend_from_slice(&FDT_END.to_be_bytes()[..]); ++ ++ // According to the spec, mem_reserve blocks shall be ended ++ // with an entry where both address and size are equal to 0. ++ self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); ++ self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); ++ ++ // Fill fdt header. ++ let total_size = FDT_HEADER_SIZE ++ + self.mem_reserve.len() ++ + self.structure_blk.len() ++ + self.strings_blk.len(); ++ let off_dt_struct = FDT_HEADER_SIZE + self.mem_reserve.len(); ++ let off_dt_strings = FDT_HEADER_SIZE + self.mem_reserve.len() + self.structure_blk.len(); ++ let off_mem_rsvmap = FDT_HEADER_SIZE; ++ ++ BigEndian::write_u32(&mut self.fdt_header[0..4], FDT_MAGIC); ++ BigEndian::write_u32(&mut self.fdt_header[4..8], total_size as u32); ++ BigEndian::write_u32(&mut self.fdt_header[8..12], off_dt_struct as u32); ++ BigEndian::write_u32(&mut self.fdt_header[12..16], off_dt_strings as u32); ++ BigEndian::write_u32(&mut self.fdt_header[16..20], off_mem_rsvmap as u32); ++ BigEndian::write_u32(&mut self.fdt_header[20..24], FDT_VERSION); ++ BigEndian::write_u32(&mut self.fdt_header[24..28], FDT_LAST_COMP_VERSION); ++ BigEndian::write_u32(&mut self.fdt_header[28..32], self.boot_cpuid_phys); ++ BigEndian::write_u32(&mut self.fdt_header[32..36], self.strings_blk.len() as u32); ++ BigEndian::write_u32( ++ &mut self.fdt_header[36..40], ++ self.structure_blk.len() as u32, ++ ); ++ ++ self.fdt_header.extend_from_slice(&self.mem_reserve); ++ self.fdt_header.extend_from_slice(&self.structure_blk); ++ self.fdt_header.extend_from_slice(&self.strings_blk); ++ Ok(self.fdt_header) + } + +- ret = unsafe { +- fdt_open_into( +- fdt.as_ptr() as *mut c_void, +- fdt.as_mut_ptr() as *mut c_void, +- FDT_MAX_SIZE as c_int, +- ) +- }; +- if ret < 0 { +- bail!("Failed to fdt_open_into, return {}.", ret); ++ pub fn add_mem_reserve(&mut self, mem_reservations: &[FdtReserveEntry]) -> Result<()> { ++ if !check_mem_reserve_overlap(mem_reservations) { ++ return Err(ErrorKind::MemReserveOverlap.into()); ++ } ++ ++ for mem_reser in mem_reservations { ++ self.mem_reserve ++ .extend_from_slice(&mem_reser.address.to_be_bytes()); ++ self.mem_reserve ++ .extend_from_slice(&mem_reser.size.to_be_bytes()); ++ } ++ self.align_structure_blk(MEM_RESERVE_ALIGNMENT); ++ ++ Ok(()) + } + +- Ok(()) +-} ++ pub fn begin_node(&mut self, node_name: &str) -> Result { ++ if !check_string_legality(node_name) { ++ return Err(ErrorKind::IllegalString(node_name.to_string()).into()); ++ } + +-pub fn add_sub_node(fdt: &mut Vec, node_path: &str) -> Result<()> { +- let names: Vec<&str> = node_path.split('/').collect(); +- if names.len() < 2 { +- bail!("Failed to add sub node, node_path: {} invalid.", node_path); ++ self.structure_blk ++ .extend_from_slice(&FDT_BEGIN_NODE.to_be_bytes()[..]); ++ if node_name.is_empty() { ++ self.structure_blk ++ .extend_from_slice(&0_u32.to_be_bytes()[..]); ++ } else { ++ let mut val_array = node_name.as_bytes().to_vec(); ++ // The node’s name string should end with null('\0'). ++ val_array.push(0x0_u8); ++ self.structure_blk.extend_from_slice(&val_array); ++ } ++ self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); ++ self.subnode_depth += 1; ++ self.begin_node = true; ++ Ok(self.subnode_depth) + } + +- let node_name = names[names.len() - 1]; +- let pare_name = names[0..names.len() - 1].join("/"); ++ pub fn end_node(&mut self, begin_node_depth: u32) -> Result<()> { ++ if begin_node_depth != self.subnode_depth { ++ return Err(ErrorKind::NodeDepthMismatch(begin_node_depth, self.subnode_depth).into()); ++ } + +- let c_str = if pare_name.is_empty() { +- CString::new("/").unwrap() +- } else { +- CString::new(pare_name).unwrap() +- }; ++ self.structure_blk ++ .extend_from_slice(&FDT_END_NODE.to_be_bytes()[..]); ++ self.subnode_depth -= 1; ++ self.begin_node = false; ++ Ok(()) ++ } + +- let offset = unsafe { fdt_path_offset(fdt.as_ptr() as *const c_void, c_str.as_ptr()) }; +- if offset < 0 { +- bail!("Failed to fdt_path_offset, return {}.", offset); ++ pub fn set_boot_cpuid_phys(&mut self, boot_cpuid: u32) { ++ self.boot_cpuid_phys = boot_cpuid; + } + +- let c_str = CString::new(node_name).unwrap(); +- let ret = unsafe { fdt_add_subnode(fdt.as_mut_ptr() as *mut c_void, offset, c_str.as_ptr()) }; +- if ret < 0 { +- bail!("Failed to fdt_add_subnode, return {}.", ret); ++ pub fn set_property_string(&mut self, prop: &str, val: &str) -> Result<()> { ++ let mut val_array = val.as_bytes().to_vec(); ++ // The string property should end with null('\0'). ++ val_array.push(0x0_u8); ++ self.set_property(prop, &val_array) ++ .chain_err(|| ErrorKind::SetPropertyErr("string".to_string())) + } + +- Ok(()) +-} ++ pub fn set_property_u32(&mut self, prop: &str, val: u32) -> Result<()> { ++ self.set_property(prop, &val.to_be_bytes()[..]) ++ .chain_err(|| ErrorKind::SetPropertyErr("u32".to_string())) ++ } + +-pub fn set_property( +- fdt: &mut Vec, +- node_path: &str, +- prop: &str, +- val: Option<&[u8]>, +-) -> Result<()> { +- let c_str = CString::new(node_path).unwrap(); +- let offset = unsafe { fdt_path_offset(fdt.as_ptr() as *const c_void, c_str.as_ptr()) }; +- if offset < 0 { +- bail!("Failed to fdt_path_offset, return {}.", offset); +- } +- +- let (ptr, len) = if let Some(val) = val { +- (val.as_ptr() as *const c_void, val.len() as i32) +- } else { +- (std::ptr::null::(), 0) +- }; +- +- let c_str = CString::new(prop).unwrap(); +- let ret = unsafe { +- fdt_setprop( +- fdt.as_mut_ptr() as *mut c_void, +- offset, +- c_str.as_ptr(), +- ptr, +- len, +- ) +- }; +- if ret < 0 { +- bail!("Failed to fdt_setprop, return {}.", ret); +- } +- +- Ok(()) +-} ++ pub fn set_property_u64(&mut self, prop: &str, val: u64) -> Result<()> { ++ self.set_property(prop, &val.to_be_bytes()[..]) ++ .chain_err(|| ErrorKind::SetPropertyErr("u64".to_string())) ++ } + +-pub fn set_property_string( +- fdt: &mut Vec, +- node_path: &str, +- prop: &str, +- val: &str, +-) -> Result<()> { +- set_property( +- fdt, +- node_path, +- prop, +- Some(&([val.as_bytes(), &[0_u8]].concat())), +- ) +-} ++ pub fn set_property_array_u32(&mut self, prop: &str, array: &[u32]) -> Result<()> { ++ let mut prop_array = Vec::with_capacity(array.len() * size_of::()); ++ for element in array { ++ prop_array.extend_from_slice(&element.to_be_bytes()[..]); ++ } ++ self.set_property(prop, &prop_array) ++ .chain_err(|| ErrorKind::SetPropertyErr("u32 array".to_string())) ++ } + +-pub fn set_property_u32(fdt: &mut Vec, node_path: &str, prop: &str, val: u32) -> Result<()> { +- set_property(fdt, node_path, prop, Some(&val.to_be_bytes())) +-} ++ pub fn set_property_array_u64(&mut self, prop: &str, array: &[u64]) -> Result<()> { ++ let mut prop_array = Vec::with_capacity(array.len() * size_of::()); ++ for element in array { ++ prop_array.extend_from_slice(&element.to_be_bytes()[..]); ++ } ++ self.set_property(prop, &prop_array) ++ .chain_err(|| ErrorKind::SetPropertyErr("u64 array".to_string())) ++ } + +-pub fn set_property_u64(fdt: &mut Vec, node_path: &str, prop: &str, val: u64) -> Result<()> { +- set_property(fdt, node_path, prop, Some(&val.to_be_bytes())) +-} ++ pub fn set_property(&mut self, property_name: &str, property_val: &[u8]) -> Result<()> { ++ if !check_string_legality(property_name) { ++ return Err(ErrorKind::IllegalString(property_name.to_string()).into()); ++ } + +-pub fn set_property_array_u32( +- fdt: &mut Vec, +- node_path: &str, +- prop: &str, +- array: &[u32], +-) -> Result<()> { +- let mut bytes: Vec = Vec::new(); +- for &val in array { +- bytes.append(&mut val.to_be_bytes().to_vec()); +- } +- set_property(fdt, node_path, prop, Some(&bytes)) +-} ++ if !self.begin_node { ++ return Err(ErrorKind::IllegelPropertyPos.into()); ++ } + +-pub fn set_property_array_u64( +- fdt: &mut Vec, +- node_path: &str, +- prop: &str, +- array: &[u64], +-) -> Result<()> { +- let mut bytes: Vec = Vec::new(); +- for &val in array { +- bytes.append(&mut val.to_be_bytes().to_vec()); +- } +- set_property(fdt, node_path, prop, Some(&bytes)) +-} ++ let len = property_val.len() as u32; ++ let nameoff = self.strings_blk.len() as u32; ++ self.structure_blk ++ .extend_from_slice(&FDT_PROP.to_be_bytes()[..]); ++ self.structure_blk.extend_from_slice(&len.to_be_bytes()[..]); ++ self.structure_blk ++ .extend_from_slice(&nameoff.to_be_bytes()[..]); ++ self.structure_blk.extend_from_slice(property_val); ++ self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); + +-pub fn dump_dtb(fdt: &[u8], file_path: &str) { +- use std::fs::File; +- use std::io::Write; ++ self.strings_blk.extend_from_slice(property_name.as_bytes()); ++ // These strings in strings block should end with null('\0'). ++ self.strings_blk.extend_from_slice("\0".as_bytes()); + +- let mut f = File::create(file_path).unwrap(); +- for i in fdt.iter() { +- f.write_all(&[*i]).expect("Unable to write data"); ++ Ok(()) ++ } ++ ++ fn align_structure_blk(&mut self, alignment: usize) { ++ let remainder = self.structure_blk.len() % alignment; ++ if remainder != 0 { ++ self.structure_blk ++ .extend(vec![0_u8; (alignment - remainder) as usize]); ++ } + } + } + +@@ -215,6 +288,13 @@ pub trait CompileFDT { + /// + /// # Arguments + /// +- /// * `fdt` - the fdt slice to be expended. +- fn generate_fdt_node(&self, fdt: &mut Vec) -> Result<()>; ++ /// * `fdt` - the FdtBuilder to be filled. ++ fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()>; ++} ++ ++pub fn dump_dtb(fdt: &[u8], file_path: &str) { ++ use std::fs::File; ++ use std::io::Write; ++ let mut f = File::create(file_path).unwrap(); ++ f.write_all(fdt).expect("Unable to write data"); + } +diff --git a/util/src/fdt.rs b/util/src/fdt.rs +deleted file mode 100644 +index 2fdab44..0000000 +--- a/util/src/fdt.rs ++++ /dev/null +@@ -1,300 +0,0 @@ +-// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved. +-// +-// StratoVirt 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. +- +-use std::mem::size_of; +- +-use crate::errors::{ErrorKind, Result, ResultExt}; +-use byteorder::{BigEndian, ByteOrder}; +- +-pub const CLK_PHANDLE: u32 = 1; +-pub const GIC_PHANDLE: u32 = 2; +-pub const GIC_ITS_PHANDLE: u32 = 3; +-pub const CPU_PHANDLE_START: u32 = 10; +- +-pub const GIC_FDT_IRQ_TYPE_SPI: u32 = 0; +-pub const GIC_FDT_IRQ_TYPE_PPI: u32 = 1; +-pub const IRQ_TYPE_EDGE_RISING: u32 = 1; +-pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4; +- +-pub const FDT_MAX_SIZE: u32 = 0x1_0000; +- +-// Magic number in fdt header(big-endian). +-const FDT_MAGIC: u32 = 0xd00dfeed; +-// Fdt Header default information. +-const FDT_HEADER_SIZE: usize = 40; +-const FDT_VERSION: u32 = 17; +-const FDT_LAST_COMP_VERSION: u32 = 16; +-// Beginning token type of structure block. +-const FDT_BEGIN_NODE: u32 = 0x00000001; +-const FDT_END_NODE: u32 = 0x00000002; +-const FDT_PROP: u32 = 0x00000003; +-const FDT_END: u32 = 0x00000009; +-// Memory reservation block alignment. +-const MEM_RESERVE_ALIGNMENT: usize = 8; +-// Structure block alignment. +-const STRUCTURE_BLOCK_ALIGNMENT: usize = 4; +- +-/// FdtBuilder structure. +-pub struct FdtBuilder { +- /// The header of flattened device tree. +- fdt_header: Vec, +- /// The memory reservation block of flattened device tree. +- /// It provides the client program with a list of areas +- /// in physical memory which are reserved. +- mem_reserve: Vec, +- /// The structure block of flattened device tree. +- /// It describes the structure and contents of the tree. +- structure_blk: Vec, +- /// The strings block of flattened device tree. +- /// It contains strings representing all the property names used in the tree. +- strings_blk: Vec, +- /// The physical ID of the system’s boot CPU. +- boot_cpuid_phys: u32, +- /// The depth of nested node. +- subnode_depth: u32, +- /// Is there a open node or not. +- begin_node: bool, +-} +- +-/// FdtReserveEntry structure. +-#[derive(Clone, Debug)] +-pub struct FdtReserveEntry { +- /// The address of reserved memory. +- /// On 32-bit CPUs the upper 32-bits of the value are ignored. +- address: u64, +- /// The size of reserved memory. +- size: u64, +-} +- +-fn check_mem_reserve_overlap(mem_reservations: &[FdtReserveEntry]) -> bool { +- if mem_reservations.len() <= 1 { +- return true; +- } +- +- let mut mem_reser = mem_reservations.to_vec(); +- mem_reser.sort_by_key(|m| m.address); +- +- for i in 0..(mem_reser.len() - 1) { +- if mem_reser[i].address + mem_reser[i].size > mem_reser[i + 1].address { +- return false; +- } +- } +- true +-} +- +-// If there is null character in string, return false. +-fn check_string_legality(s: &str) -> bool { +- !s.contains('\0') +-} +- +-impl Default for FdtBuilder { +- fn default() -> Self { +- Self { +- fdt_header: vec![0_u8; FDT_HEADER_SIZE], +- mem_reserve: Vec::new(), +- structure_blk: Vec::new(), +- strings_blk: Vec::new(), +- boot_cpuid_phys: 0, +- subnode_depth: 0, +- begin_node: false, +- } +- } +-} +- +-impl FdtBuilder { +- pub fn new() -> Self { +- FdtBuilder::default() +- } +- +- pub fn finish(mut self) -> Result> { +- if self.subnode_depth > 0 { +- return Err(ErrorKind::NodeUnclosed(self.subnode_depth).into()); +- } +- self.structure_blk +- .extend_from_slice(&FDT_END.to_be_bytes()[..]); +- +- // According to the spec, mem_reserve blocks shall be ended +- // with an entry where both address and size are equal to 0. +- self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); +- self.mem_reserve.extend_from_slice(&0_u64.to_be_bytes()); +- +- // Fill fdt header. +- let total_size = FDT_HEADER_SIZE +- + self.mem_reserve.len() +- + self.structure_blk.len() +- + self.strings_blk.len(); +- let off_dt_struct = FDT_HEADER_SIZE + self.mem_reserve.len(); +- let off_dt_strings = FDT_HEADER_SIZE + self.mem_reserve.len() + self.structure_blk.len(); +- let off_mem_rsvmap = FDT_HEADER_SIZE; +- +- BigEndian::write_u32(&mut self.fdt_header[0..4], FDT_MAGIC); +- BigEndian::write_u32(&mut self.fdt_header[4..8], total_size as u32); +- BigEndian::write_u32(&mut self.fdt_header[8..12], off_dt_struct as u32); +- BigEndian::write_u32(&mut self.fdt_header[12..16], off_dt_strings as u32); +- BigEndian::write_u32(&mut self.fdt_header[16..20], off_mem_rsvmap as u32); +- BigEndian::write_u32(&mut self.fdt_header[20..24], FDT_VERSION); +- BigEndian::write_u32(&mut self.fdt_header[24..28], FDT_LAST_COMP_VERSION); +- BigEndian::write_u32(&mut self.fdt_header[28..32], self.boot_cpuid_phys); +- BigEndian::write_u32(&mut self.fdt_header[32..36], self.strings_blk.len() as u32); +- BigEndian::write_u32( +- &mut self.fdt_header[36..40], +- self.structure_blk.len() as u32, +- ); +- +- self.fdt_header.extend_from_slice(&self.mem_reserve); +- self.fdt_header.extend_from_slice(&self.structure_blk); +- self.fdt_header.extend_from_slice(&self.strings_blk); +- Ok(self.fdt_header) +- } +- +- pub fn add_mem_reserve(&mut self, mem_reservations: &[FdtReserveEntry]) -> Result<()> { +- if !check_mem_reserve_overlap(mem_reservations) { +- return Err(ErrorKind::MemReserveOverlap.into()); +- } +- +- for mem_reser in mem_reservations { +- self.mem_reserve +- .extend_from_slice(&mem_reser.address.to_be_bytes()); +- self.mem_reserve +- .extend_from_slice(&mem_reser.size.to_be_bytes()); +- } +- self.align_structure_blk(MEM_RESERVE_ALIGNMENT); +- +- Ok(()) +- } +- +- pub fn begin_node(&mut self, node_name: &str) -> Result { +- if !check_string_legality(node_name) { +- return Err(ErrorKind::IllegalString(node_name.to_string()).into()); +- } +- +- self.structure_blk +- .extend_from_slice(&FDT_BEGIN_NODE.to_be_bytes()[..]); +- if node_name.is_empty() { +- self.structure_blk +- .extend_from_slice(&0_u32.to_be_bytes()[..]); +- } else { +- let mut val_array = node_name.as_bytes().to_vec(); +- // The node’s name string should end with null('\0'). +- val_array.push(0x0_u8); +- self.structure_blk.extend_from_slice(&val_array); +- } +- self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); +- self.subnode_depth += 1; +- self.begin_node = true; +- Ok(self.subnode_depth) +- } +- +- pub fn end_node(&mut self, begin_node_depth: u32) -> Result<()> { +- if begin_node_depth != self.subnode_depth { +- return Err(ErrorKind::NodeDepthMismatch(begin_node_depth, self.subnode_depth).into()); +- } +- +- self.structure_blk +- .extend_from_slice(&FDT_END_NODE.to_be_bytes()[..]); +- self.subnode_depth -= 1; +- self.begin_node = false; +- Ok(()) +- } +- +- pub fn set_boot_cpuid_phys(&mut self, boot_cpuid: u32) { +- self.boot_cpuid_phys = boot_cpuid; +- } +- +- pub fn set_property_string(&mut self, prop: &str, val: &str) -> Result<()> { +- let mut val_array = val.as_bytes().to_vec(); +- // The string property should end with null('\0'). +- val_array.push(0x0_u8); +- self.set_property(prop, &val_array) +- .chain_err(|| ErrorKind::SetPropertyErr("string".to_string())) +- } +- +- pub fn set_property_u32(&mut self, prop: &str, val: u32) -> Result<()> { +- self.set_property(prop, &val.to_be_bytes()[..]) +- .chain_err(|| ErrorKind::SetPropertyErr("u32".to_string())) +- } +- +- pub fn set_property_u64(&mut self, prop: &str, val: u64) -> Result<()> { +- self.set_property(prop, &val.to_be_bytes()[..]) +- .chain_err(|| ErrorKind::SetPropertyErr("u64".to_string())) +- } +- +- pub fn set_property_array_u32(&mut self, prop: &str, array: &[u32]) -> Result<()> { +- let mut prop_array = Vec::with_capacity(array.len() * size_of::()); +- for element in array { +- prop_array.extend_from_slice(&element.to_be_bytes()[..]); +- } +- self.set_property(prop, &prop_array) +- .chain_err(|| ErrorKind::SetPropertyErr("u32 array".to_string())) +- } +- +- pub fn set_property_array_u64(&mut self, prop: &str, array: &[u64]) -> Result<()> { +- let mut prop_array = Vec::with_capacity(array.len() * size_of::()); +- for element in array { +- prop_array.extend_from_slice(&element.to_be_bytes()[..]); +- } +- self.set_property(prop, &prop_array) +- .chain_err(|| ErrorKind::SetPropertyErr("u64 array".to_string())) +- } +- +- pub fn set_property(&mut self, property_name: &str, property_val: &[u8]) -> Result<()> { +- if !check_string_legality(property_name) { +- return Err(ErrorKind::IllegalString(property_name.to_string()).into()); +- } +- +- if !self.begin_node { +- return Err(ErrorKind::IllegelPropertyPos.into()); +- } +- +- let len = property_val.len() as u32; +- let nameoff = self.strings_blk.len() as u32; +- self.structure_blk +- .extend_from_slice(&FDT_PROP.to_be_bytes()[..]); +- self.structure_blk.extend_from_slice(&len.to_be_bytes()[..]); +- self.structure_blk +- .extend_from_slice(&nameoff.to_be_bytes()[..]); +- self.structure_blk.extend_from_slice(property_val); +- self.align_structure_blk(STRUCTURE_BLOCK_ALIGNMENT); +- +- self.strings_blk.extend_from_slice(property_name.as_bytes()); +- // These strings in strings block should end with null('\0'). +- self.strings_blk.extend_from_slice("\0".as_bytes()); +- +- Ok(()) +- } +- +- fn align_structure_blk(&mut self, alignment: usize) { +- let remainder = self.structure_blk.len() % alignment; +- if remainder != 0 { +- self.structure_blk +- .extend(vec![0_u8; (alignment - remainder) as usize]); +- } +- } +-} +- +-/// Trait for devices to be added to the Flattened Device Tree. +-#[allow(clippy::upper_case_acronyms)] +-pub trait CompileFDT { +- /// function to generate fdt node +- /// +- /// # Arguments +- /// +- /// * `fdt` - the FdtBuilder to be filled. +- fn generate_fdt_node(&self, fdt: &mut FdtBuilder) -> Result<()>; +-} +- +-pub fn dump_dtb(fdt: &[u8], file_path: &str) { +- use std::fs::File; +- use std::io::Write; +- let mut f = File::create(file_path).unwrap(); +- f.write_all(fdt).expect("Unable to write data"); +-} +diff --git a/util/src/lib.rs b/util/src/lib.rs +index d135c74..2c59065 100644 +--- a/util/src/lib.rs ++++ b/util/src/lib.rs +@@ -28,8 +28,6 @@ pub mod checksum; + pub mod daemonize; + #[cfg(target_arch = "aarch64")] + pub mod device_tree; +-#[cfg(target_arch = "aarch64")] +-pub mod fdt; + pub mod leak_bucket; + mod link_list; + pub mod loop_context; +-- +2.31.1 + diff --git a/0015-util-fdt-add-some-UT-test-cases.patch b/0015-util-fdt-add-some-UT-test-cases.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad9b44d8ebb5ab43ac01842408beb585759c40de --- /dev/null +++ b/0015-util-fdt-add-some-UT-test-cases.patch @@ -0,0 +1,220 @@ +From 1081b4f57b1bc959fa5e26a1e6520f1cfbf999b0 Mon Sep 17 00:00:00 2001 +From: Jiajie Li +Date: Thu, 24 Jun 2021 16:15:48 +0800 +Subject: [PATCH 5/5] util/fdt: add some UT test cases + +Test the basic function of mod fdt, like adding all kinds +of properties for fdt node, adding nested node, getting the +final result. What's more, add some boundary test cases. + +Signed-off-by: Jiajie Li +--- + util/src/device_tree.rs | 195 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 195 insertions(+) + +diff --git a/util/src/device_tree.rs b/util/src/device_tree.rs +index 2fdab44..d47b7f5 100644 +--- a/util/src/device_tree.rs ++++ b/util/src/device_tree.rs +@@ -298,3 +298,198 @@ pub fn dump_dtb(fdt: &[u8], file_path: &str) { + let mut f = File::create(file_path).unwrap(); + f.write_all(fdt).expect("Unable to write data"); + } ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ ++ #[test] ++ fn test_add_all_properties() { ++ let mut fdt_builder = FdtBuilder::new(); ++ let root_node = fdt_builder.begin_node("").unwrap(); ++ fdt_builder.set_property("null", &[]).unwrap(); ++ fdt_builder.set_property_u32("u32", 0x01234567).unwrap(); ++ fdt_builder ++ .set_property_u64("u64", 0x0123456789abcdef) ++ .unwrap(); ++ fdt_builder ++ .set_property_array_u32( ++ "u32_array", ++ &vec![0x11223344, 0x55667788, 0x99aabbcc, 0xddeeff00], ++ ) ++ .unwrap(); ++ fdt_builder ++ .set_property_array_u64("u64_array", &vec![0x0011223344556677, 0x8899aabbccddeeff]) ++ .unwrap(); ++ fdt_builder ++ .set_property_string("string", "hello fdt") ++ .unwrap(); ++ fdt_builder.end_node(root_node).unwrap(); ++ let right_fdt: Vec = vec![ ++ 0xd0, 0x0d, 0xfe, 0xed, // 00: magic (0xd00dfeed) ++ 0x00, 0x00, 0x00, 0xf0, // 04: totalsize (0xf0) ++ 0x00, 0x00, 0x00, 0x38, // 08: off_dt_struct (0x38) ++ 0x00, 0x00, 0x00, 0xc8, // 0c: off_dt_strings (0xc8) ++ 0x00, 0x00, 0x00, 0x28, // 10: off_mem_rsvmap (0x28) ++ 0x00, 0x00, 0x00, 0x11, // 14: version (17) ++ 0x00, 0x00, 0x00, 0x10, // 18: last_comp_version (16) ++ 0x00, 0x00, 0x00, 0x00, // 1c: boot_cpuid_phys (0) ++ 0x00, 0x00, 0x00, 0x28, // 20: size_dt_strings (0x28) ++ 0x00, 0x00, 0x00, 0x90, // 24: size_dt_struct (0x90) ++ 0x00, 0x00, 0x00, 0x00, // 28: high address of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x00, // 2c: low address of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x00, // 30: high size of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x00, // 34: low size of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x01, // 38: FDT_BEGIN_NODE ++ 0x00, 0x00, 0x00, 0x00, // 3c: node name ("") with 4-byte alignment ++ 0x00, 0x00, 0x00, 0x03, // 40: FDT_PROP ("null") ++ 0x00, 0x00, 0x00, 0x00, // 44: property len (0) ++ 0x00, 0x00, 0x00, 0x00, // 48: property nameoff (0x00) ++ 0x00, 0x00, 0x00, 0x03, // 4c: FDT_PROP ("u32") ++ 0x00, 0x00, 0x00, 0x04, // 50: property len (4) ++ 0x00, 0x00, 0x00, 0x05, // 54: property nameoff (0x05) ++ 0x01, 0x23, 0x45, 0x67, // 58: property’s value (0x01234567) ++ 0x00, 0x00, 0x00, 0x03, // 5c: FDT_PROP ("u64") ++ 0x00, 0x00, 0x00, 0x08, // 60: property len (8) ++ 0x00, 0x00, 0x00, 0x09, // 64: property nameoff (0x09) ++ 0x01, 0x23, 0x45, 0x67, // 68: property’s value (0x01234567) ++ 0x89, 0xab, 0xcd, 0xef, // 6c: property’s value (0x89abcdef) ++ 0x00, 0x00, 0x00, 0x03, // 70: FDT_PROP ("u32_array") ++ 0x00, 0x00, 0x00, 0x10, // 74: property len (16) ++ 0x00, 0x00, 0x00, 0x0d, // 78: property nameoff (0x0d) ++ 0x11, 0x22, 0x33, 0x44, // 7c: property’s value (0x11223344) ++ 0x55, 0x66, 0x77, 0x88, // 80: property’s value (0x55667788) ++ 0x99, 0xaa, 0xbb, 0xcc, // 84: property’s value (0x99aabbcc) ++ 0xdd, 0xee, 0xff, 0x00, // 88: property’s value (0xddeeff00) ++ 0x00, 0x00, 0x00, 0x03, // 8c: FDT_PROP ("u64_array") ++ 0x00, 0x00, 0x00, 0x10, // 90: property len (16) ++ 0x00, 0x00, 0x00, 0x17, // 94: property nameoff (0x17) ++ 0x00, 0x11, 0x22, 0x33, // 98: property’s value (0x00112233) ++ 0x44, 0x55, 0x66, 0x77, // 9c: property’s value (0x44556677) ++ 0x88, 0x99, 0xaa, 0xbb, // a0: property’s value (0x8899aabb) ++ 0xcc, 0xdd, 0xee, 0xff, // a4: property’s value (0xccddeeff) ++ 0x00, 0x00, 0x00, 0x03, // a8: FDT_PROP ("string") ++ 0x00, 0x00, 0x00, 0x0a, // ac: property len (10) ++ 0x00, 0x00, 0x00, 0x21, // b0: property nameoff (0x21) ++ b'h', b'e', b'l', b'l', // b4: property’s value ("hell") ++ b'o', b' ', b'f', b'd', // b8: property’s value ("o fd") ++ b't', b'\0', 0x00, 0x00, // bc: property’s value ("t\0" with padding) ++ 0x00, 0x00, 0x00, 0x02, // c0: FDT_END_NODE ++ 0x00, 0x00, 0x00, 0x09, // c4: FDT_END ++ b'n', b'u', b'l', b'l', b'\0', // c8: "null" with offset 0x00 ++ b'u', b'3', b'2', b'\0', // cd: "u32" with offset 0x05 ++ b'u', b'6', b'4', b'\0', // d1: "u64" with offset 0x09 ++ b'u', b'3', b'2', b'_', b'a', b'r', b'r', b'a', b'y', ++ b'\0', // d5: "u32_array" with offset 0x0d ++ b'u', b'6', b'4', b'_', b'a', b'r', b'r', b'a', b'y', ++ b'\0', // df: "u64_array" with offset 0x17 ++ b's', b't', b'r', b'i', b'n', b'g', b'\0', // e9: "string" with offset 0x21 ++ ]; ++ let sample_fdt = fdt_builder.finish().unwrap(); ++ assert_eq!(right_fdt, sample_fdt); ++ } ++ ++ #[test] ++ fn test_nested_node() { ++ let mut fdt_builder = FdtBuilder::new(); ++ let root_node = fdt_builder.begin_node("").unwrap(); ++ ++ let cpus_node = fdt_builder.begin_node("cpus").unwrap(); ++ fdt_builder.set_property_u32("addrcells", 0x02).unwrap(); ++ fdt_builder.set_property_u32("sizecells", 0x0).unwrap(); ++ ++ let cpu_map_node = fdt_builder.begin_node("cpu-map").unwrap(); ++ fdt_builder.set_property_u32("cpu", 10).unwrap(); ++ ++ fdt_builder.end_node(cpu_map_node).unwrap(); ++ fdt_builder.end_node(cpus_node).unwrap(); ++ fdt_builder.end_node(root_node).unwrap(); ++ ++ fdt_builder.set_boot_cpuid_phys(1); ++ ++ let right_fdt: Vec = vec![ ++ 0xd0, 0x0d, 0xfe, 0xed, // 00: magic (0xd00dfeed) ++ 0x00, 0x00, 0x00, 0xb0, // 04: totalsize (0xb0) ++ 0x00, 0x00, 0x00, 0x38, // 08: off_dt_struct (0x38) ++ 0x00, 0x00, 0x00, 0x98, // 0c: off_dt_strings (0x98) ++ 0x00, 0x00, 0x00, 0x28, // 10: off_mem_rsvmap (0x28) ++ 0x00, 0x00, 0x00, 0x11, // 14: version (17) ++ 0x00, 0x00, 0x00, 0x10, // 18: last_comp_version (16) ++ 0x00, 0x00, 0x00, 0x01, // 1c: boot_cpuid_phys (1) ++ 0x00, 0x00, 0x00, 0x18, // 20: size_dt_strings (0x18) ++ 0x00, 0x00, 0x00, 0x60, // 24: size_dt_struct (0x60) ++ 0x00, 0x00, 0x00, 0x00, // 28: high address of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x00, // 2c: low address of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x00, // 30: high size of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x00, // 34: low size of memory reservation block terminator ++ 0x00, 0x00, 0x00, 0x01, // 38: FDT_BEGIN_NODE ++ 0x00, 0x00, 0x00, 0x00, // 3c: node name ("") ++ 0x00, 0x00, 0x00, 0x01, // 40: FDT_BEGIN_NODE ++ b'c', b'p', b'u', b's', // 44: node name ("cpus") with 4-byte alignment ++ b'\0', 0x00, 0x00, 0x00, // 48: padding ++ 0x00, 0x00, 0x00, 0x03, // 4c: FDT_PROP ("addrcells") ++ 0x00, 0x00, 0x00, 0x04, // 50: property len (4) ++ 0x00, 0x00, 0x00, 0x00, // 54: property nameoff (0x00) ++ 0x00, 0x00, 0x00, 0x02, // 58: property’s value (0x02) ++ 0x00, 0x00, 0x00, 0x03, // 5c: FDT_PROP ("sizecells") ++ 0x00, 0x00, 0x00, 0x04, // 60: property len (4) ++ 0x00, 0x00, 0x00, 0x0a, // 64: property nameoff (0xa) ++ 0x00, 0x00, 0x00, 0x00, // 68: property’s value (0x0) ++ 0x00, 0x00, 0x00, 0x01, // 6c: FDT_BEGIN_NODE ++ b'c', b'p', b'u', b'-', // 70: node name ("cpu-map") ++ b'm', b'a', b'p', b'\0', // 74: node name ("cpu-map") ++ 0x00, 0x00, 0x00, 0x03, // 78: FDT_PROP ("cpu") ++ 0x00, 0x00, 0x00, 0x04, // 7c: property len (4) ++ 0x00, 0x00, 0x00, 0x14, // 80: property nameoff (0x14) ++ 0x00, 0x00, 0x00, 0x0a, // 84: property’s value (10) ++ 0x00, 0x00, 0x00, 0x02, // 88: FDT_END_NODE ++ 0x00, 0x00, 0x00, 0x02, // 8c: FDT_END_NODE ++ 0x00, 0x00, 0x00, 0x02, // 90: FDT_END_NODE ++ 0x00, 0x00, 0x00, 0x09, // 94: FDT_END ++ b'a', b'd', b'd', b'r', b'c', b'e', b'l', b'l', b's', ++ b'\0', // 98: "addrcells" with offset 0x00 ++ b's', b'i', b'z', b'e', b'c', b'e', b'l', b'l', b's', ++ b'\0', // a2: "sizecells" with offset 0x0a ++ b'c', b'p', b'u', b'\0', // ac: "cpu" with offset 0x14 ++ ]; ++ let sample_fdt = fdt_builder.finish().unwrap(); ++ assert_eq!(right_fdt, sample_fdt); ++ } ++ ++ #[test] ++ fn test_illegeal_string() { ++ let mut fdt_builder = FdtBuilder::new(); ++ assert!(fdt_builder.begin_node("bad\0string").is_err()); ++ ++ fdt_builder.begin_node("good string").unwrap(); ++ assert!(fdt_builder.set_property("bad property\0name", &[]).is_err()); ++ assert!(fdt_builder ++ .set_property_string("good property name", "test\0val") ++ .is_ok()); ++ } ++ ++ #[test] ++ fn test_unclose_nested_node() { ++ let mut fdt_builder = FdtBuilder::new(); ++ let root_node = fdt_builder.begin_node("").unwrap(); ++ fdt_builder.begin_node("nested node").unwrap(); ++ assert!(fdt_builder.end_node(root_node).is_err()); ++ assert!(fdt_builder.finish().is_err()); ++ } ++ ++ #[test] ++ fn test_mem_reserve_overlap() { ++ let mut fdt_builder = FdtBuilder::new(); ++ let mem_reservations = [ ++ FdtReserveEntry { ++ address: 0x100, ++ size: 0x100, ++ }, ++ FdtReserveEntry { ++ address: 0x150, ++ size: 0x100, ++ }, ++ ]; ++ assert!(fdt_builder.add_mem_reserve(&mem_reservations).is_err()); ++ } ++} +-- +2.31.1 + diff --git a/stratovirt.spec b/stratovirt.spec index 284d261f84fca68d3400f8878c14e285689cfd17..dc957c3f22b68e248aa712d25119cba993a304d8 100644 --- a/stratovirt.spec +++ b/stratovirt.spec @@ -6,7 +6,7 @@ Name: stratovirt Version: 0.3.0 -Release: 4 +Release: 5 Summary: StratoVirt is an opensource VMM(Virtual Machine Manager) which aims to perform next generation virtualization. License: Mulan PSL v2 @@ -23,6 +23,12 @@ Patch0007: 0007-testcases-virtio_blk-decrease-hot-plugged-blk-number.patch Patch0008: 0008-testscases-vmlife-decrease-test-blk-number.patch Patch0009: 0009-README-update-readme.patch Patch0010: 0010-docs-add-IMAGE_BUILD.md.patch +Patch0011: 0011-util-fdt-implement-basic-fdt-API.patch +Patch0012: 0012-devices-gicv3-use-mod-fdt-instead-of-device_tree.patch +Patch0013: 0013-machine-micro_vm-use-fdt-API-of-mod-fdt-instead-of-d.patch +Patch0014: 0014-Replace-mod-device_tree-with-mod-fdt.patch +Patch0015: 0015-util-fdt-add-some-UT-test-cases.patch + ExclusiveArch: x86_64 aarch64 @@ -55,11 +61,19 @@ Summary: %{summary} %build +%ifarch aarch64 +sed -i '/\[build\]/a target="aarch64-unknown-linux-musl"' ./.cargo/config +%endif + +%ifarch x86_64 +sed -i '/\[build\]/a target="x86_64-unknown-linux-musl"' ./.cargo/config +%endif + sed -i '/\[source.crates-io\]/{n;d}' ./.cargo/config sed -i '/\[source.local-registry\]/{n;d}' ./.cargo/config sed -i '/\[source.local-registry\]/a directory = "vendor"' ./.cargo/config %ifarch aarch64 -sed -i 's/rustflags = \[/rustflags = \["-Clink-arg=-lgcc", "-Clink-arg=-lfdt", /g' ./.cargo/config +sed -i 's/rustflags = \[/rustflags = \["-Clink-arg=-lgcc", /g' ./.cargo/config %endif %cargo_build -a @@ -69,6 +83,12 @@ sed -i 's/rustflags = \[/rustflags = \["-Clink-arg=-lgcc", "-Clink-arg=-lfdt", / chmod 550 ${RPM_BUILD_ROOT}/usr/bin/stratovirt %changelog +* Tue Jul 27 2021 XuFei - 0.3.0-5 +- Type:NA +- ID:NA +- SUG:NA +- DESC:add fdt patches for musl compilation + * Wed Jun 16 2021 XuFei - 0.3.0-4 - Type:NA - ID:NA