]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/BdsLib/BdsHelper.c
ArmPkg/BdsLib: Prevent a hang in BdsConnectDevicePath() when a sub-device path is...
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsHelper.c
CommitLineData
1e57a462 1/** @file\r
2*\r
c0b2e477 3* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
1e57a462 4*\r
c0b2e477 5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
1e57a462 12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
1e57a462 17#include <Library/HobLib.h>\r
18#include <Library/TimerLib.h>\r
19#include <Library/PrintLib.h>\r
20#include <Library/SerialPortLib.h>\r
21\r
22STATIC CHAR8 *mTokenList[] = {\r
23 /*"SEC",*/\r
24 "PEI",\r
25 "DXE",\r
26 "BDS",\r
27 NULL\r
28};\r
29\r
30EFI_STATUS\r
31ShutdownUefiBootServices (\r
32 VOID\r
33 )\r
34{\r
35 EFI_STATUS Status;\r
36 UINTN MemoryMapSize;\r
37 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
38 UINTN MapKey;\r
39 UINTN DescriptorSize;\r
40 UINT32 DescriptorVersion;\r
41 UINTN Pages;\r
42\r
43 MemoryMap = NULL;\r
44 MemoryMapSize = 0;\r
45 Pages = 0;\r
46\r
47 do {\r
48 Status = gBS->GetMemoryMap (\r
49 &MemoryMapSize,\r
50 MemoryMap,\r
51 &MapKey,\r
52 &DescriptorSize,\r
53 &DescriptorVersion\r
54 );\r
55 if (Status == EFI_BUFFER_TOO_SMALL) {\r
56\r
57 Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;\r
58 MemoryMap = AllocatePages (Pages);\r
59\r
60 //\r
61 // Get System MemoryMap\r
62 //\r
63 Status = gBS->GetMemoryMap (\r
64 &MemoryMapSize,\r
65 MemoryMap,\r
66 &MapKey,\r
67 &DescriptorSize,\r
68 &DescriptorVersion\r
69 );\r
70 }\r
71\r
72 // Don't do anything between the GetMemoryMap() and ExitBootServices()\r
73 if (!EFI_ERROR(Status)) {\r
74 Status = gBS->ExitBootServices (gImageHandle, MapKey);\r
75 if (EFI_ERROR(Status)) {\r
76 FreePages (MemoryMap, Pages);\r
77 MemoryMap = NULL;\r
78 MemoryMapSize = 0;\r
79 }\r
80 }\r
81 } while (EFI_ERROR(Status));\r
82\r
83 return Status;\r
84}\r
85\r
86/**\r
87 Connect all DXE drivers\r
88\r
89 @retval EFI_SUCCESS All drivers have been connected\r
90 @retval EFI_NOT_FOUND No handles match the search.\r
91 @retval EFI_OUT_OF_RESOURCES There is not resource pool memory to store the matching results.\r
92\r
93**/\r
94EFI_STATUS\r
95BdsConnectAllDrivers (\r
96 VOID\r
97 )\r
98{\r
99 UINTN HandleCount, Index;\r
100 EFI_HANDLE *HandleBuffer;\r
101 EFI_STATUS Status;\r
102\r
103 do {\r
104 // Locate all the driver handles\r
105 Status = gBS->LocateHandleBuffer (\r
106 AllHandles,\r
107 NULL,\r
108 NULL,\r
109 &HandleCount,\r
110 &HandleBuffer\r
111 );\r
112 if (EFI_ERROR (Status)) {\r
113 break;\r
114 }\r
115\r
116 // Connect every handles\r
117 for (Index = 0; Index < HandleCount; Index++) {\r
118 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);\r
119 }\r
120\r
121 if (HandleBuffer != NULL) {\r
122 FreePool (HandleBuffer);\r
123 }\r
124\r
125 // Check if new handles have been created after the start of the previous handles\r
126 Status = gDS->Dispatch ();\r
127 } while (!EFI_ERROR(Status));\r
128\r
129 return EFI_SUCCESS;\r
130}\r
131\r
132STATIC\r
133EFI_STATUS\r
134InsertSystemMemoryResources (\r
135 LIST_ENTRY *ResourceList,\r
136 EFI_HOB_RESOURCE_DESCRIPTOR *ResHob\r
137 )\r
138{\r
139 BDS_SYSTEM_MEMORY_RESOURCE *NewResource;\r
140 LIST_ENTRY *Link;\r
141 LIST_ENTRY *NextLink;\r
142 LIST_ENTRY AttachedResources;\r
143 BDS_SYSTEM_MEMORY_RESOURCE *Resource;\r
144 EFI_PHYSICAL_ADDRESS NewResourceEnd;\r
145\r
146 if (IsListEmpty (ResourceList)) {\r
147 NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));\r
148 NewResource->PhysicalStart = ResHob->PhysicalStart;\r
149 NewResource->ResourceLength = ResHob->ResourceLength;\r
150 InsertTailList (ResourceList, &NewResource->Link);\r
151 return EFI_SUCCESS;\r
152 }\r
153\r
154 InitializeListHead (&AttachedResources);\r
155\r
156 Link = ResourceList->ForwardLink;\r
157 ASSERT (Link != NULL);\r
158 while (Link != ResourceList) {\r
159 Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;\r
160\r
161 // Sanity Check. The resources should not overlapped.\r
162 ASSERT(!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))));\r
163 ASSERT(!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) &&\r
164 ((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength))));\r
165\r
166 // The new resource is attached after this resource descriptor\r
167 if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) {\r
168 Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;\r
169\r
170 NextLink = RemoveEntryList (&Resource->Link);\r
171 InsertTailList (&AttachedResources, &Resource->Link);\r
172 Link = NextLink;\r
173 }\r
174 // The new resource is attached before this resource descriptor\r
175 else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) {\r
176 Resource->PhysicalStart = ResHob->PhysicalStart;\r
177 Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength;\r
178\r
179 NextLink = RemoveEntryList (&Resource->Link);\r
180 InsertTailList (&AttachedResources, &Resource->Link);\r
181 Link = NextLink;\r
182 } else {\r
183 Link = Link->ForwardLink;\r
184 }\r
185 }\r
186\r
187 if (!IsListEmpty (&AttachedResources)) {\r
188 // See if we can merge the attached resource with other resources\r
189\r
190 NewResource = (BDS_SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources);\r
191 Link = RemoveEntryList (&NewResource->Link);\r
192 while (!IsListEmpty (&AttachedResources)) {\r
193 // Merge resources\r
194 Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link;\r
195\r
196 // Ensure they overlap each other\r
197 ASSERT(\r
198 ((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) ||\r
199 (((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength)))\r
200 );\r
201\r
202 NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength);\r
203 NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart);\r
204 NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart;\r
205\r
206 Link = RemoveEntryList (Link);\r
207 }\r
208 } else {\r
209 // None of the Resource of the list is attached to this ResHob. Create a new entry for it\r
210 NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE));\r
211 NewResource->PhysicalStart = ResHob->PhysicalStart;\r
212 NewResource->ResourceLength = ResHob->ResourceLength;\r
213 }\r
214 InsertTailList (ResourceList, &NewResource->Link);\r
215 return EFI_SUCCESS;\r
216}\r
217\r
218EFI_STATUS\r
219GetSystemMemoryResources (\r
220 IN LIST_ENTRY *ResourceList\r
221 )\r
222{\r
223 EFI_HOB_RESOURCE_DESCRIPTOR *ResHob;\r
224\r
225 InitializeListHead (ResourceList);\r
226\r
227 // Find the first System Memory Resource Descriptor\r
228 ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
229 while ((ResHob != NULL) && (ResHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)) {\r
230 ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));\r
231 }\r
232\r
233 // Did not find any\r
234 if (ResHob == NULL) {\r
235 return EFI_NOT_FOUND;\r
236 } else {\r
237 InsertSystemMemoryResources (ResourceList, ResHob);\r
238 }\r
239\r
240 ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));\r
241 while (ResHob != NULL) {\r
242 if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
243 InsertSystemMemoryResources (ResourceList, ResHob);\r
244 }\r
245 ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength));\r
246 }\r
247\r
248 return EFI_SUCCESS;\r
249}\r
250\r
251VOID\r
252PrintPerformance (\r
253 VOID\r
254 )\r
255{\r
256 UINTN Key;\r
257 CONST VOID *Handle;\r
258 CONST CHAR8 *Token, *Module;\r
259 UINT64 Start, Stop, TimeStamp;\r
260 UINT64 Delta, TicksPerSecond, Milliseconds;\r
261 UINTN Index;\r
262 CHAR8 Buffer[100];\r
263 UINTN CharCount;\r
264 BOOLEAN CountUp;\r
265\r
266 TicksPerSecond = GetPerformanceCounterProperties (&Start, &Stop);\r
267 if (Start < Stop) {\r
268 CountUp = TRUE;\r
269 } else {\r
270 CountUp = FALSE;\r
271 }\r
272\r
273 TimeStamp = 0;\r
274 Key = 0;\r
275 do {\r
276 Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop);\r
277 if (Key != 0) {\r
278 for (Index = 0; mTokenList[Index] != NULL; Index++) {\r
279 if (AsciiStriCmp (mTokenList[Index], Token) == 0) {\r
280 Delta = CountUp?(Stop - Start):(Start - Stop);\r
281 TimeStamp += Delta;\r
282 Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL);\r
283 CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"%6a %6ld ms\n", Token, Milliseconds);\r
284 SerialPortWrite ((UINT8 *) Buffer, CharCount);\r
285 break;\r
286 }\r
287 }\r
288 }\r
289 } while (Key != 0);\r
290\r
291 CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL));\r
292 SerialPortWrite ((UINT8 *) Buffer, CharCount);\r
293}\r
294\r
c0b2e477 295EFI_STATUS\r
296GetGlobalEnvironmentVariable (\r
297 IN CONST CHAR16* VariableName,\r
298 IN VOID* DefaultValue,\r
299 IN OUT UINTN* Size,\r
300 OUT VOID** Value\r
301 )\r
302{\r
303 return GetEnvironmentVariable (VariableName, &gEfiGlobalVariableGuid,\r
304 DefaultValue, Size, Value);\r
305}\r
306\r
1e57a462 307EFI_STATUS\r
308GetEnvironmentVariable (\r
309 IN CONST CHAR16* VariableName,\r
c0b2e477 310 IN EFI_GUID* VendorGuid,\r
1e57a462 311 IN VOID* DefaultValue,\r
312 IN OUT UINTN* Size,\r
313 OUT VOID** Value\r
314 )\r
315{\r
316 EFI_STATUS Status;\r
317 UINTN VariableSize;\r
318\r
319 // Try to get the variable size.\r
320 *Value = NULL;\r
321 VariableSize = 0;\r
c0b2e477 322 Status = gRT->GetVariable ((CHAR16 *) VariableName, VendorGuid, NULL, &VariableSize, *Value);\r
1e57a462 323 if (Status == EFI_NOT_FOUND) {\r
324 if ((DefaultValue != NULL) && (Size != NULL) && (*Size != 0)) {\r
325 // If the environment variable does not exist yet then set it with the default value\r
326 Status = gRT->SetVariable (\r
327 (CHAR16*)VariableName,\r
c0b2e477 328 VendorGuid,\r
1e57a462 329 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
330 *Size,\r
331 DefaultValue\r
332 );\r
d8dc9f0a 333 *Value = AllocateCopyPool (*Size, DefaultValue);\r
1e57a462 334 } else {\r
335 return EFI_NOT_FOUND;\r
336 }\r
337 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
338 // Get the environment variable value\r
339 *Value = AllocatePool (VariableSize);\r
340 if (*Value == NULL) {\r
341 return EFI_OUT_OF_RESOURCES;\r
342 }\r
343\r
c0b2e477 344 Status = gRT->GetVariable ((CHAR16 *)VariableName, VendorGuid, NULL, &VariableSize, *Value);\r
1e57a462 345 if (EFI_ERROR (Status)) {\r
346 FreePool(*Value);\r
347 return EFI_INVALID_PARAMETER;\r
348 }\r
349\r
350 if (Size) {\r
351 *Size = VariableSize;\r
352 }\r
353 } else {\r
d8dc9f0a 354 *Value = AllocateCopyPool (*Size, DefaultValue);\r
1e57a462 355 return Status;\r
356 }\r
357\r
358 return EFI_SUCCESS;\r
359}\r