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