e9245d2fb62a38af9d4c43a749bca320546d610f
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Dxe / PlatformBds / Generic / BootMaint / BmLib.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   BmLib.c\r
15     \r
16 AgBStract:\r
17 \r
18   Boot Maintainence Helper functions\r
19 \r
20 --*/\r
21 \r
22 #include "BootMaint.h"\r
23 \r
24 EFI_STATUS\r
25 EfiLibLocateProtocol (\r
26   IN  EFI_GUID    *ProtocolGuid,\r
27   OUT VOID        **Interface\r
28   )\r
29 /*++\r
30 \r
31 Routine Description:\r
32 \r
33   Find the first instance of this Protocol \r
34   in the system and return it's interface\r
35 \r
36 Arguments:\r
37 \r
38   ProtocolGuid    - Provides the protocol to search for\r
39   Interface       - On return, a pointer to the first interface \r
40                     that matches ProtocolGuid\r
41 \r
42 Returns:\r
43 \r
44   EFI_SUCCESS     - A protocol instance matching ProtocolGuid was found\r
45 \r
46   EFI_NOT_FOUND   - No protocol instances were found that match ProtocolGuid\r
47 \r
48 --*/\r
49 {\r
50   EFI_STATUS  Status;\r
51 \r
52   Status = gBS->LocateProtocol (\r
53                   ProtocolGuid,\r
54                   NULL,\r
55                   Interface\r
56                   );\r
57   return Status;\r
58 }\r
59 \r
60 EFI_FILE_HANDLE\r
61 EfiLibOpenRoot (\r
62   IN EFI_HANDLE                   DeviceHandle\r
63   )\r
64 /*++\r
65 \r
66 Routine Description:\r
67 \r
68   Function opens and returns a file handle to the root directory of a volume.\r
69 \r
70 Arguments:\r
71 \r
72   DeviceHandle         - A handle for a device\r
73 \r
74 Returns:\r
75   \r
76   A valid file handle or NULL is returned\r
77 \r
78 --*/\r
79 {\r
80   EFI_STATUS                      Status;\r
81   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
82   EFI_FILE_HANDLE                 File;\r
83 \r
84   File = NULL;\r
85 \r
86   //\r
87   // File the file system interface to the device\r
88   //\r
89   Status = gBS->HandleProtocol (\r
90                   DeviceHandle,\r
91                   &gEfiSimpleFileSystemProtocolGuid,\r
92                   (VOID *) &Volume\r
93                   );\r
94 \r
95   //\r
96   // Open the root directory of the volume\r
97   //\r
98   if (!EFI_ERROR (Status)) {\r
99     Status = Volume->OpenVolume (\r
100                       Volume,\r
101                       &File\r
102                       );\r
103   }\r
104   //\r
105   // Done\r
106   //\r
107   return EFI_ERROR (Status) ? NULL : File;\r
108 }\r
109 \r
110 BOOLEAN\r
111 EfiGrowBuffer (\r
112   IN OUT EFI_STATUS   *Status,\r
113   IN OUT VOID         **Buffer,\r
114   IN UINTN            BufferSize\r
115   )\r
116 /*++\r
117 \r
118 Routine Description:\r
119 \r
120     Helper function called as part of the code needed\r
121     to allocate the proper sized buffer for various \r
122     EFI interfaces.\r
123 \r
124 Arguments:\r
125 \r
126     Status      - Current status\r
127 \r
128     Buffer      - Current allocated buffer, or NULL\r
129 \r
130     BufferSize  - Current buffer size needed\r
131     \r
132 Returns:\r
133     \r
134     TRUE - if the buffer was reallocated and the caller \r
135     should try the API again.\r
136 \r
137 --*/\r
138 {\r
139   BOOLEAN TryAgain;\r
140 \r
141   //\r
142   // If this is an initial request, buffer will be null with a new buffer size\r
143   //\r
144   if (!*Buffer && BufferSize) {\r
145     *Status = EFI_BUFFER_TOO_SMALL;\r
146   }\r
147   //\r
148   // If the status code is "buffer too small", resize the buffer\r
149   //\r
150   TryAgain = FALSE;\r
151   if (*Status == EFI_BUFFER_TOO_SMALL) {\r
152 \r
153     SafeFreePool (*Buffer);\r
154 \r
155     *Buffer = AllocateZeroPool (BufferSize);\r
156 \r
157     if (*Buffer) {\r
158       TryAgain = TRUE;\r
159     } else {\r
160       *Status = EFI_OUT_OF_RESOURCES;\r
161     }\r
162   }\r
163   //\r
164   // If there's an error, free the buffer\r
165   //\r
166   if (!TryAgain && EFI_ERROR (*Status) && *Buffer) {\r
167     SafeFreePool (*Buffer);\r
168     *Buffer = NULL;\r
169   }\r
170 \r
171   return TryAgain;\r
172 }\r
173 \r
174 VOID *\r
175 EfiLibGetVariable (\r
176   IN CHAR16               *Name,\r
177   IN EFI_GUID             *VendorGuid\r
178   )\r
179 /*++\r
180 \r
181 Routine Description:\r
182   Function returns the value of the specified variable.\r
183 \r
184 Arguments:\r
185   Name                - A Null-terminated Unicode string that is \r
186                         the name of the vendor's variable.\r
187 \r
188   VendorGuid          - A unique identifier for the vendor.\r
189 \r
190 Returns:\r
191 \r
192   None\r
193 \r
194 --*/\r
195 {\r
196   UINTN VarSize;\r
197 \r
198   return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);\r
199 }\r
200 \r
201 EFI_STATUS\r
202 EfiLibDeleteVariable (\r
203   IN CHAR16   *VarName,\r
204   IN EFI_GUID *VarGuid\r
205   )\r
206 /*++\r
207 \r
208 Routine Description:\r
209   Function deletes the variable specified by VarName and VarGuid.\r
210 \r
211 Arguments:\r
212   VarName              - A Null-terminated Unicode string that is \r
213                          the name of the vendor's variable.\r
214 \r
215   VendorGuid           - A unique identifier for the vendor.\r
216 \r
217 Returns:\r
218 \r
219   EFI_SUCCESS          - The variable was found and removed\r
220 \r
221   EFI_UNSUPPORTED      - The variable store was inaccessible\r
222 \r
223   EFI_OUT_OF_RESOURCES - The temporary buffer was not available\r
224 \r
225   EFI_NOT_FOUND        - The variable was not found\r
226 \r
227 --*/\r
228 {\r
229   VOID        *VarBuf;\r
230   EFI_STATUS  Status;\r
231 \r
232   VarBuf  = EfiLibGetVariable (VarName, VarGuid);\r
233   Status  = EFI_NOT_FOUND;\r
234 \r
235   if (VarBuf) {\r
236     //\r
237     // Delete variable from Storage\r
238     //\r
239     Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL);\r
240     ASSERT (!EFI_ERROR (Status));\r
241     SafeFreePool (VarBuf);\r
242   }\r
243 \r
244   return Status;\r
245 }\r
246 \r
247 EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *\r
248 EfiLibFileSystemVolumeLabelInfo (\r
249   IN EFI_FILE_HANDLE      FHand\r
250   )\r
251 /*++\r
252 \r
253 Routine Description:\r
254 \r
255   Function gets the file system information from an open file descriptor, \r
256   and stores it in a buffer allocated from pool.\r
257 \r
258 Arguments:\r
259 \r
260   Fhand         - A file handle\r
261 \r
262 Returns:\r
263   \r
264   A pointer to a buffer with file information or NULL is returned\r
265 \r
266 --*/\r
267 {\r
268   EFI_STATUS                        Status;\r
269   EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Buffer;\r
270   UINTN                             BufferSize;\r
271   //\r
272   // Initialize for GrowBuffer loop\r
273   //\r
274   Buffer      = NULL;\r
275   BufferSize  = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 200;\r
276 \r
277   //\r
278   // Call the real function\r
279   //\r
280   while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {\r
281     Status = FHand->GetInfo (\r
282                       FHand,\r
283                       &gEfiFileSystemVolumeLabelInfoIdGuid,\r
284                       &BufferSize,\r
285                       Buffer\r
286                       );\r
287   }\r
288 \r
289   return Buffer;\r
290 }\r
291 \r
292 CHAR16 *\r
293 EfiStrDuplicate (\r
294   IN CHAR16   *Src\r
295   )\r
296 {\r
297   CHAR16  *Dest;\r
298   UINTN   Size;\r
299 \r
300   Size  = StrSize (Src);\r
301   Dest  = AllocateZeroPool (Size);\r
302   ASSERT (Dest != NULL);\r
303   if (Dest) {\r
304     CopyMem (Dest, Src, Size);\r
305   }\r
306 \r
307   return Dest;\r
308 }\r
309 \r
310 EFI_FILE_INFO *\r
311 EfiLibFileInfo (\r
312   IN EFI_FILE_HANDLE      FHand\r
313   )\r
314 /*++\r
315 \r
316 Routine Description:\r
317 \r
318   Function gets the file information from an open file descriptor, and stores it \r
319   in a buffer allocated from pool.\r
320 \r
321 Arguments:\r
322 \r
323   Fhand         - A file handle\r
324 \r
325 Returns:\r
326   \r
327   A pointer to a buffer with file information or NULL is returned\r
328 \r
329 --*/\r
330 {\r
331   EFI_STATUS    Status;\r
332   EFI_FILE_INFO *Buffer;\r
333   UINTN         BufferSize;\r
334 \r
335   //\r
336   // Initialize for GrowBuffer loop\r
337   //\r
338   Buffer      = NULL;\r
339   BufferSize  = SIZE_OF_EFI_FILE_INFO + 200;\r
340 \r
341   //\r
342   // Call the real function\r
343   //\r
344   while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {\r
345     Status = FHand->GetInfo (\r
346                       FHand,\r
347                       &gEfiFileInfoGuid,\r
348                       &BufferSize,\r
349                       Buffer\r
350                       );\r
351   }\r
352 \r
353   return Buffer;\r
354 }\r
355 \r
356 UINTN\r
357 EfiDevicePathInstanceCount (\r
358   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath\r
359   )\r
360 /*++\r
361 \r
362 Routine Description:\r
363   Function is used to determine the number of device path instances \r
364   that exist in a device path.\r
365 \r
366 Arguments:\r
367   DevicePath           - A pointer to a device path data structure.\r
368 \r
369 Returns:\r
370 \r
371   This function counts and returns the number of device path instances \r
372   in DevicePath.\r
373 \r
374 --*/\r
375 {\r
376   UINTN Count;\r
377   UINTN Size;\r
378 \r
379   Count = 0;\r
380   while (GetNextDevicePathInstance (&DevicePath, &Size)) {\r
381     Count += 1;\r
382   }\r
383 \r
384   return Count;\r
385 }\r
386 \r
387 VOID *\r
388 EfiReallocatePool (\r
389   IN VOID                 *OldPool,\r
390   IN UINTN                OldSize,\r
391   IN UINTN                NewSize\r
392   )\r
393 /*++\r
394 \r
395 Routine Description:\r
396   Adjusts the size of a previously allocated buffer.\r
397 \r
398 Arguments:\r
399   OldPool               - A pointer to the buffer whose size is being adjusted.\r
400   OldSize               - The size of the current buffer.\r
401   NewSize               - The size of the new buffer.\r
402 \r
403 Returns:\r
404 \r
405   EFI_SUCEESS           - The requested number of bytes were allocated.\r
406 \r
407   EFI_OUT_OF_RESOURCES  - The pool requested could not be allocated.\r
408 \r
409   EFI_INVALID_PARAMETER - The buffer was invalid.\r
410 \r
411 --*/\r
412 {\r
413   VOID  *NewPool;\r
414 \r
415   NewPool = NULL;\r
416   if (NewSize) {\r
417     NewPool = AllocateZeroPool (NewSize);\r
418   }\r
419 \r
420   if (OldPool) {\r
421     if (NewPool) {\r
422       CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);\r
423     }\r
424 \r
425     SafeFreePool (OldPool);\r
426   }\r
427 \r
428   return NewPool;\r
429 }\r
430 \r
431 EFI_STATUS\r
432 EfiLibGetStringFromToken (\r
433   IN      EFI_GUID                  *ProducerGuid,\r
434   IN      STRING_REF                Token,\r
435   OUT     CHAR16                    **String\r
436   )\r
437 /*++\r
438 \r
439 Routine Description:\r
440   \r
441   Acquire the string associated with the ProducerGuid and return it.\r
442 \r
443 Arguments:\r
444   \r
445   ProducerGuid - The Guid to search the HII database for\r
446   Token        - The token value of the string to extract\r
447   String       - The string that is extracted\r
448   \r
449 Returns:\r
450 \r
451   EFI_SUCCESS           -  Buffer filled with the requested forms. BufferLength\r
452                            was updated.\r
453   EFI_BUFFER_TOO_SMALL  -  The buffer provided was not large enough to allow the form to be stored.\r
454 \r
455 --*/\r
456 {\r
457   EFI_STATUS        Status;\r
458   UINT16            HandleBufferLength;\r
459   EFI_HII_HANDLE    *HiiHandleBuffer;\r
460   UINTN             StringBufferLength;\r
461   UINTN             NumberOfHiiHandles;\r
462   UINTN             Index;\r
463   UINT16            Length;\r
464   EFI_GUID          HiiGuid;\r
465   EFI_HII_PROTOCOL  *Hii;\r
466 \r
467   //\r
468   // Initialize params.\r
469   //\r
470   HandleBufferLength  = 0;\r
471   HiiHandleBuffer     = NULL;\r
472   \r
473   Status = gBS->LocateProtocol (\r
474                   &gEfiHiiProtocolGuid,\r
475                   NULL,\r
476                   (VOID**) &Hii\r
477                   );\r
478   if (EFI_ERROR (Status)) {\r
479     *String = NULL;\r
480     return Status;\r
481   }\r
482   //\r
483   // Get all the Hii handles\r
484   //\r
485   Status = BdsLibGetHiiHandles (Hii, &HandleBufferLength, &HiiHandleBuffer);\r
486   ASSERT_EFI_ERROR (Status);\r
487   \r
488   //\r
489   // Get the Hii Handle that matches the StructureNode->ProducerName\r
490   //\r
491   NumberOfHiiHandles = HandleBufferLength / sizeof (EFI_HII_HANDLE);\r
492   for (Index = 0; Index < NumberOfHiiHandles; Index++) {\r
493     Length = 0;\r
494     Status = ExtractDataFromHiiHandle (\r
495               HiiHandleBuffer[Index],\r
496               &Length,\r
497               NULL,\r
498               &HiiGuid\r
499               );\r
500     if (CompareGuid (ProducerGuid, &HiiGuid)) {\r
501       break;\r
502     }\r
503   }\r
504   //\r
505   // Find the string based on the current language\r
506   //\r
507   StringBufferLength  = 0x100;\r
508   *String             = AllocateZeroPool (0x100);\r
509   ASSERT (*String != NULL);\r
510 \r
511   Status = Hii->GetString (\r
512                   Hii,\r
513                   HiiHandleBuffer[Index],\r
514                   Token,\r
515                   FALSE,\r
516                   NULL,\r
517                   &StringBufferLength,\r
518                   *String\r
519                   );\r
520 \r
521   gBS->FreePool (HiiHandleBuffer);\r
522 \r
523   return Status;\r
524 }\r
525 \r
526 BOOLEAN\r
527 TimeCompare (\r
528   IN EFI_TIME               *FirstTime,\r
529   IN EFI_TIME               *SecondTime\r
530   )\r
531 /*++\r
532 \r
533 Routine Description:\r
534   Compare two EFI_TIME data.\r
535 \r
536 Arguments:\r
537 \r
538   FirstTime         - A pointer to the first EFI_TIME data.\r
539   SecondTime        - A pointer to the second EFI_TIME data.\r
540 \r
541 Returns:\r
542   TRUE              The FirstTime is not later than the SecondTime.\r
543   FALSE             The FirstTime is later than the SecondTime.\r
544   \r
545 --*/\r
546 {\r
547   if (FirstTime->Year != SecondTime->Year) {\r
548     return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
549   } else if (FirstTime->Month != SecondTime->Month) {\r
550     return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
551   } else if (FirstTime->Day != SecondTime->Day) {\r
552     return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
553   } else if (FirstTime->Hour != SecondTime->Hour) {\r
554     return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
555   } else if (FirstTime->Minute != SecondTime->Minute) {\r
556     return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
557   } else if (FirstTime->Second != SecondTime->Second) {\r
558     return (BOOLEAN) (FirstTime->Second < SecondTime->Second);\r
559   }\r
560 \r
561   return (BOOLEAN) (FirstTime->Nanosecond <= SecondTime->Nanosecond);\r
562 }\r
563 \r
564 UINT16 *\r
565 EfiLibStrFromDatahub (\r
566   IN EFI_DEVICE_PATH_PROTOCOL                 *DevPath\r
567   )\r
568 {\r
569   EFI_STATUS                                  Status;\r
570   UINT16                                      *Desc;\r
571   EFI_DATA_HUB_PROTOCOL                       *Datahub;\r
572   UINT64                                      Count;\r
573   EFI_DATA_RECORD_HEADER                      *Record;\r
574   EFI_SUBCLASS_TYPE1_HEADER                   *DataHdr;\r
575   EFI_GUID                                    MiscGuid = EFI_MISC_SUBCLASS_GUID;\r
576   EFI_MISC_ONBOARD_DEVICE_DATA                *ob;\r
577   EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *Port;\r
578   EFI_TIME                                    CurTime;\r
579 \r
580   Status = gBS->LocateProtocol (\r
581                   &gEfiDataHubProtocolGuid,\r
582                   NULL,\r
583                   (VOID**) &Datahub\r
584                   );\r
585   if (EFI_ERROR (Status)) {\r
586     return NULL;\r
587   }\r
588 \r
589   Status = gRT->GetTime (&CurTime, NULL);\r
590   if (EFI_ERROR (Status)) {\r
591     return NULL;\r
592   }\r
593 \r
594   Count = 0;\r
595   do {\r
596     Status = Datahub->GetNextRecord (Datahub, &Count, NULL, &Record);\r
597 \r
598     if (EFI_ERROR (Status)) {\r
599       break;\r
600     }\r
601 \r
602     if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA && CompareGuid (&Record->DataRecordGuid, &MiscGuid)) {\r
603       //\r
604       // This record is what we need\r
605       //\r
606       DataHdr = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);\r
607       if (EFI_MISC_ONBOARD_DEVICE_RECORD_NUMBER == DataHdr->RecordType) {\r
608         ob = (EFI_MISC_ONBOARD_DEVICE_DATA *) (DataHdr + 1);\r
609         if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &ob->OnBoardDevicePath, DevPath)) {\r
610           EfiLibGetStringFromToken (&Record->ProducerName, ob->OnBoardDeviceDescription, &Desc);\r
611           return Desc;\r
612         }\r
613       }\r
614 \r
615       if (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_RECORD_NUMBER == DataHdr->RecordType) {\r
616         Port = (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) (DataHdr + 1);\r
617         if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &Port->PortPath, DevPath)) {\r
618           EfiLibGetStringFromToken (&Record->ProducerName, Port->PortExternalConnectorDesignator, &Desc);\r
619           return Desc;\r
620         }\r
621       }\r
622     }\r
623 \r
624   } while (TimeCompare (&Record->LogTime, &CurTime) && Count != 0);\r
625 \r
626   return NULL;\r
627 }\r