ArmVirtPkg/FdtClientDxe: supplement missing EFIAPI calling conv specifiers
[mirror_edk2.git] / ArmVirtPkg / FdtClientDxe / FdtClientDxe.c
1 /** @file
2 * FDT client driver
3 *
4 * Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
5 *
6 * This program and the accompanying materials are
7 * licensed and made available under the terms and conditions of the BSD License
8 * which accompanies this distribution. The full text of the license may be found at
9 * http://opensource.org/licenses/bsd-license.php
10 *
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/UefiDriverEntryPoint.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/HobLib.h>
21 #include <libfdt.h>
22
23 #include <Guid/Fdt.h>
24 #include <Guid/FdtHob.h>
25
26 #include <Protocol/FdtClient.h>
27
28 STATIC VOID *mDeviceTreeBase;
29
30 STATIC
31 EFI_STATUS
32 EFIAPI
33 GetNodeProperty (
34 IN FDT_CLIENT_PROTOCOL *This,
35 IN INT32 Node,
36 IN CONST CHAR8 *PropertyName,
37 OUT CONST VOID **Prop,
38 OUT UINT32 *PropSize OPTIONAL
39 )
40 {
41 INT32 Len;
42
43 ASSERT (mDeviceTreeBase != NULL);
44 ASSERT (Prop != NULL);
45
46 *Prop = fdt_getprop (mDeviceTreeBase, Node, PropertyName, &Len);
47 if (*Prop == NULL) {
48 return EFI_NOT_FOUND;
49 }
50
51 if (PropSize != NULL) {
52 *PropSize = Len;
53 }
54 return EFI_SUCCESS;
55 }
56
57 STATIC
58 EFI_STATUS
59 EFIAPI
60 SetNodeProperty (
61 IN FDT_CLIENT_PROTOCOL *This,
62 IN INT32 Node,
63 IN CONST CHAR8 *PropertyName,
64 IN CONST VOID *Prop,
65 IN UINT32 PropSize
66 )
67 {
68 INT32 Ret;
69
70 ASSERT (mDeviceTreeBase != NULL);
71
72 Ret = fdt_setprop (mDeviceTreeBase, Node, PropertyName, Prop, PropSize);
73 if (Ret != 0) {
74 return EFI_DEVICE_ERROR;
75 }
76
77 return EFI_SUCCESS;
78 }
79
80 STATIC
81 EFI_STATUS
82 EFIAPI
83 FindNextCompatibleNode (
84 IN FDT_CLIENT_PROTOCOL *This,
85 IN CONST CHAR8 *CompatibleString,
86 IN INT32 PrevNode,
87 OUT INT32 *Node
88 )
89 {
90 INT32 Prev, Next;
91 CONST CHAR8 *Type, *Compatible;
92 INT32 Len;
93
94 ASSERT (mDeviceTreeBase != NULL);
95 ASSERT (Node != NULL);
96
97 for (Prev = PrevNode;; Prev = Next) {
98 Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);
99 if (Next < 0) {
100 break;
101 }
102
103 Type = fdt_getprop (mDeviceTreeBase, Next, "compatible", &Len);
104 if (Type == NULL) {
105 continue;
106 }
107
108 //
109 // A 'compatible' node may contain a sequence of NUL terminated
110 // compatible strings so check each one
111 //
112 for (Compatible = Type; Compatible < Type + Len && *Compatible;
113 Compatible += 1 + AsciiStrLen (Compatible)) {
114 if (AsciiStrCmp (CompatibleString, Compatible) == 0) {
115 *Node = Next;
116 return EFI_SUCCESS;
117 }
118 }
119 }
120 return EFI_NOT_FOUND;
121 }
122
123 STATIC
124 EFI_STATUS
125 EFIAPI
126 FindCompatibleNode (
127 IN FDT_CLIENT_PROTOCOL *This,
128 IN CONST CHAR8 *CompatibleString,
129 OUT INT32 *Node
130 )
131 {
132 return FindNextCompatibleNode (This, CompatibleString, 0, Node);
133 }
134
135 STATIC
136 EFI_STATUS
137 EFIAPI
138 FindCompatibleNodeProperty (
139 IN FDT_CLIENT_PROTOCOL *This,
140 IN CONST CHAR8 *CompatibleString,
141 IN CONST CHAR8 *PropertyName,
142 OUT CONST VOID **Prop,
143 OUT UINT32 *PropSize OPTIONAL
144 )
145 {
146 EFI_STATUS Status;
147 INT32 Node;
148
149 Status = FindCompatibleNode (This, CompatibleString, &Node);
150 if (EFI_ERROR (Status)) {
151 return Status;
152 }
153
154 return GetNodeProperty (This, Node, PropertyName, Prop, PropSize);
155 }
156
157 STATIC
158 EFI_STATUS
159 EFIAPI
160 FindCompatibleNodeReg (
161 IN FDT_CLIENT_PROTOCOL *This,
162 IN CONST CHAR8 *CompatibleString,
163 OUT CONST VOID **Reg,
164 OUT UINTN *AddressCells,
165 OUT UINTN *SizeCells,
166 OUT UINT32 *RegSize
167 )
168 {
169 EFI_STATUS Status;
170
171 ASSERT (RegSize != NULL);
172
173 //
174 // Get the 'reg' property of this node. For now, we will assume
175 // 8 byte quantities for base and size, respectively.
176 // TODO use #cells root properties instead
177 //
178 Status = FindCompatibleNodeProperty (This, CompatibleString, "reg", Reg,
179 RegSize);
180 if (EFI_ERROR (Status)) {
181 return Status;
182 }
183
184 if ((*RegSize % 16) != 0) {
185 DEBUG ((EFI_D_ERROR,
186 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",
187 __FUNCTION__, CompatibleString, *RegSize));
188 return EFI_NOT_FOUND;
189 }
190
191 *AddressCells = 2;
192 *SizeCells = 2;
193
194 return EFI_SUCCESS;
195 }
196
197 STATIC
198 EFI_STATUS
199 EFIAPI
200 FindNextMemoryNodeReg (
201 IN FDT_CLIENT_PROTOCOL *This,
202 IN INT32 PrevNode,
203 OUT INT32 *Node,
204 OUT CONST VOID **Reg,
205 OUT UINTN *AddressCells,
206 OUT UINTN *SizeCells,
207 OUT UINT32 *RegSize
208 )
209 {
210 INT32 Prev, Next;
211 CONST CHAR8 *DeviceType;
212 INT32 Len;
213 EFI_STATUS Status;
214
215 ASSERT (mDeviceTreeBase != NULL);
216 ASSERT (Node != NULL);
217
218 for (Prev = PrevNode;; Prev = Next) {
219 Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);
220 if (Next < 0) {
221 break;
222 }
223
224 DeviceType = fdt_getprop (mDeviceTreeBase, Next, "device_type", &Len);
225 if (DeviceType != NULL && AsciiStrCmp (DeviceType, "memory") == 0) {
226 //
227 // Get the 'reg' property of this memory node. For now, we will assume
228 // 8 byte quantities for base and size, respectively.
229 // TODO use #cells root properties instead
230 //
231 Status = GetNodeProperty (This, Next, "reg", Reg, RegSize);
232 if (EFI_ERROR (Status)) {
233 DEBUG ((EFI_D_WARN,
234 "%a: ignoring memory node with no 'reg' property\n",
235 __FUNCTION__));
236 continue;
237 }
238 if ((*RegSize % 16) != 0) {
239 DEBUG ((EFI_D_WARN,
240 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",
241 __FUNCTION__, *RegSize));
242 continue;
243 }
244
245 *Node = Next;
246 *AddressCells = 2;
247 *SizeCells = 2;
248 return EFI_SUCCESS;
249 }
250 }
251 return EFI_NOT_FOUND;
252 }
253
254 STATIC
255 EFI_STATUS
256 EFIAPI
257 FindMemoryNodeReg (
258 IN FDT_CLIENT_PROTOCOL *This,
259 OUT INT32 *Node,
260 OUT CONST VOID **Reg,
261 OUT UINTN *AddressCells,
262 OUT UINTN *SizeCells,
263 OUT UINT32 *RegSize
264 )
265 {
266 return FindNextMemoryNodeReg (This, 0, Node, Reg, AddressCells, SizeCells,
267 RegSize);
268 }
269
270 STATIC
271 EFI_STATUS
272 EFIAPI
273 GetOrInsertChosenNode (
274 IN FDT_CLIENT_PROTOCOL *This,
275 OUT INT32 *Node
276 )
277 {
278 INT32 NewNode;
279
280 ASSERT (mDeviceTreeBase != NULL);
281 ASSERT (Node != NULL);
282
283 NewNode = fdt_path_offset (mDeviceTreeBase, "/chosen");
284 if (NewNode < 0) {
285 NewNode = fdt_add_subnode (mDeviceTreeBase, 0, "/chosen");
286 }
287
288 if (NewNode < 0) {
289 return EFI_OUT_OF_RESOURCES;
290 }
291
292 *Node = NewNode;
293
294 return EFI_SUCCESS;
295 }
296
297 STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = {
298 GetNodeProperty,
299 SetNodeProperty,
300 FindCompatibleNode,
301 FindNextCompatibleNode,
302 FindCompatibleNodeProperty,
303 FindCompatibleNodeReg,
304 FindMemoryNodeReg,
305 FindNextMemoryNodeReg,
306 GetOrInsertChosenNode,
307 };
308
309 EFI_STATUS
310 EFIAPI
311 InitializeFdtClientDxe (
312 IN EFI_HANDLE ImageHandle,
313 IN EFI_SYSTEM_TABLE *SystemTable
314 )
315 {
316 VOID *Hob;
317 VOID *DeviceTreeBase;
318 EFI_STATUS Status;
319
320 Hob = GetFirstGuidHob (&gFdtHobGuid);
321 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
322 return EFI_NOT_FOUND;
323 }
324 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
325
326 if (fdt_check_header (DeviceTreeBase) != 0) {
327 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__,
328 DeviceTreeBase));
329 return EFI_NOT_FOUND;
330 }
331
332 mDeviceTreeBase = DeviceTreeBase;
333
334 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, mDeviceTreeBase));
335
336 if (!FeaturePcdGet (PcdPureAcpiBoot)) {
337 //
338 // Only install the FDT as a configuration table if we want to leave it up
339 // to the OS to decide whether it prefers ACPI over DT.
340 //
341 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
342 ASSERT_EFI_ERROR (Status);
343 }
344
345 return gBS->InstallProtocolInterface (&ImageHandle, &gFdtClientProtocolGuid,
346 EFI_NATIVE_INTERFACE, &mFdtClientProtocol);
347 }