]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BootMaint/BmLib.c
d5c32c8ac193dc3f212ea62fc0b5d4630d0e0f5a
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BootMaint / BmLib.c
1 /** @file
2 Utility routines used by boot maintenance modules.
3
4 Copyright (c) 2004 - 2008, Intel Corporation. <BR>
5 All rights reserved. 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 "BootMaint.h"
16
17 /**
18 Wrap original AllocatePool gBS call
19 and ZeroMem gBS call into a single
20 function in order to decrease code length
21
22
23 @param Size The size to allocate
24
25 @return Valid pointer to the allocated buffer
26 @retval Null for failure
27
28 **/
29 VOID *
30 EfiAllocateZeroPool (
31 IN UINTN Size
32 )
33 {
34 EFI_STATUS Status;
35 VOID *Ptr;
36 Status = gBS->AllocatePool (EfiBootServicesData, Size, &Ptr);
37 if (EFI_ERROR (Status)) {
38 Ptr = NULL;
39 return Ptr;
40 }
41
42 ZeroMem (Ptr, Size);
43 return Ptr;
44 }
45
46 /**
47
48 Find the first instance of this Protocol
49 in the system and return it's interface
50
51
52 @param ProtocolGuid - Provides the protocol to search for
53 @param Interface - On return, a pointer to the first interface
54 that matches ProtocolGuid
55
56 @retval EFI_SUCCESS A protocol instance matching ProtocolGuid was found
57 @retval EFI_NOT_FOUND No protocol instances were found that match ProtocolGuid
58
59 **/
60 EFI_STATUS
61 EfiLibLocateProtocol (
62 IN EFI_GUID *ProtocolGuid,
63 OUT VOID **Interface
64 )
65 {
66 EFI_STATUS Status;
67
68 Status = gBS->LocateProtocol (
69 ProtocolGuid,
70 NULL,
71 (VOID **) Interface
72 );
73 return Status;
74 }
75
76 /**
77
78 Function opens and returns a file handle to the root directory of a volume.
79
80
81 @param DeviceHandle - A handle for a device
82
83 @return A valid file handle or NULL is returned
84
85 **/
86 EFI_FILE_HANDLE
87 EfiLibOpenRoot (
88 IN EFI_HANDLE DeviceHandle
89 )
90 {
91 EFI_STATUS Status;
92 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
93 EFI_FILE_HANDLE File;
94
95 File = NULL;
96
97 //
98 // File the file system interface to the device
99 //
100 Status = gBS->HandleProtocol (
101 DeviceHandle,
102 &gEfiSimpleFileSystemProtocolGuid,
103 (VOID *) &Volume
104 );
105
106 //
107 // Open the root directory of the volume
108 //
109 if (!EFI_ERROR (Status)) {
110 Status = Volume->OpenVolume (
111 Volume,
112 &File
113 );
114 }
115 //
116 // Done
117 //
118 return EFI_ERROR (Status) ? NULL : File;
119 }
120
121 /**
122
123 Helper function called as part of the code needed
124 to allocate the proper sized buffer for various
125 EFI interfaces.
126
127
128 @param Status - Current status
129 @param Buffer - Current allocated buffer, or NULL
130 @param BufferSize - Current buffer size needed
131
132 @retval TRUE if the buffer was reallocated and the caller
133 should try the API again.
134
135 **/
136 BOOLEAN
137 EfiGrowBuffer (
138 IN OUT EFI_STATUS *Status,
139 IN OUT VOID **Buffer,
140 IN UINTN BufferSize
141 )
142 {
143 BOOLEAN TryAgain;
144
145 //
146 // If this is an initial request, buffer will be null with a new buffer size
147 //
148 if ((*Buffer == NULL) && (BufferSize != 0)) {
149 *Status = EFI_BUFFER_TOO_SMALL;
150 }
151 //
152 // If the status code is "buffer too small", resize the buffer
153 //
154 TryAgain = FALSE;
155 if (*Status == EFI_BUFFER_TOO_SMALL) {
156
157 SafeFreePool (*Buffer);
158
159 *Buffer = EfiAllocateZeroPool (BufferSize);
160
161 if (*Buffer != NULL) {
162 TryAgain = TRUE;
163 } else {
164 *Status = EFI_OUT_OF_RESOURCES;
165 }
166 }
167 //
168 // If there's an error, free the buffer
169 //
170 if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {
171 SafeFreePool (*Buffer);
172 *Buffer = NULL;
173 }
174
175 return TryAgain;
176 }
177
178 /**
179 Function returns the value of the specified variable.
180
181
182 @param Name - A Null-terminated Unicode string that is
183 the name of the vendor's variable.
184 @param VendorGuid - A unique identifier for the vendor.
185
186 @return The payload of the variable.
187
188 **/
189 VOID *
190 EfiLibGetVariable (
191 IN CHAR16 *Name,
192 IN EFI_GUID *VendorGuid
193 )
194 {
195 UINTN VarSize;
196
197 return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
198 }
199
200 /**
201 Function deletes the variable specified by VarName and VarGuid.
202
203
204 @param VarName - A Null-terminated Unicode string that is
205 the name of the vendor's variable.
206
207 @param VendorGuid - A unique identifier for the vendor.
208
209 @retval EFI_SUCCESS The variable was found and removed
210 @retval EFI_UNSUPPORTED The variable store was inaccessible
211 @retval EFI_OUT_OF_RESOURCES The temporary buffer was not available
212 @retval EFI_NOT_FOUND The variable was not found
213
214 **/
215 EFI_STATUS
216 EfiLibDeleteVariable (
217 IN CHAR16 *VarName,
218 IN EFI_GUID *VarGuid
219 )
220 {
221 VOID *VarBuf;
222 EFI_STATUS Status;
223
224 VarBuf = EfiLibGetVariable (VarName, VarGuid);
225 Status = EFI_NOT_FOUND;
226
227 if (VarBuf != NULL) {
228 //
229 // Delete variable from Storage
230 //
231 Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL);
232 ASSERT (!EFI_ERROR (Status));
233 SafeFreePool (VarBuf);
234 }
235
236 return Status;
237 }
238
239 /**
240
241 Function gets the file system information from an open file descriptor,
242 and stores it in a buffer allocated from pool.
243
244
245 @param FHand The file handle.
246
247 @return A pointer to a buffer with file information or NULL is returned
248
249 **/
250 EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *
251 EfiLibFileSystemVolumeLabelInfo (
252 IN EFI_FILE_HANDLE FHand
253 )
254 {
255 EFI_STATUS Status;
256 EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Buffer;
257 UINTN BufferSize;
258 //
259 // Initialize for GrowBuffer loop
260 //
261 Buffer = NULL;
262 BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 200;
263
264 //
265 // Call the real function
266 //
267 while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
268 Status = FHand->GetInfo (
269 FHand,
270 &gEfiFileSystemVolumeLabelInfoIdGuid,
271 &BufferSize,
272 Buffer
273 );
274 }
275
276 return Buffer;
277 }
278
279 /**
280 Duplicate a string.
281
282 @param Src The source.
283
284 @return A new string which is duplicated copy of the source.
285 @retval NULL If there is not enought memory.
286
287 **/
288 CHAR16 *
289 EfiStrDuplicate (
290 IN CHAR16 *Src
291 )
292 {
293 CHAR16 *Dest;
294 UINTN Size;
295
296 Size = StrSize (Src);
297 Dest = EfiAllocateZeroPool (Size);
298 ASSERT (Dest != NULL);
299 if (Dest != NULL) {
300 CopyMem (Dest, Src, Size);
301 }
302
303 return Dest;
304 }
305
306 /**
307
308 Function gets the file information from an open file descriptor, and stores it
309 in a buffer allocated from pool.
310
311 @param FHand File Handle.
312
313 @return A pointer to a buffer with file information or NULL is returned
314
315 **/
316 EFI_FILE_INFO *
317 EfiLibFileInfo (
318 IN EFI_FILE_HANDLE FHand
319 )
320 {
321 EFI_STATUS Status;
322 EFI_FILE_INFO *Buffer;
323 UINTN BufferSize;
324
325 //
326 // Initialize for GrowBuffer loop
327 //
328 Buffer = NULL;
329 BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
330
331 //
332 // Call the real function
333 //
334 while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
335 Status = FHand->GetInfo (
336 FHand,
337 &gEfiFileInfoGuid,
338 &BufferSize,
339 Buffer
340 );
341 }
342
343 return Buffer;
344 }
345
346 /**
347 Function is used to determine the number of device path instances
348 that exist in a device path.
349
350
351 @param DevicePath - A pointer to a device path data structure.
352
353 @return This function counts and returns the number of device path instances
354 in DevicePath.
355
356 **/
357 UINTN
358 EfiDevicePathInstanceCount (
359 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
360 )
361 {
362 UINTN Count;
363 UINTN Size;
364
365 Count = 0;
366 while (GetNextDevicePathInstance (&DevicePath, &Size)) {
367 Count += 1;
368 }
369
370 return Count;
371 }
372
373 /**
374 Adjusts the size of a previously allocated buffer.
375
376
377 @param OldPool - A pointer to the buffer whose size is being adjusted.
378 @param OldSize - The size of the current buffer.
379 @param NewSize - The size of the new buffer.
380
381 @retval EFI_SUCEESS The requested number of bytes were allocated.
382 @retval EFI_OUT_OF_RESOURCES The pool requested could not be allocated.
383 @retval EFI_INVALID_PARAMETER The buffer was invalid.
384
385 **/
386 VOID *
387 EfiReallocatePool (
388 IN VOID *OldPool,
389 IN UINTN OldSize,
390 IN UINTN NewSize
391 )
392 {
393 VOID *NewPool;
394
395 NewPool = NULL;
396 if (NewSize != 0) {
397 NewPool = EfiAllocateZeroPool (NewSize);
398 }
399
400 if (OldPool != NULL) {
401 if (NewPool != NULL) {
402 CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
403 }
404
405 SafeFreePool (OldPool);
406 }
407
408 return NewPool;
409 }
410
411 /**
412 Compare two EFI_TIME data.
413
414
415 @param FirstTime - A pointer to the first EFI_TIME data.
416 @param SecondTime - A pointer to the second EFI_TIME data.
417
418 @retval TRUE The FirstTime is not later than the SecondTime.
419 @retval FALSE The FirstTime is later than the SecondTime.
420
421 **/
422 BOOLEAN
423 TimeCompare (
424 IN EFI_TIME *FirstTime,
425 IN EFI_TIME *SecondTime
426 )
427 {
428 if (FirstTime->Year != SecondTime->Year) {
429 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
430 } else if (FirstTime->Month != SecondTime->Month) {
431 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
432 } else if (FirstTime->Day != SecondTime->Day) {
433 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
434 } else if (FirstTime->Hour != SecondTime->Hour) {
435 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
436 } else if (FirstTime->Minute != SecondTime->Minute) {
437 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
438 } else if (FirstTime->Second != SecondTime->Second) {
439 return (BOOLEAN) (FirstTime->Second < SecondTime->Second);
440 }
441
442 return (BOOLEAN) (FirstTime->Nanosecond <= SecondTime->Nanosecond);
443 }
444
445 /**
446 Get a string from the Data Hub record based on
447 a device path.
448
449 @param DevPath The device Path.
450
451 @return A string located from the Data Hub records based on
452 the device path.
453
454 **/
455 UINT16 *
456 EfiLibStrFromDatahub (
457 IN EFI_DEVICE_PATH_PROTOCOL *DevPath
458 )
459 {
460 EFI_STATUS Status;
461 UINT16 *Desc;
462 EFI_DATA_HUB_PROTOCOL *Datahub;
463 UINT64 Count;
464 EFI_DATA_RECORD_HEADER *Record;
465 EFI_SUBCLASS_TYPE1_HEADER *DataHdr;
466 EFI_GUID MiscGuid = EFI_MISC_SUBCLASS_GUID;
467 EFI_MISC_ONBOARD_DEVICE_DATA *ob;
468 EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *Port;
469 EFI_TIME CurTime;
470
471 Status = gBS->LocateProtocol (
472 &gEfiDataHubProtocolGuid,
473 NULL,
474 (VOID **) &Datahub
475 );
476 if (EFI_ERROR (Status)) {
477 return NULL;
478 }
479
480 Status = gRT->GetTime (&CurTime, NULL);
481 if (EFI_ERROR (Status)) {
482 return NULL;
483 }
484
485 Count = 0;
486 do {
487 Status = Datahub->GetNextRecord (Datahub, &Count, NULL, &Record);
488
489 if (EFI_ERROR (Status)) {
490 break;
491 }
492
493 if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA && CompareGuid (&Record->DataRecordGuid, &MiscGuid)) {
494 //
495 // This record is what we need
496 //
497 DataHdr = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);
498 if (EFI_MISC_ONBOARD_DEVICE_RECORD_NUMBER == DataHdr->RecordType) {
499 ob = (EFI_MISC_ONBOARD_DEVICE_DATA *) (DataHdr + 1);
500 if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &ob->OnBoardDevicePath, DevPath)) {
501 GetProducerString (&Record->ProducerName, ob->OnBoardDeviceDescription, &Desc);
502 return Desc;
503 }
504 }
505
506 if (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_RECORD_NUMBER == DataHdr->RecordType) {
507 Port = (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) (DataHdr + 1);
508 if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &Port->PortPath, DevPath)) {
509 GetProducerString (&Record->ProducerName, Port->PortExternalConnectorDesignator, &Desc);
510 return Desc;
511 }
512 }
513 }
514
515 } while (TimeCompare (&Record->LogTime, &CurTime) && Count != 0);
516
517 return NULL;
518 }