├── .gitattributes ├── .gitignore ├── DeviceTreeBus.sln ├── LICENSE.txt ├── README.md ├── docs ├── sq3-microsoft-volterra.dtb └── t6002-j375d.dtb └── src ├── DeviceTreeReaderApp ├── DeviceTreeReaderApp.cpp ├── DeviceTreeReaderApp.vcxproj └── DeviceTreeReaderApp.vcxproj.filters ├── fdtbus ├── Device.c ├── Device.h ├── DeviceTreeBus.inf ├── DeviceTreeBus.vcxproj ├── DeviceTreeBus.vcxproj.filters ├── Driver.c ├── Driver.h ├── Public.h ├── Queue.c ├── Queue.h ├── Trace.h └── include │ ├── TestDeviceTreeApple.h │ └── TestDeviceTreeQC.h ├── libfdt.um ├── libfdt.um.vcxproj └── libfdt.um.vcxproj.filters └── libfdt ├── fdt.c ├── fdt_addresses.c ├── fdt_check.c ├── fdt_empty_tree.c ├── fdt_overlay.c ├── fdt_ro.c ├── fdt_rw.c ├── fdt_strerror.c ├── fdt_sw.c ├── fdt_wip.c ├── include ├── fdt.h ├── libfdt.h ├── libfdt_env.h ├── libfdt_internal.h └── stdint_kmdf.h ├── libfdt.vcxproj ├── libfdt.vcxproj.filters └── version.lds /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | 365 | # Build system 366 | build/ 367 | out/ 368 | -------------------------------------------------------------------------------- /DeviceTreeBus.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33516.290 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfdt", "src\libfdt\libfdt.vcxproj", "{F8DA265D-FABB-48B2-A61E-18FB31F2C795}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeviceTreeBus", "src\fdtbus\DeviceTreeBus.vcxproj", "{84825888-8631-471F-8BB3-78389CBFB113}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfdt.um", "src\libfdt.um\libfdt.um.vcxproj", "{C358F93B-E0FF-4AC7-B056-E06442758AF5}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "um", "um", "{21E6BB48-661C-4128-98B7-BBE1916A4946}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "km", "km", "{45D2D36E-2655-4F3A-B4F5-96742305515A}" 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeviceTreeReaderApp", "src\DeviceTreeReaderApp\DeviceTreeReaderApp.vcxproj", "{98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|ARM64 = Debug|ARM64 21 | Debug|x64 = Debug|x64 22 | Release|ARM64 = Release|ARM64 23 | Release|x64 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Debug|ARM64.ActiveCfg = Debug|ARM64 27 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Debug|ARM64.Build.0 = Debug|ARM64 28 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Debug|ARM64.Deploy.0 = Debug|ARM64 29 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Debug|x64.ActiveCfg = Debug|x64 30 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Debug|x64.Build.0 = Debug|x64 31 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Debug|x64.Deploy.0 = Debug|x64 32 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Release|ARM64.ActiveCfg = Release|ARM64 33 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Release|ARM64.Build.0 = Release|ARM64 34 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Release|ARM64.Deploy.0 = Release|ARM64 35 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Release|x64.ActiveCfg = Release|x64 36 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Release|x64.Build.0 = Release|x64 37 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795}.Release|x64.Deploy.0 = Release|x64 38 | {84825888-8631-471F-8BB3-78389CBFB113}.Debug|ARM64.ActiveCfg = Debug|ARM64 39 | {84825888-8631-471F-8BB3-78389CBFB113}.Debug|ARM64.Build.0 = Debug|ARM64 40 | {84825888-8631-471F-8BB3-78389CBFB113}.Debug|ARM64.Deploy.0 = Debug|ARM64 41 | {84825888-8631-471F-8BB3-78389CBFB113}.Debug|x64.ActiveCfg = Debug|x64 42 | {84825888-8631-471F-8BB3-78389CBFB113}.Debug|x64.Build.0 = Debug|x64 43 | {84825888-8631-471F-8BB3-78389CBFB113}.Debug|x64.Deploy.0 = Debug|x64 44 | {84825888-8631-471F-8BB3-78389CBFB113}.Release|ARM64.ActiveCfg = Release|ARM64 45 | {84825888-8631-471F-8BB3-78389CBFB113}.Release|ARM64.Build.0 = Release|ARM64 46 | {84825888-8631-471F-8BB3-78389CBFB113}.Release|ARM64.Deploy.0 = Release|ARM64 47 | {84825888-8631-471F-8BB3-78389CBFB113}.Release|x64.ActiveCfg = Release|x64 48 | {84825888-8631-471F-8BB3-78389CBFB113}.Release|x64.Build.0 = Release|x64 49 | {84825888-8631-471F-8BB3-78389CBFB113}.Release|x64.Deploy.0 = Release|x64 50 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Debug|ARM64.ActiveCfg = Debug|ARM64 51 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Debug|ARM64.Build.0 = Debug|ARM64 52 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Debug|x64.ActiveCfg = Debug|x64 53 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Debug|x64.Build.0 = Debug|x64 54 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Release|ARM64.ActiveCfg = Release|ARM64 55 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Release|ARM64.Build.0 = Release|ARM64 56 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Release|x64.ActiveCfg = Release|x64 57 | {C358F93B-E0FF-4AC7-B056-E06442758AF5}.Release|x64.Build.0 = Release|x64 58 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Debug|ARM64.ActiveCfg = Debug|ARM64 59 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Debug|ARM64.Build.0 = Debug|ARM64 60 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Debug|x64.ActiveCfg = Debug|x64 61 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Debug|x64.Build.0 = Debug|x64 62 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Release|ARM64.ActiveCfg = Release|ARM64 63 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Release|ARM64.Build.0 = Release|ARM64 64 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Release|x64.ActiveCfg = Release|x64 65 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB}.Release|x64.Build.0 = Release|x64 66 | EndGlobalSection 67 | GlobalSection(SolutionProperties) = preSolution 68 | HideSolutionNode = FALSE 69 | EndGlobalSection 70 | GlobalSection(NestedProjects) = preSolution 71 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795} = {45D2D36E-2655-4F3A-B4F5-96742305515A} 72 | {84825888-8631-471F-8BB3-78389CBFB113} = {45D2D36E-2655-4F3A-B4F5-96742305515A} 73 | {C358F93B-E0FF-4AC7-B056-E06442758AF5} = {21E6BB48-661C-4128-98B7-BBE1916A4946} 74 | {98D8443B-9549-4B4F-9BB4-1A1CE08E33CB} = {21E6BB48-661C-4128-98B7-BBE1916A4946} 75 | EndGlobalSection 76 | GlobalSection(ExtensibilityGlobals) = postSolution 77 | SolutionGuid = {7B05C4B3-7A3B-4870-8563-401920D3583A} 78 | EndGlobalSection 79 | EndGlobal 80 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Device Tree Bus Driver 2 | 3 | This is a statically-enumerated Windows Bus Driver that takes a Linux/Open Firmware Flattened Device Tree input and emits devices nodes. It might be useful for certain scenarios where writing a complete ACPI DSDT table takes too much effort and time. 4 | 5 | So far it enumerates all device nodes, but doing nothing else. 6 | 7 | ## Testing 8 | 9 | Using Visual Studio 2022 and Windows 11 WDK to build. 10 | 11 | devcon install DeviceTreeBus.inf Root\DeviceTreeBus 12 | 13 | ## TODO 14 | 15 | - Make code cleaner. There are many copy and paste now. 16 | - Create ACPI device binding simular to Hyper-V Virtual Machine Bus device, and load Device Tree payload from DSDT (load Device Tree externally via Filesystem/Registry may create a security hazard) 17 | - Hide certain devices/nodes that are not applicable in PnP context, such as Interrupt Controller, Architectural Timer and PSCI information (they can be trivially translated to static ACPI tables) 18 | - Provide resource information (MMIO addresses, interrupt line, etc.) to PnP subsystem 19 | - Handle known ACPI IOCTLs for device connections with known standard binding (GPIO, I2C, etc.) 20 | - Create an interface for querying raw OF DeviceTree properties (similar/compatible to `ACPI\PRP0001`) 21 | 22 | ## License 23 | 24 | GPLv2 / BSD 25 | -------------------------------------------------------------------------------- /docs/sq3-microsoft-volterra.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imbushuo/DeviceTreeBus/58d4fe6ea35638cffa7a8aa9b7eeae6aaa6656ed/docs/sq3-microsoft-volterra.dtb -------------------------------------------------------------------------------- /docs/t6002-j375d.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imbushuo/DeviceTreeBus/58d4fe6ea35638cffa7a8aa9b7eeae6aaa6656ed/docs/t6002-j375d.dtb -------------------------------------------------------------------------------- /src/DeviceTreeReaderApp/DeviceTreeReaderApp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main(int argc, char* argv[]) 11 | { 12 | if (argc <= 1) return 0; 13 | 14 | ifstream dtbfile(argv[1], ios::binary | ios::ate); 15 | auto size = dtbfile.tellg(); 16 | dtbfile.seekg(0, ios::beg); 17 | 18 | char* dtbBuffer = NULL; 19 | dtbBuffer = reinterpret_cast(malloc(size)); 20 | if (dtbBuffer == NULL) 21 | { 22 | return -errno; 23 | } 24 | 25 | if (!dtbfile.read(dtbBuffer, size)) 26 | { 27 | dtbfile.close(); 28 | return -1; 29 | } 30 | 31 | int err; 32 | err = fdt_check_header(dtbBuffer); 33 | if (err != 0) { 34 | fprintf(stderr, "Invalid device tree binary: %s\n", fdt_strerror(err)); 35 | return 1; 36 | } 37 | 38 | int nodeoffset = 0; 39 | int depth = 0; 40 | while (nodeoffset >= 0 && depth >= 0) { 41 | printf("%d %d ", nodeoffset, depth); 42 | const char* nodename = fdt_get_name(dtbBuffer, nodeoffset, NULL); 43 | if (nodename == NULL) { 44 | fprintf(stderr, "Failed to get node name\n"); 45 | break; 46 | } 47 | printf("Node name: %s ", nodename); 48 | 49 | const auto prop = fdt_get_property(dtbBuffer, nodeoffset, "compatible", NULL); 50 | if (prop != NULL && prop->len > 0) { 51 | printf("has compatible property: %s", prop->data); 52 | } 53 | 54 | int tmpOffset = 0, tmpDepth = 0; 55 | tmpOffset = fdt_next_node(dtbBuffer, nodeoffset, &tmpDepth); 56 | if (tmpOffset >= 0) tmpDepth = fdt_node_depth(dtbBuffer, tmpOffset); 57 | bool busNode = (tmpOffset >= 0 && tmpDepth > depth) ? true : false; 58 | if (busNode) printf(" is bus node"); 59 | 60 | printf("\n"); 61 | 62 | #if 0 63 | int propoffset = fdt_first_property_offset(dtbBuffer, nodeoffset); 64 | while (propoffset >= 0) { 65 | int len; 66 | auto property = fdt_get_property_by_offset(dtbBuffer, propoffset, &len); 67 | if (property == NULL) { 68 | break; 69 | } 70 | 71 | const char* propertyName = fdt_string(dtbBuffer, fdt32_to_cpu(property->nameoff)); 72 | if (propertyName != NULL) 73 | { 74 | int proplen = fdt32_to_cpu(property->len); 75 | 76 | printf("- Property: %s = ", propertyName); 77 | for (int i = 0; i < proplen; i++) { 78 | const uint8_t c = property->data[i]; 79 | 80 | if (isprint(c)) 81 | putc(c, stdout); 82 | else 83 | printf("%02x", c); 84 | } 85 | printf("\n"); 86 | } 87 | 88 | propoffset = fdt_next_property_offset(dtbBuffer, propoffset); 89 | } 90 | #endif 91 | 92 | nodeoffset = fdt_next_node(dtbBuffer, nodeoffset, &depth); 93 | } 94 | 95 | free(dtbBuffer); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /src/DeviceTreeReaderApp/DeviceTreeReaderApp.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM64 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | ARM64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {98d8443b-9549-4b4f-9bb4-1a1ce08e33cb} 25 | DeviceTreeReaderApp 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | true 38 | v143 39 | Unicode 40 | 41 | 42 | Application 43 | false 44 | v143 45 | true 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 75 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 76 | $(SolutionDir)src\libfdt\include;$(IncludePath) 77 | 78 | 79 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 80 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 81 | $(SolutionDir)src\libfdt\include;$(IncludePath) 82 | 83 | 84 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 85 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 86 | $(SolutionDir)src\libfdt\include;$(IncludePath) 87 | 88 | 89 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 90 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 91 | $(SolutionDir)src\libfdt\include;$(IncludePath) 92 | 93 | 94 | 95 | Level3 96 | true 97 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 98 | true 99 | stdcpp17 100 | stdc17 101 | 102 | 103 | Console 104 | true 105 | 106 | 107 | 108 | 109 | Level3 110 | true 111 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | true 113 | stdcpp17 114 | stdc17 115 | 116 | 117 | Console 118 | true 119 | 120 | 121 | 122 | 123 | Level3 124 | true 125 | true 126 | true 127 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 128 | true 129 | stdcpp17 130 | stdc17 131 | 132 | 133 | Console 134 | true 135 | true 136 | true 137 | 138 | 139 | 140 | 141 | Level3 142 | true 143 | true 144 | true 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | true 147 | stdcpp17 148 | stdc17 149 | 150 | 151 | Console 152 | true 153 | true 154 | true 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | {c358f93b-e0ff-4ac7-b056-e06442758af5} 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /src/DeviceTreeReaderApp/DeviceTreeReaderApp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/fdtbus/Device.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include "device.tmh" 3 | #include "include/TestDeviceTreeApple.h" 4 | 5 | #define NTSTRSAFE_LIB 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #ifdef ALLOC_PRAGMA 13 | #pragma alloc_text (PAGE, DeviceTreeBusCreateDevice) 14 | #endif 15 | 16 | NTSTATUS 17 | DeviceTreeBusCreateDevice( 18 | _Inout_ PWDFDEVICE_INIT DeviceInit 19 | ) 20 | { 21 | WDF_OBJECT_ATTRIBUTES attributes; 22 | PFDO_DEVICE_CONTEXT deviceContext; 23 | WDFDEVICE device; 24 | NTSTATUS status; 25 | PNP_BUS_INFORMATION busInfo; 26 | DT_BUS_INTERFACE_STANDARD Interface; 27 | int err = 0; 28 | 29 | PAGED_CODE(); 30 | 31 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_CONTEXT); 32 | status = WdfDeviceCreate(&DeviceInit, &attributes, &device); 33 | if (!NT_SUCCESS(status)) { 34 | return status; 35 | } 36 | 37 | deviceContext = FdoGetContext(device); 38 | 39 | // Try to probe the device interface of parent device, and retrieve depth and offset information back 40 | status = WdfFdoQueryForInterface( 41 | device, 42 | &GUID_INTERNAL_INTERFACE_QUERY_DT, 43 | (PINTERFACE)&Interface, 44 | sizeof(Interface), 45 | 1, 46 | NULL 47 | ); 48 | 49 | // Initialize the context. 50 | if (NT_SUCCESS(status)) { 51 | if (sizeof(g_testDeviceTree) != Interface.DeviceTreeBlobSize) 52 | { 53 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! Child device has a mismatched DT"); 54 | status = STATUS_BAD_DATA; 55 | return status; 56 | } 57 | 58 | deviceContext->CurrentDepth = Interface.CurrentDepth; 59 | deviceContext->CurrentOffset = Interface.CurrentOffset; 60 | deviceContext->pDeviceTreeBlob = (VOID*)g_testDeviceTree; 61 | deviceContext->DeviceTreeBlobSize = sizeof(g_testDeviceTree); 62 | 63 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! WdfFdoQueryForInterface succeeded, this is a child device node. Depth %d, Offset %d", Interface.CurrentDepth, Interface.CurrentOffset); 64 | } 65 | else { 66 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! WdfFdoQueryForInterface failed, this is a root device node"); 67 | deviceContext->CurrentDepth = 0; 68 | deviceContext->pDeviceTreeBlob = (VOID*)g_testDeviceTree; 69 | deviceContext->DeviceTreeBlobSize = sizeof(g_testDeviceTree); 70 | deviceContext->CurrentOffset = 0; 71 | status = STATUS_SUCCESS; 72 | } 73 | 74 | // Make sure the device tree has sanity. 75 | err = fdt_check_header(deviceContext->pDeviceTreeBlob); 76 | if (err != 0) { 77 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! fdt_check_header reported invalid DT header: %d", err); 78 | return STATUS_BAD_DATA; 79 | } 80 | 81 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 82 | attributes.ParentObject = device; 83 | status = WdfWaitLockCreate(&attributes, &deviceContext->ChildLock); 84 | if (!NT_SUCCESS(status)) { 85 | return status; 86 | } 87 | 88 | // Initialize the I/O Package and any Queues 89 | status = DeviceTreeBusQueueInitialize(device); 90 | if (!NT_SUCCESS(status)) { 91 | return status; 92 | } 93 | 94 | // Create interface 95 | status = WdfDeviceCreateDeviceInterface( 96 | device, 97 | &GUID_DEVINTERFACE_DeviceTreeBus, 98 | NULL // ReferenceString 99 | ); 100 | if (!NT_SUCCESS(status)) { 101 | return status; 102 | } 103 | 104 | // Set optional bus info 105 | busInfo.BusTypeGuid = GUID_DEVCLASS_SYSTEM; 106 | busInfo.LegacyBusType = PNPBus; 107 | busInfo.BusNumber = 0; 108 | WdfDeviceSetBusInformationForChildren(device, &busInfo); 109 | 110 | // Perform static enumeration of bus device 111 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Start to enumearte devices"); 112 | if (deviceContext->CurrentDepth > 0) 113 | { 114 | status = CreateAccessNodeForChildBus(device, deviceContext, &Interface); 115 | if (!NT_SUCCESS(status)) return status; 116 | } 117 | 118 | status = EnumerateDevices(device, deviceContext); 119 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Finished enumerating devices"); 120 | 121 | return status; 122 | } 123 | 124 | NTSTATUS 125 | EnumerateDevices( 126 | _In_ WDFDEVICE Device, 127 | _In_ PFDO_DEVICE_CONTEXT Context 128 | ) 129 | { 130 | int offset = Context->CurrentOffset, depth = Context->CurrentDepth; 131 | NTSTATUS status; 132 | 133 | PAGED_CODE(); 134 | 135 | // We have strong guarantee that this will only be run by entry point, so no lock here. 136 | offset = fdt_next_node(Context->pDeviceTreeBlob, offset, &depth); 137 | while (offset >= 0 && depth >= 0) { 138 | int tmpOffset = 0, tmpDepth = 0; 139 | BOOLEAN busNode = FALSE; 140 | 141 | // For depth = 0 (Root node), automatically advance to the next node if this device is root node, otherwise 142 | // bail out 143 | if (Context->CurrentDepth == 0 && depth == 0) { 144 | goto next_node; 145 | } 146 | else if (Context->CurrentDepth != 0 && depth == 0) { 147 | break; 148 | } 149 | // For depth > 0 (child node), enumerate anything with current depth + 1, run until see node of current depth 150 | if (Context->CurrentDepth != 0 && depth <= Context->CurrentDepth) { 151 | break; 152 | } 153 | // Guardrail: only enumerate one level device 154 | if (depth > Context->CurrentDepth + 1) 155 | { 156 | goto next_node; 157 | } 158 | 159 | // Check if this is a end device node, or it's a extended bus node 160 | tmpOffset = fdt_next_node(Context->pDeviceTreeBlob, offset, &tmpDepth); 161 | if (tmpOffset >= 0) tmpDepth = fdt_node_depth(Context->pDeviceTreeBlob, tmpOffset); 162 | busNode = (tmpOffset >= 0 && tmpDepth > depth) ? TRUE : FALSE; 163 | 164 | // Read name property and enumerate the device 165 | const char* nodename = fdt_get_name(Context->pDeviceTreeBlob, offset, NULL); 166 | if (nodename == NULL) { 167 | TraceEvents(TRACE_LEVEL_WARNING, TRACE_DEVICE, "%!FUNC! Skipped enumerating node %d with no name", offset); 168 | goto next_node; 169 | } 170 | 171 | // Enumerate static device 172 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Enumerate device for %s @ %d (Depth = %d), BusNode %d", nodename, offset, depth, busNode); 173 | status = CreatePdoAndInsert(Device, Context, nodename, offset, depth, busNode); 174 | if (!NT_SUCCESS(status)) { 175 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! CreatePdoAndInsert failed on node %d with %!STATUS!", offset, status); 176 | return status; 177 | } 178 | 179 | next_node: 180 | offset = fdt_next_node(Context->pDeviceTreeBlob, offset, &depth); 181 | } 182 | 183 | return STATUS_SUCCESS; 184 | } 185 | 186 | NTSTATUS 187 | CreateAccessNodeForChildBus( 188 | _In_ WDFDEVICE Device, 189 | _In_ PFDO_DEVICE_CONTEXT Context, 190 | _In_ PDT_BUS_INTERFACE_STANDARD pInterface 191 | ) 192 | { 193 | NTSTATUS status = STATUS_SUCCESS; 194 | PWDFDEVICE_INIT pDeviceInit = NULL; 195 | WDFDEVICE hChild = NULL; 196 | WDF_OBJECT_ATTRIBUTES pdoAttributes; 197 | WDF_DEVICE_PNP_CAPABILITIES pnpCaps; 198 | WDF_DEVICE_POWER_CAPABILITIES powerCaps; 199 | 200 | ANSI_STRING nodeNameAnsi; 201 | ANSI_STRING dtCompatibleNameAnsi; 202 | UNICODE_STRING dtCompatibleNameUnicode; 203 | DECLARE_CONST_UNICODE_STRING(devNodeCompatId, DT_BUSENUM_DEVICENODE_COMPATIBLE_IDS); 204 | DECLARE_CONST_UNICODE_STRING(deviceLocation, DT_BUSENUM_LOCATION_ID); 205 | DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); 206 | DECLARE_UNICODE_STRING_SIZE(deviceId, 255); 207 | DECLARE_UNICODE_STRING_SIZE(hardwareId, 255); 208 | 209 | // Requires compatible property to successfully enumerate (for hardware ID), otherwise silently drop it 210 | const struct fdt_property* compatProperty = fdt_get_property(Context->pDeviceTreeBlob, pInterface->CurrentOffset, DT_COMPATIBLE_PROP, NULL); 211 | if (compatProperty == NULL || compatProperty->len < 1) { 212 | status = STATUS_SUCCESS; 213 | goto cleanup; 214 | } 215 | 216 | // Post process dtCompatibleName and generate hardware ID 217 | RtlInitAnsiString(&dtCompatibleNameAnsi, compatProperty->data); 218 | status = RtlAnsiStringToUnicodeString(&dtCompatibleNameUnicode, &dtCompatibleNameAnsi, TRUE); 219 | if (!NT_SUCCESS(status)) { 220 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlAnsiStringToUnicodeString with %!STATUS!", status); 221 | goto cleanup; 222 | } 223 | status = RtlUnicodeStringPrintf(&hardwareId, L"OFDT\\%wZ", &dtCompatibleNameUnicode); 224 | if (!NT_SUCCESS(status)) { 225 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlUnicodeStringPrintf with %!STATUS!", status); 226 | goto cleanup; 227 | } 228 | for (auto i = 0; i < dtCompatibleNameUnicode.Length; i++) { 229 | if (dtCompatibleNameUnicode.Buffer[i] == L',' || dtCompatibleNameUnicode.Buffer[i] == L'-' || dtCompatibleNameUnicode.Buffer[i] == L'.') { 230 | dtCompatibleNameUnicode.Buffer[i] = L'_'; 231 | } 232 | } 233 | 234 | // Build a device ID on the fly 235 | status = RtlUnicodeStringPrintf(&deviceId, L"OFDT\\DT_NODE_%d_Access", pInterface->CurrentOffset); 236 | if (!NT_SUCCESS(status)) { 237 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlUnicodeStringPrintf with %!STATUS!", status); 238 | goto cleanup; 239 | } 240 | 241 | // Post process dtCompatibleName and generate hardware ID 242 | status = RtlUnicodeStringPrintf(&hardwareId, L"OFDT\\%wZ", &dtCompatibleNameUnicode); 243 | if (!NT_SUCCESS(status)) { 244 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlUnicodeStringPrintf with %!STATUS!", status); 245 | goto cleanup; 246 | } 247 | 248 | pDeviceInit = WdfPdoInitAllocate(Device); 249 | if (pDeviceInit == NULL) { 250 | status = STATUS_INSUFFICIENT_RESOURCES; 251 | goto cleanup; 252 | } 253 | 254 | // XXX: Should this be changed? 255 | WdfDeviceInitSetDeviceType(pDeviceInit, FILE_DEVICE_BUS_EXTENDER); 256 | 257 | status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); 258 | if (!NT_SUCCESS(status)) { 259 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAssignDeviceID with %!STATUS!", status); 260 | goto cleanup; 261 | } 262 | 263 | status = WdfPdoInitAddHardwareID(pDeviceInit, &hardwareId); 264 | if (!NT_SUCCESS(status)) { 265 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAddHardwareID with %!STATUS!", status); 266 | goto cleanup; 267 | } 268 | 269 | status = WdfPdoInitAddCompatibleID(pDeviceInit, &devNodeCompatId); 270 | if (!NT_SUCCESS(status)) { 271 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAddCompatibleID with %!STATUS!", status); 272 | goto cleanup; 273 | } 274 | 275 | status = RtlUnicodeStringPrintf(&buffer, L"%02d", pInterface->CurrentOffset + 1); 276 | if (!NT_SUCCESS(status)) { 277 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlUnicodeStringPrintf with %!STATUS!", status); 278 | goto cleanup; 279 | } 280 | 281 | status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); 282 | if (!NT_SUCCESS(status)) { 283 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAssignInstanceID with %!STATUS!", status); 284 | goto cleanup; 285 | } 286 | 287 | const char* nodename = fdt_get_name(Context->pDeviceTreeBlob, pInterface->CurrentOffset, NULL); 288 | RtlInitAnsiString(&nodeNameAnsi, nodename); 289 | status = RtlAnsiStringToUnicodeString(&buffer, &nodeNameAnsi, FALSE); 290 | if (!NT_SUCCESS(status)) { 291 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlAnsiStringToUnicodeString with %!STATUS!", status); 292 | goto cleanup; 293 | } 294 | 295 | status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x409); 296 | if (!NT_SUCCESS(status)) { 297 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAddDeviceText with %!STATUS!", status); 298 | goto cleanup; 299 | } 300 | 301 | WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); 302 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_DEVICE_CONTEXT); 303 | status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); 304 | if (!NT_SUCCESS(status)) { 305 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfDeviceCreate with %!STATUS!", status); 306 | goto cleanup; 307 | } 308 | 309 | PPDO_DEVICE_CONTEXT pdoData = PdoGetContext(hChild); 310 | pdoData->CurrentDepth = pInterface->CurrentDepth; 311 | pdoData->CurrentOffset = pInterface->CurrentOffset; 312 | pdoData->DeviceTreeBlobSize = Context->DeviceTreeBlobSize; 313 | pdoData->pDeviceTreeBlob = Context->pDeviceTreeBlob; 314 | 315 | // Platform device, can't be removed 316 | WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); 317 | pnpCaps.Removable = WdfFalse; 318 | pnpCaps.EjectSupported = WdfFalse; 319 | pnpCaps.SurpriseRemovalOK = WdfFalse; 320 | pnpCaps.Address = pInterface->CurrentOffset + 1; 321 | pnpCaps.UINumber = pInterface->CurrentOffset + 1; 322 | WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); 323 | 324 | WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps); 325 | powerCaps.DeviceD1 = WdfTrue; 326 | powerCaps.WakeFromD1 = WdfTrue; 327 | powerCaps.DeviceWake = PowerDeviceD1; 328 | powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0; 329 | powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1; 330 | powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3; 331 | powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3; 332 | powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3; 333 | powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3; 334 | WdfDeviceSetPowerCapabilities(hChild, &powerCaps); 335 | 336 | status = WdfFdoAddStaticChild(Device, hChild); 337 | if (!NT_SUCCESS(status)) { 338 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfFdoAddStaticChild with %!STATUS!", status); 339 | goto cleanup; 340 | } 341 | 342 | cleanup: 343 | if (pDeviceInit != NULL) WdfDeviceInitFree(pDeviceInit); 344 | if (hChild) WdfObjectDelete(hChild); 345 | return status; 346 | } 347 | 348 | NTSTATUS 349 | CreatePdoAndInsert( 350 | _In_ WDFDEVICE Device, 351 | _In_ PFDO_DEVICE_CONTEXT Context, 352 | _In_ const char* NodeName, 353 | _In_ int Offset, 354 | _In_ int Depth, 355 | _In_ BOOLEAN IsBusNode 356 | ) 357 | { 358 | NTSTATUS status = STATUS_SUCCESS; 359 | PWDFDEVICE_INIT pDeviceInit = NULL; 360 | WDFDEVICE hChild = NULL; 361 | WDF_OBJECT_ATTRIBUTES pdoAttributes; 362 | WDF_DEVICE_PNP_CAPABILITIES pnpCaps; 363 | WDF_DEVICE_POWER_CAPABILITIES powerCaps; 364 | 365 | ANSI_STRING nodeNameAnsi; 366 | ANSI_STRING dtCompatibleNameAnsi; 367 | UNICODE_STRING dtCompatibleNameUnicode; 368 | DECLARE_CONST_UNICODE_STRING(busNodeCompatId, DT_BUSENUM_BUSNODE_COMPATIBLE_IDS); 369 | DECLARE_CONST_UNICODE_STRING(devNodeCompatId, DT_BUSENUM_DEVICENODE_COMPATIBLE_IDS); 370 | DECLARE_CONST_UNICODE_STRING(deviceLocation, DT_BUSENUM_LOCATION_ID); 371 | DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); 372 | DECLARE_UNICODE_STRING_SIZE(deviceId, 255); 373 | DECLARE_UNICODE_STRING_SIZE(hardwareId, 255); 374 | 375 | DT_BUS_INTERFACE_STANDARD BusInterface; 376 | WDF_QUERY_INTERFACE_CONFIG qiConfig; 377 | 378 | PAGED_CODE(); 379 | 380 | // Requires compatible property to successfully enumerate (for hardware ID), otherwise silently drop it 381 | const struct fdt_property* compatProperty = fdt_get_property(Context->pDeviceTreeBlob, Offset, DT_COMPATIBLE_PROP, NULL); 382 | if (compatProperty == NULL || compatProperty->len < 1) { 383 | status = STATUS_SUCCESS; 384 | goto cleanup; 385 | } 386 | 387 | // Build a device ID on the fly 388 | status = RtlUnicodeStringPrintf(&deviceId, L"OFDT\\DT_NODE_%d", Offset); 389 | if (!NT_SUCCESS(status)) { 390 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlUnicodeStringPrintf with %!STATUS!", status); 391 | goto cleanup; 392 | } 393 | 394 | // Post process dtCompatibleName and generate hardware ID 395 | RtlInitAnsiString(&dtCompatibleNameAnsi, compatProperty->data); 396 | status = RtlAnsiStringToUnicodeString(&dtCompatibleNameUnicode, &dtCompatibleNameAnsi, TRUE); 397 | if (!NT_SUCCESS(status)) { 398 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlAnsiStringToUnicodeString with %!STATUS!", status); 399 | goto cleanup; 400 | } 401 | for (auto i = 0; i < dtCompatibleNameUnicode.Length; i++) { 402 | if (dtCompatibleNameUnicode.Buffer[i] == L',' || dtCompatibleNameUnicode.Buffer[i] == L'-' || dtCompatibleNameUnicode.Buffer[i] == L'.') { 403 | dtCompatibleNameUnicode.Buffer[i] = L'_'; 404 | } 405 | } 406 | status = RtlUnicodeStringPrintf(&hardwareId, L"OFDT\\%wZ", &dtCompatibleNameUnicode); 407 | if (!NT_SUCCESS(status)) { 408 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlUnicodeStringPrintf with %!STATUS!", status); 409 | goto cleanup; 410 | } 411 | 412 | pDeviceInit = WdfPdoInitAllocate(Device); 413 | if (pDeviceInit == NULL) { 414 | status = STATUS_INSUFFICIENT_RESOURCES; 415 | goto cleanup; 416 | } 417 | 418 | // XXX: Should this be changed? 419 | WdfDeviceInitSetDeviceType(pDeviceInit, FILE_DEVICE_BUS_EXTENDER); 420 | 421 | status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); 422 | if (!NT_SUCCESS(status)) { 423 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAssignDeviceID with %!STATUS!", status); 424 | goto cleanup; 425 | } 426 | 427 | status = WdfPdoInitAddHardwareID(pDeviceInit, IsBusNode ? &deviceId : &hardwareId); 428 | if (!NT_SUCCESS(status)) { 429 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAddHardwareID with %!STATUS!", status); 430 | goto cleanup; 431 | } 432 | 433 | status = WdfPdoInitAddCompatibleID(pDeviceInit, IsBusNode ? &busNodeCompatId : &devNodeCompatId); 434 | if (!NT_SUCCESS(status)) { 435 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAddCompatibleID with %!STATUS!", status); 436 | goto cleanup; 437 | } 438 | 439 | status = RtlUnicodeStringPrintf(&buffer, L"%02d", Offset); 440 | if (!NT_SUCCESS(status)) { 441 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlUnicodeStringPrintf with %!STATUS!", status); 442 | goto cleanup; 443 | } 444 | 445 | status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); 446 | if (!NT_SUCCESS(status)) { 447 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAssignInstanceID with %!STATUS!", status); 448 | goto cleanup; 449 | } 450 | 451 | RtlInitAnsiString(&nodeNameAnsi, NodeName); 452 | status = RtlAnsiStringToUnicodeString(&buffer, &nodeNameAnsi, FALSE); 453 | if (!NT_SUCCESS(status)) { 454 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! RtlAnsiStringToUnicodeString with %!STATUS!", status); 455 | goto cleanup; 456 | } 457 | 458 | status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x409); 459 | if (!NT_SUCCESS(status)) { 460 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAddDeviceText with %!STATUS!", status); 461 | goto cleanup; 462 | } 463 | 464 | WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); 465 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_DEVICE_CONTEXT); 466 | status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); 467 | if (!NT_SUCCESS(status)) { 468 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfDeviceCreate with %!STATUS!", status); 469 | goto cleanup; 470 | } 471 | 472 | PPDO_DEVICE_CONTEXT pdoData = PdoGetContext(hChild); 473 | pdoData->CurrentDepth = Depth; 474 | pdoData->CurrentOffset = Offset; 475 | pdoData->DeviceTreeBlobSize = Context->DeviceTreeBlobSize; 476 | pdoData->pDeviceTreeBlob = Context->pDeviceTreeBlob; 477 | 478 | // Platform device, can't be removed 479 | WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); 480 | pnpCaps.Removable = WdfFalse; 481 | pnpCaps.EjectSupported = WdfFalse; 482 | pnpCaps.SurpriseRemovalOK = WdfFalse; 483 | pnpCaps.Address = Offset; 484 | pnpCaps.UINumber = Offset; 485 | WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); 486 | 487 | WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps); 488 | powerCaps.DeviceD1 = WdfTrue; 489 | powerCaps.WakeFromD1 = WdfTrue; 490 | powerCaps.DeviceWake = PowerDeviceD1; 491 | powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0; 492 | powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1; 493 | powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3; 494 | powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3; 495 | powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3; 496 | powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3; 497 | WdfDeviceSetPowerCapabilities(hChild, &powerCaps); 498 | 499 | // Add an interface for child device use 500 | if (IsBusNode) { 501 | RtlZeroMemory(&BusInterface, sizeof(BusInterface)); 502 | BusInterface.InterfaceHeader.Size = sizeof(BusInterface); 503 | BusInterface.InterfaceHeader.Version = 1; 504 | BusInterface.InterfaceHeader.Context = (PVOID)hChild; 505 | BusInterface.InterfaceHeader.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; 506 | BusInterface.InterfaceHeader.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; 507 | BusInterface.CurrentDepth = Depth; 508 | BusInterface.CurrentOffset = Offset; 509 | BusInterface.DeviceTreeBlobSize = Context->DeviceTreeBlobSize; 510 | BusInterface.pDeviceTreeBlob = Context->pDeviceTreeBlob; 511 | 512 | WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig, 513 | (PINTERFACE)&BusInterface, 514 | &GUID_INTERNAL_INTERFACE_QUERY_DT, 515 | NULL); 516 | 517 | status = WdfDeviceAddQueryInterface(hChild, &qiConfig); 518 | if (!NT_SUCCESS(status)) { 519 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfDeviceAddQueryInterface with %!STATUS!", status); 520 | goto cleanup; 521 | } 522 | } 523 | 524 | status = WdfFdoAddStaticChild(Device, hChild); 525 | if (!NT_SUCCESS(status)) { 526 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfFdoAddStaticChild with %!STATUS!", status); 527 | goto cleanup; 528 | } 529 | 530 | cleanup: 531 | if (pDeviceInit != NULL) WdfDeviceInitFree(pDeviceInit); 532 | if (hChild) WdfObjectDelete(hChild); 533 | return status; 534 | } 535 | -------------------------------------------------------------------------------- /src/fdtbus/Device.h: -------------------------------------------------------------------------------- 1 | #include "public.h" 2 | 3 | EXTERN_C_START 4 | 5 | // 6 | // The device context performs the same job as 7 | // a WDM device extension in the driver frameworks 8 | // 9 | typedef struct _FDO_DEVICE_CONTEXT 10 | { 11 | WDFWAITLOCK ChildLock; 12 | 13 | VOID* pDeviceTreeBlob; 14 | size_t DeviceTreeBlobSize; 15 | 16 | int CurrentDepth; 17 | int CurrentOffset; 18 | } FDO_DEVICE_CONTEXT, *PFDO_DEVICE_CONTEXT; 19 | 20 | typedef struct _PDO_DEVICE_CONTEXT 21 | { 22 | VOID* pDeviceTreeBlob; 23 | size_t DeviceTreeBlobSize; 24 | 25 | int CurrentDepth; 26 | int CurrentOffset; 27 | } PDO_DEVICE_CONTEXT, *PPDO_DEVICE_CONTEXT; 28 | 29 | typedef struct _DT_BUS_INTERFACE_STANDARD { 30 | INTERFACE InterfaceHeader; 31 | 32 | VOID* pDeviceTreeBlob; 33 | size_t DeviceTreeBlobSize; 34 | int CurrentDepth; 35 | int CurrentOffset; 36 | } DT_BUS_INTERFACE_STANDARD, *PDT_BUS_INTERFACE_STANDARD; 37 | 38 | // 39 | // This macro will generate an inline function called DeviceGetContext 40 | // which will be used to get a pointer to the device context memory 41 | // in a type safe manner. 42 | // 43 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DEVICE_CONTEXT, FdoGetContext) 44 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_DEVICE_CONTEXT, PdoGetContext) 45 | 46 | // 47 | // Function to initialize the device and its callbacks 48 | // 49 | NTSTATUS 50 | DeviceTreeBusCreateDevice( 51 | _Inout_ PWDFDEVICE_INIT DeviceInit 52 | ); 53 | 54 | NTSTATUS 55 | EnumerateDevices( 56 | _In_ WDFDEVICE Device, 57 | _In_ PFDO_DEVICE_CONTEXT Context 58 | ); 59 | 60 | NTSTATUS 61 | CreatePdoAndInsert( 62 | _In_ WDFDEVICE Device, 63 | _In_ PFDO_DEVICE_CONTEXT Context, 64 | _In_ const char* NodeName, 65 | _In_ int Offset, 66 | _In_ int Depth, 67 | _In_ BOOLEAN IsBusNode 68 | ); 69 | 70 | NTSTATUS 71 | CreateAccessNodeForChildBus( 72 | _In_ WDFDEVICE Device, 73 | _In_ PFDO_DEVICE_CONTEXT Context, 74 | _In_ PDT_BUS_INTERFACE_STANDARD pInterface 75 | ); 76 | 77 | #define DT_BUSENUM_DEVICENODE_COMPATIBLE_IDS L"DEVICETREE\\DeviceNode" 78 | #define DT_BUSENUM_DEVICENODE_COMPATIBLE_IDS_LENGTH sizeof(DT_BUSENUM_DEVICENODE_COMPATIBLE_IDS) 79 | 80 | #define DT_BUSENUM_BUSNODE_COMPATIBLE_IDS L"DEVICETREE\\BusNode" 81 | #define DT_BUSENUM_BUSNODE_COMPATIBLE_IDS_LENGTH sizeof(DT_BUSENUM_BUSNODE_COMPATIBLE_IDS) 82 | 83 | #define DT_BUSENUM_LOCATION_ID L"Device Tree Bus 0" 84 | 85 | #define DT_COMPATIBLE_PROP "compatible" 86 | 87 | #define MAX_ID_LEN 255 88 | 89 | EXTERN_C_END 90 | -------------------------------------------------------------------------------- /src/fdtbus/DeviceTreeBus.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; DeviceTreeBus.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System ; TODO: specify appropriate Class 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} ; TODO: specify appropriate ClassGuid 9 | Provider=%ManufacturerName% 10 | CatalogFile=DeviceTreeBus.cat 11 | DriverVer= ; TODO: set DriverVer in stampinf property pages 12 | PnpLockdown=1 13 | 14 | [DestinationDirs] 15 | DefaultDestDir = 12 16 | DeviceTreeBus_Device_CoInstaller_CopyFiles = 11 17 | 18 | [SourceDisksNames] 19 | 1 = %DiskName%,,,"" 20 | 21 | [SourceDisksFiles] 22 | DeviceTreeBus.sys = 1,, 23 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames 24 | 25 | ;***************************************** 26 | ; Install Section 27 | ;***************************************** 28 | 29 | [Manufacturer] 30 | %ManufacturerName%=Standard,NT$ARCH$ 31 | 32 | [Standard.NT$ARCH$] 33 | %DeviceTreeBus.DeviceDesc%=DeviceTreeBus_Device, Root\DeviceTreeBus 34 | %DeviceTreeDeviceNodeBus.DeviceDesc%=DeviceTreeBus_Device, DEVICETREE\BusNode 35 | 36 | [DeviceTreeBus_Device.NT] 37 | CopyFiles=Drivers_Dir 38 | 39 | [Drivers_Dir] 40 | DeviceTreeBus.sys 41 | 42 | ;-------------- Service installation 43 | [DeviceTreeBus_Device.NT.Services] 44 | AddService = DeviceTreeBus,%SPSVCINST_ASSOCSERVICE%, DeviceTreeBus_Service_Inst 45 | 46 | ; -------------- DeviceTreeBus driver install sections 47 | [DeviceTreeBus_Service_Inst] 48 | DisplayName = %DeviceTreeBus.SVCDESC% 49 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 50 | StartType = 3 ; SERVICE_DEMAND_START 51 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 52 | ServiceBinary = %12%\DeviceTreeBus.sys 53 | 54 | ; 55 | ;--- DeviceTreeBus_Device Coinstaller installation ------ 56 | ; 57 | 58 | [DeviceTreeBus_Device.NT.CoInstallers] 59 | AddReg=DeviceTreeBus_Device_CoInstaller_AddReg 60 | CopyFiles=DeviceTreeBus_Device_CoInstaller_CopyFiles 61 | 62 | [DeviceTreeBus_Device_CoInstaller_AddReg] 63 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 64 | 65 | [DeviceTreeBus_Device_CoInstaller_CopyFiles] 66 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 67 | 68 | [DeviceTreeBus_Device.NT.Wdf] 69 | KmdfService = DeviceTreeBus, DeviceTreeBus_wdfsect 70 | [DeviceTreeBus_wdfsect] 71 | KmdfLibraryVersion = $KMDFVERSION$ 72 | 73 | [Strings] 74 | SPSVCINST_ASSOCSERVICE= 0x00000002 75 | ManufacturerName="Random" 76 | DiskName = "DeviceTreeBus Installation Disk" 77 | DeviceTreeBus.DeviceDesc = "Flattened Device Tree Root Bus Module" 78 | DeviceTreeDeviceNodeBus.DeviceDesc = "Device Node" 79 | DeviceTreeBus.SVCDESC = "FDT Device Tree Bus Service" 80 | -------------------------------------------------------------------------------- /src/fdtbus/DeviceTreeBus.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {84825888-8631-471F-8BB3-78389CBFB113} 40 | {497e31cb-056b-4f31-abb8-447fd55ee5a5} 41 | v4.5 42 | 12.0 43 | Debug 44 | x64 45 | DeviceTreeBus 46 | $(LatestTargetPlatformVersion) 47 | 48 | 49 | 50 | Windows10 51 | true 52 | WindowsKernelModeDriver10.0 53 | Driver 54 | KMDF 55 | Universal 56 | 1 57 | 33 58 | 33 59 | 60 | 61 | Windows10 62 | false 63 | WindowsKernelModeDriver10.0 64 | Driver 65 | KMDF 66 | Universal 67 | 1 68 | 33 69 | 33 70 | 71 | 72 | Windows10 73 | true 74 | WindowsKernelModeDriver10.0 75 | Driver 76 | KMDF 77 | Universal 78 | 1 79 | 33 80 | 33 81 | 82 | 83 | Windows10 84 | false 85 | WindowsKernelModeDriver10.0 86 | Driver 87 | KMDF 88 | Universal 89 | 1 90 | 33 91 | 33 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | DbgengKernelDebugger 103 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 104 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 105 | $(SolutionDir)src\libfdt\include;$(IncludePath) 106 | 107 | 108 | DbgengKernelDebugger 109 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 110 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 111 | $(SolutionDir)src\libfdt\include;$(IncludePath) 112 | 113 | 114 | DbgengKernelDebugger 115 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 116 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 117 | $(SolutionDir)src\libfdt\include;$(IncludePath) 118 | 119 | 120 | DbgengKernelDebugger 121 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 122 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 123 | $(SolutionDir)src\libfdt\include;$(IncludePath) 124 | 125 | 126 | 127 | true 128 | true 129 | trace.h 130 | true 131 | stdc17 132 | stdcpp17 133 | 134 | 135 | sha256 136 | 137 | 138 | $(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) 139 | 140 | 141 | 142 | 143 | true 144 | true 145 | trace.h 146 | true 147 | stdc17 148 | stdcpp17 149 | 150 | 151 | sha256 152 | 153 | 154 | $(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) 155 | 156 | 157 | 158 | 159 | true 160 | true 161 | trace.h 162 | true 163 | stdc17 164 | stdcpp17 165 | 166 | 167 | sha256 168 | 169 | 170 | $(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) 171 | 172 | 173 | 174 | 175 | true 176 | true 177 | trace.h 178 | true 179 | stdc17 180 | stdcpp17 181 | 182 | 183 | sha256 184 | 185 | 186 | $(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | {f8da265d-fabb-48b2-a61e-18fb31f2c795} 195 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /src/fdtbus/DeviceTreeBus.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/fdtbus/Driver.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include "driver.tmh" 3 | 4 | #ifdef ALLOC_PRAGMA 5 | #pragma alloc_text (INIT, DriverEntry) 6 | #pragma alloc_text (PAGE, DeviceTreeBusEvtDeviceAdd) 7 | #pragma alloc_text (PAGE, DeviceTreeBusEvtDriverContextCleanup) 8 | #endif 9 | 10 | NTSTATUS 11 | DriverEntry( 12 | _In_ PDRIVER_OBJECT DriverObject, 13 | _In_ PUNICODE_STRING RegistryPath 14 | ) 15 | { 16 | WDF_DRIVER_CONFIG config; 17 | NTSTATUS status; 18 | WDF_OBJECT_ATTRIBUTES attributes; 19 | 20 | // 21 | // Initialize WPP Tracing 22 | // 23 | WPP_INIT_TRACING(DriverObject, RegistryPath); 24 | 25 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); 26 | 27 | // 28 | // Register a cleanup callback so that we can call WPP_CLEANUP when 29 | // the framework driver object is deleted during driver unload. 30 | // 31 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 32 | attributes.EvtCleanupCallback = DeviceTreeBusEvtDriverContextCleanup; 33 | 34 | WDF_DRIVER_CONFIG_INIT(&config, 35 | DeviceTreeBusEvtDeviceAdd 36 | ); 37 | 38 | status = WdfDriverCreate(DriverObject, 39 | RegistryPath, 40 | &attributes, 41 | &config, 42 | WDF_NO_HANDLE 43 | ); 44 | 45 | if (!NT_SUCCESS(status)) { 46 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status); 47 | WPP_CLEANUP(DriverObject); 48 | return status; 49 | } 50 | 51 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); 52 | return status; 53 | } 54 | 55 | NTSTATUS 56 | DeviceTreeBusEvtDeviceAdd( 57 | _In_ WDFDRIVER Driver, 58 | _Inout_ PWDFDEVICE_INIT DeviceInit 59 | ) 60 | { 61 | NTSTATUS status; 62 | 63 | UNREFERENCED_PARAMETER(Driver); 64 | PAGED_CODE(); 65 | 66 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); 67 | 68 | WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); 69 | WdfDeviceInitSetExclusive(DeviceInit, TRUE); 70 | 71 | status = DeviceTreeBusCreateDevice(DeviceInit); 72 | 73 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); 74 | return status; 75 | } 76 | 77 | VOID 78 | DeviceTreeBusEvtDriverContextCleanup( 79 | _In_ WDFOBJECT DriverObject 80 | ) 81 | { 82 | UNREFERENCED_PARAMETER(DriverObject); 83 | 84 | PAGED_CODE(); 85 | 86 | TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); 87 | 88 | // 89 | // Stop WPP Tracing 90 | // 91 | WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject)); 92 | } 93 | -------------------------------------------------------------------------------- /src/fdtbus/Driver.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Module Name: 4 | 5 | driver.h 6 | 7 | Abstract: 8 | 9 | This file contains the driver definitions. 10 | 11 | Environment: 12 | 13 | Kernel-mode Driver Framework 14 | 15 | --*/ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "device.h" 22 | #include "queue.h" 23 | #include "trace.h" 24 | 25 | EXTERN_C_START 26 | 27 | // 28 | // WDFDRIVER Events 29 | // 30 | 31 | DRIVER_INITIALIZE DriverEntry; 32 | EVT_WDF_DRIVER_DEVICE_ADD DeviceTreeBusEvtDeviceAdd; 33 | EVT_WDF_OBJECT_CONTEXT_CLEANUP DeviceTreeBusEvtDriverContextCleanup; 34 | 35 | EXTERN_C_END 36 | -------------------------------------------------------------------------------- /src/fdtbus/Public.h: -------------------------------------------------------------------------------- 1 | // 2 | // Define an Interface Guid so that apps can find the device and talk to it. 3 | // 4 | 5 | DEFINE_GUID (GUID_DEVINTERFACE_DeviceTreeBus, 6 | 0xa7f0bca4,0xe8ba,0x4aa9,0x85,0xb5,0x15,0x75,0x07,0xcf,0x41,0xad); 7 | // {a7f0bca4-e8ba-4aa9-85b5-157507cf41ad} 8 | 9 | DEFINE_GUID(GUID_INTERNAL_INTERFACE_QUERY_DT, 10 | 0x6a7b374a, 0x4794, 0x4999, 0x88, 0xa9, 0x75, 0x54, 0xc9, 0x6e, 0x28, 0xa3); 11 | // {6A7B374A-4794-4999-88A9-7554C96E28A3} 12 | -------------------------------------------------------------------------------- /src/fdtbus/Queue.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include "queue.tmh" 3 | 4 | #ifdef ALLOC_PRAGMA 5 | #pragma alloc_text (PAGE, DeviceTreeBusQueueInitialize) 6 | #endif 7 | 8 | NTSTATUS 9 | DeviceTreeBusQueueInitialize( 10 | _In_ WDFDEVICE Device 11 | ) 12 | { 13 | WDFQUEUE queue; 14 | NTSTATUS status; 15 | WDF_IO_QUEUE_CONFIG queueConfig; 16 | 17 | PAGED_CODE(); 18 | 19 | // 20 | // Configure a default queue so that requests that are not 21 | // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto 22 | // other queues get dispatched here. 23 | // 24 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( 25 | &queueConfig, 26 | WdfIoQueueDispatchParallel 27 | ); 28 | 29 | queueConfig.EvtIoDeviceControl = DeviceTreeBusEvtIoDeviceControl; 30 | 31 | __analysis_assume(queueConfig.EvtIoStop != 0); 32 | status = WdfIoQueueCreate( 33 | Device, 34 | &queueConfig, 35 | WDF_NO_OBJECT_ATTRIBUTES, 36 | &queue 37 | ); 38 | __analysis_assume(queueConfig.EvtIoStop == 0); 39 | 40 | if(!NT_SUCCESS(status)) { 41 | TraceEvents(TRACE_LEVEL_ERROR, TRACE_QUEUE, "WdfIoQueueCreate failed %!STATUS!", status); 42 | return status; 43 | } 44 | 45 | return status; 46 | } 47 | 48 | VOID 49 | DeviceTreeBusEvtIoDeviceControl( 50 | _In_ WDFQUEUE Queue, 51 | _In_ WDFREQUEST Request, 52 | _In_ size_t OutputBufferLength, 53 | _In_ size_t InputBufferLength, 54 | _In_ ULONG IoControlCode 55 | ) 56 | { 57 | TraceEvents(TRACE_LEVEL_INFORMATION, 58 | TRACE_QUEUE, 59 | "%!FUNC! Queue 0x%p, Request 0x%p OutputBufferLength %d InputBufferLength %d IoControlCode %d", 60 | Queue, Request, (int) OutputBufferLength, (int) InputBufferLength, IoControlCode); 61 | 62 | WdfRequestComplete(Request, STATUS_SUCCESS); 63 | 64 | return; 65 | } 66 | -------------------------------------------------------------------------------- /src/fdtbus/Queue.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Module Name: 4 | 5 | queue.h 6 | 7 | Abstract: 8 | 9 | This file contains the queue definitions. 10 | 11 | Environment: 12 | 13 | Kernel-mode Driver Framework 14 | 15 | --*/ 16 | 17 | EXTERN_C_START 18 | 19 | // 20 | // This is the context that can be placed per queue 21 | // and would contain per queue information. 22 | // 23 | typedef struct _QUEUE_CONTEXT { 24 | 25 | ULONG PrivateDeviceData; // just a placeholder 26 | 27 | } QUEUE_CONTEXT, *PQUEUE_CONTEXT; 28 | 29 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext) 30 | 31 | NTSTATUS 32 | DeviceTreeBusQueueInitialize( 33 | _In_ WDFDEVICE Device 34 | ); 35 | 36 | // 37 | // Events from the IoQueue object 38 | // 39 | EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL DeviceTreeBusEvtIoDeviceControl; 40 | 41 | EXTERN_C_END 42 | -------------------------------------------------------------------------------- /src/fdtbus/Trace.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Module Name: 4 | 5 | Trace.h 6 | 7 | Abstract: 8 | 9 | Header file for the debug tracing related function defintions and macros. 10 | 11 | Environment: 12 | 13 | Kernel mode 14 | 15 | --*/ 16 | 17 | // 18 | // Define the tracing flags. 19 | // 20 | // Tracing GUID - a49c8414-8f7e-4fc4-9cad-df394284e216 21 | // 22 | 23 | #define WPP_CONTROL_GUIDS \ 24 | WPP_DEFINE_CONTROL_GUID( \ 25 | DeviceTreeBusTraceGuid, (a49c8414,8f7e,4fc4,9cad,df394284e216), \ 26 | \ 27 | WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ 28 | WPP_DEFINE_BIT(TRACE_DRIVER) \ 29 | WPP_DEFINE_BIT(TRACE_DEVICE) \ 30 | WPP_DEFINE_BIT(TRACE_QUEUE) \ 31 | ) 32 | 33 | #define WPP_FLAG_LEVEL_LOGGER(flag, level) \ 34 | WPP_LEVEL_LOGGER(flag) 35 | 36 | #define WPP_FLAG_LEVEL_ENABLED(flag, level) \ 37 | (WPP_LEVEL_ENABLED(flag) && \ 38 | WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) 39 | 40 | #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ 41 | WPP_LEVEL_LOGGER(flags) 42 | 43 | #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ 44 | (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) 45 | 46 | // 47 | // WPP orders static parameters before dynamic parameters. To support the Trace function 48 | // defined below which sets FLAGS=MYDRIVER_ALL_INFO, a custom macro must be defined to 49 | // reorder the arguments to what the .tpl configuration file expects. 50 | // 51 | #define WPP_RECORDER_FLAGS_LEVEL_ARGS(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags) 52 | #define WPP_RECORDER_FLAGS_LEVEL_FILTER(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl, flags) 53 | 54 | // 55 | // This comment block is scanned by the trace preprocessor to define our 56 | // Trace function. 57 | // 58 | // begin_wpp config 59 | // FUNC Trace{FLAGS=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); 60 | // FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); 61 | // end_wpp 62 | // 63 | -------------------------------------------------------------------------------- /src/libfdt.um/libfdt.um.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM64 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | ARM64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 16.0 41 | Win32Proj 42 | {c358f93b-e0ff-4ac7-b056-e06442758af5} 43 | libfdtum 44 | 10.0 45 | 46 | 47 | 48 | StaticLibrary 49 | true 50 | v143 51 | Unicode 52 | 53 | 54 | StaticLibrary 55 | true 56 | v143 57 | Unicode 58 | 59 | 60 | StaticLibrary 61 | false 62 | v143 63 | true 64 | Unicode 65 | 66 | 67 | StaticLibrary 68 | false 69 | v143 70 | true 71 | Unicode 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 93 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 94 | $(SolutionDir)src\libfdt\include;$(IncludePath) 95 | 96 | 97 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 98 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 99 | $(SolutionDir)src\libfdt\include;$(IncludePath) 100 | 101 | 102 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 103 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 104 | $(SolutionDir)src\libfdt\include;$(IncludePath) 105 | 106 | 107 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 108 | $(SolutionDir)build\$(ProjectName)\$(Platform).$(Configuration)\ 109 | $(SolutionDir)src\libfdt\include;$(IncludePath) 110 | 111 | 112 | 113 | Level3 114 | true 115 | _DEBUG;_LIB;%(PreprocessorDefinitions) 116 | true 117 | NotUsing 118 | pch.h 119 | stdcpp17 120 | stdc17 121 | 122 | 123 | 124 | 125 | true 126 | 127 | 128 | 129 | 130 | Level3 131 | true 132 | _DEBUG;_LIB;%(PreprocessorDefinitions) 133 | true 134 | NotUsing 135 | pch.h 136 | stdcpp17 137 | stdc17 138 | 139 | 140 | 141 | 142 | true 143 | 144 | 145 | 146 | 147 | Level3 148 | true 149 | true 150 | true 151 | NDEBUG;_LIB;%(PreprocessorDefinitions) 152 | true 153 | NotUsing 154 | pch.h 155 | stdcpp17 156 | stdc17 157 | 158 | 159 | 160 | 161 | true 162 | true 163 | true 164 | 165 | 166 | 167 | 168 | Level3 169 | true 170 | true 171 | true 172 | NDEBUG;_LIB;%(PreprocessorDefinitions) 173 | true 174 | NotUsing 175 | pch.h 176 | stdcpp17 177 | stdc17 178 | 179 | 180 | 181 | 182 | true 183 | true 184 | true 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /src/libfdt.um/libfdt.um.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/libfdt/fdt.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | /* 14 | * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks 15 | * that the given buffer contains what appears to be a flattened 16 | * device tree with sane information in its header. 17 | */ 18 | int32_t fdt_ro_probe_(const void *fdt) 19 | { 20 | uint32_t totalsize = fdt_totalsize(fdt); 21 | 22 | if (can_assume(VALID_DTB)) 23 | return totalsize; 24 | 25 | /* The device tree must be at an 8-byte aligned address */ 26 | if ((uintptr_t)fdt & 7) 27 | return -FDT_ERR_ALIGNMENT; 28 | 29 | if (fdt_magic(fdt) == FDT_MAGIC) { 30 | /* Complete tree */ 31 | if (!can_assume(LATEST)) { 32 | if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) 33 | return -FDT_ERR_BADVERSION; 34 | if (fdt_last_comp_version(fdt) > 35 | FDT_LAST_SUPPORTED_VERSION) 36 | return -FDT_ERR_BADVERSION; 37 | } 38 | } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { 39 | /* Unfinished sequential-write blob */ 40 | if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0) 41 | return -FDT_ERR_BADSTATE; 42 | } else { 43 | return -FDT_ERR_BADMAGIC; 44 | } 45 | 46 | if (totalsize < INT32_MAX) 47 | return totalsize; 48 | else 49 | return -FDT_ERR_TRUNCATED; 50 | } 51 | 52 | static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) 53 | { 54 | return (off >= hdrsize) && (off <= totalsize); 55 | } 56 | 57 | static int check_block_(uint32_t hdrsize, uint32_t totalsize, 58 | uint32_t base, uint32_t size) 59 | { 60 | if (!check_off_(hdrsize, totalsize, base)) 61 | return 0; /* block start out of bounds */ 62 | if ((base + size) < base) 63 | return 0; /* overflow */ 64 | if (!check_off_(hdrsize, totalsize, base + size)) 65 | return 0; /* block end out of bounds */ 66 | return 1; 67 | } 68 | 69 | size_t fdt_header_size_(uint32_t version) 70 | { 71 | if (version <= 1) 72 | return FDT_V1_SIZE; 73 | else if (version <= 2) 74 | return FDT_V2_SIZE; 75 | else if (version <= 3) 76 | return FDT_V3_SIZE; 77 | else if (version <= 16) 78 | return FDT_V16_SIZE; 79 | else 80 | return FDT_V17_SIZE; 81 | } 82 | 83 | size_t fdt_header_size(const void *fdt) 84 | { 85 | return can_assume(LATEST) ? FDT_V17_SIZE : 86 | fdt_header_size_(fdt_version(fdt)); 87 | } 88 | 89 | int fdt_check_header(const void *fdt) 90 | { 91 | size_t hdrsize; 92 | 93 | /* The device tree must be at an 8-byte aligned address */ 94 | if ((uintptr_t)fdt & 7) 95 | return -FDT_ERR_ALIGNMENT; 96 | 97 | if (fdt_magic(fdt) != FDT_MAGIC) 98 | return -FDT_ERR_BADMAGIC; 99 | if (!can_assume(LATEST)) { 100 | if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) 101 | || (fdt_last_comp_version(fdt) > 102 | FDT_LAST_SUPPORTED_VERSION)) 103 | return -FDT_ERR_BADVERSION; 104 | if (fdt_version(fdt) < fdt_last_comp_version(fdt)) 105 | return -FDT_ERR_BADVERSION; 106 | } 107 | hdrsize = fdt_header_size(fdt); 108 | if (!can_assume(VALID_DTB)) { 109 | if ((fdt_totalsize(fdt) < hdrsize) 110 | || (fdt_totalsize(fdt) > INT_MAX)) 111 | return -FDT_ERR_TRUNCATED; 112 | 113 | /* Bounds check memrsv block */ 114 | if (!check_off_(hdrsize, fdt_totalsize(fdt), 115 | fdt_off_mem_rsvmap(fdt))) 116 | return -FDT_ERR_TRUNCATED; 117 | 118 | /* Bounds check structure block */ 119 | if (!can_assume(LATEST) && fdt_version(fdt) < 17) { 120 | if (!check_off_(hdrsize, fdt_totalsize(fdt), 121 | fdt_off_dt_struct(fdt))) 122 | return -FDT_ERR_TRUNCATED; 123 | } else { 124 | if (!check_block_(hdrsize, fdt_totalsize(fdt), 125 | fdt_off_dt_struct(fdt), 126 | fdt_size_dt_struct(fdt))) 127 | return -FDT_ERR_TRUNCATED; 128 | } 129 | 130 | /* Bounds check strings block */ 131 | if (!check_block_(hdrsize, fdt_totalsize(fdt), 132 | fdt_off_dt_strings(fdt), 133 | fdt_size_dt_strings(fdt))) 134 | return -FDT_ERR_TRUNCATED; 135 | } 136 | 137 | return 0; 138 | } 139 | 140 | const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) 141 | { 142 | unsigned int uoffset = offset; 143 | unsigned int absoffset = offset + fdt_off_dt_struct(fdt); 144 | 145 | if (offset < 0) 146 | return NULL; 147 | 148 | if (!can_assume(VALID_INPUT)) 149 | if ((absoffset < uoffset) 150 | || ((absoffset + len) < absoffset) 151 | || (absoffset + len) > fdt_totalsize(fdt)) 152 | return NULL; 153 | 154 | if (can_assume(LATEST) || fdt_version(fdt) >= 0x11) 155 | if (((uoffset + len) < uoffset) 156 | || ((offset + len) > fdt_size_dt_struct(fdt))) 157 | return NULL; 158 | 159 | return fdt_offset_ptr_(fdt, offset); 160 | } 161 | 162 | uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) 163 | { 164 | const fdt32_t *tagp, *lenp; 165 | uint32_t tag, len, sum; 166 | int offset = startoffset; 167 | const char *p; 168 | 169 | *nextoffset = -FDT_ERR_TRUNCATED; 170 | tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); 171 | if (!can_assume(VALID_DTB) && !tagp) 172 | return FDT_END; /* premature end */ 173 | tag = fdt32_to_cpu(*tagp); 174 | offset += FDT_TAGSIZE; 175 | 176 | *nextoffset = -FDT_ERR_BADSTRUCTURE; 177 | switch (tag) { 178 | case FDT_BEGIN_NODE: 179 | /* skip name */ 180 | do { 181 | p = fdt_offset_ptr(fdt, offset++, 1); 182 | } while (p && (*p != '\0')); 183 | if (!can_assume(VALID_DTB) && !p) 184 | return FDT_END; /* premature end */ 185 | break; 186 | 187 | case FDT_PROP: 188 | lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); 189 | if (!can_assume(VALID_DTB) && !lenp) 190 | return FDT_END; /* premature end */ 191 | 192 | len = fdt32_to_cpu(*lenp); 193 | sum = len + offset; 194 | if (!can_assume(VALID_DTB) && 195 | (INT_MAX <= sum || sum < (uint32_t) offset)) 196 | return FDT_END; /* premature end */ 197 | 198 | /* skip-name offset, length and value */ 199 | offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len; 200 | 201 | if (!can_assume(LATEST) && 202 | fdt_version(fdt) < 0x10 && len >= 8 && 203 | ((offset - len) % 8) != 0) 204 | offset += 4; 205 | break; 206 | 207 | case FDT_END: 208 | case FDT_END_NODE: 209 | case FDT_NOP: 210 | break; 211 | 212 | default: 213 | return FDT_END; 214 | } 215 | 216 | if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) 217 | return FDT_END; /* premature end */ 218 | 219 | *nextoffset = FDT_TAGALIGN(offset); 220 | return tag; 221 | } 222 | 223 | int fdt_check_node_offset_(const void *fdt, int offset) 224 | { 225 | if (!can_assume(VALID_INPUT) 226 | && ((offset < 0) || (offset % FDT_TAGSIZE))) 227 | return -FDT_ERR_BADOFFSET; 228 | 229 | if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE) 230 | return -FDT_ERR_BADOFFSET; 231 | 232 | return offset; 233 | } 234 | 235 | int fdt_check_prop_offset_(const void *fdt, int offset) 236 | { 237 | if (!can_assume(VALID_INPUT) 238 | && ((offset < 0) || (offset % FDT_TAGSIZE))) 239 | return -FDT_ERR_BADOFFSET; 240 | 241 | if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP) 242 | return -FDT_ERR_BADOFFSET; 243 | 244 | return offset; 245 | } 246 | 247 | int fdt_next_node(const void *fdt, int offset, int *depth) 248 | { 249 | int nextoffset = 0; 250 | uint32_t tag; 251 | 252 | if (offset >= 0) 253 | if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0) 254 | return nextoffset; 255 | 256 | do { 257 | offset = nextoffset; 258 | tag = fdt_next_tag(fdt, offset, &nextoffset); 259 | 260 | switch (tag) { 261 | case FDT_PROP: 262 | case FDT_NOP: 263 | break; 264 | 265 | case FDT_BEGIN_NODE: 266 | if (depth) 267 | (*depth)++; 268 | break; 269 | 270 | case FDT_END_NODE: 271 | if (depth && ((--(*depth)) < 0)) 272 | return nextoffset; 273 | break; 274 | 275 | case FDT_END: 276 | if ((nextoffset >= 0) 277 | || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) 278 | return -FDT_ERR_NOTFOUND; 279 | else 280 | return nextoffset; 281 | } 282 | } while (tag != FDT_BEGIN_NODE); 283 | 284 | return offset; 285 | } 286 | 287 | int fdt_first_subnode(const void *fdt, int offset) 288 | { 289 | int depth = 0; 290 | 291 | offset = fdt_next_node(fdt, offset, &depth); 292 | if (offset < 0 || depth != 1) 293 | return -FDT_ERR_NOTFOUND; 294 | 295 | return offset; 296 | } 297 | 298 | int fdt_next_subnode(const void *fdt, int offset) 299 | { 300 | int depth = 1; 301 | 302 | /* 303 | * With respect to the parent, the depth of the next subnode will be 304 | * the same as the last. 305 | */ 306 | do { 307 | offset = fdt_next_node(fdt, offset, &depth); 308 | if (offset < 0 || depth < 1) 309 | return -FDT_ERR_NOTFOUND; 310 | } while (depth > 1); 311 | 312 | return offset; 313 | } 314 | 315 | const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) 316 | { 317 | int len = strlen(s) + 1; 318 | const char *last = strtab + tabsize - len; 319 | const char *p; 320 | 321 | for (p = strtab; p <= last; p++) 322 | if (memcmp(p, s, len) == 0) 323 | return p; 324 | return NULL; 325 | } 326 | 327 | int fdt_move(const void *fdt, void *buf, int bufsize) 328 | { 329 | if (!can_assume(VALID_INPUT) && bufsize < 0) 330 | return -FDT_ERR_NOSPACE; 331 | 332 | FDT_RO_PROBE(fdt); 333 | 334 | if (fdt_totalsize(fdt) > (unsigned int)bufsize) 335 | return -FDT_ERR_NOSPACE; 336 | 337 | memmove(buf, fdt, fdt_totalsize(fdt)); 338 | return 0; 339 | } 340 | -------------------------------------------------------------------------------- /src/libfdt/fdt_addresses.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2014 David Gibson 5 | * Copyright (C) 2018 embedded brains GmbH 6 | */ 7 | #include "libfdt_env.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "libfdt_internal.h" 13 | 14 | static int fdt_cells(const void *fdt, int nodeoffset, const char *name) 15 | { 16 | const fdt32_t *c; 17 | uint32_t val; 18 | int len; 19 | 20 | c = fdt_getprop(fdt, nodeoffset, name, &len); 21 | if (!c) 22 | return len; 23 | 24 | if (len != sizeof(*c)) 25 | return -FDT_ERR_BADNCELLS; 26 | 27 | val = fdt32_to_cpu(*c); 28 | if (val > FDT_MAX_NCELLS) 29 | return -FDT_ERR_BADNCELLS; 30 | 31 | return (int)val; 32 | } 33 | 34 | int fdt_address_cells(const void *fdt, int nodeoffset) 35 | { 36 | int val; 37 | 38 | val = fdt_cells(fdt, nodeoffset, "#address-cells"); 39 | if (val == 0) 40 | return -FDT_ERR_BADNCELLS; 41 | if (val == -FDT_ERR_NOTFOUND) 42 | return 2; 43 | return val; 44 | } 45 | 46 | int fdt_size_cells(const void *fdt, int nodeoffset) 47 | { 48 | int val; 49 | 50 | val = fdt_cells(fdt, nodeoffset, "#size-cells"); 51 | if (val == -FDT_ERR_NOTFOUND) 52 | return 1; 53 | return val; 54 | } 55 | 56 | /* This function assumes that [address|size]_cells is 1 or 2 */ 57 | int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, 58 | const char *name, uint64_t addr, uint64_t size) 59 | { 60 | int addr_cells, size_cells, ret; 61 | uint8_t data[sizeof(fdt64_t) * 2], *prop; 62 | 63 | ret = fdt_address_cells(fdt, parent); 64 | if (ret < 0) 65 | return ret; 66 | addr_cells = ret; 67 | 68 | ret = fdt_size_cells(fdt, parent); 69 | if (ret < 0) 70 | return ret; 71 | size_cells = ret; 72 | 73 | /* check validity of address */ 74 | prop = data; 75 | if (addr_cells == 1) { 76 | if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) 77 | return -FDT_ERR_BADVALUE; 78 | 79 | fdt32_st(prop, (uint32_t)addr); 80 | } else if (addr_cells == 2) { 81 | fdt64_st(prop, addr); 82 | } else { 83 | return -FDT_ERR_BADNCELLS; 84 | } 85 | 86 | /* check validity of size */ 87 | prop += addr_cells * sizeof(fdt32_t); 88 | if (size_cells == 1) { 89 | if (size > UINT32_MAX) 90 | return -FDT_ERR_BADVALUE; 91 | 92 | fdt32_st(prop, (uint32_t)size); 93 | } else if (size_cells == 2) { 94 | fdt64_st(prop, size); 95 | } else { 96 | return -FDT_ERR_BADNCELLS; 97 | } 98 | 99 | return fdt_appendprop(fdt, nodeoffset, name, data, 100 | (addr_cells + size_cells) * sizeof(fdt32_t)); 101 | } 102 | -------------------------------------------------------------------------------- /src/libfdt/fdt_check.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | int fdt_check_full(const void *fdt, size_t bufsize) 14 | { 15 | int err; 16 | int num_memrsv; 17 | int offset, nextoffset = 0; 18 | uint32_t tag; 19 | unsigned int depth = 0; 20 | const void *prop; 21 | const char *propname; 22 | bool expect_end = false; 23 | 24 | if (bufsize < FDT_V1_SIZE) 25 | return -FDT_ERR_TRUNCATED; 26 | if (bufsize < fdt_header_size(fdt)) 27 | return -FDT_ERR_TRUNCATED; 28 | err = fdt_check_header(fdt); 29 | if (err != 0) 30 | return err; 31 | if (bufsize < fdt_totalsize(fdt)) 32 | return -FDT_ERR_TRUNCATED; 33 | 34 | num_memrsv = fdt_num_mem_rsv(fdt); 35 | if (num_memrsv < 0) 36 | return num_memrsv; 37 | 38 | while (1) { 39 | offset = nextoffset; 40 | tag = fdt_next_tag(fdt, offset, &nextoffset); 41 | 42 | if (nextoffset < 0) 43 | return nextoffset; 44 | 45 | /* If we see two root nodes, something is wrong */ 46 | if (expect_end && tag != FDT_END) 47 | return -FDT_ERR_BADSTRUCTURE; 48 | 49 | switch (tag) { 50 | case FDT_NOP: 51 | break; 52 | 53 | case FDT_END: 54 | if (depth != 0) 55 | return -FDT_ERR_BADSTRUCTURE; 56 | return 0; 57 | 58 | case FDT_BEGIN_NODE: 59 | depth++; 60 | if (depth > INT_MAX) 61 | return -FDT_ERR_BADSTRUCTURE; 62 | 63 | /* The root node must have an empty name */ 64 | if (depth == 1) { 65 | const char *name; 66 | int len; 67 | 68 | name = fdt_get_name(fdt, offset, &len); 69 | if (!name) 70 | return len; 71 | 72 | if (*name || len) 73 | return -FDT_ERR_BADSTRUCTURE; 74 | } 75 | break; 76 | 77 | case FDT_END_NODE: 78 | if (depth == 0) 79 | return -FDT_ERR_BADSTRUCTURE; 80 | depth--; 81 | if (depth == 0) 82 | expect_end = true; 83 | break; 84 | 85 | case FDT_PROP: 86 | prop = fdt_getprop_by_offset(fdt, offset, &propname, 87 | &err); 88 | if (!prop) 89 | return err; 90 | break; 91 | 92 | default: 93 | return -FDT_ERR_INTERNAL; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/libfdt/fdt_empty_tree.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2012 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | int fdt_create_empty_tree(void *buf, int bufsize) 14 | { 15 | int err; 16 | 17 | err = fdt_create(buf, bufsize); 18 | if (err) 19 | return err; 20 | 21 | err = fdt_finish_reservemap(buf); 22 | if (err) 23 | return err; 24 | 25 | err = fdt_begin_node(buf, ""); 26 | if (err) 27 | return err; 28 | 29 | err = fdt_end_node(buf); 30 | if (err) 31 | return err; 32 | 33 | err = fdt_finish(buf); 34 | if (err) 35 | return err; 36 | 37 | return fdt_open_into(buf, buf, bufsize); 38 | } 39 | -------------------------------------------------------------------------------- /src/libfdt/fdt_ro.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | static int fdt_nodename_eq_(const void *fdt, int offset, 14 | const char *s, int len) 15 | { 16 | int olen; 17 | const char *p = fdt_get_name(fdt, offset, &olen); 18 | 19 | if (!p || olen < len) 20 | /* short match */ 21 | return 0; 22 | 23 | if (memcmp(p, s, len) != 0) 24 | return 0; 25 | 26 | if (p[len] == '\0') 27 | return 1; 28 | else if (!memchr(s, '@', len) && (p[len] == '@')) 29 | return 1; 30 | else 31 | return 0; 32 | } 33 | 34 | const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) 35 | { 36 | int32_t totalsize; 37 | uint32_t absoffset; 38 | size_t len; 39 | int err; 40 | const char *s, *n; 41 | 42 | if (can_assume(VALID_INPUT)) { 43 | s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; 44 | 45 | if (lenp) 46 | *lenp = strlen(s); 47 | return s; 48 | } 49 | totalsize = fdt_ro_probe_(fdt); 50 | err = totalsize; 51 | if (totalsize < 0) 52 | goto fail; 53 | 54 | err = -FDT_ERR_BADOFFSET; 55 | absoffset = stroffset + fdt_off_dt_strings(fdt); 56 | if (absoffset >= (unsigned)totalsize) 57 | goto fail; 58 | len = totalsize - absoffset; 59 | 60 | if (fdt_magic(fdt) == FDT_MAGIC) { 61 | if (stroffset < 0) 62 | goto fail; 63 | if (can_assume(LATEST) || fdt_version(fdt) >= 17) { 64 | if ((unsigned)stroffset >= fdt_size_dt_strings(fdt)) 65 | goto fail; 66 | if ((fdt_size_dt_strings(fdt) - stroffset) < len) 67 | len = fdt_size_dt_strings(fdt) - stroffset; 68 | } 69 | } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { 70 | unsigned int sw_stroffset = -stroffset; 71 | 72 | if ((stroffset >= 0) || 73 | (sw_stroffset > fdt_size_dt_strings(fdt))) 74 | goto fail; 75 | if (sw_stroffset < len) 76 | len = sw_stroffset; 77 | } else { 78 | err = -FDT_ERR_INTERNAL; 79 | goto fail; 80 | } 81 | 82 | s = (const char *)fdt + absoffset; 83 | n = memchr(s, '\0', len); 84 | if (!n) { 85 | /* missing terminating NULL */ 86 | err = -FDT_ERR_TRUNCATED; 87 | goto fail; 88 | } 89 | 90 | if (lenp) 91 | *lenp = n - s; 92 | return s; 93 | 94 | fail: 95 | if (lenp) 96 | *lenp = err; 97 | return NULL; 98 | } 99 | 100 | const char *fdt_string(const void *fdt, int stroffset) 101 | { 102 | return fdt_get_string(fdt, stroffset, NULL); 103 | } 104 | 105 | static int fdt_string_eq_(const void *fdt, int stroffset, 106 | const char *s, int len) 107 | { 108 | int slen; 109 | const char *p = fdt_get_string(fdt, stroffset, &slen); 110 | 111 | return p && (slen == len) && (memcmp(p, s, len) == 0); 112 | } 113 | 114 | int fdt_find_max_phandle(const void *fdt, uint32_t *phandle) 115 | { 116 | uint32_t max = 0; 117 | int offset = -1; 118 | 119 | while (true) { 120 | uint32_t value; 121 | 122 | offset = fdt_next_node(fdt, offset, NULL); 123 | if (offset < 0) { 124 | if (offset == -FDT_ERR_NOTFOUND) 125 | break; 126 | 127 | return offset; 128 | } 129 | 130 | value = fdt_get_phandle(fdt, offset); 131 | 132 | if (value > max) 133 | max = value; 134 | } 135 | 136 | if (phandle) 137 | *phandle = max; 138 | 139 | return 0; 140 | } 141 | 142 | int fdt_generate_phandle(const void *fdt, uint32_t *phandle) 143 | { 144 | uint32_t max; 145 | int err; 146 | 147 | err = fdt_find_max_phandle(fdt, &max); 148 | if (err < 0) 149 | return err; 150 | 151 | if (max == FDT_MAX_PHANDLE) 152 | return -FDT_ERR_NOPHANDLES; 153 | 154 | if (phandle) 155 | *phandle = max + 1; 156 | 157 | return 0; 158 | } 159 | 160 | static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) 161 | { 162 | unsigned int offset = n * sizeof(struct fdt_reserve_entry); 163 | unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; 164 | 165 | if (!can_assume(VALID_INPUT)) { 166 | if (absoffset < fdt_off_mem_rsvmap(fdt)) 167 | return NULL; 168 | if (absoffset > fdt_totalsize(fdt) - 169 | sizeof(struct fdt_reserve_entry)) 170 | return NULL; 171 | } 172 | return fdt_mem_rsv_(fdt, n); 173 | } 174 | 175 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) 176 | { 177 | const struct fdt_reserve_entry *re; 178 | 179 | FDT_RO_PROBE(fdt); 180 | re = fdt_mem_rsv(fdt, n); 181 | if (!can_assume(VALID_INPUT) && !re) 182 | return -FDT_ERR_BADOFFSET; 183 | 184 | *address = fdt64_ld_(&re->address); 185 | *size = fdt64_ld_(&re->size); 186 | return 0; 187 | } 188 | 189 | int fdt_num_mem_rsv(const void *fdt) 190 | { 191 | int i; 192 | const struct fdt_reserve_entry *re; 193 | 194 | for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { 195 | if (fdt64_ld_(&re->size) == 0) 196 | return i; 197 | } 198 | return -FDT_ERR_TRUNCATED; 199 | } 200 | 201 | static int nextprop_(const void *fdt, int offset) 202 | { 203 | uint32_t tag; 204 | int nextoffset; 205 | 206 | do { 207 | tag = fdt_next_tag(fdt, offset, &nextoffset); 208 | 209 | switch (tag) { 210 | case FDT_END: 211 | if (nextoffset >= 0) 212 | return -FDT_ERR_BADSTRUCTURE; 213 | else 214 | return nextoffset; 215 | 216 | case FDT_PROP: 217 | return offset; 218 | } 219 | offset = nextoffset; 220 | } while (tag == FDT_NOP); 221 | 222 | return -FDT_ERR_NOTFOUND; 223 | } 224 | 225 | int fdt_subnode_offset_namelen(const void *fdt, int offset, 226 | const char *name, int namelen) 227 | { 228 | int depth; 229 | 230 | FDT_RO_PROBE(fdt); 231 | 232 | for (depth = 0; 233 | (offset >= 0) && (depth >= 0); 234 | offset = fdt_next_node(fdt, offset, &depth)) 235 | if ((depth == 1) 236 | && fdt_nodename_eq_(fdt, offset, name, namelen)) 237 | return offset; 238 | 239 | if (depth < 0) 240 | return -FDT_ERR_NOTFOUND; 241 | return offset; /* error */ 242 | } 243 | 244 | int fdt_subnode_offset(const void *fdt, int parentoffset, 245 | const char *name) 246 | { 247 | return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); 248 | } 249 | 250 | int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) 251 | { 252 | const char *end = path + namelen; 253 | const char *p = path; 254 | int offset = 0; 255 | 256 | FDT_RO_PROBE(fdt); 257 | 258 | /* see if we have an alias */ 259 | if (*path != '/') { 260 | const char *q = memchr(path, '/', end - p); 261 | 262 | if (!q) 263 | q = end; 264 | 265 | p = fdt_get_alias_namelen(fdt, p, q - p); 266 | if (!p) 267 | return -FDT_ERR_BADPATH; 268 | offset = fdt_path_offset(fdt, p); 269 | 270 | p = q; 271 | } 272 | 273 | while (p < end) { 274 | const char *q; 275 | 276 | while (*p == '/') { 277 | p++; 278 | if (p == end) 279 | return offset; 280 | } 281 | q = memchr(p, '/', end - p); 282 | if (! q) 283 | q = end; 284 | 285 | offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); 286 | if (offset < 0) 287 | return offset; 288 | 289 | p = q; 290 | } 291 | 292 | return offset; 293 | } 294 | 295 | int fdt_path_offset(const void *fdt, const char *path) 296 | { 297 | return fdt_path_offset_namelen(fdt, path, strlen(path)); 298 | } 299 | 300 | const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) 301 | { 302 | const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); 303 | const char *nameptr; 304 | int err; 305 | 306 | if (((err = fdt_ro_probe_(fdt)) < 0) 307 | || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) 308 | goto fail; 309 | 310 | nameptr = nh->name; 311 | 312 | if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { 313 | /* 314 | * For old FDT versions, match the naming conventions of V16: 315 | * give only the leaf name (after all /). The actual tree 316 | * contents are loosely checked. 317 | */ 318 | const char *leaf; 319 | leaf = strrchr(nameptr, '/'); 320 | if (leaf == NULL) { 321 | err = -FDT_ERR_BADSTRUCTURE; 322 | goto fail; 323 | } 324 | nameptr = leaf+1; 325 | } 326 | 327 | if (len) 328 | *len = strlen(nameptr); 329 | 330 | return nameptr; 331 | 332 | fail: 333 | if (len) 334 | *len = err; 335 | return NULL; 336 | } 337 | 338 | int fdt_first_property_offset(const void *fdt, int nodeoffset) 339 | { 340 | int offset; 341 | 342 | if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) 343 | return offset; 344 | 345 | return nextprop_(fdt, offset); 346 | } 347 | 348 | int fdt_next_property_offset(const void *fdt, int offset) 349 | { 350 | if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) 351 | return offset; 352 | 353 | return nextprop_(fdt, offset); 354 | } 355 | 356 | static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, 357 | int offset, 358 | int *lenp) 359 | { 360 | int err; 361 | const struct fdt_property *prop; 362 | 363 | if (!can_assume(VALID_INPUT) && 364 | (err = fdt_check_prop_offset_(fdt, offset)) < 0) { 365 | if (lenp) 366 | *lenp = err; 367 | return NULL; 368 | } 369 | 370 | prop = fdt_offset_ptr_(fdt, offset); 371 | 372 | if (lenp) 373 | *lenp = fdt32_ld_(&prop->len); 374 | 375 | return prop; 376 | } 377 | 378 | const struct fdt_property *fdt_get_property_by_offset(const void *fdt, 379 | int offset, 380 | int *lenp) 381 | { 382 | /* Prior to version 16, properties may need realignment 383 | * and this API does not work. fdt_getprop_*() will, however. */ 384 | 385 | if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { 386 | if (lenp) 387 | *lenp = -FDT_ERR_BADVERSION; 388 | return NULL; 389 | } 390 | 391 | return fdt_get_property_by_offset_(fdt, offset, lenp); 392 | } 393 | 394 | static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, 395 | int offset, 396 | const char *name, 397 | int namelen, 398 | int *lenp, 399 | int *poffset) 400 | { 401 | for (offset = fdt_first_property_offset(fdt, offset); 402 | (offset >= 0); 403 | (offset = fdt_next_property_offset(fdt, offset))) { 404 | const struct fdt_property *prop; 405 | 406 | prop = fdt_get_property_by_offset_(fdt, offset, lenp); 407 | if (!can_assume(LIBFDT_FLAWLESS) && !prop) { 408 | offset = -FDT_ERR_INTERNAL; 409 | break; 410 | } 411 | if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff), 412 | name, namelen)) { 413 | if (poffset) 414 | *poffset = offset; 415 | return prop; 416 | } 417 | } 418 | 419 | if (lenp) 420 | *lenp = offset; 421 | return NULL; 422 | } 423 | 424 | 425 | const struct fdt_property *fdt_get_property_namelen(const void *fdt, 426 | int offset, 427 | const char *name, 428 | int namelen, int *lenp) 429 | { 430 | /* Prior to version 16, properties may need realignment 431 | * and this API does not work. fdt_getprop_*() will, however. */ 432 | if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { 433 | if (lenp) 434 | *lenp = -FDT_ERR_BADVERSION; 435 | return NULL; 436 | } 437 | 438 | return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, 439 | NULL); 440 | } 441 | 442 | 443 | const struct fdt_property *fdt_get_property(const void *fdt, 444 | int nodeoffset, 445 | const char *name, int *lenp) 446 | { 447 | return fdt_get_property_namelen(fdt, nodeoffset, name, 448 | strlen(name), lenp); 449 | } 450 | 451 | const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, 452 | const char *name, int namelen, int *lenp) 453 | { 454 | int poffset; 455 | const struct fdt_property *prop; 456 | 457 | prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, 458 | &poffset); 459 | if (!prop) 460 | return NULL; 461 | 462 | /* Handle realignment */ 463 | if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && 464 | (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) 465 | return prop->data + 4; 466 | return prop->data; 467 | } 468 | 469 | const void *fdt_getprop_by_offset(const void *fdt, int offset, 470 | const char **namep, int *lenp) 471 | { 472 | const struct fdt_property *prop; 473 | 474 | prop = fdt_get_property_by_offset_(fdt, offset, lenp); 475 | if (!prop) 476 | return NULL; 477 | if (namep) { 478 | const char *name; 479 | int namelen; 480 | 481 | if (!can_assume(VALID_INPUT)) { 482 | name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), 483 | &namelen); 484 | *namep = name; 485 | if (!name) { 486 | if (lenp) 487 | *lenp = namelen; 488 | return NULL; 489 | } 490 | } else { 491 | *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); 492 | } 493 | } 494 | 495 | /* Handle realignment */ 496 | if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && 497 | (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) 498 | return prop->data + 4; 499 | return prop->data; 500 | } 501 | 502 | const void *fdt_getprop(const void *fdt, int nodeoffset, 503 | const char *name, int *lenp) 504 | { 505 | return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); 506 | } 507 | 508 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) 509 | { 510 | const fdt32_t *php; 511 | int len; 512 | 513 | /* FIXME: This is a bit sub-optimal, since we potentially scan 514 | * over all the properties twice. */ 515 | php = fdt_getprop(fdt, nodeoffset, "phandle", &len); 516 | if (!php || (len != sizeof(*php))) { 517 | php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); 518 | if (!php || (len != sizeof(*php))) 519 | return 0; 520 | } 521 | 522 | return fdt32_ld_(php); 523 | } 524 | 525 | const char *fdt_get_alias_namelen(const void *fdt, 526 | const char *name, int namelen) 527 | { 528 | int aliasoffset; 529 | 530 | aliasoffset = fdt_path_offset(fdt, "/aliases"); 531 | if (aliasoffset < 0) 532 | return NULL; 533 | 534 | return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); 535 | } 536 | 537 | const char *fdt_get_alias(const void *fdt, const char *name) 538 | { 539 | return fdt_get_alias_namelen(fdt, name, strlen(name)); 540 | } 541 | 542 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) 543 | { 544 | int pdepth = 0, p = 0; 545 | int offset, depth, namelen; 546 | const char *name; 547 | 548 | FDT_RO_PROBE(fdt); 549 | 550 | if (buflen < 2) 551 | return -FDT_ERR_NOSPACE; 552 | 553 | for (offset = 0, depth = 0; 554 | (offset >= 0) && (offset <= nodeoffset); 555 | offset = fdt_next_node(fdt, offset, &depth)) { 556 | while (pdepth > depth) { 557 | do { 558 | p--; 559 | } while (buf[p-1] != '/'); 560 | pdepth--; 561 | } 562 | 563 | if (pdepth >= depth) { 564 | name = fdt_get_name(fdt, offset, &namelen); 565 | if (!name) 566 | return namelen; 567 | if ((p + namelen + 1) <= buflen) { 568 | memcpy(buf + p, name, namelen); 569 | p += namelen; 570 | buf[p++] = '/'; 571 | pdepth++; 572 | } 573 | } 574 | 575 | if (offset == nodeoffset) { 576 | if (pdepth < (depth + 1)) 577 | return -FDT_ERR_NOSPACE; 578 | 579 | if (p > 1) /* special case so that root path is "/", not "" */ 580 | p--; 581 | buf[p] = '\0'; 582 | return 0; 583 | } 584 | } 585 | 586 | if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) 587 | return -FDT_ERR_BADOFFSET; 588 | else if (offset == -FDT_ERR_BADOFFSET) 589 | return -FDT_ERR_BADSTRUCTURE; 590 | 591 | return offset; /* error from fdt_next_node() */ 592 | } 593 | 594 | int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, 595 | int supernodedepth, int *nodedepth) 596 | { 597 | int offset, depth; 598 | int supernodeoffset = -FDT_ERR_INTERNAL; 599 | 600 | FDT_RO_PROBE(fdt); 601 | 602 | if (supernodedepth < 0) 603 | return -FDT_ERR_NOTFOUND; 604 | 605 | for (offset = 0, depth = 0; 606 | (offset >= 0) && (offset <= nodeoffset); 607 | offset = fdt_next_node(fdt, offset, &depth)) { 608 | if (depth == supernodedepth) 609 | supernodeoffset = offset; 610 | 611 | if (offset == nodeoffset) { 612 | if (nodedepth) 613 | *nodedepth = depth; 614 | 615 | if (supernodedepth > depth) 616 | return -FDT_ERR_NOTFOUND; 617 | else 618 | return supernodeoffset; 619 | } 620 | } 621 | 622 | if (!can_assume(VALID_INPUT)) { 623 | if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) 624 | return -FDT_ERR_BADOFFSET; 625 | else if (offset == -FDT_ERR_BADOFFSET) 626 | return -FDT_ERR_BADSTRUCTURE; 627 | } 628 | 629 | return offset; /* error from fdt_next_node() */ 630 | } 631 | 632 | int fdt_node_depth(const void *fdt, int nodeoffset) 633 | { 634 | int nodedepth; 635 | int err; 636 | 637 | err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); 638 | if (err) 639 | return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err : 640 | -FDT_ERR_INTERNAL; 641 | return nodedepth; 642 | } 643 | 644 | int fdt_parent_offset(const void *fdt, int nodeoffset) 645 | { 646 | int nodedepth = fdt_node_depth(fdt, nodeoffset); 647 | 648 | if (nodedepth < 0) 649 | return nodedepth; 650 | return fdt_supernode_atdepth_offset(fdt, nodeoffset, 651 | nodedepth - 1, NULL); 652 | } 653 | 654 | int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, 655 | const char *propname, 656 | const void *propval, int proplen) 657 | { 658 | int offset; 659 | const void *val; 660 | int len; 661 | 662 | FDT_RO_PROBE(fdt); 663 | 664 | /* FIXME: The algorithm here is pretty horrible: we scan each 665 | * property of a node in fdt_getprop(), then if that didn't 666 | * find what we want, we scan over them again making our way 667 | * to the next node. Still it's the easiest to implement 668 | * approach; performance can come later. */ 669 | for (offset = fdt_next_node(fdt, startoffset, NULL); 670 | offset >= 0; 671 | offset = fdt_next_node(fdt, offset, NULL)) { 672 | val = fdt_getprop(fdt, offset, propname, &len); 673 | if (val && (len == proplen) 674 | && (memcmp(val, propval, len) == 0)) 675 | return offset; 676 | } 677 | 678 | return offset; /* error from fdt_next_node() */ 679 | } 680 | 681 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) 682 | { 683 | int offset; 684 | 685 | if ((phandle == 0) || (phandle == ~0U)) 686 | return -FDT_ERR_BADPHANDLE; 687 | 688 | FDT_RO_PROBE(fdt); 689 | 690 | /* FIXME: The algorithm here is pretty horrible: we 691 | * potentially scan each property of a node in 692 | * fdt_get_phandle(), then if that didn't find what 693 | * we want, we scan over them again making our way to the next 694 | * node. Still it's the easiest to implement approach; 695 | * performance can come later. */ 696 | for (offset = fdt_next_node(fdt, -1, NULL); 697 | offset >= 0; 698 | offset = fdt_next_node(fdt, offset, NULL)) { 699 | if (fdt_get_phandle(fdt, offset) == phandle) 700 | return offset; 701 | } 702 | 703 | return offset; /* error from fdt_next_node() */ 704 | } 705 | 706 | int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) 707 | { 708 | int len = strlen(str); 709 | const char *p; 710 | 711 | while (listlen >= len) { 712 | if (memcmp(str, strlist, len+1) == 0) 713 | return 1; 714 | p = memchr(strlist, '\0', listlen); 715 | if (!p) 716 | return 0; /* malformed strlist.. */ 717 | listlen -= (p-strlist) + 1; 718 | strlist = p + 1; 719 | } 720 | return 0; 721 | } 722 | 723 | int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) 724 | { 725 | const char *list, *end; 726 | int length, count = 0; 727 | 728 | list = fdt_getprop(fdt, nodeoffset, property, &length); 729 | if (!list) 730 | return length; 731 | 732 | end = list + length; 733 | 734 | while (list < end) { 735 | length = strnlen(list, end - list) + 1; 736 | 737 | /* Abort if the last string isn't properly NUL-terminated. */ 738 | if (list + length > end) 739 | return -FDT_ERR_BADVALUE; 740 | 741 | list += length; 742 | count++; 743 | } 744 | 745 | return count; 746 | } 747 | 748 | int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, 749 | const char *string) 750 | { 751 | int length, len, idx = 0; 752 | const char *list, *end; 753 | 754 | list = fdt_getprop(fdt, nodeoffset, property, &length); 755 | if (!list) 756 | return length; 757 | 758 | len = strlen(string) + 1; 759 | end = list + length; 760 | 761 | while (list < end) { 762 | length = strnlen(list, end - list) + 1; 763 | 764 | /* Abort if the last string isn't properly NUL-terminated. */ 765 | if (list + length > end) 766 | return -FDT_ERR_BADVALUE; 767 | 768 | if (length == len && memcmp(list, string, length) == 0) 769 | return idx; 770 | 771 | list += length; 772 | idx++; 773 | } 774 | 775 | return -FDT_ERR_NOTFOUND; 776 | } 777 | 778 | const char *fdt_stringlist_get(const void *fdt, int nodeoffset, 779 | const char *property, int idx, 780 | int *lenp) 781 | { 782 | const char *list, *end; 783 | int length; 784 | 785 | list = fdt_getprop(fdt, nodeoffset, property, &length); 786 | if (!list) { 787 | if (lenp) 788 | *lenp = length; 789 | 790 | return NULL; 791 | } 792 | 793 | end = list + length; 794 | 795 | while (list < end) { 796 | length = strnlen(list, end - list) + 1; 797 | 798 | /* Abort if the last string isn't properly NUL-terminated. */ 799 | if (list + length > end) { 800 | if (lenp) 801 | *lenp = -FDT_ERR_BADVALUE; 802 | 803 | return NULL; 804 | } 805 | 806 | if (idx == 0) { 807 | if (lenp) 808 | *lenp = length - 1; 809 | 810 | return list; 811 | } 812 | 813 | list += length; 814 | idx--; 815 | } 816 | 817 | if (lenp) 818 | *lenp = -FDT_ERR_NOTFOUND; 819 | 820 | return NULL; 821 | } 822 | 823 | int fdt_node_check_compatible(const void *fdt, int nodeoffset, 824 | const char *compatible) 825 | { 826 | const void *prop; 827 | int len; 828 | 829 | prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); 830 | if (!prop) 831 | return len; 832 | 833 | return !fdt_stringlist_contains(prop, len, compatible); 834 | } 835 | 836 | int fdt_node_offset_by_compatible(const void *fdt, int startoffset, 837 | const char *compatible) 838 | { 839 | int offset, err; 840 | 841 | FDT_RO_PROBE(fdt); 842 | 843 | /* FIXME: The algorithm here is pretty horrible: we scan each 844 | * property of a node in fdt_node_check_compatible(), then if 845 | * that didn't find what we want, we scan over them again 846 | * making our way to the next node. Still it's the easiest to 847 | * implement approach; performance can come later. */ 848 | for (offset = fdt_next_node(fdt, startoffset, NULL); 849 | offset >= 0; 850 | offset = fdt_next_node(fdt, offset, NULL)) { 851 | err = fdt_node_check_compatible(fdt, offset, compatible); 852 | if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) 853 | return err; 854 | else if (err == 0) 855 | return offset; 856 | } 857 | 858 | return offset; /* error from fdt_next_node() */ 859 | } 860 | -------------------------------------------------------------------------------- /src/libfdt/fdt_rw.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | static int fdt_blocks_misordered_(const void *fdt, 14 | int mem_rsv_size, int struct_size) 15 | { 16 | return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) 17 | || (fdt_off_dt_struct(fdt) < 18 | (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) 19 | || (fdt_off_dt_strings(fdt) < 20 | (fdt_off_dt_struct(fdt) + struct_size)) 21 | || (fdt_totalsize(fdt) < 22 | (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); 23 | } 24 | 25 | static int fdt_rw_probe_(void *fdt) 26 | { 27 | if (can_assume(VALID_DTB)) 28 | return 0; 29 | FDT_RO_PROBE(fdt); 30 | 31 | if (!can_assume(LATEST) && fdt_version(fdt) < 17) 32 | return -FDT_ERR_BADVERSION; 33 | if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), 34 | fdt_size_dt_struct(fdt))) 35 | return -FDT_ERR_BADLAYOUT; 36 | if (!can_assume(LATEST) && fdt_version(fdt) > 17) 37 | fdt_set_version(fdt, 17); 38 | 39 | return 0; 40 | } 41 | 42 | #define FDT_RW_PROBE(fdt) \ 43 | { \ 44 | int err_; \ 45 | if ((err_ = fdt_rw_probe_(fdt)) != 0) \ 46 | return err_; \ 47 | } 48 | 49 | static inline unsigned int fdt_data_size_(void *fdt) 50 | { 51 | return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 52 | } 53 | 54 | static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) 55 | { 56 | char *p = splicepoint; 57 | unsigned int dsize = fdt_data_size_(fdt); 58 | size_t soff = p - (char *)fdt; 59 | 60 | if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) 61 | return -FDT_ERR_BADOFFSET; 62 | if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) 63 | return -FDT_ERR_BADOFFSET; 64 | if (dsize - oldlen + newlen > fdt_totalsize(fdt)) 65 | return -FDT_ERR_NOSPACE; 66 | memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen)); 67 | return 0; 68 | } 69 | 70 | static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p, 71 | int oldn, int newn) 72 | { 73 | int delta = (newn - oldn) * sizeof(*p); 74 | int err; 75 | err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); 76 | if (err) 77 | return err; 78 | fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); 79 | fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 80 | return 0; 81 | } 82 | 83 | static int fdt_splice_struct_(void *fdt, void *p, 84 | int oldlen, int newlen) 85 | { 86 | int delta = newlen - oldlen; 87 | int err; 88 | 89 | if ((err = fdt_splice_(fdt, p, oldlen, newlen))) 90 | return err; 91 | 92 | fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); 93 | fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 94 | return 0; 95 | } 96 | 97 | /* Must only be used to roll back in case of error */ 98 | static void fdt_del_last_string_(void *fdt, const char *s) 99 | { 100 | int newlen = strlen(s) + 1; 101 | 102 | fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen); 103 | } 104 | 105 | static int fdt_splice_string_(void *fdt, int newlen) 106 | { 107 | void *p = (char *)fdt 108 | + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 109 | int err; 110 | 111 | if ((err = fdt_splice_(fdt, p, 0, newlen))) 112 | return err; 113 | 114 | fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); 115 | return 0; 116 | } 117 | 118 | /** 119 | * fdt_find_add_string_() - Find or allocate a string 120 | * 121 | * @fdt: pointer to the device tree to check/adjust 122 | * @s: string to find/add 123 | * @allocated: Set to 0 if the string was found, 1 if not found and so 124 | * allocated. Ignored if can_assume(NO_ROLLBACK) 125 | * @return offset of string in the string table (whether found or added) 126 | */ 127 | static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) 128 | { 129 | char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); 130 | const char *p; 131 | char *new; 132 | int len = strlen(s) + 1; 133 | int err; 134 | 135 | if (!can_assume(NO_ROLLBACK)) 136 | *allocated = 0; 137 | 138 | p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); 139 | if (p) 140 | /* found it */ 141 | return (p - strtab); 142 | 143 | new = strtab + fdt_size_dt_strings(fdt); 144 | err = fdt_splice_string_(fdt, len); 145 | if (err) 146 | return err; 147 | 148 | if (!can_assume(NO_ROLLBACK)) 149 | *allocated = 1; 150 | 151 | memcpy(new, s, len); 152 | return (new - strtab); 153 | } 154 | 155 | int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) 156 | { 157 | struct fdt_reserve_entry *re; 158 | int err; 159 | 160 | FDT_RW_PROBE(fdt); 161 | 162 | re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); 163 | err = fdt_splice_mem_rsv_(fdt, re, 0, 1); 164 | if (err) 165 | return err; 166 | 167 | re->address = cpu_to_fdt64(address); 168 | re->size = cpu_to_fdt64(size); 169 | return 0; 170 | } 171 | 172 | int fdt_del_mem_rsv(void *fdt, int n) 173 | { 174 | struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); 175 | 176 | FDT_RW_PROBE(fdt); 177 | 178 | if (n >= fdt_num_mem_rsv(fdt)) 179 | return -FDT_ERR_NOTFOUND; 180 | 181 | return fdt_splice_mem_rsv_(fdt, re, 1, 0); 182 | } 183 | 184 | static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, 185 | int len, struct fdt_property **prop) 186 | { 187 | int oldlen; 188 | int err; 189 | 190 | *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 191 | if (!*prop) 192 | return oldlen; 193 | 194 | if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), 195 | FDT_TAGALIGN(len)))) 196 | return err; 197 | 198 | (*prop)->len = cpu_to_fdt32(len); 199 | return 0; 200 | } 201 | 202 | static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, 203 | int len, struct fdt_property **prop) 204 | { 205 | int proplen; 206 | int nextoffset; 207 | int namestroff; 208 | int err; 209 | int allocated; 210 | 211 | if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) 212 | return nextoffset; 213 | 214 | namestroff = fdt_find_add_string_(fdt, name, &allocated); 215 | if (namestroff < 0) 216 | return namestroff; 217 | 218 | *prop = fdt_offset_ptr_w_(fdt, nextoffset); 219 | proplen = sizeof(**prop) + FDT_TAGALIGN(len); 220 | 221 | err = fdt_splice_struct_(fdt, *prop, 0, proplen); 222 | if (err) { 223 | /* Delete the string if we failed to add it */ 224 | if (!can_assume(NO_ROLLBACK) && allocated) 225 | fdt_del_last_string_(fdt, name); 226 | return err; 227 | } 228 | 229 | (*prop)->tag = cpu_to_fdt32(FDT_PROP); 230 | (*prop)->nameoff = cpu_to_fdt32(namestroff); 231 | (*prop)->len = cpu_to_fdt32(len); 232 | return 0; 233 | } 234 | 235 | int fdt_set_name(void *fdt, int nodeoffset, const char *name) 236 | { 237 | char *namep; 238 | int oldlen, newlen; 239 | int err; 240 | 241 | FDT_RW_PROBE(fdt); 242 | 243 | namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); 244 | if (!namep) 245 | return oldlen; 246 | 247 | newlen = strlen(name); 248 | 249 | err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1), 250 | FDT_TAGALIGN(newlen+1)); 251 | if (err) 252 | return err; 253 | 254 | memcpy(namep, name, newlen+1); 255 | return 0; 256 | } 257 | 258 | int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, 259 | int len, void **prop_data) 260 | { 261 | struct fdt_property *prop; 262 | int err; 263 | 264 | FDT_RW_PROBE(fdt); 265 | 266 | err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); 267 | if (err == -FDT_ERR_NOTFOUND) 268 | err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); 269 | if (err) 270 | return err; 271 | 272 | *prop_data = prop->data; 273 | return 0; 274 | } 275 | 276 | int fdt_setprop(void *fdt, int nodeoffset, const char *name, 277 | const void *val, int len) 278 | { 279 | void *prop_data; 280 | int err; 281 | 282 | err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); 283 | if (err) 284 | return err; 285 | 286 | if (len) 287 | memcpy(prop_data, val, len); 288 | return 0; 289 | } 290 | 291 | int fdt_appendprop(void *fdt, int nodeoffset, const char *name, 292 | const void *val, int len) 293 | { 294 | struct fdt_property *prop; 295 | int err, oldlen, newlen; 296 | 297 | FDT_RW_PROBE(fdt); 298 | 299 | prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 300 | if (prop) { 301 | newlen = len + oldlen; 302 | err = fdt_splice_struct_(fdt, prop->data, 303 | FDT_TAGALIGN(oldlen), 304 | FDT_TAGALIGN(newlen)); 305 | if (err) 306 | return err; 307 | prop->len = cpu_to_fdt32(newlen); 308 | memcpy(prop->data + oldlen, val, len); 309 | } else { 310 | err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); 311 | if (err) 312 | return err; 313 | memcpy(prop->data, val, len); 314 | } 315 | return 0; 316 | } 317 | 318 | int fdt_delprop(void *fdt, int nodeoffset, const char *name) 319 | { 320 | struct fdt_property *prop; 321 | int len, proplen; 322 | 323 | FDT_RW_PROBE(fdt); 324 | 325 | prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 326 | if (!prop) 327 | return len; 328 | 329 | proplen = sizeof(*prop) + FDT_TAGALIGN(len); 330 | return fdt_splice_struct_(fdt, prop, proplen, 0); 331 | } 332 | 333 | int fdt_add_subnode_namelen(void *fdt, int parentoffset, 334 | const char *name, int namelen) 335 | { 336 | struct fdt_node_header *nh; 337 | int offset, nextoffset; 338 | int nodelen; 339 | int err; 340 | uint32_t tag; 341 | fdt32_t *endtag; 342 | 343 | FDT_RW_PROBE(fdt); 344 | 345 | offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); 346 | if (offset >= 0) 347 | return -FDT_ERR_EXISTS; 348 | else if (offset != -FDT_ERR_NOTFOUND) 349 | return offset; 350 | 351 | /* Try to place the new node after the parent's properties */ 352 | tag = fdt_next_tag(fdt, parentoffset, &nextoffset); 353 | /* the fdt_subnode_offset_namelen() should ensure this never hits */ 354 | if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) 355 | return -FDT_ERR_INTERNAL; 356 | do { 357 | offset = nextoffset; 358 | tag = fdt_next_tag(fdt, offset, &nextoffset); 359 | } while ((tag == FDT_PROP) || (tag == FDT_NOP)); 360 | 361 | nh = fdt_offset_ptr_w_(fdt, offset); 362 | nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; 363 | 364 | err = fdt_splice_struct_(fdt, nh, 0, nodelen); 365 | if (err) 366 | return err; 367 | 368 | nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 369 | memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); 370 | memcpy(nh->name, name, namelen); 371 | endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); 372 | *endtag = cpu_to_fdt32(FDT_END_NODE); 373 | 374 | return offset; 375 | } 376 | 377 | int fdt_add_subnode(void *fdt, int parentoffset, const char *name) 378 | { 379 | return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); 380 | } 381 | 382 | int fdt_del_node(void *fdt, int nodeoffset) 383 | { 384 | int endoffset; 385 | 386 | FDT_RW_PROBE(fdt); 387 | 388 | endoffset = fdt_node_end_offset_(fdt, nodeoffset); 389 | if (endoffset < 0) 390 | return endoffset; 391 | 392 | return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset), 393 | endoffset - nodeoffset, 0); 394 | } 395 | 396 | static void fdt_packblocks_(const char *old, char *new, 397 | int mem_rsv_size, 398 | int struct_size, 399 | int strings_size) 400 | { 401 | int mem_rsv_off, struct_off, strings_off; 402 | 403 | mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); 404 | struct_off = mem_rsv_off + mem_rsv_size; 405 | strings_off = struct_off + struct_size; 406 | 407 | memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); 408 | fdt_set_off_mem_rsvmap(new, mem_rsv_off); 409 | 410 | memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); 411 | fdt_set_off_dt_struct(new, struct_off); 412 | fdt_set_size_dt_struct(new, struct_size); 413 | 414 | memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); 415 | fdt_set_off_dt_strings(new, strings_off); 416 | fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); 417 | } 418 | 419 | int fdt_open_into(const void *fdt, void *buf, int bufsize) 420 | { 421 | int err; 422 | int mem_rsv_size, struct_size; 423 | int newsize; 424 | const char *fdtstart = fdt; 425 | const char *fdtend = fdtstart + fdt_totalsize(fdt); 426 | char *tmp; 427 | 428 | FDT_RO_PROBE(fdt); 429 | 430 | mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 431 | * sizeof(struct fdt_reserve_entry); 432 | 433 | if (can_assume(LATEST) || fdt_version(fdt) >= 17) { 434 | struct_size = fdt_size_dt_struct(fdt); 435 | } else if (fdt_version(fdt) == 16) { 436 | struct_size = 0; 437 | while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) 438 | ; 439 | if (struct_size < 0) 440 | return struct_size; 441 | } else { 442 | return -FDT_ERR_BADVERSION; 443 | } 444 | 445 | if (can_assume(LIBFDT_ORDER) || 446 | !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { 447 | /* no further work necessary */ 448 | err = fdt_move(fdt, buf, bufsize); 449 | if (err) 450 | return err; 451 | fdt_set_version(buf, 17); 452 | fdt_set_size_dt_struct(buf, struct_size); 453 | fdt_set_totalsize(buf, bufsize); 454 | return 0; 455 | } 456 | 457 | /* Need to reorder */ 458 | newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size 459 | + struct_size + fdt_size_dt_strings(fdt); 460 | 461 | if (bufsize < newsize) 462 | return -FDT_ERR_NOSPACE; 463 | 464 | /* First attempt to build converted tree at beginning of buffer */ 465 | tmp = buf; 466 | /* But if that overlaps with the old tree... */ 467 | if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { 468 | /* Try right after the old tree instead */ 469 | tmp = (char *)(uintptr_t)fdtend; 470 | if ((tmp + newsize) > ((char *)buf + bufsize)) 471 | return -FDT_ERR_NOSPACE; 472 | } 473 | 474 | fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, 475 | fdt_size_dt_strings(fdt)); 476 | memmove(buf, tmp, newsize); 477 | 478 | fdt_set_magic(buf, FDT_MAGIC); 479 | fdt_set_totalsize(buf, bufsize); 480 | fdt_set_version(buf, 17); 481 | fdt_set_last_comp_version(buf, 16); 482 | fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); 483 | 484 | return 0; 485 | } 486 | 487 | int fdt_pack(void *fdt) 488 | { 489 | int mem_rsv_size; 490 | 491 | FDT_RW_PROBE(fdt); 492 | 493 | mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 494 | * sizeof(struct fdt_reserve_entry); 495 | fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), 496 | fdt_size_dt_strings(fdt)); 497 | fdt_set_totalsize(fdt, fdt_data_size_(fdt)); 498 | 499 | return 0; 500 | } 501 | -------------------------------------------------------------------------------- /src/libfdt/fdt_strerror.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6 | */ 7 | #include "libfdt_env.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "libfdt_internal.h" 13 | 14 | struct fdt_errtabent { 15 | const char *str; 16 | }; 17 | 18 | #define FDT_ERRTABENT(val) \ 19 | [(val)] = { .str = #val, } 20 | 21 | static struct fdt_errtabent fdt_errtable[] = { 22 | FDT_ERRTABENT(FDT_ERR_NOTFOUND), 23 | FDT_ERRTABENT(FDT_ERR_EXISTS), 24 | FDT_ERRTABENT(FDT_ERR_NOSPACE), 25 | 26 | FDT_ERRTABENT(FDT_ERR_BADOFFSET), 27 | FDT_ERRTABENT(FDT_ERR_BADPATH), 28 | FDT_ERRTABENT(FDT_ERR_BADPHANDLE), 29 | FDT_ERRTABENT(FDT_ERR_BADSTATE), 30 | 31 | FDT_ERRTABENT(FDT_ERR_TRUNCATED), 32 | FDT_ERRTABENT(FDT_ERR_BADMAGIC), 33 | FDT_ERRTABENT(FDT_ERR_BADVERSION), 34 | FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), 35 | FDT_ERRTABENT(FDT_ERR_BADLAYOUT), 36 | FDT_ERRTABENT(FDT_ERR_INTERNAL), 37 | FDT_ERRTABENT(FDT_ERR_BADNCELLS), 38 | FDT_ERRTABENT(FDT_ERR_BADVALUE), 39 | FDT_ERRTABENT(FDT_ERR_BADOVERLAY), 40 | FDT_ERRTABENT(FDT_ERR_NOPHANDLES), 41 | FDT_ERRTABENT(FDT_ERR_BADFLAGS), 42 | FDT_ERRTABENT(FDT_ERR_ALIGNMENT), 43 | }; 44 | #define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) 45 | 46 | const char *fdt_strerror(int errval) 47 | { 48 | if (errval > 0) 49 | return ""; 50 | else if (errval == 0) 51 | return ""; 52 | else if (-errval < FDT_ERRTABSIZE) { 53 | const char *s = fdt_errtable[-errval].str; 54 | 55 | if (s) 56 | return s; 57 | } 58 | 59 | return ""; 60 | } 61 | -------------------------------------------------------------------------------- /src/libfdt/fdt_sw.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | static int fdt_sw_probe_(void *fdt) 14 | { 15 | if (!can_assume(VALID_INPUT)) { 16 | if (fdt_magic(fdt) == FDT_MAGIC) 17 | return -FDT_ERR_BADSTATE; 18 | else if (fdt_magic(fdt) != FDT_SW_MAGIC) 19 | return -FDT_ERR_BADMAGIC; 20 | } 21 | 22 | return 0; 23 | } 24 | 25 | #define FDT_SW_PROBE(fdt) \ 26 | { \ 27 | int err; \ 28 | if ((err = fdt_sw_probe_(fdt)) != 0) \ 29 | return err; \ 30 | } 31 | 32 | /* 'memrsv' state: Initial state after fdt_create() 33 | * 34 | * Allowed functions: 35 | * fdt_add_reservemap_entry() 36 | * fdt_finish_reservemap() [moves to 'struct' state] 37 | */ 38 | static int fdt_sw_probe_memrsv_(void *fdt) 39 | { 40 | int err = fdt_sw_probe_(fdt); 41 | if (err) 42 | return err; 43 | 44 | if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) 45 | return -FDT_ERR_BADSTATE; 46 | return 0; 47 | } 48 | 49 | #define FDT_SW_PROBE_MEMRSV(fdt) \ 50 | { \ 51 | int err; \ 52 | if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ 53 | return err; \ 54 | } 55 | 56 | /* 'struct' state: Enter this state after fdt_finish_reservemap() 57 | * 58 | * Allowed functions: 59 | * fdt_begin_node() 60 | * fdt_end_node() 61 | * fdt_property*() 62 | * fdt_finish() [moves to 'complete' state] 63 | */ 64 | static int fdt_sw_probe_struct_(void *fdt) 65 | { 66 | int err = fdt_sw_probe_(fdt); 67 | if (err) 68 | return err; 69 | 70 | if (!can_assume(VALID_INPUT) && 71 | fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) 72 | return -FDT_ERR_BADSTATE; 73 | return 0; 74 | } 75 | 76 | #define FDT_SW_PROBE_STRUCT(fdt) \ 77 | { \ 78 | int err; \ 79 | if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ 80 | return err; \ 81 | } 82 | 83 | static inline uint32_t sw_flags(void *fdt) 84 | { 85 | /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ 86 | return fdt_last_comp_version(fdt); 87 | } 88 | 89 | /* 'complete' state: Enter this state after fdt_finish() 90 | * 91 | * Allowed functions: none 92 | */ 93 | 94 | static void *fdt_grab_space_(void *fdt, size_t len) 95 | { 96 | unsigned int offset = fdt_size_dt_struct(fdt); 97 | unsigned int spaceleft; 98 | 99 | spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) 100 | - fdt_size_dt_strings(fdt); 101 | 102 | if ((offset + len < offset) || (offset + len > spaceleft)) 103 | return NULL; 104 | 105 | fdt_set_size_dt_struct(fdt, offset + len); 106 | return fdt_offset_ptr_w_(fdt, offset); 107 | } 108 | 109 | int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) 110 | { 111 | const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), 112 | sizeof(struct fdt_reserve_entry)); 113 | void *fdt = buf; 114 | 115 | if (bufsize < hdrsize) 116 | return -FDT_ERR_NOSPACE; 117 | 118 | if (flags & ~FDT_CREATE_FLAGS_ALL) 119 | return -FDT_ERR_BADFLAGS; 120 | 121 | memset(buf, 0, bufsize); 122 | 123 | /* 124 | * magic and last_comp_version keep intermediate state during the fdt 125 | * creation process, which is replaced with the proper FDT format by 126 | * fdt_finish(). 127 | * 128 | * flags should be accessed with sw_flags(). 129 | */ 130 | fdt_set_magic(fdt, FDT_SW_MAGIC); 131 | fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 132 | fdt_set_last_comp_version(fdt, flags); 133 | 134 | fdt_set_totalsize(fdt, bufsize); 135 | 136 | fdt_set_off_mem_rsvmap(fdt, hdrsize); 137 | fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 138 | fdt_set_off_dt_strings(fdt, 0); 139 | 140 | return 0; 141 | } 142 | 143 | int fdt_create(void *buf, int bufsize) 144 | { 145 | return fdt_create_with_flags(buf, bufsize, 0); 146 | } 147 | 148 | int fdt_resize(void *fdt, void *buf, int bufsize) 149 | { 150 | size_t headsize, tailsize; 151 | char *oldtail, *newtail; 152 | 153 | FDT_SW_PROBE(fdt); 154 | 155 | if (bufsize < 0) 156 | return -FDT_ERR_NOSPACE; 157 | 158 | headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 159 | tailsize = fdt_size_dt_strings(fdt); 160 | 161 | if (!can_assume(VALID_DTB) && 162 | headsize + tailsize > fdt_totalsize(fdt)) 163 | return -FDT_ERR_INTERNAL; 164 | 165 | if ((headsize + tailsize) > (unsigned)bufsize) 166 | return -FDT_ERR_NOSPACE; 167 | 168 | oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; 169 | newtail = (char *)buf + bufsize - tailsize; 170 | 171 | /* Two cases to avoid clobbering data if the old and new 172 | * buffers partially overlap */ 173 | if (buf <= fdt) { 174 | memmove(buf, fdt, headsize); 175 | memmove(newtail, oldtail, tailsize); 176 | } else { 177 | memmove(newtail, oldtail, tailsize); 178 | memmove(buf, fdt, headsize); 179 | } 180 | 181 | fdt_set_totalsize(buf, bufsize); 182 | if (fdt_off_dt_strings(buf)) 183 | fdt_set_off_dt_strings(buf, bufsize); 184 | 185 | return 0; 186 | } 187 | 188 | int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 189 | { 190 | struct fdt_reserve_entry *re; 191 | int offset; 192 | 193 | FDT_SW_PROBE_MEMRSV(fdt); 194 | 195 | offset = fdt_off_dt_struct(fdt); 196 | if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 197 | return -FDT_ERR_NOSPACE; 198 | 199 | re = (struct fdt_reserve_entry *)((char *)fdt + offset); 200 | re->address = cpu_to_fdt64(addr); 201 | re->size = cpu_to_fdt64(size); 202 | 203 | fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); 204 | 205 | return 0; 206 | } 207 | 208 | int fdt_finish_reservemap(void *fdt) 209 | { 210 | int err = fdt_add_reservemap_entry(fdt, 0, 0); 211 | 212 | if (err) 213 | return err; 214 | 215 | fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); 216 | return 0; 217 | } 218 | 219 | int fdt_begin_node(void *fdt, const char *name) 220 | { 221 | struct fdt_node_header *nh; 222 | int namelen; 223 | 224 | FDT_SW_PROBE_STRUCT(fdt); 225 | 226 | namelen = strlen(name) + 1; 227 | nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 228 | if (! nh) 229 | return -FDT_ERR_NOSPACE; 230 | 231 | nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 232 | memcpy(nh->name, name, namelen); 233 | return 0; 234 | } 235 | 236 | int fdt_end_node(void *fdt) 237 | { 238 | fdt32_t *en; 239 | 240 | FDT_SW_PROBE_STRUCT(fdt); 241 | 242 | en = fdt_grab_space_(fdt, FDT_TAGSIZE); 243 | if (! en) 244 | return -FDT_ERR_NOSPACE; 245 | 246 | *en = cpu_to_fdt32(FDT_END_NODE); 247 | return 0; 248 | } 249 | 250 | static int fdt_add_string_(void *fdt, const char *s) 251 | { 252 | char *strtab = (char *)fdt + fdt_totalsize(fdt); 253 | unsigned int strtabsize = fdt_size_dt_strings(fdt); 254 | unsigned int len = strlen(s) + 1; 255 | unsigned int struct_top, offset; 256 | 257 | offset = strtabsize + len; 258 | struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 259 | if (fdt_totalsize(fdt) - offset < struct_top) 260 | return 0; /* no more room :( */ 261 | 262 | memcpy(strtab - offset, s, len); 263 | fdt_set_size_dt_strings(fdt, strtabsize + len); 264 | return -offset; 265 | } 266 | 267 | /* Must only be used to roll back in case of error */ 268 | static void fdt_del_last_string_(void *fdt, const char *s) 269 | { 270 | int strtabsize = fdt_size_dt_strings(fdt); 271 | int len = strlen(s) + 1; 272 | 273 | fdt_set_size_dt_strings(fdt, strtabsize - len); 274 | } 275 | 276 | static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) 277 | { 278 | char *strtab = (char *)fdt + fdt_totalsize(fdt); 279 | int strtabsize = fdt_size_dt_strings(fdt); 280 | const char *p; 281 | 282 | *allocated = 0; 283 | 284 | p = fdt_find_string_(strtab - strtabsize, strtabsize, s); 285 | if (p) 286 | return p - strtab; 287 | 288 | *allocated = 1; 289 | 290 | return fdt_add_string_(fdt, s); 291 | } 292 | 293 | int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) 294 | { 295 | struct fdt_property *prop; 296 | int nameoff; 297 | int allocated; 298 | 299 | FDT_SW_PROBE_STRUCT(fdt); 300 | 301 | /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ 302 | if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { 303 | allocated = 1; 304 | nameoff = fdt_add_string_(fdt, name); 305 | } else { 306 | nameoff = fdt_find_add_string_(fdt, name, &allocated); 307 | } 308 | if (nameoff == 0) 309 | return -FDT_ERR_NOSPACE; 310 | 311 | prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 312 | if (! prop) { 313 | if (allocated) 314 | fdt_del_last_string_(fdt, name); 315 | return -FDT_ERR_NOSPACE; 316 | } 317 | 318 | prop->tag = cpu_to_fdt32(FDT_PROP); 319 | prop->nameoff = cpu_to_fdt32(nameoff); 320 | prop->len = cpu_to_fdt32(len); 321 | *valp = prop->data; 322 | return 0; 323 | } 324 | 325 | int fdt_property(void *fdt, const char *name, const void *val, int len) 326 | { 327 | void *ptr; 328 | int ret; 329 | 330 | ret = fdt_property_placeholder(fdt, name, len, &ptr); 331 | if (ret) 332 | return ret; 333 | memcpy(ptr, val, len); 334 | return 0; 335 | } 336 | 337 | int fdt_finish(void *fdt) 338 | { 339 | char *p = (char *)fdt; 340 | fdt32_t *end; 341 | int oldstroffset, newstroffset; 342 | uint32_t tag; 343 | int offset, nextoffset; 344 | 345 | FDT_SW_PROBE_STRUCT(fdt); 346 | 347 | /* Add terminator */ 348 | end = fdt_grab_space_(fdt, sizeof(*end)); 349 | if (! end) 350 | return -FDT_ERR_NOSPACE; 351 | *end = cpu_to_fdt32(FDT_END); 352 | 353 | /* Relocate the string table */ 354 | oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); 355 | newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 356 | memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); 357 | fdt_set_off_dt_strings(fdt, newstroffset); 358 | 359 | /* Walk the structure, correcting string offsets */ 360 | offset = 0; 361 | while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { 362 | if (tag == FDT_PROP) { 363 | struct fdt_property *prop = 364 | fdt_offset_ptr_w_(fdt, offset); 365 | int nameoff; 366 | 367 | nameoff = fdt32_to_cpu(prop->nameoff); 368 | nameoff += fdt_size_dt_strings(fdt); 369 | prop->nameoff = cpu_to_fdt32(nameoff); 370 | } 371 | offset = nextoffset; 372 | } 373 | if (nextoffset < 0) 374 | return nextoffset; 375 | 376 | /* Finally, adjust the header */ 377 | fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 378 | 379 | /* And fix up fields that were keeping intermediate state. */ 380 | fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION); 381 | fdt_set_magic(fdt, FDT_MAGIC); 382 | 383 | return 0; 384 | } 385 | -------------------------------------------------------------------------------- /src/libfdt/fdt_wip.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, 14 | const char *name, int namelen, 15 | uint32_t idx, const void *val, 16 | int len) 17 | { 18 | void *propval; 19 | int proplen; 20 | 21 | propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, 22 | &proplen); 23 | if (!propval) 24 | return proplen; 25 | 26 | if ((unsigned)proplen < (len + idx)) 27 | return -FDT_ERR_NOSPACE; 28 | 29 | memcpy((char *)propval + idx, val, len); 30 | return 0; 31 | } 32 | 33 | int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, 34 | const void *val, int len) 35 | { 36 | const void *propval; 37 | int proplen; 38 | 39 | propval = fdt_getprop(fdt, nodeoffset, name, &proplen); 40 | if (!propval) 41 | return proplen; 42 | 43 | if (proplen != len) 44 | return -FDT_ERR_NOSPACE; 45 | 46 | return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, 47 | strlen(name), 0, 48 | val, len); 49 | } 50 | 51 | static void fdt_nop_region_(void *start, int len) 52 | { 53 | fdt32_t *p; 54 | 55 | for (p = start; (char *)p < ((char *)start + len); p++) 56 | *p = cpu_to_fdt32(FDT_NOP); 57 | } 58 | 59 | int fdt_nop_property(void *fdt, int nodeoffset, const char *name) 60 | { 61 | struct fdt_property *prop; 62 | int len; 63 | 64 | prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 65 | if (!prop) 66 | return len; 67 | 68 | fdt_nop_region_(prop, len + sizeof(*prop)); 69 | 70 | return 0; 71 | } 72 | 73 | int fdt_node_end_offset_(void *fdt, int offset) 74 | { 75 | int depth = 0; 76 | 77 | while ((offset >= 0) && (depth >= 0)) 78 | offset = fdt_next_node(fdt, offset, &depth); 79 | 80 | return offset; 81 | } 82 | 83 | int fdt_nop_node(void *fdt, int nodeoffset) 84 | { 85 | int endoffset; 86 | 87 | endoffset = fdt_node_end_offset_(fdt, nodeoffset); 88 | if (endoffset < 0) 89 | return endoffset; 90 | 91 | fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0), 92 | endoffset - nodeoffset); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /src/libfdt/include/fdt.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ 2 | #ifndef FDT_H 3 | #define FDT_H 4 | /* 5 | * libfdt - Flat Device Tree manipulation 6 | * Copyright (C) 2006 David Gibson, IBM Corporation. 7 | * Copyright 2012 Kim Phillips, Freescale Semiconductor. 8 | */ 9 | 10 | #pragma warning(disable : 4200) 11 | 12 | #ifndef __ASSEMBLY__ 13 | 14 | struct fdt_header { 15 | fdt32_t magic; /* magic word FDT_MAGIC */ 16 | fdt32_t totalsize; /* total size of DT block */ 17 | fdt32_t off_dt_struct; /* offset to structure */ 18 | fdt32_t off_dt_strings; /* offset to strings */ 19 | fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ 20 | fdt32_t version; /* format version */ 21 | fdt32_t last_comp_version; /* last compatible version */ 22 | 23 | /* version 2 fields below */ 24 | fdt32_t boot_cpuid_phys; /* Which physical CPU id we're 25 | booting on */ 26 | /* version 3 fields below */ 27 | fdt32_t size_dt_strings; /* size of the strings block */ 28 | 29 | /* version 17 fields below */ 30 | fdt32_t size_dt_struct; /* size of the structure block */ 31 | }; 32 | 33 | struct fdt_reserve_entry { 34 | fdt64_t address; 35 | fdt64_t size; 36 | }; 37 | 38 | struct fdt_node_header { 39 | fdt32_t tag; 40 | char name[]; 41 | }; 42 | 43 | struct fdt_property { 44 | fdt32_t tag; 45 | fdt32_t len; 46 | fdt32_t nameoff; 47 | char data[]; 48 | }; 49 | 50 | #endif /* !__ASSEMBLY */ 51 | 52 | #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ 53 | #define FDT_TAGSIZE sizeof(fdt32_t) 54 | 55 | #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ 56 | #define FDT_END_NODE 0x2 /* End node */ 57 | #define FDT_PROP 0x3 /* Property: name off, 58 | size, content */ 59 | #define FDT_NOP 0x4 /* nop */ 60 | #define FDT_END 0x9 61 | 62 | #define FDT_V1_SIZE (7*sizeof(fdt32_t)) 63 | #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) 64 | #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) 65 | #define FDT_V16_SIZE FDT_V3_SIZE 66 | #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) 67 | 68 | #pragma warning(default : 4200) 69 | 70 | #endif /* FDT_H */ 71 | -------------------------------------------------------------------------------- /src/libfdt/include/libfdt_env.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ 2 | #ifndef LIBFDT_ENV_H 3 | #define LIBFDT_ENV_H 4 | /* 5 | * libfdt - Flat Device Tree manipulation 6 | * Copyright (C) 2006 David Gibson, IBM Corporation. 7 | * Copyright 2012 Kim Phillips, Freescale Semiconductor. 8 | */ 9 | 10 | 11 | #include 12 | #include 13 | #if !defined(NTDDI_VERSION) // MSVC STDINT depends on VC Runtime bits which can't be used in regular KM drivers 14 | #include 15 | #else 16 | #include 17 | #endif 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef __CHECKER__ 23 | #define FDT_FORCE __attribute__((force)) 24 | #define FDT_BITWISE __attribute__((bitwise)) 25 | #else 26 | #define FDT_FORCE 27 | #define FDT_BITWISE 28 | #endif 29 | 30 | typedef uint16_t FDT_BITWISE fdt16_t; 31 | typedef uint32_t FDT_BITWISE fdt32_t; 32 | typedef uint64_t FDT_BITWISE fdt64_t; 33 | 34 | #define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) 35 | #define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) 36 | #define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ 37 | (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) 38 | #define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ 39 | (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ 40 | (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ 41 | (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) 42 | 43 | static inline uint16_t fdt16_to_cpu(fdt16_t x) 44 | { 45 | return (FDT_FORCE uint16_t)CPU_TO_FDT16(x); 46 | } 47 | static inline fdt16_t cpu_to_fdt16(uint16_t x) 48 | { 49 | return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x); 50 | } 51 | 52 | static inline uint32_t fdt32_to_cpu(fdt32_t x) 53 | { 54 | return (FDT_FORCE uint32_t)CPU_TO_FDT32(x); 55 | } 56 | static inline fdt32_t cpu_to_fdt32(uint32_t x) 57 | { 58 | return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x); 59 | } 60 | 61 | static inline uint64_t fdt64_to_cpu(fdt64_t x) 62 | { 63 | return (FDT_FORCE uint64_t)CPU_TO_FDT64(x); 64 | } 65 | static inline fdt64_t cpu_to_fdt64(uint64_t x) 66 | { 67 | return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x); 68 | } 69 | #undef CPU_TO_FDT64 70 | #undef CPU_TO_FDT32 71 | #undef CPU_TO_FDT16 72 | #undef EXTRACT_BYTE 73 | 74 | #ifdef __APPLE__ 75 | #include 76 | 77 | /* strnlen() is not available on Mac OS < 10.7 */ 78 | # if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \ 79 | MAC_OS_X_VERSION_10_7) 80 | 81 | #define strnlen fdt_strnlen 82 | 83 | /* 84 | * fdt_strnlen: returns the length of a string or max_count - which ever is 85 | * smallest. 86 | * Input 1 string: the string whose size is to be determined 87 | * Input 2 max_count: the maximum value returned by this function 88 | * Output: length of the string or max_count (the smallest of the two) 89 | */ 90 | static inline size_t fdt_strnlen(const char *string, size_t max_count) 91 | { 92 | const char *p = memchr(string, 0, max_count); 93 | return p ? p - string : max_count; 94 | } 95 | 96 | #endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < 97 | MAC_OS_X_VERSION_10_7) */ 98 | 99 | #endif /* __APPLE__ */ 100 | 101 | #endif /* LIBFDT_ENV_H */ 102 | -------------------------------------------------------------------------------- /src/libfdt/include/libfdt_internal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ 2 | #ifndef LIBFDT_INTERNAL_H 3 | #define LIBFDT_INTERNAL_H 4 | /* 5 | * libfdt - Flat Device Tree manipulation 6 | * Copyright (C) 2006 David Gibson, IBM Corporation. 7 | */ 8 | #include 9 | 10 | #pragma warning(disable : 4146) 11 | #pragma warning(disable : 4242) 12 | #pragma warning(disable : 4244) 13 | #pragma warning(disable : 4267) 14 | #pragma warning(disable : 4706) 15 | 16 | #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) 17 | #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) 18 | 19 | int32_t fdt_ro_probe_(const void *fdt); 20 | #define FDT_RO_PROBE(fdt) \ 21 | { \ 22 | int32_t totalsize_; \ 23 | if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ 24 | return totalsize_; \ 25 | } 26 | 27 | int fdt_check_node_offset_(const void *fdt, int offset); 28 | int fdt_check_prop_offset_(const void *fdt, int offset); 29 | const char *fdt_find_string_(const char *strtab, int tabsize, const char *s); 30 | int fdt_node_end_offset_(void *fdt, int nodeoffset); 31 | 32 | static inline const void *fdt_offset_ptr_(const void *fdt, int offset) 33 | { 34 | return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; 35 | } 36 | 37 | static inline void *fdt_offset_ptr_w_(void *fdt, int offset) 38 | { 39 | return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset); 40 | } 41 | 42 | static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n) 43 | { 44 | const struct fdt_reserve_entry *rsv_table = 45 | (const struct fdt_reserve_entry *) 46 | ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); 47 | 48 | return rsv_table + n; 49 | } 50 | static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) 51 | { 52 | return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); 53 | } 54 | 55 | /* 56 | * Internal helpers to access tructural elements of the device tree 57 | * blob (rather than for exaple reading integers from within property 58 | * values). We assume that we are either given a naturally aligned 59 | * address for the platform or if we are not, we are on a platform 60 | * where unaligned memory reads will be handled in a graceful manner. 61 | * If not the external helpers fdtXX_ld() from libfdt.h can be used 62 | * instead. 63 | */ 64 | static inline uint32_t fdt32_ld_(const fdt32_t *p) 65 | { 66 | return fdt32_to_cpu(*p); 67 | } 68 | 69 | static inline uint64_t fdt64_ld_(const fdt64_t *p) 70 | { 71 | return fdt64_to_cpu(*p); 72 | } 73 | 74 | #define FDT_SW_MAGIC (~FDT_MAGIC) 75 | 76 | /**********************************************************************/ 77 | /* Checking controls */ 78 | /**********************************************************************/ 79 | 80 | #ifndef FDT_ASSUME_MASK 81 | #define FDT_ASSUME_MASK 0 82 | #endif 83 | 84 | /* 85 | * Defines assumptions which can be enabled. Each of these can be enabled 86 | * individually. For maximum safety, don't enable any assumptions! 87 | * 88 | * For minimal code size and no safety, use ASSUME_PERFECT at your own risk. 89 | * You should have another method of validating the device tree, such as a 90 | * signature or hash check before using libfdt. 91 | * 92 | * For situations where security is not a concern it may be safe to enable 93 | * ASSUME_SANE. 94 | */ 95 | enum { 96 | /* 97 | * This does essentially no checks. Only the latest device-tree 98 | * version is correctly handled. Inconsistencies or errors in the device 99 | * tree may cause undefined behaviour or crashes. Invalid parameters 100 | * passed to libfdt may do the same. 101 | * 102 | * If an error occurs when modifying the tree it may leave the tree in 103 | * an intermediate (but valid) state. As an example, adding a property 104 | * where there is insufficient space may result in the property name 105 | * being added to the string table even though the property itself is 106 | * not added to the struct section. 107 | * 108 | * Only use this if you have a fully validated device tree with 109 | * the latest supported version and wish to minimise code size. 110 | */ 111 | ASSUME_PERFECT = 0xff, 112 | 113 | /* 114 | * This assumes that the device tree is sane. i.e. header metadata 115 | * and basic hierarchy are correct. 116 | * 117 | * With this assumption enabled, normal device trees produced by libfdt 118 | * and the compiler should be handled safely. Malicious device trees and 119 | * complete garbage may cause libfdt to behave badly or crash. Truncated 120 | * device trees (e.g. those only partially loaded) can also cause 121 | * problems. 122 | * 123 | * Note: Only checks that relate exclusively to the device tree itself 124 | * (not the parameters passed to libfdt) are disabled by this 125 | * assumption. This includes checking headers, tags and the like. 126 | */ 127 | ASSUME_VALID_DTB = 1 << 0, 128 | 129 | /* 130 | * This builds on ASSUME_VALID_DTB and further assumes that libfdt 131 | * functions are called with valid parameters, i.e. not trigger 132 | * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any 133 | * extensive checking of parameters and the device tree, making various 134 | * assumptions about correctness. 135 | * 136 | * It doesn't make sense to enable this assumption unless 137 | * ASSUME_VALID_DTB is also enabled. 138 | */ 139 | ASSUME_VALID_INPUT = 1 << 1, 140 | 141 | /* 142 | * This disables checks for device-tree version and removes all code 143 | * which handles older versions. 144 | * 145 | * Only enable this if you know you have a device tree with the latest 146 | * version. 147 | */ 148 | ASSUME_LATEST = 1 << 2, 149 | 150 | /* 151 | * This assumes that it is OK for a failed addition to the device tree, 152 | * due to lack of space or some other problem, to skip any rollback 153 | * steps (such as dropping the property name from the string table). 154 | * This is safe to enable in most circumstances, even though it may 155 | * leave the tree in a sub-optimal state. 156 | */ 157 | ASSUME_NO_ROLLBACK = 1 << 3, 158 | 159 | /* 160 | * This assumes that the device tree components appear in a 'convenient' 161 | * order, i.e. the memory reservation block first, then the structure 162 | * block and finally the string block. 163 | * 164 | * This order is not specified by the device-tree specification, 165 | * but is expected by libfdt. The device-tree compiler always created 166 | * device trees with this order. 167 | * 168 | * This assumption disables a check in fdt_open_into() and removes the 169 | * ability to fix the problem there. This is safe if you know that the 170 | * device tree is correctly ordered. See fdt_blocks_misordered_(). 171 | */ 172 | ASSUME_LIBFDT_ORDER = 1 << 4, 173 | 174 | /* 175 | * This assumes that libfdt itself does not have any internal bugs. It 176 | * drops certain checks that should never be needed unless libfdt has an 177 | * undiscovered bug. 178 | * 179 | * This can generally be considered safe to enable. 180 | */ 181 | ASSUME_LIBFDT_FLAWLESS = 1 << 5, 182 | }; 183 | 184 | /** 185 | * can_assume_() - check if a particular assumption is enabled 186 | * 187 | * @mask: Mask to check (ASSUME_...) 188 | * @return true if that assumption is enabled, else false 189 | */ 190 | static inline bool can_assume_(int mask) 191 | { 192 | return FDT_ASSUME_MASK & mask; 193 | } 194 | 195 | /** helper macros for checking assumptions */ 196 | #define can_assume(_assume) can_assume_(ASSUME_ ## _assume) 197 | 198 | #endif /* LIBFDT_INTERNAL_H */ 199 | -------------------------------------------------------------------------------- /src/libfdt/include/stdint_kmdf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __STDINT_KMDF__ 3 | #define __STDINT_KMDF__ 4 | 5 | #include 6 | 7 | // Type forwarder to WDF types 8 | typedef UINT8 uint8_t; 9 | typedef UINT16 uint16_t; 10 | typedef UINT32 uint32_t; 11 | typedef UINT64 uint64_t; 12 | 13 | typedef INT8 int8_t; 14 | typedef INT16 int16_t; 15 | typedef INT32 int32_t; 16 | typedef INT64 int64_t; 17 | 18 | /* 7.18.2.1 Limits of exact-width integer types */ 19 | #define INT8_MIN (-128) 20 | #define INT16_MIN (-32768) 21 | #define INT32_MIN (-2147483647 - 1) 22 | #define INT64_MIN (-9223372036854775807LL - 1) 23 | 24 | #define INT8_MAX 127 25 | #define INT16_MAX 32767 26 | #define INT32_MAX 2147483647 27 | #define INT64_MAX 9223372036854775807LL 28 | 29 | #define UINT8_MAX 0xff /* 255U */ 30 | #define UINT16_MAX 0xffff /* 65535U */ 31 | #define UINT32_MAX 0xffffffff /* 4294967295U */ 32 | #define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/libfdt/libfdt.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | {F8DA265D-FABB-48B2-A61E-18FB31F2C795} 42 | {0a049372-4c4d-4ea0-a64e-dc6ad88ceca1} 43 | v4.5 44 | 12.0 45 | Debug 46 | Win32 47 | libfdt 48 | KMDF 49 | $(LatestTargetPlatformVersion) 50 | 51 | 52 | 53 | Windows10 54 | true 55 | WindowsKernelModeDriver10.0 56 | StaticLibrary 57 | Universal 58 | Unicode 59 | Spectre 60 | 61 | 62 | Windows10 63 | false 64 | WindowsKernelModeDriver10.0 65 | StaticLibrary 66 | Universal 67 | Unicode 68 | Spectre 69 | 70 | 71 | Windows10 72 | true 73 | WindowsKernelModeDriver10.0 74 | StaticLibrary 75 | Universal 76 | Unicode 77 | Spectre 78 | 79 | 80 | Windows10 81 | false 82 | WindowsKernelModeDriver10.0 83 | StaticLibrary 84 | Universal 85 | Unicode 86 | Spectre 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 97 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 98 | 99 | 100 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 101 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 102 | 103 | 104 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 105 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 106 | 107 | 108 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 109 | $(SolutionDir)out\$(ProjectName)\$(Platform).$(Configuration)\ 110 | 111 | 112 | 113 | _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions) 114 | MultiThreadedDebugDLL 115 | stdcpp17 116 | stdc17 117 | $(ProjectDir)include\;%(AdditionalIncludeDirectories) 118 | 4267;4200;4242;4146;4245;%(DisableSpecificWarnings) 119 | 120 | 121 | 122 | 123 | WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions) 124 | stdcpp17 125 | stdc17 126 | $(ProjectDir)include\;%(AdditionalIncludeDirectories) 127 | 4267;4200;4242;4146;4245;%(DisableSpecificWarnings) 128 | 129 | 130 | 131 | 132 | _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions) 133 | MultiThreadedDebugDLL 134 | stdcpp17 135 | stdc17 136 | $(ProjectDir)include\;%(AdditionalIncludeDirectories) 137 | 4267;4200;4242;4146;4245;%(DisableSpecificWarnings) 138 | 139 | 140 | 141 | 142 | WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions) 143 | stdcpp17 144 | stdc17 145 | $(ProjectDir)include\;%(AdditionalIncludeDirectories) 146 | 4267;4200;4242;4146;4245;%(DisableSpecificWarnings) 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /src/libfdt/libfdt.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/libfdt/version.lds: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ 2 | LIBFDT_1.2 { 3 | global: 4 | fdt_next_node; 5 | fdt_check_header; 6 | fdt_move; 7 | fdt_string; 8 | fdt_num_mem_rsv; 9 | fdt_get_mem_rsv; 10 | fdt_subnode_offset_namelen; 11 | fdt_subnode_offset; 12 | fdt_path_offset_namelen; 13 | fdt_path_offset; 14 | fdt_get_name; 15 | fdt_get_property_namelen; 16 | fdt_get_property; 17 | fdt_getprop_namelen; 18 | fdt_getprop; 19 | fdt_get_phandle; 20 | fdt_get_alias_namelen; 21 | fdt_get_alias; 22 | fdt_get_path; 23 | fdt_header_size; 24 | fdt_supernode_atdepth_offset; 25 | fdt_node_depth; 26 | fdt_parent_offset; 27 | fdt_node_offset_by_prop_value; 28 | fdt_node_offset_by_phandle; 29 | fdt_node_check_compatible; 30 | fdt_node_offset_by_compatible; 31 | fdt_setprop_inplace; 32 | fdt_nop_property; 33 | fdt_nop_node; 34 | fdt_create; 35 | fdt_add_reservemap_entry; 36 | fdt_finish_reservemap; 37 | fdt_begin_node; 38 | fdt_property; 39 | fdt_end_node; 40 | fdt_finish; 41 | fdt_open_into; 42 | fdt_pack; 43 | fdt_add_mem_rsv; 44 | fdt_del_mem_rsv; 45 | fdt_set_name; 46 | fdt_setprop; 47 | fdt_delprop; 48 | fdt_add_subnode_namelen; 49 | fdt_add_subnode; 50 | fdt_del_node; 51 | fdt_strerror; 52 | fdt_offset_ptr; 53 | fdt_next_tag; 54 | fdt_appendprop; 55 | fdt_create_empty_tree; 56 | fdt_first_property_offset; 57 | fdt_get_property_by_offset; 58 | fdt_getprop_by_offset; 59 | fdt_next_property_offset; 60 | fdt_first_subnode; 61 | fdt_next_subnode; 62 | fdt_address_cells; 63 | fdt_size_cells; 64 | fdt_stringlist_contains; 65 | fdt_stringlist_count; 66 | fdt_stringlist_search; 67 | fdt_stringlist_get; 68 | fdt_resize; 69 | fdt_overlay_apply; 70 | fdt_get_string; 71 | fdt_find_max_phandle; 72 | fdt_generate_phandle; 73 | fdt_check_full; 74 | fdt_setprop_placeholder; 75 | fdt_property_placeholder; 76 | fdt_header_size_; 77 | fdt_appendprop_addrrange; 78 | fdt_setprop_inplace_namelen_partial; 79 | fdt_create_with_flags; 80 | fdt_overlay_target_offset; 81 | local: 82 | *; 83 | }; 84 | --------------------------------------------------------------------------------