mirror of
git://nv-tegra.nvidia.com/3rdparty/dtc-src/1.4.5.git
synced 2025-12-22 09:12:08 +03:00
Compare commits
25 Commits
jetson_38.
...
jetson_36.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76525e9afc | ||
|
|
26c9c43ea4 | ||
|
|
8ca3c104dd | ||
|
|
9b78b2a62e | ||
|
|
48475d4bc7 | ||
|
|
2cc61f91f2 | ||
|
|
7f5d0c7d23 | ||
|
|
1d7e7285d0 | ||
|
|
73374601a1 | ||
|
|
76eb3c1da4 | ||
|
|
f5d1e4d4ed | ||
|
|
cdbb83e8ff | ||
|
|
dda1ec1510 | ||
|
|
289f83bd20 | ||
|
|
079ce808e2 | ||
|
|
96698332d5 | ||
|
|
b5444064c1 | ||
|
|
dd33e569f5 | ||
|
|
7b904d57ee | ||
|
|
9bd10333ce | ||
|
|
2ec01bddac | ||
|
|
a5c14e66ad | ||
|
|
bcbee0f50a | ||
|
|
84ad287a98 | ||
|
|
92b3051bcc |
268
commitFile.txt
Normal file
268
commitFile.txt
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
Updating prebuilts and/or headers
|
||||||
|
|
||||||
|
dfac199a7539a404407098a2541b9482279f690d - dtc-1.4.5/GPL
|
||||||
|
688431c05a68fedfcb7a36fb482a952d75b05a75 - dtc-1.4.5/Makefile
|
||||||
|
a4555a920b020b1bb06ca45224d692c0094362c1 - dtc-1.4.5/fdtoverlay.c
|
||||||
|
81ec523838a03a9f6e95e6e6b4a57a0a2b81620a - dtc-1.4.5/.gitignore
|
||||||
|
d525dcaa04b47f205c8cb69936399691e89b1fbb - dtc-1.4.5/README
|
||||||
|
29d5b51f10d7874704f2faaf9741d793e973a8ba - dtc-1.4.5/fdtget.c
|
||||||
|
db29d7f8b36abb5ab1d3c0ff25a2e056cbb7471e - dtc-1.4.5/flattree.c
|
||||||
|
cab130d5213077509e3b7c88fb99c589945625f1 - dtc-1.4.5/fdtput.c
|
||||||
|
e6060b19e275bde4187546231ba289a486d987e9 - dtc-1.4.5/README.license
|
||||||
|
95a16c709f1da90f55607005158862d34bd777ca - dtc-1.4.5/data.c
|
||||||
|
01c714a2f40e85b39871ff83605edbf2078ffe57 - dtc-1.4.5/srcpos.c
|
||||||
|
3c3ab9789cf4a6bce3448e8fbfdc9f2df2bd2aff - dtc-1.4.5/treesource.c
|
||||||
|
aa5cc18bcc85135e1d2a053a9ee8a3c40fc6ae7b - dtc-1.4.5/dtdiff
|
||||||
|
ebfc1d387c8ae94200e421549e1a301add720c66 - dtc-1.4.5/dtc.c
|
||||||
|
ce3d01a2829cf142f32579b9b429c0a53fc27bdb - dtc-1.4.5/dtc-lexer.l
|
||||||
|
53a52ecbb1b16bf144144f68c5e681f9554ff862 - dtc-1.4.5/util.h
|
||||||
|
e565c2b61d5c44d608b35f52a321ea68ccc794b0 - dtc-1.4.5/dtc-parser.y
|
||||||
|
453c878d681e2e6bbfec2a0b522e7e05e2363056 - dtc-1.4.5/checks.c
|
||||||
|
a39cc082f177f5f833b7fbfa2a35f8ca88f41826 - dtc-1.4.5/Makefile.dtc
|
||||||
|
edc3f2659d0771955ddea5e11f6d4d8b73dbd85b - dtc-1.4.5/.travis.yml
|
||||||
|
0cb72d7f3aeaee1cb122bac3c9d4c2227725b8f0 - dtc-1.4.5/fstree.c
|
||||||
|
e5147ec0a4049d9551c81c703e5fd4d51db8f366 - dtc-1.4.5/Makefile.convert-dtsv0
|
||||||
|
5ea9fc651c441c3cd5a381092581ed691dc49d5d - dtc-1.4.5/fdtdump.c
|
||||||
|
ce99f6374471fc140add69b0c86f623b4fe23186 - dtc-1.4.5/util.c
|
||||||
|
597d528effbe428cb6bacc6d4a4d093644e3fbd4 - dtc-1.4.5/dtc.h
|
||||||
|
cc0e7e5a498451c733e735ed95db6c2591aaf868 - dtc-1.4.5/Makefile.utils
|
||||||
|
25ae5e897cd351320137faa6577f11cf585f32da - dtc-1.4.5/srcpos.h
|
||||||
|
c56abdacfd7fe1144c6e68e7b1d0465e66e1545b - dtc-1.4.5/TODO
|
||||||
|
2c9a841513149efc0f5234215752b58b1c93a0f6 - dtc-1.4.5/convert-dtsv0-lexer.l
|
||||||
|
2e76fbfb41b15c4a60f2479eb1657308d4a024e1 - dtc-1.4.5/livetree.c
|
||||||
|
23dae1b1e6d96cbf7557ceac42bfa1cf13936ad5 - dtc-1.4.5/libfdt/fdt_wip.c
|
||||||
|
cb6dd625a5f8e41e0a0312c2bed4ba2167e62750 - dtc-1.4.5/libfdt/fdt_ro.c
|
||||||
|
2eb4a858b80211c6b700414b37b3ba1d9558ace1 - dtc-1.4.5/libfdt/fdt.h
|
||||||
|
9a1e89e0a6ad35bb3463e3a3f87dd7626d918c20 - dtc-1.4.5/libfdt/fdt_overlay.c
|
||||||
|
ebadc1eeeb3e463427b13de190569c9ca3849c27 - dtc-1.4.5/libfdt/fdt_rw.c
|
||||||
|
cb09ff924d581148c98dce072ecdaee4c5f289cd - dtc-1.4.5/libfdt/fdt.c
|
||||||
|
09a844c8978591b0af11e81928b851d4599a40fa - dtc-1.4.5/libfdt/fdt_empty_tree.c
|
||||||
|
a288dd3281a869616871849278224af702129e47 - dtc-1.4.5/libfdt/libfdt_env.h
|
||||||
|
e1c374080fc1e9f2101102f8aeb356082fe370c8 - dtc-1.4.5/libfdt/fdt_strerror.c
|
||||||
|
e49c8031e598fa2956bb26367570d8c06745367f - dtc-1.4.5/libfdt/fdt_sw.c
|
||||||
|
9332862189cd63c6d7e7e80c6b67446181fdd4c4 - dtc-1.4.5/libfdt/libfdt_internal.h
|
||||||
|
b929dc832e5ad67a6027aa0fdb3d39868f10125e - dtc-1.4.5/libfdt/Makefile.libfdt
|
||||||
|
431fd6a95e97ff1fec779f086cf35833c2bc33dd - dtc-1.4.5/libfdt/fdt_addresses.c
|
||||||
|
31ae7f44847e5a4e4a207f182dbb80f8714ec510 - dtc-1.4.5/libfdt/version.lds
|
||||||
|
f88a9a1f847941e4e8d8cd75b8337251c2ac8a1b - dtc-1.4.5/libfdt/libfdt.h
|
||||||
|
96d83160ed4341696adae458a154984eec3c7dfc - dtc-1.4.5/libfdt/TODO
|
||||||
|
628865d7616d254cc4c7996d1e972842ad922d98 - dtc-1.4.5/scripts/kup-dtc
|
||||||
|
2a320e30ee21461af08bb76f4051052044441de8 - dtc-1.4.5/scripts/setlocalversion
|
||||||
|
5b6353ff199345f7dde7fd8dcaaf32441befef95 - dtc-1.4.5/tests/obsolete-chosen-interrupt-controller.dts
|
||||||
|
1a13a82806e74da0fe7e39587e6bb9d6323d0012 - dtc-1.4.5/tests/truncated_property.c
|
||||||
|
e04703bdbb788f6f519059006d11a04c66c2d4e9 - dtc-1.4.5/tests/nonexist-label-ref.dts
|
||||||
|
6fb4a06a4267d2efe200ba82a2516817c70e7338 - dtc-1.4.5/tests/boot-cpuid.c
|
||||||
|
7e60aa8d9e1d0fc859d83bb287b12c7884b51d54 - dtc-1.4.5/tests/minusone-phandle.dts
|
||||||
|
a92ee30ee224515ec9e74dd392d22f1c370583c1 - dtc-1.4.5/tests/test_tree1_wrong4.dts
|
||||||
|
17a04207b4941b17fd362cb2e4cd958e3e74ad91 - dtc-1.4.5/tests/test01.dts
|
||||||
|
b1ee15fb5ad66b865f12e6994c4c8cd8ff125d57 - dtc-1.4.5/tests/dtbs_equal_ordered.c
|
||||||
|
dc4372a1ce8bf6a8175133dbc747b8e5802ef767 - dtc-1.4.5/tests/bad-gpio.dts
|
||||||
|
e597380112f351dc1d96530824b4c9eab2130c8b - dtc-1.4.5/tests/mangle-layout.supp
|
||||||
|
1a1de5c063dff543882f638a0dc5801628364556 - dtc-1.4.5/tests/extra-terminating-null.c
|
||||||
|
db16441c4b330570a9ac83b0e0b006fcd74cc32b - dtc-1.4.5/tests/incbin.bin
|
||||||
|
e94ef627a9dbfae24ea5eaccc985ced1738ad96f - dtc-1.4.5/tests/test_tree1_wrong9.dts
|
||||||
|
b3d47e46906126d2e0277adb8c35e6fc22e6380e - dtc-1.4.5/tests/include8.dts
|
||||||
|
a2cd7d79b779d2adfe2ec0c6b2a87312287c7abe - dtc-1.4.5/tests/include5a.dts
|
||||||
|
3e3767ef8b845fa7cace62543fda1fb19dd59d9d - dtc-1.4.5/tests/include2.dts
|
||||||
|
45e3fa0098f1d154ea2c1b3b61e87853f63cc4c2 - dtc-1.4.5/tests/sw_tree1.supp
|
||||||
|
58a4885d5573e8f0153839633f0c27820b373359 - dtc-1.4.5/tests/.gitignore
|
||||||
|
8f42d8e919b03dc09cac7ab58b2f9a28c830c9f5 - dtc-1.4.5/tests/stringlist.dts
|
||||||
|
968572da053916799c6b292dbd7ae6aba6755eda - dtc-1.4.5/tests/stacked_overlay_bar.dts
|
||||||
|
5fe77cdfa90bb405ded8bf20f7c3ed796f40abd5 - dtc-1.4.5/tests/reuse-label5.dts
|
||||||
|
e7e02f700b8e537130b0bc7a5fd9459660f8060c - dtc-1.4.5/tests/subnode_offset.c
|
||||||
|
7eae2be2813b5dca217a4e56bf8fae289e35166b - dtc-1.4.5/tests/Makefile.tests
|
||||||
|
e2d500c1ce6a9cff11cfba7b3859ebbcbbc588f4 - dtc-1.4.5/tests/trees.S
|
||||||
|
d576360fbfe36cc1f2c8f8c879f9109ab7cf9001 - dtc-1.4.5/tests/overlay_bad_fixup_index_trailing.dts
|
||||||
|
0082526b79f4d6d567faa039b5bec0295b5ec40b - dtc-1.4.5/tests/incbin.c
|
||||||
|
0886327c6106fd381312af3ceca674a4101380e0 - dtc-1.4.5/tests/nonexist-node-ref2.dts
|
||||||
|
fd68ece161bb07980e8ab678c61e293439906e2e - dtc-1.4.5/tests/run_tests.sh
|
||||||
|
4d98a0b920d0a7d37426b858e02387b16f007d58 - dtc-1.4.5/tests/overlay_overlay.dts
|
||||||
|
99c9cab16ce9f3db83dab99f1798f0bee79f055c - dtc-1.4.5/tests/open_pack.supp
|
||||||
|
210a4bfe688816869d79d5e9ce31a0a757441921 - dtc-1.4.5/tests/embedded_nul.dts
|
||||||
|
67c6674e15b3157690e444af5b5bedbd987659e2 - dtc-1.4.5/tests/overlay.c
|
||||||
|
cfcd5acf194801ca0b01302bf1d64eabeca89f68 - dtc-1.4.5/tests/value-labels.c
|
||||||
|
e3accfdb6f94c8d1bebcca85d9a5b52db0333670 - dtc-1.4.5/tests/sw_tree1.c
|
||||||
|
17846cb1d5428c6b0736ebcf8c2426dce37b47cf - dtc-1.4.5/tests/tests.h
|
||||||
|
773742f1338a51bde4d17f50b8ce97aac353a4ce - dtc-1.4.5/tests/overlay_bad_fixup_bad_index.dts
|
||||||
|
2a3c7f084000959f1b8fb4c405c23baf507835eb - dtc-1.4.5/tests/subnode_iterate.dts
|
||||||
|
7d6aa332681677fa7ac56d3390d1790b24ecc67f - dtc-1.4.5/tests/del_node.c
|
||||||
|
50be2e1000a7f0e19b94276143ed086a3081d161 - dtc-1.4.5/tests/get_path.c
|
||||||
|
4d1ae34edf08284d07b15103276d9c2a90059528 - dtc-1.4.5/tests/property_iterate.dts
|
||||||
|
097641bc7cdb15643af0ce67afa53910b559fa71 - dtc-1.4.5/tests/test_tree1_wrong5.dts
|
||||||
|
b98faf87f6f8dc361fc5fb11938921027c08b84f - dtc-1.4.5/tests/overlay_bad_fixup.c
|
||||||
|
cc5da65a932ea3005fb828dd16adb4b6049c0503 - dtc-1.4.5/tests/reuse-label6.dts
|
||||||
|
0bbd9c00bbe4150c13eed944cb787cf1480ddb9a - dtc-1.4.5/tests/references.dts
|
||||||
|
09c7a2b43ab5861b597da0497506e5a1a6ea1a9c - dtc-1.4.5/tests/include6.dts
|
||||||
|
bdcecf87f4aeb28c666d1196253746415f459864 - dtc-1.4.5/tests/overlay_bad_fixup_path_empty_prop.dts
|
||||||
|
53d884493b1a91d6d94e2d9fef517f9edbbdb7ec - dtc-1.4.5/tests/test_kernel_dts
|
||||||
|
3f29e779d64b1fb3fe743c958473e6a37879e1d9 - dtc-1.4.5/tests/path_offset_aliases.c
|
||||||
|
bace86d14d5a88839dc38c67b7bfdb78a0cd30f7 - dtc-1.4.5/tests/overlay_overlay_manual_fixups.dts
|
||||||
|
e15294970cf6645789ecb2fa573f4cfcdfc18008 - dtc-1.4.5/tests/appendprop2.c
|
||||||
|
78c9a2794d6684c52e601e58a6348f808a667122 - dtc-1.4.5/tests/bad-interrupt-cells.dts
|
||||||
|
dc911a4dd77c234586d0abdfccb66d23b990279f - dtc-1.4.5/tests/test01.asm
|
||||||
|
c58561b0a7af860779d89d27ebd4fbcfe3dd9862 - dtc-1.4.5/tests/base01.asm
|
||||||
|
4c182e2cd290bbc9677007b2cc26d526525cea7e - dtc-1.4.5/tests/overlay_base_manual_symbols.dts
|
||||||
|
3d58b283fc73faeab28eddf460ba97a401469c8c - dtc-1.4.5/tests/nonexist-node-ref.dts
|
||||||
|
1450026fe5e5d5c0854803d9d90567e9999a7c94 - dtc-1.4.5/tests/getprop.c
|
||||||
|
ca049c8511a0081118bca5cc76d17a5214b6fe9a - dtc-1.4.5/tests/fdtput-runtest.sh
|
||||||
|
557bd08f0cb8a37abd7568e5857508b1dd861474 - dtc-1.4.5/tests/parent_offset.c
|
||||||
|
ff6959ed32b3495ef5766c03da4f312488bb3983 - dtc-1.4.5/tests/deps_inc1.dtsi
|
||||||
|
7856fa203be221173cb6bafca81bf394a4f355bd - dtc-1.4.5/tests/test_tree1_merge.dts
|
||||||
|
4e44e71434ff788af4781ee934c70331870458ca - dtc-1.4.5/tests/path-references.c
|
||||||
|
e000be7a8d461e4a76027d36cc9c4839fbc2d58d - dtc-1.4.5/tests/node_offset_by_phandle.c
|
||||||
|
8abd5ffeb21a0ebc6795240d73152acb2240f442 - dtc-1.4.5/tests/include5.dts
|
||||||
|
7895dc6b800832b032bc29c87e78b1c97408f605 - dtc-1.4.5/tests/search_paths.dts
|
||||||
|
d0d88754d30e63fedd93010747838960d98c915e - dtc-1.4.5/tests/dup-propname.dts
|
||||||
|
e03aa51b95a671a3f98cae0051cd3474b7c207dd - dtc-1.4.5/tests/test_tree1_wrong7.dts
|
||||||
|
56b55df15337c52aac7c0246a5d44b3e82b76c6f - dtc-1.4.5/tests/overlay_base.dts
|
||||||
|
0e209c69b49d699ee05d19ae1424ea08585b1b6b - dtc-1.4.5/tests/pylibfdt_tests.py
|
||||||
|
4548237d664096155c80836bb9f273adddf7b6d6 - dtc-1.4.5/tests/comments-cmp.dts
|
||||||
|
a9415e9554e16fc01e5978cea5881c7ef5ddee40 - dtc-1.4.5/tests/node_offset_by_prop_value.c
|
||||||
|
2b5cf055b95da40dfa61458471fe259db8e9d0ee - dtc-1.4.5/tests/extra-terminating-null.dts
|
||||||
|
6cf4266274b916b715ada14627a86b19435a202e - dtc-1.4.5/tests/subnode_iterate.c
|
||||||
|
95a8a947549e7daaea521605f6bd4613d006dd29 - dtc-1.4.5/tests/fdtget-runtest.sh
|
||||||
|
b71203a02d1cb91de3b063e87aab076fee50cb3f - dtc-1.4.5/tests/references.c
|
||||||
|
064610a3c824b272b84c94e2518ed42b09e598ff - dtc-1.4.5/tests/reuse-label4.dts
|
||||||
|
dfd7e528eefbe6be39865053c8d1787ab95faf81 - dtc-1.4.5/tests/add_subnode_with_nops.c
|
||||||
|
18a64c7d93e2dc77c78cca13d9d187a0a2ee5d83 - dtc-1.4.5/tests/del_property.c
|
||||||
|
825eaa2f39e18b03c44e4fc04869294fb955d56c - dtc-1.4.5/tests/dup-nodename.dts
|
||||||
|
a34a59272e4ded11d69fa1563608a7cf417efb53 - dtc-1.4.5/tests/addresses.dts
|
||||||
|
a9323cf5194c13e3c29af052c1a85286f9492fa4 - dtc-1.4.5/tests/overlay_bad_fixup_base.dtsi
|
||||||
|
d2e394c31434137df0d3989fb15cebeec2bed2e7 - dtc-1.4.5/tests/base01.stderr
|
||||||
|
c267915a9a6b62629b509d13990b19aac4ad44ca - dtc-1.4.5/tests/fdtoverlay-runtest.sh
|
||||||
|
6225480114e8a14d25c2bd170f55ed78529db893 - dtc-1.4.5/tests/bad-ncells.dts
|
||||||
|
1ea38bf20a653f9b757f98160739a90737c4ce00 - dtc-1.4.5/tests/reg-ranges-root.dts
|
||||||
|
03e8cf8533103cb87b399fef32a36514b64bdcbc - dtc-1.4.5/tests/dtbs_equal_unordered.c
|
||||||
|
c3bbd9a0eb2ce642a716955eab223cca11e427ac - dtc-1.4.5/tests/overlay_bad_fixup_empty.dts
|
||||||
|
a6f8e3450be51ce6cd2ec18fa592726889b616ee - dtc-1.4.5/tests/char_literal.dts
|
||||||
|
627781fdd8a4fc415142e12d0edd5f7ac92f8f14 - dtc-1.4.5/tests/check_path.c
|
||||||
|
c27562784d986c84137d4e2500b8b3e321d46a1b - dtc-1.4.5/tests/nopulate.c
|
||||||
|
238b692003697e0cc242d047971bb6a3af60b464 - dtc-1.4.5/tests/nul-in-line-info2.dts
|
||||||
|
48599e299578b9ca040e45ab220edbb397a55108 - dtc-1.4.5/tests/embedded_nul_equiv.dts
|
||||||
|
a577bd5b22f52302600164b952210ee0a69b86fe - dtc-1.4.5/tests/stringlist.c
|
||||||
|
606a0da173c3d23f841cf8f5184a867f3cc9b1f3 - dtc-1.4.5/tests/utilfdt_test.c
|
||||||
|
1171b227d4252d704d9a300c0cd5e85e244b55e9 - dtc-1.4.5/tests/include4.dts
|
||||||
|
6e38c669946d6d95d026f40d735e730ade3aa714 - dtc-1.4.5/tests/deps_inc2.dtsi
|
||||||
|
c31535957cc2cea57dab87317a0bbb7c5a107b0c - dtc-1.4.5/tests/label01.dts
|
||||||
|
944504b8f4474793305037eddf9dd13979265432 - dtc-1.4.5/tests/get_name.c
|
||||||
|
aadb873ed244256fb50ea64d1b25b7796ffcffca - dtc-1.4.5/tests/include7.dts
|
||||||
|
6ff537c825a6683b1e857eebd754a1cdfc18d75c - dtc-1.4.5/tests/phandle_format.c
|
||||||
|
4cdb0a0f5aeddf820d35d5f9154e4359325c3e2e - dtc-1.4.5/tests/reuse-label.dts
|
||||||
|
fdf6935c1ab9032dc683ecfff2cc21f0185370f4 - dtc-1.4.5/tests/bad-name-property.dts
|
||||||
|
b0a1a56999d7db375e2e52055cbcf8f60ebf7077 - dtc-1.4.5/tests/overlay_overlay_simple.dts
|
||||||
|
b6517c85f38b3175d84d2986922d1751c92d242e - dtc-1.4.5/tests/appendprop.dts
|
||||||
|
e7e1445b585cd04a7992a66c346374f9c97a1188 - dtc-1.4.5/tests/bad-reg-ranges.dts
|
||||||
|
b5a2155cb7a8d9094f7de6f7bb16442abaf42436 - dtc-1.4.5/tests/unit-addr-leading-0s.dts
|
||||||
|
05057f2e73c3d8a5c9dfea99ccfe6553cafcbf74 - dtc-1.4.5/tests/bad-string-props.dts
|
||||||
|
27ac33471f9f470dd15959f1b43a58582b763298 - dtc-1.4.5/tests/root_node.c
|
||||||
|
8f1d286da170262b3ac2e705c175bd6cf1af14cd - dtc-1.4.5/tests/multilabel.dts
|
||||||
|
df629984df17b68032f9e61a688865fe5ec52798 - dtc-1.4.5/tests/move_and_save.c
|
||||||
|
59f8b8532a360f30d639aee56ecf821d8810c39e - dtc-1.4.5/tests/empty.dts
|
||||||
|
587400ca7d9a39476a5162859da7d21f9e816d64 - dtc-1.4.5/tests/testdata.h
|
||||||
|
399a348f311be369f68220b3732fcefde0f740f1 - dtc-1.4.5/tests/test_tree1.dts
|
||||||
|
94e0a5da6d15f081a21a2a5d02bbf45c3f85b62b - dtc-1.4.5/tests/supernode_atdepth_offset.c
|
||||||
|
c5deddb0fb0cd547da34fcaf924bdbe303b17492 - dtc-1.4.5/tests/test_tree1_wrong2.dts
|
||||||
|
49599b99ec6deb90718c05cb56711f1072ef623a - dtc-1.4.5/tests/reg-without-unit-addr.dts
|
||||||
|
6e6a7ec861bd63506d082a793bda483f8540be5b - dtc-1.4.5/tests/open_pack.c
|
||||||
|
08a95e2c1ce9ff35b2b6d9bad6a31bda3d2dadb4 - dtc-1.4.5/tests/overlay_bad_fixup_empty_index.dts
|
||||||
|
29a54f5c1c352e672dd7742b342629f356e5df6e - dtc-1.4.5/tests/zero-phandle.dts
|
||||||
|
8b046ab9a11a0c3a6780cf09cc82b5a6c5cec5c9 - dtc-1.4.5/tests/overlay_bad_fixup_path_prop.dts
|
||||||
|
9bc91516a068a176123a69777f41ad435c82933f - dtc-1.4.5/tests/string_escapes.c
|
||||||
|
c33c776418f1a2f4206f32680137822d6665eb89 - dtc-1.4.5/tests/mangle-layout.c
|
||||||
|
2e52702a5a474751f42991a4c68246a7c6356102 - dtc-1.4.5/tests/default-addr-size.dts
|
||||||
|
7c16967c713c20f58949e9a1d64dd14fcc0006a1 - dtc-1.4.5/tests/escapes.dts
|
||||||
|
265a369071203707125f015936d258f095f7db10 - dtc-1.4.5/tests/dtc-fatal.sh
|
||||||
|
da2bc0ecdecb507bfd11c951c3f0612834fcc922 - dtc-1.4.5/tests/nul-in-escape.dts
|
||||||
|
58bb1310303666817f190475c130e19a411a0c1f - dtc-1.4.5/tests/base01.dts
|
||||||
|
a1720d7f7d1c022c7e4f6717009a691693556aa1 - dtc-1.4.5/tests/find_property.c
|
||||||
|
03e96eb3ee1f650106cb90e06a4841681de15197 - dtc-1.4.5/tests/addr_size_cells.c
|
||||||
|
a748aadffd49ef78eeac7ad521a0d84aebcdbdbf - dtc-1.4.5/tests/dumptrees.c
|
||||||
|
f0eeb4b91084a61d9008a90d09b86425f4733c0c - dtc-1.4.5/tests/test01.stderr
|
||||||
|
8700502c294e949f908fa5c0c44248bd96af5ca6 - dtc-1.4.5/tests/dtc-fails.sh
|
||||||
|
9dcc1f85d0c8a1ce34c57d64c8e3fff4920f2df7 - dtc-1.4.5/tests/asm_tree_dump.c
|
||||||
|
1e8705f0eaec9950cd074b09b8463ede99a019b6 - dtc-1.4.5/tests/test_label_ref.dts
|
||||||
|
1ab3cfcd6d35f35618dc3d0b90a1b093a3467c1d - dtc-1.4.5/tests/division-by-zero.dts
|
||||||
|
06d3aebaaa4a26b6cb8fc1b3804fbef8d3ddd9ac - dtc-1.4.5/tests/line_directives.dts
|
||||||
|
9f00325b7377977b942eb0a1e01f978c806482f4 - dtc-1.4.5/tests/property_iterate.c
|
||||||
|
0181f2cb1a32b682733fa9db274226c7745c80cd - dtc-1.4.5/tests/test_tree1_delete.dts
|
||||||
|
bcc58605628d627ab670e8afe59d82916737e534 - dtc-1.4.5/tests/comments.dts
|
||||||
|
21e36b524a10b28810260a151e718818b79d87d1 - dtc-1.4.5/tests/sized_cells.c
|
||||||
|
3d6060bcbb5d4e369be0b5b518f0b80fd448faa0 - dtc-1.4.5/tests/setprop.c
|
||||||
|
82c9e391f5ba20d3b1c56ea7978a925f60481f18 - dtc-1.4.5/tests/overlay_overlay_no_fixups.dts
|
||||||
|
c825d82e7ed5fa8bdc4b0cd04cca5cc73a156709 - dtc-1.4.5/tests/bad-octal-literal.dts
|
||||||
|
444db827745be8840705a7cce26b024194624d15 - dtc-1.4.5/tests/incbin.dts
|
||||||
|
6ea01b148f3a82e51d775f9fadc37602ffe095ed - dtc-1.4.5/tests/testutils.c
|
||||||
|
026b4b16a20b6e79c02dba88f997f35d9562bb30 - dtc-1.4.5/tests/appendprop1.c
|
||||||
|
132e01eefa23f6a8c7b88c2a234b04c7d6529e4c - dtc-1.4.5/tests/unit-addr-without-reg.dts
|
||||||
|
9533807e3b9982017e411ba37f29dc322e691b68 - dtc-1.4.5/tests/unit-addr-leading-0x.dts
|
||||||
|
5286525de751b12c681101f6336d48533d904aa5 - dtc-1.4.5/tests/node_check_compatible.c
|
||||||
|
3f3316bfa1b4b2e718c30765c999b5a7075af3bd - dtc-1.4.5/tests/sized_cells.dts
|
||||||
|
09d871f55acf837e1467bde782781212dfecabc1 - dtc-1.4.5/tests/dependencies.dts
|
||||||
|
66f3655753343a0b87ff386da265bede08f99aee - dtc-1.4.5/tests/path_offset.c
|
||||||
|
f62430e11919a194daf565d6681a1df5fc6017f9 - dtc-1.4.5/tests/fdtdump-runtest.sh
|
||||||
|
c05d5b477def26d28273932ffc2bac34a91f4b8e - dtc-1.4.5/tests/propname_escapes.c
|
||||||
|
e6f56bdf21ace78b4e2150b088263c3ce7e1f1c9 - dtc-1.4.5/tests/test_tree1_merge_path.dts
|
||||||
|
c95ed15e2b3847366ecf12d1a7c8f4756ee745e6 - dtc-1.4.5/tests/delete_reinstate_multilabel_ref.dts
|
||||||
|
fd7d8b2bb9a288532134b0c82ee7fc3d7c983bfb - dtc-1.4.5/tests/dependencies.cmp
|
||||||
|
80911d8420ea3e794b86bd9c04aeae892eaad657 - dtc-1.4.5/tests/label_repeated.dts
|
||||||
|
3150edab60c72057f68b275f7f0bd2abeabf67de - dtc-1.4.5/tests/nop_property.c
|
||||||
|
1df4762532e24bf29f9cfaf82772fef9487683d2 - dtc-1.4.5/tests/search_paths_b.dts
|
||||||
|
52cf04b57ff7424ca1c57a12f5df19247940a3eb - dtc-1.4.5/tests/fdtdump.dts
|
||||||
|
332afd52254b8dbfaff4c7c1644d8c73cac2d855 - dtc-1.4.5/tests/stacked_overlay_baz.dts
|
||||||
|
02eef4caeaddab2f3722b86026ce2e1e434cde14 - dtc-1.4.5/tests/reuse-label1.dts
|
||||||
|
bdd28adcd03ea8a4c41a3e75de84a85c6938a044 - dtc-1.4.5/tests/dtc-checkfails.sh
|
||||||
|
53995be36144e22baca01a26b5c2113e5e9dea11 - dtc-1.4.5/tests/overlay_bad_fixup_path_only_sep.dts
|
||||||
|
6d74b16a531067c828acfdf118ecd5765f3168da - dtc-1.4.5/tests/node_offset_by_compatible.c
|
||||||
|
05a8ec0dae916212ba5e29c17ab63c766b8f6142 - dtc-1.4.5/tests/nop_node.c
|
||||||
|
badb0d8f62608674030ca278620b061f1d53f625 - dtc-1.4.5/tests/notfound.c
|
||||||
|
52ffd7a9b99beedbf46df87b18396daf91187d2d - dtc-1.4.5/tests/test_tree1_label_noderef.dts
|
||||||
|
ccecd5a83df37929613b6fdde5c88c3ecc8e84a8 - dtc-1.4.5/tests/include3.dts
|
||||||
|
78c91d2a0808bae30377b1dae9731c15725a972d - dtc-1.4.5/tests/prop-after-subnode.dts
|
||||||
|
42a972b76e039f30913fa708eb708901ed470c38 - dtc-1.4.5/tests/test_tree1_wrong8.dts
|
||||||
|
c7f82cecdd0ce4ca602890f2dd9d029d216deddf - dtc-1.4.5/tests/get_alias.c
|
||||||
|
771dc03d722d5c951a41f1fbab202f3f66f9a91e - dtc-1.4.5/tests/aliases.dts
|
||||||
|
2d816cf202120e151e9a4c10a11a68c4115f4f29 - dtc-1.4.5/tests/value-labels.dts
|
||||||
|
555bcf861816bdd82884301d1de455221cb1d288 - dtc-1.4.5/tests/data.S
|
||||||
|
c925cf6f789d4e7b879863a4414b3805a201cbae - dtc-1.4.5/tests/base01.cmd
|
||||||
|
03535626db5128f181593328582a7ef441776e2f - dtc-1.4.5/tests/sourceoutput.dts
|
||||||
|
a82abc5909ca25c13485da36752562db0acb1d3e - dtc-1.4.5/tests/get_mem_rsv.c
|
||||||
|
7b4ee02efa4d17433ba49c82dd2f30f1773c9d7a - dtc-1.4.5/tests/boot-cpuid.dts
|
||||||
|
55074ad8e933275058412606c278e1002a94b55a - dtc-1.4.5/tests/bad-size-cells.dts
|
||||||
|
fda3eb684c8ea2dae5845f23fd2f18ac8719d3e1 - dtc-1.4.5/tests/reuse-label3.dts
|
||||||
|
1187a7fb193ca9eb92ddbfb1500cf9ec7595a43a - dtc-1.4.5/tests/dtb_reverse.c
|
||||||
|
cd3ebe8d5c0e89669dc866b78d74611ec1d399cb - dtc-1.4.5/tests/reuse-label2.dts
|
||||||
|
fbaa8c4c9b156b24b74456bc8824f1aa6e777ec3 - dtc-1.4.5/tests/include1.dts
|
||||||
|
18a5eaaf67886b19caeec13d1f91fbac9dab40ea - dtc-1.4.5/tests/include0.dts
|
||||||
|
e220e5db0820592bd028adb9431401970522cd93 - dtc-1.4.5/tests/nul-in-line-info1.dts
|
||||||
|
9cb78df0d0f7fd73119b57ce7a171704631af5e4 - dtc-1.4.5/tests/delete_reinstate_multilabel.dts
|
||||||
|
ba55daa9627a9fa3af7ddbbb4c8e23b159fef96b - dtc-1.4.5/tests/char_literal.c
|
||||||
|
7997cfd671338152e5947ad6e3a7476b762f84b0 - dtc-1.4.5/tests/set_name.c
|
||||||
|
f7c3f569b0ef5a9c2ffe17656de222437bdcba78 - dtc-1.4.5/tests/overlay_bad_fixup_path_only.dts
|
||||||
|
738ebbc0f6e1fc9e4462d3b74081a83335be17aa - dtc-1.4.5/tests/bad-empty-ranges.dts
|
||||||
|
3a30897484d829884db97735b23fedec00d1df18 - dtc-1.4.5/tests/test_tree1_wrong3.dts
|
||||||
|
f3b0a0b0586f072ca642e33648ad6a8cc88f0ac9 - dtc-1.4.5/tests/setprop_inplace.c
|
||||||
|
549b82463e24ea3d3cbb8992cc21c8ea65686671 - dtc-1.4.5/tests/test_tree1_merge_labelled.dts
|
||||||
|
7ff38d835b0084e9a2fa409cd697a2e0d135ac19 - dtc-1.4.5/tests/tests.sh
|
||||||
|
86e03f6d539ccb33585658f93b9b53e89534719c - dtc-1.4.5/tests/path-references.dts
|
||||||
|
42c311ee4bcf10bd46c6894d5338d00b69a0a7e7 - dtc-1.4.5/tests/propname_escapes.dts
|
||||||
|
32913f10eab70e2a11e13a7d4a0f31aee903a53d - dtc-1.4.5/tests/test_tree1_wrong6.dts
|
||||||
|
d7da06091195ba54e6904bd46ccd5aeb5445c22a - dtc-1.4.5/tests/test_tree1_wrong1.dts
|
||||||
|
54b58cc0e02047df34ab21ff906ad4d8669521c8 - dtc-1.4.5/tests/bad-phandle-cells.dts
|
||||||
|
2c7f7bed3fa31d608e32095cc3469559a80376df - dtc-1.4.5/tests/multilabel_merge.dts
|
||||||
|
81c4b081a92462f90ffa24915b2cad76cb687f88 - dtc-1.4.5/tests/dup-phandle.dts
|
||||||
|
665f89ab83944d57bb09f3a18a1391280f446db3 - dtc-1.4.5/tests/rw_tree1.c
|
||||||
|
90fd6ea3d82dfc9cadd37a93e3a62fc72e6b336d - dtc-1.4.5/tests/integer-expressions.c
|
||||||
|
e8c561bde2558fb895f327e6e005c7af8818a1f5 - dtc-1.4.5/tests/stacked_overlay_base.dts
|
||||||
|
0ea1b9337b59fd9872199301ac37114c37a2a620 - dtc-1.4.5/tests/get_phandle.c
|
||||||
|
448994a1143852a9b1154db51a9db49d717d9c31 - dtc-1.4.5/tests/search_dir_b/search_test_c.dtsi
|
||||||
|
74d5e33802b093e2abd21b884a018223a853c93d - dtc-1.4.5/tests/search_dir_b/search_test_b.dtsi
|
||||||
|
60d17f79adc996b2b1ea979208cca39f6acf4145 - dtc-1.4.5/tests/search_dir_b/search_paths_subdir.dts
|
||||||
|
e3a9bc2e23703093aca0d62db5587a8c7da3e9a3 - dtc-1.4.5/tests/search_dir_b/search_test_b2.dtsi
|
||||||
|
a3efef7df14727a6a4e97a1a6c5c5dc70ee761d9 - dtc-1.4.5/tests/search_dir/search_test2.dtsi
|
||||||
|
2adb422636000206499201175d397a4e065118d1 - dtc-1.4.5/tests/search_dir/search_test.dtsi
|
||||||
|
cbaff71343d90c58f78fa1ee686fc0114bc88399 - dtc-1.4.5/pylibfdt/.gitignore
|
||||||
|
950f95518e818abf2c8f84f1074b6f7c67002a36 - dtc-1.4.5/pylibfdt/Makefile.pylibfdt
|
||||||
|
103f0f23a13380d020ea07587574e3c16a8812d2 - dtc-1.4.5/pylibfdt/setup.py
|
||||||
|
efd79993fabe982fc1c772d90d796f9ca3be096c - dtc-1.4.5/pylibfdt/libfdt.i
|
||||||
|
edcd4769af7d6adf1bd71db82c02b377a55a665f - dtc-1.4.5/Documentation/dtc-paper.tex
|
||||||
|
657ff4514367b424637b70b785eda2b5f527374c - dtc-1.4.5/Documentation/dtc-paper.bib
|
||||||
18
dtc-1.4.5/.gitignore
vendored
Normal file
18
dtc-1.4.5/.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
*.o
|
||||||
|
*.d
|
||||||
|
*.a
|
||||||
|
*.patch
|
||||||
|
*.so
|
||||||
|
*~
|
||||||
|
*.tab.[ch]
|
||||||
|
lex.yy.c
|
||||||
|
*.lex.c
|
||||||
|
/dtc
|
||||||
|
/fdtdump
|
||||||
|
/convert-dtsv0
|
||||||
|
/version_gen.h
|
||||||
|
/fdtget
|
||||||
|
/fdtput
|
||||||
|
/fdtoverlay
|
||||||
|
/patches
|
||||||
|
/.pc
|
||||||
30
dtc-1.4.5/.travis.yml
Normal file
30
dtc-1.4.5/.travis.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
language: c
|
||||||
|
|
||||||
|
# Coverity Scan uploads
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
# COVERITY_SCAN_TOKEN (dgibson/dtc)
|
||||||
|
- secure: "vlHvXe618//IM9LQaKzqsrUbjs7ng0L9UCST4kJbJnFQDXvVe5JiSmJGd4ef7mm0NUv5bMRl2W3xCiu6BYAu/NvU3tMNHoLG+JgCJs0+wLJXbWOwji/NmH7olqgJG+CmpaCMXjARF6+nrTnBYHJL6cYyf4KVoV4B0I/hLUW91+s="
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- swig
|
||||||
|
- python-dev
|
||||||
|
coverity_scan:
|
||||||
|
project:
|
||||||
|
name: dtc
|
||||||
|
description: Device Tree Compiler
|
||||||
|
notification_email: david@gibson.dropbear.id.au
|
||||||
|
build_command: make
|
||||||
|
branch_pattern: coverity_scan
|
||||||
|
|
||||||
|
- addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make
|
||||||
|
- make check
|
||||||
310
dtc-1.4.5/Documentation/dt-object-internal.txt
Normal file
310
dtc-1.4.5/Documentation/dt-object-internal.txt
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
Device Tree Dynamic Object format internals
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
The Device Tree for most platforms is a static representation of
|
||||||
|
the hardware capabilities. This is insufficient for platforms
|
||||||
|
that need to dynamically insert Device Tree fragments into the
|
||||||
|
live tree.
|
||||||
|
|
||||||
|
This document explains the the Device Tree object format and
|
||||||
|
modifications made to the Device Tree compiler, which make it possible.
|
||||||
|
|
||||||
|
1. Simplified Problem Definition
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Assume we have a platform which boots using following simplified Device Tree.
|
||||||
|
|
||||||
|
---- foo.dts -----------------------------------------------------------------
|
||||||
|
/* FOO platform */
|
||||||
|
/ {
|
||||||
|
compatible = "corp,foo";
|
||||||
|
|
||||||
|
/* shared resources */
|
||||||
|
res: res {
|
||||||
|
};
|
||||||
|
|
||||||
|
/* On chip peripherals */
|
||||||
|
ocp: ocp {
|
||||||
|
/* peripherals that are always instantiated */
|
||||||
|
peripheral1 { ... };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
---- foo.dts -----------------------------------------------------------------
|
||||||
|
|
||||||
|
We have a number of peripherals that after probing (using some undefined method)
|
||||||
|
should result in different Device Tree configuration.
|
||||||
|
|
||||||
|
We cannot boot with this static tree because due to the configuration of the
|
||||||
|
foo platform there exist multiple conficting peripherals DT fragments.
|
||||||
|
|
||||||
|
So for the bar peripheral we would have this:
|
||||||
|
|
||||||
|
---- foo+bar.dts -------------------------------------------------------------
|
||||||
|
/* FOO platform + bar peripheral */
|
||||||
|
/ {
|
||||||
|
compatible = "corp,foo";
|
||||||
|
|
||||||
|
/* shared resources */
|
||||||
|
res: res {
|
||||||
|
};
|
||||||
|
|
||||||
|
/* On chip peripherals */
|
||||||
|
ocp: ocp {
|
||||||
|
/* peripherals that are always instantiated */
|
||||||
|
peripheral1 { ... };
|
||||||
|
|
||||||
|
/* bar peripheral */
|
||||||
|
bar {
|
||||||
|
compatible = "corp,bar";
|
||||||
|
... /* various properties and child nodes */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
---- foo+bar.dts -------------------------------------------------------------
|
||||||
|
|
||||||
|
While for the baz peripheral we would have this:
|
||||||
|
|
||||||
|
---- foo+baz.dts -------------------------------------------------------------
|
||||||
|
/* FOO platform + baz peripheral */
|
||||||
|
/ {
|
||||||
|
compatible = "corp,foo";
|
||||||
|
|
||||||
|
/* shared resources */
|
||||||
|
res: res {
|
||||||
|
/* baz resources */
|
||||||
|
baz_res: res_baz { ... };
|
||||||
|
};
|
||||||
|
|
||||||
|
/* On chip peripherals */
|
||||||
|
ocp: ocp {
|
||||||
|
/* peripherals that are always instantiated */
|
||||||
|
peripheral1 { ... };
|
||||||
|
|
||||||
|
/* baz peripheral */
|
||||||
|
baz {
|
||||||
|
compatible = "corp,baz";
|
||||||
|
/* reference to another point in the tree */
|
||||||
|
ref-to-res = <&baz_res>;
|
||||||
|
... /* various properties and child nodes */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
---- foo+baz.dts -------------------------------------------------------------
|
||||||
|
|
||||||
|
We note that the baz case is more complicated, since the baz peripheral needs to
|
||||||
|
reference another node in the DT tree.
|
||||||
|
|
||||||
|
2. Device Tree Object Format Requirements
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
Since the Device Tree is used for booting a number of very different hardware
|
||||||
|
platforms it is imperative that we tread very carefully.
|
||||||
|
|
||||||
|
2.a) No changes to the Device Tree binary format for the base tree. We cannot
|
||||||
|
modify the tree format at all and all the information we require should be
|
||||||
|
encoded using Device Tree itself. We can add nodes that can be safely ignored
|
||||||
|
by both bootloaders and the kernel. The plugin dtbs are optionally tagged
|
||||||
|
with a different magic number in the header but otherwise they're simple
|
||||||
|
blobs.
|
||||||
|
|
||||||
|
2.b) Changes to the DTS source format should be absolutely minimal, and should
|
||||||
|
only be needed for the DT fragment definitions, and not the base boot DT.
|
||||||
|
|
||||||
|
2.c) An explicit option should be used to instruct DTC to generate the required
|
||||||
|
information needed for object resolution. Platforms that don't use the
|
||||||
|
dynamic object format can safely ignore it.
|
||||||
|
|
||||||
|
2.d) Finally, DT syntax changes should be kept to a minimum. It should be
|
||||||
|
possible to express everything using the existing DT syntax.
|
||||||
|
|
||||||
|
3. Implementation
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The basic unit of addressing in Device Tree is the phandle. Turns out it's
|
||||||
|
relatively simple to extend the way phandles are generated and referenced
|
||||||
|
so that it's possible to dynamically convert symbolic references (labels)
|
||||||
|
to phandle values. This is a valid assumption as long as the author uses
|
||||||
|
reference syntax and does not assign phandle values manually (which might
|
||||||
|
be a problem with decompiled source files).
|
||||||
|
|
||||||
|
We can roughly divide the operation into two steps.
|
||||||
|
|
||||||
|
3.a) Compilation of the base board DTS file using the '-@' option
|
||||||
|
generates a valid DT blob with an added __symbols__ node at the root node,
|
||||||
|
containing a list of all nodes that are marked with a label.
|
||||||
|
|
||||||
|
Using the foo.dts file above the following node will be generated;
|
||||||
|
|
||||||
|
$ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts
|
||||||
|
$ fdtdump foo.dtb
|
||||||
|
...
|
||||||
|
/ {
|
||||||
|
...
|
||||||
|
res {
|
||||||
|
...
|
||||||
|
phandle = <0x00000001>;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
ocp {
|
||||||
|
...
|
||||||
|
phandle = <0x00000002>;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
__symbols__ {
|
||||||
|
res="/res";
|
||||||
|
ocp="/ocp";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Notice that all the nodes that had a label have been recorded, and that
|
||||||
|
phandles have been generated for them.
|
||||||
|
|
||||||
|
This blob can be used to boot the board normally, the __symbols__ node will
|
||||||
|
be safely ignored both by the bootloader and the kernel (the only loss will
|
||||||
|
be a few bytes of memory and disk space).
|
||||||
|
|
||||||
|
We generate a __symbols__ node to record nodes that had labels in the base
|
||||||
|
tree (or subsequent loaded overlays) so that they can be matched up with
|
||||||
|
references made to them in Device Tree objects.
|
||||||
|
|
||||||
|
3.b) The Device Tree fragments must be compiled with the same option but they
|
||||||
|
must also have a tag (/plugin/) that allows undefined references to nodes
|
||||||
|
that are not present at compilation time to be recorded so that the runtime
|
||||||
|
loader can fix them.
|
||||||
|
|
||||||
|
So the bar peripheral's DTS format would be of the form:
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
/plugin/; /* allow undefined references and record them */
|
||||||
|
/ {
|
||||||
|
.... /* various properties for loader use; i.e. part id etc. */
|
||||||
|
fragment@0 {
|
||||||
|
target = <&ocp>;
|
||||||
|
__overlay__ {
|
||||||
|
/* bar peripheral */
|
||||||
|
bar {
|
||||||
|
compatible = "corp,bar";
|
||||||
|
... /* various properties and child nodes */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Note that there's a target property that specifies the location where the
|
||||||
|
contents of the overlay node will be placed, and it references the node
|
||||||
|
in the foo.dts file.
|
||||||
|
|
||||||
|
$ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts
|
||||||
|
$ fdtdump bar.dtbo
|
||||||
|
...
|
||||||
|
/ {
|
||||||
|
... /* properties */
|
||||||
|
fragment@0 {
|
||||||
|
target = <0xffffffff>;
|
||||||
|
__overlay__ {
|
||||||
|
bar {
|
||||||
|
compatible = "corp,bar";
|
||||||
|
... /* various properties and child nodes */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
__fixups__ {
|
||||||
|
ocp = "/fragment@0:target:0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
No __symbols__ node has been generated (no label in bar.dts).
|
||||||
|
Note that the target's ocp label is undefined, so the phandle
|
||||||
|
value is filled with the illegal value '0xffffffff', while a __fixups__
|
||||||
|
node has been generated, which marks the location in the tree where
|
||||||
|
the label lookup should store the runtime phandle value of the ocp node.
|
||||||
|
|
||||||
|
The format of the __fixups__ node entry is
|
||||||
|
|
||||||
|
<label> = "<local-full-path>:<property-name>:<offset>"
|
||||||
|
[, "<local-full-path>:<property-name>:<offset>"...];
|
||||||
|
|
||||||
|
<label> Is the label we're referring
|
||||||
|
<local-full-path> Is the full path of the node the reference is
|
||||||
|
<property-name> Is the name of the property containing the
|
||||||
|
reference
|
||||||
|
<offset> The offset (in bytes) of where the property's
|
||||||
|
phandle value is located.
|
||||||
|
|
||||||
|
Doing the same with the baz peripheral's DTS format is a little bit more
|
||||||
|
involved, since baz contains references to local labels which require
|
||||||
|
local fixups.
|
||||||
|
|
||||||
|
/dts-v1/;
|
||||||
|
/plugin/; /* allow undefined label references and record them */
|
||||||
|
/ {
|
||||||
|
.... /* various properties for loader use; i.e. part id etc. */
|
||||||
|
fragment@0 {
|
||||||
|
target = <&res>;
|
||||||
|
__overlay__ {
|
||||||
|
/* baz resources */
|
||||||
|
baz_res: res_baz { ... };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
fragment@1 {
|
||||||
|
target = <&ocp>;
|
||||||
|
__overlay__ {
|
||||||
|
/* baz peripheral */
|
||||||
|
baz {
|
||||||
|
compatible = "corp,baz";
|
||||||
|
/* reference to another point in the tree */
|
||||||
|
ref-to-res = <&baz_res>;
|
||||||
|
... /* various properties and child nodes */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Note that &bar_res reference.
|
||||||
|
|
||||||
|
$ dtc -@ -O dtb -o baz.dtbo -b 0 baz.dts
|
||||||
|
$ fdtdump baz.dtbo
|
||||||
|
...
|
||||||
|
/ {
|
||||||
|
... /* properties */
|
||||||
|
fragment@0 {
|
||||||
|
target = <0xffffffff>;
|
||||||
|
__overlay__ {
|
||||||
|
res_baz {
|
||||||
|
....
|
||||||
|
phandle = <0x00000001>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
fragment@1 {
|
||||||
|
target = <0xffffffff>;
|
||||||
|
__overlay__ {
|
||||||
|
baz {
|
||||||
|
compatible = "corp,baz";
|
||||||
|
... /* various properties and child nodes */
|
||||||
|
ref-to-res = <0x00000001>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
__fixups__ {
|
||||||
|
res = "/fragment@0:target:0";
|
||||||
|
ocp = "/fragment@1:target:0";
|
||||||
|
};
|
||||||
|
__local_fixups__ {
|
||||||
|
fragment@1 {
|
||||||
|
__overlay__ {
|
||||||
|
baz {
|
||||||
|
ref-to-res = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
This is similar to the bar case, but the reference of a local label by the
|
||||||
|
baz node generates a __local_fixups__ entry that records the place that the
|
||||||
|
local reference is being made. No matter how phandles are allocated from dtc
|
||||||
|
the run time loader must apply an offset to each phandle in every dynamic
|
||||||
|
DT object loaded. The __local_fixups__ node records the offset relative to the
|
||||||
|
start of every local reference within that property so that the loader can apply
|
||||||
|
the offset.
|
||||||
43
dtc-1.4.5/Documentation/dtc-paper.bib
Normal file
43
dtc-1.4.5/Documentation/dtc-paper.bib
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
@STRING{pub-IEEE = "IEEE Computer Society"}
|
||||||
|
@STRING{pub-IEEE:adr = "345 E. 47th St, New York, NY 10017, USA"}
|
||||||
|
|
||||||
|
@BOOK{IEEE1275,
|
||||||
|
key = "IEEE1275",
|
||||||
|
title = "{IEEE} {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware: {C}ore {R}equirements and {P}ractices",
|
||||||
|
publisher = pub-IEEE,
|
||||||
|
address = pub-IEEE:adr,
|
||||||
|
series = "IEEE Std 1275-1994",
|
||||||
|
year = 1994,
|
||||||
|
}
|
||||||
|
|
||||||
|
@BOOK{IEEE1275-pci,
|
||||||
|
key = "IEEE1275-pci",
|
||||||
|
title = "{PCI} {B}us {B}inding to: {IEEE} {S}td 1275-1994 {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware",
|
||||||
|
publisher = pub-IEEE,
|
||||||
|
address = pub-IEEE:adr,
|
||||||
|
note = "Revision 2.1",
|
||||||
|
year = 1998,
|
||||||
|
}
|
||||||
|
|
||||||
|
@MISC{noof1,
|
||||||
|
author = "Benjamin Herrenschmidt",
|
||||||
|
title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
|
||||||
|
month = may,
|
||||||
|
year = 2005,
|
||||||
|
note = "v0.1, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-May/004073.html}",
|
||||||
|
}
|
||||||
|
|
||||||
|
@MISC{noof5,
|
||||||
|
author = "Benjamin Herrenschmidt",
|
||||||
|
title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
|
||||||
|
month = nov,
|
||||||
|
year = 2005,
|
||||||
|
note = "v0.5, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-December/006994.html}",
|
||||||
|
}
|
||||||
|
|
||||||
|
@MISC{dtcgit,
|
||||||
|
author = "David Gibson et al.",
|
||||||
|
title = "\dtc{}",
|
||||||
|
howpublished = "git tree",
|
||||||
|
note = "\url{http://ozlabs.org/~dgibson/dtc/dtc.git}",
|
||||||
|
}
|
||||||
597
dtc-1.4.5/Documentation/dtc-paper.tex
Normal file
597
dtc-1.4.5/Documentation/dtc-paper.tex
Normal file
@@ -0,0 +1,597 @@
|
|||||||
|
\documentclass[a4paper,twocolumn]{article}
|
||||||
|
|
||||||
|
\usepackage{abstract}
|
||||||
|
\usepackage{xspace}
|
||||||
|
\usepackage{amssymb}
|
||||||
|
\usepackage{latexsym}
|
||||||
|
\usepackage{tabularx}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage{calc}
|
||||||
|
\usepackage{listings}
|
||||||
|
\usepackage{color}
|
||||||
|
\usepackage{url}
|
||||||
|
|
||||||
|
\title{Device trees everywhere}
|
||||||
|
|
||||||
|
\author{David Gibson \texttt{<{dwg}{@}{au1.ibm.com}>}\\
|
||||||
|
Benjamin Herrenschmidt \texttt{<{benh}{@}{kernel.crashing.org}>}\\
|
||||||
|
\emph{OzLabs, IBM Linux Technology Center}}
|
||||||
|
|
||||||
|
\newcommand{\R}{\textsuperscript{\textregistered}\xspace}
|
||||||
|
\newcommand{\tm}{\textsuperscript{\texttrademark}\xspace}
|
||||||
|
\newcommand{\tge}{$\geqslant$}
|
||||||
|
%\newcommand{\ditto}{\textquotedbl\xspace}
|
||||||
|
|
||||||
|
\newcommand{\fixme}[1]{$\bigstar$\emph{\textbf{\large #1}}$\bigstar$\xspace}
|
||||||
|
|
||||||
|
\newcommand{\ppc}{\mbox{PowerPC}\xspace}
|
||||||
|
\newcommand{\of}{Open Firmware\xspace}
|
||||||
|
\newcommand{\benh}{Ben Herrenschmidt\xspace}
|
||||||
|
\newcommand{\kexec}{\texttt{kexec()}\xspace}
|
||||||
|
\newcommand{\dtbeginnode}{\texttt{OF\_DT\_BEGIN\_NODE\xspace}}
|
||||||
|
\newcommand{\dtendnode}{\texttt{OF\_DT\_END\_NODE\xspace}}
|
||||||
|
\newcommand{\dtprop}{\texttt{OF\_DT\_PROP\xspace}}
|
||||||
|
\newcommand{\dtend}{\texttt{OF\_DT\_END\xspace}}
|
||||||
|
\newcommand{\dtc}{\texttt{dtc}\xspace}
|
||||||
|
\newcommand{\phandle}{\texttt{linux,phandle}\xspace}
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\begin{abstract}
|
||||||
|
We present a method for booting a \ppc{}\R Linux\R kernel on an
|
||||||
|
embedded machine. To do this, we supply the kernel with a compact
|
||||||
|
flattened-tree representation of the system's hardware based on the
|
||||||
|
device tree supplied by Open Firmware on IBM\R servers and Apple\R
|
||||||
|
Power Macintosh\R machines.
|
||||||
|
|
||||||
|
The ``blob'' representing the device tree can be created using \dtc
|
||||||
|
--- the Device Tree Compiler --- that turns a simple text
|
||||||
|
representation of the tree into the compact representation used by
|
||||||
|
the kernel. The compiler can produce either a binary ``blob'' or an
|
||||||
|
assembler file ready to be built into a firmware or bootwrapper
|
||||||
|
image.
|
||||||
|
|
||||||
|
This flattened-tree approach is now the only supported method of
|
||||||
|
booting a \texttt{ppc64} kernel without Open Firmware, and we plan
|
||||||
|
to make it the only supported method for all \texttt{powerpc}
|
||||||
|
kernels in the future.
|
||||||
|
\end{abstract}
|
||||||
|
|
||||||
|
\section{Introduction}
|
||||||
|
|
||||||
|
\subsection{OF and the device tree}
|
||||||
|
|
||||||
|
Historically, ``everyday'' \ppc machines have booted with the help of
|
||||||
|
\of (OF), a firmware environment defined by IEEE1275 \cite{IEEE1275}.
|
||||||
|
Among other boot-time services, OF maintains a device tree that
|
||||||
|
describes all of the system's hardware devices and how they're
|
||||||
|
connected. During boot, before taking control of memory management,
|
||||||
|
the Linux kernel uses OF calls to scan the device tree and transfer it
|
||||||
|
to an internal representation that is used at run time to look up
|
||||||
|
various device information.
|
||||||
|
|
||||||
|
The device tree consists of nodes representing devices or
|
||||||
|
buses\footnote{Well, mostly. There are a few special exceptions.}.
|
||||||
|
Each node contains \emph{properties}, name--value pairs that give
|
||||||
|
information about the device. The values are arbitrary byte strings,
|
||||||
|
and for some properties, they contain tables or other structured
|
||||||
|
information.
|
||||||
|
|
||||||
|
\subsection{The bad old days}
|
||||||
|
|
||||||
|
Embedded systems, by contrast, usually have a minimal firmware that
|
||||||
|
might supply a few vital system parameters (size of RAM and the like),
|
||||||
|
but nothing as detailed or complete as the OF device tree. This has
|
||||||
|
meant that the various 32-bit \ppc embedded ports have required a
|
||||||
|
variety of hacks spread across the kernel to deal with the lack of
|
||||||
|
device tree. These vary from specialised boot wrappers to parse
|
||||||
|
parameters (which are at least reasonably localised) to
|
||||||
|
CONFIG-dependent hacks in drivers to override normal probe logic with
|
||||||
|
hardcoded addresses for a particular board. As well as being ugly of
|
||||||
|
itself, such CONFIG-dependent hacks make it hard to build a single
|
||||||
|
kernel image that supports multiple embedded machines.
|
||||||
|
|
||||||
|
Until relatively recently, the only 64-bit \ppc machines without OF
|
||||||
|
were legacy (pre-POWER5\R) iSeries\R machines. iSeries machines often
|
||||||
|
only have virtual IO devices, which makes it quite simple to work
|
||||||
|
around the lack of a device tree. Even so, the lack means the iSeries
|
||||||
|
boot sequence must be quite different from the pSeries or Macintosh,
|
||||||
|
which is not ideal.
|
||||||
|
|
||||||
|
The device tree also presents a problem for implementing \kexec. When
|
||||||
|
the kernel boots, it takes over full control of the system from OF,
|
||||||
|
even re-using OF's memory. So, when \kexec comes to boot another
|
||||||
|
kernel, OF is no longer around for the second kernel to query.
|
||||||
|
|
||||||
|
\section{The Flattened Tree}
|
||||||
|
|
||||||
|
In May 2005 \benh implemented a new approach to handling the device
|
||||||
|
tree that addresses all these problems. When booting on OF systems,
|
||||||
|
the first thing the kernel runs is a small piece of code in
|
||||||
|
\texttt{prom\_init.c}, which executes in the context of OF. This code
|
||||||
|
walks the device tree using OF calls, and transcribes it into a
|
||||||
|
compact, flattened format. The resulting device tree ``blob'' is then
|
||||||
|
passed to the kernel proper, which eventually unflattens the tree into
|
||||||
|
its runtime form. This blob is the only data communicated between the
|
||||||
|
\texttt{prom\_init.c} bootstrap and the rest of the kernel.
|
||||||
|
|
||||||
|
When OF isn't available, either because the machine doesn't have it at
|
||||||
|
all or because \kexec has been used, the kernel instead starts
|
||||||
|
directly from the entry point taking a flattened device tree. The
|
||||||
|
device tree blob must be passed in from outside, rather than generated
|
||||||
|
by part of the kernel from OF. For \kexec, the userland
|
||||||
|
\texttt{kexec} tools build the blob from the runtime device tree
|
||||||
|
before invoking the new kernel. For embedded systems the blob can
|
||||||
|
come either from the embedded bootloader, or from a specialised
|
||||||
|
version of the \texttt{zImage} wrapper for the system in question.
|
||||||
|
|
||||||
|
\subsection{Properties of the flattened tree}
|
||||||
|
|
||||||
|
The flattened tree format should be easy to handle, both for the
|
||||||
|
kernel that parses it and the bootloader that generates it. In
|
||||||
|
particular, the following properties are desirable:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item \emph{relocatable}: the bootloader or kernel should be able to
|
||||||
|
move the blob around as a whole, without needing to parse or adjust
|
||||||
|
its internals. In practice that means we must not use pointers
|
||||||
|
within the blob.
|
||||||
|
\item \emph{insert and delete}: sometimes the bootloader might want to
|
||||||
|
make tweaks to the flattened tree, such as deleting or inserting a
|
||||||
|
node (or whole subtree). It should be possible to do this without
|
||||||
|
having to effectively regenerate the whole flattened tree. In
|
||||||
|
practice this means limiting the use of internal offsets in the blob
|
||||||
|
that need recalculation if a section is inserted or removed with
|
||||||
|
\texttt{memmove()}.
|
||||||
|
\item \emph{compact}: embedded systems are frequently short of
|
||||||
|
resources, particularly RAM and flash memory space. Thus, the tree
|
||||||
|
representation should be kept as small as conveniently possible.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\subsection{Format of the device tree blob}
|
||||||
|
\label{sec:format}
|
||||||
|
|
||||||
|
\begin{figure}[htb!]
|
||||||
|
\centering
|
||||||
|
\footnotesize
|
||||||
|
\begin{tabular}{r|c|l}
|
||||||
|
\multicolumn{1}{r}{\textbf{Offset}}& \multicolumn{1}{c}{\textbf{Contents}} \\\cline{2-2}
|
||||||
|
\texttt{0x00} & \texttt{0xd00dfeed} & magic number \\\cline{2-2}
|
||||||
|
\texttt{0x04} & \emph{totalsize} \\\cline{2-2}
|
||||||
|
\texttt{0x08} & \emph{off\_struct} & \\\cline{2-2}
|
||||||
|
\texttt{0x0C} & \emph{off\_strs} & \\\cline{2-2}
|
||||||
|
\texttt{0x10} & \emph{off\_rsvmap} & \\\cline{2-2}
|
||||||
|
\texttt{0x14} & \emph{version} \\\cline{2-2}
|
||||||
|
\texttt{0x18} & \emph{last\_comp\_ver} & \\\cline{2-2}
|
||||||
|
\texttt{0x1C} & \emph{boot\_cpu\_id} & \tge v2 only\\\cline{2-2}
|
||||||
|
\texttt{0x20} & \emph{size\_strs} & \tge v3 only\\\cline{2-2}
|
||||||
|
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
|
||||||
|
\emph{off\_rsvmap} & \emph{address0} & memory reserve \\
|
||||||
|
+ \texttt{0x04} & ...& table \\\cline{2-2}
|
||||||
|
+ \texttt{0x08} & \emph{len0} & \\
|
||||||
|
+ \texttt{0x0C} & ...& \\\cline{2-2}
|
||||||
|
\vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
|
||||||
|
& \texttt{0x00000000}- & end marker\\
|
||||||
|
& \texttt{00000000} & \\\cline{2-2}
|
||||||
|
& \texttt{0x00000000}- & \\
|
||||||
|
& \texttt{00000000} & \\\cline{2-2}
|
||||||
|
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
|
||||||
|
\emph{off\_strs} & \texttt{'n' 'a' 'm' 'e'} & strings block \\
|
||||||
|
+ \texttt{0x04} & \texttt{~0~ 'm' 'o' 'd'} & \\
|
||||||
|
+ \texttt{0x08} & \texttt{'e' 'l' ~0~ \makebox[\widthof{~~~}]{\textrm{...}}} & \\
|
||||||
|
\vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
|
||||||
|
\multicolumn{1}{r}{+ \emph{size\_strs}} \\
|
||||||
|
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
|
||||||
|
\emph{off\_struct} & \dtbeginnode & structure block \\\cline{2-2}
|
||||||
|
+ \texttt{0x04} & \texttt{'/' ~0~ ~0~ ~0~} & root node\\\cline{2-2}
|
||||||
|
+ \texttt{0x08} & \dtprop & \\\cline{2-2}
|
||||||
|
+ \texttt{0x0C} & \texttt{0x00000005} & ``\texttt{model}''\\\cline{2-2}
|
||||||
|
+ \texttt{0x10} & \texttt{0x00000008} & \\\cline{2-2}
|
||||||
|
+ \texttt{0x14} & \texttt{'M' 'y' 'B' 'o'} & \\
|
||||||
|
+ \texttt{0x18} & \texttt{'a' 'r' 'd' ~0~} & \\\cline{2-2}
|
||||||
|
\vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
|
||||||
|
& \texttt{\dtendnode} \\\cline{2-2}
|
||||||
|
& \texttt{\dtend} \\\cline{2-2}
|
||||||
|
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
|
||||||
|
\multicolumn{1}{r}{\emph{totalsize}} \\
|
||||||
|
\end{tabular}
|
||||||
|
\caption{Device tree blob layout}
|
||||||
|
\label{fig:blob-layout}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
The format for the blob we devised, was first described on the
|
||||||
|
\texttt{linuxppc64-dev} mailing list in \cite{noof1}. The format has
|
||||||
|
since evolved through various revisions, and the current version is
|
||||||
|
included as part of the \dtc (see \S\ref{sec:dtc}) git tree,
|
||||||
|
\cite{dtcgit}.
|
||||||
|
|
||||||
|
Figure \ref{fig:blob-layout} shows the layout of the blob of data
|
||||||
|
containing the device tree. It has three sections of variable size:
|
||||||
|
the \emph{memory reserve table}, the \emph{structure block} and the
|
||||||
|
\emph{strings block}. A small header gives the blob's size and
|
||||||
|
version and the locations of the three sections, plus a handful of
|
||||||
|
vital parameters used during early boot.
|
||||||
|
|
||||||
|
The memory reserve map section gives a list of regions of memory that
|
||||||
|
the kernel must not use\footnote{Usually such ranges contain some data
|
||||||
|
structure initialised by the firmware that must be preserved by the
|
||||||
|
kernel.}. The list is represented as a simple array of (address,
|
||||||
|
size) pairs of 64 bit values, terminated by a zero size entry. The
|
||||||
|
strings block is similarly simple, consisting of a number of
|
||||||
|
null-terminated strings appended together, which are referenced from
|
||||||
|
the structure block as described below.
|
||||||
|
|
||||||
|
The structure block contains the device tree proper. Each node is
|
||||||
|
introduced with a 32-bit \dtbeginnode tag, followed by the node's name
|
||||||
|
as a null-terminated string, padded to a 32-bit boundary. Then
|
||||||
|
follows all of the properties of the node, each introduced with a
|
||||||
|
\dtprop tag, then all of the node's subnodes, each introduced with
|
||||||
|
their own \dtbeginnode tag. The node ends with an \dtendnode tag, and
|
||||||
|
after the \dtendnode for the root node is an \dtend tag, indicating
|
||||||
|
the end of the whole tree\footnote{This is redundant, but included for
|
||||||
|
ease of parsing.}. The structure block starts with the \dtbeginnode
|
||||||
|
introducing the description of the root node (named \texttt{/}).
|
||||||
|
|
||||||
|
Each property, after the \dtprop, has a 32-bit value giving an offset
|
||||||
|
from the beginning of the strings block at which the property name is
|
||||||
|
stored. Because it's common for many nodes to have properties with
|
||||||
|
the same name, this approach can substantially reduce the total size
|
||||||
|
of the blob. The name offset is followed by the length of the
|
||||||
|
property value (as a 32-bit value) and then the data itself padded to
|
||||||
|
a 32-bit boundary.
|
||||||
|
|
||||||
|
\subsection{Contents of the tree}
|
||||||
|
\label{sec:treecontents}
|
||||||
|
|
||||||
|
Having seen how to represent the device tree structure as a flattened
|
||||||
|
blob, what actually goes into the tree? The short answer is ``the
|
||||||
|
same as an OF tree''. On OF systems, the flattened tree is
|
||||||
|
transcribed directly from the OF device tree, so for simplicity we
|
||||||
|
also use OF conventions for the tree on other systems.
|
||||||
|
|
||||||
|
In many cases a flat tree can be simpler than a typical OF provided
|
||||||
|
device tree. The flattened tree need only provide those nodes and
|
||||||
|
properties that the kernel actually requires; the flattened tree
|
||||||
|
generally need not include devices that the kernel can probe itself.
|
||||||
|
For example, an OF device tree would normally include nodes for each
|
||||||
|
PCI device on the system. A flattened tree need only include nodes
|
||||||
|
for the PCI host bridges; the kernel will scan the buses thus
|
||||||
|
described to find the subsidiary devices. The device tree can include
|
||||||
|
nodes for devices where the kernel needs extra information, though:
|
||||||
|
for example, for ISA devices on a subsidiary PCI/ISA bridge, or for
|
||||||
|
devices with unusual interrupt routing.
|
||||||
|
|
||||||
|
Where they exist, we follow the IEEE1275 bindings that specify how to
|
||||||
|
describe various buses in the device tree (for example,
|
||||||
|
\cite{IEEE1275-pci} describe how to represent PCI devices). The
|
||||||
|
standard has not been updated for a long time, however, and lacks
|
||||||
|
bindings for many modern buses and devices. In particular, embedded
|
||||||
|
specific devices such as the various System-on-Chip buses are not
|
||||||
|
covered. We intend to create new bindings for such buses, in keeping
|
||||||
|
with the general conventions of IEEE1275 (a simple such binding for a
|
||||||
|
System-on-Chip bus was included in \cite{noof5} a revision of
|
||||||
|
\cite{noof1}).
|
||||||
|
|
||||||
|
One complication arises for representing ``phandles'' in the flattened
|
||||||
|
tree. In OF, each node in the tree has an associated phandle, a
|
||||||
|
32-bit integer that uniquely identifies the node\footnote{In practice
|
||||||
|
usually implemented as a pointer or offset within OF memory.}. This
|
||||||
|
handle is used by the various OF calls to query and traverse the tree.
|
||||||
|
Sometimes phandles are also used within the tree to refer to other
|
||||||
|
nodes in the tree. For example, devices that produce interrupts
|
||||||
|
generally have an \texttt{interrupt-parent} property giving the
|
||||||
|
phandle of the interrupt controller that handles interrupts from this
|
||||||
|
device. Parsing these and other interrupt related properties allows
|
||||||
|
the kernel to build a complete representation of the system's
|
||||||
|
interrupt tree, which can be quite different from the tree of bus
|
||||||
|
connections.
|
||||||
|
|
||||||
|
In the flattened tree, a node's phandle is represented by a special
|
||||||
|
\phandle property. When the kernel generates a flattened tree from
|
||||||
|
OF, it adds a \phandle property to each node, containing the phandle
|
||||||
|
retrieved from OF. When the tree is generated without OF, however,
|
||||||
|
only nodes that are actually referred to by phandle need to have this
|
||||||
|
property.
|
||||||
|
|
||||||
|
Another complication arises because nodes in an OF tree have two
|
||||||
|
names. First they have the ``unit name'', which is how the node is
|
||||||
|
referred to in an OF path. The unit name generally consists of a
|
||||||
|
device type followed by an \texttt{@} followed by a \emph{unit
|
||||||
|
address}. For example \texttt{/memory@0} is the full path of a memory
|
||||||
|
node at address 0, \texttt{/ht@0,f2000000/pci@1} is the path of a PCI
|
||||||
|
bus node, which is under a HyperTransport\tm bus node. The form of
|
||||||
|
the unit address is bus dependent, but is generally derived from the
|
||||||
|
node's \texttt{reg} property. In addition, nodes have a property,
|
||||||
|
\texttt{name}, whose value is usually equal to the first path of the
|
||||||
|
unit name. For example, the nodes in the previous example would have
|
||||||
|
\texttt{name} properties equal to \texttt{memory} and \texttt{pci},
|
||||||
|
respectively. To save space in the blob, the current version of the
|
||||||
|
flattened tree format only requires the unit names to be present.
|
||||||
|
When the kernel unflattens the tree, it automatically generates a
|
||||||
|
\texttt{name} property from the node's path name.
|
||||||
|
|
||||||
|
\section{The Device Tree Compiler}
|
||||||
|
\label{sec:dtc}
|
||||||
|
|
||||||
|
\begin{figure}[htb!]
|
||||||
|
\centering
|
||||||
|
\begin{lstlisting}[frame=single,basicstyle=\footnotesize\ttfamily,
|
||||||
|
tabsize=3,numbers=left,xleftmargin=2em]
|
||||||
|
/memreserve/ 0x20000000-0x21FFFFFF;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
model = "MyBoard";
|
||||||
|
compatible = "MyBoardFamily";
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
PowerPC,970@0 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <0>;
|
||||||
|
clock-frequency = <5f5e1000>;
|
||||||
|
timebase-frequency = <1FCA055>;
|
||||||
|
linux,boot-cpu;
|
||||||
|
i-cache-size = <10000>;
|
||||||
|
d-cache-size = <8000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
memory@0 {
|
||||||
|
device_type = "memory";
|
||||||
|
memreg: reg = <00000000 00000000
|
||||||
|
00000000 20000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
mpic@0x3fffdd08400 {
|
||||||
|
/* Interrupt controller */
|
||||||
|
/* ... */
|
||||||
|
};
|
||||||
|
|
||||||
|
pci@40000000000000 {
|
||||||
|
/* PCI host bridge */
|
||||||
|
/* ... */
|
||||||
|
};
|
||||||
|
|
||||||
|
chosen {
|
||||||
|
bootargs = "root=/dev/sda2";
|
||||||
|
linux,platform = <00000600>;
|
||||||
|
interrupt-controller =
|
||||||
|
< &/mpic@0x3fffdd08400 >;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
\end{lstlisting}
|
||||||
|
\caption{Example \dtc source}
|
||||||
|
\label{fig:dts}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
As we've seen, the flattened device tree format provides a convenient
|
||||||
|
way of communicating device tree information to the kernel. It's
|
||||||
|
simple for the kernel to parse, and simple for bootloaders to
|
||||||
|
manipulate. On OF systems, it's easy to generate the flattened tree
|
||||||
|
by walking the OF maintained tree. However, for embedded systems, the
|
||||||
|
flattened tree must be generated from scratch.
|
||||||
|
|
||||||
|
Embedded bootloaders are generally built for a particular board. So,
|
||||||
|
it's usually possible to build the device tree blob at compile time
|
||||||
|
and include it in the bootloader image. For minor revisions of the
|
||||||
|
board, the bootloader can contain code to make the necessary tweaks to
|
||||||
|
the tree before passing it to the booted kernel.
|
||||||
|
|
||||||
|
The device trees for embedded boards are usually quite simple, and
|
||||||
|
it's possible to hand construct the necessary blob by hand, but doing
|
||||||
|
so is tedious. The ``device tree compiler'', \dtc{}\footnote{\dtc can
|
||||||
|
be obtained from \cite{dtcgit}.}, is designed to make creating device
|
||||||
|
tree blobs easier by converting a text representation of the tree
|
||||||
|
into the necessary blob.
|
||||||
|
|
||||||
|
\subsection{Input and output formats}
|
||||||
|
|
||||||
|
As well as the normal mode of compiling a device tree blob from text
|
||||||
|
source, \dtc can convert a device tree between a number of
|
||||||
|
representations. It can take its input in one of three different
|
||||||
|
formats:
|
||||||
|
\begin{itemize}
|
||||||
|
\item source, the normal case. The device tree is described in a text
|
||||||
|
form, described in \S\ref{sec:dts}.
|
||||||
|
\item blob (\texttt{dtb}), the flattened tree format described in
|
||||||
|
\S\ref{sec:format}. This mode is useful for checking a pre-existing
|
||||||
|
device tree blob.
|
||||||
|
\item filesystem (\texttt{fs}), input is a directory tree in the
|
||||||
|
layout of \texttt{/proc/device-tree} (roughly, a directory for each
|
||||||
|
node in the device tree, a file for each property). This is useful
|
||||||
|
for building a blob for the device tree in use by the currently
|
||||||
|
running kernel.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
In addition, \dtc can output the tree in one of three different
|
||||||
|
formats:
|
||||||
|
\begin{itemize}
|
||||||
|
\item blob (\texttt{dtb}), as in \S\ref{sec:format}. The most
|
||||||
|
straightforward use of \dtc is to compile from ``source'' to
|
||||||
|
``blob'' format.
|
||||||
|
\item source (\texttt{dts}), as in \S\ref{sec:dts}. If used with blob
|
||||||
|
input, this allows \dtc to act as a ``decompiler''.
|
||||||
|
\item assembler source (\texttt{asm}). \dtc can produce an assembler
|
||||||
|
file, which will assemble into a \texttt{.o} file containing the
|
||||||
|
device tree blob, with symbols giving the beginning of the blob and
|
||||||
|
its various subsections. This can then be linked directly into a
|
||||||
|
bootloader or firmware image.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
For maximum applicability, \dtc can both read and write any of the
|
||||||
|
existing revisions of the blob format. When reading, \dtc takes the
|
||||||
|
version from the blob header, and when writing it takes a command line
|
||||||
|
option specifying the desired version. It automatically makes any
|
||||||
|
necessary adjustments to the tree that are necessary for the specified
|
||||||
|
version. For example, formats before 0x10 require each node to have
|
||||||
|
an explicit \texttt{name} property. When \dtc creates such a blob, it
|
||||||
|
will automatically generate \texttt{name} properties from the unit
|
||||||
|
names.
|
||||||
|
|
||||||
|
\subsection{Source format}
|
||||||
|
\label{sec:dts}
|
||||||
|
|
||||||
|
The ``source'' format for \dtc is a text description of the device
|
||||||
|
tree in a vaguely C-like form. Figure \ref{fig:dts} shows an
|
||||||
|
example. The file starts with \texttt{/memreserve/} directives, which
|
||||||
|
gives address ranges to add to the output blob's memory reserve table,
|
||||||
|
then the device tree proper is described.
|
||||||
|
|
||||||
|
Nodes of the tree are introduced with the node name, followed by a
|
||||||
|
\texttt{\{} ... \texttt{\};} block containing the node's properties
|
||||||
|
and subnodes. Properties are given as just {\emph{name} \texttt{=}
|
||||||
|
\emph{value}\texttt{;}}. The property values can be given in any
|
||||||
|
of three forms:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \emph{string} (for example, \texttt{"MyBoard"}). The property
|
||||||
|
value is the given string, including terminating NULL. C-style
|
||||||
|
escapes (\verb+\t+, \verb+\n+, \verb+\0+ and so forth) are allowed.
|
||||||
|
\item \emph{cells} (for example, \texttt{<0 8000 f0000000>}). The
|
||||||
|
property value is made up of a list of 32-bit ``cells'', each given
|
||||||
|
as a hex value.
|
||||||
|
\item \emph{bytestring} (for example, \texttt{[1234abcdef]}). The
|
||||||
|
property value is given as a hex bytestring.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Cell properties can also contain \emph{references}. Instead of a hex
|
||||||
|
number, the source can give an ampersand (\texttt{\&}) followed by the
|
||||||
|
full path to some node in the tree. For example, in Figure
|
||||||
|
\ref{fig:dts}, the \texttt{/chosen} node has an
|
||||||
|
\texttt{interrupt-controller} property referring to the interrupt
|
||||||
|
controller described by the node \texttt{/mpic@0x3fffdd08400}. In the
|
||||||
|
output tree, the value of the referenced node's phandle is included in
|
||||||
|
the property. If that node doesn't have an explicit phandle property,
|
||||||
|
\dtc will automatically create a unique phandle for it. This approach
|
||||||
|
makes it easy to create interrupt trees without having to explicitly
|
||||||
|
assign and remember phandles for the various interrupt controller
|
||||||
|
nodes.
|
||||||
|
|
||||||
|
The \dtc source can also include ``labels'', which are placed on a
|
||||||
|
particular node or property. For example, Figure \ref{fig:dts} has a
|
||||||
|
label ``\texttt{memreg}'' on the \texttt{reg} property of the node
|
||||||
|
\texttt{/memory@0}. When using assembler output, corresponding labels
|
||||||
|
in the output are generated, which will assemble into symbols
|
||||||
|
addressing the part of the blob with the node or property in question.
|
||||||
|
This is useful for the common case where an embedded board has an
|
||||||
|
essentially fixed device tree with a few variable properties, such as
|
||||||
|
the size of memory. The bootloader for such a board can have a device
|
||||||
|
tree linked in, including a symbol referring to the right place in the
|
||||||
|
blob to update the parameter with the correct value determined at
|
||||||
|
runtime.
|
||||||
|
|
||||||
|
\subsection{Tree checking}
|
||||||
|
|
||||||
|
Between reading in the device tree and writing it out in the new
|
||||||
|
format, \dtc performs a number of checks on the tree:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \emph{syntactic structure}: \dtc checks that node and property
|
||||||
|
names contain only allowed characters and meet length restrictions.
|
||||||
|
It checks that a node does not have multiple properties or subnodes
|
||||||
|
with the same name.
|
||||||
|
\item \emph{semantic structure}: In some cases, \dtc checks that
|
||||||
|
properties whose contents are defined by convention have appropriate
|
||||||
|
values. For example, it checks that \texttt{reg} properties have a
|
||||||
|
length that makes sense given the address forms specified by the
|
||||||
|
\texttt{\#address-cells} and \texttt{\#size-cells} properties. It
|
||||||
|
checks that properties such as \texttt{interrupt-parent} contain a
|
||||||
|
valid phandle.
|
||||||
|
\item \emph{Linux requirements}: \dtc checks that the device tree
|
||||||
|
contains those nodes and properties that are required by the Linux
|
||||||
|
kernel to boot correctly.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
These checks are useful to catch simple problems with the device tree,
|
||||||
|
rather than having to debug the results on an embedded kernel. With
|
||||||
|
the blob input mode, it can also be used for diagnosing problems with
|
||||||
|
an existing blob.
|
||||||
|
|
||||||
|
\section{Future Work}
|
||||||
|
|
||||||
|
\subsection{Board ports}
|
||||||
|
|
||||||
|
The flattened device tree has always been the only supported way to
|
||||||
|
boot a \texttt{ppc64} kernel on an embedded system. With the merge of
|
||||||
|
\texttt{ppc32} and \texttt{ppc64} code it has also become the only
|
||||||
|
supported way to boot any merged \texttt{powerpc} kernel, 32-bit or
|
||||||
|
64-bit. In fact, the old \texttt{ppc} architecture exists mainly just
|
||||||
|
to support the old ppc32 embedded ports that have not been migrated
|
||||||
|
to the flattened device tree approach. We plan to remove the
|
||||||
|
\texttt{ppc} architecture eventually, which will mean porting all the
|
||||||
|
various embedded boards to use the flattened device tree.
|
||||||
|
|
||||||
|
\subsection{\dtc features}
|
||||||
|
|
||||||
|
While it is already quite usable, there are a number of extra features
|
||||||
|
that \dtc could include to make creating device trees more convenient:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \emph{better tree checking}: Although \dtc already performs a
|
||||||
|
number of checks on the device tree, they are rather haphazard. In
|
||||||
|
many cases \dtc will give up after detecting a minor error early and
|
||||||
|
won't pick up more interesting errors later on. There is a
|
||||||
|
\texttt{-f} parameter that forces \dtc to generate an output tree
|
||||||
|
even if there are errors. At present, this needs to be used more
|
||||||
|
often than one might hope, because \dtc is bad at deciding which
|
||||||
|
errors should really be fatal, and which rate mere warnings.
|
||||||
|
\item \emph{binary include}: Occasionally, it is useful for the device
|
||||||
|
tree to incorporate as a property a block of binary data for some
|
||||||
|
board-specific purpose. For example, many of Apple's device trees
|
||||||
|
incorporate bytecode drivers for certain platform devices. \dtc's
|
||||||
|
source format ought to allow this by letting a property's value be
|
||||||
|
read directly from a binary file.
|
||||||
|
\item \emph{macros}: it might be useful for \dtc to implement some
|
||||||
|
sort of macros so that a tree containing a number of similar devices
|
||||||
|
(for example, multiple identical ethernet controllers or PCI buses)
|
||||||
|
can be written more quickly. At present, this can be accomplished
|
||||||
|
in part by running the source file through CPP before compiling with
|
||||||
|
\dtc. It's not clear whether ``native'' support for macros would be
|
||||||
|
more useful.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\bibliographystyle{amsplain}
|
||||||
|
\bibliography{dtc-paper}
|
||||||
|
|
||||||
|
\section*{About the authors}
|
||||||
|
|
||||||
|
David Gibson has been a member of the IBM Linux Technology Center,
|
||||||
|
working from Canberra, Australia, since 2001. Recently he has worked
|
||||||
|
on Linux hugepage support and performance counter support for ppc64,
|
||||||
|
as well as the device tree compiler. In the past, he has worked on
|
||||||
|
bringup for various ppc and ppc64 embedded systems, the orinoco
|
||||||
|
wireless driver, ramfs, and a userspace checkpointing system
|
||||||
|
(\texttt{esky}).
|
||||||
|
|
||||||
|
Benjamin Herrenschmidt was a MacOS developer for about 10 years, but
|
||||||
|
ultimately saw the light and installed Linux on his Apple PowerPC
|
||||||
|
machine. After writing a bootloader, BootX, for it in 1998, he
|
||||||
|
started contributing to the PowerPC Linux port in various areas,
|
||||||
|
mostly around the support for Apple machines. He became official
|
||||||
|
PowerMac maintainer in 2001. In 2003, he joined the IBM Linux
|
||||||
|
Technology Center in Canberra, Australia, where he ported the 64 bit
|
||||||
|
PowerPC kernel to Apple G5 machines and the Maple embedded board,
|
||||||
|
among others things. He's a member of the ppc64 development ``team''
|
||||||
|
and one of his current goals is to make the integration of embedded
|
||||||
|
platforms smoother and more maintainable than in the 32-bit PowerPC
|
||||||
|
kernel.
|
||||||
|
|
||||||
|
\section*{Legal Statement}
|
||||||
|
|
||||||
|
This work represents the view of the author and does not necessarily
|
||||||
|
represent the view of IBM.
|
||||||
|
|
||||||
|
IBM, \ppc, \ppc Architecture, POWER5, pSeries and iSeries are
|
||||||
|
trademarks or registered trademarks of International Business Machines
|
||||||
|
Corporation in the United States and/or other countries.
|
||||||
|
|
||||||
|
Apple and Power Macintosh are a registered trademarks of Apple
|
||||||
|
Computer Inc. in the United States, other countries, or both.
|
||||||
|
|
||||||
|
Linux is a registered trademark of Linus Torvalds.
|
||||||
|
|
||||||
|
Other company, product, and service names may be trademarks or service
|
||||||
|
marks of others.
|
||||||
|
|
||||||
|
\end{document}
|
||||||
122
dtc-1.4.5/Documentation/dts-format.txt
Normal file
122
dtc-1.4.5/Documentation/dts-format.txt
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
Device Tree Source Format (version 1)
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
The Device Tree Source (DTS) format is a textual representation of a
|
||||||
|
device tree in a form that can be processed by dtc into a binary
|
||||||
|
device tree in the form expected by the kernel. The description below
|
||||||
|
is not a formal syntax definition of DTS, but describes the basic
|
||||||
|
constructs used to represent device trees.
|
||||||
|
|
||||||
|
Node and property definitions
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Device tree nodes are defined with a node name and unit address with
|
||||||
|
braces marking the start and end of the node definition. They may be
|
||||||
|
preceded by a label.
|
||||||
|
|
||||||
|
[label:] node-name[@unit-address] {
|
||||||
|
[properties definitions]
|
||||||
|
[child nodes]
|
||||||
|
}
|
||||||
|
|
||||||
|
Nodes may contain property definitions and/or child node
|
||||||
|
definitions. If both are present, properties must come before child
|
||||||
|
nodes.
|
||||||
|
|
||||||
|
Property definitions are name value pairs in the form:
|
||||||
|
[label:] property-name = value;
|
||||||
|
except for properties with empty (zero length) value which have the
|
||||||
|
form:
|
||||||
|
[label:] property-name;
|
||||||
|
|
||||||
|
Property values may be defined as an array of 8, 16, 32, or 64-bit integer
|
||||||
|
elements, as NUL-terminated strings, as bytestrings or a combination of these.
|
||||||
|
|
||||||
|
* Arrays are represented by angle brackets surrounding a space separated list
|
||||||
|
of C-style integers or character literals. Array elements default to 32-bits
|
||||||
|
in size. An array of 32-bit elements is also known as a cell list or a list
|
||||||
|
of cells. A cell being an unsigned 32-bit integer.
|
||||||
|
|
||||||
|
e.g. interrupts = <17 0xc>;
|
||||||
|
|
||||||
|
* A 64-bit value can be represented with two 32-bit elements.
|
||||||
|
|
||||||
|
e.g. clock-frequency = <0x00000001 0x00000000>;
|
||||||
|
|
||||||
|
* The storage size of an element can be changed using the /bits/ prefix. The
|
||||||
|
/bits/ prefix allows for the creation of 8, 16, 32, and 64-bit elements.
|
||||||
|
The resulting array will not be padded to a multiple of the default 32-bit
|
||||||
|
element size.
|
||||||
|
|
||||||
|
e.g. interrupts = /bits/ 8 <17 0xc>;
|
||||||
|
e.g. clock-frequency = /bits/ 64 <0x0000000100000000>;
|
||||||
|
|
||||||
|
* A NUL-terminated string value is represented using double quotes
|
||||||
|
(the property value is considered to include the terminating NUL
|
||||||
|
character).
|
||||||
|
|
||||||
|
e.g. compatible = "simple-bus";
|
||||||
|
|
||||||
|
* A bytestring is enclosed in square brackets [] with each byte
|
||||||
|
represented by two hexadecimal digits. Spaces between each byte are
|
||||||
|
optional.
|
||||||
|
|
||||||
|
e.g. local-mac-address = [00 00 12 34 56 78]; or equivalently
|
||||||
|
local-mac-address = [000012345678];
|
||||||
|
|
||||||
|
* Values may have several comma-separated components, which are
|
||||||
|
concatenated together.
|
||||||
|
e.g. compatible = "ns16550", "ns8250";
|
||||||
|
example = <0xf00f0000 19>, "a strange property format";
|
||||||
|
|
||||||
|
* In an array a reference to another node will be expanded to that node's
|
||||||
|
phandle. References may by '&' followed by a node's label:
|
||||||
|
e.g. interrupt-parent = < &mpic >;
|
||||||
|
or they may be '&' followed by a node's full path in braces:
|
||||||
|
e.g. interrupt-parent = < &{/soc/interrupt-controller@40000} >;
|
||||||
|
References are only permitted in arrays that have an element size of
|
||||||
|
32-bits.
|
||||||
|
|
||||||
|
* Outside an array, a reference to another node will be expanded to that
|
||||||
|
node's full path.
|
||||||
|
e.g. ethernet0 = &EMAC0;
|
||||||
|
|
||||||
|
* Labels may also appear before or after any component of a property
|
||||||
|
value, or between elements of an array, or between bytes of a bytestring.
|
||||||
|
e.g. reg = reglabel: <0 sizelabel: 0x1000000>;
|
||||||
|
e.g. prop = [ab cd ef byte4: 00 ff fe];
|
||||||
|
e.g. str = start: "string value" end: ;
|
||||||
|
|
||||||
|
|
||||||
|
File layout
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Version 1 DTS files have the overall layout:
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
[memory reservations]
|
||||||
|
|
||||||
|
/ {
|
||||||
|
[property definitions]
|
||||||
|
[child nodes]
|
||||||
|
};
|
||||||
|
|
||||||
|
* The "/dts-v1/;" must be present to identify the file as a version 1
|
||||||
|
DTS (dts files without this tag will be treated by dtc as being in
|
||||||
|
the obsolete "version 0", which uses a different format for integers
|
||||||
|
amongst other small but incompatible changes).
|
||||||
|
|
||||||
|
* Memory reservations define an entry for the device tree blob's
|
||||||
|
memory reservation table. They have the form:
|
||||||
|
e.g. /memreserve/ <address> <length>;
|
||||||
|
Where <address> and <length> are 64-bit C-style integers.
|
||||||
|
|
||||||
|
* The / { ... }; section defines the root node of the device tree.
|
||||||
|
|
||||||
|
* C style (/* ... */) and C++ style (// ...) comments are supported.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
-- Yoder Stuart <stuart.yoder@freescale.com>
|
||||||
|
-- Anton Staaf <robotboy@chromium.org>
|
||||||
695
dtc-1.4.5/Documentation/manual.txt
Normal file
695
dtc-1.4.5/Documentation/manual.txt
Normal file
@@ -0,0 +1,695 @@
|
|||||||
|
Device Tree Compiler Manual
|
||||||
|
===========================
|
||||||
|
|
||||||
|
I - "dtc", the device tree compiler
|
||||||
|
1) Obtaining Sources
|
||||||
|
1.1) Submitting Patches
|
||||||
|
2) Description
|
||||||
|
3) Command Line
|
||||||
|
4) Source File
|
||||||
|
4.1) Overview
|
||||||
|
4.2) Properties
|
||||||
|
4.3) Labels and References
|
||||||
|
|
||||||
|
II - The DT block format
|
||||||
|
1) Header
|
||||||
|
2) Device tree generalities
|
||||||
|
3) Device tree "structure" block
|
||||||
|
4) Device tree "strings" block
|
||||||
|
|
||||||
|
|
||||||
|
III - libfdt
|
||||||
|
|
||||||
|
IV - Utility Tools
|
||||||
|
1) convert-dtsv0 -- Conversion to Version 1
|
||||||
|
1) fdtdump
|
||||||
|
|
||||||
|
|
||||||
|
I - "dtc", the device tree compiler
|
||||||
|
===================================
|
||||||
|
|
||||||
|
1) Sources
|
||||||
|
|
||||||
|
Source code for the Device Tree Compiler can be found at git.kernel.org.
|
||||||
|
|
||||||
|
The upstream repository is here:
|
||||||
|
|
||||||
|
git://git.kernel.org/pub/scm/utils/dtc/dtc.git
|
||||||
|
https://git.kernel.org/pub/scm/utils/dtc/dtc.git
|
||||||
|
|
||||||
|
The gitweb interface for the upstream respository is:
|
||||||
|
|
||||||
|
https://git.kernel.org/cgit/utils/dtc/dtc.git/
|
||||||
|
|
||||||
|
1.1) Submitting Patches
|
||||||
|
|
||||||
|
Patches should be sent to the maintainers:
|
||||||
|
David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
Jon Loeliger <jdl@jdl.com>
|
||||||
|
and CCed to <devicetree-compiler@vger.kernel.org>.
|
||||||
|
|
||||||
|
2) Description
|
||||||
|
|
||||||
|
The Device Tree Compiler, dtc, takes as input a device-tree in
|
||||||
|
a given format and outputs a device-tree in another format.
|
||||||
|
Typically, the input format is "dts", a human readable source
|
||||||
|
format, and creates a "dtb", or binary format as output.
|
||||||
|
|
||||||
|
The currently supported Input Formats are:
|
||||||
|
|
||||||
|
- "dtb": "blob" format. A flattened device-tree block with
|
||||||
|
header in one binary blob.
|
||||||
|
|
||||||
|
- "dts": "source" format. A text file containing a "source"
|
||||||
|
for a device-tree.
|
||||||
|
|
||||||
|
- "fs" format. A representation equivalent to the output of
|
||||||
|
/proc/device-tree where nodes are directories and
|
||||||
|
properties are files.
|
||||||
|
|
||||||
|
The currently supported Output Formats are:
|
||||||
|
|
||||||
|
- "dtb": "blob" format
|
||||||
|
|
||||||
|
- "dts": "source" format
|
||||||
|
|
||||||
|
- "asm": assembly language file. A file that can be sourced
|
||||||
|
by gas to generate a device-tree "blob". That file can
|
||||||
|
then simply be added to your Makefile. Additionally, the
|
||||||
|
assembly file exports some symbols that can be used.
|
||||||
|
|
||||||
|
|
||||||
|
3) Command Line
|
||||||
|
|
||||||
|
The syntax of the dtc command line is:
|
||||||
|
|
||||||
|
dtc [options] [<input_filename>]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
<input_filename>
|
||||||
|
The name of the input source file. If no <input_filename>
|
||||||
|
or "-" is given, stdin is used.
|
||||||
|
|
||||||
|
-b <number>
|
||||||
|
Set the physical boot cpu.
|
||||||
|
|
||||||
|
-f
|
||||||
|
Force. Try to produce output even if the input tree has errors.
|
||||||
|
|
||||||
|
-h
|
||||||
|
Emit a brief usage and help message.
|
||||||
|
|
||||||
|
-I <input_format>
|
||||||
|
The source input format, as listed above.
|
||||||
|
|
||||||
|
-o <output_filename>
|
||||||
|
The name of the generated output file. Use "-" for stdout.
|
||||||
|
|
||||||
|
-O <output_format>
|
||||||
|
The generated output format, as listed above.
|
||||||
|
|
||||||
|
-d <dependency_filename>
|
||||||
|
Generate a dependency file during compilation.
|
||||||
|
|
||||||
|
-q
|
||||||
|
Quiet: -q suppress warnings, -qq errors, -qqq all
|
||||||
|
|
||||||
|
-R <number>
|
||||||
|
Make space for <number> reserve map entries
|
||||||
|
Relevant for dtb and asm output only.
|
||||||
|
|
||||||
|
-@
|
||||||
|
Generates a __symbols__ node at the root node of the resulting blob
|
||||||
|
for any node labels used, and for any local references using phandles
|
||||||
|
it also generates a __local_fixups__ node that tracks them.
|
||||||
|
|
||||||
|
When using the /plugin/ tag all unresolved label references to
|
||||||
|
be tracked in the __fixups__ node, making dynamic resolution possible.
|
||||||
|
|
||||||
|
-A
|
||||||
|
Generate automatically aliases for all node labels. This is similar to
|
||||||
|
the -@ option (the __symbols__ node contain identical information) but
|
||||||
|
the semantics are slightly different since no phandles are automatically
|
||||||
|
generated for labeled nodes.
|
||||||
|
|
||||||
|
-S <bytes>
|
||||||
|
Ensure the blob at least <bytes> long, adding additional
|
||||||
|
space if needed.
|
||||||
|
|
||||||
|
-v
|
||||||
|
Print DTC version and exit.
|
||||||
|
|
||||||
|
-V <output_version>
|
||||||
|
Generate output conforming to the given <output_version>.
|
||||||
|
By default the most recent version is generated.
|
||||||
|
Relevant for dtb and asm output only.
|
||||||
|
|
||||||
|
|
||||||
|
The <output_version> defines what version of the "blob" format will be
|
||||||
|
generated. Supported versions are 1, 2, 3, 16 and 17. The default is
|
||||||
|
always the most recent version and is likely the highest number.
|
||||||
|
|
||||||
|
Additionally, dtc performs various sanity checks on the tree.
|
||||||
|
|
||||||
|
|
||||||
|
4) Device Tree Source file
|
||||||
|
|
||||||
|
4.1) Overview
|
||||||
|
|
||||||
|
Here is a very rough overview of the layout of a DTS source file:
|
||||||
|
|
||||||
|
|
||||||
|
sourcefile: versioninfo plugindecl list_of_memreserve devicetree
|
||||||
|
|
||||||
|
memreserve: label 'memreserve' ADDR ADDR ';'
|
||||||
|
| label 'memreserve' ADDR '-' ADDR ';'
|
||||||
|
|
||||||
|
devicetree: '/' nodedef
|
||||||
|
|
||||||
|
versioninfo: '/' 'dts-v1' '/' ';'
|
||||||
|
|
||||||
|
plugindecl: '/' 'plugin' '/' ';'
|
||||||
|
| /* empty */
|
||||||
|
|
||||||
|
nodedef: '{' list_of_property list_of_subnode '}' ';'
|
||||||
|
|
||||||
|
property: label PROPNAME '=' propdata ';'
|
||||||
|
|
||||||
|
propdata: STRING
|
||||||
|
| '<' list_of_cells '>'
|
||||||
|
| '[' list_of_bytes ']'
|
||||||
|
|
||||||
|
subnode: label nodename nodedef
|
||||||
|
|
||||||
|
That structure forms a hierarchical layout of nodes and properties
|
||||||
|
rooted at an initial node as:
|
||||||
|
|
||||||
|
/ {
|
||||||
|
}
|
||||||
|
|
||||||
|
Both classic C style and C++ style comments are supported.
|
||||||
|
|
||||||
|
Source files may be directly included using the syntax:
|
||||||
|
|
||||||
|
/include/ "filename"
|
||||||
|
|
||||||
|
|
||||||
|
4.2) Properties
|
||||||
|
|
||||||
|
Properties are named, possibly labeled, values. Each value
|
||||||
|
is one of:
|
||||||
|
|
||||||
|
- A null-teminated C-like string,
|
||||||
|
- A numeric value fitting in 32 bits,
|
||||||
|
- A list of 32-bit values
|
||||||
|
- A byte sequence
|
||||||
|
|
||||||
|
Here are some example property definitions:
|
||||||
|
|
||||||
|
- A property containing a 0 terminated string
|
||||||
|
|
||||||
|
property1 = "string_value";
|
||||||
|
|
||||||
|
- A property containing a numerical 32-bit hexadecimal value
|
||||||
|
|
||||||
|
property2 = <1234abcd>;
|
||||||
|
|
||||||
|
- A property containing 3 numerical 32-bit hexadecimal values
|
||||||
|
|
||||||
|
property3 = <12345678 12345678 deadbeef>;
|
||||||
|
|
||||||
|
- A property whose content is an arbitrary array of bytes
|
||||||
|
|
||||||
|
property4 = [0a 0b 0c 0d de ea ad be ef];
|
||||||
|
|
||||||
|
|
||||||
|
Node may contain sub-nodes to obtain a hierarchical structure.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
- A child node named "childnode" whose unit name is
|
||||||
|
"childnode at address". It in turn has a string property
|
||||||
|
called "childprop".
|
||||||
|
|
||||||
|
childnode@addresss {
|
||||||
|
childprop = "hello\n";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
By default, all numeric values are hexadecimal. Alternate bases
|
||||||
|
may be specified using a prefix "d#" for decimal, "b#" for binary,
|
||||||
|
and "o#" for octal.
|
||||||
|
|
||||||
|
Strings support common escape sequences from C: "\n", "\t", "\r",
|
||||||
|
"\(octal value)", "\x(hex value)".
|
||||||
|
|
||||||
|
|
||||||
|
4.3) Labels and References
|
||||||
|
|
||||||
|
Labels may be applied to nodes or properties. Labels appear
|
||||||
|
before a node name, and are referenced using an ampersand: &label.
|
||||||
|
Absolute node path names are also allowed in node references.
|
||||||
|
|
||||||
|
In this exmaple, a node is labled "mpic" and then referenced:
|
||||||
|
|
||||||
|
mpic: interrupt-controller@40000 {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
ethernet-phy@3 {
|
||||||
|
interrupt-parent = <&mpic>;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
And used in properties, lables may appear before or after any value:
|
||||||
|
|
||||||
|
randomnode {
|
||||||
|
prop: string = data: "mystring\n" data_end: ;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
II - The DT block format
|
||||||
|
========================
|
||||||
|
|
||||||
|
This chapter defines the format of the flattened device-tree
|
||||||
|
passed to the kernel. The actual content of the device tree
|
||||||
|
are described in the kernel documentation in the file
|
||||||
|
|
||||||
|
linux-2.6/Documentation/powerpc/booting-without-of.txt
|
||||||
|
|
||||||
|
You can find example of code manipulating that format within
|
||||||
|
the kernel. For example, the file:
|
||||||
|
|
||||||
|
including arch/powerpc/kernel/prom_init.c
|
||||||
|
|
||||||
|
will generate a flattened device-tree from the Open Firmware
|
||||||
|
representation. Other utilities such as fs2dt, which is part of
|
||||||
|
the kexec tools, will generate one from a filesystem representation.
|
||||||
|
Some bootloaders such as U-Boot provide a bit more support by
|
||||||
|
using the libfdt code.
|
||||||
|
|
||||||
|
For booting the kernel, the device tree block has to be in main memory.
|
||||||
|
It has to be accessible in both real mode and virtual mode with no
|
||||||
|
mapping other than main memory. If you are writing a simple flash
|
||||||
|
bootloader, it should copy the block to RAM before passing it to
|
||||||
|
the kernel.
|
||||||
|
|
||||||
|
|
||||||
|
1) Header
|
||||||
|
---------
|
||||||
|
|
||||||
|
The kernel is entered with r3 pointing to an area of memory that is
|
||||||
|
roughly described in include/asm-powerpc/prom.h by the structure
|
||||||
|
boot_param_header:
|
||||||
|
|
||||||
|
struct boot_param_header {
|
||||||
|
u32 magic; /* magic word OF_DT_HEADER */
|
||||||
|
u32 totalsize; /* total size of DT block */
|
||||||
|
u32 off_dt_struct; /* offset to structure */
|
||||||
|
u32 off_dt_strings; /* offset to strings */
|
||||||
|
u32 off_mem_rsvmap; /* offset to memory reserve map */
|
||||||
|
u32 version; /* format version */
|
||||||
|
u32 last_comp_version; /* last compatible version */
|
||||||
|
|
||||||
|
/* version 2 fields below */
|
||||||
|
u32 boot_cpuid_phys; /* Which physical CPU id we're
|
||||||
|
booting on */
|
||||||
|
/* version 3 fields below */
|
||||||
|
u32 size_dt_strings; /* size of the strings block */
|
||||||
|
|
||||||
|
/* version 17 fields below */
|
||||||
|
u32 size_dt_struct; /* size of the DT structure block */
|
||||||
|
};
|
||||||
|
|
||||||
|
Along with the constants:
|
||||||
|
|
||||||
|
/* Definitions used by the flattened device tree */
|
||||||
|
#define OF_DT_HEADER 0xd00dfeed /* 4: version,
|
||||||
|
4: total size */
|
||||||
|
#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name
|
||||||
|
*/
|
||||||
|
#define OF_DT_END_NODE 0x2 /* End node */
|
||||||
|
#define OF_DT_PROP 0x3 /* Property: name off,
|
||||||
|
size, content */
|
||||||
|
#define OF_DT_END 0x9
|
||||||
|
|
||||||
|
All values in this header are in big endian format, the various
|
||||||
|
fields in this header are defined more precisely below. All "offset"
|
||||||
|
values are in bytes from the start of the header; that is from the
|
||||||
|
value of r3.
|
||||||
|
|
||||||
|
- magic
|
||||||
|
|
||||||
|
This is a magic value that "marks" the beginning of the
|
||||||
|
device-tree block header. It contains the value 0xd00dfeed and is
|
||||||
|
defined by the constant OF_DT_HEADER
|
||||||
|
|
||||||
|
- totalsize
|
||||||
|
|
||||||
|
This is the total size of the DT block including the header. The
|
||||||
|
"DT" block should enclose all data structures defined in this
|
||||||
|
chapter (who are pointed to by offsets in this header). That is,
|
||||||
|
the device-tree structure, strings, and the memory reserve map.
|
||||||
|
|
||||||
|
- off_dt_struct
|
||||||
|
|
||||||
|
This is an offset from the beginning of the header to the start
|
||||||
|
of the "structure" part the device tree. (see 2) device tree)
|
||||||
|
|
||||||
|
- off_dt_strings
|
||||||
|
|
||||||
|
This is an offset from the beginning of the header to the start
|
||||||
|
of the "strings" part of the device-tree
|
||||||
|
|
||||||
|
- off_mem_rsvmap
|
||||||
|
|
||||||
|
This is an offset from the beginning of the header to the start
|
||||||
|
of the reserved memory map. This map is a list of pairs of 64-
|
||||||
|
bit integers. Each pair is a physical address and a size. The
|
||||||
|
list is terminated by an entry of size 0. This map provides the
|
||||||
|
kernel with a list of physical memory areas that are "reserved"
|
||||||
|
and thus not to be used for memory allocations, especially during
|
||||||
|
early initialization. The kernel needs to allocate memory during
|
||||||
|
boot for things like un-flattening the device-tree, allocating an
|
||||||
|
MMU hash table, etc... Those allocations must be done in such a
|
||||||
|
way to avoid overriding critical things like, on Open Firmware
|
||||||
|
capable machines, the RTAS instance, or on some pSeries, the TCE
|
||||||
|
tables used for the iommu. Typically, the reserve map should
|
||||||
|
contain _at least_ this DT block itself (header,total_size). If
|
||||||
|
you are passing an initrd to the kernel, you should reserve it as
|
||||||
|
well. You do not need to reserve the kernel image itself. The map
|
||||||
|
should be 64-bit aligned.
|
||||||
|
|
||||||
|
- version
|
||||||
|
|
||||||
|
This is the version of this structure. Version 1 stops
|
||||||
|
here. Version 2 adds an additional field boot_cpuid_phys.
|
||||||
|
Version 3 adds the size of the strings block, allowing the kernel
|
||||||
|
to reallocate it easily at boot and free up the unused flattened
|
||||||
|
structure after expansion. Version 16 introduces a new more
|
||||||
|
"compact" format for the tree itself that is however not backward
|
||||||
|
compatible. Version 17 adds an additional field, size_dt_struct,
|
||||||
|
allowing it to be reallocated or moved more easily (this is
|
||||||
|
particularly useful for bootloaders which need to make
|
||||||
|
adjustments to a device tree based on probed information). You
|
||||||
|
should always generate a structure of the highest version defined
|
||||||
|
at the time of your implementation. Currently that is version 17,
|
||||||
|
unless you explicitly aim at being backward compatible.
|
||||||
|
|
||||||
|
- last_comp_version
|
||||||
|
|
||||||
|
Last compatible version. This indicates down to what version of
|
||||||
|
the DT block you are backward compatible. For example, version 2
|
||||||
|
is backward compatible with version 1 (that is, a kernel build
|
||||||
|
for version 1 will be able to boot with a version 2 format). You
|
||||||
|
should put a 1 in this field if you generate a device tree of
|
||||||
|
version 1 to 3, or 16 if you generate a tree of version 16 or 17
|
||||||
|
using the new unit name format.
|
||||||
|
|
||||||
|
- boot_cpuid_phys
|
||||||
|
|
||||||
|
This field only exist on version 2 headers. It indicate which
|
||||||
|
physical CPU ID is calling the kernel entry point. This is used,
|
||||||
|
among others, by kexec. If you are on an SMP system, this value
|
||||||
|
should match the content of the "reg" property of the CPU node in
|
||||||
|
the device-tree corresponding to the CPU calling the kernel entry
|
||||||
|
point (see further chapters for more informations on the required
|
||||||
|
device-tree contents)
|
||||||
|
|
||||||
|
- size_dt_strings
|
||||||
|
|
||||||
|
This field only exists on version 3 and later headers. It
|
||||||
|
gives the size of the "strings" section of the device tree (which
|
||||||
|
starts at the offset given by off_dt_strings).
|
||||||
|
|
||||||
|
- size_dt_struct
|
||||||
|
|
||||||
|
This field only exists on version 17 and later headers. It gives
|
||||||
|
the size of the "structure" section of the device tree (which
|
||||||
|
starts at the offset given by off_dt_struct).
|
||||||
|
|
||||||
|
So the typical layout of a DT block (though the various parts don't
|
||||||
|
need to be in that order) looks like this (addresses go from top to
|
||||||
|
bottom):
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
r3 -> | struct boot_param_header |
|
||||||
|
------------------------------
|
||||||
|
| (alignment gap) (*) |
|
||||||
|
------------------------------
|
||||||
|
| memory reserve map |
|
||||||
|
------------------------------
|
||||||
|
| (alignment gap) |
|
||||||
|
------------------------------
|
||||||
|
| |
|
||||||
|
| device-tree structure |
|
||||||
|
| |
|
||||||
|
------------------------------
|
||||||
|
| (alignment gap) |
|
||||||
|
------------------------------
|
||||||
|
| |
|
||||||
|
| device-tree strings |
|
||||||
|
| |
|
||||||
|
-----> ------------------------------
|
||||||
|
|
|
||||||
|
|
|
||||||
|
--- (r3 + totalsize)
|
||||||
|
|
||||||
|
(*) The alignment gaps are not necessarily present; their presence
|
||||||
|
and size are dependent on the various alignment requirements of
|
||||||
|
the individual data blocks.
|
||||||
|
|
||||||
|
|
||||||
|
2) Device tree generalities
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
This device-tree itself is separated in two different blocks, a
|
||||||
|
structure block and a strings block. Both need to be aligned to a 4
|
||||||
|
byte boundary.
|
||||||
|
|
||||||
|
First, let's quickly describe the device-tree concept before detailing
|
||||||
|
the storage format. This chapter does _not_ describe the detail of the
|
||||||
|
required types of nodes & properties for the kernel, this is done
|
||||||
|
later in chapter III.
|
||||||
|
|
||||||
|
The device-tree layout is strongly inherited from the definition of
|
||||||
|
the Open Firmware IEEE 1275 device-tree. It's basically a tree of
|
||||||
|
nodes, each node having two or more named properties. A property can
|
||||||
|
have a value or not.
|
||||||
|
|
||||||
|
It is a tree, so each node has one and only one parent except for the
|
||||||
|
root node who has no parent.
|
||||||
|
|
||||||
|
A node has 2 names. The actual node name is generally contained in a
|
||||||
|
property of type "name" in the node property list whose value is a
|
||||||
|
zero terminated string and is mandatory for version 1 to 3 of the
|
||||||
|
format definition (as it is in Open Firmware). Version 16 makes it
|
||||||
|
optional as it can generate it from the unit name defined below.
|
||||||
|
|
||||||
|
There is also a "unit name" that is used to differentiate nodes with
|
||||||
|
the same name at the same level, it is usually made of the node
|
||||||
|
names, the "@" sign, and a "unit address", which definition is
|
||||||
|
specific to the bus type the node sits on.
|
||||||
|
|
||||||
|
The unit name doesn't exist as a property per-se but is included in
|
||||||
|
the device-tree structure. It is typically used to represent "path" in
|
||||||
|
the device-tree. More details about the actual format of these will be
|
||||||
|
below.
|
||||||
|
|
||||||
|
The kernel powerpc generic code does not make any formal use of the
|
||||||
|
unit address (though some board support code may do) so the only real
|
||||||
|
requirement here for the unit address is to ensure uniqueness of
|
||||||
|
the node unit name at a given level of the tree. Nodes with no notion
|
||||||
|
of address and no possible sibling of the same name (like /memory or
|
||||||
|
/cpus) may omit the unit address in the context of this specification,
|
||||||
|
or use the "@0" default unit address. The unit name is used to define
|
||||||
|
a node "full path", which is the concatenation of all parent node
|
||||||
|
unit names separated with "/".
|
||||||
|
|
||||||
|
The root node doesn't have a defined name, and isn't required to have
|
||||||
|
a name property either if you are using version 3 or earlier of the
|
||||||
|
format. It also has no unit address (no @ symbol followed by a unit
|
||||||
|
address). The root node unit name is thus an empty string. The full
|
||||||
|
path to the root node is "/".
|
||||||
|
|
||||||
|
Every node which actually represents an actual device (that is, a node
|
||||||
|
which isn't only a virtual "container" for more nodes, like "/cpus"
|
||||||
|
is) is also required to have a "device_type" property indicating the
|
||||||
|
type of node .
|
||||||
|
|
||||||
|
Finally, every node that can be referenced from a property in another
|
||||||
|
node is required to have a "linux,phandle" property. Real open
|
||||||
|
firmware implementations provide a unique "phandle" value for every
|
||||||
|
node that the "prom_init()" trampoline code turns into
|
||||||
|
"linux,phandle" properties. However, this is made optional if the
|
||||||
|
flattened device tree is used directly. An example of a node
|
||||||
|
referencing another node via "phandle" is when laying out the
|
||||||
|
interrupt tree which will be described in a further version of this
|
||||||
|
document.
|
||||||
|
|
||||||
|
This "linux, phandle" property is a 32-bit value that uniquely
|
||||||
|
identifies a node. You are free to use whatever values or system of
|
||||||
|
values, internal pointers, or whatever to generate these, the only
|
||||||
|
requirement is that every node for which you provide that property has
|
||||||
|
a unique value for it.
|
||||||
|
|
||||||
|
Here is an example of a simple device-tree. In this example, an "o"
|
||||||
|
designates a node followed by the node unit name. Properties are
|
||||||
|
presented with their name followed by their content. "content"
|
||||||
|
represents an ASCII string (zero terminated) value, while <content>
|
||||||
|
represents a 32-bit hexadecimal value. The various nodes in this
|
||||||
|
example will be discussed in a later chapter. At this point, it is
|
||||||
|
only meant to give you a idea of what a device-tree looks like. I have
|
||||||
|
purposefully kept the "name" and "linux,phandle" properties which
|
||||||
|
aren't necessary in order to give you a better idea of what the tree
|
||||||
|
looks like in practice.
|
||||||
|
|
||||||
|
/ o device-tree
|
||||||
|
|- name = "device-tree"
|
||||||
|
|- model = "MyBoardName"
|
||||||
|
|- compatible = "MyBoardFamilyName"
|
||||||
|
|- #address-cells = <2>
|
||||||
|
|- #size-cells = <2>
|
||||||
|
|- linux,phandle = <0>
|
||||||
|
|
|
||||||
|
o cpus
|
||||||
|
| | - name = "cpus"
|
||||||
|
| | - linux,phandle = <1>
|
||||||
|
| | - #address-cells = <1>
|
||||||
|
| | - #size-cells = <0>
|
||||||
|
| |
|
||||||
|
| o PowerPC,970@0
|
||||||
|
| |- name = "PowerPC,970"
|
||||||
|
| |- device_type = "cpu"
|
||||||
|
| |- reg = <0>
|
||||||
|
| |- clock-frequency = <5f5e1000>
|
||||||
|
| |- 64-bit
|
||||||
|
| |- linux,phandle = <2>
|
||||||
|
|
|
||||||
|
o memory@0
|
||||||
|
| |- name = "memory"
|
||||||
|
| |- device_type = "memory"
|
||||||
|
| |- reg = <00000000 00000000 00000000 20000000>
|
||||||
|
| |- linux,phandle = <3>
|
||||||
|
|
|
||||||
|
o chosen
|
||||||
|
|- name = "chosen"
|
||||||
|
|- bootargs = "root=/dev/sda2"
|
||||||
|
|- linux,phandle = <4>
|
||||||
|
|
||||||
|
This tree is almost a minimal tree. It pretty much contains the
|
||||||
|
minimal set of required nodes and properties to boot a linux kernel;
|
||||||
|
that is, some basic model informations at the root, the CPUs, and the
|
||||||
|
physical memory layout. It also includes misc information passed
|
||||||
|
through /chosen, like in this example, the platform type (mandatory)
|
||||||
|
and the kernel command line arguments (optional).
|
||||||
|
|
||||||
|
The /cpus/PowerPC,970@0/64-bit property is an example of a
|
||||||
|
property without a value. All other properties have a value. The
|
||||||
|
significance of the #address-cells and #size-cells properties will be
|
||||||
|
explained in chapter IV which defines precisely the required nodes and
|
||||||
|
properties and their content.
|
||||||
|
|
||||||
|
|
||||||
|
3) Device tree "structure" block
|
||||||
|
|
||||||
|
The structure of the device tree is a linearized tree structure. The
|
||||||
|
"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE"
|
||||||
|
ends that node definition. Child nodes are simply defined before
|
||||||
|
"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
|
||||||
|
bit value. The tree has to be "finished" with a OF_DT_END token
|
||||||
|
|
||||||
|
Here's the basic structure of a single node:
|
||||||
|
|
||||||
|
* token OF_DT_BEGIN_NODE (that is 0x00000001)
|
||||||
|
* for version 1 to 3, this is the node full path as a zero
|
||||||
|
terminated string, starting with "/". For version 16 and later,
|
||||||
|
this is the node unit name only (or an empty string for the
|
||||||
|
root node)
|
||||||
|
* [align gap to next 4 bytes boundary]
|
||||||
|
* for each property:
|
||||||
|
* token OF_DT_PROP (that is 0x00000003)
|
||||||
|
* 32-bit value of property value size in bytes (or 0 if no
|
||||||
|
value)
|
||||||
|
* 32-bit value of offset in string block of property name
|
||||||
|
* property value data if any
|
||||||
|
* [align gap to next 4 bytes boundary]
|
||||||
|
* [child nodes if any]
|
||||||
|
* token OF_DT_END_NODE (that is 0x00000002)
|
||||||
|
|
||||||
|
So the node content can be summarized as a start token, a full path,
|
||||||
|
a list of properties, a list of child nodes, and an end token. Every
|
||||||
|
child node is a full node structure itself as defined above.
|
||||||
|
|
||||||
|
NOTE: The above definition requires that all property definitions for
|
||||||
|
a particular node MUST precede any subnode definitions for that node.
|
||||||
|
Although the structure would not be ambiguous if properties and
|
||||||
|
subnodes were intermingled, the kernel parser requires that the
|
||||||
|
properties come first (up until at least 2.6.22). Any tools
|
||||||
|
manipulating a flattened tree must take care to preserve this
|
||||||
|
constraint.
|
||||||
|
|
||||||
|
4) Device tree "strings" block
|
||||||
|
|
||||||
|
In order to save space, property names, which are generally redundant,
|
||||||
|
are stored separately in the "strings" block. This block is simply the
|
||||||
|
whole bunch of zero terminated strings for all property names
|
||||||
|
concatenated together. The device-tree property definitions in the
|
||||||
|
structure block will contain offset values from the beginning of the
|
||||||
|
strings block.
|
||||||
|
|
||||||
|
|
||||||
|
III - libfdt
|
||||||
|
============
|
||||||
|
|
||||||
|
This library should be merged into dtc proper.
|
||||||
|
This library should likely be worked into U-Boot and the kernel.
|
||||||
|
|
||||||
|
|
||||||
|
IV - Utility Tools
|
||||||
|
==================
|
||||||
|
|
||||||
|
1) convert-dtsv0 -- Conversion to Version 1
|
||||||
|
|
||||||
|
convert-dtsv0 is a small utility program which converts (DTS)
|
||||||
|
Device Tree Source from the obsolete version 0 to version 1.
|
||||||
|
|
||||||
|
Version 1 DTS files are marked by line "/dts-v1/;" at the top of the file.
|
||||||
|
|
||||||
|
The syntax of the convert-dtsv0 command line is:
|
||||||
|
|
||||||
|
convert-dtsv0 [<input_filename ... >]
|
||||||
|
|
||||||
|
Each file passed will be converted to the new /dts-v1/ version by creating
|
||||||
|
a new file with a "v1" appended the filename.
|
||||||
|
|
||||||
|
Comments, empty lines, etc. are preserved.
|
||||||
|
|
||||||
|
|
||||||
|
2) fdtdump -- Flat Device Tree dumping utility
|
||||||
|
|
||||||
|
The fdtdump program prints a readable version of a flat device tree file.
|
||||||
|
|
||||||
|
The syntax of the fdtdump command line is:
|
||||||
|
|
||||||
|
fdtdump [options] <DTB-file-name>
|
||||||
|
|
||||||
|
Where options are:
|
||||||
|
-d,--debug Dump debug information while decoding the file
|
||||||
|
-s,--scan Scan for an embedded fdt in given file
|
||||||
|
|
||||||
|
3) fdtoverlay -- Flat Device Tree overlay applicator
|
||||||
|
|
||||||
|
The fdtoverlay applies an arbitrary number of FDT overlays to a base FDT blob
|
||||||
|
to a given output file.
|
||||||
|
|
||||||
|
The syntax of the fdtoverlay command line is:
|
||||||
|
|
||||||
|
fdtoverlay -i <base-blob> -o <output-blob> <overlay-blob0> [<overlay-blob1> ...]
|
||||||
|
|
||||||
|
Where options are:
|
||||||
|
-i, --input Input base DT blob
|
||||||
|
-o, --output Output DT blob
|
||||||
|
-v, --verbose Verbose message output
|
||||||
340
dtc-1.4.5/GPL
Normal file
340
dtc-1.4.5/GPL
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
||||||
354
dtc-1.4.5/Makefile
Normal file
354
dtc-1.4.5/Makefile
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
#
|
||||||
|
# Device Tree Compiler
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Version information will be constructed in this order:
|
||||||
|
# EXTRAVERSION might be "-rc", for example.
|
||||||
|
# LOCAL_VERSION is likely from command line.
|
||||||
|
# CONFIG_LOCALVERSION from some future config system.
|
||||||
|
#
|
||||||
|
VERSION = 1
|
||||||
|
PATCHLEVEL = 4
|
||||||
|
SUBLEVEL = 5
|
||||||
|
EXTRAVERSION =
|
||||||
|
LOCAL_VERSION =
|
||||||
|
CONFIG_LOCALVERSION =
|
||||||
|
|
||||||
|
CPPFLAGS = -I libfdt -I .
|
||||||
|
WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
|
||||||
|
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
|
||||||
|
CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS)
|
||||||
|
|
||||||
|
BISON = bison
|
||||||
|
LEX = flex
|
||||||
|
SWIG = swig
|
||||||
|
PKG_CONFIG ?= pkg-config
|
||||||
|
|
||||||
|
INSTALL = /usr/bin/install
|
||||||
|
DESTDIR =
|
||||||
|
PREFIX = $(HOME)
|
||||||
|
BINDIR = $(PREFIX)/bin
|
||||||
|
LIBDIR = $(PREFIX)/lib
|
||||||
|
INCLUDEDIR = $(PREFIX)/include
|
||||||
|
|
||||||
|
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
|
||||||
|
sed -e 's/\(cygwin\|msys\).*/\1/')
|
||||||
|
|
||||||
|
ifeq ($(HOSTOS),darwin)
|
||||||
|
SHAREDLIB_EXT = dylib
|
||||||
|
SHAREDLIB_CFLAGS = -fPIC
|
||||||
|
SHAREDLIB_LDFLAGS = -fPIC -dynamiclib -Wl,-install_name -Wl,
|
||||||
|
else ifeq ($(HOSTOS),$(filter $(HOSTOS),msys cygwin))
|
||||||
|
SHAREDLIB_EXT = so
|
||||||
|
SHAREDLIB_CFLAGS =
|
||||||
|
SHAREDLIB_LDFLAGS = -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
|
||||||
|
else
|
||||||
|
SHAREDLIB_EXT = so
|
||||||
|
SHAREDLIB_CFLAGS = -fPIC
|
||||||
|
SHAREDLIB_LDFLAGS = -fPIC -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Overall rules
|
||||||
|
#
|
||||||
|
ifdef V
|
||||||
|
VECHO = :
|
||||||
|
else
|
||||||
|
VECHO = echo " "
|
||||||
|
ARFLAGS = rc
|
||||||
|
.SILENT:
|
||||||
|
endif
|
||||||
|
|
||||||
|
NODEPTARGETS = clean
|
||||||
|
ifeq ($(MAKECMDGOALS),)
|
||||||
|
DEPTARGETS = all
|
||||||
|
else
|
||||||
|
DEPTARGETS = $(filter-out $(NODEPTARGETS),$(MAKECMDGOALS))
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Rules for versioning
|
||||||
|
#
|
||||||
|
|
||||||
|
DTC_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
|
||||||
|
VERSION_FILE = version_gen.h
|
||||||
|
|
||||||
|
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
|
||||||
|
else if [ -x /bin/bash ]; then echo /bin/bash; \
|
||||||
|
else echo sh; fi ; fi)
|
||||||
|
|
||||||
|
nullstring :=
|
||||||
|
space := $(nullstring) # end of line
|
||||||
|
|
||||||
|
localver_config = $(subst $(space),, $(string) \
|
||||||
|
$(patsubst "%",%,$(CONFIG_LOCALVERSION)))
|
||||||
|
|
||||||
|
localver_cmd = $(subst $(space),, $(string) \
|
||||||
|
$(patsubst "%",%,$(LOCALVERSION)))
|
||||||
|
|
||||||
|
localver_scm = $(shell $(CONFIG_SHELL) ./scripts/setlocalversion)
|
||||||
|
localver_full = $(localver_config)$(localver_cmd)$(localver_scm)
|
||||||
|
|
||||||
|
dtc_version = $(DTC_VERSION)$(localver_full)
|
||||||
|
|
||||||
|
# Contents of the generated version file.
|
||||||
|
define filechk_version
|
||||||
|
(echo "#define DTC_VERSION \"DTC $(dtc_version)\""; )
|
||||||
|
endef
|
||||||
|
|
||||||
|
define filechk
|
||||||
|
set -e; \
|
||||||
|
echo ' CHK $@'; \
|
||||||
|
mkdir -p $(dir $@); \
|
||||||
|
$(filechk_$(1)) < $< > $@.tmp; \
|
||||||
|
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
|
||||||
|
rm -f $@.tmp; \
|
||||||
|
else \
|
||||||
|
echo ' UPD $@'; \
|
||||||
|
mv -f $@.tmp $@; \
|
||||||
|
fi;
|
||||||
|
endef
|
||||||
|
|
||||||
|
|
||||||
|
include Makefile.convert-dtsv0
|
||||||
|
include Makefile.dtc
|
||||||
|
include Makefile.utils
|
||||||
|
|
||||||
|
BIN += convert-dtsv0
|
||||||
|
BIN += dtc
|
||||||
|
BIN += fdtdump
|
||||||
|
BIN += fdtget
|
||||||
|
BIN += fdtput
|
||||||
|
BIN += fdtoverlay
|
||||||
|
|
||||||
|
SCRIPTS = dtdiff
|
||||||
|
|
||||||
|
all: $(BIN) libfdt
|
||||||
|
|
||||||
|
# We need both Python and swig to build pylibfdt.
|
||||||
|
.PHONY: maybe_pylibfdt
|
||||||
|
maybe_pylibfdt: FORCE
|
||||||
|
if $(PKG_CONFIG) --cflags python2 >/dev/null 2>&1; then \
|
||||||
|
if which swig >/dev/null 2>&1; then \
|
||||||
|
can_build=yes; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
if [ "$$can_build" = "yes" ]; then \
|
||||||
|
$(MAKE) pylibfdt; \
|
||||||
|
else \
|
||||||
|
echo "## Skipping pylibfdt (install python dev and swig to build)"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
ifeq ($(NO_PYTHON),)
|
||||||
|
all: maybe_pylibfdt
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(DEPTARGETS),)
|
||||||
|
-include $(DTC_OBJS:%.o=%.d)
|
||||||
|
-include $(CONVERT_OBJS:%.o=%.d)
|
||||||
|
-include $(FDTDUMP_OBJS:%.o=%.d)
|
||||||
|
-include $(FDTGET_OBJS:%.o=%.d)
|
||||||
|
-include $(FDTPUT_OBJS:%.o=%.d)
|
||||||
|
-include $(FDTOVERLAY_OBJS:%.o=%.d)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Rules for libfdt
|
||||||
|
#
|
||||||
|
LIBFDT_objdir = libfdt
|
||||||
|
LIBFDT_srcdir = libfdt
|
||||||
|
LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
|
||||||
|
LIBFDT_lib = $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
|
||||||
|
LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
|
||||||
|
LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
|
||||||
|
|
||||||
|
include $(LIBFDT_srcdir)/Makefile.libfdt
|
||||||
|
|
||||||
|
.PHONY: libfdt
|
||||||
|
libfdt: $(LIBFDT_archive) $(LIBFDT_lib)
|
||||||
|
|
||||||
|
$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
|
||||||
|
$(LIBFDT_lib): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
|
||||||
|
|
||||||
|
libfdt_clean:
|
||||||
|
@$(VECHO) CLEAN "(libfdt)"
|
||||||
|
rm -f $(addprefix $(LIBFDT_objdir)/,$(STD_CLEANFILES))
|
||||||
|
rm -f $(LIBFDT_objdir)/*.so
|
||||||
|
|
||||||
|
ifneq ($(DEPTARGETS),)
|
||||||
|
-include $(LIBFDT_OBJS:%.o=$(LIBFDT_objdir)/%.d)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# This stops make from generating the lex and bison output during
|
||||||
|
# auto-dependency computation, but throwing them away as an
|
||||||
|
# intermediate target and building them again "for real"
|
||||||
|
.SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS)
|
||||||
|
|
||||||
|
install-bin: all $(SCRIPTS)
|
||||||
|
@$(VECHO) INSTALL-BIN
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||||
|
$(INSTALL) $(BIN) $(SCRIPTS) $(DESTDIR)$(BINDIR)
|
||||||
|
|
||||||
|
install-lib: all
|
||||||
|
@$(VECHO) INSTALL-LIB
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
|
||||||
|
$(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
|
||||||
|
ln -sf $(notdir $(LIBFDT_lib)) $(DESTDIR)$(LIBDIR)/$(LIBFDT_soname)
|
||||||
|
ln -sf $(LIBFDT_soname) $(DESTDIR)$(LIBDIR)/libfdt.$(SHAREDLIB_EXT)
|
||||||
|
$(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
|
||||||
|
|
||||||
|
install-includes:
|
||||||
|
@$(VECHO) INSTALL-INC
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
|
||||||
|
install: install-bin install-lib install-includes
|
||||||
|
|
||||||
|
ifeq ($(NO_PYTHON),)
|
||||||
|
install: install_pylibfdt
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(VERSION_FILE): Makefile FORCE
|
||||||
|
$(call filechk,version)
|
||||||
|
|
||||||
|
|
||||||
|
dtc: $(DTC_OBJS)
|
||||||
|
|
||||||
|
convert-dtsv0: $(CONVERT_OBJS)
|
||||||
|
@$(VECHO) LD $@
|
||||||
|
$(LINK.c) -o $@ $^
|
||||||
|
|
||||||
|
fdtdump: $(FDTDUMP_OBJS)
|
||||||
|
|
||||||
|
fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)
|
||||||
|
|
||||||
|
fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)
|
||||||
|
|
||||||
|
fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_archive)
|
||||||
|
|
||||||
|
dist:
|
||||||
|
git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
|
||||||
|
> ../dtc-$(dtc_version).tar
|
||||||
|
cat ../dtc-$(dtc_version).tar | \
|
||||||
|
gzip -9 > ../dtc-$(dtc_version).tar.gz
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Rules for pylibfdt
|
||||||
|
#
|
||||||
|
PYLIBFDT_srcdir = pylibfdt
|
||||||
|
PYLIBFDT_objdir = pylibfdt
|
||||||
|
|
||||||
|
include $(PYLIBFDT_srcdir)/Makefile.pylibfdt
|
||||||
|
|
||||||
|
.PHONY: pylibfdt
|
||||||
|
pylibfdt: $(PYLIBFDT_objdir)/_libfdt.so
|
||||||
|
|
||||||
|
pylibfdt_clean:
|
||||||
|
@$(VECHO) CLEAN "(pylibfdt)"
|
||||||
|
rm -f $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles))
|
||||||
|
|
||||||
|
#
|
||||||
|
# Release signing and uploading
|
||||||
|
# This is for maintainer convenience, don't try this at home.
|
||||||
|
#
|
||||||
|
ifeq ($(MAINTAINER),y)
|
||||||
|
GPG = gpg2
|
||||||
|
KUP = kup
|
||||||
|
KUPDIR = /pub/software/utils/dtc
|
||||||
|
|
||||||
|
kup: dist
|
||||||
|
$(GPG) --detach-sign --armor -o ../dtc-$(dtc_version).tar.sign \
|
||||||
|
../dtc-$(dtc_version).tar
|
||||||
|
$(KUP) put ../dtc-$(dtc_version).tar.gz ../dtc-$(dtc_version).tar.sign \
|
||||||
|
$(KUPDIR)/dtc-$(dtc_version).tar.gz
|
||||||
|
endif
|
||||||
|
|
||||||
|
tags: FORCE
|
||||||
|
rm -f tags
|
||||||
|
find . \( -name tests -type d -prune \) -o \
|
||||||
|
\( ! -name '*.tab.[ch]' ! -name '*.lex.c' \
|
||||||
|
-name '*.[chly]' -type f -print \) | xargs ctags -a
|
||||||
|
|
||||||
|
#
|
||||||
|
# Testsuite rules
|
||||||
|
#
|
||||||
|
TESTS_PREFIX=tests/
|
||||||
|
|
||||||
|
TESTS_BIN += dtc
|
||||||
|
TESTS_BIN += convert-dtsv0
|
||||||
|
TESTS_BIN += fdtput
|
||||||
|
TESTS_BIN += fdtget
|
||||||
|
TESTS_BIN += fdtdump
|
||||||
|
TESTS_BIN += fdtoverlay
|
||||||
|
ifeq ($(NO_PYTHON),)
|
||||||
|
TESTS_PYLIBFDT += maybe_pylibfdt
|
||||||
|
endif
|
||||||
|
|
||||||
|
include tests/Makefile.tests
|
||||||
|
|
||||||
|
#
|
||||||
|
# Clean rules
|
||||||
|
#
|
||||||
|
STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \
|
||||||
|
*.tab.[ch] *.lex.c *.output
|
||||||
|
|
||||||
|
clean: libfdt_clean pylibfdt_clean tests_clean
|
||||||
|
@$(VECHO) CLEAN
|
||||||
|
rm -f $(STD_CLEANFILES)
|
||||||
|
rm -f $(VERSION_FILE)
|
||||||
|
rm -f $(BIN)
|
||||||
|
rm -f dtc-*.tar dtc-*.tar.sign dtc-*.tar.asc
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generic compile rules
|
||||||
|
#
|
||||||
|
%: %.o
|
||||||
|
@$(VECHO) LD $@
|
||||||
|
$(LINK.c) -o $@ $^
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
@$(VECHO) CC $@
|
||||||
|
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
@$(VECHO) AS $@
|
||||||
|
$(CC) $(CPPFLAGS) $(AFLAGS) -D__ASSEMBLY__ -o $@ -c $<
|
||||||
|
|
||||||
|
%.d: %.c
|
||||||
|
@$(VECHO) DEP $<
|
||||||
|
$(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@
|
||||||
|
|
||||||
|
%.d: %.S
|
||||||
|
@$(VECHO) DEP $<
|
||||||
|
$(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@
|
||||||
|
|
||||||
|
%.i: %.c
|
||||||
|
@$(VECHO) CPP $@
|
||||||
|
$(CC) $(CPPFLAGS) -E $< > $@
|
||||||
|
|
||||||
|
%.s: %.c
|
||||||
|
@$(VECHO) CC -S $@
|
||||||
|
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -S $<
|
||||||
|
|
||||||
|
%.a:
|
||||||
|
@$(VECHO) AR $@
|
||||||
|
$(AR) $(ARFLAGS) $@ $^
|
||||||
|
|
||||||
|
$(LIBFDT_lib):
|
||||||
|
@$(VECHO) LD $@
|
||||||
|
$(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
|
||||||
|
|
||||||
|
%.lex.c: %.l
|
||||||
|
@$(VECHO) LEX $@
|
||||||
|
$(LEX) -o$@ $<
|
||||||
|
|
||||||
|
%.tab.c %.tab.h %.output: %.y
|
||||||
|
@$(VECHO) BISON $@
|
||||||
|
$(BISON) -d $<
|
||||||
|
|
||||||
|
FORCE:
|
||||||
13
dtc-1.4.5/Makefile.convert-dtsv0
Normal file
13
dtc-1.4.5/Makefile.convert-dtsv0
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#
|
||||||
|
# This is not a complete Makefile of itself.
|
||||||
|
# Instead, it is designed to be easily embeddable
|
||||||
|
# into other systems of Makefiles.
|
||||||
|
#
|
||||||
|
|
||||||
|
CONVERT_SRCS = \
|
||||||
|
srcpos.c \
|
||||||
|
util.c
|
||||||
|
|
||||||
|
CONVERT_GEN_SRCS = convert-dtsv0-lexer.lex.c
|
||||||
|
|
||||||
|
CONVERT_OBJS = $(CONVERT_SRCS:%.c=%.o) $(CONVERT_GEN_SRCS:%.c=%.o)
|
||||||
18
dtc-1.4.5/Makefile.dtc
Normal file
18
dtc-1.4.5/Makefile.dtc
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Makefile.dtc
|
||||||
|
#
|
||||||
|
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||||
|
# be easily embeddable into other systems of Makefiles.
|
||||||
|
#
|
||||||
|
DTC_SRCS = \
|
||||||
|
checks.c \
|
||||||
|
data.c \
|
||||||
|
dtc.c \
|
||||||
|
flattree.c \
|
||||||
|
fstree.c \
|
||||||
|
livetree.c \
|
||||||
|
srcpos.c \
|
||||||
|
treesource.c \
|
||||||
|
util.c
|
||||||
|
|
||||||
|
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
|
||||||
|
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
|
||||||
30
dtc-1.4.5/Makefile.utils
Normal file
30
dtc-1.4.5/Makefile.utils
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#
|
||||||
|
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||||
|
# be easily embeddable into other systems of Makefiles.
|
||||||
|
#
|
||||||
|
|
||||||
|
FDTDUMP_SRCS = \
|
||||||
|
fdtdump.c \
|
||||||
|
util.c
|
||||||
|
|
||||||
|
FDTDUMP_OBJS = $(FDTDUMP_SRCS:%.c=%.o)
|
||||||
|
|
||||||
|
|
||||||
|
FDTGET_SRCS = \
|
||||||
|
fdtget.c \
|
||||||
|
util.c
|
||||||
|
|
||||||
|
FDTGET_OBJS = $(FDTGET_SRCS:%.c=%.o)
|
||||||
|
|
||||||
|
|
||||||
|
FDTPUT_SRCS = \
|
||||||
|
fdtput.c \
|
||||||
|
util.c
|
||||||
|
|
||||||
|
FDTPUT_OBJS = $(FDTPUT_SRCS:%.c=%.o)
|
||||||
|
|
||||||
|
FDTOVERLAY_SRCS = \
|
||||||
|
fdtoverlay.c \
|
||||||
|
util.c
|
||||||
|
|
||||||
|
FDTOVERLAY_OBJS = $(FDTOVERLAY_SRCS:%.c=%.o)
|
||||||
93
dtc-1.4.5/README
Normal file
93
dtc-1.4.5/README
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
The source tree contains the Device Tree Compiler (dtc) toolchain for
|
||||||
|
working with device tree source and binary files and also libfdt, a
|
||||||
|
utility library for reading and manipulating the binary format.
|
||||||
|
|
||||||
|
DTC and LIBFDT are maintained by:
|
||||||
|
|
||||||
|
David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
Jon Loeliger <jdl@jdl.com>
|
||||||
|
|
||||||
|
|
||||||
|
Python library
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A Python library is also available. To build this you will need to install
|
||||||
|
swig and Python development files. On Debian distributions:
|
||||||
|
|
||||||
|
sudo apt-get install swig python-dev
|
||||||
|
|
||||||
|
The library provides an Fdt class which you can use like this:
|
||||||
|
|
||||||
|
$ PYTHONPATH=../pylibfdt python
|
||||||
|
>>> import libfdt
|
||||||
|
>>> fdt = libfdt.Fdt(open('test_tree1.dtb').read())
|
||||||
|
>>> node = fdt.path_offset('/subnode@1')
|
||||||
|
>>> print node
|
||||||
|
124
|
||||||
|
>>> prop_offset = fdt.first_property_offset(node)
|
||||||
|
>>> prop = fdt.get_property_by_offset(prop_offset)
|
||||||
|
>>> print '%s=%r' % (prop.name, prop.value)
|
||||||
|
compatible=bytearray(b'subnode1\x00')
|
||||||
|
>>> print '%s=%s' % (prop.name, prop.value)
|
||||||
|
compatible=subnode1
|
||||||
|
>>> node2 = fdt.path_offset('/')
|
||||||
|
>>> print fdt.getprop(node2, 'compatible')
|
||||||
|
test_tree1
|
||||||
|
|
||||||
|
You will find tests in tests/pylibfdt_tests.py showing how to use each
|
||||||
|
method. Help is available using the Python help command, e.g.:
|
||||||
|
|
||||||
|
$ cd pylibfdt
|
||||||
|
$ python -c "import libfdt; help(libfdt)"
|
||||||
|
|
||||||
|
If you add new features, please check code coverage:
|
||||||
|
|
||||||
|
$ sudo apt-get install python-pip python-pytest
|
||||||
|
$ sudo pip install coverage
|
||||||
|
$ cd tests
|
||||||
|
$ coverage run pylibfdt_tests.py
|
||||||
|
$ coverage html
|
||||||
|
# Open 'htmlcov/index.html' in your browser
|
||||||
|
|
||||||
|
|
||||||
|
To install the library via the normal setup.py method, use:
|
||||||
|
|
||||||
|
./pylibfdt/setup.py [--prefix=/path/to/install_dir]
|
||||||
|
|
||||||
|
If --prefix is not provided, the default prefix is used, typically '/usr'
|
||||||
|
or '/usr/local'. See Python's distutils documentation for details. You can
|
||||||
|
also install via the Makefile if you like, but the above is more common.
|
||||||
|
|
||||||
|
To install both libfdt and pylibfdt you can use:
|
||||||
|
|
||||||
|
make install [SETUP_PREFIX=/path/to/install_dir] \
|
||||||
|
[PREFIX=/path/to/install_dir]
|
||||||
|
|
||||||
|
To disable building the python library, even if swig and Python are available,
|
||||||
|
use:
|
||||||
|
|
||||||
|
make NO_PYTHON=1
|
||||||
|
|
||||||
|
|
||||||
|
More work remains to support all of libfdt, including access to numeric
|
||||||
|
values.
|
||||||
|
|
||||||
|
|
||||||
|
Tests
|
||||||
|
-----
|
||||||
|
|
||||||
|
Test files are kept in the tests/ directory. Use 'make check' to build and run
|
||||||
|
all tests.
|
||||||
|
|
||||||
|
If you want to adjust a test file, be aware that tree_tree1.dts is compiled
|
||||||
|
and checked against a binary tree from assembler macros in trees.S. So
|
||||||
|
if you change that file you must change tree.S also.
|
||||||
|
|
||||||
|
|
||||||
|
Mailing list
|
||||||
|
------------
|
||||||
|
The following list is for discussion about dtc and libfdt implementation
|
||||||
|
mailto:devicetree-compiler@vger.kernel.org
|
||||||
|
|
||||||
|
Core device tree bindings are discussed on the devicetree-spec list:
|
||||||
|
mailto:devicetree-spec@vger.kernel.org
|
||||||
56
dtc-1.4.5/README.license
Normal file
56
dtc-1.4.5/README.license
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
Licensing and contribution policy of dtc and libfdt
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
This dtc package contains two pieces of software: dtc itself, and
|
||||||
|
libfdt which comprises the files in the libfdt/ subdirectory. These
|
||||||
|
two pieces of software, although closely related, are quite distinct.
|
||||||
|
dtc does not incoporate or rely on libfdt for its operation, nor vice
|
||||||
|
versa. It is important that these two pieces of software have
|
||||||
|
different license conditions.
|
||||||
|
|
||||||
|
As the copyright banners in each source file attest, dtc is licensed
|
||||||
|
under the GNU GPL. The full text of the GPL can be found in the file
|
||||||
|
entitled 'GPL' which should be included in this package. dtc code,
|
||||||
|
therefore, may not be incorporated into works which do not have a GPL
|
||||||
|
compatible license.
|
||||||
|
|
||||||
|
libfdt, however, is GPL/BSD dual-licensed. That is, it may be used
|
||||||
|
either under the terms of the GPL, or under the terms of the 2-clause
|
||||||
|
BSD license (aka the ISC license). The full terms of that license are
|
||||||
|
given in the copyright banners of each of the libfdt source files.
|
||||||
|
This is, in practice, equivalent to being BSD licensed, since the
|
||||||
|
terms of the BSD license are strictly more permissive than the GPL.
|
||||||
|
|
||||||
|
I made the decision to license libfdt in this way because I want to
|
||||||
|
encourage widespread and correct usage of flattened device trees,
|
||||||
|
including by proprietary or otherwise GPL-incompatible firmware or
|
||||||
|
tools. Allowing libfdt to be used under the terms of the BSD license
|
||||||
|
makes that it easier for vendors or authors of such software to do so.
|
||||||
|
|
||||||
|
This does mean that libfdt code could be "stolen" - say, included in a
|
||||||
|
proprietary fimware and extended without contributing those extensions
|
||||||
|
back to the libfdt mainline. While I hope that doesn't happen, I
|
||||||
|
believe the goal of allowing libfdt to be widely used is more
|
||||||
|
important than avoiding that. libfdt is quite small, and hardly
|
||||||
|
rocket science; so the incentive for such impolite behaviour is small,
|
||||||
|
and the inconvenience caused therby is not dire.
|
||||||
|
|
||||||
|
Licenses such as the LGPL which would allow code to be used in non-GPL
|
||||||
|
software, but also require contributions to be returned were
|
||||||
|
considered. However, libfdt is designed to be used in firmwares and
|
||||||
|
other environments with unusual technical constraints. It's difficult
|
||||||
|
to anticipate all possible changes which might be needed to meld
|
||||||
|
libfdt into such environments and so difficult to suitably word a
|
||||||
|
license that puts the boundary between what is and isn't permitted in
|
||||||
|
the intended place. Again, I judged encouraging widespread use of
|
||||||
|
libfdt by keeping the license terms simple and familiar to be the more
|
||||||
|
important goal.
|
||||||
|
|
||||||
|
**IMPORTANT** It's intended that all of libfdt as released remain
|
||||||
|
permissively licensed this way. Therefore only contributions which
|
||||||
|
are released under these terms can be merged into the libfdt mainline.
|
||||||
|
|
||||||
|
|
||||||
|
David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
(principal original author of dtc and libfdt)
|
||||||
|
2 November 2007
|
||||||
8
dtc-1.4.5/TODO
Normal file
8
dtc-1.4.5/TODO
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
- Bugfixes:
|
||||||
|
* Proper handling of boot cpu information
|
||||||
|
- Generate mem reserve map
|
||||||
|
* linux,reserve-map property
|
||||||
|
* generating reserve entry for device tree itself
|
||||||
|
* generating reserve entries from tce, rtas etc. properties
|
||||||
|
- Expression support
|
||||||
|
- Macro system
|
||||||
1356
dtc-1.4.5/checks.c
Normal file
1356
dtc-1.4.5/checks.c
Normal file
File diff suppressed because it is too large
Load Diff
249
dtc-1.4.5/convert-dtsv0-lexer.l
Normal file
249
dtc-1.4.5/convert-dtsv0-lexer.l
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005, 2008.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
%option noyywrap nounput noinput never-interactive
|
||||||
|
|
||||||
|
%x BYTESTRING
|
||||||
|
%x PROPNODENAME
|
||||||
|
|
||||||
|
PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
|
||||||
|
PATHCHAR ({PROPNODECHAR}|[/])
|
||||||
|
LABEL [a-zA-Z_][a-zA-Z0-9_]*
|
||||||
|
STRING \"([^\\"]|\\.)*\"
|
||||||
|
WS [[:space:]]
|
||||||
|
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
|
||||||
|
LINECOMMENT "//".*\n
|
||||||
|
GAP ({WS}|{COMMENT}|{LINECOMMENT})*
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
|
||||||
|
#include "srcpos.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int v1_tagged; /* = 0 */
|
||||||
|
static int cbase = 16;
|
||||||
|
static int saw_hyphen; /* = 0 */
|
||||||
|
static unsigned long long last_val;
|
||||||
|
static char *last_name; /* = NULL */
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char *pattern;
|
||||||
|
int obase, width;
|
||||||
|
} guess_table[] = {
|
||||||
|
{ "*-frequency", 10, 0 },
|
||||||
|
{ "num-*", 10, 0 },
|
||||||
|
{ "#*-cells", 10, 0 },
|
||||||
|
{ "*cache-line-size", 10, 0 },
|
||||||
|
{ "*cache-block-size", 10, 0 },
|
||||||
|
{ "*cache-size", 10, 0 },
|
||||||
|
{ "*cache-sets", 10, 0 },
|
||||||
|
{ "cell-index", 10, 0 },
|
||||||
|
{ "bank-width", 10, 0 },
|
||||||
|
{ "*-fifo-size", 10, 0 },
|
||||||
|
{ "*-frame-size", 10, 0 },
|
||||||
|
{ "*-channel", 10, 0 },
|
||||||
|
{ "current-speed", 10, 0 },
|
||||||
|
{ "phy-map", 16, 8 },
|
||||||
|
{ "dcr-reg", 16, 3 },
|
||||||
|
{ "reg", 16, 8 },
|
||||||
|
{ "ranges", 16, 8},
|
||||||
|
};
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
<*>"/include/"{GAP}{STRING} ECHO;
|
||||||
|
|
||||||
|
<*>\"([^\\"]|\\.)*\" ECHO;
|
||||||
|
|
||||||
|
<*>"/dts-v1/" {
|
||||||
|
die("Input dts file is already version 1\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"/memreserve/" {
|
||||||
|
if (!v1_tagged) {
|
||||||
|
fprintf(yyout, "/dts-v1/;\n\n");
|
||||||
|
v1_tagged = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ECHO;
|
||||||
|
BEGIN(INITIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>{LABEL}: ECHO;
|
||||||
|
|
||||||
|
<INITIAL>[bodh]# {
|
||||||
|
if (*yytext == 'b')
|
||||||
|
cbase = 2;
|
||||||
|
else if (*yytext == 'o')
|
||||||
|
cbase = 8;
|
||||||
|
else if (*yytext == 'd')
|
||||||
|
cbase = 10;
|
||||||
|
else
|
||||||
|
cbase = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
<INITIAL>[0-9a-fA-F]+ {
|
||||||
|
unsigned long long val;
|
||||||
|
int obase = 16, width = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
val = strtoull(yytext, NULL, cbase);
|
||||||
|
|
||||||
|
if (saw_hyphen)
|
||||||
|
val = val - last_val + 1;
|
||||||
|
|
||||||
|
if (last_name) {
|
||||||
|
for (i = 0; i < ARRAY_SIZE(guess_table); i++)
|
||||||
|
if (fnmatch(guess_table[i].pattern,
|
||||||
|
last_name, 0) == 0) {
|
||||||
|
obase = guess_table[i].obase;
|
||||||
|
width = guess_table[i].width;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obase = 16;
|
||||||
|
width = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbase != 16)
|
||||||
|
obase = cbase;
|
||||||
|
|
||||||
|
switch (obase) {
|
||||||
|
case 2:
|
||||||
|
case 16:
|
||||||
|
fprintf(yyout, "0x%0*llx", width, val);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
fprintf(yyout, "0%0*llo", width, val);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
fprintf(yyout, "%*llu", width, val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cbase = 16;
|
||||||
|
last_val = val;
|
||||||
|
saw_hyphen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
\&{LABEL} ECHO;
|
||||||
|
|
||||||
|
"&{/"{PATHCHAR}+\} ECHO;
|
||||||
|
|
||||||
|
<INITIAL>"&/"{PATHCHAR}+ fprintf(yyout, "&{/%s}", yytext + 2);
|
||||||
|
|
||||||
|
<BYTESTRING>[0-9a-fA-F]{2} ECHO;
|
||||||
|
|
||||||
|
<BYTESTRING>"]" {
|
||||||
|
ECHO;
|
||||||
|
BEGIN(INITIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
<PROPNODENAME>{PROPNODECHAR}+ {
|
||||||
|
ECHO;
|
||||||
|
last_name = xstrdup(yytext);
|
||||||
|
BEGIN(INITIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>{GAP} ECHO;
|
||||||
|
|
||||||
|
<*>- { /* Hack to convert old style memreserves */
|
||||||
|
saw_hyphen = 1;
|
||||||
|
fprintf(yyout, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>. {
|
||||||
|
if (!v1_tagged) {
|
||||||
|
fprintf(yyout, "/dts-v1/;\n\n");
|
||||||
|
v1_tagged = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ECHO;
|
||||||
|
if (yytext[0] == '[') {
|
||||||
|
BEGIN(BYTESTRING);
|
||||||
|
}
|
||||||
|
if ((yytext[0] == '{')
|
||||||
|
|| (yytext[0] == ';')) {
|
||||||
|
BEGIN(PROPNODENAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%%
|
||||||
|
/* Usage related data. */
|
||||||
|
static const char usage_synopsis[] = "convert-dtsv0 [options] <v0 dts file>...";
|
||||||
|
static const char usage_short_opts[] = "" USAGE_COMMON_SHORT_OPTS;
|
||||||
|
static struct option const usage_long_opts[] = {
|
||||||
|
USAGE_COMMON_LONG_OPTS
|
||||||
|
};
|
||||||
|
static const char * const usage_opts_help[] = {
|
||||||
|
USAGE_COMMON_OPTS_HELP
|
||||||
|
};
|
||||||
|
|
||||||
|
static void convert_file(const char *fname)
|
||||||
|
{
|
||||||
|
const char suffix[] = "v1";
|
||||||
|
int len = strlen(fname);
|
||||||
|
char *newname;
|
||||||
|
|
||||||
|
newname = xmalloc(len + sizeof(suffix));
|
||||||
|
memcpy(newname, fname, len);
|
||||||
|
memcpy(newname + len, suffix, sizeof(suffix));
|
||||||
|
|
||||||
|
yyin = fopen(fname, "r");
|
||||||
|
if (!yyin)
|
||||||
|
die("Couldn't open input file %s: %s\n",
|
||||||
|
fname, strerror(errno));
|
||||||
|
|
||||||
|
yyout = fopen(newname, "w");
|
||||||
|
if (!yyout)
|
||||||
|
die("Couldn't open output file %s: %s\n",
|
||||||
|
newname, strerror(errno));
|
||||||
|
|
||||||
|
while(yylex())
|
||||||
|
;
|
||||||
|
|
||||||
|
free(newname);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while ((opt = util_getopt_long()) != EOF) {
|
||||||
|
switch (opt) {
|
||||||
|
case_USAGE_COMMON_FLAGS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argc < 2)
|
||||||
|
usage("missing filename");
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
fprintf(stderr, "Converting %s from dts v0 to dts v1\n", argv[i]);
|
||||||
|
convert_file(argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
269
dtc-1.4.5/data.c
Normal file
269
dtc-1.4.5/data.c
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dtc.h"
|
||||||
|
|
||||||
|
void data_free(struct data d)
|
||||||
|
{
|
||||||
|
struct marker *m, *nm;
|
||||||
|
|
||||||
|
m = d.markers;
|
||||||
|
while (m) {
|
||||||
|
nm = m->next;
|
||||||
|
free(m->ref);
|
||||||
|
free(m);
|
||||||
|
m = nm;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.val)
|
||||||
|
free(d.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_grow_for(struct data d, int xlen)
|
||||||
|
{
|
||||||
|
struct data nd;
|
||||||
|
int newsize;
|
||||||
|
|
||||||
|
if (xlen == 0)
|
||||||
|
return d;
|
||||||
|
|
||||||
|
nd = d;
|
||||||
|
|
||||||
|
newsize = xlen;
|
||||||
|
|
||||||
|
while ((d.len + xlen) > newsize)
|
||||||
|
newsize *= 2;
|
||||||
|
|
||||||
|
nd.val = xrealloc(d.val, newsize);
|
||||||
|
|
||||||
|
return nd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_copy_mem(const char *mem, int len)
|
||||||
|
{
|
||||||
|
struct data d;
|
||||||
|
|
||||||
|
d = data_grow_for(empty_data, len);
|
||||||
|
|
||||||
|
d.len = len;
|
||||||
|
memcpy(d.val, mem, len);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_copy_escape_string(const char *s, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
struct data d;
|
||||||
|
char *q;
|
||||||
|
|
||||||
|
d = data_grow_for(empty_data, len + 1);
|
||||||
|
|
||||||
|
q = d.val;
|
||||||
|
while (i < len) {
|
||||||
|
char c = s[i++];
|
||||||
|
|
||||||
|
if (c == '\\')
|
||||||
|
c = get_escape_char(s, &i);
|
||||||
|
|
||||||
|
q[d.len++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
q[d.len++] = '\0';
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_copy_file(FILE *f, size_t maxlen)
|
||||||
|
{
|
||||||
|
struct data d = empty_data;
|
||||||
|
|
||||||
|
while (!feof(f) && (d.len < maxlen)) {
|
||||||
|
size_t chunksize, ret;
|
||||||
|
|
||||||
|
if (maxlen == -1)
|
||||||
|
chunksize = 4096;
|
||||||
|
else
|
||||||
|
chunksize = maxlen - d.len;
|
||||||
|
|
||||||
|
d = data_grow_for(d, chunksize);
|
||||||
|
ret = fread(d.val + d.len, 1, chunksize, f);
|
||||||
|
|
||||||
|
if (ferror(f))
|
||||||
|
die("Error reading file into data: %s", strerror(errno));
|
||||||
|
|
||||||
|
if (d.len + ret < d.len)
|
||||||
|
die("Overflow reading file into data\n");
|
||||||
|
|
||||||
|
d.len += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_data(struct data d, const void *p, int len)
|
||||||
|
{
|
||||||
|
d = data_grow_for(d, len);
|
||||||
|
memcpy(d.val + d.len, p, len);
|
||||||
|
d.len += len;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_insert_at_marker(struct data d, struct marker *m,
|
||||||
|
const void *p, int len)
|
||||||
|
{
|
||||||
|
d = data_grow_for(d, len);
|
||||||
|
memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
|
||||||
|
memcpy(d.val + m->offset, p, len);
|
||||||
|
d.len += len;
|
||||||
|
|
||||||
|
/* Adjust all markers after the one we're inserting at */
|
||||||
|
m = m->next;
|
||||||
|
for_each_marker(m)
|
||||||
|
m->offset += len;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct data data_append_markers(struct data d, struct marker *m)
|
||||||
|
{
|
||||||
|
struct marker **mp = &d.markers;
|
||||||
|
|
||||||
|
/* Find the end of the markerlist */
|
||||||
|
while (*mp)
|
||||||
|
mp = &((*mp)->next);
|
||||||
|
*mp = m;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_merge(struct data d1, struct data d2)
|
||||||
|
{
|
||||||
|
struct data d;
|
||||||
|
struct marker *m2 = d2.markers;
|
||||||
|
|
||||||
|
d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
|
||||||
|
|
||||||
|
/* Adjust for the length of d1 */
|
||||||
|
for_each_marker(m2)
|
||||||
|
m2->offset += d1.len;
|
||||||
|
|
||||||
|
d2.markers = NULL; /* So data_free() doesn't clobber them */
|
||||||
|
data_free(d2);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_integer(struct data d, uint64_t value, int bits)
|
||||||
|
{
|
||||||
|
uint8_t value_8;
|
||||||
|
fdt16_t value_16;
|
||||||
|
fdt32_t value_32;
|
||||||
|
fdt64_t value_64;
|
||||||
|
|
||||||
|
switch (bits) {
|
||||||
|
case 8:
|
||||||
|
value_8 = value;
|
||||||
|
return data_append_data(d, &value_8, 1);
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
value_16 = cpu_to_fdt16(value);
|
||||||
|
return data_append_data(d, &value_16, 2);
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
value_32 = cpu_to_fdt32(value);
|
||||||
|
return data_append_data(d, &value_32, 4);
|
||||||
|
|
||||||
|
case 64:
|
||||||
|
value_64 = cpu_to_fdt64(value);
|
||||||
|
return data_append_data(d, &value_64, 8);
|
||||||
|
|
||||||
|
default:
|
||||||
|
die("Invalid literal size (%d)\n", bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_re(struct data d, uint64_t address, uint64_t size)
|
||||||
|
{
|
||||||
|
struct fdt_reserve_entry re;
|
||||||
|
|
||||||
|
re.address = cpu_to_fdt64(address);
|
||||||
|
re.size = cpu_to_fdt64(size);
|
||||||
|
|
||||||
|
return data_append_data(d, &re, sizeof(re));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_cell(struct data d, cell_t word)
|
||||||
|
{
|
||||||
|
return data_append_integer(d, word, sizeof(word) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_addr(struct data d, uint64_t addr)
|
||||||
|
{
|
||||||
|
return data_append_integer(d, addr, sizeof(addr) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_byte(struct data d, uint8_t byte)
|
||||||
|
{
|
||||||
|
return data_append_data(d, &byte, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_zeroes(struct data d, int len)
|
||||||
|
{
|
||||||
|
d = data_grow_for(d, len);
|
||||||
|
|
||||||
|
memset(d.val + d.len, 0, len);
|
||||||
|
d.len += len;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_append_align(struct data d, int align)
|
||||||
|
{
|
||||||
|
int newlen = ALIGN(d.len, align);
|
||||||
|
return data_append_zeroes(d, newlen - d.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data data_add_marker(struct data d, enum markertype type, char *ref)
|
||||||
|
{
|
||||||
|
struct marker *m;
|
||||||
|
|
||||||
|
m = xmalloc(sizeof(*m));
|
||||||
|
m->offset = d.len;
|
||||||
|
m->type = type;
|
||||||
|
m->ref = ref;
|
||||||
|
m->next = NULL;
|
||||||
|
|
||||||
|
return data_append_markers(d, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool data_is_one_string(struct data d)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int len = d.len;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i = 0; i < len-1; i++)
|
||||||
|
if (d.val[i] == '\0')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (d.val[len-1] != '\0')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
306
dtc-1.4.5/dtc-lexer.l
Normal file
306
dtc-1.4.5/dtc-lexer.l
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
%option noyywrap nounput noinput never-interactive
|
||||||
|
|
||||||
|
%x BYTESTRING
|
||||||
|
%x PROPNODENAME
|
||||||
|
%s V1
|
||||||
|
|
||||||
|
PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
|
||||||
|
PATHCHAR ({PROPNODECHAR}|[/])
|
||||||
|
LABEL [a-zA-Z_][a-zA-Z0-9_]*
|
||||||
|
STRING \"([^\\"]|\\.)*\"
|
||||||
|
CHAR_LITERAL '([^']|\\')*'
|
||||||
|
WS [[:space:]]
|
||||||
|
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
|
||||||
|
LINECOMMENT "//".*\n
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include "dtc.h"
|
||||||
|
#include "srcpos.h"
|
||||||
|
#include "dtc-parser.tab.h"
|
||||||
|
|
||||||
|
YYLTYPE yylloc;
|
||||||
|
extern bool treesource_error;
|
||||||
|
|
||||||
|
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
|
||||||
|
#define YY_USER_ACTION \
|
||||||
|
{ \
|
||||||
|
srcpos_update(&yylloc, yytext, yyleng); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#define LEXDEBUG 1*/
|
||||||
|
|
||||||
|
#ifdef LEXDEBUG
|
||||||
|
#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DPRINT(fmt, ...) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int dts_version = 1;
|
||||||
|
|
||||||
|
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
|
||||||
|
BEGIN(V1); \
|
||||||
|
|
||||||
|
static void push_input_file(const char *filename);
|
||||||
|
static bool pop_input_file(void);
|
||||||
|
static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
<*>"/include/"{WS}*{STRING} {
|
||||||
|
char *name = strchr(yytext, '\"') + 1;
|
||||||
|
yytext[yyleng-1] = '\0';
|
||||||
|
push_input_file(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
|
||||||
|
char *line, *fnstart, *fnend;
|
||||||
|
struct data fn;
|
||||||
|
/* skip text before line # */
|
||||||
|
line = yytext;
|
||||||
|
while (!isdigit((unsigned char)*line))
|
||||||
|
line++;
|
||||||
|
|
||||||
|
/* regexp ensures that first and list "
|
||||||
|
* in the whole yytext are those at
|
||||||
|
* beginning and end of the filename string */
|
||||||
|
fnstart = memchr(yytext, '"', yyleng);
|
||||||
|
for (fnend = yytext + yyleng - 1;
|
||||||
|
*fnend != '"'; fnend--)
|
||||||
|
;
|
||||||
|
assert(fnstart && fnend && (fnend > fnstart));
|
||||||
|
|
||||||
|
fn = data_copy_escape_string(fnstart + 1,
|
||||||
|
fnend - fnstart - 1);
|
||||||
|
|
||||||
|
/* Don't allow nuls in filenames */
|
||||||
|
if (memchr(fn.val, '\0', fn.len - 1))
|
||||||
|
lexical_error("nul in line number directive");
|
||||||
|
|
||||||
|
/* -1 since #line is the number of the next line */
|
||||||
|
srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
|
||||||
|
data_free(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
<*><<EOF>> {
|
||||||
|
if (!pop_input_file()) {
|
||||||
|
yyterminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>{STRING} {
|
||||||
|
DPRINT("String: %s\n", yytext);
|
||||||
|
yylval.data = data_copy_escape_string(yytext+1,
|
||||||
|
yyleng-2);
|
||||||
|
return DT_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"/dts-v1/" {
|
||||||
|
DPRINT("Keyword: /dts-v1/\n");
|
||||||
|
dts_version = 1;
|
||||||
|
BEGIN_DEFAULT();
|
||||||
|
return DT_V1;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"/plugin/" {
|
||||||
|
DPRINT("Keyword: /plugin/\n");
|
||||||
|
return DT_PLUGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"/memreserve/" {
|
||||||
|
DPRINT("Keyword: /memreserve/\n");
|
||||||
|
BEGIN_DEFAULT();
|
||||||
|
return DT_MEMRESERVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"/bits/" {
|
||||||
|
DPRINT("Keyword: /bits/\n");
|
||||||
|
BEGIN_DEFAULT();
|
||||||
|
return DT_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"/delete-property/" {
|
||||||
|
DPRINT("Keyword: /delete-property/\n");
|
||||||
|
DPRINT("<PROPNODENAME>\n");
|
||||||
|
BEGIN(PROPNODENAME);
|
||||||
|
return DT_DEL_PROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"/delete-node/" {
|
||||||
|
DPRINT("Keyword: /delete-node/\n");
|
||||||
|
DPRINT("<PROPNODENAME>\n");
|
||||||
|
BEGIN(PROPNODENAME);
|
||||||
|
return DT_DEL_NODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>{LABEL}: {
|
||||||
|
DPRINT("Label: %s\n", yytext);
|
||||||
|
yylval.labelref = xstrdup(yytext);
|
||||||
|
yylval.labelref[yyleng-1] = '\0';
|
||||||
|
return DT_LABEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
|
||||||
|
char *e;
|
||||||
|
DPRINT("Integer Literal: '%s'\n", yytext);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
yylval.integer = strtoull(yytext, &e, 0);
|
||||||
|
|
||||||
|
if (*e && e[strspn(e, "UL")]) {
|
||||||
|
lexical_error("Bad integer literal '%s'",
|
||||||
|
yytext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == ERANGE)
|
||||||
|
lexical_error("Integer literal '%s' out of range",
|
||||||
|
yytext);
|
||||||
|
else
|
||||||
|
/* ERANGE is the only strtoull error triggerable
|
||||||
|
* by strings matching the pattern */
|
||||||
|
assert(errno == 0);
|
||||||
|
return DT_LITERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>{CHAR_LITERAL} {
|
||||||
|
struct data d;
|
||||||
|
DPRINT("Character literal: %s\n", yytext);
|
||||||
|
|
||||||
|
d = data_copy_escape_string(yytext+1, yyleng-2);
|
||||||
|
if (d.len == 1) {
|
||||||
|
lexical_error("Empty character literal");
|
||||||
|
yylval.integer = 0;
|
||||||
|
} else {
|
||||||
|
yylval.integer = (unsigned char)d.val[0];
|
||||||
|
|
||||||
|
if (d.len > 2)
|
||||||
|
lexical_error("Character literal has %d"
|
||||||
|
" characters instead of 1",
|
||||||
|
d.len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_free(d);
|
||||||
|
return DT_CHAR_LITERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>\&{LABEL} { /* label reference */
|
||||||
|
DPRINT("Ref: %s\n", yytext+1);
|
||||||
|
yylval.labelref = xstrdup(yytext+1);
|
||||||
|
return DT_REF;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
|
||||||
|
yytext[yyleng-1] = '\0';
|
||||||
|
DPRINT("Ref: %s\n", yytext+2);
|
||||||
|
yylval.labelref = xstrdup(yytext+2);
|
||||||
|
return DT_REF;
|
||||||
|
}
|
||||||
|
|
||||||
|
<BYTESTRING>[0-9a-fA-F]{2} {
|
||||||
|
yylval.byte = strtol(yytext, NULL, 16);
|
||||||
|
DPRINT("Byte: %02x\n", (int)yylval.byte);
|
||||||
|
return DT_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
<BYTESTRING>"]" {
|
||||||
|
DPRINT("/BYTESTRING\n");
|
||||||
|
BEGIN_DEFAULT();
|
||||||
|
return ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
<PROPNODENAME>\\?{PROPNODECHAR}+ {
|
||||||
|
DPRINT("PropNodeName: %s\n", yytext);
|
||||||
|
yylval.propnodename = xstrdup((yytext[0] == '\\') ?
|
||||||
|
yytext + 1 : yytext);
|
||||||
|
BEGIN_DEFAULT();
|
||||||
|
return DT_PROPNODENAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
"/incbin/" {
|
||||||
|
DPRINT("Binary Include\n");
|
||||||
|
return DT_INCBIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
<*>{WS}+ /* eat whitespace */
|
||||||
|
<*>{COMMENT}+ /* eat C-style comments */
|
||||||
|
<*>{LINECOMMENT}+ /* eat C++-style comments */
|
||||||
|
|
||||||
|
<*>"<<" { return DT_LSHIFT; };
|
||||||
|
<*>">>" { return DT_RSHIFT; };
|
||||||
|
<*>"<=" { return DT_LE; };
|
||||||
|
<*>">=" { return DT_GE; };
|
||||||
|
<*>"==" { return DT_EQ; };
|
||||||
|
<*>"!=" { return DT_NE; };
|
||||||
|
<*>"&&" { return DT_AND; };
|
||||||
|
<*>"||" { return DT_OR; };
|
||||||
|
|
||||||
|
<*>. {
|
||||||
|
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
|
||||||
|
(unsigned)yytext[0]);
|
||||||
|
if (yytext[0] == '[') {
|
||||||
|
DPRINT("<BYTESTRING>\n");
|
||||||
|
BEGIN(BYTESTRING);
|
||||||
|
}
|
||||||
|
if ((yytext[0] == '{')
|
||||||
|
|| (yytext[0] == ';')) {
|
||||||
|
DPRINT("<PROPNODENAME>\n");
|
||||||
|
BEGIN(PROPNODENAME);
|
||||||
|
}
|
||||||
|
return yytext[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
static void push_input_file(const char *filename)
|
||||||
|
{
|
||||||
|
assert(filename);
|
||||||
|
|
||||||
|
srcfile_push(filename);
|
||||||
|
|
||||||
|
yyin = current_srcfile->f;
|
||||||
|
|
||||||
|
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool pop_input_file(void)
|
||||||
|
{
|
||||||
|
if (srcfile_pop() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
yypop_buffer_state();
|
||||||
|
yyin = current_srcfile->f;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lexical_error(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
srcpos_verror(&yylloc, "Lexical error", fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
treesource_error = true;
|
||||||
|
}
|
||||||
519
dtc-1.4.5/dtc-parser.y
Normal file
519
dtc-1.4.5/dtc-parser.y
Normal file
@@ -0,0 +1,519 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
%{
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "dtc.h"
|
||||||
|
#include "srcpos.h"
|
||||||
|
|
||||||
|
extern int yylex(void);
|
||||||
|
extern void yyerror(char const *s);
|
||||||
|
#define ERROR(loc, ...) \
|
||||||
|
do { \
|
||||||
|
srcpos_error((loc), "Error", __VA_ARGS__); \
|
||||||
|
treesource_error = true; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
extern struct dt_info *parser_output;
|
||||||
|
extern bool treesource_error;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%union {
|
||||||
|
char *propnodename;
|
||||||
|
char *labelref;
|
||||||
|
uint8_t byte;
|
||||||
|
struct data data;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct data data;
|
||||||
|
int bits;
|
||||||
|
} array;
|
||||||
|
|
||||||
|
struct property *prop;
|
||||||
|
struct property *proplist;
|
||||||
|
struct node *node;
|
||||||
|
struct node *nodelist;
|
||||||
|
struct reserve_info *re;
|
||||||
|
uint64_t integer;
|
||||||
|
unsigned int flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
%token DT_V1
|
||||||
|
%token DT_PLUGIN
|
||||||
|
%token DT_MEMRESERVE
|
||||||
|
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
|
||||||
|
%token DT_BITS
|
||||||
|
%token DT_DEL_PROP
|
||||||
|
%token DT_DEL_NODE
|
||||||
|
%token <propnodename> DT_PROPNODENAME
|
||||||
|
%token <integer> DT_LITERAL
|
||||||
|
%token <integer> DT_CHAR_LITERAL
|
||||||
|
%token <byte> DT_BYTE
|
||||||
|
%token <data> DT_STRING
|
||||||
|
%token <labelref> DT_LABEL
|
||||||
|
%token <labelref> DT_REF
|
||||||
|
%token DT_INCBIN
|
||||||
|
|
||||||
|
%type <data> propdata
|
||||||
|
%type <data> propdataprefix
|
||||||
|
%type <flags> header
|
||||||
|
%type <flags> headers
|
||||||
|
%type <re> memreserve
|
||||||
|
%type <re> memreserves
|
||||||
|
%type <array> arrayprefix
|
||||||
|
%type <data> bytestring
|
||||||
|
%type <prop> propdef
|
||||||
|
%type <proplist> proplist
|
||||||
|
|
||||||
|
%type <node> devicetree
|
||||||
|
%type <node> nodedef
|
||||||
|
%type <node> subnode
|
||||||
|
%type <nodelist> subnodes
|
||||||
|
|
||||||
|
%type <integer> integer_prim
|
||||||
|
%type <integer> integer_unary
|
||||||
|
%type <integer> integer_mul
|
||||||
|
%type <integer> integer_add
|
||||||
|
%type <integer> integer_shift
|
||||||
|
%type <integer> integer_rela
|
||||||
|
%type <integer> integer_eq
|
||||||
|
%type <integer> integer_bitand
|
||||||
|
%type <integer> integer_bitxor
|
||||||
|
%type <integer> integer_bitor
|
||||||
|
%type <integer> integer_and
|
||||||
|
%type <integer> integer_or
|
||||||
|
%type <integer> integer_trinary
|
||||||
|
%type <integer> integer_expr
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
sourcefile:
|
||||||
|
headers memreserves devicetree
|
||||||
|
{
|
||||||
|
parser_output = build_dt_info($1, $2, $3,
|
||||||
|
guess_boot_cpuid($3));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
header:
|
||||||
|
DT_V1 ';'
|
||||||
|
{
|
||||||
|
$$ = DTSF_V1;
|
||||||
|
}
|
||||||
|
| DT_V1 ';' DT_PLUGIN ';'
|
||||||
|
{
|
||||||
|
$$ = DTSF_V1 | DTSF_PLUGIN;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
headers:
|
||||||
|
header
|
||||||
|
| header headers
|
||||||
|
{
|
||||||
|
if ($2 != $1)
|
||||||
|
ERROR(&@2, "Header flags don't match earlier ones");
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
memreserves:
|
||||||
|
/* empty */
|
||||||
|
{
|
||||||
|
$$ = NULL;
|
||||||
|
}
|
||||||
|
| memreserve memreserves
|
||||||
|
{
|
||||||
|
$$ = chain_reserve_entry($1, $2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
memreserve:
|
||||||
|
DT_MEMRESERVE integer_prim integer_prim ';'
|
||||||
|
{
|
||||||
|
$$ = build_reserve_entry($2, $3);
|
||||||
|
}
|
||||||
|
| DT_LABEL memreserve
|
||||||
|
{
|
||||||
|
add_label(&$2->labels, $1);
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
devicetree:
|
||||||
|
'/' nodedef
|
||||||
|
{
|
||||||
|
$$ = name_node($2, "");
|
||||||
|
}
|
||||||
|
| devicetree '/' nodedef
|
||||||
|
{
|
||||||
|
$$ = merge_nodes($1, $3);
|
||||||
|
}
|
||||||
|
|
||||||
|
| devicetree DT_LABEL DT_REF nodedef
|
||||||
|
{
|
||||||
|
struct node *target = get_node_by_ref($1, $3);
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
add_label(&target->labels, $2);
|
||||||
|
merge_nodes(target, $4);
|
||||||
|
} else
|
||||||
|
ERROR(&@3, "Label or path %s not found", $3);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| devicetree DT_REF nodedef
|
||||||
|
{
|
||||||
|
struct node *target = get_node_by_ref($1, $2);
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
merge_nodes(target, $3);
|
||||||
|
else
|
||||||
|
ERROR(&@2, "Label or path %s not found", $2);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| devicetree DT_DEL_NODE DT_REF ';'
|
||||||
|
{
|
||||||
|
struct node *target = get_node_by_ref($1, $3);
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
delete_node(target);
|
||||||
|
else
|
||||||
|
ERROR(&@3, "Label or path %s not found", $3);
|
||||||
|
|
||||||
|
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
nodedef:
|
||||||
|
'{' proplist subnodes '}' ';'
|
||||||
|
{
|
||||||
|
$$ = build_node($2, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
proplist:
|
||||||
|
/* empty */
|
||||||
|
{
|
||||||
|
$$ = NULL;
|
||||||
|
}
|
||||||
|
| proplist propdef
|
||||||
|
{
|
||||||
|
$$ = chain_property($2, $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
propdef:
|
||||||
|
DT_PROPNODENAME '=' propdata ';'
|
||||||
|
{
|
||||||
|
$$ = build_property($1, $3);
|
||||||
|
}
|
||||||
|
| DT_PROPNODENAME ';'
|
||||||
|
{
|
||||||
|
$$ = build_property($1, empty_data);
|
||||||
|
}
|
||||||
|
| DT_DEL_PROP DT_PROPNODENAME ';'
|
||||||
|
{
|
||||||
|
$$ = build_property_delete($2);
|
||||||
|
}
|
||||||
|
| DT_LABEL propdef
|
||||||
|
{
|
||||||
|
add_label(&$2->labels, $1);
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
propdata:
|
||||||
|
propdataprefix DT_STRING
|
||||||
|
{
|
||||||
|
$$ = data_merge($1, $2);
|
||||||
|
}
|
||||||
|
| propdataprefix arrayprefix '>'
|
||||||
|
{
|
||||||
|
$$ = data_merge($1, $2.data);
|
||||||
|
}
|
||||||
|
| propdataprefix '[' bytestring ']'
|
||||||
|
{
|
||||||
|
$$ = data_merge($1, $3);
|
||||||
|
}
|
||||||
|
| propdataprefix DT_REF
|
||||||
|
{
|
||||||
|
$$ = data_add_marker($1, REF_PATH, $2);
|
||||||
|
}
|
||||||
|
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
|
||||||
|
{
|
||||||
|
FILE *f = srcfile_relative_open($4.val, NULL);
|
||||||
|
struct data d;
|
||||||
|
|
||||||
|
if ($6 != 0)
|
||||||
|
if (fseek(f, $6, SEEK_SET) != 0)
|
||||||
|
die("Couldn't seek to offset %llu in \"%s\": %s",
|
||||||
|
(unsigned long long)$6, $4.val,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
d = data_copy_file(f, $8);
|
||||||
|
|
||||||
|
$$ = data_merge($1, d);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
| propdataprefix DT_INCBIN '(' DT_STRING ')'
|
||||||
|
{
|
||||||
|
FILE *f = srcfile_relative_open($4.val, NULL);
|
||||||
|
struct data d = empty_data;
|
||||||
|
|
||||||
|
d = data_copy_file(f, -1);
|
||||||
|
|
||||||
|
$$ = data_merge($1, d);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
| propdata DT_LABEL
|
||||||
|
{
|
||||||
|
$$ = data_add_marker($1, LABEL, $2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
propdataprefix:
|
||||||
|
/* empty */
|
||||||
|
{
|
||||||
|
$$ = empty_data;
|
||||||
|
}
|
||||||
|
| propdata ','
|
||||||
|
{
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| propdataprefix DT_LABEL
|
||||||
|
{
|
||||||
|
$$ = data_add_marker($1, LABEL, $2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
arrayprefix:
|
||||||
|
DT_BITS DT_LITERAL '<'
|
||||||
|
{
|
||||||
|
unsigned long long bits;
|
||||||
|
|
||||||
|
bits = $2;
|
||||||
|
|
||||||
|
if ((bits != 8) && (bits != 16) &&
|
||||||
|
(bits != 32) && (bits != 64)) {
|
||||||
|
ERROR(&@2, "Array elements must be"
|
||||||
|
" 8, 16, 32 or 64-bits");
|
||||||
|
bits = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
$$.data = empty_data;
|
||||||
|
$$.bits = bits;
|
||||||
|
}
|
||||||
|
| '<'
|
||||||
|
{
|
||||||
|
$$.data = empty_data;
|
||||||
|
$$.bits = 32;
|
||||||
|
}
|
||||||
|
| arrayprefix integer_prim
|
||||||
|
{
|
||||||
|
if ($1.bits < 64) {
|
||||||
|
uint64_t mask = (1ULL << $1.bits) - 1;
|
||||||
|
/*
|
||||||
|
* Bits above mask must either be all zero
|
||||||
|
* (positive within range of mask) or all one
|
||||||
|
* (negative and sign-extended). The second
|
||||||
|
* condition is true if when we set all bits
|
||||||
|
* within the mask to one (i.e. | in the
|
||||||
|
* mask), all bits are one.
|
||||||
|
*/
|
||||||
|
if (($2 > mask) && (($2 | mask) != -1ULL))
|
||||||
|
ERROR(&@2, "Value out of range for"
|
||||||
|
" %d-bit array element", $1.bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
$$.data = data_append_integer($1.data, $2, $1.bits);
|
||||||
|
}
|
||||||
|
| arrayprefix DT_REF
|
||||||
|
{
|
||||||
|
uint64_t val = ~0ULL >> (64 - $1.bits);
|
||||||
|
|
||||||
|
if ($1.bits == 32)
|
||||||
|
$1.data = data_add_marker($1.data,
|
||||||
|
REF_PHANDLE,
|
||||||
|
$2);
|
||||||
|
else
|
||||||
|
ERROR(&@2, "References are only allowed in "
|
||||||
|
"arrays with 32-bit elements.");
|
||||||
|
|
||||||
|
$$.data = data_append_integer($1.data, val, $1.bits);
|
||||||
|
}
|
||||||
|
| arrayprefix DT_LABEL
|
||||||
|
{
|
||||||
|
$$.data = data_add_marker($1.data, LABEL, $2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_prim:
|
||||||
|
DT_LITERAL
|
||||||
|
| DT_CHAR_LITERAL
|
||||||
|
| '(' integer_expr ')'
|
||||||
|
{
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_expr:
|
||||||
|
integer_trinary
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_trinary:
|
||||||
|
integer_or
|
||||||
|
| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_or:
|
||||||
|
integer_and
|
||||||
|
| integer_or DT_OR integer_and { $$ = $1 || $3; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_and:
|
||||||
|
integer_bitor
|
||||||
|
| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_bitor:
|
||||||
|
integer_bitxor
|
||||||
|
| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_bitxor:
|
||||||
|
integer_bitand
|
||||||
|
| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_bitand:
|
||||||
|
integer_eq
|
||||||
|
| integer_bitand '&' integer_eq { $$ = $1 & $3; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_eq:
|
||||||
|
integer_rela
|
||||||
|
| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
|
||||||
|
| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_rela:
|
||||||
|
integer_shift
|
||||||
|
| integer_rela '<' integer_shift { $$ = $1 < $3; }
|
||||||
|
| integer_rela '>' integer_shift { $$ = $1 > $3; }
|
||||||
|
| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
|
||||||
|
| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_shift:
|
||||||
|
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
|
||||||
|
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
|
||||||
|
| integer_add
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_add:
|
||||||
|
integer_add '+' integer_mul { $$ = $1 + $3; }
|
||||||
|
| integer_add '-' integer_mul { $$ = $1 - $3; }
|
||||||
|
| integer_mul
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_mul:
|
||||||
|
integer_mul '*' integer_unary { $$ = $1 * $3; }
|
||||||
|
| integer_mul '/' integer_unary
|
||||||
|
{
|
||||||
|
if ($3 != 0) {
|
||||||
|
$$ = $1 / $3;
|
||||||
|
} else {
|
||||||
|
ERROR(&@$, "Division by zero");
|
||||||
|
$$ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| integer_mul '%' integer_unary
|
||||||
|
{
|
||||||
|
if ($3 != 0) {
|
||||||
|
$$ = $1 % $3;
|
||||||
|
} else {
|
||||||
|
ERROR(&@$, "Division by zero");
|
||||||
|
$$ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| integer_unary
|
||||||
|
;
|
||||||
|
|
||||||
|
integer_unary:
|
||||||
|
integer_prim
|
||||||
|
| '-' integer_unary { $$ = -$2; }
|
||||||
|
| '~' integer_unary { $$ = ~$2; }
|
||||||
|
| '!' integer_unary { $$ = !$2; }
|
||||||
|
;
|
||||||
|
|
||||||
|
bytestring:
|
||||||
|
/* empty */
|
||||||
|
{
|
||||||
|
$$ = empty_data;
|
||||||
|
}
|
||||||
|
| bytestring DT_BYTE
|
||||||
|
{
|
||||||
|
$$ = data_append_byte($1, $2);
|
||||||
|
}
|
||||||
|
| bytestring DT_LABEL
|
||||||
|
{
|
||||||
|
$$ = data_add_marker($1, LABEL, $2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
subnodes:
|
||||||
|
/* empty */
|
||||||
|
{
|
||||||
|
$$ = NULL;
|
||||||
|
}
|
||||||
|
| subnode subnodes
|
||||||
|
{
|
||||||
|
$$ = chain_node($1, $2);
|
||||||
|
}
|
||||||
|
| subnode propdef
|
||||||
|
{
|
||||||
|
ERROR(&@2, "Properties must precede subnodes");
|
||||||
|
YYERROR;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
subnode:
|
||||||
|
DT_PROPNODENAME nodedef
|
||||||
|
{
|
||||||
|
$$ = name_node($2, $1);
|
||||||
|
}
|
||||||
|
| DT_DEL_NODE DT_PROPNODENAME ';'
|
||||||
|
{
|
||||||
|
$$ = name_node(build_node_delete(), $2);
|
||||||
|
}
|
||||||
|
| DT_LABEL subnode
|
||||||
|
{
|
||||||
|
add_label(&$2->labels, $1);
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
void yyerror(char const *s)
|
||||||
|
{
|
||||||
|
ERROR(&yylloc, "%s", s);
|
||||||
|
}
|
||||||
365
dtc-1.4.5/dtc.c
Normal file
365
dtc-1.4.5/dtc.c
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "dtc.h"
|
||||||
|
#include "srcpos.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command line options
|
||||||
|
*/
|
||||||
|
int quiet; /* Level of quietness */
|
||||||
|
int reservenum; /* Number of memory reservation slots */
|
||||||
|
int minsize; /* Minimum blob size */
|
||||||
|
int padsize; /* Additional padding to blob */
|
||||||
|
int alignsize; /* Additional padding to blob accroding to the alignsize */
|
||||||
|
int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */
|
||||||
|
int generate_symbols; /* enable symbols & fixup support */
|
||||||
|
int generate_fixups; /* suppress generation of fixups on symbol support */
|
||||||
|
int auto_label_aliases; /* auto generate labels -> aliases */
|
||||||
|
|
||||||
|
static int is_power_of_2(int x)
|
||||||
|
{
|
||||||
|
return (x > 0) && ((x & (x - 1)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||||
|
{
|
||||||
|
struct node *child;
|
||||||
|
const char *unit;
|
||||||
|
|
||||||
|
tree->fullpath = join_path(prefix, tree->name);
|
||||||
|
|
||||||
|
unit = strchr(tree->name, '@');
|
||||||
|
if (unit)
|
||||||
|
tree->basenamelen = unit - tree->name;
|
||||||
|
else
|
||||||
|
tree->basenamelen = strlen(tree->name);
|
||||||
|
|
||||||
|
for_each_child(tree, child)
|
||||||
|
fill_fullpaths(child, tree->fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Usage related data. */
|
||||||
|
#define FDT_VERSION(version) _FDT_VERSION(version)
|
||||||
|
#define _FDT_VERSION(version) #version
|
||||||
|
static const char usage_synopsis[] = "dtc [options] <input file>";
|
||||||
|
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
|
||||||
|
static struct option const usage_long_opts[] = {
|
||||||
|
{"quiet", no_argument, NULL, 'q'},
|
||||||
|
{"in-format", a_argument, NULL, 'I'},
|
||||||
|
{"out", a_argument, NULL, 'o'},
|
||||||
|
{"out-format", a_argument, NULL, 'O'},
|
||||||
|
{"out-version", a_argument, NULL, 'V'},
|
||||||
|
{"out-dependency", a_argument, NULL, 'd'},
|
||||||
|
{"reserve", a_argument, NULL, 'R'},
|
||||||
|
{"space", a_argument, NULL, 'S'},
|
||||||
|
{"pad", a_argument, NULL, 'p'},
|
||||||
|
{"align", a_argument, NULL, 'a'},
|
||||||
|
{"boot-cpu", a_argument, NULL, 'b'},
|
||||||
|
{"force", no_argument, NULL, 'f'},
|
||||||
|
{"include", a_argument, NULL, 'i'},
|
||||||
|
{"sort", no_argument, NULL, 's'},
|
||||||
|
{"phandle", a_argument, NULL, 'H'},
|
||||||
|
{"warning", a_argument, NULL, 'W'},
|
||||||
|
{"error", a_argument, NULL, 'E'},
|
||||||
|
{"symbols", no_argument, NULL, '@'},
|
||||||
|
{"auto-alias", no_argument, NULL, 'A'},
|
||||||
|
{"help", no_argument, NULL, 'h'},
|
||||||
|
{"version", no_argument, NULL, 'v'},
|
||||||
|
{NULL, no_argument, NULL, 0x0},
|
||||||
|
};
|
||||||
|
static const char * const usage_opts_help[] = {
|
||||||
|
"\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
|
||||||
|
"\n\tInput formats are:\n"
|
||||||
|
"\t\tdts - device tree source text\n"
|
||||||
|
"\t\tdtb - device tree blob\n"
|
||||||
|
"\t\tfs - /proc/device-tree style directory",
|
||||||
|
"\n\tOutput file",
|
||||||
|
"\n\tOutput formats are:\n"
|
||||||
|
"\t\tdts - device tree source text\n"
|
||||||
|
"\t\tdtb - device tree blob\n"
|
||||||
|
"\t\tasm - assembler source",
|
||||||
|
"\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
|
||||||
|
"\n\tOutput dependency file",
|
||||||
|
"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
|
||||||
|
"\n\tMake the blob at least <bytes> long (extra space)",
|
||||||
|
"\n\tAdd padding to the blob of <bytes> long (extra space)",
|
||||||
|
"\n\tMake the blob align to the <bytes> (extra space)",
|
||||||
|
"\n\tSet the physical boot cpu",
|
||||||
|
"\n\tTry to produce output even if the input tree has errors",
|
||||||
|
"\n\tAdd a path to search for include files",
|
||||||
|
"\n\tSort nodes and properties before outputting (useful for comparing trees)",
|
||||||
|
"\n\tValid phandle formats are:\n"
|
||||||
|
"\t\tlegacy - \"linux,phandle\" properties only\n"
|
||||||
|
"\t\tepapr - \"phandle\" properties only\n"
|
||||||
|
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
|
||||||
|
"\n\tEnable/disable warnings (prefix with \"no-\")",
|
||||||
|
"\n\tEnable/disable errors (prefix with \"no-\")",
|
||||||
|
"\n\tEnable generation of symbols",
|
||||||
|
"\n\tEnable auto-alias of labels",
|
||||||
|
"\n\tPrint this help and exit",
|
||||||
|
"\n\tPrint version and exit",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *guess_type_by_name(const char *fname, const char *fallback)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
s = strrchr(fname, '.');
|
||||||
|
if (s == NULL)
|
||||||
|
return fallback;
|
||||||
|
if (!strcasecmp(s, ".dts"))
|
||||||
|
return "dts";
|
||||||
|
if (!strcasecmp(s, ".dtb"))
|
||||||
|
return "dtb";
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *guess_input_format(const char *fname, const char *fallback)
|
||||||
|
{
|
||||||
|
struct stat statbuf;
|
||||||
|
fdt32_t magic;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (stat(fname, &statbuf) != 0)
|
||||||
|
return fallback;
|
||||||
|
|
||||||
|
if (S_ISDIR(statbuf.st_mode))
|
||||||
|
return "fs";
|
||||||
|
|
||||||
|
if (!S_ISREG(statbuf.st_mode))
|
||||||
|
return fallback;
|
||||||
|
|
||||||
|
f = fopen(fname, "r");
|
||||||
|
if (f == NULL)
|
||||||
|
return fallback;
|
||||||
|
if (fread(&magic, 4, 1, f) != 1) {
|
||||||
|
fclose(f);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (fdt32_to_cpu(magic) == FDT_MAGIC)
|
||||||
|
return "dtb";
|
||||||
|
|
||||||
|
return guess_type_by_name(fname, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct dt_info *dti;
|
||||||
|
const char *inform = NULL;
|
||||||
|
const char *outform = NULL;
|
||||||
|
const char *outname = "-";
|
||||||
|
const char *depname = NULL;
|
||||||
|
bool force = false, sort = false;
|
||||||
|
const char *arg;
|
||||||
|
int opt;
|
||||||
|
FILE *outf = NULL;
|
||||||
|
int outversion = DEFAULT_FDT_VERSION;
|
||||||
|
long long cmdline_boot_cpuid = -1;
|
||||||
|
|
||||||
|
quiet = 0;
|
||||||
|
reservenum = 0;
|
||||||
|
minsize = 0;
|
||||||
|
padsize = 0;
|
||||||
|
alignsize = 0;
|
||||||
|
|
||||||
|
while ((opt = util_getopt_long()) != EOF) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'I':
|
||||||
|
inform = optarg;
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
outform = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
outname = optarg;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
outversion = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
depname = optarg;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
reservenum = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
minsize = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
padsize = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
alignsize = strtol(optarg, NULL, 0);
|
||||||
|
if (!is_power_of_2(alignsize))
|
||||||
|
die("Invalid argument \"%d\" to -a option\n",
|
||||||
|
alignsize);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
force = true;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
quiet++;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
srcfile_add_search_path(optarg);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
util_version();
|
||||||
|
case 'H':
|
||||||
|
if (streq(optarg, "legacy"))
|
||||||
|
phandle_format = PHANDLE_LEGACY;
|
||||||
|
else if (streq(optarg, "epapr"))
|
||||||
|
phandle_format = PHANDLE_EPAPR;
|
||||||
|
else if (streq(optarg, "both"))
|
||||||
|
phandle_format = PHANDLE_BOTH;
|
||||||
|
else
|
||||||
|
die("Invalid argument \"%s\" to -H option\n",
|
||||||
|
optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
sort = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'W':
|
||||||
|
parse_checks_option(true, false, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
parse_checks_option(false, true, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '@':
|
||||||
|
generate_symbols = 1;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
auto_label_aliases = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
usage(NULL);
|
||||||
|
default:
|
||||||
|
usage("unknown option");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > (optind+1))
|
||||||
|
usage("missing files");
|
||||||
|
else if (argc < (optind+1))
|
||||||
|
arg = "-";
|
||||||
|
else
|
||||||
|
arg = argv[optind];
|
||||||
|
|
||||||
|
/* minsize and padsize are mutually exclusive */
|
||||||
|
if (minsize && padsize)
|
||||||
|
die("Can't set both -p and -S\n");
|
||||||
|
|
||||||
|
if (depname) {
|
||||||
|
depfile = fopen(depname, "w");
|
||||||
|
if (!depfile)
|
||||||
|
die("Couldn't open dependency file %s: %s\n", depname,
|
||||||
|
strerror(errno));
|
||||||
|
fprintf(depfile, "%s:", outname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inform == NULL)
|
||||||
|
inform = guess_input_format(arg, "dts");
|
||||||
|
if (outform == NULL) {
|
||||||
|
outform = guess_type_by_name(outname, NULL);
|
||||||
|
if (outform == NULL) {
|
||||||
|
if (streq(inform, "dts"))
|
||||||
|
outform = "dtb";
|
||||||
|
else
|
||||||
|
outform = "dts";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (streq(inform, "dts"))
|
||||||
|
dti = dt_from_source(arg);
|
||||||
|
else if (streq(inform, "fs"))
|
||||||
|
dti = dt_from_fs(arg);
|
||||||
|
else if(streq(inform, "dtb"))
|
||||||
|
dti = dt_from_blob(arg);
|
||||||
|
else
|
||||||
|
die("Unknown input format \"%s\"\n", inform);
|
||||||
|
|
||||||
|
dti->outname = outname;
|
||||||
|
|
||||||
|
if (depfile) {
|
||||||
|
fputc('\n', depfile);
|
||||||
|
fclose(depfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdline_boot_cpuid != -1)
|
||||||
|
dti->boot_cpuid_phys = cmdline_boot_cpuid;
|
||||||
|
|
||||||
|
fill_fullpaths(dti->dt, "");
|
||||||
|
process_checks(force, dti);
|
||||||
|
|
||||||
|
/* on a plugin, generate by default */
|
||||||
|
if (dti->dtsflags & DTSF_PLUGIN) {
|
||||||
|
generate_fixups = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto_label_aliases)
|
||||||
|
generate_label_tree(dti, "aliases", false);
|
||||||
|
|
||||||
|
if (generate_symbols)
|
||||||
|
generate_label_tree(dti, "__symbols__", true);
|
||||||
|
|
||||||
|
if (generate_fixups) {
|
||||||
|
generate_fixups_tree(dti, "__fixups__");
|
||||||
|
generate_local_fixups_tree(dti, "__local_fixups__");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sort)
|
||||||
|
sort_tree(dti);
|
||||||
|
|
||||||
|
if (streq(outname, "-")) {
|
||||||
|
outf = stdout;
|
||||||
|
} else {
|
||||||
|
outf = fopen(outname, "wb");
|
||||||
|
if (! outf)
|
||||||
|
die("Couldn't open output file %s: %s\n",
|
||||||
|
outname, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(outform, "dts")) {
|
||||||
|
dt_to_source(outf, dti);
|
||||||
|
} else if (streq(outform, "dtb")) {
|
||||||
|
dt_to_blob(outf, dti, outversion);
|
||||||
|
} else if (streq(outform, "asm")) {
|
||||||
|
dt_to_asm(outf, dti, outversion);
|
||||||
|
} else if (streq(outform, "null")) {
|
||||||
|
/* do nothing */
|
||||||
|
} else {
|
||||||
|
die("Unknown output format \"%s\"\n", outform);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
291
dtc-1.4.5/dtc.h
Normal file
291
dtc-1.4.5/dtc.h
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
#ifndef _DTC_H
|
||||||
|
#define _DTC_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <libfdt_env.h>
|
||||||
|
#include <fdt.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define debug(...) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define debug(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_FDT_VERSION 17
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command line options
|
||||||
|
*/
|
||||||
|
extern int quiet; /* Level of quietness */
|
||||||
|
extern int reservenum; /* Number of memory reservation slots */
|
||||||
|
extern int minsize; /* Minimum blob size */
|
||||||
|
extern int padsize; /* Additional padding to blob */
|
||||||
|
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
|
||||||
|
extern int phandle_format; /* Use linux,phandle or phandle properties */
|
||||||
|
extern int generate_symbols; /* generate symbols for nodes with labels */
|
||||||
|
extern int generate_fixups; /* generate fixups */
|
||||||
|
extern int auto_label_aliases; /* auto generate labels -> aliases */
|
||||||
|
|
||||||
|
#define PHANDLE_LEGACY 0x1
|
||||||
|
#define PHANDLE_EPAPR 0x2
|
||||||
|
#define PHANDLE_BOTH 0x3
|
||||||
|
|
||||||
|
typedef uint32_t cell_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define streq(a, b) (strcmp((a), (b)) == 0)
|
||||||
|
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
|
||||||
|
|
||||||
|
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||||
|
|
||||||
|
/* Data blobs */
|
||||||
|
enum markertype {
|
||||||
|
REF_PHANDLE,
|
||||||
|
REF_PATH,
|
||||||
|
LABEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct marker {
|
||||||
|
enum markertype type;
|
||||||
|
int offset;
|
||||||
|
char *ref;
|
||||||
|
struct marker *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct data {
|
||||||
|
int len;
|
||||||
|
char *val;
|
||||||
|
struct marker *markers;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define empty_data ((struct data){ 0 /* all .members = 0 or NULL */ })
|
||||||
|
|
||||||
|
#define for_each_marker(m) \
|
||||||
|
for (; (m); (m) = (m)->next)
|
||||||
|
#define for_each_marker_of_type(m, t) \
|
||||||
|
for_each_marker(m) \
|
||||||
|
if ((m)->type == (t))
|
||||||
|
|
||||||
|
void data_free(struct data d);
|
||||||
|
|
||||||
|
struct data data_grow_for(struct data d, int xlen);
|
||||||
|
|
||||||
|
struct data data_copy_mem(const char *mem, int len);
|
||||||
|
struct data data_copy_escape_string(const char *s, int len);
|
||||||
|
struct data data_copy_file(FILE *f, size_t len);
|
||||||
|
|
||||||
|
struct data data_append_data(struct data d, const void *p, int len);
|
||||||
|
struct data data_insert_at_marker(struct data d, struct marker *m,
|
||||||
|
const void *p, int len);
|
||||||
|
struct data data_merge(struct data d1, struct data d2);
|
||||||
|
struct data data_append_cell(struct data d, cell_t word);
|
||||||
|
struct data data_append_integer(struct data d, uint64_t word, int bits);
|
||||||
|
struct data data_append_re(struct data d, uint64_t address, uint64_t size);
|
||||||
|
struct data data_append_addr(struct data d, uint64_t addr);
|
||||||
|
struct data data_append_byte(struct data d, uint8_t byte);
|
||||||
|
struct data data_append_zeroes(struct data d, int len);
|
||||||
|
struct data data_append_align(struct data d, int align);
|
||||||
|
|
||||||
|
struct data data_add_marker(struct data d, enum markertype type, char *ref);
|
||||||
|
|
||||||
|
bool data_is_one_string(struct data d);
|
||||||
|
|
||||||
|
/* DT constraints */
|
||||||
|
|
||||||
|
#define MAX_PROPNAME_LEN 31
|
||||||
|
#define MAX_NODENAME_LEN 31
|
||||||
|
|
||||||
|
/* Live trees */
|
||||||
|
struct label {
|
||||||
|
bool deleted;
|
||||||
|
char *label;
|
||||||
|
struct label *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bus_type {
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct property {
|
||||||
|
bool deleted;
|
||||||
|
char *name;
|
||||||
|
struct data val;
|
||||||
|
|
||||||
|
struct property *next;
|
||||||
|
|
||||||
|
struct label *labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct node {
|
||||||
|
bool deleted;
|
||||||
|
char *name;
|
||||||
|
struct property *proplist;
|
||||||
|
struct node *children;
|
||||||
|
|
||||||
|
struct node *parent;
|
||||||
|
struct node *next_sibling;
|
||||||
|
|
||||||
|
char *fullpath;
|
||||||
|
int basenamelen;
|
||||||
|
|
||||||
|
cell_t phandle;
|
||||||
|
int addr_cells, size_cells;
|
||||||
|
|
||||||
|
struct label *labels;
|
||||||
|
const struct bus_type *bus;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define for_each_label_withdel(l0, l) \
|
||||||
|
for ((l) = (l0); (l); (l) = (l)->next)
|
||||||
|
|
||||||
|
#define for_each_label(l0, l) \
|
||||||
|
for_each_label_withdel(l0, l) \
|
||||||
|
if (!(l)->deleted)
|
||||||
|
|
||||||
|
#define for_each_property_withdel(n, p) \
|
||||||
|
for ((p) = (n)->proplist; (p); (p) = (p)->next)
|
||||||
|
|
||||||
|
#define for_each_property(n, p) \
|
||||||
|
for_each_property_withdel(n, p) \
|
||||||
|
if (!(p)->deleted)
|
||||||
|
|
||||||
|
#define for_each_child_withdel(n, c) \
|
||||||
|
for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
|
||||||
|
|
||||||
|
#define for_each_child(n, c) \
|
||||||
|
for_each_child_withdel(n, c) \
|
||||||
|
if (!(c)->deleted)
|
||||||
|
|
||||||
|
void add_label(struct label **labels, char *label);
|
||||||
|
void delete_labels(struct label **labels);
|
||||||
|
|
||||||
|
struct property *build_property(char *name, struct data val);
|
||||||
|
struct property *build_property_delete(char *name);
|
||||||
|
struct property *chain_property(struct property *first, struct property *list);
|
||||||
|
struct property *reverse_properties(struct property *first);
|
||||||
|
|
||||||
|
struct node *build_node(struct property *proplist, struct node *children);
|
||||||
|
struct node *build_node_delete(void);
|
||||||
|
struct node *name_node(struct node *node, char *name);
|
||||||
|
struct node *chain_node(struct node *first, struct node *list);
|
||||||
|
struct node *merge_nodes(struct node *old_node, struct node *new_node);
|
||||||
|
|
||||||
|
void add_property(struct node *node, struct property *prop);
|
||||||
|
void delete_property_by_name(struct node *node, char *name);
|
||||||
|
void delete_property(struct property *prop);
|
||||||
|
void add_child(struct node *parent, struct node *child);
|
||||||
|
void delete_node_by_name(struct node *parent, char *name);
|
||||||
|
void delete_node(struct node *node);
|
||||||
|
void append_to_property(struct node *node,
|
||||||
|
char *name, const void *data, int len);
|
||||||
|
|
||||||
|
const char *get_unitname(struct node *node);
|
||||||
|
struct property *get_property(struct node *node, const char *propname);
|
||||||
|
cell_t propval_cell(struct property *prop);
|
||||||
|
cell_t propval_cell_n(struct property *prop, int n);
|
||||||
|
struct property *get_property_by_label(struct node *tree, const char *label,
|
||||||
|
struct node **node);
|
||||||
|
struct marker *get_marker_label(struct node *tree, const char *label,
|
||||||
|
struct node **node, struct property **prop);
|
||||||
|
struct node *get_subnode(struct node *node, const char *nodename);
|
||||||
|
struct node *get_node_by_path(struct node *tree, const char *path);
|
||||||
|
struct node *get_node_by_label(struct node *tree, const char *label);
|
||||||
|
struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
|
||||||
|
struct node *get_node_by_ref(struct node *tree, const char *ref);
|
||||||
|
cell_t get_node_phandle(struct node *root, struct node *node);
|
||||||
|
|
||||||
|
uint32_t guess_boot_cpuid(struct node *tree);
|
||||||
|
|
||||||
|
/* Boot info (tree plus memreserve information */
|
||||||
|
|
||||||
|
struct reserve_info {
|
||||||
|
uint64_t address, size;
|
||||||
|
|
||||||
|
struct reserve_info *next;
|
||||||
|
|
||||||
|
struct label *labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
|
||||||
|
struct reserve_info *chain_reserve_entry(struct reserve_info *first,
|
||||||
|
struct reserve_info *list);
|
||||||
|
struct reserve_info *add_reserve_entry(struct reserve_info *list,
|
||||||
|
struct reserve_info *new);
|
||||||
|
|
||||||
|
|
||||||
|
struct dt_info {
|
||||||
|
unsigned int dtsflags;
|
||||||
|
struct reserve_info *reservelist;
|
||||||
|
uint32_t boot_cpuid_phys;
|
||||||
|
struct node *dt; /* the device tree */
|
||||||
|
const char *outname; /* filename being written to, "-" for stdout */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* DTS version flags definitions */
|
||||||
|
#define DTSF_V1 0x0001 /* /dts-v1/ */
|
||||||
|
#define DTSF_PLUGIN 0x0002 /* /plugin/ */
|
||||||
|
|
||||||
|
struct dt_info *build_dt_info(unsigned int dtsflags,
|
||||||
|
struct reserve_info *reservelist,
|
||||||
|
struct node *tree, uint32_t boot_cpuid_phys);
|
||||||
|
void sort_tree(struct dt_info *dti);
|
||||||
|
void generate_label_tree(struct dt_info *dti, char *name, bool allocph);
|
||||||
|
void generate_fixups_tree(struct dt_info *dti, char *name);
|
||||||
|
void generate_local_fixups_tree(struct dt_info *dti, char *name);
|
||||||
|
|
||||||
|
/* Checks */
|
||||||
|
|
||||||
|
void parse_checks_option(bool warn, bool error, const char *arg);
|
||||||
|
void process_checks(bool force, struct dt_info *dti);
|
||||||
|
|
||||||
|
/* Flattened trees */
|
||||||
|
|
||||||
|
void dt_to_blob(FILE *f, struct dt_info *dti, int version);
|
||||||
|
void dt_to_asm(FILE *f, struct dt_info *dti, int version);
|
||||||
|
|
||||||
|
struct dt_info *dt_from_blob(const char *fname);
|
||||||
|
|
||||||
|
/* Tree source */
|
||||||
|
|
||||||
|
void dt_to_source(FILE *f, struct dt_info *dti);
|
||||||
|
struct dt_info *dt_from_source(const char *f);
|
||||||
|
|
||||||
|
/* FS trees */
|
||||||
|
|
||||||
|
struct dt_info *dt_from_fs(const char *dirname);
|
||||||
|
|
||||||
|
#endif /* _DTC_H */
|
||||||
38
dtc-1.4.5/dtdiff
Normal file
38
dtc-1.4.5/dtdiff
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
# This script uses the bash <(...) extension.
|
||||||
|
# If you want to change this to work with a generic /bin/sh, make sure
|
||||||
|
# you fix that.
|
||||||
|
|
||||||
|
|
||||||
|
DTC=dtc
|
||||||
|
|
||||||
|
source_and_sort () {
|
||||||
|
DT="$1"
|
||||||
|
if [ -d "$DT" ]; then
|
||||||
|
IFORMAT=fs
|
||||||
|
elif [ -f "$DT" ]; then
|
||||||
|
case "$DT" in
|
||||||
|
*.dts)
|
||||||
|
IFORMAT=dts
|
||||||
|
;;
|
||||||
|
*.dtb)
|
||||||
|
IFORMAT=dtb
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$IFORMAT" ]; then
|
||||||
|
echo "Unrecognized format for $DT" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
$DTC -I $IFORMAT -O dts -qq -f -s -o - "$DT"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# != 2 ]; then
|
||||||
|
echo "Usage: dtdiff <device tree> <device tree>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
diff -u <(source_and_sort "$1") <(source_and_sort "$2")
|
||||||
245
dtc-1.4.5/fdtdump.c
Normal file
245
dtc-1.4.5/fdtdump.c
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <libfdt_env.h>
|
||||||
|
#include <fdt.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define FDT_MAGIC_SIZE 4
|
||||||
|
#define MAX_VERSION 17
|
||||||
|
|
||||||
|
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||||||
|
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
|
||||||
|
#define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4)))
|
||||||
|
|
||||||
|
static const char *tagname(uint32_t tag)
|
||||||
|
{
|
||||||
|
static const char * const names[] = {
|
||||||
|
#define TN(t) [t] = #t
|
||||||
|
TN(FDT_BEGIN_NODE),
|
||||||
|
TN(FDT_END_NODE),
|
||||||
|
TN(FDT_PROP),
|
||||||
|
TN(FDT_NOP),
|
||||||
|
TN(FDT_END),
|
||||||
|
#undef TN
|
||||||
|
};
|
||||||
|
if (tag < ARRAY_SIZE(names))
|
||||||
|
if (names[tag])
|
||||||
|
return names[tag];
|
||||||
|
return "FDT_???";
|
||||||
|
}
|
||||||
|
|
||||||
|
#define dumpf(fmt, args...) \
|
||||||
|
do { if (debug) printf("// " fmt, ## args); } while (0)
|
||||||
|
|
||||||
|
static void dump_blob(void *blob, bool debug)
|
||||||
|
{
|
||||||
|
uintptr_t blob_off = (uintptr_t)blob;
|
||||||
|
struct fdt_header *bph = blob;
|
||||||
|
uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
|
||||||
|
uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
|
||||||
|
uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
|
||||||
|
struct fdt_reserve_entry *p_rsvmap =
|
||||||
|
(struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
|
||||||
|
const char *p_struct = (const char *)blob + off_dt;
|
||||||
|
const char *p_strings = (const char *)blob + off_str;
|
||||||
|
uint32_t version = fdt32_to_cpu(bph->version);
|
||||||
|
uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
|
||||||
|
uint32_t tag;
|
||||||
|
const char *p, *s, *t;
|
||||||
|
int depth, sz, shift;
|
||||||
|
int i;
|
||||||
|
uint64_t addr, size;
|
||||||
|
|
||||||
|
depth = 0;
|
||||||
|
shift = 4;
|
||||||
|
|
||||||
|
printf("/dts-v1/;\n");
|
||||||
|
printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
|
||||||
|
printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
|
||||||
|
printf("// off_dt_struct:\t0x%x\n", off_dt);
|
||||||
|
printf("// off_dt_strings:\t0x%x\n", off_str);
|
||||||
|
printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
|
||||||
|
printf("// version:\t\t%d\n", version);
|
||||||
|
printf("// last_comp_version:\t%d\n",
|
||||||
|
fdt32_to_cpu(bph->last_comp_version));
|
||||||
|
if (version >= 2)
|
||||||
|
printf("// boot_cpuid_phys:\t0x%x\n",
|
||||||
|
fdt32_to_cpu(bph->boot_cpuid_phys));
|
||||||
|
|
||||||
|
if (version >= 3)
|
||||||
|
printf("// size_dt_strings:\t0x%x\n",
|
||||||
|
fdt32_to_cpu(bph->size_dt_strings));
|
||||||
|
if (version >= 17)
|
||||||
|
printf("// size_dt_struct:\t0x%x\n",
|
||||||
|
fdt32_to_cpu(bph->size_dt_struct));
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
for (i = 0; ; i++) {
|
||||||
|
addr = fdt64_to_cpu(p_rsvmap[i].address);
|
||||||
|
size = fdt64_to_cpu(p_rsvmap[i].size);
|
||||||
|
if (addr == 0 && size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
printf("/memreserve/ %#llx %#llx;\n",
|
||||||
|
(unsigned long long)addr, (unsigned long long)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p_struct;
|
||||||
|
while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
|
||||||
|
|
||||||
|
dumpf("%04zx: tag: 0x%08x (%s)\n",
|
||||||
|
(uintptr_t)p - blob_off - 4, tag, tagname(tag));
|
||||||
|
|
||||||
|
if (tag == FDT_BEGIN_NODE) {
|
||||||
|
s = p;
|
||||||
|
p = PALIGN(p + strlen(s) + 1, 4);
|
||||||
|
|
||||||
|
if (*s == '\0')
|
||||||
|
s = "/";
|
||||||
|
|
||||||
|
printf("%*s%s {\n", depth * shift, "", s);
|
||||||
|
|
||||||
|
depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == FDT_END_NODE) {
|
||||||
|
depth--;
|
||||||
|
|
||||||
|
printf("%*s};\n", depth * shift, "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == FDT_NOP) {
|
||||||
|
printf("%*s// [NOP]\n", depth * shift, "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag != FDT_PROP) {
|
||||||
|
fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sz = fdt32_to_cpu(GET_CELL(p));
|
||||||
|
s = p_strings + fdt32_to_cpu(GET_CELL(p));
|
||||||
|
if (version < 16 && sz >= 8)
|
||||||
|
p = PALIGN(p, 8);
|
||||||
|
t = p;
|
||||||
|
|
||||||
|
p = PALIGN(p + sz, 4);
|
||||||
|
|
||||||
|
dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s);
|
||||||
|
dumpf("%04zx: value\n", (uintptr_t)t - blob_off);
|
||||||
|
printf("%*s%s", depth * shift, "", s);
|
||||||
|
utilfdt_print_data(t, sz);
|
||||||
|
printf(";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Usage related data. */
|
||||||
|
static const char usage_synopsis[] = "fdtdump [options] <file>";
|
||||||
|
static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS;
|
||||||
|
static struct option const usage_long_opts[] = {
|
||||||
|
{"debug", no_argument, NULL, 'd'},
|
||||||
|
{"scan", no_argument, NULL, 's'},
|
||||||
|
USAGE_COMMON_LONG_OPTS
|
||||||
|
};
|
||||||
|
static const char * const usage_opts_help[] = {
|
||||||
|
"Dump debug information while decoding the file",
|
||||||
|
"Scan for an embedded fdt in file",
|
||||||
|
USAGE_COMMON_OPTS_HELP
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool valid_header(char *p, off_t len)
|
||||||
|
{
|
||||||
|
if (len < sizeof(struct fdt_header) ||
|
||||||
|
fdt_magic(p) != FDT_MAGIC ||
|
||||||
|
fdt_version(p) > MAX_VERSION ||
|
||||||
|
fdt_last_comp_version(p) > MAX_VERSION ||
|
||||||
|
fdt_totalsize(p) >= len ||
|
||||||
|
fdt_off_dt_struct(p) >= len ||
|
||||||
|
fdt_off_dt_strings(p) >= len)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
const char *file;
|
||||||
|
char *buf;
|
||||||
|
bool debug = false;
|
||||||
|
bool scan = false;
|
||||||
|
off_t len;
|
||||||
|
|
||||||
|
fprintf(stderr, "\n"
|
||||||
|
"**** fdtdump is a low-level debugging tool, not meant for general use.\n"
|
||||||
|
"**** If you want to decompile a dtb, you probably want\n"
|
||||||
|
"**** dtc -I dtb -O dts <filename>\n\n"
|
||||||
|
);
|
||||||
|
while ((opt = util_getopt_long()) != EOF) {
|
||||||
|
switch (opt) {
|
||||||
|
case_USAGE_COMMON_FLAGS
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
debug = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
scan = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (optind != argc - 1)
|
||||||
|
usage("missing input filename");
|
||||||
|
file = argv[optind];
|
||||||
|
|
||||||
|
buf = utilfdt_read_len(file, &len);
|
||||||
|
if (!buf)
|
||||||
|
die("could not read: %s\n", file);
|
||||||
|
|
||||||
|
/* try and locate an embedded fdt in a bigger blob */
|
||||||
|
if (scan) {
|
||||||
|
unsigned char smagic[FDT_MAGIC_SIZE];
|
||||||
|
char *p = buf;
|
||||||
|
char *endp = buf + len;
|
||||||
|
|
||||||
|
fdt_set_magic(smagic, FDT_MAGIC);
|
||||||
|
|
||||||
|
/* poor man's memmem */
|
||||||
|
while ((endp - p) >= FDT_MAGIC_SIZE) {
|
||||||
|
p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
|
||||||
|
if (!p)
|
||||||
|
break;
|
||||||
|
if (fdt_magic(p) == FDT_MAGIC) {
|
||||||
|
/* try and validate the main struct */
|
||||||
|
off_t this_len = endp - p;
|
||||||
|
if (valid_header(p, this_len))
|
||||||
|
break;
|
||||||
|
if (debug)
|
||||||
|
printf("%s: skipping fdt magic at offset %#zx\n",
|
||||||
|
file, p - buf);
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
if (!p || endp - p < sizeof(struct fdt_header))
|
||||||
|
die("%s: could not locate fdt magic\n", file);
|
||||||
|
printf("%s: found fdt at offset %#zx\n", file, p - buf);
|
||||||
|
buf = p;
|
||||||
|
} else if (!valid_header(buf, len))
|
||||||
|
die("%s: header is not valid\n", file);
|
||||||
|
|
||||||
|
dump_blob(buf, debug);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
385
dtc-1.4.5/fdtget.c
Normal file
385
dtc-1.4.5/fdtget.c
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Portions from U-Boot cmd_fdt.c (C) Copyright 2007
|
||||||
|
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
|
||||||
|
* Based on code written by:
|
||||||
|
* Pantelis Antoniou <pantelis.antoniou@gmail.com> and
|
||||||
|
* Matthew McClintock <msm@freescale.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
|
* MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
enum display_mode {
|
||||||
|
MODE_SHOW_VALUE, /* show values for node properties */
|
||||||
|
MODE_LIST_PROPS, /* list the properties for a node */
|
||||||
|
MODE_LIST_SUBNODES, /* list the subnodes of a node */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Holds information which controls our output and options */
|
||||||
|
struct display_info {
|
||||||
|
int type; /* data type (s/i/u/x or 0 for default) */
|
||||||
|
int size; /* data size (1/2/4) */
|
||||||
|
enum display_mode mode; /* display mode that we are using */
|
||||||
|
const char *default_val; /* default value if node/property not found */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void report_error(const char *where, int err)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a list of cells in the requested format
|
||||||
|
*
|
||||||
|
* @param disp Display information / options
|
||||||
|
* @param data Data to display
|
||||||
|
* @param len Maximum length of buffer
|
||||||
|
* @param size Data size to use for display (e.g. 4 for 32-bit)
|
||||||
|
* @return 0 if ok, -1 on error
|
||||||
|
*/
|
||||||
|
static int show_cell_list(struct display_info *disp, const char *data, int len,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)data;
|
||||||
|
char fmt[3];
|
||||||
|
int value;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fmt[0] = '%';
|
||||||
|
fmt[1] = disp->type ? disp->type : 'd';
|
||||||
|
fmt[2] = '\0';
|
||||||
|
for (i = 0; i < len; i += size, p += size) {
|
||||||
|
if (i)
|
||||||
|
printf(" ");
|
||||||
|
value = size == 4 ? fdt32_to_cpu(*(const fdt32_t *)p) :
|
||||||
|
size == 2 ? (*p << 8) | p[1] : *p;
|
||||||
|
printf(fmt, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays data of a given length according to selected options
|
||||||
|
*
|
||||||
|
* If a specific data type is provided in disp, then this is used. Otherwise
|
||||||
|
* we try to guess the data type / size from the contents.
|
||||||
|
*
|
||||||
|
* @param disp Display information / options
|
||||||
|
* @param data Data to display
|
||||||
|
* @param len Maximum length of buffer
|
||||||
|
* @return 0 if ok, -1 if data does not match format
|
||||||
|
*/
|
||||||
|
static int show_data(struct display_info *disp, const char *data, int len)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
const char *s;
|
||||||
|
int is_string;
|
||||||
|
|
||||||
|
/* no data, don't print */
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
is_string = (disp->type) == 's' ||
|
||||||
|
(!disp->type && util_is_printable_string(data, len));
|
||||||
|
if (is_string) {
|
||||||
|
if (data[len - 1] != '\0') {
|
||||||
|
fprintf(stderr, "Unterminated string\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (s = data; s - data < len; s += strlen(s) + 1) {
|
||||||
|
if (s != data)
|
||||||
|
printf(" ");
|
||||||
|
printf("%s", (const char *)s);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size = disp->size;
|
||||||
|
if (size == -1) {
|
||||||
|
size = (len % 4) == 0 ? 4 : 1;
|
||||||
|
} else if (len % size) {
|
||||||
|
fprintf(stderr, "Property length must be a multiple of "
|
||||||
|
"selected data size\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return show_cell_list(disp, data, len, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all properties in a node, one per line.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob
|
||||||
|
* @param node Node to display
|
||||||
|
* @return 0 if ok, or FDT_ERR... if not.
|
||||||
|
*/
|
||||||
|
static int list_properties(const void *blob, int node)
|
||||||
|
{
|
||||||
|
const struct fdt_property *data;
|
||||||
|
const char *name;
|
||||||
|
int prop;
|
||||||
|
|
||||||
|
prop = fdt_first_property_offset(blob, node);
|
||||||
|
do {
|
||||||
|
/* Stop silently when there are no more properties */
|
||||||
|
if (prop < 0)
|
||||||
|
return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
|
||||||
|
data = fdt_get_property_by_offset(blob, prop, NULL);
|
||||||
|
name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
|
||||||
|
if (name)
|
||||||
|
puts(name);
|
||||||
|
prop = fdt_next_property_offset(blob, prop);
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_LEVEL 32 /* how deeply nested we will go */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all subnodes in a node, one per line
|
||||||
|
*
|
||||||
|
* @param blob FDT blob
|
||||||
|
* @param node Node to display
|
||||||
|
* @return 0 if ok, or FDT_ERR... if not.
|
||||||
|
*/
|
||||||
|
static int list_subnodes(const void *blob, int node)
|
||||||
|
{
|
||||||
|
int nextoffset; /* next node offset from libfdt */
|
||||||
|
uint32_t tag; /* current tag */
|
||||||
|
int level = 0; /* keep track of nesting level */
|
||||||
|
const char *pathp;
|
||||||
|
int depth = 1; /* the assumed depth of this node */
|
||||||
|
|
||||||
|
while (level >= 0) {
|
||||||
|
tag = fdt_next_tag(blob, node, &nextoffset);
|
||||||
|
switch (tag) {
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
pathp = fdt_get_name(blob, node, NULL);
|
||||||
|
if (level <= depth) {
|
||||||
|
if (pathp == NULL)
|
||||||
|
pathp = "/* NULL pointer error */";
|
||||||
|
if (*pathp == '\0')
|
||||||
|
pathp = "/"; /* root is nameless */
|
||||||
|
if (level == 1)
|
||||||
|
puts(pathp);
|
||||||
|
}
|
||||||
|
level++;
|
||||||
|
if (level >= MAX_LEVEL) {
|
||||||
|
printf("Nested too deep, aborting.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FDT_END_NODE:
|
||||||
|
level--;
|
||||||
|
if (level == 0)
|
||||||
|
level = -1; /* exit the loop */
|
||||||
|
break;
|
||||||
|
case FDT_END:
|
||||||
|
return 1;
|
||||||
|
case FDT_PROP:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (level <= depth)
|
||||||
|
printf("Unknown tag 0x%08X\n", tag);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
node = nextoffset;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the data for a given node (and perhaps property) according to the
|
||||||
|
* display option provided.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob
|
||||||
|
* @param disp Display information / options
|
||||||
|
* @param node Node to display
|
||||||
|
* @param property Name of property to display, or NULL if none
|
||||||
|
* @return 0 if ok, -ve on error
|
||||||
|
*/
|
||||||
|
static int show_data_for_item(const void *blob, struct display_info *disp,
|
||||||
|
int node, const char *property)
|
||||||
|
{
|
||||||
|
const void *value = NULL;
|
||||||
|
int len, err = 0;
|
||||||
|
|
||||||
|
switch (disp->mode) {
|
||||||
|
case MODE_LIST_PROPS:
|
||||||
|
err = list_properties(blob, node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_LIST_SUBNODES:
|
||||||
|
err = list_subnodes(blob, node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(property);
|
||||||
|
value = fdt_getprop(blob, node, property, &len);
|
||||||
|
if (value) {
|
||||||
|
if (show_data(disp, value, len))
|
||||||
|
err = -1;
|
||||||
|
else
|
||||||
|
printf("\n");
|
||||||
|
} else if (disp->default_val) {
|
||||||
|
puts(disp->default_val);
|
||||||
|
} else {
|
||||||
|
report_error(property, len);
|
||||||
|
err = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the main fdtget operation, given a filename and valid arguments
|
||||||
|
*
|
||||||
|
* @param disp Display information / options
|
||||||
|
* @param filename Filename of blob file
|
||||||
|
* @param arg List of arguments to process
|
||||||
|
* @param arg_count Number of arguments
|
||||||
|
* @return 0 if ok, -ve on error
|
||||||
|
*/
|
||||||
|
static int do_fdtget(struct display_info *disp, const char *filename,
|
||||||
|
char **arg, int arg_count, int args_per_step)
|
||||||
|
{
|
||||||
|
char *blob;
|
||||||
|
const char *prop;
|
||||||
|
int i, node;
|
||||||
|
|
||||||
|
blob = utilfdt_read(filename);
|
||||||
|
if (!blob)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
|
||||||
|
node = fdt_path_offset(blob, arg[i]);
|
||||||
|
if (node < 0) {
|
||||||
|
if (disp->default_val) {
|
||||||
|
puts(disp->default_val);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
report_error(arg[i], node);
|
||||||
|
free(blob);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prop = args_per_step == 1 ? NULL : arg[i + 1];
|
||||||
|
|
||||||
|
if (show_data_for_item(blob, disp, node, prop)) {
|
||||||
|
free(blob);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(blob);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Usage related data. */
|
||||||
|
static const char usage_synopsis[] =
|
||||||
|
"read values from device tree\n"
|
||||||
|
" fdtget <options> <dt file> [<node> <property>]...\n"
|
||||||
|
" fdtget -p <options> <dt file> [<node> ]...\n"
|
||||||
|
"\n"
|
||||||
|
"Each value is printed on a new line.\n"
|
||||||
|
USAGE_TYPE_MSG;
|
||||||
|
static const char usage_short_opts[] = "t:pld:" USAGE_COMMON_SHORT_OPTS;
|
||||||
|
static struct option const usage_long_opts[] = {
|
||||||
|
{"type", a_argument, NULL, 't'},
|
||||||
|
{"properties", no_argument, NULL, 'p'},
|
||||||
|
{"list", no_argument, NULL, 'l'},
|
||||||
|
{"default", a_argument, NULL, 'd'},
|
||||||
|
USAGE_COMMON_LONG_OPTS,
|
||||||
|
};
|
||||||
|
static const char * const usage_opts_help[] = {
|
||||||
|
"Type of data",
|
||||||
|
"List properties for each node",
|
||||||
|
"List subnodes for each node",
|
||||||
|
"Default value to display when the property is missing",
|
||||||
|
USAGE_COMMON_OPTS_HELP
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
char *filename = NULL;
|
||||||
|
struct display_info disp;
|
||||||
|
int args_per_step = 2;
|
||||||
|
|
||||||
|
/* set defaults */
|
||||||
|
memset(&disp, '\0', sizeof(disp));
|
||||||
|
disp.size = -1;
|
||||||
|
disp.mode = MODE_SHOW_VALUE;
|
||||||
|
while ((opt = util_getopt_long()) != EOF) {
|
||||||
|
switch (opt) {
|
||||||
|
case_USAGE_COMMON_FLAGS
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
if (utilfdt_decode_type(optarg, &disp.type,
|
||||||
|
&disp.size))
|
||||||
|
usage("invalid type string");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
disp.mode = MODE_LIST_PROPS;
|
||||||
|
args_per_step = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
disp.mode = MODE_LIST_SUBNODES;
|
||||||
|
args_per_step = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
disp.default_val = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
filename = argv[optind++];
|
||||||
|
if (!filename)
|
||||||
|
usage("missing filename");
|
||||||
|
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
/* Allow no arguments, and silently succeed */
|
||||||
|
if (!argc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check for node, property arguments */
|
||||||
|
if (args_per_step == 2 && (argc % 2))
|
||||||
|
usage("must have an even number of arguments");
|
||||||
|
|
||||||
|
if (do_fdtget(&disp, filename, argv, argc, args_per_step))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
175
dtc-1.4.5/fdtoverlay.c
Normal file
175
dtc-1.4.5/fdtoverlay.c
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Author:
|
||||||
|
* Pantelis Antoniou <pantelis.antoniou@konsulko.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
|
* MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* Usage related data. */
|
||||||
|
static const char usage_synopsis[] =
|
||||||
|
"apply a number of overlays to a base blob\n"
|
||||||
|
" fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]\n"
|
||||||
|
"\n"
|
||||||
|
USAGE_TYPE_MSG;
|
||||||
|
static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
|
||||||
|
static struct option const usage_long_opts[] = {
|
||||||
|
{"input", required_argument, NULL, 'i'},
|
||||||
|
{"output", required_argument, NULL, 'o'},
|
||||||
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
|
USAGE_COMMON_LONG_OPTS,
|
||||||
|
};
|
||||||
|
static const char * const usage_opts_help[] = {
|
||||||
|
"Input base DT blob",
|
||||||
|
"Output DT blob",
|
||||||
|
"Verbose messages",
|
||||||
|
USAGE_COMMON_OPTS_HELP
|
||||||
|
};
|
||||||
|
|
||||||
|
int verbose = 0;
|
||||||
|
|
||||||
|
static int do_fdtoverlay(const char *input_filename,
|
||||||
|
const char *output_filename,
|
||||||
|
int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *blob = NULL;
|
||||||
|
char **ovblob = NULL;
|
||||||
|
off_t blob_len, ov_len, total_len;
|
||||||
|
int i, ret = -1;
|
||||||
|
|
||||||
|
blob = utilfdt_read_len(input_filename, &blob_len);
|
||||||
|
if (!blob) {
|
||||||
|
fprintf(stderr, "\nFailed to read base blob %s\n",
|
||||||
|
input_filename);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
if (fdt_totalsize(blob) > blob_len) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
|
||||||
|
(unsigned long)blob_len, fdt_totalsize(blob));
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
/* allocate blob pointer array */
|
||||||
|
ovblob = alloca(sizeof(*ovblob) * argc);
|
||||||
|
memset(ovblob, 0, sizeof(*ovblob) * argc);
|
||||||
|
|
||||||
|
/* read and keep track of the overlay blobs */
|
||||||
|
total_len = 0;
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
ovblob[i] = utilfdt_read_len(argv[i], &ov_len);
|
||||||
|
if (!ovblob[i]) {
|
||||||
|
fprintf(stderr, "\nFailed to read overlay %s\n",
|
||||||
|
argv[i]);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
total_len += ov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grow the blob to worst case */
|
||||||
|
blob_len = fdt_totalsize(blob) + total_len;
|
||||||
|
blob = xrealloc(blob, blob_len);
|
||||||
|
fdt_open_into(blob, blob, blob_len);
|
||||||
|
|
||||||
|
/* apply the overlays in sequence */
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
ret = fdt_overlay_apply(blob, ovblob[i]);
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "\nFailed to apply %s (%d)\n",
|
||||||
|
argv[i], ret);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_pack(blob);
|
||||||
|
ret = utilfdt_write(output_filename, blob);
|
||||||
|
if (ret)
|
||||||
|
fprintf(stderr, "\nFailed to write output blob %s\n",
|
||||||
|
output_filename);
|
||||||
|
|
||||||
|
out_err:
|
||||||
|
if (ovblob) {
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if (ovblob[i])
|
||||||
|
free(ovblob[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(blob);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt, i;
|
||||||
|
char *input_filename = NULL;
|
||||||
|
char *output_filename = NULL;
|
||||||
|
|
||||||
|
while ((opt = util_getopt_long()) != EOF) {
|
||||||
|
switch (opt) {
|
||||||
|
case_USAGE_COMMON_FLAGS
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
input_filename = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
output_filename = optarg;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input_filename)
|
||||||
|
usage("missing input file");
|
||||||
|
|
||||||
|
if (!output_filename)
|
||||||
|
usage("missing output file");
|
||||||
|
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
if (argc <= 0)
|
||||||
|
usage("missing overlay file(s)");
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("input = %s\n", input_filename);
|
||||||
|
printf("output = %s\n", output_filename);
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
printf("overlay[%d] = %s\n", i, argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_fdtoverlay(input_filename, output_filename, argc, argv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
480
dtc-1.4.5/fdtput.c
Normal file
480
dtc-1.4.5/fdtput.c
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
|
* MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* These are the operations we support */
|
||||||
|
enum oper_type {
|
||||||
|
OPER_WRITE_PROP, /* Write a property in a node */
|
||||||
|
OPER_CREATE_NODE, /* Create a new node */
|
||||||
|
OPER_REMOVE_NODE, /* Delete a node */
|
||||||
|
OPER_DELETE_PROP, /* Delete a property in a node */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct display_info {
|
||||||
|
enum oper_type oper; /* operation to perform */
|
||||||
|
int type; /* data type (s/i/u/x or 0 for default) */
|
||||||
|
int size; /* data size (1/2/4) */
|
||||||
|
int verbose; /* verbose output */
|
||||||
|
int auto_path; /* automatically create all path components */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report an error with a particular node.
|
||||||
|
*
|
||||||
|
* @param name Node name to report error on
|
||||||
|
* @param namelen Length of node name, or -1 to use entire string
|
||||||
|
* @param err Error number to report (-FDT_ERR_...)
|
||||||
|
*/
|
||||||
|
static void report_error(const char *name, int namelen, int err)
|
||||||
|
{
|
||||||
|
if (namelen == -1)
|
||||||
|
namelen = strlen(name);
|
||||||
|
fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
|
||||||
|
fdt_strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a series of arguments in a property value.
|
||||||
|
*
|
||||||
|
* @param disp Display information / options
|
||||||
|
* @param arg List of arguments from command line
|
||||||
|
* @param arg_count Number of arguments (may be 0)
|
||||||
|
* @param valuep Returns buffer containing value
|
||||||
|
* @param value_len Returns length of value encoded
|
||||||
|
*/
|
||||||
|
static int encode_value(struct display_info *disp, char **arg, int arg_count,
|
||||||
|
char **valuep, int *value_len)
|
||||||
|
{
|
||||||
|
char *value = NULL; /* holding area for value */
|
||||||
|
int value_size = 0; /* size of holding area */
|
||||||
|
char *ptr; /* pointer to current value position */
|
||||||
|
int len; /* length of this cell/string/byte */
|
||||||
|
int ival;
|
||||||
|
int upto; /* the number of bytes we have written to buf */
|
||||||
|
char fmt[3];
|
||||||
|
|
||||||
|
upto = 0;
|
||||||
|
|
||||||
|
if (disp->verbose)
|
||||||
|
fprintf(stderr, "Decoding value:\n");
|
||||||
|
|
||||||
|
fmt[0] = '%';
|
||||||
|
fmt[1] = disp->type ? disp->type : 'd';
|
||||||
|
fmt[2] = '\0';
|
||||||
|
for (; arg_count > 0; arg++, arg_count--, upto += len) {
|
||||||
|
/* assume integer unless told otherwise */
|
||||||
|
if (disp->type == 's')
|
||||||
|
len = strlen(*arg) + 1;
|
||||||
|
else
|
||||||
|
len = disp->size == -1 ? 4 : disp->size;
|
||||||
|
|
||||||
|
/* enlarge our value buffer by a suitable margin if needed */
|
||||||
|
if (upto + len > value_size) {
|
||||||
|
value_size = (upto + len) + 500;
|
||||||
|
value = xrealloc(value, value_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = value + upto;
|
||||||
|
if (disp->type == 's') {
|
||||||
|
memcpy(ptr, *arg, len);
|
||||||
|
if (disp->verbose)
|
||||||
|
fprintf(stderr, "\tstring: '%s'\n", ptr);
|
||||||
|
} else {
|
||||||
|
fdt32_t *iptr = (fdt32_t *)ptr;
|
||||||
|
sscanf(*arg, fmt, &ival);
|
||||||
|
if (len == 4)
|
||||||
|
*iptr = cpu_to_fdt32(ival);
|
||||||
|
else
|
||||||
|
*ptr = (uint8_t)ival;
|
||||||
|
if (disp->verbose) {
|
||||||
|
fprintf(stderr, "\t%s: %d\n",
|
||||||
|
disp->size == 1 ? "byte" :
|
||||||
|
disp->size == 2 ? "short" : "int",
|
||||||
|
ival);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*value_len = upto;
|
||||||
|
*valuep = value;
|
||||||
|
if (disp->verbose)
|
||||||
|
fprintf(stderr, "Value size %d\n", upto);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
|
||||||
|
|
||||||
|
static char *_realloc_fdt(char *fdt, int delta)
|
||||||
|
{
|
||||||
|
int new_sz = fdt_totalsize(fdt) + delta;
|
||||||
|
fdt = xrealloc(fdt, new_sz);
|
||||||
|
fdt_open_into(fdt, fdt, new_sz);
|
||||||
|
return fdt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *realloc_node(char *fdt, const char *name)
|
||||||
|
{
|
||||||
|
int delta;
|
||||||
|
/* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
|
||||||
|
delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
|
||||||
|
+ FDT_TAGSIZE;
|
||||||
|
return _realloc_fdt(fdt, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *realloc_property(char *fdt, int nodeoffset,
|
||||||
|
const char *name, int newlen)
|
||||||
|
{
|
||||||
|
int delta = 0;
|
||||||
|
int oldlen = 0;
|
||||||
|
|
||||||
|
if (!fdt_get_property(fdt, nodeoffset, name, &oldlen))
|
||||||
|
/* strings + property header */
|
||||||
|
delta = sizeof(struct fdt_property) + strlen(name) + 1;
|
||||||
|
|
||||||
|
if (newlen > oldlen)
|
||||||
|
/* actual value in off_struct */
|
||||||
|
delta += ALIGN(newlen) - ALIGN(oldlen);
|
||||||
|
|
||||||
|
return _realloc_fdt(fdt, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int store_key_value(char **blob, const char *node_name,
|
||||||
|
const char *property, const char *buf, int len)
|
||||||
|
{
|
||||||
|
int node;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
node = fdt_path_offset(*blob, node_name);
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(node_name, -1, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop(*blob, node, property, buf, len);
|
||||||
|
if (err == -FDT_ERR_NOSPACE) {
|
||||||
|
*blob = realloc_property(*blob, node, property, len);
|
||||||
|
err = fdt_setprop(*blob, node, property, buf, len);
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
report_error(property, -1, err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create paths as needed for all components of a path
|
||||||
|
*
|
||||||
|
* Any components of the path that do not exist are created. Errors are
|
||||||
|
* reported.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob to write into
|
||||||
|
* @param in_path Path to process
|
||||||
|
* @return 0 if ok, -1 on error
|
||||||
|
*/
|
||||||
|
static int create_paths(char **blob, const char *in_path)
|
||||||
|
{
|
||||||
|
const char *path = in_path;
|
||||||
|
const char *sep;
|
||||||
|
int node, offset = 0;
|
||||||
|
|
||||||
|
/* skip leading '/' */
|
||||||
|
while (*path == '/')
|
||||||
|
path++;
|
||||||
|
|
||||||
|
for (sep = path; *sep; path = sep + 1, offset = node) {
|
||||||
|
/* equivalent to strchrnul(), but it requires _GNU_SOURCE */
|
||||||
|
sep = strchr(path, '/');
|
||||||
|
if (!sep)
|
||||||
|
sep = path + strlen(path);
|
||||||
|
|
||||||
|
node = fdt_subnode_offset_namelen(*blob, offset, path,
|
||||||
|
sep - path);
|
||||||
|
if (node == -FDT_ERR_NOTFOUND) {
|
||||||
|
*blob = realloc_node(*blob, path);
|
||||||
|
node = fdt_add_subnode_namelen(*blob, offset, path,
|
||||||
|
sep - path);
|
||||||
|
}
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(path, sep - path, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new node in the fdt.
|
||||||
|
*
|
||||||
|
* This will overwrite the node_name string. Any error is reported.
|
||||||
|
*
|
||||||
|
* TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob to write into
|
||||||
|
* @param node_name Name of node to create
|
||||||
|
* @return new node offset if found, or -1 on failure
|
||||||
|
*/
|
||||||
|
static int create_node(char **blob, const char *node_name)
|
||||||
|
{
|
||||||
|
int node = 0;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = strrchr(node_name, '/');
|
||||||
|
if (!p) {
|
||||||
|
report_error(node_name, -1, -FDT_ERR_BADPATH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
*blob = realloc_node(*blob, p + 1);
|
||||||
|
|
||||||
|
if (p > node_name) {
|
||||||
|
node = fdt_path_offset(*blob, node_name);
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(node_name, -1, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node = fdt_add_subnode(*blob, node, p + 1);
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(p + 1, -1, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a property of a node in the fdt.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob to write into
|
||||||
|
* @param node_name Path to node containing the property to delete
|
||||||
|
* @param prop_name Name of property to delete
|
||||||
|
* @return 0 on success, or -1 on failure
|
||||||
|
*/
|
||||||
|
static int delete_prop(char *blob, const char *node_name, const char *prop_name)
|
||||||
|
{
|
||||||
|
int node = 0;
|
||||||
|
|
||||||
|
node = fdt_path_offset(blob, node_name);
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(node_name, -1, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = fdt_delprop(blob, node, prop_name);
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(node_name, -1, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a node in the fdt.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob to write into
|
||||||
|
* @param node_name Name of node to delete
|
||||||
|
* @return 0 on success, or -1 on failure
|
||||||
|
*/
|
||||||
|
static int delete_node(char *blob, const char *node_name)
|
||||||
|
{
|
||||||
|
int node = 0;
|
||||||
|
|
||||||
|
node = fdt_path_offset(blob, node_name);
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(node_name, -1, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = fdt_del_node(blob, node);
|
||||||
|
if (node < 0) {
|
||||||
|
report_error(node_name, -1, node);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_fdtput(struct display_info *disp, const char *filename,
|
||||||
|
char **arg, int arg_count)
|
||||||
|
{
|
||||||
|
char *value = NULL;
|
||||||
|
char *blob;
|
||||||
|
char *node;
|
||||||
|
int len, ret = 0;
|
||||||
|
|
||||||
|
blob = utilfdt_read(filename);
|
||||||
|
if (!blob)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (disp->oper) {
|
||||||
|
case OPER_WRITE_PROP:
|
||||||
|
/*
|
||||||
|
* Convert the arguments into a single binary value, then
|
||||||
|
* store them into the property.
|
||||||
|
*/
|
||||||
|
assert(arg_count >= 2);
|
||||||
|
if (disp->auto_path && create_paths(&blob, *arg))
|
||||||
|
return -1;
|
||||||
|
if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
|
||||||
|
store_key_value(&blob, *arg, arg[1], value, len))
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case OPER_CREATE_NODE:
|
||||||
|
for (; ret >= 0 && arg_count--; arg++) {
|
||||||
|
if (disp->auto_path)
|
||||||
|
ret = create_paths(&blob, *arg);
|
||||||
|
else
|
||||||
|
ret = create_node(&blob, *arg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPER_REMOVE_NODE:
|
||||||
|
for (; ret >= 0 && arg_count--; arg++)
|
||||||
|
ret = delete_node(blob, *arg);
|
||||||
|
break;
|
||||||
|
case OPER_DELETE_PROP:
|
||||||
|
node = *arg;
|
||||||
|
for (arg++; ret >= 0 && arg_count-- > 1; arg++)
|
||||||
|
ret = delete_prop(blob, node, *arg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret >= 0) {
|
||||||
|
fdt_pack(blob);
|
||||||
|
ret = utilfdt_write(filename, blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(blob);
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Usage related data. */
|
||||||
|
static const char usage_synopsis[] =
|
||||||
|
"write a property value to a device tree\n"
|
||||||
|
" fdtput <options> <dt file> <node> <property> [<value>...]\n"
|
||||||
|
" fdtput -c <options> <dt file> [<node>...]\n"
|
||||||
|
" fdtput -r <options> <dt file> [<node>...]\n"
|
||||||
|
" fdtput -d <options> <dt file> <node> [<property>...]\n"
|
||||||
|
"\n"
|
||||||
|
"The command line arguments are joined together into a single value.\n"
|
||||||
|
USAGE_TYPE_MSG;
|
||||||
|
static const char usage_short_opts[] = "crdpt:v" USAGE_COMMON_SHORT_OPTS;
|
||||||
|
static struct option const usage_long_opts[] = {
|
||||||
|
{"create", no_argument, NULL, 'c'},
|
||||||
|
{"remove", no_argument, NULL, 'r'},
|
||||||
|
{"delete", no_argument, NULL, 'd'},
|
||||||
|
{"auto-path", no_argument, NULL, 'p'},
|
||||||
|
{"type", a_argument, NULL, 't'},
|
||||||
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
|
USAGE_COMMON_LONG_OPTS,
|
||||||
|
};
|
||||||
|
static const char * const usage_opts_help[] = {
|
||||||
|
"Create nodes if they don't already exist",
|
||||||
|
"Delete nodes (and any subnodes) if they already exist",
|
||||||
|
"Delete properties if they already exist",
|
||||||
|
"Automatically create nodes as needed for the node path",
|
||||||
|
"Type of data",
|
||||||
|
"Display each value decoded from command line",
|
||||||
|
USAGE_COMMON_OPTS_HELP
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
struct display_info disp;
|
||||||
|
char *filename = NULL;
|
||||||
|
|
||||||
|
memset(&disp, '\0', sizeof(disp));
|
||||||
|
disp.size = -1;
|
||||||
|
disp.oper = OPER_WRITE_PROP;
|
||||||
|
while ((opt = util_getopt_long()) != EOF) {
|
||||||
|
/*
|
||||||
|
* TODO: add options to:
|
||||||
|
* - rename node
|
||||||
|
* - pack fdt before writing
|
||||||
|
* - set amount of free space when writing
|
||||||
|
*/
|
||||||
|
switch (opt) {
|
||||||
|
case_USAGE_COMMON_FLAGS
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
disp.oper = OPER_CREATE_NODE;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
disp.oper = OPER_REMOVE_NODE;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
disp.oper = OPER_DELETE_PROP;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
disp.auto_path = 1;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if (utilfdt_decode_type(optarg, &disp.type,
|
||||||
|
&disp.size))
|
||||||
|
usage("Invalid type string");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
disp.verbose = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
filename = argv[optind++];
|
||||||
|
if (!filename)
|
||||||
|
usage("missing filename");
|
||||||
|
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
if (disp.oper == OPER_WRITE_PROP) {
|
||||||
|
if (argc < 1)
|
||||||
|
usage("missing node");
|
||||||
|
if (argc < 2)
|
||||||
|
usage("missing property");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disp.oper == OPER_DELETE_PROP)
|
||||||
|
if (argc < 1)
|
||||||
|
usage("missing node");
|
||||||
|
|
||||||
|
if (do_fdtput(&disp, filename, argv, argc))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
940
dtc-1.4.5/flattree.c
Normal file
940
dtc-1.4.5/flattree.c
Normal file
@@ -0,0 +1,940 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dtc.h"
|
||||||
|
#include "srcpos.h"
|
||||||
|
|
||||||
|
#define FTF_FULLPATH 0x1
|
||||||
|
#define FTF_VARALIGN 0x2
|
||||||
|
#define FTF_NAMEPROPS 0x4
|
||||||
|
#define FTF_BOOTCPUID 0x8
|
||||||
|
#define FTF_STRTABSIZE 0x10
|
||||||
|
#define FTF_STRUCTSIZE 0x20
|
||||||
|
#define FTF_NOPS 0x40
|
||||||
|
|
||||||
|
static struct version_info {
|
||||||
|
int version;
|
||||||
|
int last_comp_version;
|
||||||
|
int hdr_size;
|
||||||
|
int flags;
|
||||||
|
} version_table[] = {
|
||||||
|
{1, 1, FDT_V1_SIZE,
|
||||||
|
FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
|
||||||
|
{2, 1, FDT_V2_SIZE,
|
||||||
|
FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
|
||||||
|
{3, 1, FDT_V3_SIZE,
|
||||||
|
FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
|
||||||
|
{16, 16, FDT_V3_SIZE,
|
||||||
|
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
|
||||||
|
{17, 16, FDT_V17_SIZE,
|
||||||
|
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct emitter {
|
||||||
|
void (*cell)(void *, cell_t);
|
||||||
|
void (*string)(void *, const char *, int);
|
||||||
|
void (*align)(void *, int);
|
||||||
|
void (*data)(void *, struct data);
|
||||||
|
void (*beginnode)(void *, struct label *labels);
|
||||||
|
void (*endnode)(void *, struct label *labels);
|
||||||
|
void (*property)(void *, struct label *labels);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void bin_emit_cell(void *e, cell_t val)
|
||||||
|
{
|
||||||
|
struct data *dtbuf = e;
|
||||||
|
|
||||||
|
*dtbuf = data_append_cell(*dtbuf, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bin_emit_string(void *e, const char *str, int len)
|
||||||
|
{
|
||||||
|
struct data *dtbuf = e;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
len = strlen(str);
|
||||||
|
|
||||||
|
*dtbuf = data_append_data(*dtbuf, str, len);
|
||||||
|
*dtbuf = data_append_byte(*dtbuf, '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bin_emit_align(void *e, int a)
|
||||||
|
{
|
||||||
|
struct data *dtbuf = e;
|
||||||
|
|
||||||
|
*dtbuf = data_append_align(*dtbuf, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bin_emit_data(void *e, struct data d)
|
||||||
|
{
|
||||||
|
struct data *dtbuf = e;
|
||||||
|
|
||||||
|
*dtbuf = data_append_data(*dtbuf, d.val, d.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bin_emit_beginnode(void *e, struct label *labels)
|
||||||
|
{
|
||||||
|
bin_emit_cell(e, FDT_BEGIN_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bin_emit_endnode(void *e, struct label *labels)
|
||||||
|
{
|
||||||
|
bin_emit_cell(e, FDT_END_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bin_emit_property(void *e, struct label *labels)
|
||||||
|
{
|
||||||
|
bin_emit_cell(e, FDT_PROP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct emitter bin_emitter = {
|
||||||
|
.cell = bin_emit_cell,
|
||||||
|
.string = bin_emit_string,
|
||||||
|
.align = bin_emit_align,
|
||||||
|
.data = bin_emit_data,
|
||||||
|
.beginnode = bin_emit_beginnode,
|
||||||
|
.endnode = bin_emit_endnode,
|
||||||
|
.property = bin_emit_property,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void emit_label(FILE *f, const char *prefix, const char *label)
|
||||||
|
{
|
||||||
|
fprintf(f, "\t.globl\t%s_%s\n", prefix, label);
|
||||||
|
fprintf(f, "%s_%s:\n", prefix, label);
|
||||||
|
fprintf(f, "_%s_%s:\n", prefix, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_offset_label(FILE *f, const char *label, int offset)
|
||||||
|
{
|
||||||
|
fprintf(f, "\t.globl\t%s\n", label);
|
||||||
|
fprintf(f, "%s\t= . + %d\n", label, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASM_EMIT_BELONG(f, fmt, ...) \
|
||||||
|
{ \
|
||||||
|
fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
|
||||||
|
fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
|
||||||
|
fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
|
||||||
|
fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_emit_cell(void *e, cell_t val)
|
||||||
|
{
|
||||||
|
FILE *f = e;
|
||||||
|
|
||||||
|
fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
|
||||||
|
(val >> 24) & 0xff, (val >> 16) & 0xff,
|
||||||
|
(val >> 8) & 0xff, val & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_emit_string(void *e, const char *str, int len)
|
||||||
|
{
|
||||||
|
FILE *f = e;
|
||||||
|
|
||||||
|
if (len != 0)
|
||||||
|
fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
|
||||||
|
else
|
||||||
|
fprintf(f, "\t.string\t\"%s\"\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_emit_align(void *e, int a)
|
||||||
|
{
|
||||||
|
FILE *f = e;
|
||||||
|
|
||||||
|
fprintf(f, "\t.balign\t%d, 0\n", a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_emit_data(void *e, struct data d)
|
||||||
|
{
|
||||||
|
FILE *f = e;
|
||||||
|
int off = 0;
|
||||||
|
struct marker *m = d.markers;
|
||||||
|
|
||||||
|
for_each_marker_of_type(m, LABEL)
|
||||||
|
emit_offset_label(f, m->ref, m->offset);
|
||||||
|
|
||||||
|
while ((d.len - off) >= sizeof(uint32_t)) {
|
||||||
|
asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
|
||||||
|
off += sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((d.len - off) >= 1) {
|
||||||
|
fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
|
||||||
|
off += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(off == d.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_emit_beginnode(void *e, struct label *labels)
|
||||||
|
{
|
||||||
|
FILE *f = e;
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
for_each_label(labels, l) {
|
||||||
|
fprintf(f, "\t.globl\t%s\n", l->label);
|
||||||
|
fprintf(f, "%s:\n", l->label);
|
||||||
|
}
|
||||||
|
fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
|
||||||
|
asm_emit_cell(e, FDT_BEGIN_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_emit_endnode(void *e, struct label *labels)
|
||||||
|
{
|
||||||
|
FILE *f = e;
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
fprintf(f, "\t/* FDT_END_NODE */\n");
|
||||||
|
asm_emit_cell(e, FDT_END_NODE);
|
||||||
|
for_each_label(labels, l) {
|
||||||
|
fprintf(f, "\t.globl\t%s_end\n", l->label);
|
||||||
|
fprintf(f, "%s_end:\n", l->label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asm_emit_property(void *e, struct label *labels)
|
||||||
|
{
|
||||||
|
FILE *f = e;
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
for_each_label(labels, l) {
|
||||||
|
fprintf(f, "\t.globl\t%s\n", l->label);
|
||||||
|
fprintf(f, "%s:\n", l->label);
|
||||||
|
}
|
||||||
|
fprintf(f, "\t/* FDT_PROP */\n");
|
||||||
|
asm_emit_cell(e, FDT_PROP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct emitter asm_emitter = {
|
||||||
|
.cell = asm_emit_cell,
|
||||||
|
.string = asm_emit_string,
|
||||||
|
.align = asm_emit_align,
|
||||||
|
.data = asm_emit_data,
|
||||||
|
.beginnode = asm_emit_beginnode,
|
||||||
|
.endnode = asm_emit_endnode,
|
||||||
|
.property = asm_emit_property,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int stringtable_insert(struct data *d, const char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* FIXME: do this more efficiently? */
|
||||||
|
|
||||||
|
for (i = 0; i < d->len; i++) {
|
||||||
|
if (streq(str, d->val + i))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
*d = data_append_data(*d, str, strlen(str)+1);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||||
|
void *etarget, struct data *strbuf,
|
||||||
|
struct version_info *vi)
|
||||||
|
{
|
||||||
|
struct property *prop;
|
||||||
|
struct node *child;
|
||||||
|
bool seen_name_prop = false;
|
||||||
|
|
||||||
|
if (tree->deleted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
emit->beginnode(etarget, tree->labels);
|
||||||
|
|
||||||
|
if (vi->flags & FTF_FULLPATH)
|
||||||
|
emit->string(etarget, tree->fullpath, 0);
|
||||||
|
else
|
||||||
|
emit->string(etarget, tree->name, 0);
|
||||||
|
|
||||||
|
emit->align(etarget, sizeof(cell_t));
|
||||||
|
|
||||||
|
for_each_property(tree, prop) {
|
||||||
|
int nameoff;
|
||||||
|
|
||||||
|
if (streq(prop->name, "name"))
|
||||||
|
seen_name_prop = true;
|
||||||
|
|
||||||
|
nameoff = stringtable_insert(strbuf, prop->name);
|
||||||
|
|
||||||
|
emit->property(etarget, prop->labels);
|
||||||
|
emit->cell(etarget, prop->val.len);
|
||||||
|
emit->cell(etarget, nameoff);
|
||||||
|
|
||||||
|
if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
|
||||||
|
emit->align(etarget, 8);
|
||||||
|
|
||||||
|
emit->data(etarget, prop->val);
|
||||||
|
emit->align(etarget, sizeof(cell_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
|
||||||
|
emit->property(etarget, NULL);
|
||||||
|
emit->cell(etarget, tree->basenamelen+1);
|
||||||
|
emit->cell(etarget, stringtable_insert(strbuf, "name"));
|
||||||
|
|
||||||
|
if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
|
||||||
|
emit->align(etarget, 8);
|
||||||
|
|
||||||
|
emit->string(etarget, tree->name, tree->basenamelen);
|
||||||
|
emit->align(etarget, sizeof(cell_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(tree, child) {
|
||||||
|
flatten_tree(child, emit, etarget, strbuf, vi);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit->endnode(etarget, tree->labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct data flatten_reserve_list(struct reserve_info *reservelist,
|
||||||
|
struct version_info *vi)
|
||||||
|
{
|
||||||
|
struct reserve_info *re;
|
||||||
|
struct data d = empty_data;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (re = reservelist; re; re = re->next) {
|
||||||
|
d = data_append_re(d, re->address, re->size);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Add additional reserved slots if the user asked for them.
|
||||||
|
*/
|
||||||
|
for (j = 0; j < reservenum; j++) {
|
||||||
|
d = data_append_re(d, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void make_fdt_header(struct fdt_header *fdt,
|
||||||
|
struct version_info *vi,
|
||||||
|
int reservesize, int dtsize, int strsize,
|
||||||
|
int boot_cpuid_phys)
|
||||||
|
{
|
||||||
|
int reserve_off;
|
||||||
|
|
||||||
|
reservesize += sizeof(struct fdt_reserve_entry);
|
||||||
|
|
||||||
|
memset(fdt, 0xff, sizeof(*fdt));
|
||||||
|
|
||||||
|
fdt->magic = cpu_to_fdt32(FDT_MAGIC);
|
||||||
|
fdt->version = cpu_to_fdt32(vi->version);
|
||||||
|
fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
|
||||||
|
|
||||||
|
/* Reserve map should be doubleword aligned */
|
||||||
|
reserve_off = ALIGN(vi->hdr_size, 8);
|
||||||
|
|
||||||
|
fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
|
||||||
|
fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
|
||||||
|
fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
|
||||||
|
+ dtsize);
|
||||||
|
fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
|
||||||
|
|
||||||
|
if (vi->flags & FTF_BOOTCPUID)
|
||||||
|
fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
|
||||||
|
if (vi->flags & FTF_STRTABSIZE)
|
||||||
|
fdt->size_dt_strings = cpu_to_fdt32(strsize);
|
||||||
|
if (vi->flags & FTF_STRUCTSIZE)
|
||||||
|
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
|
||||||
|
{
|
||||||
|
struct version_info *vi = NULL;
|
||||||
|
int i;
|
||||||
|
struct data blob = empty_data;
|
||||||
|
struct data reservebuf = empty_data;
|
||||||
|
struct data dtbuf = empty_data;
|
||||||
|
struct data strbuf = empty_data;
|
||||||
|
struct fdt_header fdt;
|
||||||
|
int padlen = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
|
||||||
|
if (version_table[i].version == version)
|
||||||
|
vi = &version_table[i];
|
||||||
|
}
|
||||||
|
if (!vi)
|
||||||
|
die("Unknown device tree blob version %d\n", version);
|
||||||
|
|
||||||
|
flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
|
||||||
|
bin_emit_cell(&dtbuf, FDT_END);
|
||||||
|
|
||||||
|
reservebuf = flatten_reserve_list(dti->reservelist, vi);
|
||||||
|
|
||||||
|
/* Make header */
|
||||||
|
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
|
||||||
|
dti->boot_cpuid_phys);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user asked for more space than is used, adjust the totalsize.
|
||||||
|
*/
|
||||||
|
if (minsize > 0) {
|
||||||
|
padlen = minsize - fdt32_to_cpu(fdt.totalsize);
|
||||||
|
if (padlen < 0) {
|
||||||
|
padlen = 0;
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: blob size %d >= minimum size %d\n",
|
||||||
|
fdt32_to_cpu(fdt.totalsize), minsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (padsize > 0)
|
||||||
|
padlen = padsize;
|
||||||
|
|
||||||
|
if (alignsize > 0)
|
||||||
|
padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
|
||||||
|
- fdt32_to_cpu(fdt.totalsize);
|
||||||
|
|
||||||
|
if (padlen > 0) {
|
||||||
|
int tsize = fdt32_to_cpu(fdt.totalsize);
|
||||||
|
tsize += padlen;
|
||||||
|
fdt.totalsize = cpu_to_fdt32(tsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assemble the blob: start with the header, add with alignment
|
||||||
|
* the reserve buffer, add the reserve map terminating zeroes,
|
||||||
|
* the device tree itself, and finally the strings.
|
||||||
|
*/
|
||||||
|
blob = data_append_data(blob, &fdt, vi->hdr_size);
|
||||||
|
blob = data_append_align(blob, 8);
|
||||||
|
blob = data_merge(blob, reservebuf);
|
||||||
|
blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
|
||||||
|
blob = data_merge(blob, dtbuf);
|
||||||
|
blob = data_merge(blob, strbuf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user asked for more space than is used, pad out the blob.
|
||||||
|
*/
|
||||||
|
if (padlen > 0)
|
||||||
|
blob = data_append_zeroes(blob, padlen);
|
||||||
|
|
||||||
|
if (fwrite(blob.val, blob.len, 1, f) != 1) {
|
||||||
|
if (ferror(f))
|
||||||
|
die("Error writing device tree blob: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
else
|
||||||
|
die("Short write on device tree blob\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* data_merge() frees the right-hand element so only the blob
|
||||||
|
* remains to be freed.
|
||||||
|
*/
|
||||||
|
data_free(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_stringtable_asm(FILE *f, struct data strbuf)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
p = strbuf.val;
|
||||||
|
|
||||||
|
while (p < (strbuf.val + strbuf.len)) {
|
||||||
|
len = strlen(p);
|
||||||
|
fprintf(f, "\t.string \"%s\"\n", p);
|
||||||
|
p += len+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dt_to_asm(FILE *f, struct dt_info *dti, int version)
|
||||||
|
{
|
||||||
|
struct version_info *vi = NULL;
|
||||||
|
int i;
|
||||||
|
struct data strbuf = empty_data;
|
||||||
|
struct reserve_info *re;
|
||||||
|
const char *symprefix = "dt";
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
|
||||||
|
if (version_table[i].version == version)
|
||||||
|
vi = &version_table[i];
|
||||||
|
}
|
||||||
|
if (!vi)
|
||||||
|
die("Unknown device tree blob version %d\n", version);
|
||||||
|
|
||||||
|
fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
|
||||||
|
|
||||||
|
emit_label(f, symprefix, "blob_start");
|
||||||
|
emit_label(f, symprefix, "header");
|
||||||
|
fprintf(f, "\t/* magic */\n");
|
||||||
|
asm_emit_cell(f, FDT_MAGIC);
|
||||||
|
fprintf(f, "\t/* totalsize */\n");
|
||||||
|
ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
|
||||||
|
symprefix, symprefix);
|
||||||
|
fprintf(f, "\t/* off_dt_struct */\n");
|
||||||
|
ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
|
||||||
|
symprefix, symprefix);
|
||||||
|
fprintf(f, "\t/* off_dt_strings */\n");
|
||||||
|
ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
|
||||||
|
symprefix, symprefix);
|
||||||
|
fprintf(f, "\t/* off_mem_rsvmap */\n");
|
||||||
|
ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
|
||||||
|
symprefix, symprefix);
|
||||||
|
fprintf(f, "\t/* version */\n");
|
||||||
|
asm_emit_cell(f, vi->version);
|
||||||
|
fprintf(f, "\t/* last_comp_version */\n");
|
||||||
|
asm_emit_cell(f, vi->last_comp_version);
|
||||||
|
|
||||||
|
if (vi->flags & FTF_BOOTCPUID) {
|
||||||
|
fprintf(f, "\t/* boot_cpuid_phys */\n");
|
||||||
|
asm_emit_cell(f, dti->boot_cpuid_phys);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vi->flags & FTF_STRTABSIZE) {
|
||||||
|
fprintf(f, "\t/* size_dt_strings */\n");
|
||||||
|
ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
|
||||||
|
symprefix, symprefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vi->flags & FTF_STRUCTSIZE) {
|
||||||
|
fprintf(f, "\t/* size_dt_struct */\n");
|
||||||
|
ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
|
||||||
|
symprefix, symprefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserve map entries.
|
||||||
|
* Align the reserve map to a doubleword boundary.
|
||||||
|
* Each entry is an (address, size) pair of u64 values.
|
||||||
|
* Always supply a zero-sized temination entry.
|
||||||
|
*/
|
||||||
|
asm_emit_align(f, 8);
|
||||||
|
emit_label(f, symprefix, "reserve_map");
|
||||||
|
|
||||||
|
fprintf(f, "/* Memory reserve map from source file */\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use .long on high and low halfs of u64s to avoid .quad
|
||||||
|
* as it appears .quad isn't available in some assemblers.
|
||||||
|
*/
|
||||||
|
for (re = dti->reservelist; re; re = re->next) {
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
for_each_label(re->labels, l) {
|
||||||
|
fprintf(f, "\t.globl\t%s\n", l->label);
|
||||||
|
fprintf(f, "%s:\n", l->label);
|
||||||
|
}
|
||||||
|
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->address >> 32));
|
||||||
|
ASM_EMIT_BELONG(f, "0x%08x",
|
||||||
|
(unsigned int)(re->address & 0xffffffff));
|
||||||
|
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size >> 32));
|
||||||
|
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size & 0xffffffff));
|
||||||
|
}
|
||||||
|
for (i = 0; i < reservenum; i++) {
|
||||||
|
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
|
||||||
|
|
||||||
|
emit_label(f, symprefix, "struct_start");
|
||||||
|
flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
|
||||||
|
|
||||||
|
fprintf(f, "\t/* FDT_END */\n");
|
||||||
|
asm_emit_cell(f, FDT_END);
|
||||||
|
emit_label(f, symprefix, "struct_end");
|
||||||
|
|
||||||
|
emit_label(f, symprefix, "strings_start");
|
||||||
|
dump_stringtable_asm(f, strbuf);
|
||||||
|
emit_label(f, symprefix, "strings_end");
|
||||||
|
|
||||||
|
emit_label(f, symprefix, "blob_end");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user asked for more space than is used, pad it out.
|
||||||
|
*/
|
||||||
|
if (minsize > 0) {
|
||||||
|
fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
|
||||||
|
minsize, symprefix, symprefix);
|
||||||
|
}
|
||||||
|
if (padsize > 0) {
|
||||||
|
fprintf(f, "\t.space\t%d, 0\n", padsize);
|
||||||
|
}
|
||||||
|
if (alignsize > 0)
|
||||||
|
asm_emit_align(f, alignsize);
|
||||||
|
emit_label(f, symprefix, "blob_abs_end");
|
||||||
|
|
||||||
|
data_free(strbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct inbuf {
|
||||||
|
char *base, *limit, *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void inbuf_init(struct inbuf *inb, void *base, void *limit)
|
||||||
|
{
|
||||||
|
inb->base = base;
|
||||||
|
inb->limit = limit;
|
||||||
|
inb->ptr = inb->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flat_read_chunk(struct inbuf *inb, void *p, int len)
|
||||||
|
{
|
||||||
|
if ((inb->ptr + len) > inb->limit)
|
||||||
|
die("Premature end of data parsing flat device tree\n");
|
||||||
|
|
||||||
|
memcpy(p, inb->ptr, len);
|
||||||
|
|
||||||
|
inb->ptr += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t flat_read_word(struct inbuf *inb)
|
||||||
|
{
|
||||||
|
fdt32_t val;
|
||||||
|
|
||||||
|
assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
|
||||||
|
|
||||||
|
flat_read_chunk(inb, &val, sizeof(val));
|
||||||
|
|
||||||
|
return fdt32_to_cpu(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flat_realign(struct inbuf *inb, int align)
|
||||||
|
{
|
||||||
|
int off = inb->ptr - inb->base;
|
||||||
|
|
||||||
|
inb->ptr = inb->base + ALIGN(off, align);
|
||||||
|
if (inb->ptr > inb->limit)
|
||||||
|
die("Premature end of data parsing flat device tree\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *flat_read_string(struct inbuf *inb)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
const char *p = inb->ptr;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (p >= inb->limit)
|
||||||
|
die("Premature end of data parsing flat device tree\n");
|
||||||
|
len++;
|
||||||
|
} while ((*p++) != '\0');
|
||||||
|
|
||||||
|
str = xstrdup(inb->ptr);
|
||||||
|
|
||||||
|
inb->ptr += len;
|
||||||
|
|
||||||
|
flat_realign(inb, sizeof(uint32_t));
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct data flat_read_data(struct inbuf *inb, int len)
|
||||||
|
{
|
||||||
|
struct data d = empty_data;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return empty_data;
|
||||||
|
|
||||||
|
d = data_grow_for(d, len);
|
||||||
|
d.len = len;
|
||||||
|
|
||||||
|
flat_read_chunk(inb, d.val, len);
|
||||||
|
|
||||||
|
flat_realign(inb, sizeof(uint32_t));
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *flat_read_stringtable(struct inbuf *inb, int offset)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
p = inb->base + offset;
|
||||||
|
while (1) {
|
||||||
|
if (p >= inb->limit || p < inb->base)
|
||||||
|
die("String offset %d overruns string table\n",
|
||||||
|
offset);
|
||||||
|
|
||||||
|
if (*p == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xstrdup(inb->base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct property *flat_read_property(struct inbuf *dtbuf,
|
||||||
|
struct inbuf *strbuf, int flags)
|
||||||
|
{
|
||||||
|
uint32_t proplen, stroff;
|
||||||
|
char *name;
|
||||||
|
struct data val;
|
||||||
|
|
||||||
|
proplen = flat_read_word(dtbuf);
|
||||||
|
stroff = flat_read_word(dtbuf);
|
||||||
|
|
||||||
|
name = flat_read_stringtable(strbuf, stroff);
|
||||||
|
|
||||||
|
if ((flags & FTF_VARALIGN) && (proplen >= 8))
|
||||||
|
flat_realign(dtbuf, 8);
|
||||||
|
|
||||||
|
val = flat_read_data(dtbuf, proplen);
|
||||||
|
|
||||||
|
return build_property(name, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
|
||||||
|
{
|
||||||
|
struct reserve_info *reservelist = NULL;
|
||||||
|
struct reserve_info *new;
|
||||||
|
struct fdt_reserve_entry re;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
|
||||||
|
* List terminates at an entry with size equal to zero.
|
||||||
|
*
|
||||||
|
* First pass, count entries.
|
||||||
|
*/
|
||||||
|
while (1) {
|
||||||
|
uint64_t address, size;
|
||||||
|
|
||||||
|
flat_read_chunk(inb, &re, sizeof(re));
|
||||||
|
address = fdt64_to_cpu(re.address);
|
||||||
|
size = fdt64_to_cpu(re.size);
|
||||||
|
if (size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
new = build_reserve_entry(address, size);
|
||||||
|
reservelist = add_reserve_entry(reservelist, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reservelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *nodename_from_path(const char *ppath, const char *cpath)
|
||||||
|
{
|
||||||
|
int plen;
|
||||||
|
|
||||||
|
plen = strlen(ppath);
|
||||||
|
|
||||||
|
if (!strneq(ppath, cpath, plen))
|
||||||
|
die("Path \"%s\" is not valid as a child of \"%s\"\n",
|
||||||
|
cpath, ppath);
|
||||||
|
|
||||||
|
/* root node is a special case */
|
||||||
|
if (!streq(ppath, "/"))
|
||||||
|
plen++;
|
||||||
|
|
||||||
|
return xstrdup(cpath + plen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct node *unflatten_tree(struct inbuf *dtbuf,
|
||||||
|
struct inbuf *strbuf,
|
||||||
|
const char *parent_flatname, int flags)
|
||||||
|
{
|
||||||
|
struct node *node;
|
||||||
|
char *flatname;
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
node = build_node(NULL, NULL);
|
||||||
|
|
||||||
|
flatname = flat_read_string(dtbuf);
|
||||||
|
|
||||||
|
if (flags & FTF_FULLPATH)
|
||||||
|
node->name = nodename_from_path(parent_flatname, flatname);
|
||||||
|
else
|
||||||
|
node->name = flatname;
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct property *prop;
|
||||||
|
struct node *child;
|
||||||
|
|
||||||
|
val = flat_read_word(dtbuf);
|
||||||
|
switch (val) {
|
||||||
|
case FDT_PROP:
|
||||||
|
if (node->children)
|
||||||
|
fprintf(stderr, "Warning: Flat tree input has "
|
||||||
|
"subnodes preceding a property.\n");
|
||||||
|
prop = flat_read_property(dtbuf, strbuf, flags);
|
||||||
|
add_property(node, prop);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
child = unflatten_tree(dtbuf,strbuf, flatname, flags);
|
||||||
|
add_child(node, child);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_END_NODE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_END:
|
||||||
|
die("Premature FDT_END in device tree blob\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_NOP:
|
||||||
|
if (!(flags & FTF_NOPS))
|
||||||
|
fprintf(stderr, "Warning: NOP tag found in flat tree"
|
||||||
|
" version <16\n");
|
||||||
|
|
||||||
|
/* Ignore */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
die("Invalid opcode word %08x in device tree blob\n",
|
||||||
|
val);
|
||||||
|
}
|
||||||
|
} while (val != FDT_END_NODE);
|
||||||
|
|
||||||
|
if (node->name != flatname) {
|
||||||
|
free(flatname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct dt_info *dt_from_blob(const char *fname)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
fdt32_t magic_buf, totalsize_buf;
|
||||||
|
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
|
||||||
|
uint32_t off_dt, off_str, off_mem_rsvmap;
|
||||||
|
int rc;
|
||||||
|
char *blob;
|
||||||
|
struct fdt_header *fdt;
|
||||||
|
char *p;
|
||||||
|
struct inbuf dtbuf, strbuf;
|
||||||
|
struct inbuf memresvbuf;
|
||||||
|
int sizeleft;
|
||||||
|
struct reserve_info *reservelist;
|
||||||
|
struct node *tree;
|
||||||
|
uint32_t val;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
f = srcfile_relative_open(fname, NULL);
|
||||||
|
|
||||||
|
rc = fread(&magic_buf, sizeof(magic_buf), 1, f);
|
||||||
|
if (ferror(f))
|
||||||
|
die("Error reading DT blob magic number: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
if (rc < 1) {
|
||||||
|
if (feof(f))
|
||||||
|
die("EOF reading DT blob magic number\n");
|
||||||
|
else
|
||||||
|
die("Mysterious short read reading magic number\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
magic = fdt32_to_cpu(magic_buf);
|
||||||
|
if (magic != FDT_MAGIC)
|
||||||
|
die("Blob has incorrect magic number\n");
|
||||||
|
|
||||||
|
rc = fread(&totalsize_buf, sizeof(totalsize_buf), 1, f);
|
||||||
|
if (ferror(f))
|
||||||
|
die("Error reading DT blob size: %s\n", strerror(errno));
|
||||||
|
if (rc < 1) {
|
||||||
|
if (feof(f))
|
||||||
|
die("EOF reading DT blob size\n");
|
||||||
|
else
|
||||||
|
die("Mysterious short read reading blob size\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
totalsize = fdt32_to_cpu(totalsize_buf);
|
||||||
|
if (totalsize < FDT_V1_SIZE)
|
||||||
|
die("DT blob size (%d) is too small\n", totalsize);
|
||||||
|
|
||||||
|
blob = xmalloc(totalsize);
|
||||||
|
|
||||||
|
fdt = (struct fdt_header *)blob;
|
||||||
|
fdt->magic = cpu_to_fdt32(magic);
|
||||||
|
fdt->totalsize = cpu_to_fdt32(totalsize);
|
||||||
|
|
||||||
|
sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
|
||||||
|
p = blob + sizeof(magic) + sizeof(totalsize);
|
||||||
|
|
||||||
|
while (sizeleft) {
|
||||||
|
if (feof(f))
|
||||||
|
die("EOF before reading %d bytes of DT blob\n",
|
||||||
|
totalsize);
|
||||||
|
|
||||||
|
rc = fread(p, 1, sizeleft, f);
|
||||||
|
if (ferror(f))
|
||||||
|
die("Error reading DT blob: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
sizeleft -= rc;
|
||||||
|
p += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_dt = fdt32_to_cpu(fdt->off_dt_struct);
|
||||||
|
off_str = fdt32_to_cpu(fdt->off_dt_strings);
|
||||||
|
off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
|
||||||
|
version = fdt32_to_cpu(fdt->version);
|
||||||
|
boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
|
||||||
|
|
||||||
|
if (off_mem_rsvmap >= totalsize)
|
||||||
|
die("Mem Reserve structure offset exceeds total size\n");
|
||||||
|
|
||||||
|
if (off_dt >= totalsize)
|
||||||
|
die("DT structure offset exceeds total size\n");
|
||||||
|
|
||||||
|
if (off_str > totalsize)
|
||||||
|
die("String table offset exceeds total size\n");
|
||||||
|
|
||||||
|
if (version >= 3) {
|
||||||
|
uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
|
||||||
|
if ((off_str+size_str < off_str) || (off_str+size_str > totalsize))
|
||||||
|
die("String table extends past total size\n");
|
||||||
|
inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
|
||||||
|
} else {
|
||||||
|
inbuf_init(&strbuf, blob + off_str, blob + totalsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version >= 17) {
|
||||||
|
size_dt = fdt32_to_cpu(fdt->size_dt_struct);
|
||||||
|
if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize))
|
||||||
|
die("Structure block extends past total size\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version < 16) {
|
||||||
|
flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
|
||||||
|
} else {
|
||||||
|
flags |= FTF_NOPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
inbuf_init(&memresvbuf,
|
||||||
|
blob + off_mem_rsvmap, blob + totalsize);
|
||||||
|
inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
|
||||||
|
|
||||||
|
reservelist = flat_read_mem_reserve(&memresvbuf);
|
||||||
|
|
||||||
|
val = flat_read_word(&dtbuf);
|
||||||
|
|
||||||
|
if (val != FDT_BEGIN_NODE)
|
||||||
|
die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
|
||||||
|
|
||||||
|
tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
|
||||||
|
|
||||||
|
val = flat_read_word(&dtbuf);
|
||||||
|
if (val != FDT_END)
|
||||||
|
die("Device tree blob doesn't end with FDT_END\n");
|
||||||
|
|
||||||
|
free(blob);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
|
||||||
|
}
|
||||||
90
dtc-1.4.5/fstree.c
Normal file
90
dtc-1.4.5/fstree.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dtc.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
static struct node *read_fstree(const char *dirname)
|
||||||
|
{
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *de;
|
||||||
|
struct stat st;
|
||||||
|
struct node *tree;
|
||||||
|
|
||||||
|
d = opendir(dirname);
|
||||||
|
if (!d)
|
||||||
|
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
|
||||||
|
|
||||||
|
tree = build_node(NULL, NULL);
|
||||||
|
|
||||||
|
while ((de = readdir(d)) != NULL) {
|
||||||
|
char *tmpname;
|
||||||
|
|
||||||
|
if (streq(de->d_name, ".")
|
||||||
|
|| streq(de->d_name, ".."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tmpname = join_path(dirname, de->d_name);
|
||||||
|
|
||||||
|
if (lstat(tmpname, &st) < 0)
|
||||||
|
die("stat(%s): %s\n", tmpname, strerror(errno));
|
||||||
|
|
||||||
|
if (S_ISREG(st.st_mode)) {
|
||||||
|
struct property *prop;
|
||||||
|
FILE *pfile;
|
||||||
|
|
||||||
|
pfile = fopen(tmpname, "rb");
|
||||||
|
if (! pfile) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: Cannot open %s: %s\n",
|
||||||
|
tmpname, strerror(errno));
|
||||||
|
} else {
|
||||||
|
prop = build_property(xstrdup(de->d_name),
|
||||||
|
data_copy_file(pfile,
|
||||||
|
st.st_size));
|
||||||
|
add_property(tree, prop);
|
||||||
|
fclose(pfile);
|
||||||
|
}
|
||||||
|
} else if (S_ISDIR(st.st_mode)) {
|
||||||
|
struct node *newchild;
|
||||||
|
|
||||||
|
newchild = read_fstree(tmpname);
|
||||||
|
newchild = name_node(newchild, xstrdup(de->d_name));
|
||||||
|
add_child(tree, newchild);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmpname);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(d);
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dt_info *dt_from_fs(const char *dirname)
|
||||||
|
{
|
||||||
|
struct node *tree;
|
||||||
|
|
||||||
|
tree = read_fstree(dirname);
|
||||||
|
tree = name_node(tree, "");
|
||||||
|
|
||||||
|
return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
|
||||||
|
}
|
||||||
11
dtc-1.4.5/libfdt/Makefile.libfdt
Normal file
11
dtc-1.4.5/libfdt/Makefile.libfdt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Makefile.libfdt
|
||||||
|
#
|
||||||
|
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||||
|
# be easily embeddable into other systems of Makefiles.
|
||||||
|
#
|
||||||
|
LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
|
||||||
|
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
|
||||||
|
LIBFDT_VERSION = version.lds
|
||||||
|
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
|
||||||
|
fdt_addresses.c fdt_overlay.c
|
||||||
|
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
|
||||||
3
dtc-1.4.5/libfdt/TODO
Normal file
3
dtc-1.4.5/libfdt/TODO
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
- Tree traversal functions
|
||||||
|
- Graft function
|
||||||
|
- Complete libfdt.h documenting comments
|
||||||
251
dtc-1.4.5/libfdt/fdt.c
Normal file
251
dtc-1.4.5/libfdt/fdt.c
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
int fdt_check_header(const void *fdt)
|
||||||
|
{
|
||||||
|
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||||
|
/* Complete tree */
|
||||||
|
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||||
|
return -FDT_ERR_BADVERSION;
|
||||||
|
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
|
||||||
|
return -FDT_ERR_BADVERSION;
|
||||||
|
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||||
|
/* Unfinished sequential-write blob */
|
||||||
|
if (fdt_size_dt_struct(fdt) == 0)
|
||||||
|
return -FDT_ERR_BADSTATE;
|
||||||
|
} else {
|
||||||
|
return -FDT_ERR_BADMAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
|
||||||
|
|
||||||
|
if ((absoffset < offset)
|
||||||
|
|| ((absoffset + len) < absoffset)
|
||||||
|
|| (absoffset + len) > fdt_totalsize(fdt))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fdt_version(fdt) >= 0x11)
|
||||||
|
if (((offset + len) < offset)
|
||||||
|
|| ((offset + len) > fdt_size_dt_struct(fdt)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return _fdt_offset_ptr(fdt, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||||
|
{
|
||||||
|
const fdt32_t *tagp, *lenp;
|
||||||
|
uint32_t tag;
|
||||||
|
int offset = startoffset;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
*nextoffset = -FDT_ERR_TRUNCATED;
|
||||||
|
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
|
||||||
|
if (!tagp)
|
||||||
|
return FDT_END; /* premature end */
|
||||||
|
tag = fdt32_to_cpu(*tagp);
|
||||||
|
offset += FDT_TAGSIZE;
|
||||||
|
|
||||||
|
*nextoffset = -FDT_ERR_BADSTRUCTURE;
|
||||||
|
switch (tag) {
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
/* skip name */
|
||||||
|
do {
|
||||||
|
p = fdt_offset_ptr(fdt, offset++, 1);
|
||||||
|
} while (p && (*p != '\0'));
|
||||||
|
if (!p)
|
||||||
|
return FDT_END; /* premature end */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_PROP:
|
||||||
|
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
|
||||||
|
if (!lenp)
|
||||||
|
return FDT_END; /* premature end */
|
||||||
|
/* skip-name offset, length and value */
|
||||||
|
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
|
||||||
|
+ fdt32_to_cpu(*lenp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_END:
|
||||||
|
case FDT_END_NODE:
|
||||||
|
case FDT_NOP:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FDT_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
|
||||||
|
return FDT_END; /* premature end */
|
||||||
|
|
||||||
|
*nextoffset = FDT_TAGALIGN(offset);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fdt_check_node_offset(const void *fdt, int offset)
|
||||||
|
{
|
||||||
|
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||||
|
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fdt_check_prop_offset(const void *fdt, int offset)
|
||||||
|
{
|
||||||
|
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||||
|
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_next_node(const void *fdt, int offset, int *depth)
|
||||||
|
{
|
||||||
|
int nextoffset = 0;
|
||||||
|
uint32_t tag;
|
||||||
|
|
||||||
|
if (offset >= 0)
|
||||||
|
if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
|
||||||
|
return nextoffset;
|
||||||
|
|
||||||
|
do {
|
||||||
|
offset = nextoffset;
|
||||||
|
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case FDT_PROP:
|
||||||
|
case FDT_NOP:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
if (depth)
|
||||||
|
(*depth)++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_END_NODE:
|
||||||
|
if (depth && ((--(*depth)) < 0))
|
||||||
|
return nextoffset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_END:
|
||||||
|
if ((nextoffset >= 0)
|
||||||
|
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
else
|
||||||
|
return nextoffset;
|
||||||
|
}
|
||||||
|
} while (tag != FDT_BEGIN_NODE);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_first_subnode(const void *fdt, int offset)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
offset = fdt_next_node(fdt, offset, &depth);
|
||||||
|
if (offset < 0 || depth != 1)
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_next_subnode(const void *fdt, int offset)
|
||||||
|
{
|
||||||
|
int depth = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With respect to the parent, the depth of the next subnode will be
|
||||||
|
* the same as the last.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
offset = fdt_next_node(fdt, offset, &depth);
|
||||||
|
if (offset < 0 || depth < 1)
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
} while (depth > 1);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
|
||||||
|
{
|
||||||
|
int len = strlen(s) + 1;
|
||||||
|
const char *last = strtab + tabsize - len;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
for (p = strtab; p <= last; p++)
|
||||||
|
if (memcmp(p, s, len) == 0)
|
||||||
|
return p;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_move(const void *fdt, void *buf, int bufsize)
|
||||||
|
{
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
if (fdt_totalsize(fdt) > bufsize)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
memmove(buf, fdt, fdt_totalsize(fdt));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
111
dtc-1.4.5/libfdt/fdt.h
Normal file
111
dtc-1.4.5/libfdt/fdt.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#ifndef _FDT_H
|
||||||
|
#define _FDT_H
|
||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
struct fdt_header {
|
||||||
|
fdt32_t magic; /* magic word FDT_MAGIC */
|
||||||
|
fdt32_t totalsize; /* total size of DT block */
|
||||||
|
fdt32_t off_dt_struct; /* offset to structure */
|
||||||
|
fdt32_t off_dt_strings; /* offset to strings */
|
||||||
|
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
|
||||||
|
fdt32_t version; /* format version */
|
||||||
|
fdt32_t last_comp_version; /* last compatible version */
|
||||||
|
|
||||||
|
/* version 2 fields below */
|
||||||
|
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
|
||||||
|
booting on */
|
||||||
|
/* version 3 fields below */
|
||||||
|
fdt32_t size_dt_strings; /* size of the strings block */
|
||||||
|
|
||||||
|
/* version 17 fields below */
|
||||||
|
fdt32_t size_dt_struct; /* size of the structure block */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_reserve_entry {
|
||||||
|
fdt64_t address;
|
||||||
|
fdt64_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_node_header {
|
||||||
|
fdt32_t tag;
|
||||||
|
char name[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_property {
|
||||||
|
fdt32_t tag;
|
||||||
|
fdt32_t len;
|
||||||
|
fdt32_t nameoff;
|
||||||
|
char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* !__ASSEMBLY */
|
||||||
|
|
||||||
|
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
|
||||||
|
#define FDT_TAGSIZE sizeof(fdt32_t)
|
||||||
|
|
||||||
|
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
|
||||||
|
#define FDT_END_NODE 0x2 /* End node */
|
||||||
|
#define FDT_PROP 0x3 /* Property: name off,
|
||||||
|
size, content */
|
||||||
|
#define FDT_NOP 0x4 /* nop */
|
||||||
|
#define FDT_END 0x9
|
||||||
|
|
||||||
|
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
|
||||||
|
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
|
||||||
|
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
|
||||||
|
#define FDT_V16_SIZE FDT_V3_SIZE
|
||||||
|
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
|
||||||
|
|
||||||
|
#endif /* _FDT_H */
|
||||||
96
dtc-1.4.5/libfdt/fdt_addresses.c
Normal file
96
dtc-1.4.5/libfdt/fdt_addresses.c
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
int fdt_address_cells(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
const fdt32_t *ac;
|
||||||
|
int val;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
|
||||||
|
if (!ac)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (len != sizeof(*ac))
|
||||||
|
return -FDT_ERR_BADNCELLS;
|
||||||
|
|
||||||
|
val = fdt32_to_cpu(*ac);
|
||||||
|
if ((val <= 0) || (val > FDT_MAX_NCELLS))
|
||||||
|
return -FDT_ERR_BADNCELLS;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_size_cells(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
const fdt32_t *sc;
|
||||||
|
int val;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
|
||||||
|
if (!sc)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (len != sizeof(*sc))
|
||||||
|
return -FDT_ERR_BADNCELLS;
|
||||||
|
|
||||||
|
val = fdt32_to_cpu(*sc);
|
||||||
|
if ((val < 0) || (val > FDT_MAX_NCELLS))
|
||||||
|
return -FDT_ERR_BADNCELLS;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
83
dtc-1.4.5/libfdt/fdt_empty_tree.c
Normal file
83
dtc-1.4.5/libfdt/fdt_empty_tree.c
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2012 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
int fdt_create_empty_tree(void *buf, int bufsize)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = fdt_create(buf, bufsize);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = fdt_finish_reservemap(buf);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = fdt_begin_node(buf, "");
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = fdt_end_node(buf);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = fdt_finish(buf);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return fdt_open_into(buf, buf, bufsize);
|
||||||
|
}
|
||||||
861
dtc-1.4.5/libfdt/fdt_overlay.c
Normal file
861
dtc-1.4.5/libfdt/fdt_overlay.c
Normal file
@@ -0,0 +1,861 @@
|
|||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_get_target_phandle - retrieves the target phandle of a fragment
|
||||||
|
* @fdto: pointer to the device tree overlay blob
|
||||||
|
* @fragment: node offset of the fragment in the overlay
|
||||||
|
*
|
||||||
|
* overlay_get_target_phandle() retrieves the target phandle of an
|
||||||
|
* overlay fragment when that fragment uses a phandle (target
|
||||||
|
* property) instead of a path (target-path property).
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* the phandle pointed by the target property
|
||||||
|
* 0, if the phandle was not found
|
||||||
|
* -1, if the phandle was malformed
|
||||||
|
*/
|
||||||
|
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdto, fragment, "target", &len);
|
||||||
|
if (!val)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
|
||||||
|
return (uint32_t)-1;
|
||||||
|
|
||||||
|
return fdt32_to_cpu(*val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_get_target - retrieves the offset of a fragment's target
|
||||||
|
* @fdt: Base device tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @fragment: node offset of the fragment in the overlay
|
||||||
|
* @pathp: pointer which receives the path of the target (or NULL)
|
||||||
|
*
|
||||||
|
* overlay_get_target() retrieves the target offset in the base
|
||||||
|
* device tree of a fragment, no matter how the actual targetting is
|
||||||
|
* done (through a phandle or a path)
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* the targetted node offset in the base device tree
|
||||||
|
* Negative error code on error
|
||||||
|
*/
|
||||||
|
static int overlay_get_target(const void *fdt, const void *fdto,
|
||||||
|
int fragment, char const **pathp)
|
||||||
|
{
|
||||||
|
uint32_t phandle;
|
||||||
|
const char *path = NULL;
|
||||||
|
int path_len = 0, ret;
|
||||||
|
|
||||||
|
/* Try first to do a phandle based lookup */
|
||||||
|
phandle = overlay_get_target_phandle(fdto, fragment);
|
||||||
|
if (phandle == (uint32_t)-1)
|
||||||
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
|
||||||
|
/* no phandle, try path */
|
||||||
|
if (!phandle) {
|
||||||
|
/* And then a path based lookup */
|
||||||
|
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
|
||||||
|
if (path)
|
||||||
|
ret = fdt_path_offset(fdt, path);
|
||||||
|
else
|
||||||
|
ret = path_len;
|
||||||
|
} else
|
||||||
|
ret = fdt_node_offset_by_phandle(fdt, phandle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we haven't found either a target or a
|
||||||
|
* target-path property in a node that contains a
|
||||||
|
* __overlay__ subnode (we wouldn't be called
|
||||||
|
* otherwise), consider it a improperly written
|
||||||
|
* overlay
|
||||||
|
*/
|
||||||
|
if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
|
||||||
|
ret = -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
/* return on error */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* return pointer to path (if available) */
|
||||||
|
if (pathp)
|
||||||
|
*pathp = path ? path : NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_phandle_add_offset - Increases a phandle by an offset
|
||||||
|
* @fdt: Base device tree blob
|
||||||
|
* @node: Device tree overlay blob
|
||||||
|
* @name: Name of the property to modify (phandle or linux,phandle)
|
||||||
|
* @delta: offset to apply
|
||||||
|
*
|
||||||
|
* overlay_phandle_add_offset() increments a node phandle by a given
|
||||||
|
* offset.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success.
|
||||||
|
* Negative error code on error
|
||||||
|
*/
|
||||||
|
static int overlay_phandle_add_offset(void *fdt, int node,
|
||||||
|
const char *name, uint32_t delta)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
uint32_t adj_val;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, node, name, &len);
|
||||||
|
if (!val)
|
||||||
|
return len;
|
||||||
|
|
||||||
|
if (len != sizeof(*val))
|
||||||
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
|
||||||
|
adj_val = fdt32_to_cpu(*val);
|
||||||
|
if ((adj_val + delta) < adj_val)
|
||||||
|
return -FDT_ERR_NOPHANDLES;
|
||||||
|
|
||||||
|
adj_val += delta;
|
||||||
|
if (adj_val == (uint32_t)-1)
|
||||||
|
return -FDT_ERR_NOPHANDLES;
|
||||||
|
|
||||||
|
return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_adjust_node_phandles - Offsets the phandles of a node
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @node: Offset of the node we want to adjust
|
||||||
|
* @delta: Offset to shift the phandles of
|
||||||
|
*
|
||||||
|
* overlay_adjust_node_phandles() adds a constant to all the phandles
|
||||||
|
* of a given node. This is mainly use as part of the overlay
|
||||||
|
* application process, when we want to update all the overlay
|
||||||
|
* phandles to not conflict with the overlays of the base device tree.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_adjust_node_phandles(void *fdto, int node,
|
||||||
|
uint32_t delta)
|
||||||
|
{
|
||||||
|
int child;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
|
||||||
|
if (ret && ret != -FDT_ERR_NOTFOUND)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
|
||||||
|
if (ret && ret != -FDT_ERR_NOTFOUND)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(child, fdto, node) {
|
||||||
|
ret = overlay_adjust_node_phandles(fdto, child, delta);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @delta: Offset to shift the phandles of
|
||||||
|
*
|
||||||
|
* overlay_adjust_local_phandles() adds a constant to all the
|
||||||
|
* phandles of an overlay. This is mainly use as part of the overlay
|
||||||
|
* application process, when we want to update all the overlay
|
||||||
|
* phandles to not conflict with the overlays of the base device tree.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Start adjusting the phandles from the overlay root
|
||||||
|
*/
|
||||||
|
return overlay_adjust_node_phandles(fdto, 0, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_update_local_node_references - Adjust the overlay references
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @tree_node: Node offset of the node to operate on
|
||||||
|
* @fixup_node: Node offset of the matching local fixups node
|
||||||
|
* @delta: Offset to shift the phandles of
|
||||||
|
*
|
||||||
|
* overlay_update_local_nodes_references() update the phandles
|
||||||
|
* pointing to a node within the device tree overlay by adding a
|
||||||
|
* constant delta.
|
||||||
|
*
|
||||||
|
* This is mainly used as part of a device tree application process,
|
||||||
|
* where you want the device tree overlays phandles to not conflict
|
||||||
|
* with the ones from the base device tree before merging them.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_update_local_node_references(void *fdto,
|
||||||
|
int tree_node,
|
||||||
|
int fixup_node,
|
||||||
|
uint32_t delta)
|
||||||
|
{
|
||||||
|
int fixup_prop;
|
||||||
|
int fixup_child;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
|
||||||
|
const fdt32_t *fixup_val;
|
||||||
|
const char *tree_val;
|
||||||
|
const char *name;
|
||||||
|
int fixup_len;
|
||||||
|
int tree_len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
|
||||||
|
&name, &fixup_len);
|
||||||
|
if (!fixup_val)
|
||||||
|
return fixup_len;
|
||||||
|
|
||||||
|
if (fixup_len % sizeof(uint32_t))
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
|
||||||
|
if (!tree_val) {
|
||||||
|
if (tree_len == -FDT_ERR_NOTFOUND)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
return tree_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
|
||||||
|
fdt32_t adj_val;
|
||||||
|
uint32_t poffset;
|
||||||
|
|
||||||
|
poffset = fdt32_to_cpu(fixup_val[i]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* phandles to fixup can be unaligned.
|
||||||
|
*
|
||||||
|
* Use a memcpy for the architectures that do
|
||||||
|
* not support unaligned accesses.
|
||||||
|
*/
|
||||||
|
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
|
||||||
|
|
||||||
|
adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
|
||||||
|
|
||||||
|
ret = fdt_setprop_inplace_namelen_partial(fdto,
|
||||||
|
tree_node,
|
||||||
|
name,
|
||||||
|
strlen(name),
|
||||||
|
poffset,
|
||||||
|
&adj_val,
|
||||||
|
sizeof(adj_val));
|
||||||
|
if (ret == -FDT_ERR_NOSPACE)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
|
||||||
|
const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
|
||||||
|
NULL);
|
||||||
|
int tree_child;
|
||||||
|
|
||||||
|
tree_child = fdt_subnode_offset(fdto, tree_node,
|
||||||
|
fixup_child_name);
|
||||||
|
if (tree_child == -FDT_ERR_NOTFOUND)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
if (tree_child < 0)
|
||||||
|
return tree_child;
|
||||||
|
|
||||||
|
ret = overlay_update_local_node_references(fdto,
|
||||||
|
tree_child,
|
||||||
|
fixup_child,
|
||||||
|
delta);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_update_local_references - Adjust the overlay references
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @delta: Offset to shift the phandles of
|
||||||
|
*
|
||||||
|
* overlay_update_local_references() update all the phandles pointing
|
||||||
|
* to a node within the device tree overlay by adding a constant
|
||||||
|
* delta to not conflict with the base overlay.
|
||||||
|
*
|
||||||
|
* This is mainly used as part of a device tree application process,
|
||||||
|
* where you want the device tree overlays phandles to not conflict
|
||||||
|
* with the ones from the base device tree before merging them.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_update_local_references(void *fdto, uint32_t delta)
|
||||||
|
{
|
||||||
|
int fixups;
|
||||||
|
|
||||||
|
fixups = fdt_path_offset(fdto, "/__local_fixups__");
|
||||||
|
if (fixups < 0) {
|
||||||
|
/* There's no local phandles to adjust, bail out */
|
||||||
|
if (fixups == -FDT_ERR_NOTFOUND)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return fixups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update our local references from the root of the tree
|
||||||
|
*/
|
||||||
|
return overlay_update_local_node_references(fdto, 0, fixups,
|
||||||
|
delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_fixup_one_phandle - Set an overlay phandle to the base one
|
||||||
|
* @fdt: Base Device Tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @symbols_off: Node offset of the symbols node in the base device tree
|
||||||
|
* @path: Path to a node holding a phandle in the overlay
|
||||||
|
* @path_len: number of path characters to consider
|
||||||
|
* @name: Name of the property holding the phandle reference in the overlay
|
||||||
|
* @name_len: number of name characters to consider
|
||||||
|
* @poffset: Offset within the overlay property where the phandle is stored
|
||||||
|
* @label: Label of the node referenced by the phandle
|
||||||
|
*
|
||||||
|
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to
|
||||||
|
* a node in the base device tree.
|
||||||
|
*
|
||||||
|
* This is part of the device tree overlay application process, when
|
||||||
|
* you want all the phandles in the overlay to point to the actual
|
||||||
|
* base dt nodes.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_fixup_one_phandle(void *fdt, void *fdto,
|
||||||
|
int symbols_off,
|
||||||
|
const char *path, uint32_t path_len,
|
||||||
|
const char *name, uint32_t name_len,
|
||||||
|
int poffset, const char *label)
|
||||||
|
{
|
||||||
|
const char *symbol_path;
|
||||||
|
uint32_t phandle;
|
||||||
|
fdt32_t phandle_prop;
|
||||||
|
int symbol_off, fixup_off;
|
||||||
|
int prop_len;
|
||||||
|
|
||||||
|
if (symbols_off < 0)
|
||||||
|
return symbols_off;
|
||||||
|
|
||||||
|
symbol_path = fdt_getprop(fdt, symbols_off, label,
|
||||||
|
&prop_len);
|
||||||
|
if (!symbol_path)
|
||||||
|
return prop_len;
|
||||||
|
|
||||||
|
symbol_off = fdt_path_offset(fdt, symbol_path);
|
||||||
|
if (symbol_off < 0)
|
||||||
|
return symbol_off;
|
||||||
|
|
||||||
|
phandle = fdt_get_phandle(fdt, symbol_off);
|
||||||
|
if (!phandle)
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
|
||||||
|
fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
|
||||||
|
if (fixup_off == -FDT_ERR_NOTFOUND)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
if (fixup_off < 0)
|
||||||
|
return fixup_off;
|
||||||
|
|
||||||
|
phandle_prop = cpu_to_fdt32(phandle);
|
||||||
|
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
|
||||||
|
name, name_len, poffset,
|
||||||
|
&phandle_prop,
|
||||||
|
sizeof(phandle_prop));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_fixup_phandle - Set an overlay phandle to the base one
|
||||||
|
* @fdt: Base Device Tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @symbols_off: Node offset of the symbols node in the base device tree
|
||||||
|
* @property: Property offset in the overlay holding the list of fixups
|
||||||
|
*
|
||||||
|
* overlay_fixup_phandle() resolves all the overlay phandles pointed
|
||||||
|
* to in a __fixups__ property, and updates them to match the phandles
|
||||||
|
* in use in the base device tree.
|
||||||
|
*
|
||||||
|
* This is part of the device tree overlay application process, when
|
||||||
|
* you want all the phandles in the overlay to point to the actual
|
||||||
|
* base dt nodes.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
|
||||||
|
int property)
|
||||||
|
{
|
||||||
|
const char *value;
|
||||||
|
const char *label;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
value = fdt_getprop_by_offset(fdto, property,
|
||||||
|
&label, &len);
|
||||||
|
if (!value) {
|
||||||
|
if (len == -FDT_ERR_NOTFOUND)
|
||||||
|
return -FDT_ERR_INTERNAL;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
const char *path, *name, *fixup_end;
|
||||||
|
const char *fixup_str = value;
|
||||||
|
uint32_t path_len, name_len;
|
||||||
|
uint32_t fixup_len;
|
||||||
|
char *sep, *endptr;
|
||||||
|
int poffset, ret;
|
||||||
|
|
||||||
|
fixup_end = memchr(value, '\0', len);
|
||||||
|
if (!fixup_end)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
fixup_len = fixup_end - fixup_str;
|
||||||
|
|
||||||
|
len -= fixup_len + 1;
|
||||||
|
value += fixup_len + 1;
|
||||||
|
|
||||||
|
path = fixup_str;
|
||||||
|
sep = memchr(fixup_str, ':', fixup_len);
|
||||||
|
if (!sep || *sep != ':')
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
path_len = sep - path;
|
||||||
|
if (path_len == (fixup_len - 1))
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
fixup_len -= path_len + 1;
|
||||||
|
name = sep + 1;
|
||||||
|
sep = memchr(name, ':', fixup_len);
|
||||||
|
if (!sep || *sep != ':')
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
name_len = sep - name;
|
||||||
|
if (!name_len)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
poffset = strtoul(sep + 1, &endptr, 10);
|
||||||
|
if ((*endptr != '\0') || (endptr <= (sep + 1)))
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
|
||||||
|
path, path_len, name, name_len,
|
||||||
|
poffset, label);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
} while (len > 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_fixup_phandles - Resolve the overlay phandles to the base
|
||||||
|
* device tree
|
||||||
|
* @fdt: Base Device Tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
*
|
||||||
|
* overlay_fixup_phandles() resolves all the overlay phandles pointing
|
||||||
|
* to nodes in the base device tree.
|
||||||
|
*
|
||||||
|
* This is one of the steps of the device tree overlay application
|
||||||
|
* process, when you want all the phandles in the overlay to point to
|
||||||
|
* the actual base dt nodes.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_fixup_phandles(void *fdt, void *fdto)
|
||||||
|
{
|
||||||
|
int fixups_off, symbols_off;
|
||||||
|
int property;
|
||||||
|
|
||||||
|
/* We can have overlays without any fixups */
|
||||||
|
fixups_off = fdt_path_offset(fdto, "/__fixups__");
|
||||||
|
if (fixups_off == -FDT_ERR_NOTFOUND)
|
||||||
|
return 0; /* nothing to do */
|
||||||
|
if (fixups_off < 0)
|
||||||
|
return fixups_off;
|
||||||
|
|
||||||
|
/* And base DTs without symbols */
|
||||||
|
symbols_off = fdt_path_offset(fdt, "/__symbols__");
|
||||||
|
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
|
||||||
|
return symbols_off;
|
||||||
|
|
||||||
|
fdt_for_each_property_offset(property, fdto, fixups_off) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_apply_node - Merges a node into the base device tree
|
||||||
|
* @fdt: Base Device Tree blob
|
||||||
|
* @target: Node offset in the base device tree to apply the fragment to
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @node: Node offset in the overlay holding the changes to merge
|
||||||
|
*
|
||||||
|
* overlay_apply_node() merges a node into a target base device tree
|
||||||
|
* node pointed.
|
||||||
|
*
|
||||||
|
* This is part of the final step in the device tree overlay
|
||||||
|
* application process, when all the phandles have been adjusted and
|
||||||
|
* resolved and you just have to merge overlay into the base device
|
||||||
|
* tree.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_apply_node(void *fdt, int target,
|
||||||
|
void *fdto, int node)
|
||||||
|
{
|
||||||
|
int property;
|
||||||
|
int subnode;
|
||||||
|
|
||||||
|
fdt_for_each_property_offset(property, fdto, node) {
|
||||||
|
const char *name;
|
||||||
|
const void *prop;
|
||||||
|
int prop_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
prop = fdt_getprop_by_offset(fdto, property, &name,
|
||||||
|
&prop_len);
|
||||||
|
if (prop_len == -FDT_ERR_NOTFOUND)
|
||||||
|
return -FDT_ERR_INTERNAL;
|
||||||
|
if (prop_len < 0)
|
||||||
|
return prop_len;
|
||||||
|
|
||||||
|
ret = fdt_setprop(fdt, target, name, prop, prop_len);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_for_each_subnode(subnode, fdto, node) {
|
||||||
|
const char *name = fdt_get_name(fdto, subnode, NULL);
|
||||||
|
int nnode;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nnode = fdt_add_subnode(fdt, target, name);
|
||||||
|
if (nnode == -FDT_ERR_EXISTS) {
|
||||||
|
nnode = fdt_subnode_offset(fdt, target, name);
|
||||||
|
if (nnode == -FDT_ERR_NOTFOUND)
|
||||||
|
return -FDT_ERR_INTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nnode < 0)
|
||||||
|
return nnode;
|
||||||
|
|
||||||
|
ret = overlay_apply_node(fdt, nnode, fdto, subnode);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_merge - Merge an overlay into its base device tree
|
||||||
|
* @fdt: Base Device Tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
*
|
||||||
|
* overlay_merge() merges an overlay into its base device tree.
|
||||||
|
*
|
||||||
|
* This is the next to last step in the device tree overlay application
|
||||||
|
* process, when all the phandles have been adjusted and resolved and
|
||||||
|
* you just have to merge overlay into the base device tree.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_merge(void *fdt, void *fdto)
|
||||||
|
{
|
||||||
|
int fragment;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(fragment, fdto, 0) {
|
||||||
|
int overlay;
|
||||||
|
int target;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each fragments will have an __overlay__ node. If
|
||||||
|
* they don't, it's not supposed to be merged
|
||||||
|
*/
|
||||||
|
overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
|
||||||
|
if (overlay == -FDT_ERR_NOTFOUND)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (overlay < 0)
|
||||||
|
return overlay;
|
||||||
|
|
||||||
|
target = overlay_get_target(fdt, fdto, fragment, NULL);
|
||||||
|
if (target < 0)
|
||||||
|
return target;
|
||||||
|
|
||||||
|
ret = overlay_apply_node(fdt, target, fdto, overlay);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_path_len(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
int len = 0, namelen;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
name = fdt_get_name(fdt, nodeoffset, &namelen);
|
||||||
|
if (!name)
|
||||||
|
return namelen;
|
||||||
|
|
||||||
|
/* root? we're done */
|
||||||
|
if (namelen == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
nodeoffset = fdt_parent_offset(fdt, nodeoffset);
|
||||||
|
if (nodeoffset < 0)
|
||||||
|
return nodeoffset;
|
||||||
|
len += namelen + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in case of root pretend it's "/" */
|
||||||
|
if (len == 0)
|
||||||
|
len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* overlay_symbol_update - Update the symbols of base tree after a merge
|
||||||
|
* @fdt: Base Device Tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
*
|
||||||
|
* overlay_symbol_update() updates the symbols of the base tree with the
|
||||||
|
* symbols of the applied overlay
|
||||||
|
*
|
||||||
|
* This is the last step in the device tree overlay application
|
||||||
|
* process, allowing the reference of overlay symbols by subsequent
|
||||||
|
* overlay operations.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0 on success
|
||||||
|
* Negative error code on failure
|
||||||
|
*/
|
||||||
|
static int overlay_symbol_update(void *fdt, void *fdto)
|
||||||
|
{
|
||||||
|
int root_sym, ov_sym, prop, path_len, fragment, target;
|
||||||
|
int len, frag_name_len, ret, rel_path_len;
|
||||||
|
const char *s, *e;
|
||||||
|
const char *path;
|
||||||
|
const char *name;
|
||||||
|
const char *frag_name;
|
||||||
|
const char *rel_path;
|
||||||
|
const char *target_path;
|
||||||
|
char *buf;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
|
||||||
|
|
||||||
|
/* if no overlay symbols exist no problem */
|
||||||
|
if (ov_sym < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
|
||||||
|
|
||||||
|
/* it no root symbols exist we should create them */
|
||||||
|
if (root_sym == -FDT_ERR_NOTFOUND)
|
||||||
|
root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
|
||||||
|
|
||||||
|
/* any error is fatal now */
|
||||||
|
if (root_sym < 0)
|
||||||
|
return root_sym;
|
||||||
|
|
||||||
|
/* iterate over each overlay symbol */
|
||||||
|
fdt_for_each_property_offset(prop, fdto, ov_sym) {
|
||||||
|
path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
|
||||||
|
if (!path)
|
||||||
|
return path_len;
|
||||||
|
|
||||||
|
/* verify it's a string property (terminated by a single \0) */
|
||||||
|
if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
|
||||||
|
return -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
|
/* keep end marker to avoid strlen() */
|
||||||
|
e = path + path_len;
|
||||||
|
|
||||||
|
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
|
||||||
|
|
||||||
|
if (*path != '/')
|
||||||
|
return -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
|
/* get fragment name first */
|
||||||
|
s = strchr(path + 1, '/');
|
||||||
|
if (!s)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
frag_name = path + 1;
|
||||||
|
frag_name_len = s - path - 1;
|
||||||
|
|
||||||
|
/* verify format; safe since "s" lies in \0 terminated prop */
|
||||||
|
len = sizeof("/__overlay__/") - 1;
|
||||||
|
if ((e - s) < len || memcmp(s, "/__overlay__/", len))
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
rel_path = s + len;
|
||||||
|
rel_path_len = e - rel_path;
|
||||||
|
|
||||||
|
/* find the fragment index in which the symbol lies */
|
||||||
|
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
|
||||||
|
frag_name_len);
|
||||||
|
/* not found? */
|
||||||
|
if (ret < 0)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
fragment = ret;
|
||||||
|
|
||||||
|
/* an __overlay__ subnode must exist */
|
||||||
|
ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
|
||||||
|
if (ret < 0)
|
||||||
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
|
/* get the target of the fragment */
|
||||||
|
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
target = ret;
|
||||||
|
|
||||||
|
/* if we have a target path use */
|
||||||
|
if (!target_path) {
|
||||||
|
ret = get_path_len(fdt, target);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
len = ret;
|
||||||
|
} else {
|
||||||
|
len = strlen(target_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fdt_setprop_placeholder(fdt, root_sym, name,
|
||||||
|
len + (len > 1) + rel_path_len + 1, &p);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!target_path) {
|
||||||
|
/* again in case setprop_placeholder changed it */
|
||||||
|
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
target = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = p;
|
||||||
|
if (len > 1) { /* target is not root */
|
||||||
|
if (!target_path) {
|
||||||
|
ret = fdt_get_path(fdt, target, buf, len + 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
} else
|
||||||
|
memcpy(buf, target_path, len + 1);
|
||||||
|
|
||||||
|
} else
|
||||||
|
len--;
|
||||||
|
|
||||||
|
buf[len] = '/';
|
||||||
|
memcpy(buf + len + 1, rel_path, rel_path_len);
|
||||||
|
buf[len + 1 + rel_path_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_overlay_apply(void *fdt, void *fdto)
|
||||||
|
{
|
||||||
|
uint32_t delta = fdt_get_max_phandle(fdt);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
FDT_CHECK_HEADER(fdto);
|
||||||
|
|
||||||
|
ret = overlay_adjust_local_phandles(fdto, delta);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = overlay_update_local_references(fdto, delta);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = overlay_fixup_phandles(fdt, fdto);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = overlay_merge(fdt, fdto);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = overlay_symbol_update(fdt, fdto);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The overlay has been damaged, erase its magic.
|
||||||
|
*/
|
||||||
|
fdt_set_magic(fdto, ~0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
/*
|
||||||
|
* The overlay might have been damaged, erase its magic.
|
||||||
|
*/
|
||||||
|
fdt_set_magic(fdto, ~0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The base device tree might have been damaged, erase its
|
||||||
|
* magic.
|
||||||
|
*/
|
||||||
|
fdt_set_magic(fdt, ~0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
703
dtc-1.4.5/libfdt/fdt_ro.c
Normal file
703
dtc-1.4.5/libfdt/fdt_ro.c
Normal file
@@ -0,0 +1,703 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
static int _fdt_nodename_eq(const void *fdt, int offset,
|
||||||
|
const char *s, int len)
|
||||||
|
{
|
||||||
|
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
/* short match */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (memcmp(p, s, len) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (p[len] == '\0')
|
||||||
|
return 1;
|
||||||
|
else if (!memchr(s, '@', len) && (p[len] == '@'))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *fdt_string(const void *fdt, int stroffset)
|
||||||
|
{
|
||||||
|
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_string_eq(const void *fdt, int stroffset,
|
||||||
|
const char *s, int len)
|
||||||
|
{
|
||||||
|
const char *p = fdt_string(fdt, stroffset);
|
||||||
|
|
||||||
|
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fdt_get_max_phandle(const void *fdt)
|
||||||
|
{
|
||||||
|
uint32_t max_phandle = 0;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
for (offset = fdt_next_node(fdt, -1, NULL);;
|
||||||
|
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||||
|
uint32_t phandle;
|
||||||
|
|
||||||
|
if (offset == -FDT_ERR_NOTFOUND)
|
||||||
|
return max_phandle;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
return (uint32_t)-1;
|
||||||
|
|
||||||
|
phandle = fdt_get_phandle(fdt, offset);
|
||||||
|
if (phandle == (uint32_t)-1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (phandle > max_phandle)
|
||||||
|
max_phandle = phandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||||
|
{
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
|
||||||
|
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_num_mem_rsv(const void *fdt)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
|
||||||
|
i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _nextprop(const void *fdt, int offset)
|
||||||
|
{
|
||||||
|
uint32_t tag;
|
||||||
|
int nextoffset;
|
||||||
|
|
||||||
|
do {
|
||||||
|
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case FDT_END:
|
||||||
|
if (nextoffset >= 0)
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
else
|
||||||
|
return nextoffset;
|
||||||
|
|
||||||
|
case FDT_PROP:
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
offset = nextoffset;
|
||||||
|
} while (tag == FDT_NOP);
|
||||||
|
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_subnode_offset_namelen(const void *fdt, int offset,
|
||||||
|
const char *name, int namelen)
|
||||||
|
{
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
for (depth = 0;
|
||||||
|
(offset >= 0) && (depth >= 0);
|
||||||
|
offset = fdt_next_node(fdt, offset, &depth))
|
||||||
|
if ((depth == 1)
|
||||||
|
&& _fdt_nodename_eq(fdt, offset, name, namelen))
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
if (depth < 0)
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
return offset; /* error */
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_subnode_offset(const void *fdt, int parentoffset,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
|
||||||
|
{
|
||||||
|
const char *end = path + namelen;
|
||||||
|
const char *p = path;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
/* see if we have an alias */
|
||||||
|
if (*path != '/') {
|
||||||
|
const char *q = memchr(path, '/', end - p);
|
||||||
|
|
||||||
|
if (!q)
|
||||||
|
q = end;
|
||||||
|
|
||||||
|
p = fdt_get_alias_namelen(fdt, p, q - p);
|
||||||
|
if (!p)
|
||||||
|
return -FDT_ERR_BADPATH;
|
||||||
|
offset = fdt_path_offset(fdt, p);
|
||||||
|
|
||||||
|
p = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p < end) {
|
||||||
|
const char *q;
|
||||||
|
|
||||||
|
while (*p == '/') {
|
||||||
|
p++;
|
||||||
|
if (p == end)
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
q = memchr(p, '/', end - p);
|
||||||
|
if (! q)
|
||||||
|
q = end;
|
||||||
|
|
||||||
|
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
|
||||||
|
if (offset < 0)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
p = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_path_offset(const void *fdt, const char *path)
|
||||||
|
{
|
||||||
|
return fdt_path_offset_namelen(fdt, path, strlen(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
||||||
|
{
|
||||||
|
const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (((err = fdt_check_header(fdt)) != 0)
|
||||||
|
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
*len = strlen(nh->name);
|
||||||
|
|
||||||
|
return nh->name;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (len)
|
||||||
|
*len = err;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_first_property_offset(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
return _nextprop(fdt, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_next_property_offset(const void *fdt, int offset)
|
||||||
|
{
|
||||||
|
if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
return _nextprop(fdt, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||||
|
int offset,
|
||||||
|
int *lenp)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
const struct fdt_property *prop;
|
||||||
|
|
||||||
|
if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
|
||||||
|
if (lenp)
|
||||||
|
*lenp = err;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop = _fdt_offset_ptr(fdt, offset);
|
||||||
|
|
||||||
|
if (lenp)
|
||||||
|
*lenp = fdt32_to_cpu(prop->len);
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||||
|
int offset,
|
||||||
|
const char *name,
|
||||||
|
int namelen, int *lenp)
|
||||||
|
{
|
||||||
|
for (offset = fdt_first_property_offset(fdt, offset);
|
||||||
|
(offset >= 0);
|
||||||
|
(offset = fdt_next_property_offset(fdt, offset))) {
|
||||||
|
const struct fdt_property *prop;
|
||||||
|
|
||||||
|
if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
|
||||||
|
offset = -FDT_ERR_INTERNAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
|
||||||
|
name, namelen))
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lenp)
|
||||||
|
*lenp = offset;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct fdt_property *fdt_get_property(const void *fdt,
|
||||||
|
int nodeoffset,
|
||||||
|
const char *name, int *lenp)
|
||||||
|
{
|
||||||
|
return fdt_get_property_namelen(fdt, nodeoffset, name,
|
||||||
|
strlen(name), lenp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||||
|
const char *name, int namelen, int *lenp)
|
||||||
|
{
|
||||||
|
const struct fdt_property *prop;
|
||||||
|
|
||||||
|
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
|
||||||
|
if (!prop)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return prop->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||||
|
const char **namep, int *lenp)
|
||||||
|
{
|
||||||
|
const struct fdt_property *prop;
|
||||||
|
|
||||||
|
prop = fdt_get_property_by_offset(fdt, offset, lenp);
|
||||||
|
if (!prop)
|
||||||
|
return NULL;
|
||||||
|
if (namep)
|
||||||
|
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
|
||||||
|
return prop->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *fdt_getprop(const void *fdt, int nodeoffset,
|
||||||
|
const char *name, int *lenp)
|
||||||
|
{
|
||||||
|
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
const fdt32_t *php;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
/* FIXME: This is a bit sub-optimal, since we potentially scan
|
||||||
|
* over all the properties twice. */
|
||||||
|
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
|
||||||
|
if (!php || (len != sizeof(*php))) {
|
||||||
|
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
|
||||||
|
if (!php || (len != sizeof(*php)))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdt32_to_cpu(*php);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *fdt_get_alias_namelen(const void *fdt,
|
||||||
|
const char *name, int namelen)
|
||||||
|
{
|
||||||
|
int aliasoffset;
|
||||||
|
|
||||||
|
aliasoffset = fdt_path_offset(fdt, "/aliases");
|
||||||
|
if (aliasoffset < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *fdt_get_alias(const void *fdt, const char *name)
|
||||||
|
{
|
||||||
|
return fdt_get_alias_namelen(fdt, name, strlen(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||||
|
{
|
||||||
|
int pdepth = 0, p = 0;
|
||||||
|
int offset, depth, namelen;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
if (buflen < 2)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
for (offset = 0, depth = 0;
|
||||||
|
(offset >= 0) && (offset <= nodeoffset);
|
||||||
|
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||||
|
while (pdepth > depth) {
|
||||||
|
do {
|
||||||
|
p--;
|
||||||
|
} while (buf[p-1] != '/');
|
||||||
|
pdepth--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdepth >= depth) {
|
||||||
|
name = fdt_get_name(fdt, offset, &namelen);
|
||||||
|
if (!name)
|
||||||
|
return namelen;
|
||||||
|
if ((p + namelen + 1) <= buflen) {
|
||||||
|
memcpy(buf + p, name, namelen);
|
||||||
|
p += namelen;
|
||||||
|
buf[p++] = '/';
|
||||||
|
pdepth++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset == nodeoffset) {
|
||||||
|
if (pdepth < (depth + 1))
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
if (p > 1) /* special case so that root path is "/", not "" */
|
||||||
|
p--;
|
||||||
|
buf[p] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
else if (offset == -FDT_ERR_BADOFFSET)
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
|
||||||
|
return offset; /* error from fdt_next_node() */
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
|
||||||
|
int supernodedepth, int *nodedepth)
|
||||||
|
{
|
||||||
|
int offset, depth;
|
||||||
|
int supernodeoffset = -FDT_ERR_INTERNAL;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
if (supernodedepth < 0)
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
|
||||||
|
for (offset = 0, depth = 0;
|
||||||
|
(offset >= 0) && (offset <= nodeoffset);
|
||||||
|
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||||
|
if (depth == supernodedepth)
|
||||||
|
supernodeoffset = offset;
|
||||||
|
|
||||||
|
if (offset == nodeoffset) {
|
||||||
|
if (nodedepth)
|
||||||
|
*nodedepth = depth;
|
||||||
|
|
||||||
|
if (supernodedepth > depth)
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
else
|
||||||
|
return supernodeoffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
else if (offset == -FDT_ERR_BADOFFSET)
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
|
||||||
|
return offset; /* error from fdt_next_node() */
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_node_depth(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
int nodedepth;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
|
||||||
|
if (err)
|
||||||
|
return (err < 0) ? err : -FDT_ERR_INTERNAL;
|
||||||
|
return nodedepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parent_offset(const void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
int nodedepth = fdt_node_depth(fdt, nodeoffset);
|
||||||
|
|
||||||
|
if (nodedepth < 0)
|
||||||
|
return nodedepth;
|
||||||
|
return fdt_supernode_atdepth_offset(fdt, nodeoffset,
|
||||||
|
nodedepth - 1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
|
||||||
|
const char *propname,
|
||||||
|
const void *propval, int proplen)
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
const void *val;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||||
|
* property of a node in fdt_getprop(), then if that didn't
|
||||||
|
* find what we want, we scan over them again making our way
|
||||||
|
* to the next node. Still it's the easiest to implement
|
||||||
|
* approach; performance can come later. */
|
||||||
|
for (offset = fdt_next_node(fdt, startoffset, NULL);
|
||||||
|
offset >= 0;
|
||||||
|
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||||
|
val = fdt_getprop(fdt, offset, propname, &len);
|
||||||
|
if (val && (len == proplen)
|
||||||
|
&& (memcmp(val, propval, len) == 0))
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset; /* error from fdt_next_node() */
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if ((phandle == 0) || (phandle == -1))
|
||||||
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
/* FIXME: The algorithm here is pretty horrible: we
|
||||||
|
* potentially scan each property of a node in
|
||||||
|
* fdt_get_phandle(), then if that didn't find what
|
||||||
|
* we want, we scan over them again making our way to the next
|
||||||
|
* node. Still it's the easiest to implement approach;
|
||||||
|
* performance can come later. */
|
||||||
|
for (offset = fdt_next_node(fdt, -1, NULL);
|
||||||
|
offset >= 0;
|
||||||
|
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||||
|
if (fdt_get_phandle(fdt, offset) == phandle)
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset; /* error from fdt_next_node() */
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
|
||||||
|
{
|
||||||
|
int len = strlen(str);
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
while (listlen >= len) {
|
||||||
|
if (memcmp(str, strlist, len+1) == 0)
|
||||||
|
return 1;
|
||||||
|
p = memchr(strlist, '\0', listlen);
|
||||||
|
if (!p)
|
||||||
|
return 0; /* malformed strlist.. */
|
||||||
|
listlen -= (p-strlist) + 1;
|
||||||
|
strlist = p + 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
|
||||||
|
{
|
||||||
|
const char *list, *end;
|
||||||
|
int length, count = 0;
|
||||||
|
|
||||||
|
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||||
|
if (!list)
|
||||||
|
return length;
|
||||||
|
|
||||||
|
end = list + length;
|
||||||
|
|
||||||
|
while (list < end) {
|
||||||
|
length = strnlen(list, end - list) + 1;
|
||||||
|
|
||||||
|
/* Abort if the last string isn't properly NUL-terminated. */
|
||||||
|
if (list + length > end)
|
||||||
|
return -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
|
list += length;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
|
||||||
|
const char *string)
|
||||||
|
{
|
||||||
|
int length, len, idx = 0;
|
||||||
|
const char *list, *end;
|
||||||
|
|
||||||
|
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||||
|
if (!list)
|
||||||
|
return length;
|
||||||
|
|
||||||
|
len = strlen(string) + 1;
|
||||||
|
end = list + length;
|
||||||
|
|
||||||
|
while (list < end) {
|
||||||
|
length = strnlen(list, end - list) + 1;
|
||||||
|
|
||||||
|
/* Abort if the last string isn't properly NUL-terminated. */
|
||||||
|
if (list + length > end)
|
||||||
|
return -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
|
if (length == len && memcmp(list, string, length) == 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
list += length;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
|
||||||
|
const char *property, int idx,
|
||||||
|
int *lenp)
|
||||||
|
{
|
||||||
|
const char *list, *end;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||||
|
if (!list) {
|
||||||
|
if (lenp)
|
||||||
|
*lenp = length;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = list + length;
|
||||||
|
|
||||||
|
while (list < end) {
|
||||||
|
length = strnlen(list, end - list) + 1;
|
||||||
|
|
||||||
|
/* Abort if the last string isn't properly NUL-terminated. */
|
||||||
|
if (list + length > end) {
|
||||||
|
if (lenp)
|
||||||
|
*lenp = -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx == 0) {
|
||||||
|
if (lenp)
|
||||||
|
*lenp = length - 1;
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
list += length;
|
||||||
|
idx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lenp)
|
||||||
|
*lenp = -FDT_ERR_NOTFOUND;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
|
||||||
|
const char *compatible)
|
||||||
|
{
|
||||||
|
const void *prop;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
|
||||||
|
if (!prop)
|
||||||
|
return len;
|
||||||
|
|
||||||
|
return !fdt_stringlist_contains(prop, len, compatible);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
|
||||||
|
const char *compatible)
|
||||||
|
{
|
||||||
|
int offset, err;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||||
|
* property of a node in fdt_node_check_compatible(), then if
|
||||||
|
* that didn't find what we want, we scan over them again
|
||||||
|
* making our way to the next node. Still it's the easiest to
|
||||||
|
* implement approach; performance can come later. */
|
||||||
|
for (offset = fdt_next_node(fdt, startoffset, NULL);
|
||||||
|
offset >= 0;
|
||||||
|
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||||
|
err = fdt_node_check_compatible(fdt, offset, compatible);
|
||||||
|
if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
|
||||||
|
return err;
|
||||||
|
else if (err == 0)
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset; /* error from fdt_next_node() */
|
||||||
|
}
|
||||||
505
dtc-1.4.5/libfdt/fdt_rw.c
Normal file
505
dtc-1.4.5/libfdt/fdt_rw.c
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
static int _fdt_blocks_misordered(const void *fdt,
|
||||||
|
int mem_rsv_size, int struct_size)
|
||||||
|
{
|
||||||
|
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|
||||||
|
|| (fdt_off_dt_struct(fdt) <
|
||||||
|
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|
||||||
|
|| (fdt_off_dt_strings(fdt) <
|
||||||
|
(fdt_off_dt_struct(fdt) + struct_size))
|
||||||
|
|| (fdt_totalsize(fdt) <
|
||||||
|
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_rw_check_header(void *fdt)
|
||||||
|
{
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
if (fdt_version(fdt) < 17)
|
||||||
|
return -FDT_ERR_BADVERSION;
|
||||||
|
if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
|
||||||
|
fdt_size_dt_struct(fdt)))
|
||||||
|
return -FDT_ERR_BADLAYOUT;
|
||||||
|
if (fdt_version(fdt) > 17)
|
||||||
|
fdt_set_version(fdt, 17);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FDT_RW_CHECK_HEADER(fdt) \
|
||||||
|
{ \
|
||||||
|
int __err; \
|
||||||
|
if ((__err = _fdt_rw_check_header(fdt)) != 0) \
|
||||||
|
return __err; \
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int _fdt_data_size(void *fdt)
|
||||||
|
{
|
||||||
|
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
|
||||||
|
{
|
||||||
|
char *p = splicepoint;
|
||||||
|
char *end = (char *)fdt + _fdt_data_size(fdt);
|
||||||
|
|
||||||
|
if (((p + oldlen) < p) || ((p + oldlen) > end))
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
memmove(p + newlen, p + oldlen, end - p - oldlen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
|
||||||
|
int oldn, int newn)
|
||||||
|
{
|
||||||
|
int delta = (newn - oldn) * sizeof(*p);
|
||||||
|
int err;
|
||||||
|
err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
|
||||||
|
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_splice_struct(void *fdt, void *p,
|
||||||
|
int oldlen, int newlen)
|
||||||
|
{
|
||||||
|
int delta = newlen - oldlen;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
|
||||||
|
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_splice_string(void *fdt, int newlen)
|
||||||
|
{
|
||||||
|
void *p = (char *)fdt
|
||||||
|
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((err = _fdt_splice(fdt, p, 0, newlen)))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_find_add_string(void *fdt, const char *s)
|
||||||
|
{
|
||||||
|
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
|
||||||
|
const char *p;
|
||||||
|
char *new;
|
||||||
|
int len = strlen(s) + 1;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
|
||||||
|
if (p)
|
||||||
|
/* found it */
|
||||||
|
return (p - strtab);
|
||||||
|
|
||||||
|
new = strtab + fdt_size_dt_strings(fdt);
|
||||||
|
err = _fdt_splice_string(fdt, len);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
memcpy(new, s, len);
|
||||||
|
return (new - strtab);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
|
||||||
|
{
|
||||||
|
struct fdt_reserve_entry *re;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
|
||||||
|
err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
re->address = cpu_to_fdt64(address);
|
||||||
|
re->size = cpu_to_fdt64(size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_del_mem_rsv(void *fdt, int n)
|
||||||
|
{
|
||||||
|
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
if (n >= fdt_num_mem_rsv(fdt))
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
|
||||||
|
return _fdt_splice_mem_rsv(fdt, re, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
|
||||||
|
int len, struct fdt_property **prop)
|
||||||
|
{
|
||||||
|
int oldlen;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||||
|
if (!*prop)
|
||||||
|
return oldlen;
|
||||||
|
|
||||||
|
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
|
||||||
|
FDT_TAGALIGN(len))))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
(*prop)->len = cpu_to_fdt32(len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
|
||||||
|
int len, struct fdt_property **prop)
|
||||||
|
{
|
||||||
|
int proplen;
|
||||||
|
int nextoffset;
|
||||||
|
int namestroff;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
|
||||||
|
return nextoffset;
|
||||||
|
|
||||||
|
namestroff = _fdt_find_add_string(fdt, name);
|
||||||
|
if (namestroff < 0)
|
||||||
|
return namestroff;
|
||||||
|
|
||||||
|
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
|
||||||
|
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
|
||||||
|
|
||||||
|
err = _fdt_splice_struct(fdt, *prop, 0, proplen);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
|
||||||
|
(*prop)->nameoff = cpu_to_fdt32(namestroff);
|
||||||
|
(*prop)->len = cpu_to_fdt32(len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_set_name(void *fdt, int nodeoffset, const char *name)
|
||||||
|
{
|
||||||
|
char *namep;
|
||||||
|
int oldlen, newlen;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
|
||||||
|
if (!namep)
|
||||||
|
return oldlen;
|
||||||
|
|
||||||
|
newlen = strlen(name);
|
||||||
|
|
||||||
|
err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
|
||||||
|
FDT_TAGALIGN(newlen+1));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
memcpy(namep, name, newlen+1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
|
||||||
|
int len, void **prop_data)
|
||||||
|
{
|
||||||
|
struct fdt_property *prop;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
|
||||||
|
if (err == -FDT_ERR_NOTFOUND)
|
||||||
|
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
*prop_data = prop->data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||||
|
const void *val, int len)
|
||||||
|
{
|
||||||
|
void *prop_data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
memcpy(prop_data, val, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
|
||||||
|
const void *val, int len)
|
||||||
|
{
|
||||||
|
struct fdt_property *prop;
|
||||||
|
int err, oldlen, newlen;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||||
|
if (prop) {
|
||||||
|
newlen = len + oldlen;
|
||||||
|
err = _fdt_splice_struct(fdt, prop->data,
|
||||||
|
FDT_TAGALIGN(oldlen),
|
||||||
|
FDT_TAGALIGN(newlen));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
prop->len = cpu_to_fdt32(newlen);
|
||||||
|
memcpy(prop->data + oldlen, val, len);
|
||||||
|
} else {
|
||||||
|
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
memcpy(prop->data, val, len);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
|
||||||
|
{
|
||||||
|
struct fdt_property *prop;
|
||||||
|
int len, proplen;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||||
|
if (!prop)
|
||||||
|
return len;
|
||||||
|
|
||||||
|
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
|
||||||
|
return _fdt_splice_struct(fdt, prop, proplen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||||
|
const char *name, int namelen)
|
||||||
|
{
|
||||||
|
struct fdt_node_header *nh;
|
||||||
|
int offset, nextoffset;
|
||||||
|
int nodelen;
|
||||||
|
int err;
|
||||||
|
uint32_t tag;
|
||||||
|
fdt32_t *endtag;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
|
||||||
|
if (offset >= 0)
|
||||||
|
return -FDT_ERR_EXISTS;
|
||||||
|
else if (offset != -FDT_ERR_NOTFOUND)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
/* Try to place the new node after the parent's properties */
|
||||||
|
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
|
||||||
|
do {
|
||||||
|
offset = nextoffset;
|
||||||
|
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||||
|
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
|
||||||
|
|
||||||
|
nh = _fdt_offset_ptr_w(fdt, offset);
|
||||||
|
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
|
||||||
|
|
||||||
|
err = _fdt_splice_struct(fdt, nh, 0, nodelen);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
|
||||||
|
memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
|
||||||
|
memcpy(nh->name, name, namelen);
|
||||||
|
endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
|
||||||
|
*endtag = cpu_to_fdt32(FDT_END_NODE);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
|
||||||
|
{
|
||||||
|
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_del_node(void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
int endoffset;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
|
||||||
|
if (endoffset < 0)
|
||||||
|
return endoffset;
|
||||||
|
|
||||||
|
return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
|
||||||
|
endoffset - nodeoffset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _fdt_packblocks(const char *old, char *new,
|
||||||
|
int mem_rsv_size, int struct_size)
|
||||||
|
{
|
||||||
|
int mem_rsv_off, struct_off, strings_off;
|
||||||
|
|
||||||
|
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
|
||||||
|
struct_off = mem_rsv_off + mem_rsv_size;
|
||||||
|
strings_off = struct_off + struct_size;
|
||||||
|
|
||||||
|
memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
|
||||||
|
fdt_set_off_mem_rsvmap(new, mem_rsv_off);
|
||||||
|
|
||||||
|
memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
|
||||||
|
fdt_set_off_dt_struct(new, struct_off);
|
||||||
|
fdt_set_size_dt_struct(new, struct_size);
|
||||||
|
|
||||||
|
memmove(new + strings_off, old + fdt_off_dt_strings(old),
|
||||||
|
fdt_size_dt_strings(old));
|
||||||
|
fdt_set_off_dt_strings(new, strings_off);
|
||||||
|
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
int mem_rsv_size, struct_size;
|
||||||
|
int newsize;
|
||||||
|
const char *fdtstart = fdt;
|
||||||
|
const char *fdtend = fdtstart + fdt_totalsize(fdt);
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||||
|
* sizeof(struct fdt_reserve_entry);
|
||||||
|
|
||||||
|
if (fdt_version(fdt) >= 17) {
|
||||||
|
struct_size = fdt_size_dt_struct(fdt);
|
||||||
|
} else {
|
||||||
|
struct_size = 0;
|
||||||
|
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
|
||||||
|
;
|
||||||
|
if (struct_size < 0)
|
||||||
|
return struct_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
|
||||||
|
/* no further work necessary */
|
||||||
|
err = fdt_move(fdt, buf, bufsize);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
fdt_set_version(buf, 17);
|
||||||
|
fdt_set_size_dt_struct(buf, struct_size);
|
||||||
|
fdt_set_totalsize(buf, bufsize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to reorder */
|
||||||
|
newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
|
||||||
|
+ struct_size + fdt_size_dt_strings(fdt);
|
||||||
|
|
||||||
|
if (bufsize < newsize)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
/* First attempt to build converted tree at beginning of buffer */
|
||||||
|
tmp = buf;
|
||||||
|
/* But if that overlaps with the old tree... */
|
||||||
|
if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
|
||||||
|
/* Try right after the old tree instead */
|
||||||
|
tmp = (char *)(uintptr_t)fdtend;
|
||||||
|
if ((tmp + newsize) > ((char *)buf + bufsize))
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
|
||||||
|
memmove(buf, tmp, newsize);
|
||||||
|
|
||||||
|
fdt_set_magic(buf, FDT_MAGIC);
|
||||||
|
fdt_set_totalsize(buf, bufsize);
|
||||||
|
fdt_set_version(buf, 17);
|
||||||
|
fdt_set_last_comp_version(buf, 16);
|
||||||
|
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_pack(void *fdt)
|
||||||
|
{
|
||||||
|
int mem_rsv_size;
|
||||||
|
|
||||||
|
FDT_RW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||||
|
* sizeof(struct fdt_reserve_entry);
|
||||||
|
_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
|
||||||
|
fdt_set_totalsize(fdt, _fdt_data_size(fdt));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
102
dtc-1.4.5/libfdt/fdt_strerror.c
Normal file
102
dtc-1.4.5/libfdt/fdt_strerror.c
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
struct fdt_errtabent {
|
||||||
|
const char *str;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FDT_ERRTABENT(val) \
|
||||||
|
[(val)] = { .str = #val, }
|
||||||
|
|
||||||
|
static struct fdt_errtabent fdt_errtable[] = {
|
||||||
|
FDT_ERRTABENT(FDT_ERR_NOTFOUND),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_EXISTS),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_NOSPACE),
|
||||||
|
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADPATH),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADSTATE),
|
||||||
|
|
||||||
|
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADMAGIC),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADVERSION),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_INTERNAL),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADVALUE),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
|
||||||
|
};
|
||||||
|
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
|
||||||
|
|
||||||
|
const char *fdt_strerror(int errval)
|
||||||
|
{
|
||||||
|
if (errval > 0)
|
||||||
|
return "<valid offset/length>";
|
||||||
|
else if (errval == 0)
|
||||||
|
return "<no error>";
|
||||||
|
else if (errval > -FDT_ERRTABSIZE) {
|
||||||
|
const char *s = fdt_errtable[-errval].str;
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<unknown error>";
|
||||||
|
}
|
||||||
300
dtc-1.4.5/libfdt/fdt_sw.c
Normal file
300
dtc-1.4.5/libfdt/fdt_sw.c
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
static int _fdt_sw_check_header(void *fdt)
|
||||||
|
{
|
||||||
|
if (fdt_magic(fdt) != FDT_SW_MAGIC)
|
||||||
|
return -FDT_ERR_BADMAGIC;
|
||||||
|
/* FIXME: should check more details about the header state */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FDT_SW_CHECK_HEADER(fdt) \
|
||||||
|
{ \
|
||||||
|
int err; \
|
||||||
|
if ((err = _fdt_sw_check_header(fdt)) != 0) \
|
||||||
|
return err; \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_fdt_grab_space(void *fdt, size_t len)
|
||||||
|
{
|
||||||
|
int offset = fdt_size_dt_struct(fdt);
|
||||||
|
int spaceleft;
|
||||||
|
|
||||||
|
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
|
||||||
|
- fdt_size_dt_strings(fdt);
|
||||||
|
|
||||||
|
if ((offset + len < offset) || (offset + len > spaceleft))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fdt_set_size_dt_struct(fdt, offset + len);
|
||||||
|
return _fdt_offset_ptr_w(fdt, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_create(void *buf, int bufsize)
|
||||||
|
{
|
||||||
|
void *fdt = buf;
|
||||||
|
|
||||||
|
if (bufsize < sizeof(struct fdt_header))
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
memset(buf, 0, bufsize);
|
||||||
|
|
||||||
|
fdt_set_magic(fdt, FDT_SW_MAGIC);
|
||||||
|
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
|
||||||
|
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
|
||||||
|
fdt_set_totalsize(fdt, bufsize);
|
||||||
|
|
||||||
|
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
|
||||||
|
sizeof(struct fdt_reserve_entry)));
|
||||||
|
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
|
||||||
|
fdt_set_off_dt_strings(fdt, bufsize);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||||
|
{
|
||||||
|
size_t headsize, tailsize;
|
||||||
|
char *oldtail, *newtail;
|
||||||
|
|
||||||
|
FDT_SW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
headsize = fdt_off_dt_struct(fdt);
|
||||||
|
tailsize = fdt_size_dt_strings(fdt);
|
||||||
|
|
||||||
|
if ((headsize + tailsize) > bufsize)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
|
||||||
|
newtail = (char *)buf + bufsize - tailsize;
|
||||||
|
|
||||||
|
/* Two cases to avoid clobbering data if the old and new
|
||||||
|
* buffers partially overlap */
|
||||||
|
if (buf <= fdt) {
|
||||||
|
memmove(buf, fdt, headsize);
|
||||||
|
memmove(newtail, oldtail, tailsize);
|
||||||
|
} else {
|
||||||
|
memmove(newtail, oldtail, tailsize);
|
||||||
|
memmove(buf, fdt, headsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_set_off_dt_strings(buf, bufsize);
|
||||||
|
fdt_set_totalsize(buf, bufsize);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
|
||||||
|
{
|
||||||
|
struct fdt_reserve_entry *re;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
FDT_SW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
if (fdt_size_dt_struct(fdt))
|
||||||
|
return -FDT_ERR_BADSTATE;
|
||||||
|
|
||||||
|
offset = fdt_off_dt_struct(fdt);
|
||||||
|
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
re = (struct fdt_reserve_entry *)((char *)fdt + offset);
|
||||||
|
re->address = cpu_to_fdt64(addr);
|
||||||
|
re->size = cpu_to_fdt64(size);
|
||||||
|
|
||||||
|
fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_finish_reservemap(void *fdt)
|
||||||
|
{
|
||||||
|
return fdt_add_reservemap_entry(fdt, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_begin_node(void *fdt, const char *name)
|
||||||
|
{
|
||||||
|
struct fdt_node_header *nh;
|
||||||
|
int namelen = strlen(name) + 1;
|
||||||
|
|
||||||
|
FDT_SW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
|
||||||
|
if (! nh)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
|
||||||
|
memcpy(nh->name, name, namelen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_end_node(void *fdt)
|
||||||
|
{
|
||||||
|
fdt32_t *en;
|
||||||
|
|
||||||
|
FDT_SW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
en = _fdt_grab_space(fdt, FDT_TAGSIZE);
|
||||||
|
if (! en)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
*en = cpu_to_fdt32(FDT_END_NODE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fdt_find_add_string(void *fdt, const char *s)
|
||||||
|
{
|
||||||
|
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
||||||
|
const char *p;
|
||||||
|
int strtabsize = fdt_size_dt_strings(fdt);
|
||||||
|
int len = strlen(s) + 1;
|
||||||
|
int struct_top, offset;
|
||||||
|
|
||||||
|
p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
|
||||||
|
if (p)
|
||||||
|
return p - strtab;
|
||||||
|
|
||||||
|
/* Add it */
|
||||||
|
offset = -strtabsize - len;
|
||||||
|
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||||
|
if (fdt_totalsize(fdt) + offset < struct_top)
|
||||||
|
return 0; /* no more room :( */
|
||||||
|
|
||||||
|
memcpy(strtab + offset, s, len);
|
||||||
|
fdt_set_size_dt_strings(fdt, strtabsize + len);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
|
||||||
|
{
|
||||||
|
struct fdt_property *prop;
|
||||||
|
int nameoff;
|
||||||
|
|
||||||
|
FDT_SW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
nameoff = _fdt_find_add_string(fdt, name);
|
||||||
|
if (nameoff == 0)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
|
||||||
|
if (! prop)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
prop->tag = cpu_to_fdt32(FDT_PROP);
|
||||||
|
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||||
|
prop->len = cpu_to_fdt32(len);
|
||||||
|
*valp = prop->data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = fdt_property_placeholder(fdt, name, len, &ptr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
memcpy(ptr, val, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_finish(void *fdt)
|
||||||
|
{
|
||||||
|
char *p = (char *)fdt;
|
||||||
|
fdt32_t *end;
|
||||||
|
int oldstroffset, newstroffset;
|
||||||
|
uint32_t tag;
|
||||||
|
int offset, nextoffset;
|
||||||
|
|
||||||
|
FDT_SW_CHECK_HEADER(fdt);
|
||||||
|
|
||||||
|
/* Add terminator */
|
||||||
|
end = _fdt_grab_space(fdt, sizeof(*end));
|
||||||
|
if (! end)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
*end = cpu_to_fdt32(FDT_END);
|
||||||
|
|
||||||
|
/* Relocate the string table */
|
||||||
|
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
|
||||||
|
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||||
|
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
|
||||||
|
fdt_set_off_dt_strings(fdt, newstroffset);
|
||||||
|
|
||||||
|
/* Walk the structure, correcting string offsets */
|
||||||
|
offset = 0;
|
||||||
|
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
|
||||||
|
if (tag == FDT_PROP) {
|
||||||
|
struct fdt_property *prop =
|
||||||
|
_fdt_offset_ptr_w(fdt, offset);
|
||||||
|
int nameoff;
|
||||||
|
|
||||||
|
nameoff = fdt32_to_cpu(prop->nameoff);
|
||||||
|
nameoff += fdt_size_dt_strings(fdt);
|
||||||
|
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||||
|
}
|
||||||
|
offset = nextoffset;
|
||||||
|
}
|
||||||
|
if (nextoffset < 0)
|
||||||
|
return nextoffset;
|
||||||
|
|
||||||
|
/* Finally, adjust the header */
|
||||||
|
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
|
||||||
|
fdt_set_magic(fdt, FDT_MAGIC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
139
dtc-1.4.5/libfdt/fdt_wip.c
Normal file
139
dtc-1.4.5/libfdt/fdt_wip.c
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "libfdt_env.h"
|
||||||
|
|
||||||
|
#include <fdt.h>
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "libfdt_internal.h"
|
||||||
|
|
||||||
|
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||||
|
const char *name, int namelen,
|
||||||
|
uint32_t idx, const void *val,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
void *propval;
|
||||||
|
int proplen;
|
||||||
|
|
||||||
|
propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
|
||||||
|
&proplen);
|
||||||
|
if (!propval)
|
||||||
|
return proplen;
|
||||||
|
|
||||||
|
if (proplen < (len + idx))
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
memcpy((char *)propval + idx, val, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||||
|
const void *val, int len)
|
||||||
|
{
|
||||||
|
const void *propval;
|
||||||
|
int proplen;
|
||||||
|
|
||||||
|
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
|
||||||
|
if (!propval)
|
||||||
|
return proplen;
|
||||||
|
|
||||||
|
if (proplen != len)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
|
||||||
|
strlen(name), 0,
|
||||||
|
val, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _fdt_nop_region(void *start, int len)
|
||||||
|
{
|
||||||
|
fdt32_t *p;
|
||||||
|
|
||||||
|
for (p = start; (char *)p < ((char *)start + len); p++)
|
||||||
|
*p = cpu_to_fdt32(FDT_NOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
|
||||||
|
{
|
||||||
|
struct fdt_property *prop;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||||
|
if (!prop)
|
||||||
|
return len;
|
||||||
|
|
||||||
|
_fdt_nop_region(prop, len + sizeof(*prop));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fdt_node_end_offset(void *fdt, int offset)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
while ((offset >= 0) && (depth >= 0))
|
||||||
|
offset = fdt_next_node(fdt, offset, &depth);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_nop_node(void *fdt, int nodeoffset)
|
||||||
|
{
|
||||||
|
int endoffset;
|
||||||
|
|
||||||
|
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
|
||||||
|
if (endoffset < 0)
|
||||||
|
return endoffset;
|
||||||
|
|
||||||
|
_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
|
||||||
|
endoffset - nodeoffset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1899
dtc-1.4.5/libfdt/libfdt.h
Normal file
1899
dtc-1.4.5/libfdt/libfdt.h
Normal file
File diff suppressed because it is too large
Load Diff
112
dtc-1.4.5/libfdt/libfdt_env.h
Normal file
112
dtc-1.4.5/libfdt/libfdt_env.h
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#ifndef _LIBFDT_ENV_H
|
||||||
|
#define _LIBFDT_ENV_H
|
||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __CHECKER__
|
||||||
|
#define FDT_FORCE __attribute__((force))
|
||||||
|
#define FDT_BITWISE __attribute__((bitwise))
|
||||||
|
#else
|
||||||
|
#define FDT_FORCE
|
||||||
|
#define FDT_BITWISE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef uint16_t FDT_BITWISE fdt16_t;
|
||||||
|
typedef uint32_t FDT_BITWISE fdt32_t;
|
||||||
|
typedef uint64_t FDT_BITWISE fdt64_t;
|
||||||
|
|
||||||
|
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
|
||||||
|
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
|
||||||
|
#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
|
||||||
|
(EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
|
||||||
|
#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
|
||||||
|
(EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
|
||||||
|
(EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
|
||||||
|
(EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
|
||||||
|
|
||||||
|
static inline uint16_t fdt16_to_cpu(fdt16_t x)
|
||||||
|
{
|
||||||
|
return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
|
||||||
|
}
|
||||||
|
static inline fdt16_t cpu_to_fdt16(uint16_t x)
|
||||||
|
{
|
||||||
|
return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t fdt32_to_cpu(fdt32_t x)
|
||||||
|
{
|
||||||
|
return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
|
||||||
|
}
|
||||||
|
static inline fdt32_t cpu_to_fdt32(uint32_t x)
|
||||||
|
{
|
||||||
|
return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t fdt64_to_cpu(fdt64_t x)
|
||||||
|
{
|
||||||
|
return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
|
||||||
|
}
|
||||||
|
static inline fdt64_t cpu_to_fdt64(uint64_t x)
|
||||||
|
{
|
||||||
|
return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
|
||||||
|
}
|
||||||
|
#undef CPU_TO_FDT64
|
||||||
|
#undef CPU_TO_FDT32
|
||||||
|
#undef CPU_TO_FDT16
|
||||||
|
#undef EXTRACT_BYTE
|
||||||
|
|
||||||
|
#endif /* _LIBFDT_ENV_H */
|
||||||
95
dtc-1.4.5/libfdt/libfdt_internal.h
Normal file
95
dtc-1.4.5/libfdt/libfdt_internal.h
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#ifndef _LIBFDT_INTERNAL_H
|
||||||
|
#define _LIBFDT_INTERNAL_H
|
||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include <fdt.h>
|
||||||
|
|
||||||
|
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||||
|
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
||||||
|
|
||||||
|
#define FDT_CHECK_HEADER(fdt) \
|
||||||
|
{ \
|
||||||
|
int __err; \
|
||||||
|
if ((__err = fdt_check_header(fdt)) != 0) \
|
||||||
|
return __err; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fdt_check_node_offset(const void *fdt, int offset);
|
||||||
|
int _fdt_check_prop_offset(const void *fdt, int offset);
|
||||||
|
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
|
||||||
|
int _fdt_node_end_offset(void *fdt, int nodeoffset);
|
||||||
|
|
||||||
|
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
|
||||||
|
{
|
||||||
|
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
|
||||||
|
{
|
||||||
|
return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
|
||||||
|
{
|
||||||
|
const struct fdt_reserve_entry *rsv_table =
|
||||||
|
(const struct fdt_reserve_entry *)
|
||||||
|
((const char *)fdt + fdt_off_mem_rsvmap(fdt));
|
||||||
|
|
||||||
|
return rsv_table + n;
|
||||||
|
}
|
||||||
|
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
|
||||||
|
{
|
||||||
|
return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FDT_SW_MAGIC (~FDT_MAGIC)
|
||||||
|
|
||||||
|
#endif /* _LIBFDT_INTERNAL_H */
|
||||||
68
dtc-1.4.5/libfdt/version.lds
Normal file
68
dtc-1.4.5/libfdt/version.lds
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
LIBFDT_1.2 {
|
||||||
|
global:
|
||||||
|
fdt_next_node;
|
||||||
|
fdt_check_header;
|
||||||
|
fdt_move;
|
||||||
|
fdt_string;
|
||||||
|
fdt_num_mem_rsv;
|
||||||
|
fdt_get_mem_rsv;
|
||||||
|
fdt_subnode_offset_namelen;
|
||||||
|
fdt_subnode_offset;
|
||||||
|
fdt_path_offset_namelen;
|
||||||
|
fdt_path_offset;
|
||||||
|
fdt_get_name;
|
||||||
|
fdt_get_property_namelen;
|
||||||
|
fdt_get_property;
|
||||||
|
fdt_getprop_namelen;
|
||||||
|
fdt_getprop;
|
||||||
|
fdt_get_phandle;
|
||||||
|
fdt_get_alias_namelen;
|
||||||
|
fdt_get_alias;
|
||||||
|
fdt_get_path;
|
||||||
|
fdt_supernode_atdepth_offset;
|
||||||
|
fdt_node_depth;
|
||||||
|
fdt_parent_offset;
|
||||||
|
fdt_node_offset_by_prop_value;
|
||||||
|
fdt_node_offset_by_phandle;
|
||||||
|
fdt_node_check_compatible;
|
||||||
|
fdt_node_offset_by_compatible;
|
||||||
|
fdt_setprop_inplace;
|
||||||
|
fdt_nop_property;
|
||||||
|
fdt_nop_node;
|
||||||
|
fdt_create;
|
||||||
|
fdt_add_reservemap_entry;
|
||||||
|
fdt_finish_reservemap;
|
||||||
|
fdt_begin_node;
|
||||||
|
fdt_property;
|
||||||
|
fdt_end_node;
|
||||||
|
fdt_finish;
|
||||||
|
fdt_open_into;
|
||||||
|
fdt_pack;
|
||||||
|
fdt_add_mem_rsv;
|
||||||
|
fdt_del_mem_rsv;
|
||||||
|
fdt_set_name;
|
||||||
|
fdt_setprop;
|
||||||
|
fdt_delprop;
|
||||||
|
fdt_add_subnode_namelen;
|
||||||
|
fdt_add_subnode;
|
||||||
|
fdt_del_node;
|
||||||
|
fdt_strerror;
|
||||||
|
fdt_offset_ptr;
|
||||||
|
fdt_next_tag;
|
||||||
|
fdt_appendprop;
|
||||||
|
fdt_create_empty_tree;
|
||||||
|
fdt_first_property_offset;
|
||||||
|
fdt_get_property_by_offset;
|
||||||
|
fdt_getprop_by_offset;
|
||||||
|
fdt_next_property_offset;
|
||||||
|
fdt_first_subnode;
|
||||||
|
fdt_next_subnode;
|
||||||
|
fdt_address_cells;
|
||||||
|
fdt_size_cells;
|
||||||
|
fdt_stringlist_contains;
|
||||||
|
fdt_resize;
|
||||||
|
fdt_overlay_apply;
|
||||||
|
|
||||||
|
local:
|
||||||
|
*;
|
||||||
|
};
|
||||||
987
dtc-1.4.5/livetree.c
Normal file
987
dtc-1.4.5/livetree.c
Normal file
@@ -0,0 +1,987 @@
|
|||||||
|
/*
|
||||||
|
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dtc.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tree building functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
void add_label(struct label **labels, char *label)
|
||||||
|
{
|
||||||
|
struct label *new;
|
||||||
|
|
||||||
|
/* Make sure the label isn't already there */
|
||||||
|
for_each_label_withdel(*labels, new)
|
||||||
|
if (streq(new->label, label)) {
|
||||||
|
new->deleted = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = xmalloc(sizeof(*new));
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
|
new->label = label;
|
||||||
|
new->next = *labels;
|
||||||
|
*labels = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_labels(struct label **labels)
|
||||||
|
{
|
||||||
|
struct label *label;
|
||||||
|
|
||||||
|
for_each_label(*labels, label)
|
||||||
|
label->deleted = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct property *build_property(char *name, struct data val)
|
||||||
|
{
|
||||||
|
struct property *new = xmalloc(sizeof(*new));
|
||||||
|
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
|
|
||||||
|
new->name = name;
|
||||||
|
new->val = val;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct property *build_property_delete(char *name)
|
||||||
|
{
|
||||||
|
struct property *new = xmalloc(sizeof(*new));
|
||||||
|
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
|
|
||||||
|
new->name = name;
|
||||||
|
new->deleted = 1;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct property *chain_property(struct property *first, struct property *list)
|
||||||
|
{
|
||||||
|
assert(first->next == NULL);
|
||||||
|
|
||||||
|
first->next = list;
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct property *reverse_properties(struct property *first)
|
||||||
|
{
|
||||||
|
struct property *p = first;
|
||||||
|
struct property *head = NULL;
|
||||||
|
struct property *next;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
next = p->next;
|
||||||
|
p->next = head;
|
||||||
|
head = p;
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *build_node(struct property *proplist, struct node *children)
|
||||||
|
{
|
||||||
|
struct node *new = xmalloc(sizeof(*new));
|
||||||
|
struct node *child;
|
||||||
|
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
|
|
||||||
|
new->proplist = reverse_properties(proplist);
|
||||||
|
new->children = children;
|
||||||
|
|
||||||
|
for_each_child(new, child) {
|
||||||
|
child->parent = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *build_node_delete(void)
|
||||||
|
{
|
||||||
|
struct node *new = xmalloc(sizeof(*new));
|
||||||
|
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
|
|
||||||
|
new->deleted = 1;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *name_node(struct node *node, char *name)
|
||||||
|
{
|
||||||
|
assert(node->name == NULL);
|
||||||
|
|
||||||
|
node->name = name;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *merge_nodes(struct node *old_node, struct node *new_node)
|
||||||
|
{
|
||||||
|
struct property *new_prop, *old_prop;
|
||||||
|
struct node *new_child, *old_child;
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
old_node->deleted = 0;
|
||||||
|
|
||||||
|
/* Add new node labels to old node */
|
||||||
|
for_each_label_withdel(new_node->labels, l)
|
||||||
|
add_label(&old_node->labels, l->label);
|
||||||
|
|
||||||
|
/* Move properties from the new node to the old node. If there
|
||||||
|
* is a collision, replace the old value with the new */
|
||||||
|
while (new_node->proplist) {
|
||||||
|
/* Pop the property off the list */
|
||||||
|
new_prop = new_node->proplist;
|
||||||
|
new_node->proplist = new_prop->next;
|
||||||
|
new_prop->next = NULL;
|
||||||
|
|
||||||
|
if (new_prop->deleted) {
|
||||||
|
delete_property_by_name(old_node, new_prop->name);
|
||||||
|
free(new_prop);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for a collision, set new value if there is */
|
||||||
|
for_each_property_withdel(old_node, old_prop) {
|
||||||
|
if (streq(old_prop->name, new_prop->name)) {
|
||||||
|
/* Add new labels to old property */
|
||||||
|
for_each_label_withdel(new_prop->labels, l)
|
||||||
|
add_label(&old_prop->labels, l->label);
|
||||||
|
|
||||||
|
old_prop->val = new_prop->val;
|
||||||
|
old_prop->deleted = 0;
|
||||||
|
free(new_prop);
|
||||||
|
new_prop = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if no collision occurred, add property to the old node. */
|
||||||
|
if (new_prop)
|
||||||
|
add_property(old_node, new_prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the override child nodes into the primary node. If
|
||||||
|
* there is a collision, then merge the nodes. */
|
||||||
|
while (new_node->children) {
|
||||||
|
/* Pop the child node off the list */
|
||||||
|
new_child = new_node->children;
|
||||||
|
new_node->children = new_child->next_sibling;
|
||||||
|
new_child->parent = NULL;
|
||||||
|
new_child->next_sibling = NULL;
|
||||||
|
|
||||||
|
if (new_child->deleted) {
|
||||||
|
delete_node_by_name(old_node, new_child->name);
|
||||||
|
free(new_child);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for a collision. Merge if there is */
|
||||||
|
for_each_child_withdel(old_node, old_child) {
|
||||||
|
if (streq(old_child->name, new_child->name)) {
|
||||||
|
merge_nodes(old_child, new_child);
|
||||||
|
new_child = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if no collision occurred, add child to the old node. */
|
||||||
|
if (new_child)
|
||||||
|
add_child(old_node, new_child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The new node contents are now merged into the old node. Free
|
||||||
|
* the new node. */
|
||||||
|
free(new_node);
|
||||||
|
|
||||||
|
return old_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *chain_node(struct node *first, struct node *list)
|
||||||
|
{
|
||||||
|
assert(first->next_sibling == NULL);
|
||||||
|
|
||||||
|
first->next_sibling = list;
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_property(struct node *node, struct property *prop)
|
||||||
|
{
|
||||||
|
struct property **p;
|
||||||
|
|
||||||
|
prop->next = NULL;
|
||||||
|
|
||||||
|
p = &node->proplist;
|
||||||
|
while (*p)
|
||||||
|
p = &((*p)->next);
|
||||||
|
|
||||||
|
*p = prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_property_by_name(struct node *node, char *name)
|
||||||
|
{
|
||||||
|
struct property *prop = node->proplist;
|
||||||
|
|
||||||
|
while (prop) {
|
||||||
|
if (streq(prop->name, name)) {
|
||||||
|
delete_property(prop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prop = prop->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_property(struct property *prop)
|
||||||
|
{
|
||||||
|
prop->deleted = 1;
|
||||||
|
delete_labels(&prop->labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_child(struct node *parent, struct node *child)
|
||||||
|
{
|
||||||
|
struct node **p;
|
||||||
|
|
||||||
|
child->next_sibling = NULL;
|
||||||
|
child->parent = parent;
|
||||||
|
|
||||||
|
p = &parent->children;
|
||||||
|
while (*p)
|
||||||
|
p = &((*p)->next_sibling);
|
||||||
|
|
||||||
|
*p = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_node_by_name(struct node *parent, char *name)
|
||||||
|
{
|
||||||
|
struct node *node = parent->children;
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
if (streq(node->name, name)) {
|
||||||
|
delete_node(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node = node->next_sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_node(struct node *node)
|
||||||
|
{
|
||||||
|
struct property *prop;
|
||||||
|
struct node *child;
|
||||||
|
|
||||||
|
node->deleted = 1;
|
||||||
|
for_each_child(node, child)
|
||||||
|
delete_node(child);
|
||||||
|
for_each_property(node, prop)
|
||||||
|
delete_property(prop);
|
||||||
|
delete_labels(&node->labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append_to_property(struct node *node,
|
||||||
|
char *name, const void *data, int len)
|
||||||
|
{
|
||||||
|
struct data d;
|
||||||
|
struct property *p;
|
||||||
|
|
||||||
|
p = get_property(node, name);
|
||||||
|
if (p) {
|
||||||
|
d = data_append_data(p->val, data, len);
|
||||||
|
p->val = d;
|
||||||
|
} else {
|
||||||
|
d = data_append_data(empty_data, data, len);
|
||||||
|
p = build_property(name, d);
|
||||||
|
add_property(node, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
|
||||||
|
{
|
||||||
|
struct reserve_info *new = xmalloc(sizeof(*new));
|
||||||
|
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
|
|
||||||
|
new->address = address;
|
||||||
|
new->size = size;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reserve_info *chain_reserve_entry(struct reserve_info *first,
|
||||||
|
struct reserve_info *list)
|
||||||
|
{
|
||||||
|
assert(first->next == NULL);
|
||||||
|
|
||||||
|
first->next = list;
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reserve_info *add_reserve_entry(struct reserve_info *list,
|
||||||
|
struct reserve_info *new)
|
||||||
|
{
|
||||||
|
struct reserve_info *last;
|
||||||
|
|
||||||
|
new->next = NULL;
|
||||||
|
|
||||||
|
if (! list)
|
||||||
|
return new;
|
||||||
|
|
||||||
|
for (last = list; last->next; last = last->next)
|
||||||
|
;
|
||||||
|
|
||||||
|
last->next = new;
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dt_info *build_dt_info(unsigned int dtsflags,
|
||||||
|
struct reserve_info *reservelist,
|
||||||
|
struct node *tree, uint32_t boot_cpuid_phys)
|
||||||
|
{
|
||||||
|
struct dt_info *dti;
|
||||||
|
|
||||||
|
dti = xmalloc(sizeof(*dti));
|
||||||
|
dti->dtsflags = dtsflags;
|
||||||
|
dti->reservelist = reservelist;
|
||||||
|
dti->dt = tree;
|
||||||
|
dti->boot_cpuid_phys = boot_cpuid_phys;
|
||||||
|
|
||||||
|
return dti;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tree accessor functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *get_unitname(struct node *node)
|
||||||
|
{
|
||||||
|
if (node->name[node->basenamelen] == '\0')
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
return node->name + node->basenamelen + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct property *get_property(struct node *node, const char *propname)
|
||||||
|
{
|
||||||
|
struct property *prop;
|
||||||
|
|
||||||
|
for_each_property(node, prop)
|
||||||
|
if (streq(prop->name, propname))
|
||||||
|
return prop;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t propval_cell(struct property *prop)
|
||||||
|
{
|
||||||
|
assert(prop->val.len == sizeof(cell_t));
|
||||||
|
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t propval_cell_n(struct property *prop, int n)
|
||||||
|
{
|
||||||
|
assert(prop->val.len / sizeof(cell_t) >= n);
|
||||||
|
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct property *get_property_by_label(struct node *tree, const char *label,
|
||||||
|
struct node **node)
|
||||||
|
{
|
||||||
|
struct property *prop;
|
||||||
|
struct node *c;
|
||||||
|
|
||||||
|
*node = tree;
|
||||||
|
|
||||||
|
for_each_property(tree, prop) {
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
for_each_label(prop->labels, l)
|
||||||
|
if (streq(l->label, label))
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(tree, c) {
|
||||||
|
prop = get_property_by_label(c, label, node);
|
||||||
|
if (prop)
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
*node = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct marker *get_marker_label(struct node *tree, const char *label,
|
||||||
|
struct node **node, struct property **prop)
|
||||||
|
{
|
||||||
|
struct marker *m;
|
||||||
|
struct property *p;
|
||||||
|
struct node *c;
|
||||||
|
|
||||||
|
*node = tree;
|
||||||
|
|
||||||
|
for_each_property(tree, p) {
|
||||||
|
*prop = p;
|
||||||
|
m = p->val.markers;
|
||||||
|
for_each_marker_of_type(m, LABEL)
|
||||||
|
if (streq(m->ref, label))
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(tree, c) {
|
||||||
|
m = get_marker_label(c, label, node, prop);
|
||||||
|
if (m)
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
*prop = NULL;
|
||||||
|
*node = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *get_subnode(struct node *node, const char *nodename)
|
||||||
|
{
|
||||||
|
struct node *child;
|
||||||
|
|
||||||
|
for_each_child(node, child)
|
||||||
|
if (streq(child->name, nodename))
|
||||||
|
return child;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *get_node_by_path(struct node *tree, const char *path)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
struct node *child;
|
||||||
|
|
||||||
|
if (!path || ! (*path)) {
|
||||||
|
if (tree->deleted)
|
||||||
|
return NULL;
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (path[0] == '/')
|
||||||
|
path++;
|
||||||
|
|
||||||
|
p = strchr(path, '/');
|
||||||
|
|
||||||
|
for_each_child(tree, child) {
|
||||||
|
if (p && (strlen(child->name) == p-path) &&
|
||||||
|
strneq(path, child->name, p-path))
|
||||||
|
return get_node_by_path(child, p+1);
|
||||||
|
else if (!p && streq(path, child->name))
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *get_node_by_label(struct node *tree, const char *label)
|
||||||
|
{
|
||||||
|
struct node *child, *node;
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
assert(label && (strlen(label) > 0));
|
||||||
|
|
||||||
|
for_each_label(tree->labels, l)
|
||||||
|
if (streq(l->label, label))
|
||||||
|
return tree;
|
||||||
|
|
||||||
|
for_each_child(tree, child) {
|
||||||
|
node = get_node_by_label(child, label);
|
||||||
|
if (node)
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
|
||||||
|
{
|
||||||
|
struct node *child, *node;
|
||||||
|
|
||||||
|
assert((phandle != 0) && (phandle != -1));
|
||||||
|
|
||||||
|
if (tree->phandle == phandle) {
|
||||||
|
if (tree->deleted)
|
||||||
|
return NULL;
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(tree, child) {
|
||||||
|
node = get_node_by_phandle(child, phandle);
|
||||||
|
if (node)
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node *get_node_by_ref(struct node *tree, const char *ref)
|
||||||
|
{
|
||||||
|
if (streq(ref, "/"))
|
||||||
|
return tree;
|
||||||
|
else if (ref[0] == '/')
|
||||||
|
return get_node_by_path(tree, ref);
|
||||||
|
else
|
||||||
|
return get_node_by_label(tree, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t get_node_phandle(struct node *root, struct node *node)
|
||||||
|
{
|
||||||
|
static cell_t phandle = 1; /* FIXME: ick, static local */
|
||||||
|
|
||||||
|
if ((node->phandle != 0) && (node->phandle != -1))
|
||||||
|
return node->phandle;
|
||||||
|
|
||||||
|
while (get_node_by_phandle(root, phandle))
|
||||||
|
phandle++;
|
||||||
|
|
||||||
|
node->phandle = phandle;
|
||||||
|
|
||||||
|
if (!get_property(node, "linux,phandle")
|
||||||
|
&& (phandle_format & PHANDLE_LEGACY))
|
||||||
|
add_property(node,
|
||||||
|
build_property("linux,phandle",
|
||||||
|
data_append_cell(empty_data, phandle)));
|
||||||
|
|
||||||
|
if (!get_property(node, "phandle")
|
||||||
|
&& (phandle_format & PHANDLE_EPAPR))
|
||||||
|
add_property(node,
|
||||||
|
build_property("phandle",
|
||||||
|
data_append_cell(empty_data, phandle)));
|
||||||
|
|
||||||
|
/* If the node *does* have a phandle property, we must
|
||||||
|
* be dealing with a self-referencing phandle, which will be
|
||||||
|
* fixed up momentarily in the caller */
|
||||||
|
|
||||||
|
return node->phandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t guess_boot_cpuid(struct node *tree)
|
||||||
|
{
|
||||||
|
struct node *cpus, *bootcpu;
|
||||||
|
struct property *reg;
|
||||||
|
|
||||||
|
cpus = get_node_by_path(tree, "/cpus");
|
||||||
|
if (!cpus)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
bootcpu = cpus->children;
|
||||||
|
if (!bootcpu)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
reg = get_property(bootcpu, "reg");
|
||||||
|
if (!reg || (reg->val.len != sizeof(uint32_t)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* FIXME: Sanity check node? */
|
||||||
|
|
||||||
|
return propval_cell(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_reserve_info(const void *ax, const void *bx)
|
||||||
|
{
|
||||||
|
const struct reserve_info *a, *b;
|
||||||
|
|
||||||
|
a = *((const struct reserve_info * const *)ax);
|
||||||
|
b = *((const struct reserve_info * const *)bx);
|
||||||
|
|
||||||
|
if (a->address < b->address)
|
||||||
|
return -1;
|
||||||
|
else if (a->address > b->address)
|
||||||
|
return 1;
|
||||||
|
else if (a->size < b->size)
|
||||||
|
return -1;
|
||||||
|
else if (a->size > b->size)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_reserve_entries(struct dt_info *dti)
|
||||||
|
{
|
||||||
|
struct reserve_info *ri, **tbl;
|
||||||
|
int n = 0, i = 0;
|
||||||
|
|
||||||
|
for (ri = dti->reservelist;
|
||||||
|
ri;
|
||||||
|
ri = ri->next)
|
||||||
|
n++;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tbl = xmalloc(n * sizeof(*tbl));
|
||||||
|
|
||||||
|
for (ri = dti->reservelist;
|
||||||
|
ri;
|
||||||
|
ri = ri->next)
|
||||||
|
tbl[i++] = ri;
|
||||||
|
|
||||||
|
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
|
||||||
|
|
||||||
|
dti->reservelist = tbl[0];
|
||||||
|
for (i = 0; i < (n-1); i++)
|
||||||
|
tbl[i]->next = tbl[i+1];
|
||||||
|
tbl[n-1]->next = NULL;
|
||||||
|
|
||||||
|
free(tbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_prop(const void *ax, const void *bx)
|
||||||
|
{
|
||||||
|
const struct property *a, *b;
|
||||||
|
|
||||||
|
a = *((const struct property * const *)ax);
|
||||||
|
b = *((const struct property * const *)bx);
|
||||||
|
|
||||||
|
return strcmp(a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_properties(struct node *node)
|
||||||
|
{
|
||||||
|
int n = 0, i = 0;
|
||||||
|
struct property *prop, **tbl;
|
||||||
|
|
||||||
|
for_each_property_withdel(node, prop)
|
||||||
|
n++;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tbl = xmalloc(n * sizeof(*tbl));
|
||||||
|
|
||||||
|
for_each_property_withdel(node, prop)
|
||||||
|
tbl[i++] = prop;
|
||||||
|
|
||||||
|
qsort(tbl, n, sizeof(*tbl), cmp_prop);
|
||||||
|
|
||||||
|
node->proplist = tbl[0];
|
||||||
|
for (i = 0; i < (n-1); i++)
|
||||||
|
tbl[i]->next = tbl[i+1];
|
||||||
|
tbl[n-1]->next = NULL;
|
||||||
|
|
||||||
|
free(tbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_subnode(const void *ax, const void *bx)
|
||||||
|
{
|
||||||
|
const struct node *a, *b;
|
||||||
|
|
||||||
|
a = *((const struct node * const *)ax);
|
||||||
|
b = *((const struct node * const *)bx);
|
||||||
|
|
||||||
|
return strcmp(a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_subnodes(struct node *node)
|
||||||
|
{
|
||||||
|
int n = 0, i = 0;
|
||||||
|
struct node *subnode, **tbl;
|
||||||
|
|
||||||
|
for_each_child_withdel(node, subnode)
|
||||||
|
n++;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tbl = xmalloc(n * sizeof(*tbl));
|
||||||
|
|
||||||
|
for_each_child_withdel(node, subnode)
|
||||||
|
tbl[i++] = subnode;
|
||||||
|
|
||||||
|
qsort(tbl, n, sizeof(*tbl), cmp_subnode);
|
||||||
|
|
||||||
|
node->children = tbl[0];
|
||||||
|
for (i = 0; i < (n-1); i++)
|
||||||
|
tbl[i]->next_sibling = tbl[i+1];
|
||||||
|
tbl[n-1]->next_sibling = NULL;
|
||||||
|
|
||||||
|
free(tbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_node(struct node *node)
|
||||||
|
{
|
||||||
|
struct node *c;
|
||||||
|
|
||||||
|
sort_properties(node);
|
||||||
|
sort_subnodes(node);
|
||||||
|
for_each_child_withdel(node, c)
|
||||||
|
sort_node(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sort_tree(struct dt_info *dti)
|
||||||
|
{
|
||||||
|
sort_reserve_entries(dti);
|
||||||
|
sort_node(dti->dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* utility helper to avoid code duplication */
|
||||||
|
static struct node *build_and_name_child_node(struct node *parent, char *name)
|
||||||
|
{
|
||||||
|
struct node *node;
|
||||||
|
|
||||||
|
node = build_node(NULL, NULL);
|
||||||
|
name_node(node, xstrdup(name));
|
||||||
|
add_child(parent, node);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct node *build_root_node(struct node *dt, char *name)
|
||||||
|
{
|
||||||
|
struct node *an;
|
||||||
|
|
||||||
|
an = get_subnode(dt, name);
|
||||||
|
if (!an)
|
||||||
|
an = build_and_name_child_node(dt, name);
|
||||||
|
|
||||||
|
if (!an)
|
||||||
|
die("Could not build root node /%s\n", name);
|
||||||
|
|
||||||
|
return an;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool any_label_tree(struct dt_info *dti, struct node *node)
|
||||||
|
{
|
||||||
|
struct node *c;
|
||||||
|
|
||||||
|
if (node->labels)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
if (any_label_tree(dti, c))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_label_tree_internal(struct dt_info *dti,
|
||||||
|
struct node *an, struct node *node,
|
||||||
|
bool allocph)
|
||||||
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
|
struct node *c;
|
||||||
|
struct property *p;
|
||||||
|
struct label *l;
|
||||||
|
|
||||||
|
/* if there are labels */
|
||||||
|
if (node->labels) {
|
||||||
|
|
||||||
|
/* now add the label in the node */
|
||||||
|
for_each_label(node->labels, l) {
|
||||||
|
|
||||||
|
/* check whether the label already exists */
|
||||||
|
p = get_property(an, l->label);
|
||||||
|
if (p) {
|
||||||
|
fprintf(stderr, "WARNING: label %s already"
|
||||||
|
" exists in /%s", l->label,
|
||||||
|
an->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* insert it */
|
||||||
|
p = build_property(l->label,
|
||||||
|
data_copy_mem(node->fullpath,
|
||||||
|
strlen(node->fullpath) + 1));
|
||||||
|
add_property(an, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* force allocation of a phandle for this node */
|
||||||
|
if (allocph)
|
||||||
|
(void)get_node_phandle(dt, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
generate_label_tree_internal(dti, an, c, allocph);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool any_fixup_tree(struct dt_info *dti, struct node *node)
|
||||||
|
{
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
if (!get_node_by_ref(dti->dt, m->ref))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c) {
|
||||||
|
if (any_fixup_tree(dti, c))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_fixup_entry(struct dt_info *dti, struct node *fn,
|
||||||
|
struct node *node, struct property *prop,
|
||||||
|
struct marker *m)
|
||||||
|
{
|
||||||
|
char *entry;
|
||||||
|
|
||||||
|
/* m->ref can only be a REF_PHANDLE, but check anyway */
|
||||||
|
assert(m->type == REF_PHANDLE);
|
||||||
|
|
||||||
|
/* there shouldn't be any ':' in the arguments */
|
||||||
|
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
|
||||||
|
die("arguments should not contain ':'\n");
|
||||||
|
|
||||||
|
xasprintf(&entry, "%s:%s:%u",
|
||||||
|
node->fullpath, prop->name, m->offset);
|
||||||
|
append_to_property(fn, m->ref, entry, strlen(entry) + 1);
|
||||||
|
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_fixups_tree_internal(struct dt_info *dti,
|
||||||
|
struct node *fn,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
struct node *refnode;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
|
if (!refnode)
|
||||||
|
add_fixup_entry(dti, fn, node, prop, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
generate_fixups_tree_internal(dti, fn, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
|
||||||
|
{
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
if (get_node_by_ref(dti->dt, m->ref))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c) {
|
||||||
|
if (any_local_fixup_tree(dti, c))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_local_fixup_entry(struct dt_info *dti,
|
||||||
|
struct node *lfn, struct node *node,
|
||||||
|
struct property *prop, struct marker *m,
|
||||||
|
struct node *refnode)
|
||||||
|
{
|
||||||
|
struct node *wn, *nwn; /* local fixup node, walk node, new */
|
||||||
|
fdt32_t value_32;
|
||||||
|
char **compp;
|
||||||
|
int i, depth;
|
||||||
|
|
||||||
|
/* walk back retreiving depth */
|
||||||
|
depth = 0;
|
||||||
|
for (wn = node; wn; wn = wn->parent)
|
||||||
|
depth++;
|
||||||
|
|
||||||
|
/* allocate name array */
|
||||||
|
compp = xmalloc(sizeof(*compp) * depth);
|
||||||
|
|
||||||
|
/* store names in the array */
|
||||||
|
for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
|
||||||
|
compp[i] = wn->name;
|
||||||
|
|
||||||
|
/* walk the path components creating nodes if they don't exist */
|
||||||
|
for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
|
||||||
|
/* if no node exists, create it */
|
||||||
|
nwn = get_subnode(wn, compp[i]);
|
||||||
|
if (!nwn)
|
||||||
|
nwn = build_and_name_child_node(wn, compp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(compp);
|
||||||
|
|
||||||
|
value_32 = cpu_to_fdt32(m->offset);
|
||||||
|
append_to_property(wn, prop->name, &value_32, sizeof(value_32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_local_fixups_tree_internal(struct dt_info *dti,
|
||||||
|
struct node *lfn,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *dt = dti->dt;
|
||||||
|
struct node *c;
|
||||||
|
struct property *prop;
|
||||||
|
struct marker *m;
|
||||||
|
struct node *refnode;
|
||||||
|
|
||||||
|
for_each_property(node, prop) {
|
||||||
|
m = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
|
if (refnode)
|
||||||
|
add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(node, c)
|
||||||
|
generate_local_fixups_tree_internal(dti, lfn, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
|
||||||
|
{
|
||||||
|
if (!any_label_tree(dti, dti->dt))
|
||||||
|
return;
|
||||||
|
generate_label_tree_internal(dti, build_root_node(dti->dt, name),
|
||||||
|
dti->dt, allocph);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_fixups_tree(struct dt_info *dti, char *name)
|
||||||
|
{
|
||||||
|
if (!any_fixup_tree(dti, dti->dt))
|
||||||
|
return;
|
||||||
|
generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
|
||||||
|
dti->dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_local_fixups_tree(struct dt_info *dti, char *name)
|
||||||
|
{
|
||||||
|
if (!any_local_fixup_tree(dti, dti->dt))
|
||||||
|
return;
|
||||||
|
generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
|
||||||
|
dti->dt);
|
||||||
|
}
|
||||||
3
dtc-1.4.5/pylibfdt/.gitignore
vendored
Normal file
3
dtc-1.4.5/pylibfdt/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
libfdt.py
|
||||||
|
libfdt.pyc
|
||||||
|
libfdt_wrap.c
|
||||||
24
dtc-1.4.5/pylibfdt/Makefile.pylibfdt
Normal file
24
dtc-1.4.5/pylibfdt/Makefile.pylibfdt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Makefile.pylibfdt
|
||||||
|
#
|
||||||
|
|
||||||
|
PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \
|
||||||
|
$(PYLIBFDT_srcdir)/libfdt.i
|
||||||
|
PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so
|
||||||
|
|
||||||
|
define run_setup
|
||||||
|
SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)"
|
||||||
|
VERSION="$(dtc_version)"
|
||||||
|
$(PYLIBFDT_objdir)/setup.py --quiet $(2)
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(PYMODULE): $(PYLIBFDT_srcs)
|
||||||
|
@$(VECHO) PYMOD $@
|
||||||
|
$(call run_setup, $^, build_ext --inplace)
|
||||||
|
mv _libfdt.so $@
|
||||||
|
|
||||||
|
install_pylibfdt: $(PYMODULE)
|
||||||
|
$(VECHO) INSTALL-PYLIB; \
|
||||||
|
$(call run_setup, $(PYLIBFDT_srcs), \
|
||||||
|
install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)))
|
||||||
|
|
||||||
|
PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so
|
||||||
493
dtc-1.4.5/pylibfdt/libfdt.i
Normal file
493
dtc-1.4.5/pylibfdt/libfdt.i
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
/*
|
||||||
|
* pylibfdt - Flat Device Tree manipulation in Python
|
||||||
|
* Copyright (C) 2017 Google, Inc.
|
||||||
|
* Written by Simon Glass <sjg@chromium.org>
|
||||||
|
*
|
||||||
|
* libfdt is dual licensed: you can use it either under the terms of
|
||||||
|
* the GPL, or the BSD license, at your option.
|
||||||
|
*
|
||||||
|
* a) This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Alternatively,
|
||||||
|
*
|
||||||
|
* b) Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
%module libfdt
|
||||||
|
|
||||||
|
%include <stdint.i>
|
||||||
|
|
||||||
|
%{
|
||||||
|
#define SWIG_FILE_WITH_INIT
|
||||||
|
#include "libfdt.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%pythoncode %{
|
||||||
|
|
||||||
|
import struct
|
||||||
|
|
||||||
|
# Error codes, corresponding to FDT_ERR_... in libfdt.h
|
||||||
|
(NOTFOUND,
|
||||||
|
EXISTS,
|
||||||
|
NOSPACE,
|
||||||
|
BADOFFSET,
|
||||||
|
BADPATH,
|
||||||
|
BADPHANDLE,
|
||||||
|
BADSTATE,
|
||||||
|
TRUNCATED,
|
||||||
|
BADMAGIC,
|
||||||
|
BADVERSION,
|
||||||
|
BADSTRUCTURE,
|
||||||
|
BADLAYOUT,
|
||||||
|
INTERNAL,
|
||||||
|
BADNCELLS,
|
||||||
|
BADVALUE,
|
||||||
|
BADOVERLAY,
|
||||||
|
NOPHANDLES) = QUIET_ALL = range(1, 18)
|
||||||
|
# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
|
||||||
|
# altogether. All # functions passed this value will return an error instead
|
||||||
|
# of raising an exception.
|
||||||
|
|
||||||
|
# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
|
||||||
|
# instead of raising an exception.
|
||||||
|
QUIET_NOTFOUND = (NOTFOUND,)
|
||||||
|
|
||||||
|
|
||||||
|
class FdtException(Exception):
|
||||||
|
"""An exception caused by an error such as one of the codes above"""
|
||||||
|
def __init__(self, err):
|
||||||
|
self.err = err
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
|
||||||
|
|
||||||
|
def strerror(fdt_err):
|
||||||
|
"""Get the string for an error number
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fdt_err: Error number (-ve)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String containing the associated error
|
||||||
|
"""
|
||||||
|
return fdt_strerror(fdt_err)
|
||||||
|
|
||||||
|
def check_err(val, quiet=()):
|
||||||
|
"""Raise an error if the return value is -ve
|
||||||
|
|
||||||
|
This is used to check for errors returned by libfdt C functions.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
val: Return value from a libfdt function
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
val if val >= 0
|
||||||
|
|
||||||
|
Raises
|
||||||
|
FdtException if val < 0
|
||||||
|
"""
|
||||||
|
if val < 0:
|
||||||
|
if -val not in quiet:
|
||||||
|
raise FdtException(val)
|
||||||
|
return val
|
||||||
|
|
||||||
|
def check_err_null(val, quiet=()):
|
||||||
|
"""Raise an error if the return value is NULL
|
||||||
|
|
||||||
|
This is used to check for a NULL return value from certain libfdt C
|
||||||
|
functions
|
||||||
|
|
||||||
|
Args:
|
||||||
|
val: Return value from a libfdt function
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
val if val is a list, None if not
|
||||||
|
|
||||||
|
Raises
|
||||||
|
FdtException if val indicates an error was reported and the error
|
||||||
|
is not in @quiet.
|
||||||
|
"""
|
||||||
|
# Normally a list is returned which contains the data and its length.
|
||||||
|
# If we get just an integer error code, it means the function failed.
|
||||||
|
if not isinstance(val, list):
|
||||||
|
if -val not in quiet:
|
||||||
|
raise FdtException(val)
|
||||||
|
return val
|
||||||
|
|
||||||
|
class Fdt:
|
||||||
|
"""Device tree class, supporting all operations
|
||||||
|
|
||||||
|
The Fdt object is created is created from a device tree binary file,
|
||||||
|
e.g. with something like:
|
||||||
|
|
||||||
|
fdt = Fdt(open("filename.dtb").read())
|
||||||
|
|
||||||
|
Operations can then be performed using the methods in this class. Each
|
||||||
|
method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
|
||||||
|
|
||||||
|
All methods raise an FdtException if an error occurs. To avoid this
|
||||||
|
behaviour a 'quiet' parameter is provided for some functions. This
|
||||||
|
defaults to empty, but you can pass a list of errors that you expect.
|
||||||
|
If one of these errors occurs, the function will return an error number
|
||||||
|
(e.g. -NOTFOUND).
|
||||||
|
"""
|
||||||
|
def __init__(self, data):
|
||||||
|
self._fdt = bytearray(data)
|
||||||
|
check_err(fdt_check_header(self._fdt));
|
||||||
|
|
||||||
|
def subnode_offset(self, parentoffset, name, quiet=()):
|
||||||
|
"""Get the offset of a named subnode
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parentoffset: Offset of the parent node to check
|
||||||
|
name: Name of the required subnode, e.g. 'subnode@1'
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The node offset of the found node, if any
|
||||||
|
|
||||||
|
Raises
|
||||||
|
FdtException if there is no node with that name, or other error
|
||||||
|
"""
|
||||||
|
return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
|
||||||
|
quiet)
|
||||||
|
|
||||||
|
def path_offset(self, path, quiet=()):
|
||||||
|
"""Get the offset for a given path
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Path to the required node, e.g. '/node@3/subnode@1'
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Node offset
|
||||||
|
|
||||||
|
Raises
|
||||||
|
FdtException if the path is not valid or not found
|
||||||
|
"""
|
||||||
|
return check_err(fdt_path_offset(self._fdt, path), quiet)
|
||||||
|
|
||||||
|
def first_property_offset(self, nodeoffset, quiet=()):
|
||||||
|
"""Get the offset of the first property in a node offset
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Offset to the node to check
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Offset of the first property
|
||||||
|
|
||||||
|
Raises
|
||||||
|
FdtException if the associated node has no properties, or some
|
||||||
|
other error occurred
|
||||||
|
"""
|
||||||
|
return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
|
||||||
|
quiet)
|
||||||
|
|
||||||
|
def next_property_offset(self, prop_offset, quiet=()):
|
||||||
|
"""Get the next property in a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_offset: Offset of the previous property
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Offset of the next property
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if the associated node has no more properties, or
|
||||||
|
some other error occurred
|
||||||
|
"""
|
||||||
|
return check_err(fdt_next_property_offset(self._fdt, prop_offset),
|
||||||
|
quiet)
|
||||||
|
|
||||||
|
def get_name(self, nodeoffset):
|
||||||
|
"""Get the name of a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Offset of node to check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Node name
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException on error (e.g. nodeoffset is invalid)
|
||||||
|
"""
|
||||||
|
return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
|
||||||
|
|
||||||
|
def get_property_by_offset(self, prop_offset, quiet=()):
|
||||||
|
"""Obtains a property that can be examined
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_offset: Offset of property (e.g. from first_property_offset())
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Property object, or None if not found
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException on error (e.g. invalid prop_offset or device
|
||||||
|
tree format)
|
||||||
|
"""
|
||||||
|
pdata = check_err_null(
|
||||||
|
fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
|
||||||
|
if isinstance(pdata, (int)):
|
||||||
|
return pdata
|
||||||
|
return Property(pdata[0], pdata[1])
|
||||||
|
|
||||||
|
def first_subnode(self, nodeoffset, quiet=()):
|
||||||
|
"""Find the first subnode of a parent node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset of parent node
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The offset of the first subnode, if any
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if no subnode found or other error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
|
||||||
|
|
||||||
|
def next_subnode(self, nodeoffset, quiet=()):
|
||||||
|
"""Find the next subnode
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset of previous subnode
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The offset of the next subnode, if any
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if no more subnode found or other error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
|
||||||
|
|
||||||
|
def totalsize(self):
|
||||||
|
"""Return the total size of the device tree
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Total tree size in bytes
|
||||||
|
"""
|
||||||
|
return check_err(fdt_totalsize(self._fdt))
|
||||||
|
|
||||||
|
def off_dt_struct(self):
|
||||||
|
"""Return the start of the device tree struct area
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Start offset of struct area
|
||||||
|
"""
|
||||||
|
return check_err(fdt_off_dt_struct(self._fdt))
|
||||||
|
|
||||||
|
def pack(self, quiet=()):
|
||||||
|
"""Pack the device tree to remove unused space
|
||||||
|
|
||||||
|
This adjusts the tree in place.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if any error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_pack(self._fdt), quiet)
|
||||||
|
|
||||||
|
def delprop(self, nodeoffset, prop_name):
|
||||||
|
"""Delete a property from a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset containing property to delete
|
||||||
|
prop_name: Name of property to delete
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtError if the property does not exist, or another error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
|
||||||
|
|
||||||
|
def getprop(self, nodeoffset, prop_name, quiet=()):
|
||||||
|
"""Get a property from a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset containing property to get
|
||||||
|
prop_name: Name of property to get
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Value of property as a bytearray, or -ve error number
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtError if any error occurs (e.g. the property is not found)
|
||||||
|
"""
|
||||||
|
pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
|
||||||
|
quiet)
|
||||||
|
if isinstance(pdata, (int)):
|
||||||
|
return pdata
|
||||||
|
return bytearray(pdata[0])
|
||||||
|
|
||||||
|
def get_phandle(self, nodeoffset):
|
||||||
|
"""Get the phandle of a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset to check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
phandle of node, or 0 if the node has no phandle or another error
|
||||||
|
occurs
|
||||||
|
"""
|
||||||
|
return fdt_get_phandle(self._fdt, nodeoffset)
|
||||||
|
|
||||||
|
def parent_offset(self, nodeoffset, quiet=()):
|
||||||
|
"""Get the offset of a node's parent
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset to check
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The offset of the parent node, if any
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if no parent found or other error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
|
||||||
|
|
||||||
|
def node_offset_by_phandle(self, phandle, quiet=()):
|
||||||
|
"""Get the offset of a node with the given phandle
|
||||||
|
|
||||||
|
Args:
|
||||||
|
phandle: Phandle to search for
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The offset of node with that phandle, if any
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if no node found or other error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
|
||||||
|
|
||||||
|
class Property:
|
||||||
|
"""Holds a device tree property name and value.
|
||||||
|
|
||||||
|
This holds a copy of a property taken from the device tree. It does not
|
||||||
|
reference the device tree, so if anything changes in the device tree,
|
||||||
|
a Property object will remain valid.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
name: Property name
|
||||||
|
value: Proper value as a bytearray
|
||||||
|
"""
|
||||||
|
def __init__(self, name, value):
|
||||||
|
self.name = name
|
||||||
|
self.value = value
|
||||||
|
%}
|
||||||
|
|
||||||
|
%rename(fdt_property) fdt_property_func;
|
||||||
|
|
||||||
|
typedef int fdt32_t;
|
||||||
|
|
||||||
|
%include "libfdt/fdt.h"
|
||||||
|
|
||||||
|
%include "typemaps.i"
|
||||||
|
|
||||||
|
/* Most functions don't change the device tree, so use a const void * */
|
||||||
|
%typemap(in) (const void *)(const void *fdt) {
|
||||||
|
if (!PyByteArray_Check($input)) {
|
||||||
|
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
|
||||||
|
"', argument " "$argnum"" of type '" "$type""'");
|
||||||
|
}
|
||||||
|
$1 = (void *)PyByteArray_AsString($input);
|
||||||
|
fdt = $1;
|
||||||
|
fdt = fdt; /* avoid unused variable warning */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some functions do change the device tree, so use void * */
|
||||||
|
%typemap(in) (void *)(const void *fdt) {
|
||||||
|
if (!PyByteArray_Check($input)) {
|
||||||
|
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
|
||||||
|
"', argument " "$argnum"" of type '" "$type""'");
|
||||||
|
}
|
||||||
|
$1 = PyByteArray_AsString($input);
|
||||||
|
fdt = $1;
|
||||||
|
fdt = fdt; /* avoid unused variable warning */
|
||||||
|
}
|
||||||
|
|
||||||
|
%typemap(out) (struct fdt_property *) {
|
||||||
|
PyObject *buff;
|
||||||
|
|
||||||
|
if ($1) {
|
||||||
|
resultobj = PyString_FromString(
|
||||||
|
fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
|
||||||
|
buff = PyByteArray_FromStringAndSize(
|
||||||
|
(const char *)($1 + 1), fdt32_to_cpu($1->len));
|
||||||
|
resultobj = SWIG_Python_AppendOutput(resultobj, buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%apply int *OUTPUT { int *lenp };
|
||||||
|
|
||||||
|
/* typemap used for fdt_getprop() */
|
||||||
|
%typemap(out) (const void *) {
|
||||||
|
if (!$1)
|
||||||
|
$result = Py_None;
|
||||||
|
else
|
||||||
|
$result = Py_BuildValue("s#", $1, *arg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have both struct fdt_property and a function fdt_property() */
|
||||||
|
%warnfilter(302) fdt_property;
|
||||||
|
|
||||||
|
/* These are macros in the header so have to be redefined here */
|
||||||
|
int fdt_magic(const void *fdt);
|
||||||
|
int fdt_totalsize(const void *fdt);
|
||||||
|
int fdt_off_dt_struct(const void *fdt);
|
||||||
|
int fdt_off_dt_strings(const void *fdt);
|
||||||
|
int fdt_off_mem_rsvmap(const void *fdt);
|
||||||
|
int fdt_version(const void *fdt);
|
||||||
|
int fdt_last_comp_version(const void *fdt);
|
||||||
|
int fdt_boot_cpuid_phys(const void *fdt);
|
||||||
|
int fdt_size_dt_strings(const void *fdt);
|
||||||
|
int fdt_size_dt_struct(const void *fdt);
|
||||||
|
|
||||||
|
%include <../libfdt/libfdt.h>
|
||||||
121
dtc-1.4.5/pylibfdt/setup.py
Executable file
121
dtc-1.4.5/pylibfdt/setup.py
Executable file
@@ -0,0 +1,121 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
"""
|
||||||
|
setup.py file for SWIG libfdt
|
||||||
|
Copyright (C) 2017 Google, Inc.
|
||||||
|
Written by Simon Glass <sjg@chromium.org>
|
||||||
|
|
||||||
|
Files to be built into the extension are provided in SOURCES
|
||||||
|
C flags to use are provided in CPPFLAGS
|
||||||
|
Object file directory is provided in OBJDIR
|
||||||
|
Version is provided in VERSION
|
||||||
|
|
||||||
|
If these variables are not given they are parsed from the Makefiles. This
|
||||||
|
allows this script to be run stand-alone, e.g.:
|
||||||
|
|
||||||
|
./pylibfdt/setup.py install [--prefix=...]
|
||||||
|
"""
|
||||||
|
|
||||||
|
from distutils.core import setup, Extension
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Decodes a Makefile assignment line into key and value (and plus for +=)
|
||||||
|
RE_KEY_VALUE = re.compile('(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$')
|
||||||
|
|
||||||
|
|
||||||
|
def ParseMakefile(fname):
|
||||||
|
"""Parse a Makefile to obtain its variables.
|
||||||
|
|
||||||
|
This collects variable assigments of the form:
|
||||||
|
|
||||||
|
VAR = value
|
||||||
|
VAR += more
|
||||||
|
|
||||||
|
It does not pick out := assignments, as these are not needed here. It does
|
||||||
|
handle line continuation.
|
||||||
|
|
||||||
|
Returns a dict:
|
||||||
|
key: Variable name (e.g. 'VAR')
|
||||||
|
value: Variable value (e.g. 'value more')
|
||||||
|
"""
|
||||||
|
makevars = {}
|
||||||
|
with open(fname) as fd:
|
||||||
|
prev_text = '' # Continuation text from previous line(s)
|
||||||
|
for line in fd.read().splitlines():
|
||||||
|
if line and line[-1] == '\\': # Deal with line continuation
|
||||||
|
prev_text += line[:-1]
|
||||||
|
continue
|
||||||
|
elif prev_text:
|
||||||
|
line = prev_text + line
|
||||||
|
prev_text = '' # Continuation is now used up
|
||||||
|
m = RE_KEY_VALUE.match(line)
|
||||||
|
if m:
|
||||||
|
value = m.group('value') or ''
|
||||||
|
key = m.group('key')
|
||||||
|
|
||||||
|
# Appending to a variable inserts a space beforehand
|
||||||
|
if 'plus' in m.groupdict() and key in makevars:
|
||||||
|
makevars[key] += ' ' + value
|
||||||
|
else:
|
||||||
|
makevars[key] = value
|
||||||
|
return makevars
|
||||||
|
|
||||||
|
def GetEnvFromMakefiles():
|
||||||
|
"""Scan the Makefiles to obtain the settings we need.
|
||||||
|
|
||||||
|
This assumes that this script is being run from the top-level directory,
|
||||||
|
not the pylibfdt directory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple with:
|
||||||
|
List of swig options
|
||||||
|
Version string
|
||||||
|
List of files to build
|
||||||
|
List of extra C preprocessor flags needed
|
||||||
|
Object directory to use (always '')
|
||||||
|
"""
|
||||||
|
basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
|
||||||
|
swig_opts = ['-I%s' % basedir]
|
||||||
|
makevars = ParseMakefile(os.path.join(basedir, 'Makefile'))
|
||||||
|
version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'],
|
||||||
|
makevars['SUBLEVEL'])
|
||||||
|
makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt'))
|
||||||
|
files = makevars['LIBFDT_SRCS'].split()
|
||||||
|
files = [os.path.join(basedir, 'libfdt', fname) for fname in files]
|
||||||
|
files.append('pylibfdt/libfdt.i')
|
||||||
|
cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir]
|
||||||
|
objdir = ''
|
||||||
|
return swig_opts, version, files, cflags, objdir
|
||||||
|
|
||||||
|
|
||||||
|
progname = sys.argv[0]
|
||||||
|
files = os.environ.get('SOURCES', '').split()
|
||||||
|
cflags = os.environ.get('CPPFLAGS', '').split()
|
||||||
|
objdir = os.environ.get('OBJDIR')
|
||||||
|
version = os.environ.get('VERSION')
|
||||||
|
swig_opts = []
|
||||||
|
|
||||||
|
# If we were called directly rather than through our Makefile (which is often
|
||||||
|
# the case with Python module installation), read the settings from the
|
||||||
|
# Makefile.
|
||||||
|
if not all((version, files, cflags, objdir)):
|
||||||
|
swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles()
|
||||||
|
|
||||||
|
libfdt_module = Extension(
|
||||||
|
'_libfdt',
|
||||||
|
sources = files,
|
||||||
|
extra_compile_args = cflags,
|
||||||
|
swig_opts = swig_opts,
|
||||||
|
)
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='libfdt',
|
||||||
|
version= version,
|
||||||
|
author='Simon Glass <sjg@chromium.org>',
|
||||||
|
description='Python binding for libfdt',
|
||||||
|
ext_modules=[libfdt_module],
|
||||||
|
package_dir={'': objdir},
|
||||||
|
py_modules=['pylibfdt/libfdt'],
|
||||||
|
)
|
||||||
31
dtc-1.4.5/scripts/kup-dtc
Executable file
31
dtc-1.4.5/scripts/kup-dtc
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
REMOTE_GIT=/pub/scm/utils/dtc/dtc.git
|
||||||
|
REMOTE_PATH=/pub/software/utils/dtc
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
kup_one () {
|
||||||
|
VERSION="$1"
|
||||||
|
|
||||||
|
TAG="v$VERSION"
|
||||||
|
|
||||||
|
PREFIX="dtc-$VERSION/"
|
||||||
|
TAR="dtc-$VERSION.tar"
|
||||||
|
SIG="$TAR.sign"
|
||||||
|
|
||||||
|
git archive --format=tar --prefix="$PREFIX" -o "$TAR" "$TAG"
|
||||||
|
gpg --detach-sign --armor -o "$SIG" "$TAR"
|
||||||
|
|
||||||
|
ls -l "$TAR"*
|
||||||
|
|
||||||
|
# Verify the signature as a sanity check
|
||||||
|
gpg --verify "$SIG" "$TAR"
|
||||||
|
|
||||||
|
kup put --tar --prefix="$PREFIX" "$REMOTE_GIT" "$TAG" "$SIG" "$REMOTE_PATH/$TAR.gz"
|
||||||
|
}
|
||||||
|
|
||||||
|
for version; do
|
||||||
|
kup_one $version
|
||||||
|
done
|
||||||
|
|
||||||
22
dtc-1.4.5/scripts/setlocalversion
Executable file
22
dtc-1.4.5/scripts/setlocalversion
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Print additional version information for non-release trees.
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 [srctree]" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cd "${1:-.}" || usage
|
||||||
|
|
||||||
|
# Check for git and a git repo.
|
||||||
|
if head=`git rev-parse --verify HEAD 2>/dev/null`; then
|
||||||
|
# Do we have an untagged version?
|
||||||
|
if git name-rev --tags HEAD | grep -E '^HEAD[[:space:]]+(.*~[0-9]*|undefined)$' > /dev/null; then
|
||||||
|
printf '%s%s' -g `echo "$head" | cut -c1-8`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Are there uncommitted changes?
|
||||||
|
if git diff-index HEAD | read dummy; then
|
||||||
|
printf '%s' -dirty
|
||||||
|
fi
|
||||||
|
fi
|
||||||
302
dtc-1.4.5/srcpos.c
Normal file
302
dtc-1.4.5/srcpos.c
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "dtc.h"
|
||||||
|
#include "srcpos.h"
|
||||||
|
|
||||||
|
/* A node in our list of directories to search for source/include files */
|
||||||
|
struct search_path {
|
||||||
|
struct search_path *next; /* next node in list, NULL for end */
|
||||||
|
const char *dirname; /* name of directory to search */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is the list of directories that we search for source files */
|
||||||
|
static struct search_path *search_path_head, **search_path_tail;
|
||||||
|
|
||||||
|
|
||||||
|
static char *get_dirname(const char *path)
|
||||||
|
{
|
||||||
|
const char *slash = strrchr(path, '/');
|
||||||
|
|
||||||
|
if (slash) {
|
||||||
|
int len = slash - path;
|
||||||
|
char *dir = xmalloc(len + 1);
|
||||||
|
|
||||||
|
memcpy(dir, path, len);
|
||||||
|
dir[len] = '\0';
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *depfile; /* = NULL */
|
||||||
|
struct srcfile_state *current_srcfile; /* = NULL */
|
||||||
|
|
||||||
|
/* Detect infinite include recursion. */
|
||||||
|
#define MAX_SRCFILE_DEPTH (100)
|
||||||
|
static int srcfile_depth; /* = 0 */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to open a file in a given directory.
|
||||||
|
*
|
||||||
|
* If the filename is an absolute path, then dirname is ignored. If it is a
|
||||||
|
* relative path, then we look in that directory for the file.
|
||||||
|
*
|
||||||
|
* @param dirname Directory to look in, or NULL for none
|
||||||
|
* @param fname Filename to look for
|
||||||
|
* @param fp Set to NULL if file did not open
|
||||||
|
* @return allocated filename on success (caller must free), NULL on failure
|
||||||
|
*/
|
||||||
|
static char *try_open(const char *dirname, const char *fname, FILE **fp)
|
||||||
|
{
|
||||||
|
char *fullname;
|
||||||
|
|
||||||
|
if (!dirname || fname[0] == '/')
|
||||||
|
fullname = xstrdup(fname);
|
||||||
|
else
|
||||||
|
fullname = join_path(dirname, fname);
|
||||||
|
|
||||||
|
*fp = fopen(fullname, "rb");
|
||||||
|
if (!*fp) {
|
||||||
|
free(fullname);
|
||||||
|
fullname = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fullname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a file for read access
|
||||||
|
*
|
||||||
|
* If it is a relative filename, we search the full search path for it.
|
||||||
|
*
|
||||||
|
* @param fname Filename to open
|
||||||
|
* @param fp Returns pointer to opened FILE, or NULL on failure
|
||||||
|
* @return pointer to allocated filename, which caller must free
|
||||||
|
*/
|
||||||
|
static char *fopen_any_on_path(const char *fname, FILE **fp)
|
||||||
|
{
|
||||||
|
const char *cur_dir = NULL;
|
||||||
|
struct search_path *node;
|
||||||
|
char *fullname;
|
||||||
|
|
||||||
|
/* Try current directory first */
|
||||||
|
assert(fp);
|
||||||
|
if (current_srcfile)
|
||||||
|
cur_dir = current_srcfile->dir;
|
||||||
|
fullname = try_open(cur_dir, fname, fp);
|
||||||
|
|
||||||
|
/* Failing that, try each search path in turn */
|
||||||
|
for (node = search_path_head; !*fp && node; node = node->next)
|
||||||
|
fullname = try_open(node->dirname, fname, fp);
|
||||||
|
|
||||||
|
return fullname;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *srcfile_relative_open(const char *fname, char **fullnamep)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
char *fullname;
|
||||||
|
|
||||||
|
if (streq(fname, "-")) {
|
||||||
|
f = stdin;
|
||||||
|
fullname = xstrdup("<stdin>");
|
||||||
|
} else {
|
||||||
|
fullname = fopen_any_on_path(fname, &f);
|
||||||
|
if (!f)
|
||||||
|
die("Couldn't open \"%s\": %s\n", fname,
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depfile)
|
||||||
|
fprintf(depfile, " %s", fullname);
|
||||||
|
|
||||||
|
if (fullnamep)
|
||||||
|
*fullnamep = fullname;
|
||||||
|
else
|
||||||
|
free(fullname);
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void srcfile_push(const char *fname)
|
||||||
|
{
|
||||||
|
struct srcfile_state *srcfile;
|
||||||
|
|
||||||
|
if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
|
||||||
|
die("Includes nested too deeply");
|
||||||
|
|
||||||
|
srcfile = xmalloc(sizeof(*srcfile));
|
||||||
|
|
||||||
|
srcfile->f = srcfile_relative_open(fname, &srcfile->name);
|
||||||
|
srcfile->dir = get_dirname(srcfile->name);
|
||||||
|
srcfile->prev = current_srcfile;
|
||||||
|
|
||||||
|
srcfile->lineno = 1;
|
||||||
|
srcfile->colno = 1;
|
||||||
|
|
||||||
|
current_srcfile = srcfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool srcfile_pop(void)
|
||||||
|
{
|
||||||
|
struct srcfile_state *srcfile = current_srcfile;
|
||||||
|
|
||||||
|
assert(srcfile);
|
||||||
|
|
||||||
|
current_srcfile = srcfile->prev;
|
||||||
|
|
||||||
|
if (fclose(srcfile->f))
|
||||||
|
die("Error closing \"%s\": %s\n", srcfile->name,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
/* FIXME: We allow the srcfile_state structure to leak,
|
||||||
|
* because it could still be referenced from a location
|
||||||
|
* variable being carried through the parser somewhere. To
|
||||||
|
* fix this we could either allocate all the files from a
|
||||||
|
* table, or use a pool allocator. */
|
||||||
|
|
||||||
|
return current_srcfile ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void srcfile_add_search_path(const char *dirname)
|
||||||
|
{
|
||||||
|
struct search_path *node;
|
||||||
|
|
||||||
|
/* Create the node */
|
||||||
|
node = xmalloc(sizeof(*node));
|
||||||
|
node->next = NULL;
|
||||||
|
node->dirname = xstrdup(dirname);
|
||||||
|
|
||||||
|
/* Add to the end of our list */
|
||||||
|
if (search_path_tail)
|
||||||
|
*search_path_tail = node;
|
||||||
|
else
|
||||||
|
search_path_head = node;
|
||||||
|
search_path_tail = &node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The empty source position.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct srcpos srcpos_empty = {
|
||||||
|
.first_line = 0,
|
||||||
|
.first_column = 0,
|
||||||
|
.last_line = 0,
|
||||||
|
.last_column = 0,
|
||||||
|
.file = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TAB_SIZE 8
|
||||||
|
|
||||||
|
void srcpos_update(struct srcpos *pos, const char *text, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pos->file = current_srcfile;
|
||||||
|
|
||||||
|
pos->first_line = current_srcfile->lineno;
|
||||||
|
pos->first_column = current_srcfile->colno;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
if (text[i] == '\n') {
|
||||||
|
current_srcfile->lineno++;
|
||||||
|
current_srcfile->colno = 1;
|
||||||
|
} else if (text[i] == '\t') {
|
||||||
|
current_srcfile->colno =
|
||||||
|
ALIGN(current_srcfile->colno, TAB_SIZE);
|
||||||
|
} else {
|
||||||
|
current_srcfile->colno++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos->last_line = current_srcfile->lineno;
|
||||||
|
pos->last_column = current_srcfile->colno;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct srcpos *
|
||||||
|
srcpos_copy(struct srcpos *pos)
|
||||||
|
{
|
||||||
|
struct srcpos *pos_new;
|
||||||
|
|
||||||
|
pos_new = xmalloc(sizeof(struct srcpos));
|
||||||
|
memcpy(pos_new, pos, sizeof(struct srcpos));
|
||||||
|
|
||||||
|
return pos_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
srcpos_string(struct srcpos *pos)
|
||||||
|
{
|
||||||
|
const char *fname = "<no-file>";
|
||||||
|
char *pos_str;
|
||||||
|
|
||||||
|
if (pos->file && pos->file->name)
|
||||||
|
fname = pos->file->name;
|
||||||
|
|
||||||
|
|
||||||
|
if (pos->first_line != pos->last_line)
|
||||||
|
xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
|
||||||
|
pos->first_line, pos->first_column,
|
||||||
|
pos->last_line, pos->last_column);
|
||||||
|
else if (pos->first_column != pos->last_column)
|
||||||
|
xasprintf(&pos_str, "%s:%d.%d-%d", fname,
|
||||||
|
pos->first_line, pos->first_column,
|
||||||
|
pos->last_column);
|
||||||
|
else
|
||||||
|
xasprintf(&pos_str, "%s:%d.%d", fname,
|
||||||
|
pos->first_line, pos->first_column);
|
||||||
|
|
||||||
|
return pos_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void srcpos_verror(struct srcpos *pos, const char *prefix,
|
||||||
|
const char *fmt, va_list va)
|
||||||
|
{
|
||||||
|
char *srcstr;
|
||||||
|
|
||||||
|
srcstr = srcpos_string(pos);
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: %s ", prefix, srcstr);
|
||||||
|
vfprintf(stderr, fmt, va);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
free(srcstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srcpos_error(struct srcpos *pos, const char *prefix,
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start(va, fmt);
|
||||||
|
srcpos_verror(pos, prefix, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srcpos_set_line(char *f, int l)
|
||||||
|
{
|
||||||
|
current_srcfile->name = f;
|
||||||
|
current_srcfile->lineno = l;
|
||||||
|
}
|
||||||
117
dtc-1.4.5/srcpos.h
Normal file
117
dtc-1.4.5/srcpos.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SRCPOS_H_
|
||||||
|
#define _SRCPOS_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct srcfile_state {
|
||||||
|
FILE *f;
|
||||||
|
char *name;
|
||||||
|
char *dir;
|
||||||
|
int lineno, colno;
|
||||||
|
struct srcfile_state *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern FILE *depfile; /* = NULL */
|
||||||
|
extern struct srcfile_state *current_srcfile; /* = NULL */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a source file.
|
||||||
|
*
|
||||||
|
* If the source file is a relative pathname, then it is searched for in the
|
||||||
|
* current directory (the directory of the last source file read) and after
|
||||||
|
* that in the search path.
|
||||||
|
*
|
||||||
|
* We work through the search path in order from the first path specified to
|
||||||
|
* the last.
|
||||||
|
*
|
||||||
|
* If the file is not found, then this function does not return, but calls
|
||||||
|
* die().
|
||||||
|
*
|
||||||
|
* @param fname Filename to search
|
||||||
|
* @param fullnamep If non-NULL, it is set to the allocated filename of the
|
||||||
|
* file that was opened. The caller is then responsible
|
||||||
|
* for freeing the pointer.
|
||||||
|
* @return pointer to opened FILE
|
||||||
|
*/
|
||||||
|
FILE *srcfile_relative_open(const char *fname, char **fullnamep);
|
||||||
|
|
||||||
|
void srcfile_push(const char *fname);
|
||||||
|
bool srcfile_pop(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new directory to the search path for input files
|
||||||
|
*
|
||||||
|
* The new path is added at the end of the list.
|
||||||
|
*
|
||||||
|
* @param dirname Directory to add
|
||||||
|
*/
|
||||||
|
void srcfile_add_search_path(const char *dirname);
|
||||||
|
|
||||||
|
struct srcpos {
|
||||||
|
int first_line;
|
||||||
|
int first_column;
|
||||||
|
int last_line;
|
||||||
|
int last_column;
|
||||||
|
struct srcfile_state *file;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define YYLTYPE struct srcpos
|
||||||
|
|
||||||
|
#define YYLLOC_DEFAULT(Current, Rhs, N) \
|
||||||
|
do { \
|
||||||
|
if (N) { \
|
||||||
|
(Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
|
||||||
|
(Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
|
||||||
|
(Current).last_line = YYRHSLOC(Rhs, N).last_line; \
|
||||||
|
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
|
||||||
|
(Current).file = YYRHSLOC(Rhs, N).file; \
|
||||||
|
} else { \
|
||||||
|
(Current).first_line = (Current).last_line = \
|
||||||
|
YYRHSLOC(Rhs, 0).last_line; \
|
||||||
|
(Current).first_column = (Current).last_column = \
|
||||||
|
YYRHSLOC(Rhs, 0).last_column; \
|
||||||
|
(Current).file = YYRHSLOC (Rhs, 0).file; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fictional source position used for IR nodes that are
|
||||||
|
* created without otherwise knowing a true source position.
|
||||||
|
* For example,constant definitions from the command line.
|
||||||
|
*/
|
||||||
|
extern struct srcpos srcpos_empty;
|
||||||
|
|
||||||
|
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
|
||||||
|
extern struct srcpos *srcpos_copy(struct srcpos *pos);
|
||||||
|
extern char *srcpos_string(struct srcpos *pos);
|
||||||
|
|
||||||
|
extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
|
||||||
|
const char *fmt, va_list va);
|
||||||
|
extern void PRINTF(3, 4) srcpos_error(struct srcpos *pos, const char *prefix,
|
||||||
|
const char *fmt, ...);
|
||||||
|
|
||||||
|
extern void srcpos_set_line(char *f, int l);
|
||||||
|
|
||||||
|
#endif /* _SRCPOS_H_ */
|
||||||
63
dtc-1.4.5/tests/.gitignore
vendored
Normal file
63
dtc-1.4.5/tests/.gitignore
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
*.dtb
|
||||||
|
*.dts.test.s
|
||||||
|
*.test.dts
|
||||||
|
tmp.*
|
||||||
|
/add_subnode_with_nops
|
||||||
|
/addr_size_cells
|
||||||
|
/appendprop[12]
|
||||||
|
/asm_tree_dump
|
||||||
|
/boot-cpuid
|
||||||
|
/char_literal
|
||||||
|
/check_path
|
||||||
|
/del_node
|
||||||
|
/del_property
|
||||||
|
/dtbs_equal_ordered
|
||||||
|
/dtbs_equal_unordered
|
||||||
|
/dtb_reverse
|
||||||
|
/dumptrees
|
||||||
|
/extra-terminating-null
|
||||||
|
/find_property
|
||||||
|
/get_alias
|
||||||
|
/get_mem_rsv
|
||||||
|
/get_name
|
||||||
|
/get_path
|
||||||
|
/get_phandle
|
||||||
|
/getprop
|
||||||
|
/incbin
|
||||||
|
/integer-expressions
|
||||||
|
/mangle-layout
|
||||||
|
/move_and_save
|
||||||
|
/node_check_compatible
|
||||||
|
/node_offset_by_compatible
|
||||||
|
/node_offset_by_phandle
|
||||||
|
/node_offset_by_prop_value
|
||||||
|
/nop_node
|
||||||
|
/nop_property
|
||||||
|
/nopulate
|
||||||
|
/notfound
|
||||||
|
/open_pack
|
||||||
|
/overlay
|
||||||
|
/overlay_bad_fixup
|
||||||
|
/parent_offset
|
||||||
|
/path-references
|
||||||
|
/path_offset
|
||||||
|
/path_offset_aliases
|
||||||
|
/phandle_format
|
||||||
|
/property_iterate
|
||||||
|
/propname_escapes
|
||||||
|
/references
|
||||||
|
/root_node
|
||||||
|
/rw_tree1
|
||||||
|
/set_name
|
||||||
|
/setprop
|
||||||
|
/setprop_inplace
|
||||||
|
/sized_cells
|
||||||
|
/string_escapes
|
||||||
|
/stringlist
|
||||||
|
/subnode_iterate
|
||||||
|
/subnode_offset
|
||||||
|
/supernode_atdepth_offset
|
||||||
|
/sw_tree1
|
||||||
|
/truncated_property
|
||||||
|
/utilfdt_test
|
||||||
|
/value-labels
|
||||||
87
dtc-1.4.5/tests/Makefile.tests
Normal file
87
dtc-1.4.5/tests/Makefile.tests
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
LIB_TESTS_L = get_mem_rsv \
|
||||||
|
root_node find_property subnode_offset path_offset \
|
||||||
|
get_name getprop get_phandle \
|
||||||
|
get_path supernode_atdepth_offset parent_offset \
|
||||||
|
node_offset_by_prop_value node_offset_by_phandle \
|
||||||
|
node_check_compatible node_offset_by_compatible \
|
||||||
|
get_alias \
|
||||||
|
char_literal \
|
||||||
|
sized_cells \
|
||||||
|
notfound \
|
||||||
|
addr_size_cells \
|
||||||
|
stringlist \
|
||||||
|
setprop_inplace nop_property nop_node \
|
||||||
|
sw_tree1 \
|
||||||
|
move_and_save mangle-layout nopulate \
|
||||||
|
open_pack rw_tree1 set_name setprop del_property del_node \
|
||||||
|
appendprop1 appendprop2 propname_escapes \
|
||||||
|
string_escapes references path-references phandle_format \
|
||||||
|
boot-cpuid incbin \
|
||||||
|
extra-terminating-null \
|
||||||
|
dtbs_equal_ordered \
|
||||||
|
dtb_reverse dtbs_equal_unordered \
|
||||||
|
add_subnode_with_nops path_offset_aliases \
|
||||||
|
utilfdt_test \
|
||||||
|
integer-expressions \
|
||||||
|
property_iterate \
|
||||||
|
subnode_iterate \
|
||||||
|
overlay overlay_bad_fixup \
|
||||||
|
check_path
|
||||||
|
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
|
LIBTREE_TESTS_L = truncated_property
|
||||||
|
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
|
DL_LIB_TESTS_L = asm_tree_dump value-labels
|
||||||
|
DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
|
TESTS = $(LIB_TESTS) $(LIBTREE_TESTS) $(DL_LIB_TESTS)
|
||||||
|
|
||||||
|
TESTS_TREES_L = test_tree1.dtb
|
||||||
|
TESTS_TREES = $(TESTS_TREES_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
|
TESTS_TARGETS = $(TESTS) $(TESTS_TREES)
|
||||||
|
|
||||||
|
TESTS_DEPFILES = $(TESTS:%=%.d) \
|
||||||
|
$(addprefix $(TESTS_PREFIX),testutils.d trees.d dumptrees.d)
|
||||||
|
|
||||||
|
TESTS_CLEANFILES_L = *.output vglog.* vgcore.* *.dtb *.test.dts *.dtsv1 tmp.*
|
||||||
|
TESTS_CLEANFILES_L += dumptrees
|
||||||
|
TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
|
.PHONY: tests
|
||||||
|
tests: $(TESTS) $(TESTS_TREES)
|
||||||
|
|
||||||
|
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
|
||||||
|
|
||||||
|
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
|
||||||
|
@$(VECHO) LD [libdl] $@
|
||||||
|
$(LINK.c) -o $@ $^ -ldl
|
||||||
|
|
||||||
|
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \
|
||||||
|
util.o $(LIBFDT_archive)
|
||||||
|
|
||||||
|
$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o
|
||||||
|
|
||||||
|
$(TESTS_TREES): $(TESTS_PREFIX)dumptrees
|
||||||
|
@$(VECHO) DUMPTREES
|
||||||
|
cd $(TESTS_PREFIX); ./dumptrees >/dev/null
|
||||||
|
|
||||||
|
tests_clean:
|
||||||
|
@$(VECHO) CLEAN "(tests)"
|
||||||
|
rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
|
||||||
|
rm -f $(TESTS_CLEANFILES)
|
||||||
|
|
||||||
|
check: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
|
||||||
|
cd $(TESTS_PREFIX); ./run_tests.sh
|
||||||
|
|
||||||
|
checkm: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
|
||||||
|
cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$
|
||||||
|
|
||||||
|
checkv: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
|
||||||
|
cd $(TESTS_PREFIX); ./run_tests.sh -v
|
||||||
|
|
||||||
|
ifneq ($(DEPTARGETS),)
|
||||||
|
-include $(TESTS_DEPFILES)
|
||||||
|
endif
|
||||||
|
|
||||||
84
dtc-1.4.5/tests/add_subnode_with_nops.c
Normal file
84
dtc-1.4.5/tests/add_subnode_with_nops.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for fdt_nop_node()
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
#define SPACE 65536
|
||||||
|
|
||||||
|
#define CHECK(code) \
|
||||||
|
{ \
|
||||||
|
err = (code); \
|
||||||
|
if (err) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OFF_CHECK(off, code) \
|
||||||
|
{ \
|
||||||
|
(off) = (code); \
|
||||||
|
if (off < 0) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(off)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
int err;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
|
||||||
|
fdt = xmalloc(SPACE);
|
||||||
|
|
||||||
|
CHECK(fdt_create(fdt, SPACE));
|
||||||
|
|
||||||
|
CHECK(fdt_finish_reservemap(fdt));
|
||||||
|
CHECK(fdt_begin_node(fdt, ""));
|
||||||
|
CHECK(fdt_property_cell(fdt, "prop1", TEST_VALUE_1));
|
||||||
|
CHECK(fdt_property_cell(fdt, "prop2", TEST_VALUE_2));
|
||||||
|
CHECK(fdt_end_node(fdt));
|
||||||
|
CHECK(fdt_finish(fdt));
|
||||||
|
|
||||||
|
verbose_printf("Built empty tree, totalsize = %d\n",
|
||||||
|
fdt_totalsize(fdt));
|
||||||
|
|
||||||
|
CHECK(fdt_open_into(fdt, fdt, SPACE));
|
||||||
|
|
||||||
|
check_getprop_cell(fdt, 0, "prop1", TEST_VALUE_1);
|
||||||
|
check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2);
|
||||||
|
|
||||||
|
CHECK(fdt_nop_property(fdt, 0, "prop1"));
|
||||||
|
|
||||||
|
check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2);
|
||||||
|
|
||||||
|
OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode"));
|
||||||
|
|
||||||
|
check_getprop_cell(fdt, 0, "prop2", TEST_VALUE_2);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
64
dtc-1.4.5/tests/addr_size_cells.c
Normal file
64
dtc-1.4.5/tests/addr_size_cells.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for #address-cells and #size-cells handling
|
||||||
|
* Copyright (C) 2014 David Gibson, <david@gibson.dropbear.id.au>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
static void check_node(const void *fdt, const char *path, int ac, int sc)
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
int xac, xsc;
|
||||||
|
|
||||||
|
offset = fdt_path_offset(fdt, path);
|
||||||
|
if (offset < 0)
|
||||||
|
FAIL("Couldn't find path %s", path);
|
||||||
|
|
||||||
|
xac = fdt_address_cells(fdt, offset);
|
||||||
|
xsc = fdt_size_cells(fdt, offset);
|
||||||
|
|
||||||
|
if (xac != ac)
|
||||||
|
FAIL("Address cells for %s is %d instead of %d\n",
|
||||||
|
path, xac, ac);
|
||||||
|
if (xsc != sc)
|
||||||
|
FAIL("Size cells for %s is %d instead of %d\n",
|
||||||
|
path, xsc, sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
CONFIG("Usage: %s <dtb file>\n", argv[0]);
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
fdt = load_blob(argv[1]);
|
||||||
|
|
||||||
|
check_node(fdt, "/", 2, 2);
|
||||||
|
check_node(fdt, "/identity-bus@0", 2, 2);
|
||||||
|
check_node(fdt, "/simple-bus@1000000", 2, 1);
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
15
dtc-1.4.5/tests/addresses.dts
Normal file
15
dtc-1.4.5/tests/addresses.dts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
compatible = "test_addresses";
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
|
||||||
|
identity-bus@0 {
|
||||||
|
};
|
||||||
|
|
||||||
|
simple-bus@1000000 {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
25
dtc-1.4.5/tests/aliases.dts
Normal file
25
dtc-1.4.5/tests/aliases.dts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
aliases {
|
||||||
|
s1 = &sub1;
|
||||||
|
ss1 = &subsub1;
|
||||||
|
sss1 = &subsubsub1;
|
||||||
|
};
|
||||||
|
|
||||||
|
sub1: subnode@1 {
|
||||||
|
compatible = "subnode1";
|
||||||
|
reg = <1>;
|
||||||
|
|
||||||
|
subsub1: subsubnode {
|
||||||
|
compatible = "subsubnode1", "subsubnode";
|
||||||
|
|
||||||
|
subsubsub1: subsubsubnode {
|
||||||
|
compatible = "subsubsubnode1", "subsubsubnode";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
8
dtc-1.4.5/tests/appendprop.dts
Normal file
8
dtc-1.4.5/tests/appendprop.dts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
prop-str = "hello world", "nastystring: \a\b\t\n\v\f\r\\\"";
|
||||||
|
prop-int64 = /bits/ 64 <0xdeadbeef01abcdef 0xdeadbeef01abcdef>;
|
||||||
|
prop-int = <0xdeadbeef 123456789>;
|
||||||
|
prop-bytes = [00010203040001020304];
|
||||||
|
};
|
||||||
70
dtc-1.4.5/tests/appendprop1.c
Normal file
70
dtc-1.4.5/tests/appendprop1.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for fdt_appendprop()
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
#define SPACE 65536
|
||||||
|
|
||||||
|
#define CHECK(code) \
|
||||||
|
{ \
|
||||||
|
err = (code); \
|
||||||
|
if (err) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
int err;
|
||||||
|
uint8_t bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04};
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
|
||||||
|
/* Create an empty tree first */
|
||||||
|
fdt = xmalloc(SPACE);
|
||||||
|
CHECK(fdt_create(fdt, SPACE));
|
||||||
|
CHECK(fdt_finish_reservemap(fdt));
|
||||||
|
CHECK(fdt_begin_node(fdt, ""));
|
||||||
|
CHECK(fdt_end_node(fdt));
|
||||||
|
CHECK(fdt_finish(fdt));
|
||||||
|
|
||||||
|
/* Now use appendprop to add properties */
|
||||||
|
CHECK(fdt_open_into(fdt, fdt, SPACE));
|
||||||
|
|
||||||
|
CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes)));
|
||||||
|
CHECK(fdt_appendprop_cell(fdt, 0, "prop-int", TEST_VALUE_1));
|
||||||
|
CHECK(fdt_appendprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1));
|
||||||
|
CHECK(fdt_appendprop_string(fdt, 0, "prop-str", TEST_STRING_1));
|
||||||
|
|
||||||
|
CHECK(fdt_pack(fdt));
|
||||||
|
|
||||||
|
save_blob("appendprop1.test.dtb", fdt);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
64
dtc-1.4.5/tests/appendprop2.c
Normal file
64
dtc-1.4.5/tests/appendprop2.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for fdt_appendprop()
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
#define SPACE 65536
|
||||||
|
|
||||||
|
#define CHECK(code) \
|
||||||
|
{ \
|
||||||
|
err = (code); \
|
||||||
|
if (err) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt, *buf;
|
||||||
|
int err;
|
||||||
|
uint8_t bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04};
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
fdt = load_blob_arg(argc, argv);
|
||||||
|
|
||||||
|
buf = xmalloc(SPACE);
|
||||||
|
CHECK(fdt_open_into(fdt, buf, SPACE));
|
||||||
|
fdt = buf;
|
||||||
|
|
||||||
|
CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes)));
|
||||||
|
CHECK(fdt_appendprop_cell(fdt, 0, "prop-int", TEST_VALUE_2));
|
||||||
|
CHECK(fdt_appendprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1));
|
||||||
|
CHECK(fdt_appendprop_string(fdt, 0, "prop-str", TEST_STRING_2));
|
||||||
|
|
||||||
|
CHECK(fdt_pack(fdt));
|
||||||
|
|
||||||
|
save_blob("appendprop2.test.dtb", fdt);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
61
dtc-1.4.5/tests/asm_tree_dump.c
Normal file
61
dtc-1.4.5/tests/asm_tree_dump.c
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Tests if an asm tree built into a shared object matches a given dtb
|
||||||
|
* Copyright (C) 2008 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *sohandle;
|
||||||
|
void *fdt;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
if (argc != 3)
|
||||||
|
CONFIG("Usage: %s <so file> <dtb file>", argv[0]);
|
||||||
|
|
||||||
|
sohandle = dlopen(argv[1], RTLD_NOW);
|
||||||
|
if (!sohandle)
|
||||||
|
FAIL("Couldn't dlopen() %s", argv[1]);
|
||||||
|
|
||||||
|
fdt = dlsym(sohandle, "dt_blob_start");
|
||||||
|
if (!fdt)
|
||||||
|
FAIL("Couldn't locate \"dt_blob_start\" symbol in %s",
|
||||||
|
argv[1]);
|
||||||
|
|
||||||
|
err = fdt_check_header(fdt);
|
||||||
|
if (err != 0)
|
||||||
|
FAIL("%s contains invalid tree: %s", argv[1],
|
||||||
|
fdt_strerror(err));
|
||||||
|
|
||||||
|
save_blob(argv[2], fdt);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
11
dtc-1.4.5/tests/bad-empty-ranges.dts
Normal file
11
dtc-1.4.5/tests/bad-empty-ranges.dts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
node {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges;
|
||||||
|
};
|
||||||
|
};
|
||||||
13
dtc-1.4.5/tests/bad-gpio.dts
Normal file
13
dtc-1.4.5/tests/bad-gpio.dts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
gpio: gpio-controller {
|
||||||
|
#gpio-cells = <3>;
|
||||||
|
};
|
||||||
|
|
||||||
|
node {
|
||||||
|
nr-gpios = <1>;
|
||||||
|
foo-gpios = <&gpio>;
|
||||||
|
bar-gpio = <&gpio 1 2 3>;
|
||||||
|
};
|
||||||
|
};
|
||||||
12
dtc-1.4.5/tests/bad-interrupt-cells.dts
Normal file
12
dtc-1.4.5/tests/bad-interrupt-cells.dts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <3>;
|
||||||
|
};
|
||||||
|
|
||||||
|
node {
|
||||||
|
interrupts = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
7
dtc-1.4.5/tests/bad-name-property.dts
Normal file
7
dtc-1.4.5/tests/bad-name-property.dts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
node@0 {
|
||||||
|
name = "badthing";
|
||||||
|
};
|
||||||
|
};
|
||||||
7
dtc-1.4.5/tests/bad-ncells.dts
Normal file
7
dtc-1.4.5/tests/bad-ncells.dts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = "badthing";
|
||||||
|
#size-cells = "badthing";
|
||||||
|
#interrupt-cells = "badthing";
|
||||||
|
};
|
||||||
5
dtc-1.4.5/tests/bad-octal-literal.dts
Normal file
5
dtc-1.4.5/tests/bad-octal-literal.dts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
x = <09>;
|
||||||
|
};
|
||||||
11
dtc-1.4.5/tests/bad-phandle-cells.dts
Normal file
11
dtc-1.4.5/tests/bad-phandle-cells.dts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <3>;
|
||||||
|
};
|
||||||
|
|
||||||
|
node {
|
||||||
|
interrupts-extended = <&intc>;
|
||||||
|
};
|
||||||
|
};
|
||||||
12
dtc-1.4.5/tests/bad-reg-ranges.dts
Normal file
12
dtc-1.4.5/tests/bad-reg-ranges.dts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
node {
|
||||||
|
reg = <0 0>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges = <0 0 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
12
dtc-1.4.5/tests/bad-size-cells.dts
Normal file
12
dtc-1.4.5/tests/bad-size-cells.dts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
mangled {
|
||||||
|
#address-cells = <0x0>;
|
||||||
|
#size-cells = <0x0>;
|
||||||
|
|
||||||
|
valid {
|
||||||
|
reg = <0x0 0x4000000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
7
dtc-1.4.5/tests/bad-string-props.dts
Normal file
7
dtc-1.4.5/tests/bad-string-props.dts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
device_type = <0xdeadbeef>;
|
||||||
|
model = <0xdeadbeef>;
|
||||||
|
status = <0xdeadbeef>
|
||||||
|
};
|
||||||
175
dtc-1.4.5/tests/base01.asm
Normal file
175
dtc-1.4.5/tests/base01.asm
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/* autogenerated by dtc, do not edit */
|
||||||
|
|
||||||
|
#define OF_DT_HEADER 0xd00dfeed
|
||||||
|
#define OF_DT_BEGIN_NODE 0x1
|
||||||
|
#define OF_DT_END_NODE 0x2
|
||||||
|
#define OF_DT_PROP 0x3
|
||||||
|
#define OF_DT_END 0x9
|
||||||
|
|
||||||
|
.globl dt_blob_start
|
||||||
|
dt_blob_start:
|
||||||
|
_dt_blob_start:
|
||||||
|
.globl dt_header
|
||||||
|
dt_header:
|
||||||
|
_dt_header:
|
||||||
|
.long OF_DT_HEADER /* magic */
|
||||||
|
.long _dt_blob_end - _dt_blob_start /* totalsize */
|
||||||
|
.long _dt_struct_start - _dt_blob_start /* off_dt_struct */
|
||||||
|
.long _dt_strings_start - _dt_blob_start /* off_dt_strings */
|
||||||
|
.long _dt_reserve_map - _dt_blob_start /* off_dt_strings */
|
||||||
|
.long 16 /* version */
|
||||||
|
.long 16 /* last_comp_version */
|
||||||
|
.long 0 /*boot_cpuid_phys*/
|
||||||
|
.long _dt_strings_end - _dt_strings_start /* size_dt_strings */
|
||||||
|
.balign 8
|
||||||
|
.globl dt_reserve_map
|
||||||
|
dt_reserve_map:
|
||||||
|
_dt_reserve_map:
|
||||||
|
/* Memory reserve map from source file */
|
||||||
|
.long 0, 0
|
||||||
|
.long 0, 0
|
||||||
|
.globl dt_struct_start
|
||||||
|
dt_struct_start:
|
||||||
|
_dt_struct_start:
|
||||||
|
.long OF_DT_BEGIN_NODE
|
||||||
|
.string ""
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0xa
|
||||||
|
.long 0x0
|
||||||
|
.long 0x536f6d65
|
||||||
|
.long 0x4d6f6465
|
||||||
|
.short 0x6c00
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x8
|
||||||
|
.long 0x6
|
||||||
|
.long 0x4e6f7468
|
||||||
|
.long 0x696e6700
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x11
|
||||||
|
.long 0x2
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x20
|
||||||
|
.long 0x2
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_BEGIN_NODE
|
||||||
|
.string "memory@0"
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x7
|
||||||
|
.long 0x2c
|
||||||
|
.long 0x6d656d6f
|
||||||
|
.short 0x7279
|
||||||
|
.byte 0x0
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x10
|
||||||
|
.long 0x38
|
||||||
|
.long 0x0
|
||||||
|
.long 0x0
|
||||||
|
.long 0x0
|
||||||
|
.long 0x20000000
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_END_NODE
|
||||||
|
.long OF_DT_BEGIN_NODE
|
||||||
|
.string "cpus"
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x11
|
||||||
|
.long 0x1
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x20
|
||||||
|
.long 0x0
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x3c
|
||||||
|
.long 0xa
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x40
|
||||||
|
.long 0x17
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x44
|
||||||
|
.long 0x5
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x49
|
||||||
|
.long 0xf
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x4d
|
||||||
|
.long 0xd00d
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x10
|
||||||
|
.long 0x53
|
||||||
|
.long 0x4d2
|
||||||
|
.long 0x162e
|
||||||
|
.long 0x2334
|
||||||
|
.long 0xd80
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x59
|
||||||
|
.long 0x0
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x61
|
||||||
|
.long 0xffffffff
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x69
|
||||||
|
.long 0x0
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_PROP
|
||||||
|
.long 0x4
|
||||||
|
.long 0x71
|
||||||
|
.long 0xffffffff
|
||||||
|
.balign 4
|
||||||
|
.long OF_DT_END_NODE
|
||||||
|
.long OF_DT_END_NODE
|
||||||
|
.long OF_DT_END
|
||||||
|
.globl dt_struct_end
|
||||||
|
dt_struct_end:
|
||||||
|
_dt_struct_end:
|
||||||
|
.globl dt_strings_start
|
||||||
|
dt_strings_start:
|
||||||
|
_dt_strings_start:
|
||||||
|
.string "model"
|
||||||
|
.string "compatible"
|
||||||
|
.string "#address-cells"
|
||||||
|
.string "#size-cells"
|
||||||
|
.string "device_type"
|
||||||
|
.string "reg"
|
||||||
|
.string "d10"
|
||||||
|
.string "d23"
|
||||||
|
.string "b101"
|
||||||
|
.string "o17"
|
||||||
|
.string "hd00d"
|
||||||
|
.string "stuff"
|
||||||
|
.string "bad-d-1"
|
||||||
|
.string "bad-d-2"
|
||||||
|
.string "bad-o-1"
|
||||||
|
.string "bad-o-2"
|
||||||
|
.globl dt_strings_end
|
||||||
|
dt_strings_end:
|
||||||
|
_dt_strings_end:
|
||||||
|
.globl dt_blob_end
|
||||||
|
dt_blob_end:
|
||||||
|
_dt_blob_end:
|
||||||
1
dtc-1.4.5/tests/base01.cmd
Normal file
1
dtc-1.4.5/tests/base01.cmd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dtc -f -b 0 -V 16 -I dts -O asm
|
||||||
33
dtc-1.4.5/tests/base01.dts
Normal file
33
dtc-1.4.5/tests/base01.dts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
model = "SomeModel";
|
||||||
|
compatible = "Nothing";
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
|
||||||
|
memory@0 {
|
||||||
|
device_type = "memory";
|
||||||
|
reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
d10 = < 10>; // hex: 0xa
|
||||||
|
d23 = < 23>; // hex: 0x17
|
||||||
|
b101 = < 0x5>; // hex: 0x5
|
||||||
|
o17 = < 017>; // hex: 0xf
|
||||||
|
hd00d = < 0xd00d>; // hex: 0xd00d
|
||||||
|
|
||||||
|
// hex: 0x4d2 0x163e 0x2334 0xd80
|
||||||
|
stuff = < 1234 5678 9012 3456>;
|
||||||
|
|
||||||
|
|
||||||
|
bad-d-1 = < 0>; // Hrm. 0
|
||||||
|
bad-d-2 = < 123456789012345>;
|
||||||
|
bad-o-1 = < 00>;
|
||||||
|
bad-o-2 = < 0123456123456>;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
6
dtc-1.4.5/tests/base01.stderr
Normal file
6
dtc-1.4.5/tests/base01.stderr
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
DTC: dts->asm on file "tests/base01.dts"
|
||||||
|
Line 26: Invalid cell value '123456789012345'; -1 assumed
|
||||||
|
Line 27: Invalid cell value '891'; 0 assumed
|
||||||
|
Line 28: Invalid cell value '123456123456'; -1 assumed
|
||||||
|
ERROR: Missing /chosen node
|
||||||
|
Input tree has errors
|
||||||
47
dtc-1.4.5/tests/boot-cpuid.c
Normal file
47
dtc-1.4.5/tests/boot-cpuid.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
uint32_t cpuid;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
|
||||||
|
if (argc != 3)
|
||||||
|
CONFIG("Usage: %s <dtb file> <cpuid>", argv[0]);
|
||||||
|
|
||||||
|
fdt = load_blob(argv[1]);
|
||||||
|
cpuid = strtoul(argv[2], NULL, 0);
|
||||||
|
|
||||||
|
if (fdt_boot_cpuid_phys(fdt) != cpuid)
|
||||||
|
FAIL("Incorrect boot_cpuid_phys (0x%x instead of 0x%x)",
|
||||||
|
fdt_boot_cpuid_phys(fdt), cpuid);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
16
dtc-1.4.5/tests/boot-cpuid.dts
Normal file
16
dtc-1.4.5/tests/boot-cpuid.dts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
cpus {
|
||||||
|
cpu@10 {
|
||||||
|
device_type = "cpu";
|
||||||
|
compatible = "fake-cpu";
|
||||||
|
reg = <0x10>;
|
||||||
|
};
|
||||||
|
cpu@11 {
|
||||||
|
device_type = "cpu";
|
||||||
|
compatible = "fake-cpu";
|
||||||
|
reg = <0x11>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
49
dtc-1.4.5/tests/char_literal.c
Normal file
49
dtc-1.4.5/tests/char_literal.c
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for character literals in dtc
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
* Copyright (C) 2011 The Chromium Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
fdt32_t expected_cells[5];
|
||||||
|
|
||||||
|
expected_cells[0] = cpu_to_fdt32((unsigned char)TEST_CHAR1);
|
||||||
|
expected_cells[1] = cpu_to_fdt32((unsigned char)TEST_CHAR2);
|
||||||
|
expected_cells[2] = cpu_to_fdt32((unsigned char)TEST_CHAR3);
|
||||||
|
expected_cells[3] = cpu_to_fdt32((unsigned char)TEST_CHAR4);
|
||||||
|
expected_cells[4] = cpu_to_fdt32((unsigned char)TEST_CHAR5);
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
fdt = load_blob_arg(argc, argv);
|
||||||
|
|
||||||
|
check_getprop(fdt, 0, "char-literal-cells",
|
||||||
|
sizeof(expected_cells), expected_cells);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
5
dtc-1.4.5/tests/char_literal.dts
Normal file
5
dtc-1.4.5/tests/char_literal.dts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
char-literal-cells = <'\r' 'b' '\0' '\'' '\xff'>;
|
||||||
|
};
|
||||||
83
dtc-1.4.5/tests/check_path.c
Normal file
83
dtc-1.4.5/tests/check_path.c
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for node existence
|
||||||
|
* Copyright (C) 2016 Konsulko Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
#define CHECK(code) \
|
||||||
|
{ \
|
||||||
|
int err = (code); \
|
||||||
|
if (err) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4k ought to be enough for anybody */
|
||||||
|
#define FDT_COPY_SIZE (4 * 1024)
|
||||||
|
|
||||||
|
static void *open_dt(char *path)
|
||||||
|
{
|
||||||
|
void *dt, *copy;
|
||||||
|
|
||||||
|
dt = load_blob(path);
|
||||||
|
copy = xmalloc(FDT_COPY_SIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resize our DTs to 4k so that we have room to operate on
|
||||||
|
*/
|
||||||
|
CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE));
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt_base;
|
||||||
|
int fail_config, exists, check_exists;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
fail_config = 0;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
fail_config = 1;
|
||||||
|
|
||||||
|
if (!fail_config) {
|
||||||
|
if (!strcmp(argv[2], "exists"))
|
||||||
|
check_exists = 1;
|
||||||
|
else if (!strcmp(argv[2], "not-exists"))
|
||||||
|
check_exists = 0;
|
||||||
|
else
|
||||||
|
fail_config = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail_config)
|
||||||
|
CONFIG("Usage: %s <base dtb> <[exists|not-exists]> <node-path>", argv[0]);
|
||||||
|
|
||||||
|
fdt_base = open_dt(argv[1]);
|
||||||
|
|
||||||
|
exists = fdt_path_offset(fdt_base, argv[3]) >= 0;
|
||||||
|
|
||||||
|
if (exists == check_exists)
|
||||||
|
PASS();
|
||||||
|
else
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
16
dtc-1.4.5/tests/comments-cmp.dts
Normal file
16
dtc-1.4.5/tests/comments-cmp.dts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
prop1;
|
||||||
|
prop2;
|
||||||
|
prop3;
|
||||||
|
prop4;
|
||||||
|
prop5;
|
||||||
|
prop6;
|
||||||
|
prop7;
|
||||||
|
prop8;
|
||||||
|
prop9;
|
||||||
|
prop10;
|
||||||
|
child {
|
||||||
|
};
|
||||||
|
};
|
||||||
39
dtc-1.4.5/tests/comments.dts
Normal file
39
dtc-1.4.5/tests/comments.dts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* regexps for lexing comments are.. tricky. Check if we've actually
|
||||||
|
* got it right */
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
// line comment
|
||||||
|
prop1;
|
||||||
|
/* comment */
|
||||||
|
prop2;
|
||||||
|
/* multiline
|
||||||
|
|
||||||
|
notaprop1;
|
||||||
|
|
||||||
|
comment */
|
||||||
|
prop3;
|
||||||
|
/**/
|
||||||
|
prop4;
|
||||||
|
/***/
|
||||||
|
prop5;
|
||||||
|
/****/
|
||||||
|
prop6;
|
||||||
|
/* another
|
||||||
|
* multiline
|
||||||
|
* comment */
|
||||||
|
prop7;
|
||||||
|
/* yet
|
||||||
|
* another
|
||||||
|
* multline
|
||||||
|
* comment
|
||||||
|
*/
|
||||||
|
prop8;
|
||||||
|
/** try this */
|
||||||
|
prop9;
|
||||||
|
/* and this **/
|
||||||
|
prop10;
|
||||||
|
child /* finally */ {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/* final comment */
|
||||||
3
dtc-1.4.5/tests/data.S
Normal file
3
dtc-1.4.5/tests/data.S
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/* Used in combination with dtc -Oasm output to embed
|
||||||
|
* a device tree in the data section of a .o */
|
||||||
|
.data
|
||||||
7
dtc-1.4.5/tests/default-addr-size.dts
Normal file
7
dtc-1.4.5/tests/default-addr-size.dts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
node {
|
||||||
|
reg = <0 0 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
123
dtc-1.4.5/tests/del_node.c
Normal file
123
dtc-1.4.5/tests/del_node.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for fdt_nop_node()
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
int subnode1_offset, subnode2_offset, subsubnode2_offset;
|
||||||
|
int err;
|
||||||
|
int oldsize, delsize, newsize;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
fdt = load_blob_arg(argc, argv);
|
||||||
|
|
||||||
|
fdt = open_blob_rw(fdt);
|
||||||
|
|
||||||
|
oldsize = fdt_totalsize(fdt);
|
||||||
|
|
||||||
|
subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
|
||||||
|
if (subnode1_offset < 0)
|
||||||
|
FAIL("Couldn't find \"/subnode@1\": %s",
|
||||||
|
fdt_strerror(subnode1_offset));
|
||||||
|
check_getprop_cell(fdt, subnode1_offset, "prop-int", TEST_VALUE_1);
|
||||||
|
|
||||||
|
subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
|
||||||
|
if (subnode2_offset < 0)
|
||||||
|
FAIL("Couldn't find \"/subnode@2\": %s",
|
||||||
|
fdt_strerror(subnode2_offset));
|
||||||
|
check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
|
||||||
|
|
||||||
|
subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
|
||||||
|
if (subsubnode2_offset < 0)
|
||||||
|
FAIL("Couldn't find \"/subnode@2/subsubnode\": %s",
|
||||||
|
fdt_strerror(subsubnode2_offset));
|
||||||
|
check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);
|
||||||
|
|
||||||
|
err = fdt_del_node(fdt, subnode1_offset);
|
||||||
|
if (err)
|
||||||
|
FAIL("fdt_del_node(subnode1): %s", fdt_strerror(err));
|
||||||
|
|
||||||
|
subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
|
||||||
|
if (subnode1_offset != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
|
||||||
|
fdt_strerror(subnode1_offset),
|
||||||
|
fdt_strerror(-FDT_ERR_NOTFOUND));
|
||||||
|
|
||||||
|
subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
|
||||||
|
if (subnode2_offset < 0)
|
||||||
|
FAIL("Couldn't find \"/subnode2\": %s",
|
||||||
|
fdt_strerror(subnode2_offset));
|
||||||
|
check_getprop_cell(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
|
||||||
|
|
||||||
|
subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
|
||||||
|
if (subsubnode2_offset < 0)
|
||||||
|
FAIL("Couldn't find \"/subnode@2/subsubnode\": %s",
|
||||||
|
fdt_strerror(subsubnode2_offset));
|
||||||
|
check_getprop_cell(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);
|
||||||
|
|
||||||
|
err = fdt_del_node(fdt, subnode2_offset);
|
||||||
|
if (err)
|
||||||
|
FAIL("fdt_del_node(subnode2): %s", fdt_strerror(err));
|
||||||
|
|
||||||
|
subnode1_offset = fdt_path_offset(fdt, "/subnode@1");
|
||||||
|
if (subnode1_offset != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
|
||||||
|
fdt_strerror(subnode1_offset),
|
||||||
|
fdt_strerror(-FDT_ERR_NOTFOUND));
|
||||||
|
|
||||||
|
subnode2_offset = fdt_path_offset(fdt, "/subnode@2");
|
||||||
|
if (subnode2_offset != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("fdt_path_offset(subnode2) returned \"%s\" instead of \"%s\"",
|
||||||
|
fdt_strerror(subnode2_offset),
|
||||||
|
fdt_strerror(-FDT_ERR_NOTFOUND));
|
||||||
|
|
||||||
|
subsubnode2_offset = fdt_path_offset(fdt, "/subnode@2/subsubnode");
|
||||||
|
if (subsubnode2_offset != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("fdt_path_offset(subsubnode2) returned \"%s\" instead of \"%s\"",
|
||||||
|
fdt_strerror(subsubnode2_offset),
|
||||||
|
fdt_strerror(-FDT_ERR_NOTFOUND));
|
||||||
|
|
||||||
|
delsize = fdt_totalsize(fdt);
|
||||||
|
|
||||||
|
err = fdt_pack(fdt);
|
||||||
|
if (err)
|
||||||
|
FAIL("fdt_pack(): %s", fdt_strerror(err));
|
||||||
|
|
||||||
|
newsize = fdt_totalsize(fdt);
|
||||||
|
|
||||||
|
verbose_printf("oldsize = %d, delsize = %d, newsize = %d\n",
|
||||||
|
oldsize, delsize, newsize);
|
||||||
|
|
||||||
|
if (newsize >= oldsize)
|
||||||
|
FAIL("Tree failed to shrink after deletions");
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
90
dtc-1.4.5/tests/del_property.c
Normal file
90
dtc-1.4.5/tests/del_property.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for fdt_delprop()
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
const uint32_t *intp;
|
||||||
|
const char *strp;
|
||||||
|
int err, lenerr;
|
||||||
|
int oldsize, delsize, newsize;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
fdt = load_blob_arg(argc, argv);
|
||||||
|
|
||||||
|
fdt = open_blob_rw(fdt);
|
||||||
|
|
||||||
|
oldsize = fdt_totalsize(fdt);
|
||||||
|
|
||||||
|
intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1);
|
||||||
|
verbose_printf("int value was 0x%08x\n", *intp);
|
||||||
|
|
||||||
|
err = fdt_delprop(fdt, 0, "prop-int");
|
||||||
|
if (err)
|
||||||
|
FAIL("Failed to delete \"prop-int\": %s", fdt_strerror(err));
|
||||||
|
|
||||||
|
intp = fdt_getprop(fdt, 0, "prop-int", &lenerr);
|
||||||
|
if (intp)
|
||||||
|
FAIL("prop-int still present after deletion");
|
||||||
|
if (lenerr != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("Unexpected error on second getprop: %s",
|
||||||
|
fdt_strerror(lenerr));
|
||||||
|
|
||||||
|
strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
|
||||||
|
TEST_STRING_1);
|
||||||
|
verbose_printf("string value was \"%s\"\n", strp);
|
||||||
|
err = fdt_delprop(fdt, 0, "prop-str");
|
||||||
|
if (err)
|
||||||
|
FAIL("Failed to delete \"prop-str\": %s", fdt_strerror(err));
|
||||||
|
|
||||||
|
strp = fdt_getprop(fdt, 0, "prop-str", &lenerr);
|
||||||
|
if (strp)
|
||||||
|
FAIL("prop-str still present after deletion");
|
||||||
|
if (lenerr != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("Unexpected error on second getprop: %s",
|
||||||
|
fdt_strerror(lenerr));
|
||||||
|
|
||||||
|
delsize = fdt_totalsize(fdt);
|
||||||
|
|
||||||
|
err = fdt_pack(fdt);
|
||||||
|
if (err)
|
||||||
|
FAIL("fdt_pack(): %s\n", fdt_strerror(err));
|
||||||
|
|
||||||
|
newsize = fdt_totalsize(fdt);
|
||||||
|
|
||||||
|
verbose_printf("oldsize = %d, delsize = %d, newsize = %d\n",
|
||||||
|
oldsize, delsize, newsize);
|
||||||
|
|
||||||
|
if (newsize >= oldsize)
|
||||||
|
FAIL("Tree failed to shrink after deletions");
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
37
dtc-1.4.5/tests/delete_reinstate_multilabel.dts
Normal file
37
dtc-1.4.5/tests/delete_reinstate_multilabel.dts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/* Create some nodes and properties with multiple labels */
|
||||||
|
|
||||||
|
/ {
|
||||||
|
label1: label2: prop = "value";
|
||||||
|
|
||||||
|
label3: label4: node {
|
||||||
|
label5: label6: prop = "value";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Delete them, and everything that's part of them, i.e. the labels */
|
||||||
|
|
||||||
|
/ {
|
||||||
|
/delete-property/ prop;
|
||||||
|
/delete-node/ node;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Re-instate them. None of the old labels should come back
|
||||||
|
*
|
||||||
|
* Note: Do not add any new/extra labels here. As of the time of writing,
|
||||||
|
* when dtc adds labels to an object, they are added to the head of the list
|
||||||
|
* of labels, and this test is specifically about ensuring the correct
|
||||||
|
* handling of lists of labels where the first label in the list is marked as
|
||||||
|
* deleted. Failure to observe this note may result in the test passing when
|
||||||
|
* it should not.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
prop = "value";
|
||||||
|
|
||||||
|
node {
|
||||||
|
prop = "value";
|
||||||
|
};
|
||||||
|
};
|
||||||
9
dtc-1.4.5/tests/delete_reinstate_multilabel_ref.dts
Normal file
9
dtc-1.4.5/tests/delete_reinstate_multilabel_ref.dts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
prop = "value";
|
||||||
|
|
||||||
|
node {
|
||||||
|
prop = "value";
|
||||||
|
};
|
||||||
|
};
|
||||||
1
dtc-1.4.5/tests/dependencies.cmp
Normal file
1
dtc-1.4.5/tests/dependencies.cmp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dependencies.test.dtb: dependencies.dts deps_inc1.dtsi deps_inc2.dtsi
|
||||||
6
dtc-1.4.5/tests/dependencies.dts
Normal file
6
dtc-1.4.5/tests/dependencies.dts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/include/ "deps_inc1.dtsi"
|
||||||
|
|
||||||
|
/ {
|
||||||
|
};
|
||||||
1
dtc-1.4.5/tests/deps_inc1.dtsi
Normal file
1
dtc-1.4.5/tests/deps_inc1.dtsi
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/include/ "deps_inc2.dtsi"
|
||||||
1
dtc-1.4.5/tests/deps_inc2.dtsi
Normal file
1
dtc-1.4.5/tests/deps_inc2.dtsi
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/* Empty */
|
||||||
6
dtc-1.4.5/tests/division-by-zero.dts
Normal file
6
dtc-1.4.5/tests/division-by-zero.dts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
prop-div = < (1/0) >;
|
||||||
|
prop-mod = < (1%0) >;
|
||||||
|
};
|
||||||
163
dtc-1.4.5/tests/dtb_reverse.c
Normal file
163
dtc-1.4.5/tests/dtb_reverse.c
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Tests if two given dtbs are structurally equal (including order)
|
||||||
|
* Copyright (C) 2010 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
#define CHECK(code) \
|
||||||
|
{ \
|
||||||
|
err = (code); \
|
||||||
|
if (err) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reverse_reservemap(void *in, void *out, int n)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
uint64_t addr, size;
|
||||||
|
|
||||||
|
verbose_printf("reverse_reservemap(): %d/%d\n",
|
||||||
|
n, fdt_num_mem_rsv(in));
|
||||||
|
|
||||||
|
if (n < (fdt_num_mem_rsv(in)-1))
|
||||||
|
reverse_reservemap(in, out, n+1);
|
||||||
|
|
||||||
|
CHECK(fdt_get_mem_rsv(in, n, &addr, &size));
|
||||||
|
CHECK(fdt_add_reservemap_entry(out, addr, size));
|
||||||
|
verbose_printf("Added entry 0x%llx 0x%llx\n",
|
||||||
|
(unsigned long long)addr, (unsigned long long)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reverse_properties(void *in, void *out, int offset)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
int len;
|
||||||
|
const char *name;
|
||||||
|
const void *data;
|
||||||
|
|
||||||
|
data = fdt_getprop_by_offset(in, offset, &name, &len);
|
||||||
|
if (!data)
|
||||||
|
FAIL("fdt_getprop_by_offset(): %s\n", fdt_strerror(len));
|
||||||
|
|
||||||
|
verbose_printf("reverse_properties(): offset=%d name=%s\n",
|
||||||
|
offset, name);
|
||||||
|
|
||||||
|
offset = fdt_next_property_offset(in, offset);
|
||||||
|
if (offset >= 0)
|
||||||
|
reverse_properties(in, out, offset);
|
||||||
|
else if (offset != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("fdt_next_property_offset(): %s\n", fdt_strerror(offset));
|
||||||
|
|
||||||
|
CHECK(fdt_property(out, name, data, len));
|
||||||
|
verbose_printf(" -> output property %s\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reverse_node(void *in, void *out, int nodeoffset);
|
||||||
|
|
||||||
|
static void reverse_children(void *in, void *out, int offset)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
int nextoffset = offset;
|
||||||
|
int depth = 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
CHECK(fdt_get_path(in, nextoffset, path, sizeof(path)));
|
||||||
|
verbose_printf("reverse_children() offset=%d nextoffset=%d [%s]"
|
||||||
|
" depth=%d\n", offset, nextoffset, path, depth);
|
||||||
|
|
||||||
|
nextoffset = fdt_next_node(in, nextoffset, &depth);
|
||||||
|
} while ((depth >= 0) && (depth != 1));
|
||||||
|
|
||||||
|
if (depth == 1)
|
||||||
|
reverse_children(in, out, nextoffset);
|
||||||
|
|
||||||
|
reverse_node(in, out, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reverse_node(void *in, void *out, int nodeoffset)
|
||||||
|
{
|
||||||
|
const char *name = fdt_get_name(in, nodeoffset, NULL);
|
||||||
|
char path[PATH_MAX];
|
||||||
|
int err;
|
||||||
|
int offset;
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
CHECK(fdt_get_path(in, nodeoffset, path, sizeof(path)));
|
||||||
|
verbose_printf("reverse_node(): nodeoffset=%d [%s]\n",
|
||||||
|
nodeoffset, path);
|
||||||
|
|
||||||
|
CHECK(fdt_begin_node(out, name));
|
||||||
|
|
||||||
|
offset = fdt_first_property_offset(in, nodeoffset);
|
||||||
|
if (offset >= 0)
|
||||||
|
reverse_properties(in, out, offset);
|
||||||
|
else if (offset != -FDT_ERR_NOTFOUND)
|
||||||
|
FAIL("fdt_first_property(): %s\n", fdt_strerror(offset));
|
||||||
|
|
||||||
|
offset = fdt_next_node(in, nodeoffset, &depth);
|
||||||
|
|
||||||
|
if (depth == 1)
|
||||||
|
reverse_children(in, out, offset);
|
||||||
|
|
||||||
|
CHECK(fdt_end_node(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *in, *out;
|
||||||
|
char outname[PATH_MAX];
|
||||||
|
int bufsize;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
if (argc != 2)
|
||||||
|
CONFIG("Usage: %s <dtb file>", argv[0]);
|
||||||
|
|
||||||
|
in = load_blob(argv[1]);
|
||||||
|
sprintf(outname, "%s.reversed.test.dtb", argv[1]);
|
||||||
|
|
||||||
|
bufsize = fdt_totalsize(in);
|
||||||
|
out = xmalloc(bufsize);
|
||||||
|
|
||||||
|
CHECK(fdt_create(out, bufsize));
|
||||||
|
|
||||||
|
fdt_set_boot_cpuid_phys(out, fdt_boot_cpuid_phys(in));
|
||||||
|
|
||||||
|
reverse_reservemap(in, out, 0);
|
||||||
|
CHECK(fdt_finish_reservemap(out));
|
||||||
|
|
||||||
|
reverse_node(in, out, 0);
|
||||||
|
|
||||||
|
CHECK(fdt_finish(out));
|
||||||
|
|
||||||
|
save_blob(outname, out);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
173
dtc-1.4.5/tests/dtbs_equal_ordered.c
Normal file
173
dtc-1.4.5/tests/dtbs_equal_ordered.c
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Tests if two given dtbs are structurally equal (including order)
|
||||||
|
* Copyright (C) 2007 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
static int notequal; /* = 0 */
|
||||||
|
|
||||||
|
#define MISMATCH(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if (notequal) \
|
||||||
|
PASS(); \
|
||||||
|
else \
|
||||||
|
FAIL(fmt, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define MATCH() \
|
||||||
|
do { \
|
||||||
|
if (!notequal) \
|
||||||
|
PASS(); \
|
||||||
|
else \
|
||||||
|
FAIL("Trees match which shouldn't"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CHECK(code) \
|
||||||
|
{ \
|
||||||
|
err = (code); \
|
||||||
|
if (err) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compare_mem_rsv(const void *fdt1, const void *fdt2)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint64_t addr1, size1, addr2, size2;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2))
|
||||||
|
MISMATCH("Trees have different number of reserve entries");
|
||||||
|
for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) {
|
||||||
|
CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1));
|
||||||
|
CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2));
|
||||||
|
|
||||||
|
if ((addr1 != addr2) || (size1 != size2))
|
||||||
|
MISMATCH("Mismatch in reserve entry %d: "
|
||||||
|
"(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
|
||||||
|
(unsigned long long)addr1,
|
||||||
|
(unsigned long long)size1,
|
||||||
|
(unsigned long long)addr2,
|
||||||
|
(unsigned long long)size2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compare_structure(const void *fdt1, const void *fdt2)
|
||||||
|
{
|
||||||
|
int nextoffset1 = 0, nextoffset2 = 0;
|
||||||
|
int offset1, offset2;
|
||||||
|
uint32_t tag1, tag2;
|
||||||
|
const char *name1, *name2;
|
||||||
|
int err;
|
||||||
|
const struct fdt_property *prop1, *prop2;
|
||||||
|
int len1, len2;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
do {
|
||||||
|
offset1 = nextoffset1;
|
||||||
|
tag1 = fdt_next_tag(fdt1, offset1, &nextoffset1);
|
||||||
|
} while (tag1 == FDT_NOP);
|
||||||
|
do {
|
||||||
|
offset2 = nextoffset2;
|
||||||
|
tag2 = fdt_next_tag(fdt2, offset2, &nextoffset2);
|
||||||
|
} while (tag2 == FDT_NOP);
|
||||||
|
|
||||||
|
if (tag1 != tag2)
|
||||||
|
MISMATCH("Tag mismatch (%d != %d) at (%d, %d)",
|
||||||
|
tag1, tag2, offset1, offset2);
|
||||||
|
|
||||||
|
switch (tag1) {
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
name1 = fdt_get_name(fdt1, offset1, &err);
|
||||||
|
if (!name1)
|
||||||
|
FAIL("fdt_get_name(fdt1, %d, ..): %s",
|
||||||
|
offset1, fdt_strerror(err));
|
||||||
|
name2 = fdt_get_name(fdt2, offset2, NULL);
|
||||||
|
if (!name2)
|
||||||
|
FAIL("fdt_get_name(fdt2, %d, ..): %s",
|
||||||
|
offset2, fdt_strerror(err));
|
||||||
|
|
||||||
|
if (!streq(name1, name2))
|
||||||
|
MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)",
|
||||||
|
name1, name2, offset1, offset2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_PROP:
|
||||||
|
prop1 = fdt_offset_ptr(fdt1, offset1, sizeof(*prop1));
|
||||||
|
if (!prop1)
|
||||||
|
FAIL("Could get fdt1 property at %d", offset1);
|
||||||
|
prop2 = fdt_offset_ptr(fdt2, offset2, sizeof(*prop2));
|
||||||
|
if (!prop2)
|
||||||
|
FAIL("Could get fdt2 property at %d", offset2);
|
||||||
|
|
||||||
|
name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff));
|
||||||
|
name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff));
|
||||||
|
if (!streq(name1, name2))
|
||||||
|
MISMATCH("Property name mismatch \"%s\" != \"%s\" "
|
||||||
|
"at (%d, %d)", name1, name2, offset1, offset2);
|
||||||
|
len1 = fdt32_to_cpu(prop1->len);
|
||||||
|
len2 = fdt32_to_cpu(prop2->len);
|
||||||
|
if (len1 != len2)
|
||||||
|
MISMATCH("Property length mismatch %u != %u "
|
||||||
|
"at (%d, %d)", len1, len2, offset1, offset2);
|
||||||
|
|
||||||
|
if (memcmp(prop1->data, prop2->data, len1) != 0)
|
||||||
|
MISMATCH("Property value mismatch at (%d, %d)",
|
||||||
|
offset1, offset2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FDT_END:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt1, *fdt2;
|
||||||
|
uint32_t cpuid1, cpuid2;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
if ((argc != 3)
|
||||||
|
&& ((argc != 4) || !streq(argv[1], "-n")))
|
||||||
|
CONFIG("Usage: %s [-n] <dtb file> <dtb file>", argv[0]);
|
||||||
|
if (argc == 4)
|
||||||
|
notequal = 1;
|
||||||
|
|
||||||
|
fdt1 = load_blob(argv[argc-2]);
|
||||||
|
fdt2 = load_blob(argv[argc-1]);
|
||||||
|
|
||||||
|
compare_mem_rsv(fdt1, fdt2);
|
||||||
|
compare_structure(fdt1, fdt2);
|
||||||
|
|
||||||
|
cpuid1 = fdt_boot_cpuid_phys(fdt1);
|
||||||
|
cpuid2 = fdt_boot_cpuid_phys(fdt2);
|
||||||
|
if (cpuid1 != cpuid2)
|
||||||
|
MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x",
|
||||||
|
cpuid1, cpuid2);
|
||||||
|
|
||||||
|
MATCH();
|
||||||
|
}
|
||||||
223
dtc-1.4.5/tests/dtbs_equal_unordered.c
Normal file
223
dtc-1.4.5/tests/dtbs_equal_unordered.c
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Tests if two given dtbs are structurally equal (including order)
|
||||||
|
* Copyright (C) 2007 David Gibson, IBM Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
static int notequal; /* = 0 */
|
||||||
|
|
||||||
|
#define MISMATCH(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if (notequal) \
|
||||||
|
PASS(); \
|
||||||
|
else \
|
||||||
|
FAIL(fmt, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define MATCH() \
|
||||||
|
do { \
|
||||||
|
if (!notequal) \
|
||||||
|
PASS(); \
|
||||||
|
else \
|
||||||
|
FAIL("Trees match which shouldn't"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CHECK(code) \
|
||||||
|
{ \
|
||||||
|
err = (code); \
|
||||||
|
if (err) \
|
||||||
|
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mem_rsv_cmp(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
const struct fdt_reserve_entry *re1 = p1;
|
||||||
|
const struct fdt_reserve_entry *re2 = p2;
|
||||||
|
|
||||||
|
if (fdt64_to_cpu(re1->address) < fdt64_to_cpu(re2->address))
|
||||||
|
return -1;
|
||||||
|
else if (fdt64_to_cpu(re1->address) > fdt64_to_cpu(re2->address))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (fdt64_to_cpu(re1->size) < fdt64_to_cpu(re2->size))
|
||||||
|
return -1;
|
||||||
|
else if (fdt64_to_cpu(re1->size) > fdt64_to_cpu(re2->size))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compare_mem_rsv(void *fdt1, void *fdt2)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint64_t addr1, size1, addr2, size2;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2))
|
||||||
|
MISMATCH("Trees have different number of reserve entries");
|
||||||
|
|
||||||
|
qsort((char *)fdt1 + fdt_off_mem_rsvmap(fdt1), fdt_num_mem_rsv(fdt1),
|
||||||
|
sizeof(struct fdt_reserve_entry), mem_rsv_cmp);
|
||||||
|
qsort((char *)fdt2 + fdt_off_mem_rsvmap(fdt2), fdt_num_mem_rsv(fdt2),
|
||||||
|
sizeof(struct fdt_reserve_entry), mem_rsv_cmp);
|
||||||
|
|
||||||
|
for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) {
|
||||||
|
CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1));
|
||||||
|
CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2));
|
||||||
|
|
||||||
|
if ((addr1 != addr2) || (size1 != size2))
|
||||||
|
MISMATCH("Mismatch in reserve entry %d: "
|
||||||
|
"(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
|
||||||
|
(unsigned long long)addr1,
|
||||||
|
(unsigned long long)size1,
|
||||||
|
(unsigned long long)addr2,
|
||||||
|
(unsigned long long)size2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compare_properties(const void *fdt1, int offset1,
|
||||||
|
const void *fdt2, int offset2)
|
||||||
|
{
|
||||||
|
int offset = offset1;
|
||||||
|
|
||||||
|
/* Check the properties */
|
||||||
|
for (offset = fdt_first_property_offset(fdt1, offset1);
|
||||||
|
offset >= 0;
|
||||||
|
offset = fdt_next_property_offset(fdt1, offset)) {
|
||||||
|
const char *name;
|
||||||
|
int len1, len2;
|
||||||
|
const void *data1, *data2;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
data1 = fdt_getprop_by_offset(fdt1, offset, &name, &len1);
|
||||||
|
if (!data1)
|
||||||
|
FAIL("fdt_getprop_by_offset(): %s\n",
|
||||||
|
fdt_strerror(len1));
|
||||||
|
|
||||||
|
verbose_printf("Property '%s'\n", name);
|
||||||
|
|
||||||
|
data2 = fdt_getprop(fdt2, offset2, name, &len2);
|
||||||
|
if (!data2) {
|
||||||
|
if (len2 == -FDT_ERR_NOTFOUND)
|
||||||
|
MISMATCH("Property '%s' missing\n", name);
|
||||||
|
else
|
||||||
|
FAIL("fdt_get_property(): %s\n",
|
||||||
|
fdt_strerror(len2));
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose_printf("len1=%d data1=", len1);
|
||||||
|
for (i = 0; i < len1; i++)
|
||||||
|
verbose_printf(" %02x", ((const char *)data1)[i]);
|
||||||
|
verbose_printf("\nlen2=%d data2=", len2);
|
||||||
|
for (i = 0; i < len1; i++)
|
||||||
|
verbose_printf(" %02x", ((const char *)data2)[i]);
|
||||||
|
verbose_printf("\n");
|
||||||
|
|
||||||
|
if (len1 != len2)
|
||||||
|
MISMATCH("Property '%s' mismatched length %d vs. %d\n",
|
||||||
|
name, len1, len2);
|
||||||
|
else if (memcmp(data1, data2, len1) != 0)
|
||||||
|
MISMATCH("Property '%s' mismatched value\n", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compare_node(const void *fdt1, int offset1,
|
||||||
|
const void *fdt2, int offset2);
|
||||||
|
|
||||||
|
static void compare_subnodes(const void *fdt1, int offset1,
|
||||||
|
const void *fdt2, int offset2,
|
||||||
|
int recurse)
|
||||||
|
{
|
||||||
|
int coffset1, coffset2, depth;
|
||||||
|
|
||||||
|
for (depth = 0, coffset1 = offset1;
|
||||||
|
(coffset1 >= 0) && (depth >= 0);
|
||||||
|
coffset1 = fdt_next_node(fdt1, coffset1, &depth))
|
||||||
|
if (depth == 1) {
|
||||||
|
const char *name = fdt_get_name(fdt1, coffset1, NULL);
|
||||||
|
|
||||||
|
verbose_printf("Subnode %s\n", name);
|
||||||
|
coffset2 = fdt_subnode_offset(fdt2, offset2, name);
|
||||||
|
if (coffset2 == -FDT_ERR_NOTFOUND)
|
||||||
|
MISMATCH("Subnode %s missing\n", name);
|
||||||
|
else if (coffset2 < 0)
|
||||||
|
FAIL("fdt_subnode_offset(): %s\n",
|
||||||
|
fdt_strerror(coffset2));
|
||||||
|
|
||||||
|
if (recurse)
|
||||||
|
compare_node(fdt1, coffset1, fdt2, coffset2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compare_node(const void *fdt1, int offset1,
|
||||||
|
const void *fdt2, int offset2)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
char path1[PATH_MAX], path2[PATH_MAX];
|
||||||
|
|
||||||
|
CHECK(fdt_get_path(fdt1, offset1, path1, sizeof(path1)));
|
||||||
|
CHECK(fdt_get_path(fdt2, offset2, path2, sizeof(path2)));
|
||||||
|
|
||||||
|
if (!streq(path1, path2))
|
||||||
|
TEST_BUG("Path mismatch %s vs. %s\n", path1, path2);
|
||||||
|
|
||||||
|
verbose_printf("Checking %s\n", path1);
|
||||||
|
|
||||||
|
compare_properties(fdt1, offset1, fdt2, offset2);
|
||||||
|
compare_properties(fdt2, offset2, fdt1, offset1);
|
||||||
|
|
||||||
|
compare_subnodes(fdt1, offset1, fdt2, offset2, 1);
|
||||||
|
compare_subnodes(fdt2, offset2, fdt1, offset1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt1, *fdt2;
|
||||||
|
uint32_t cpuid1, cpuid2;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
if ((argc != 3)
|
||||||
|
&& ((argc != 4) || !streq(argv[1], "-n")))
|
||||||
|
CONFIG("Usage: %s [-n] <dtb file> <dtb file>", argv[0]);
|
||||||
|
if (argc == 4)
|
||||||
|
notequal = 1;
|
||||||
|
|
||||||
|
fdt1 = load_blob(argv[argc-2]);
|
||||||
|
fdt2 = load_blob(argv[argc-1]);
|
||||||
|
|
||||||
|
compare_mem_rsv(fdt1, fdt2);
|
||||||
|
compare_node(fdt1, 0, fdt2, 0);
|
||||||
|
|
||||||
|
cpuid1 = fdt_boot_cpuid_phys(fdt1);
|
||||||
|
cpuid2 = fdt_boot_cpuid_phys(fdt2);
|
||||||
|
if (cpuid1 != cpuid2)
|
||||||
|
MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x",
|
||||||
|
cpuid1, cpuid2);
|
||||||
|
|
||||||
|
MATCH();
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user