TianoCore EDK2 master
Loading...
Searching...
No Matches
FdtClientDxe.c
Go to the documentation of this file.
1
10#include <Library/BaseLib.h>
11#include <Library/DebugLib.h>
12#include <Library/FdtLib.h>
15#include <Library/HobLib.h>
16
17#include <Guid/Fdt.h>
18#include <Guid/FdtHob.h>
20
21#include <Protocol/FdtClient.h>
22
23STATIC VOID *mDeviceTreeBase;
24
27EFIAPI
28GetNodeProperty (
30 IN INT32 Node,
31 IN CONST CHAR8 *PropertyName,
32 OUT CONST VOID **Prop,
33 OUT UINT32 *PropSize OPTIONAL
34 )
35{
36 INT32 Len;
37
38 ASSERT (mDeviceTreeBase != NULL);
39 ASSERT (Prop != NULL);
40
41 *Prop = FdtGetProp (mDeviceTreeBase, Node, PropertyName, &Len);
42 if (*Prop == NULL) {
43 return EFI_NOT_FOUND;
44 }
45
46 if (PropSize != NULL) {
47 *PropSize = Len;
48 }
49
50 return EFI_SUCCESS;
51}
52
55EFIAPI
56SetNodeProperty (
58 IN INT32 Node,
59 IN CONST CHAR8 *PropertyName,
60 IN CONST VOID *Prop,
61 IN UINT32 PropSize
62 )
63{
64 INT32 Ret;
65
66 ASSERT (mDeviceTreeBase != NULL);
67
68 Ret = FdtSetProp (mDeviceTreeBase, Node, PropertyName, Prop, PropSize);
69 if (Ret != 0) {
70 return EFI_DEVICE_ERROR;
71 }
72
73 return EFI_SUCCESS;
74}
75
77BOOLEAN
78IsNodeEnabled (
79 INT32 Node
80 )
81{
82 CONST CHAR8 *NodeStatus;
83 INT32 Len;
84
85 //
86 // A missing status property implies 'ok' so ignore any errors that
87 // may occur here. If the status property is present, check whether
88 // it is set to 'ok' or 'okay', anything else is treated as 'disabled'.
89 //
90 NodeStatus = FdtGetProp (mDeviceTreeBase, Node, "status", &Len);
91 if (NodeStatus == NULL) {
92 return TRUE;
93 }
94
95 if ((Len >= 5) && (AsciiStrCmp (NodeStatus, "okay") == 0)) {
96 return TRUE;
97 }
98
99 if ((Len >= 3) && (AsciiStrCmp (NodeStatus, "ok") == 0)) {
100 return TRUE;
101 }
102
103 return FALSE;
104}
105
106STATIC
108EFIAPI
109FindNextCompatibleNode (
111 IN CONST CHAR8 *CompatibleString,
112 IN INT32 PrevNode,
113 OUT INT32 *Node
114 )
115{
116 INT32 Prev, Next;
117 CONST CHAR8 *Type, *Compatible;
118 INT32 Len;
119
120 ASSERT (mDeviceTreeBase != NULL);
121 ASSERT (Node != NULL);
122
123 for (Prev = PrevNode; ; Prev = Next) {
124 Next = FdtNextNode (mDeviceTreeBase, Prev, NULL);
125 if (Next < 0) {
126 break;
127 }
128
129 if (!IsNodeEnabled (Next)) {
130 continue;
131 }
132
133 Type = FdtGetProp (mDeviceTreeBase, Next, "compatible", &Len);
134 if (Type == NULL) {
135 continue;
136 }
137
138 //
139 // A 'compatible' node may contain a sequence of NUL terminated
140 // compatible strings so check each one
141 //
142 for (Compatible = Type; Compatible < Type + Len && *Compatible;
143 Compatible += 1 + AsciiStrLen (Compatible))
144 {
145 if (AsciiStrCmp (CompatibleString, Compatible) == 0) {
146 *Node = Next;
147 return EFI_SUCCESS;
148 }
149 }
150 }
151
152 return EFI_NOT_FOUND;
153}
154
155STATIC
157EFIAPI
158FindCompatibleNode (
160 IN CONST CHAR8 *CompatibleString,
161 OUT INT32 *Node
162 )
163{
164 return FindNextCompatibleNode (This, CompatibleString, 0, Node);
165}
166
167STATIC
169EFIAPI
170FindCompatibleNodeProperty (
172 IN CONST CHAR8 *CompatibleString,
173 IN CONST CHAR8 *PropertyName,
174 OUT CONST VOID **Prop,
175 OUT UINT32 *PropSize OPTIONAL
176 )
177{
178 EFI_STATUS Status;
179 INT32 Node;
180
181 Status = FindCompatibleNode (This, CompatibleString, &Node);
182 if (EFI_ERROR (Status)) {
183 return Status;
184 }
185
186 return GetNodeProperty (This, Node, PropertyName, Prop, PropSize);
187}
188
189STATIC
191EFIAPI
192FindCompatibleNodeReg (
194 IN CONST CHAR8 *CompatibleString,
195 OUT CONST VOID **Reg,
196 OUT UINTN *AddressCells,
197 OUT UINTN *SizeCells,
198 OUT UINT32 *RegSize
199 )
200{
201 EFI_STATUS Status;
202
203 ASSERT (RegSize != NULL);
204
205 //
206 // Get the 'reg' property of this node. For now, we will assume
207 // 8 byte quantities for base and size, respectively.
208 // TODO use #cells root properties instead
209 //
210 Status = FindCompatibleNodeProperty (
211 This,
212 CompatibleString,
213 "reg",
214 Reg,
215 RegSize
216 );
217 if (EFI_ERROR (Status)) {
218 return Status;
219 }
220
221 if ((*RegSize % 16) != 0) {
222 DEBUG ((
223 DEBUG_ERROR,
224 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",
225 __func__,
226 CompatibleString,
227 *RegSize
228 ));
229 return EFI_NOT_FOUND;
230 }
231
232 *AddressCells = 2;
233 *SizeCells = 2;
234
235 return EFI_SUCCESS;
236}
237
238STATIC
240EFIAPI
241FindNextMemoryNodeReg (
243 IN INT32 PrevNode,
244 OUT INT32 *Node,
245 OUT CONST VOID **Reg,
246 OUT UINTN *AddressCells,
247 OUT UINTN *SizeCells,
248 OUT UINT32 *RegSize
249 )
250{
251 INT32 Prev, Next;
252 CONST CHAR8 *DeviceType;
253 INT32 Len;
254 EFI_STATUS Status;
255
256 ASSERT (mDeviceTreeBase != NULL);
257 ASSERT (Node != NULL);
258
259 for (Prev = PrevNode; ; Prev = Next) {
260 Next = FdtNextNode (mDeviceTreeBase, Prev, NULL);
261 if (Next < 0) {
262 break;
263 }
264
265 DeviceType = FdtGetProp (mDeviceTreeBase, Next, "device_type", &Len);
266 if ((DeviceType == NULL) || (AsciiStrCmp (DeviceType, "memory") != 0)) {
267 continue;
268 }
269
270 if (!IsNodeEnabled (Next)) {
271 DEBUG ((DEBUG_WARN, "%a: ignoring disabled memory node\n", __func__));
272 continue;
273 }
274
275 //
276 // Get the 'reg' property of this memory node. For now, we will assume
277 // 8 byte quantities for base and size, respectively.
278 // TODO use #cells root properties instead
279 //
280 Status = GetNodeProperty (This, Next, "reg", Reg, RegSize);
281 if (EFI_ERROR (Status)) {
282 DEBUG ((
283 DEBUG_WARN,
284 "%a: ignoring memory node with no 'reg' property\n",
285 __func__
286 ));
287 continue;
288 }
289
290 if ((*RegSize % 16) != 0) {
291 DEBUG ((
292 DEBUG_WARN,
293 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",
294 __func__,
295 *RegSize
296 ));
297 continue;
298 }
299
300 *Node = Next;
301 *AddressCells = 2;
302 *SizeCells = 2;
303 return EFI_SUCCESS;
304 }
305
306 return EFI_NOT_FOUND;
307}
308
309STATIC
311EFIAPI
312FindMemoryNodeReg (
314 OUT INT32 *Node,
315 OUT CONST VOID **Reg,
316 OUT UINTN *AddressCells,
317 OUT UINTN *SizeCells,
318 OUT UINT32 *RegSize
319 )
320{
321 return FindNextMemoryNodeReg (
322 This,
323 0,
324 Node,
325 Reg,
326 AddressCells,
327 SizeCells,
328 RegSize
329 );
330}
331
332STATIC
334EFIAPI
335GetOrInsertChosenNode (
337 OUT INT32 *Node
338 )
339{
340 INT32 NewNode;
341
342 ASSERT (mDeviceTreeBase != NULL);
343 ASSERT (Node != NULL);
344
345 NewNode = FdtPathOffset (mDeviceTreeBase, "/chosen");
346 if (NewNode < 0) {
347 NewNode = FdtAddSubnode (mDeviceTreeBase, 0, "/chosen");
348 }
349
350 if (NewNode < 0) {
351 return EFI_OUT_OF_RESOURCES;
352 }
353
354 *Node = NewNode;
355
356 return EFI_SUCCESS;
357}
358
359STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = {
360 GetNodeProperty,
361 SetNodeProperty,
362 FindCompatibleNode,
363 FindNextCompatibleNode,
364 FindCompatibleNodeProperty,
365 FindCompatibleNodeReg,
366 FindMemoryNodeReg,
367 FindNextMemoryNodeReg,
368 GetOrInsertChosenNode,
369};
370
371STATIC
372VOID
373EFIAPI
374OnPlatformHasDeviceTree (
375 IN EFI_EVENT Event,
376 IN VOID *Context
377 )
378{
379 EFI_STATUS Status;
380 VOID *Interface;
381 VOID *DeviceTreeBase;
382
383 Status = gBS->LocateProtocol (
384 &gEdkiiPlatformHasDeviceTreeGuid,
385 NULL, // Registration
386 &Interface
387 );
388 if (EFI_ERROR (Status)) {
389 return;
390 }
391
392 DeviceTreeBase = Context;
393 DEBUG ((
394 DEBUG_INFO,
395 "%a: exposing DTB @ 0x%p to OS\n",
396 __func__,
397 DeviceTreeBase
398 ));
399 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
400 ASSERT_EFI_ERROR (Status);
401
402 gBS->CloseEvent (Event);
403}
404
406EFIAPI
407InitializeFdtClientDxe (
408 IN EFI_HANDLE ImageHandle,
409 IN EFI_SYSTEM_TABLE *SystemTable
410 )
411{
412 VOID *Hob;
413 VOID *DeviceTreeBase;
414 EFI_STATUS Status;
415 EFI_EVENT PlatformHasDeviceTreeEvent;
416 VOID *Registration;
417
418 Hob = GetFirstGuidHob (&gFdtHobGuid);
419 if ((Hob == NULL) || (GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64))) {
420 return EFI_NOT_FOUND;
421 }
422
423 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
424
425 if (FdtCheckHeader (DeviceTreeBase) != 0) {
426 DEBUG ((
427 DEBUG_ERROR,
428 "%a: No DTB found @ 0x%p\n",
429 __func__,
430 DeviceTreeBase
431 ));
432 return EFI_NOT_FOUND;
433 }
434
435 mDeviceTreeBase = DeviceTreeBase;
436
437 DEBUG ((DEBUG_INFO, "%a: DTB @ 0x%p\n", __func__, mDeviceTreeBase));
438
439 //
440 // Register a protocol notify for the EDKII Platform Has Device Tree
441 // Protocol.
442 //
443 Status = gBS->CreateEvent (
444 EVT_NOTIFY_SIGNAL,
445 TPL_CALLBACK,
446 OnPlatformHasDeviceTree,
447 DeviceTreeBase, // Context
448 &PlatformHasDeviceTreeEvent
449 );
450 if (EFI_ERROR (Status)) {
451 DEBUG ((DEBUG_ERROR, "%a: CreateEvent(): %r\n", __func__, Status));
452 return Status;
453 }
454
455 Status = gBS->RegisterProtocolNotify (
456 &gEdkiiPlatformHasDeviceTreeGuid,
457 PlatformHasDeviceTreeEvent,
458 &Registration
459 );
460 if (EFI_ERROR (Status)) {
461 DEBUG ((
462 DEBUG_ERROR,
463 "%a: RegisterProtocolNotify(): %r\n",
464 __func__,
465 Status
466 ));
467 goto CloseEvent;
468 }
469
470 //
471 // Kick the event; the protocol could be available already.
472 //
473 Status = gBS->SignalEvent (PlatformHasDeviceTreeEvent);
474 if (EFI_ERROR (Status)) {
475 DEBUG ((DEBUG_ERROR, "%a: SignalEvent(): %r\n", __func__, Status));
476 goto CloseEvent;
477 }
478
479 Status = gBS->InstallProtocolInterface (
480 &ImageHandle,
481 &gFdtClientProtocolGuid,
483 &mFdtClientProtocol
484 );
485 if (EFI_ERROR (Status)) {
486 DEBUG ((
487 DEBUG_ERROR,
488 "%a: InstallProtocolInterface(): %r\n",
489 __func__,
490 Status
491 ));
492 goto CloseEvent;
493 }
494
495 return Status;
496
497CloseEvent:
498 gBS->CloseEvent (PlatformHasDeviceTreeEvent);
499 return Status;
500}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
INTN EFIAPI AsciiStrCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:716
INT32 EFIAPI FdtSetProp(IN VOID *Fdt, IN INT32 NodeOffset, IN CONST CHAR8 *Name, IN CONST VOID *Value, IN UINT32 Length)
Definition: FdtLib.c:661
INT32 EFIAPI FdtAddSubnode(IN VOID *Fdt, IN INT32 ParentOffset, IN CONST CHAR8 *Name)
Definition: FdtLib.c:619
INT32 EFIAPI FdtNextNode(IN CONST VOID *Fdt, IN INT32 Offset, IN INT32 *Depth)
Definition: FdtLib.c:220
INT32 EFIAPI FdtCheckHeader(IN CONST VOID *Fdt)
Definition: FdtLib.c:125
INT32 EFIAPI FdtPathOffset(IN CONST VOID *Fdt, IN CONST CHAR8 *Path)
Definition: FdtLib.c:777
CONST VOID *EFIAPI FdtGetProp(IN CONST VOID *Fdt, IN INT32 NodeOffset, IN CONST CHAR8 *Name, IN INT32 *Length)
Definition: FdtLib.c:495
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define VOID
Definition: Base.h:269
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:463
#define DEBUG(Expression)
Definition: DebugLib.h:435
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1203