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