xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/lib/misc.c (revision 154bfe8e089c1a0a4e9ed8414f08d3da90949162)
1 /*	$NetBSD: misc.c,v 1.1.1.2 2018/08/16 18:17:47 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 *
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 *
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 *
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
85 FreePool (
86     IN VOID                 *Buffer
87     )
88 {
89     uefi_call_wrapper(BS->FreePool, 1, Buffer);
90 }
91 
92 
93 
94 VOID
95 ZeroMem (
96     IN VOID     *Buffer,
97     IN UINTN    Size
98     )
99 {
100     RtZeroMem (Buffer, Size);
101 }
102 
103 VOID
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
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
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
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 *
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 *
245 LibGetVariableAndSize (
246     IN CHAR16               *Name,
247     IN EFI_GUID             *VendorGuid,
248     OUT UINTN               *VarSize
249     )
250 {
251     EFI_STATUS              Status;
252     VOID                    *Buffer;
253     UINTN                   BufferSize;
254 
255     //
256     // Initialize for GrowBuffer loop
257     //
258 
259     Buffer = NULL;
260     BufferSize = 100;
261 
262     //
263     // Call the real function
264     //
265 
266     while (GrowBuffer (&Status, &Buffer, BufferSize)) {
267         Status = uefi_call_wrapper(
268 		    RT->GetVariable,
269 			5,
270                     Name,
271                     VendorGuid,
272                     NULL,
273                     &BufferSize,
274                     Buffer
275                     );
276     }
277     if (Buffer) {
278         *VarSize = BufferSize;
279     } else {
280         *VarSize = 0;
281     }
282     return Buffer;
283 }
284 
285 VOID *
286 LibGetVariable (
287     IN CHAR16               *Name,
288     IN EFI_GUID             *VendorGuid
289     )
290 {
291     UINTN   VarSize;
292 
293     return LibGetVariableAndSize (Name, VendorGuid, &VarSize);
294 }
295 
296 EFI_STATUS
297 LibDeleteVariable (
298     IN CHAR16   *VarName,
299     IN EFI_GUID *VarGuid
300     )
301 {
302     VOID        *VarBuf;
303     EFI_STATUS  Status;
304 
305     VarBuf = LibGetVariable(VarName,VarGuid);
306 
307     Status = EFI_NOT_FOUND;
308 
309     if (VarBuf) {
310         //
311         // Delete variable from Storage
312         //
313         Status = uefi_call_wrapper(
314 		    RT->SetVariable,
315 			5,
316                     VarName, VarGuid,
317                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
318                     0, NULL
319                  );
320         ASSERT (!EFI_ERROR(Status));
321         FreePool(VarBuf);
322     }
323 
324     return (Status);
325 }
326 
327 EFI_STATUS
328 LibSetNVVariable (
329     IN CHAR16   *VarName,
330     IN EFI_GUID *VarGuid,
331     IN UINTN	 DataSize,
332     IN VOID     *Data
333     )
334 {
335     EFI_STATUS  Status;
336 
337     Status = uefi_call_wrapper(
338 	    RT->SetVariable,
339 	    5,
340 	    VarName, VarGuid,
341 	    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
342 	    DataSize, Data
343 	    );
344     ASSERT (!EFI_ERROR(Status));
345     return (Status);
346 }
347 
348 EFI_STATUS
349 LibSetVariable (
350     IN CHAR16   *VarName,
351     IN EFI_GUID *VarGuid,
352     IN UINTN	 DataSize,
353     IN VOID     *Data
354     )
355 {
356     EFI_STATUS  Status;
357 
358     Status = uefi_call_wrapper(
359 	    RT->SetVariable,
360 	    5,
361 	    VarName, VarGuid,
362 	    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
363 	    DataSize, Data
364 	    );
365     ASSERT (!EFI_ERROR(Status));
366     return (Status);
367 }
368 
369 EFI_STATUS
370 LibInsertToTailOfBootOrder (
371     IN  UINT16  BootOption,
372     IN  BOOLEAN OnlyInsertIfEmpty
373     )
374 {
375     UINT16      *BootOptionArray;
376     UINT16      *NewBootOptionArray;
377     UINTN       VarSize;
378     UINTN       Index;
379     EFI_STATUS  Status;
380 
381     BootOptionArray = LibGetVariableAndSize (VarBootOrder, &EfiGlobalVariable, &VarSize);
382     if (VarSize != 0 && OnlyInsertIfEmpty) {
383         if (BootOptionArray) {
384             FreePool (BootOptionArray);
385         }
386         return EFI_UNSUPPORTED;
387     }
388 
389     VarSize += sizeof(UINT16);
390     NewBootOptionArray = AllocatePool (VarSize);
391 
392     for (Index = 0; Index < ((VarSize/sizeof(UINT16)) - 1); Index++) {
393         NewBootOptionArray[Index] = BootOptionArray[Index];
394     }
395     //
396     // Insert in the tail of the array
397     //
398     NewBootOptionArray[Index] = BootOption;
399 
400     Status = uefi_call_wrapper(
401 		RT->SetVariable,
402 		5,
403                 VarBootOrder, &EfiGlobalVariable,
404                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
405                 VarSize, (VOID*) NewBootOptionArray
406                 );
407 
408     if (NewBootOptionArray) {
409         FreePool (NewBootOptionArray);
410     }
411     if (BootOptionArray) {
412         FreePool (BootOptionArray);
413     }
414     return Status;
415 }
416 
417 
418 BOOLEAN
419 ValidMBR(
420     IN  MASTER_BOOT_RECORD  *Mbr,
421     IN  EFI_BLOCK_IO        *BlkIo
422     )
423 {
424     UINT32      StartingLBA, EndingLBA;
425     UINT32      NewEndingLBA;
426     INTN        i, j;
427     BOOLEAN     ValidMbr;
428 
429     if (Mbr->Signature != MBR_SIGNATURE) {
430         //
431         // The BPB also has this signature, so it can not be used alone.
432         //
433         return FALSE;
434     }
435 
436     ValidMbr = FALSE;
437     for (i=0; i<MAX_MBR_PARTITIONS; i++) {
438         if ( Mbr->Partition[i].OSIndicator == 0x00 || EXTRACT_UINT32(Mbr->Partition[i].SizeInLBA) == 0 ) {
439             continue;
440         }
441         ValidMbr = TRUE;
442         StartingLBA = EXTRACT_UINT32(Mbr->Partition[i].StartingLBA);
443         EndingLBA = StartingLBA + EXTRACT_UINT32(Mbr->Partition[i].SizeInLBA) - 1;
444         if (EndingLBA > BlkIo->Media->LastBlock) {
445             //
446             // Compatability Errata:
447             //  Some systems try to hide drive space with thier INT 13h driver
448             //  This does not hide space from the OS driver. This means the MBR
449             //  that gets created from DOS is smaller than the MBR created from
450             //  a real OS (NT & Win98). This leads to BlkIo->LastBlock being
451             //  wrong on some systems FDISKed by the OS.
452             //
453             //
454             if (BlkIo->Media->LastBlock < MIN_MBR_DEVICE_SIZE) {
455                 //
456                 // If this is a very small device then trust the BlkIo->LastBlock
457                 //
458                 return FALSE;
459             }
460 
461             if (EndingLBA > (BlkIo->Media->LastBlock + MBR_ERRATA_PAD)) {
462                 return FALSE;
463             }
464 
465         }
466         for (j=i+1; j<MAX_MBR_PARTITIONS; j++) {
467             if (Mbr->Partition[j].OSIndicator == 0x00 || EXTRACT_UINT32(Mbr->Partition[j].SizeInLBA) == 0) {
468                 continue;
469             }
470             if (   EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) >= StartingLBA &&
471                    EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) <= EndingLBA       ) {
472                 //
473                 // The Start of this region overlaps with the i'th region
474                 //
475                 return FALSE;
476             }
477             NewEndingLBA = EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) + EXTRACT_UINT32(Mbr->Partition[j].SizeInLBA) - 1;
478             if ( NewEndingLBA >= StartingLBA && NewEndingLBA <= EndingLBA ) {
479                 //
480                 // The End of this region overlaps with the i'th region
481                 //
482                 return FALSE;
483             }
484         }
485     }
486     //
487     // Non of the regions overlapped so MBR is O.K.
488     //
489     return ValidMbr;
490 }
491 
492 
493 UINT8
494 DecimaltoBCD(
495     IN  UINT8 DecValue
496     )
497 {
498     return RtDecimaltoBCD (DecValue);
499 }
500 
501 
502 UINT8
503 BCDtoDecimal(
504     IN  UINT8 BcdValue
505     )
506 {
507     return RtBCDtoDecimal (BcdValue);
508 }
509 
510 EFI_STATUS
511 LibGetSystemConfigurationTable(
512     IN EFI_GUID *TableGuid,
513     IN OUT VOID **Table
514     )
515 
516 {
517     UINTN Index;
518 
519     for(Index=0;Index<ST->NumberOfTableEntries;Index++) {
520         if (CompareGuid(TableGuid,&(ST->ConfigurationTable[Index].VendorGuid))==0) {
521             *Table = ST->ConfigurationTable[Index].VendorTable;
522             return EFI_SUCCESS;
523         }
524     }
525     return EFI_NOT_FOUND;
526 }
527 
528 
529 CHAR16 *
530 LibGetUiString (
531     IN  EFI_HANDLE      Handle,
532     IN  UI_STRING_TYPE  StringType,
533     IN  ISO_639_2       *LangCode,
534     IN  BOOLEAN         ReturnDevicePathStrOnMismatch
535     )
536 {
537     UI_INTERFACE    *Ui;
538     UI_STRING_TYPE  Index;
539     UI_STRING_ENTRY *Array;
540     EFI_STATUS      Status;
541 
542     Status = uefi_call_wrapper(BS->HandleProtocol, 3, Handle, &UiProtocol, (VOID *)&Ui);
543     if (EFI_ERROR(Status)) {
544         return (ReturnDevicePathStrOnMismatch) ? DevicePathToStr(DevicePathFromHandle(Handle)) : NULL;
545     }
546 
547     //
548     // Skip the first strings
549     //
550     for (Index = UiDeviceString, Array = Ui->Entry; Index < StringType; Index++, Array++) {
551         while (Array->LangCode) {
552             Array++;
553         }
554     }
555 
556     //
557     // Search for the match
558     //
559     while (Array->LangCode) {
560         if (strcmpa (Array->LangCode, LangCode) == 0) {
561             return Array->UiString;
562         }
563     }
564     return (ReturnDevicePathStrOnMismatch) ? DevicePathToStr(DevicePathFromHandle(Handle)) : NULL;
565 }
566