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>
14#include <Library/HobLib.h>
15#include <libfdt.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 = fdt_getprop (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 = fdt_setprop (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 = fdt_getprop (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 = fdt_next_node (mDeviceTreeBase, Prev, NULL);
125 if (Next < 0) {
126 break;
127 }
128
129 if (!IsNodeEnabled (Next)) {
130 continue;
131 }
132
133 Type = fdt_getprop (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 = fdt_next_node (mDeviceTreeBase, Prev, NULL);
261 if (Next < 0) {
262 break;
263 }
264
265 if (!IsNodeEnabled (Next)) {
266 DEBUG ((DEBUG_WARN, "%a: ignoring disabled memory node\n", __func__));
267 continue;
268 }
269
270 DeviceType = fdt_getprop (mDeviceTreeBase, Next, "device_type", &Len);
271 if ((DeviceType != NULL) && (AsciiStrCmp (DeviceType, "memory") == 0)) {
272 //
273 // Get the 'reg' property of this memory node. For now, we will assume
274 // 8 byte quantities for base and size, respectively.
275 // TODO use #cells root properties instead
276 //
277 Status = GetNodeProperty (This, Next, "reg", Reg, RegSize);
278 if (EFI_ERROR (Status)) {
279 DEBUG ((
280 DEBUG_WARN,
281 "%a: ignoring memory node with no 'reg' property\n",
282 __func__
283 ));
284 continue;
285 }
286
287 if ((*RegSize % 16) != 0) {
288 DEBUG ((
289 DEBUG_WARN,
290 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",
291 __func__,
292 *RegSize
293 ));
294 continue;
295 }
296
297 *Node = Next;
298 *AddressCells = 2;
299 *SizeCells = 2;
300 return EFI_SUCCESS;
301 }
302 }
303
304 return EFI_NOT_FOUND;
305}
306
307STATIC
309EFIAPI
310FindMemoryNodeReg (
312 OUT INT32 *Node,
313 OUT CONST VOID **Reg,
314 OUT UINTN *AddressCells,
315 OUT UINTN *SizeCells,
316 OUT UINT32 *RegSize
317 )
318{
319 return FindNextMemoryNodeReg (
320 This,
321 0,
322 Node,
323 Reg,
324 AddressCells,
325 SizeCells,
326 RegSize
327 );
328}
329
330STATIC
332EFIAPI
333GetOrInsertChosenNode (
335 OUT INT32 *Node
336 )
337{
338 INT32 NewNode;
339
340 ASSERT (mDeviceTreeBase != NULL);
341 ASSERT (Node != NULL);
342
343 NewNode = fdt_path_offset (mDeviceTreeBase, "/chosen");
344 if (NewNode < 0) {
345 NewNode = fdt_add_subnode (mDeviceTreeBase, 0, "/chosen");
346 }
347
348 if (NewNode < 0) {
349 return EFI_OUT_OF_RESOURCES;
350 }
351
352 *Node = NewNode;
353
354 return EFI_SUCCESS;
355}
356
357STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = {
358 GetNodeProperty,
359 SetNodeProperty,
360 FindCompatibleNode,
361 FindNextCompatibleNode,
362 FindCompatibleNodeProperty,
363 FindCompatibleNodeReg,
364 FindMemoryNodeReg,
365 FindNextMemoryNodeReg,
366 GetOrInsertChosenNode,
367};
368
369STATIC
370VOID
371EFIAPI
372OnPlatformHasDeviceTree (
373 IN EFI_EVENT Event,
374 IN VOID *Context
375 )
376{
377 EFI_STATUS Status;
378 VOID *Interface;
379 VOID *DeviceTreeBase;
380
381 Status = gBS->LocateProtocol (
382 &gEdkiiPlatformHasDeviceTreeGuid,
383 NULL, // Registration
384 &Interface
385 );
386 if (EFI_ERROR (Status)) {
387 return;
388 }
389
390 DeviceTreeBase = Context;
391 DEBUG ((
392 DEBUG_INFO,
393 "%a: exposing DTB @ 0x%p to OS\n",
394 __func__,
395 DeviceTreeBase
396 ));
397 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
398 ASSERT_EFI_ERROR (Status);
399
400 gBS->CloseEvent (Event);
401}
402
404EFIAPI
405InitializeFdtClientDxe (
406 IN EFI_HANDLE ImageHandle,
407 IN EFI_SYSTEM_TABLE *SystemTable
408 )
409{
410 VOID *Hob;
411 VOID *DeviceTreeBase;
412 EFI_STATUS Status;
413 EFI_EVENT PlatformHasDeviceTreeEvent;
414 VOID *Registration;
415
416 Hob = GetFirstGuidHob (&gFdtHobGuid);
417 if ((Hob == NULL) || (GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64))) {
418 return EFI_NOT_FOUND;
419 }
420
421 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
422
423 if (fdt_check_header (DeviceTreeBase) != 0) {
424 DEBUG ((
425 DEBUG_ERROR,
426 "%a: No DTB found @ 0x%p\n",
427 __func__,
428 DeviceTreeBase
429 ));
430 return EFI_NOT_FOUND;
431 }
432
433 mDeviceTreeBase = DeviceTreeBase;
434
435 DEBUG ((DEBUG_INFO, "%a: DTB @ 0x%p\n", __func__, mDeviceTreeBase));
436
437 //
438 // Register a protocol notify for the EDKII Platform Has Device Tree
439 // Protocol.
440 //
441 Status = gBS->CreateEvent (
442 EVT_NOTIFY_SIGNAL,
443 TPL_CALLBACK,
444 OnPlatformHasDeviceTree,
445 DeviceTreeBase, // Context
446 &PlatformHasDeviceTreeEvent
447 );
448 if (EFI_ERROR (Status)) {
449 DEBUG ((DEBUG_ERROR, "%a: CreateEvent(): %r\n", __func__, Status));
450 return Status;
451 }
452
453 Status = gBS->RegisterProtocolNotify (
454 &gEdkiiPlatformHasDeviceTreeGuid,
455 PlatformHasDeviceTreeEvent,
456 &Registration
457 );
458 if (EFI_ERROR (Status)) {
459 DEBUG ((
460 DEBUG_ERROR,
461 "%a: RegisterProtocolNotify(): %r\n",
462 __func__,
463 Status
464 ));
465 goto CloseEvent;
466 }
467
468 //
469 // Kick the event; the protocol could be available already.
470 //
471 Status = gBS->SignalEvent (PlatformHasDeviceTreeEvent);
472 if (EFI_ERROR (Status)) {
473 DEBUG ((DEBUG_ERROR, "%a: SignalEvent(): %r\n", __func__, Status));
474 goto CloseEvent;
475 }
476
477 Status = gBS->InstallProtocolInterface (
478 &ImageHandle,
479 &gFdtClientProtocolGuid,
481 &mFdtClientProtocol
482 );
483 if (EFI_ERROR (Status)) {
484 DEBUG ((
485 DEBUG_ERROR,
486 "%a: InstallProtocolInterface(): %r\n",
487 __func__,
488 Status
489 ));
490 goto CloseEvent;
491 }
492
493 return Status;
494
495CloseEvent:
496 gBS->CloseEvent (PlatformHasDeviceTreeEvent);
497 return Status;
498}
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
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#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:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
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:1193