OpenCore  1.0.4
OpenCore Bootloader
1.0.4
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
OcDeviceTreeLib.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16
17#include <Library/BaseLib.h>
18#include <Library/DebugLib.h>
19#include <Library/BaseMemoryLib.h>
20#include <Library/MemoryAllocationLib.h>
21#include <Library/PrintLib.h>
22#include <Library/OcMiscLib.h>
23#include <Library/OcStringLib.h>
25#include <Library/UefiBootServicesTableLib.h>
26#include <Library/UefiLib.h>
27
28//
29// Obtain next property by address.
30//
31#define DEVICE_TREE_GET_NEXT_PROPERTY(Prop) \
32 (DTProperty *)(((UINT8 *)(UINTN)(Prop)) \
33 + sizeof (*Prop) + ALIGN_VALUE (Prop->Length, sizeof (UINT32)))
34
35//
36// Location of the Device Tree.
37//
39
40//
41// Pointer to location that contains the length of the Device Tree.
42//
43STATIC UINT32 *mDTLength;
44
45STATIC UINT32 mDTNodeDepth;
46
48
49//
50// Support Routines.
51//
52
53STATIC
56 IN DTEntry Entry
57 )
58{
59 DTProperty *Prop;
60 UINT32 Count;
61
62 if ((Entry == NULL) || (Entry->NumProperties == 0)) {
63 return NULL;
64 } else {
65 Prop = (DTProperty *)(Entry + 1);
66 for (Count = 0; Count < Entry->NumProperties; ++Count) {
68 }
69 }
70
71 return (DTEntry)Prop;
72}
73
74STATIC
77 IN DTEntry Root
78 )
79{
80 DTEntry Entry;
81 UINT32 Count;
82
83 Entry = DTSkipProperties (Root);
84
85 if (Entry == NULL) {
86 return NULL;
87 }
88
89 for (Count = 0; Count < Root->NumChildren; ++Count) {
90 Entry = DTSkipTree (Entry);
91 }
92
93 return Entry;
94}
95
96STATIC
99 IN DTEntry Parent
100 )
101{
102 return DTSkipProperties (Parent);
103}
104
105STATIC
108 IN DTEntry Sibling
109 )
110{
111 return DTSkipTree (Sibling);
112}
113
114STATIC
115CONST CHAR8 *
117 IN CONST CHAR8 *Cp,
118 IN CHAR8 *Bp
119 )
120{
121 while (*Cp != 0) {
122 if (*Cp == DT_PATH_NAME_SEPERATOR) {
123 Cp++;
124 break;
125 }
126
127 *Bp++ = *Cp++;
128 }
129
130 *Bp = 0;
131 return Cp;
132}
133
134STATIC
137 IN DTEntry Cur,
138 IN CHAR8 *Buf
139 )
140{
141 DTEntry Child;
142 UINTN Index;
143 CHAR8 *Str;
144 UINT32 Dummy;
145
146 if (Cur->NumChildren == 0) {
147 return NULL;
148 }
149
150 Index = 1;
151 Child = GetFirstChild (Cur);
152 while (1) {
153 if (EFI_ERROR (DTGetProperty (Child, "name", (VOID **)&Str, &Dummy))) {
154 break;
155 }
156
157 if (AsciiStrCmp (Str, Buf) == 0) {
158 return Child;
159 }
160
161 if (Index >= Cur->NumChildren) {
162 break;
163 }
164
165 Child = GetNextChild (Child);
166 ++Index;
167 }
168
169 return NULL;
170}
171
172//
173// External Routines.
174//
175
176EFI_STATUS
178 IN CONST DTEntry SearchPoint,
179 IN CONST CHAR8 *PathName,
180 IN DTEntry *FoundEntry
181 )
182{
183 DTEntryNameBuf Buf;
184 DTEntry Cur;
185 CONST CHAR8 *Cp;
186
187 if (mDTRootNode == NULL) {
188 return EFI_INVALID_PARAMETER;
189 }
190
191 if (SearchPoint == NULL) {
192 Cur = mDTRootNode;
193 } else {
194 Cur = SearchPoint;
195 }
196
197 Cp = PathName;
198 if (*Cp == DT_PATH_NAME_SEPERATOR) {
199 Cp++;
200 if (*Cp == '\0') {
201 *FoundEntry = Cur;
202 return EFI_SUCCESS;
203 }
204 }
205
206 do {
207 Cp = GetNextComponent (Cp, Buf);
208
209 //
210 // Check for done.
211 //
212 if (*Buf == '\0') {
213 if (*Cp == '\0') {
214 *FoundEntry = Cur;
215 return EFI_SUCCESS;
216 }
217
218 break;
219 }
220
221 Cur = FindChild (Cur, Buf);
222 } while (Cur != NULL);
223
224 return EFI_INVALID_PARAMETER;
225}
226
227EFI_STATUS
229 IN CONST DTEntry StartEntry,
230 IN DTEntryIterator *Iterator
231 )
232{
233 DTEntryIterator Iter;
234
235 if (mDTRootNode == NULL) {
236 return EFI_INVALID_PARAMETER;
237 }
238
239 Iter = AllocatePool (sizeof (OpaqueDTEntryIterator));
240
241 if (Iter == NULL) {
242 return EFI_OUT_OF_RESOURCES;
243 }
244
245 if (StartEntry != NULL) {
246 Iter->OuterScope = (DTEntry)StartEntry;
247 Iter->CurrentScope = (DTEntry)StartEntry;
248 } else {
249 Iter->OuterScope = mDTRootNode;
251 }
252
253 Iter->CurrentEntry = NULL;
254 Iter->SavedScope = NULL;
255 Iter->CurrentIndex = 0;
256
257 *Iterator = Iter;
258 return EFI_SUCCESS;
259}
260
261EFI_STATUS
263 IN DTEntryIterator Iterator
264 )
265{
266 DTSavedScopePtr Scope;
267
268 while ((Scope = Iterator->SavedScope) != NULL) {
269 Iterator->SavedScope = Scope->NextScope;
270 FreePool (Scope);
271 }
272
273 FreePool (Iterator);
274 return EFI_SUCCESS;
275}
276
277EFI_STATUS
279 IN DTEntryIterator Iterator,
280 IN DTEntry ChildEntry
281 )
282{
283 DTSavedScopePtr NewScope;
284
285 if (ChildEntry == NULL) {
286 return EFI_INVALID_PARAMETER;
287 }
288
289 NewScope = AllocatePool (sizeof (DTSavedScope));
290
291 if (NewScope == NULL) {
292 return EFI_OUT_OF_RESOURCES;
293 }
294
295 NewScope->NextScope = Iterator->SavedScope;
296 NewScope->Scope = Iterator->CurrentScope;
297 NewScope->Entry = Iterator->CurrentEntry;
298 NewScope->Index = Iterator->CurrentIndex;
299
300 Iterator->CurrentScope = ChildEntry;
301 Iterator->CurrentEntry = NULL;
302 Iterator->SavedScope = NewScope;
303 Iterator->CurrentIndex = 0;
304
305 return EFI_SUCCESS;
306}
307
308EFI_STATUS
310 IN DTEntryIterator Iterator,
311 IN DTEntry *CurrentPosition
312 )
313{
314 DTSavedScopePtr NewScope;
315
316 NewScope = Iterator->SavedScope;
317
318 if (NewScope == NULL) {
319 return EFI_INVALID_PARAMETER;
320 }
321
322 Iterator->SavedScope = NewScope->NextScope;
323 Iterator->CurrentScope = NewScope->Scope;
324 Iterator->CurrentEntry = NewScope->Entry;
325 Iterator->CurrentIndex = NewScope->Index;
326
327 *CurrentPosition = Iterator->CurrentEntry;
328
329 FreePool (NewScope);
330
331 return EFI_SUCCESS;
332}
333
334EFI_STATUS
336 IN DTEntryIterator Iterator,
337 IN DTEntry *NextEntry
338 )
339{
340 if (Iterator->CurrentIndex >= Iterator->CurrentScope->NumChildren) {
341 *NextEntry = NULL;
342 return EFI_END_OF_MEDIA;
343 }
344
345 ++Iterator->CurrentIndex;
346 if (Iterator->CurrentIndex == 1) {
347 Iterator->CurrentEntry = GetFirstChild (Iterator->CurrentScope);
348 } else {
349 Iterator->CurrentEntry = GetNextChild (Iterator->CurrentEntry);
350 }
351
352 *NextEntry = Iterator->CurrentEntry;
353 return EFI_SUCCESS;
354}
355
356EFI_STATUS
358 IN DTEntryIterator Iterator
359 )
360{
361 Iterator->CurrentEntry = NULL;
362 Iterator->CurrentIndex = 0;
363 return EFI_SUCCESS;
364}
365
366EFI_STATUS
368 IN CONST DTEntry Entry,
369 IN CHAR8 *PropertyName,
370 IN VOID **PropertyValue,
371 IN UINT32 *PropertySize
372 )
373{
374 DTProperty *Prop;
375 UINT32 Count;
376
377 if ((Entry == NULL) || (Entry->NumProperties == 0)) {
378 return EFI_INVALID_PARAMETER;
379 }
380
381 Prop = (DTProperty *)(Entry + 1);
382 for (Count = 0; Count < Entry->NumProperties; Count++) {
383 if (AsciiStrCmp (Prop->Name, PropertyName) == 0) {
384 *PropertyValue = (VOID *)(((UINT8 *)Prop) + sizeof (DTProperty));
385 *PropertySize = Prop->Length;
386 return EFI_SUCCESS;
387 }
388
389 Prop = DEVICE_TREE_GET_NEXT_PROPERTY (Prop);
390 }
391
392 return EFI_INVALID_PARAMETER;
393}
394
395EFI_STATUS
397 IN CONST DTEntry Entry,
398 IN DTPropertyIterator Iterator
399 )
400{
401 Iterator->Entry = Entry;
402 Iterator->CurrentProperty = NULL;
403 Iterator->CurrentIndex = 0;
404
405 return EFI_SUCCESS;
406}
407
408EFI_STATUS
410 IN DTPropertyIterator Iterator,
411 IN CHAR8 **FoundProperty
412 )
413{
414 if (Iterator->CurrentIndex >= Iterator->Entry->NumProperties) {
415 *FoundProperty = NULL;
416 return EFI_END_OF_MEDIA;
417 }
418
419 Iterator->CurrentIndex++;
420 if (Iterator->CurrentIndex == 1) {
421 Iterator->CurrentProperty = (DTProperty *)(Iterator->Entry + 1);
422 } else {
423 Iterator->CurrentProperty = DEVICE_TREE_GET_NEXT_PROPERTY (Iterator->CurrentProperty);
424 }
425
426 *FoundProperty = Iterator->CurrentProperty->Name;
427
428 return EFI_SUCCESS;
429}
430
431EFI_STATUS
433 IN DTPropertyIterator Iterator
434 )
435{
436 Iterator->CurrentProperty = NULL;
437 Iterator->CurrentIndex = 0;
438
439 return EFI_SUCCESS;
440}
441
442EFI_STATUS
444 IN DTEntry Entry
445 )
446{
447 EFI_STATUS Status;
448 DTEntry Root;
449 UINTN Spacer;
450
451 DTEntryIterator EntryIterator;
452 DTPropertyIterator PropIter;
455 UINT8 *Address;
456
457 CHAR8 *PropertyParent = NULL;
458 CHAR8 *PropertyName = NULL;
459 CHAR8 *PropertyValue = NULL;
460
461 UINT32 PropertySize = 0;
462
463 PropIter = &mOpaquePropIter;
464
465 if (Entry == NULL) {
466 return EFI_INVALID_PARAMETER;
467 }
468
469 Root = Entry;
470 Spacer = 1;
471
472 Status = DTCreatePropertyIterator (Entry, PropIter);
473
474 if (!EFI_ERROR (Status)) {
475 PropertyParent = "/";
476
477 while ((Status = DTIterateProperties (PropIter, &PropertyName)) == EFI_SUCCESS) {
478 if ((Status = DTGetProperty (Entry, (CHAR8 *)PropertyName, (void *)&PropertyValue, &PropertySize)) != EFI_SUCCESS) {
479 DEBUG ((DEBUG_WARN, "DeviceTree is probably invalid - %r\n", Status));
480 break;
481 }
482
483 if (AsciiStrnCmp (PropertyName, "name", 4) == 0) {
484 DEBUG ((DEBUG_INFO, "+%*ao %a\n", mDTNodeDepth * Spacer, "-", PropertyValue, mDTNodeDepth));
485 DEBUG ((DEBUG_INFO, "|%*a\n", mDTNodeDepth * Spacer, " {", mDTNodeDepth));
486 PropertyParent = PropertyValue;
487 mDTNodeDepth++;
488 } else if (AsciiStrnCmp (PropertyName, "guid", 4) == 0) {
489 //
490 // Show Guid.
491 //
492 DEBUG ((DEBUG_INFO, "|%*a \"%a\" = < %g >\n", mDTNodeDepth * Spacer, " ", PropertyName, PropertyValue, PropertySize));
493 } else if (AsciiStrnCmp (PropertyParent, "memory-map", 10) == 0) {
494 MemMap = (DTMemMapEntry *)PropertyValue;
495
496 if (AsciiStrnCmp (PropertyName, "Driver-", 7) == 0) {
497 Kext = (DTBooterKextFileInfo *)(UINTN)MemMap->Address;
498
499 if ((Kext != NULL) && (Kext->ExecutablePhysAddr != 0)) {
500 DEBUG ((
501 DEBUG_INFO,
502 "|%*a \"%a\" = < Dict 0x%0X Binary 0x%0X \"%a\" >\n",
503 mDTNodeDepth * Spacer,
504 " ",
505 PropertyName,
506 Kext->InfoDictPhysAddr,
507 Kext->ExecutablePhysAddr,
509 ));
510 }
511 } else {
512 Address = (UINT8 *)(UINTN)MemMap->Address;
513 if (Address != NULL) {
514 DEBUG ((
515 DEBUG_INFO,
516 "|%*a \"%a\" = < 0x%0X %02X %02X %02X %02X Length %X >\n",
517 mDTNodeDepth * Spacer,
518 " ",
519 PropertyName,
520 MemMap->Address,
521 Address[0],
522 Address[1],
523 Address[2],
524 Address[3],
525 MemMap->Length
526 ));
527 }
528 }
529 } else {
530 //
531 // TODO: Print data here.
532 //
533 DEBUG ((
534 DEBUG_INFO,
535 "|%*a \"%a\" = < ... > (%d)\n",
536 mDTNodeDepth * Spacer,
537 " ",
538 PropertyName,
539 PropertySize
540 ));
541 }
542 }
543
544 DEBUG ((DEBUG_INFO, "|%*a\n", (mDTNodeDepth - 1) * Spacer, " }", mDTNodeDepth));
545 }
546
547 Status = DTCreateEntryIterator (Root, &EntryIterator);
548
549 if (!EFI_ERROR (Status)) {
550 while (!EFI_ERROR (DTIterateEntries (EntryIterator, &Root))) {
552 mDTNodeDepth--;
553 }
554 }
555
556 return !EFI_ERROR (Status) ? EFI_SUCCESS : EFI_NOT_FOUND;
557}
558
559VOID
561 VOID
562 )
563{
564 DTEntry DTRoot = NULL;
565
566 if (!EFI_ERROR (DTLookupEntry (NULL, "/", &DTRoot))) {
568 }
569}
570
571// DTInit
577
578VOID
580 IN VOID *Base,
581 IN UINT32 *Length
582 )
583{
584 if ((Base != NULL) && (Length != NULL)) {
585 mDTRootNode = (DTEntry)Base;
587 }
588}
589
590// DTDeleteProperty
596
597UINT32
599 IN CHAR8 *NodeName,
600 IN CHAR8 *DeletePropertyName
601 )
602{
603 DTEntry Node;
604 DTPropertyIterator PropIter;
605 DTProperty *Property;
606 CHAR8 *DeletePosition;
607 CHAR8 *DeviceTreeEnd;
608 UINT32 DeleteLength;
609
610 ASSERT (mDTLength != NULL);
611
612 PropIter = &mOpaquePropIter;
613 DeletePosition = NULL;
614 DeviceTreeEnd = (CHAR8 *)mDTRootNode + *mDTLength;
615 DeleteLength = 0;
616
617 if (!EFI_ERROR (DTLookupEntry (NULL, NodeName, &Node))) {
618 if (!EFI_ERROR (DTCreatePropertyIterator (Node, PropIter))) {
619 while (!EFI_ERROR (DTIterateProperties (PropIter, &DeletePosition))) {
620 if (AsciiStrStr (DeletePosition, DeletePropertyName) != NULL) {
621 Property = (DTProperty *)DeletePosition;
622 DeleteLength = sizeof (DTProperty) + ALIGN_VALUE (Property->Length, sizeof (UINT32));
623
624 //
625 // Adjust Device Tree Length.
626 //
627 *mDTLength -= DeleteLength;
628
629 //
630 // Delete Property.
631 //
632 CopyMem (DeletePosition, DeletePosition + DeleteLength, DeviceTreeEnd - DeletePosition);
633 ZeroMem (DeviceTreeEnd - DeleteLength, DeleteLength);
634
635 //
636 // Decrement Nodes Properties Count.
637 //
638 Node->NumProperties--;
639
640 break;
641 }
642 }
643 }
644 }
645
646 return DeleteLength;
647}
648
649// DTInsertProperty
659
660VOID
662 IN CHAR8 *NodeName,
663 IN CHAR8 *InsertPropertyName,
664 IN CHAR8 *AddPropertyName,
665 IN VOID *AddPropertyValue,
666 IN UINT32 ValueLength,
667 IN BOOLEAN InsertAfter
668 )
669{
670 DTEntry Node;
671 DTPropertyIterator PropIter;
672 DTProperty *Property;
673 UINT32 EntryLength;
674 CHAR8 *DeviceTree;
675 CHAR8 *DeviceTreeEnd;
676 CHAR8 *InsertPosition;
677
678 ASSERT (mDTLength != NULL);
679
680 PropIter = &mOpaquePropIter;
681 EntryLength = ALIGN_VALUE (ValueLength, sizeof (UINT32));
682 DeviceTree = NULL;
683 DeviceTreeEnd = (CHAR8 *)mDTRootNode + *mDTLength;
684 InsertPosition = NULL;
685
686 if (!EFI_ERROR (DTLookupEntry (NULL, NodeName, &Node))) {
687 if (!EFI_ERROR (DTCreatePropertyIterator (Node, PropIter))) {
688 while (!EFI_ERROR (DTIterateProperties (PropIter, &DeviceTree))) {
689 InsertPosition = DeviceTree;
690 if (AsciiStrStr (InsertPosition, InsertPropertyName) != NULL) {
691 break;
692 }
693 }
694
695 if (InsertAfter) {
696 Property = (DTProperty *)InsertPosition;
697 InsertPosition += sizeof (DTProperty) + ALIGN_VALUE (Property->Length, sizeof (UINT32));
698 }
699
700 Property = (DTProperty *)InsertPosition;
701
702 //
703 // Make space.
704 //
705 CopyMem (InsertPosition + sizeof (DTProperty) + EntryLength, InsertPosition, DeviceTreeEnd - InsertPosition);
706 ZeroMem (InsertPosition, sizeof (DTProperty) + EntryLength);
707
708 //
709 // Insert Property Name.
710 //
711 CopyMem (Property->Name, AddPropertyName, AsciiStrLen (AddPropertyName));
712
713 //
714 // Insert Property Value Length.
715 //
716 Property->Length = ValueLength;
717
718 //
719 // Insert Property Value.
720 //
721 CopyMem (InsertPosition + sizeof (DTProperty), AddPropertyValue, ValueLength);
722
723 //
724 // Increment Nodes Properties Count.
725 //
726 Node->NumProperties++;
727
728 //
729 // Adjust Length.
730 //
731 *mDTLength += sizeof (DTProperty) + EntryLength;
732 }
733 }
734}
UINT64 Length
MEMMAP_DEVICE_PATH MemMap
CHAR16 PathName[DMG_FILE_PATH_LEN]
EFI_STATUS DTLookupEntry(IN CONST DTEntry SearchPoint, IN CONST CHAR8 *PathName, IN DTEntry *FoundEntry)
STATIC CONST CHAR8 * GetNextComponent(IN CONST CHAR8 *Cp, IN CHAR8 *Bp)
EFI_STATUS DTDisposeEntryIterator(IN DTEntryIterator Iterator)
VOID DTInit(IN VOID *Base, IN UINT32 *Length)
EFI_STATUS DTIterateProperties(IN DTPropertyIterator Iterator, IN CHAR8 **FoundProperty)
EFI_STATUS DTRestartPropertyIteration(IN DTPropertyIterator Iterator)
STATIC DTEntry DTSkipTree(IN DTEntry Root)
EFI_STATUS DTCreateEntryIterator(IN CONST DTEntry StartEntry, IN DTEntryIterator *Iterator)
EFI_STATUS DTGetProperty(IN CONST DTEntry Entry, IN CHAR8 *PropertyName, IN VOID **PropertyValue, IN UINT32 *PropertySize)
STATIC UINT32 mDTNodeDepth
STATIC UINT32 * mDTLength
STATIC DTEntry GetFirstChild(IN DTEntry Parent)
UINT32 DTDeleteProperty(IN CHAR8 *NodeName, IN CHAR8 *DeletePropertyName)
VOID DTInsertProperty(IN CHAR8 *NodeName, IN CHAR8 *InsertPropertyName, IN CHAR8 *AddPropertyName, IN VOID *AddPropertyValue, IN UINT32 ValueLength, IN BOOLEAN InsertAfter)
EFI_STATUS DTCreatePropertyIterator(IN CONST DTEntry Entry, IN DTPropertyIterator Iterator)
#define DEVICE_TREE_GET_NEXT_PROPERTY(Prop)
STATIC OpaqueDTPropertyIterator mOpaquePropIter
EFI_STATUS DumpDeviceTreeNodeRecusively(IN DTEntry Entry)
STATIC DTEntry DTSkipProperties(IN DTEntry Entry)
EFI_STATUS DTExitEntry(IN DTEntryIterator Iterator, IN DTEntry *CurrentPosition)
STATIC DTEntry mDTRootNode
EFI_STATUS DTIterateEntries(IN DTEntryIterator Iterator, IN DTEntry *NextEntry)
STATIC DTEntry GetNextChild(IN DTEntry Sibling)
EFI_STATUS DTRestartEntryIteration(IN DTEntryIterator Iterator)
EFI_STATUS DTEnterEntry(IN DTEntryIterator Iterator, IN DTEntry ChildEntry)
STATIC DTEntry FindChild(IN DTEntry Cur, IN CHAR8 *Buf)
VOID DumpDeviceTree(VOID)
struct OpaqueDTProperty_ DTProperty
DeviceTreeNode * DTEntry
Entry.
#define DT_PATH_NAME_SEPERATOR
0x2F
CHAR8 DTEntryNameBuf[DT_PROPERTY_NAME_LENGTH]
Length of DTEntryNameBuf = DT_MAX_ENTRY_NAME_LENGTH + 1.
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define ASSERT(x)
Definition coder.h:55
DTSavedScopePtr NextScope
UINT32 NumProperties
DTSavedScopePtr SavedScope
DTEntry OuterScope
DTEntry CurrentScope
DTEntry CurrentEntry
UINT32 CurrentIndex
UINT32 Length
Length (bytes) of folloing prop value.
CHAR8 Name[DT_PROPERTY_NAME_LENGTH]
NUL terminated property name.