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