xref: /netbsd/sys/external/bsd/gnu-efi/dist/lib/misc.c (revision 48704958)
1 /*	$NetBSD: misc.c,v 1.3 2021/09/30 19:02:48 jmcneill Exp $	*/
2 
3 /*++
4 
5 Copyright (c) 1998  Intel Corporation
6 
7 Module Name:
8 
9     misc.c
10 
11 Abstract:
12 
13 
14 
15 
16 Revision History
17 
18 --*/
19 
20 #include "lib.h"
21 
22 
23 //
24 //
25 //
26 
27 VOID *
AllocatePool(IN UINTN Size)28 AllocatePool (
29     IN UINTN                Size
30     )
31 {
32     EFI_STATUS              Status;
33     VOID                    *p;
34 
35     Status = uefi_call_wrapper(BS->AllocatePool, 3, PoolAllocationType, Size, &p);
36     if (EFI_ERROR(Status)) {
37         DEBUG((D_ERROR, "AllocatePool: out of pool  %x\n", Status));
38         p = NULL;
39     }
40     return p;
41 }
42 
43 VOID *
AllocateZeroPool(IN UINTN Size)44 AllocateZeroPool (
45     IN UINTN                Size
46     )
47 {
48     VOID                    *p;
49 
50     p = AllocatePool (Size);
51     if (p) {
52         ZeroMem (p, Size);
53     }
54 
55     return p;
56 }
57 
58 VOID *
ReallocatePool(IN VOID * OldPool,IN UINTN OldSize,IN UINTN NewSize)59 ReallocatePool (
60     IN VOID                 *OldPool,
61     IN UINTN                OldSize,
62     IN UINTN                NewSize
63     )
64 {
65     VOID                    *NewPool;
66 
67     NewPool = NULL;
68     if (NewSize) {
69         NewPool = AllocatePool (NewSize);
70     }
71 
72     if (OldPool) {
73         if (NewPool) {
74             CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
75         }
76 
77         FreePool (OldPool);
78     }
79 
80     return NewPool;
81 }
82 
83 
84 VOID
FreePool(IN VOID * Buffer)85 FreePool (
86     IN VOID                 *Buffer
87     )
88 {
89     uefi_call_wrapper(BS->FreePool, 1, Buffer);
90 }
91 
92 
93 
94 VOID
ZeroMem(IN VOID * Buffer,IN UINTN Size)95 ZeroMem (
96     IN VOID     *Buffer,
97     IN UINTN    Size
98     )
99 {
100     RtZeroMem (Buffer, Size);
101 }
102 
103 VOID
SetMem(IN VOID * Buffer,IN UINTN Size,IN UINT8 Value)104 SetMem (
105     IN VOID     *Buffer,
106     IN UINTN    Size,
107     IN UINT8    Value
108     )
109 {
110     RtSetMem (Buffer, Size, Value);
111 }
112 
113 VOID
CopyMem(IN VOID * Dest,IN CONST VOID * Src,IN UINTN len)114 CopyMem (
115     IN VOID     *Dest,
116     IN CONST VOID     *Src,
117     IN UINTN    len
118     )
119 {
120     RtCopyMem (Dest, Src, len);
121 }
122 
123 INTN
CompareMem(IN CONST VOID * Dest,IN CONST VOID * Src,IN UINTN len)124 CompareMem (
125     IN CONST VOID     *Dest,
126     IN CONST VOID     *Src,
127     IN UINTN    len
128     )
129 {
130     return RtCompareMem (Dest, Src, len);
131 }
132 
133 BOOLEAN
GrowBuffer(IN OUT EFI_STATUS * Status,IN OUT VOID ** Buffer,IN UINTN BufferSize)134 GrowBuffer(
135     IN OUT EFI_STATUS   *Status,
136     IN OUT VOID         **Buffer,
137     IN UINTN            BufferSize
138     )
139 /*++
140 
141 Routine Description:
142 
143     Helper function called as part of the code needed
144     to allocate the proper sized buffer for various
145     EFI interfaces.
146 
147 Arguments:
148 
149     Status      - Current status
150 
151     Buffer      - Current allocated buffer, or NULL
152 
153     BufferSize  - Current buffer size needed
154 
155 Returns:
156 
157     TRUE - if the buffer was reallocated and the caller
158     should try the API again.
159 
160 --*/
161 {
162     BOOLEAN         TryAgain;
163 
164     //
165     // If this is an initial request, buffer will be null with a new buffer size
166     //
167 
168     if (!*Buffer && BufferSize) {
169         *Status = EFI_BUFFER_TOO_SMALL;
170     }
171 
172     //
173     // If the status code is "buffer too small", resize the buffer
174     //
175 
176     TryAgain = FALSE;
177     if (*Status == EFI_BUFFER_TOO_SMALL) {
178 
179         if (*Buffer) {
180             FreePool (*Buffer);
181         }
182 
183         *Buffer = AllocatePool (BufferSize);
184 
185         if (*Buffer) {
186             TryAgain = TRUE;
187         } else {
188             *Status = EFI_OUT_OF_RESOURCES;
189         }
190     }
191 
192     //
193     // If there's an error, free the buffer
194     //
195 
196     if (!TryAgain && EFI_ERROR(*Status) && *Buffer) {
197         FreePool (*Buffer);
198         *Buffer = NULL;
199     }
200 
201     return TryAgain;
202 }
203 
204 
205 EFI_MEMORY_DESCRIPTOR *
LibMemoryMap(OUT UINTN * NoEntries,OUT UINTN * MapKey,OUT UINTN * DescriptorSize,OUT UINT32 * DescriptorVersion)206 LibMemoryMap (
207     OUT UINTN               *NoEntries,
208     OUT UINTN               *MapKey,
209     OUT UINTN               *DescriptorSize,
210     OUT UINT32              *DescriptorVersion
211     )
212 {
213     EFI_STATUS              Status;
214     EFI_MEMORY_DESCRIPTOR   *Buffer;
215     UINTN                   BufferSize;
216 
217     //
218     // Initialize for GrowBuffer loop
219     //
220 
221     Status = EFI_SUCCESS;
222     Buffer = NULL;
223     BufferSize = sizeof(EFI_MEMORY_DESCRIPTOR);
224 
225     //
226     // Call the real function
227     //
228 
229     while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
230         Status = uefi_call_wrapper(BS->GetMemoryMap, 5, &BufferSize, Buffer, MapKey, DescriptorSize, DescriptorVersion);
231     }
232 
233     //
234     // Convert buffer size to NoEntries
235     //
236 
237     if (!EFI_ERROR(Status)) {
238         *NoEntries = BufferSize / *DescriptorSize;
239     }
240 
241     return Buffer;
242 }
243 
244 VOID *
LibGetVariableAndSize(IN CHAR16 * Name,IN EFI_GUID * VendorGuid,OUT UINTN * VarSize)245 LibGetVariableAndSize (
246     IN CHAR16               *Name,
247     IN EFI_GUID             *VendorGuid,
248     OUT UINTN               *VarSize
249     )
250 {
251     EFI_STATUS              Status = EFI_SUCCESS;
252     VOID                    *Buffer;
253     UINTN                   BufferSize;
254 
255     //
256     // Initialize for GrowBuffer loop
257     //
258 
259     Status = EFI_SUCCESS;
260     Buffer = NULL;
261     BufferSize = 100;
262 
263     //
264     // Call the real function
265     //
266 
267     while (GrowBuffer (&Status, &Buffer, BufferSize)) {
268         Status = uefi_call_wrapper(
269 		    RT->GetVariable,
270 			5,
271                     Name,
272                     VendorGuid,
273                     NULL,
274                     &BufferSize,
275                     Buffer
276                     );
277     }
278     if (Buffer) {
279         *VarSize = BufferSize;
280     } else {
281         *VarSize = 0;
282     }
283     return Buffer;
284 }
285 
286 VOID *
LibGetVariable(IN CHAR16 * Name,IN EFI_GUID * VendorGuid)287 LibGetVariable (
288     IN CHAR16               *Name,
289     IN EFI_GUID             *VendorGuid
290     )
291 {
292     UINTN   VarSize;
293 
294     return LibGetVariableAndSize (Name, VendorGuid, &VarSize);
295 }
296 
297 EFI_STATUS
LibDeleteVariable(IN CHAR16 * VarName,IN EFI_GUID * VarGuid)298 LibDeleteVariable (
299     IN CHAR16   *VarName,
300     IN EFI_GUID *VarGuid
301     )
302 {
303     VOID        *VarBuf;
304     EFI_STATUS  Status;
305 
306     VarBuf = LibGetVariable(VarName,VarGuid);
307 
308     Status = EFI_NOT_FOUND;
309 
310     if (VarBuf) {
311         //
312         // Delete variable from Storage
313         //
314         Status = uefi_call_wrapper(
315 		    RT->SetVariable,
316 			5,
317                     VarName, VarGuid,
318                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
319                     0, NULL
320                  );
321         ASSERT (!EFI_ERROR(Status));
322         FreePool(VarBuf);
323     }
324 
325     return (Status);
326 }
327 
328 EFI_STATUS
LibSetNVVariable(IN CHAR16 * VarName,IN EFI_GUID * VarGuid,IN UINTN DataSize,IN VOID * Data)329 LibSetNVVariable (
330     IN CHAR16   *VarName,
331     IN EFI_GUID *VarGuid,
332     IN UINTN	 DataSize,
333     IN VOID     *Data
334     )
335 {
336     EFI_STATUS  Status;
337 
338     Status = uefi_call_wrapper(
339 	    RT->SetVariable,
340 	    5,
341 	    VarName, VarGuid,
342 	    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
343 	    DataSize, Data
344 	    );
345     ASSERT (!EFI_ERROR(Status));
346     return (Status);
347 }
348 
349 EFI_STATUS
LibSetVariable(IN CHAR16 * VarName,IN EFI_GUID * VarGuid,IN UINTN DataSize,IN VOID * Data)350 LibSetVariable (
351     IN CHAR16   *VarName,
352     IN EFI_GUID *VarGuid,
353     IN UINTN	 DataSize,
354     IN VOID     *Data
355     )
356 {
357     EFI_STATUS  Status;
358 
359     Status = uefi_call_wrapper(
360 	    RT->SetVariable,
361 	    5,
362 	    VarName, VarGuid,
363 	    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
364 	    DataSize, Data
365 	    );
366     ASSERT (!EFI_ERROR(Status));
367     return (Status);
368 }
369 
370 EFI_STATUS
LibInsertToTailOfBootOrder(IN UINT16 BootOption,IN BOOLEAN OnlyInsertIfEmpty)371 LibInsertToTailOfBootOrder (
372     IN  UINT16  BootOption,
373     IN  BOOLEAN OnlyInsertIfEmpty
374     )
375 {
376     UINT16      *BootOptionArray;
377     UINT16      *NewBootOptionArray;
378     UINTN       VarSize;
379     UINTN       Index;
380     EFI_STATUS  Status;
381 
382     BootOptionArray = LibGetVariableAndSize (VarBootOrder, &EfiGlobalVariable, &VarSize);
383     if (VarSize != 0 && OnlyInsertIfEmpty) {
384         if (BootOptionArray) {
385             FreePool (BootOptionArray);
386         }
387         return EFI_UNSUPPORTED;
388     }
389 
390     VarSize += sizeof(UINT16);
391     NewBootOptionArray = AllocatePool (VarSize);
392     if (!NewBootOptionArray)
393         return EFI_OUT_OF_RESOURCES;
394 
395     for (Index = 0; Index < ((VarSize/sizeof(UINT16)) - 1); Index++) {
396         NewBootOptionArray[Index] = BootOptionArray[Index];
397     }
398     //
399     // Insert in the tail of the array
400     //
401     NewBootOptionArray[Index] = BootOption;
402 
403     Status = uefi_call_wrapper(
404 		RT->SetVariable,
405 		5,
406                 VarBootOrder, &EfiGlobalVariable,
407                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
408                 VarSize, (VOID*) NewBootOptionArray
409                 );
410 
411     FreePool (NewBootOptionArray);
412     if (BootOptionArray) {
413         FreePool (BootOptionArray);
414     }
415     return Status;
416 }
417 
418 
419 BOOLEAN
ValidMBR(IN MASTER_BOOT_RECORD * Mbr,IN EFI_BLOCK_IO * BlkIo)420 ValidMBR(
421     IN  MASTER_BOOT_RECORD  *Mbr,
422     IN  EFI_BLOCK_IO        *BlkIo
423     )
424 {
425     UINT32      StartingLBA, EndingLBA;
426     UINT32      NewEndingLBA;
427     INTN        i, j;
428     BOOLEAN     ValidMbr;
429 
430     if (Mbr->Signature != MBR_SIGNATURE) {
431         //
432         // The BPB also has this signature, so it can not be used alone.
433         //
434         return FALSE;
435     }
436 
437     ValidMbr = FALSE;
438     for (i=0; i<MAX_MBR_PARTITIONS; i++) {
439         if ( Mbr->Partition[i].OSIndicator == 0x00 || EXTRACT_UINT32(Mbr->Partition[i].SizeInLBA) == 0 ) {
440             continue;
441         }
442         ValidMbr = TRUE;
443         StartingLBA = EXTRACT_UINT32(Mbr->Partition[i].StartingLBA);
444         EndingLBA = StartingLBA + EXTRACT_UINT32(Mbr->Partition[i].SizeInLBA) - 1;
445         if (EndingLBA > BlkIo->Media->LastBlock) {
446             //
447             // Compatability Errata:
448             //  Some systems try to hide drive space with thier INT 13h driver
449             //  This does not hide space from the OS driver. This means the MBR
450             //  that gets created from DOS is smaller than the MBR created from
451             //  a real OS (NT & Win98). This leads to BlkIo->LastBlock being
452             //  wrong on some systems FDISKed by the OS.
453             //
454             //
455             if (BlkIo->Media->LastBlock < MIN_MBR_DEVICE_SIZE) {
456                 //
457                 // If this is a very small device then trust the BlkIo->LastBlock
458                 //
459                 return FALSE;
460             }
461 
462             if (EndingLBA > (BlkIo->Media->LastBlock + MBR_ERRATA_PAD)) {
463                 return FALSE;
464             }
465 
466         }
467         for (j=i+1; j<MAX_MBR_PARTITIONS; j++) {
468             if (Mbr->Partition[j].OSIndicator == 0x00 || EXTRACT_UINT32(Mbr->Partition[j].SizeInLBA) == 0) {
469                 continue;
470             }
471             if (   EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) >= StartingLBA &&
472                    EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) <= EndingLBA       ) {
473                 //
474                 // The Start of this region overlaps with the i'th region
475                 //
476                 return FALSE;
477             }
478             NewEndingLBA = EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) + EXTRACT_UINT32(Mbr->Partition[j].SizeInLBA) - 1;
479             if ( NewEndingLBA >= StartingLBA && NewEndingLBA <= EndingLBA ) {
480                 //
481                 // The End of this region overlaps with the i'th region
482                 //
483                 return FALSE;
484             }
485         }
486     }
487     //
488     // Non of the regions overlapped so MBR is O.K.
489     //
490     return ValidMbr;
491 }
492 
493 
494 UINT8
DecimaltoBCD(IN UINT8 DecValue)495 DecimaltoBCD(
496     IN  UINT8 DecValue
497     )
498 {
499     return RtDecimaltoBCD (DecValue);
500 }
501 
502 
503 UINT8
BCDtoDecimal(IN UINT8 BcdValue)504 BCDtoDecimal(
505     IN  UINT8 BcdValue
506     )
507 {
508     return RtBCDtoDecimal (BcdValue);
509 }
510 
511 EFI_STATUS
LibGetSystemConfigurationTable(IN EFI_GUID * TableGuid,IN OUT VOID ** Table)512 LibGetSystemConfigurationTable(
513     IN EFI_GUID *TableGuid,
514     IN OUT VOID **Table
515     )
516 
517 {
518     UINTN Index;
519 
520     for(Index=0;Index<ST->NumberOfTableEntries;Index++) {
521         if (CompareGuid(TableGuid,&(ST->ConfigurationTable[Index].VendorGuid))==0) {
522             *Table = ST->ConfigurationTable[Index].VendorTable;
523             return EFI_SUCCESS;
524         }
525     }
526     return EFI_NOT_FOUND;
527 }
528 
529 
530 CHAR16 *
LibGetUiString(IN EFI_HANDLE Handle,IN UI_STRING_TYPE StringType,IN ISO_639_2 * LangCode,IN BOOLEAN ReturnDevicePathStrOnMismatch)531 LibGetUiString (
532     IN  EFI_HANDLE      Handle,
533     IN  UI_STRING_TYPE  StringType,
534     IN  ISO_639_2       *LangCode,
535     IN  BOOLEAN         ReturnDevicePathStrOnMismatch
536     )
537 {
538     UI_INTERFACE    *Ui;
539     UI_STRING_TYPE  Index;
540     UI_STRING_ENTRY *Array;
541     EFI_STATUS      Status;
542 
543     Status = uefi_call_wrapper(BS->HandleProtocol, 3, Handle, &UiProtocol, (VOID *)&Ui);
544     if (EFI_ERROR(Status)) {
545         return (ReturnDevicePathStrOnMismatch) ? DevicePathToStr(DevicePathFromHandle(Handle)) : NULL;
546     }
547 
548     //
549     // Skip the first strings
550     //
551     for (Index = UiDeviceString, Array = Ui->Entry; Index < StringType; Index++, Array++) {
552         while (Array->LangCode) {
553             Array++;
554         }
555     }
556 
557     //
558     // Search for the match
559     //
560     while (Array->LangCode) {
561         if (strcmpa (Array->LangCode, LangCode) == 0) {
562             return Array->UiString;
563         }
564     }
565     return (ReturnDevicePathStrOnMismatch) ? DevicePathToStr(DevicePathFromHandle(Handle)) : NULL;
566 }
567