]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/GenericBdsLib/BdsMisc.c
UEFI HII: Merge UEFI HII support changes from branch.
[mirror_edk2.git] / MdeModulePkg / Library / GenericBdsLib / BdsMisc.c
1 /** @file
2
3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 BdsMisc.c
15
16 Abstract:
17
18 Misc BDS library function
19
20
21 **/
22
23 #include "InternalBdsLib.h"
24
25
26 #define MAX_STRING_LEN 200
27
28 static BOOLEAN mFeaturerSwitch = TRUE;
29 static BOOLEAN mResetRequired = FALSE;
30
31 extern UINT16 gPlatformBootTimeOutDefault;
32
33
34 /**
35 Return the default value for system Timeout variable.
36
37 None
38
39 @return Timeout value.
40
41 **/
42 UINT16
43 BdsLibGetTimeout (
44 VOID
45 )
46 {
47 UINT16 Timeout;
48 UINTN Size;
49 EFI_STATUS Status;
50
51 //
52 // Return Timeout variable or 0xffff if no valid
53 // Timeout variable exists.
54 //
55 Size = sizeof (UINT16);
56 Status = gRT->GetVariable (L"Timeout", &gEfiGlobalVariableGuid, NULL, &Size, &Timeout);
57 if (!EFI_ERROR (Status)) {
58 return Timeout;
59 }
60 //
61 // To make the current EFI Automatic-Test activity possible, just add
62 // following code to make AutoBoot enabled when this variable is not
63 // present.
64 // This code should be removed later.
65 //
66 Timeout = PcdGet16 (PcdPlatformBootTimeOutDefault);
67
68 //
69 // Notes: Platform should set default variable if non exists on all error cases!!!
70 //
71 Status = gRT->SetVariable (
72 L"Timeout",
73 &gEfiGlobalVariableGuid,
74 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
75 sizeof (UINT16),
76 &Timeout
77 );
78 return Timeout;
79 }
80
81
82 /**
83 The function will go through the driver optoin link list, load and start
84 every driver the driver optoin device path point to.
85
86 @param BdsDriverLists The header of the current driver option link list
87
88 @return None
89
90 **/
91 VOID
92 BdsLibLoadDrivers (
93 IN LIST_ENTRY *BdsDriverLists
94 )
95 {
96 EFI_STATUS Status;
97 LIST_ENTRY *Link;
98 BDS_COMMON_OPTION *Option;
99 EFI_HANDLE ImageHandle;
100 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
101 UINTN ExitDataSize;
102 CHAR16 *ExitData;
103 BOOLEAN ReconnectAll;
104
105 ReconnectAll = FALSE;
106
107 //
108 // Process the driver option
109 //
110 for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {
111 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
112 //
113 // If a load option is not marked as LOAD_OPTION_ACTIVE,
114 // the boot manager will not automatically load the option.
115 //
116 if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {
117 continue;
118 }
119 //
120 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
121 // then all of the EFI drivers in the system will be disconnected and
122 // reconnected after the last driver load option is processed.
123 //
124 if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {
125 ReconnectAll = TRUE;
126 }
127 //
128 // Make sure the driver path is connected.
129 //
130 BdsLibConnectDevicePath (Option->DevicePath);
131
132 //
133 // Load and start the image that Driver#### describes
134 //
135 Status = gBS->LoadImage (
136 FALSE,
137 mBdsImageHandle,
138 Option->DevicePath,
139 NULL,
140 0,
141 &ImageHandle
142 );
143
144 if (!EFI_ERROR (Status)) {
145 gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
146
147 //
148 // Verify whether this image is a driver, if not,
149 // exit it and continue to parse next load option
150 //
151 if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
152 gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
153 continue;
154 }
155
156 if (Option->LoadOptionsSize != 0) {
157 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
158 ImageInfo->LoadOptions = Option->LoadOptions;
159 }
160 //
161 // Before calling the image, enable the Watchdog Timer for
162 // the 5 Minute period
163 //
164 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
165
166 Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
167 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));
168
169 //
170 // Clear the Watchdog Timer after the image returns
171 //
172 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
173 }
174 }
175 //
176 // Process the LOAD_OPTION_FORCE_RECONNECT driver option
177 //
178 if (ReconnectAll) {
179 BdsLibDisconnectAllEfi ();
180 BdsLibConnectAll ();
181 }
182
183 }
184
185
186 /**
187 Get the Option Number that does not used
188 Try to locate the specific option variable one by one untile find a free number
189
190 @param VariableName Indicate if the boot#### or driver#### option
191
192 @return The Minimal Free Option Number
193
194 **/
195 UINT16
196 BdsLibGetFreeOptionNumber (
197 IN CHAR16 *VariableName
198 )
199 {
200 UINT16 Number;
201 UINTN Index;
202 CHAR16 StrTemp[10];
203 UINT16 *OptionBuffer;
204 UINTN OptionSize;
205
206 //
207 // Try to find the minimum free number from 0, 1, 2, 3....
208 //
209 Index = 0;
210 do {
211 if (*VariableName == 'B') {
212 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
213 } else {
214 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Driver%04x", Index);
215 }
216 //
217 // try if the option number is used
218 //
219 OptionBuffer = BdsLibGetVariableAndSize (
220 StrTemp,
221 &gEfiGlobalVariableGuid,
222 &OptionSize
223 );
224 if (OptionBuffer == NULL) {
225 break;
226 }
227 Index++;
228 } while (1);
229
230 Number = (UINT16) Index;
231 return Number;
232 }
233
234
235 /**
236 This function will register the new boot#### or driver#### option base on
237 the VariableName. The new registered boot#### or driver#### will be linked
238 to BdsOptionList and also update to the VariableName. After the boot#### or
239 driver#### updated, the BootOrder or DriverOrder will also be updated.
240
241 @param BdsOptionList The header of the boot#### or driver#### link list
242 @param DevicePath The device path which the boot#### or driver####
243 option present
244 @param String The description of the boot#### or driver####
245 @param VariableName Indicate if the boot#### or driver#### option
246
247 @retval EFI_SUCCESS The boot#### or driver#### have been success
248 registered
249 @retval EFI_STATUS Return the status of gRT->SetVariable ().
250
251 **/
252 EFI_STATUS
253 BdsLibRegisterNewOption (
254 IN LIST_ENTRY *BdsOptionList,
255 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
256 IN CHAR16 *String,
257 IN CHAR16 *VariableName
258 )
259 {
260 EFI_STATUS Status;
261 UINTN Index;
262 UINT16 RegisterOptionNumber;
263 UINT16 *TempOptionPtr;
264 UINTN TempOptionSize;
265 UINT16 *OptionOrderPtr;
266 VOID *OptionPtr;
267 UINTN OptionSize;
268 UINT8 *TempPtr;
269 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
270 CHAR16 *Description;
271 CHAR16 OptionName[10];
272 BOOLEAN UpdateBootDevicePath;
273 UINT16 BootOrderEntry;
274 UINTN OrderItemNum;
275
276
277 OptionPtr = NULL;
278 OptionSize = 0;
279 TempPtr = NULL;
280 OptionDevicePath = NULL;
281 Description = NULL;
282 OptionOrderPtr = NULL;
283 UpdateBootDevicePath = FALSE;
284 ZeroMem (OptionName, sizeof (OptionName));
285
286 TempOptionSize = 0;
287 TempOptionPtr = BdsLibGetVariableAndSize (
288 VariableName,
289 &gEfiGlobalVariableGuid,
290 &TempOptionSize
291 );
292
293 //
294 // Compare with current option variable
295 //
296 for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {
297
298 if (*VariableName == 'B') {
299 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);
300 } else {
301 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);
302 }
303
304 OptionPtr = BdsLibGetVariableAndSize (
305 OptionName,
306 &gEfiGlobalVariableGuid,
307 &OptionSize
308 );
309 if (OptionPtr == NULL) {
310 continue;
311 }
312 TempPtr = OptionPtr;
313 TempPtr += sizeof (UINT32) + sizeof (UINT16);
314 Description = (CHAR16 *) TempPtr;
315 TempPtr += StrSize ((CHAR16 *) TempPtr);
316 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
317
318 //
319 // Notes: the description may will change base on the GetStringToken
320 //
321 if (CompareMem (Description, String, StrSize (Description)) == 0) {
322 if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {
323 //
324 // Got the option, so just return
325 //
326 gBS->FreePool (OptionPtr);
327 gBS->FreePool (TempOptionPtr);
328 return EFI_SUCCESS;
329 } else {
330 //
331 // Boot device path changed, need update.
332 //
333 UpdateBootDevicePath = TRUE;
334 break;
335 }
336 }
337
338 gBS->FreePool (OptionPtr);
339 }
340
341 OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);
342 OptionSize += GetDevicePathSize (DevicePath);
343 OptionPtr = AllocateZeroPool (OptionSize);
344 TempPtr = OptionPtr;
345 *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
346 TempPtr += sizeof (UINT32);
347 *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
348 TempPtr += sizeof (UINT16);
349 CopyMem (TempPtr, String, StrSize (String));
350 TempPtr += StrSize (String);
351 CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
352
353 if (UpdateBootDevicePath) {
354 //
355 // The number in option#### to be updated
356 //
357 RegisterOptionNumber = TempOptionPtr[Index];
358 } else {
359 //
360 // The new option#### number
361 //
362 RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);
363 }
364
365 if (*VariableName == 'B') {
366 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
367 } else {
368 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
369 }
370
371 Status = gRT->SetVariable (
372 OptionName,
373 &gEfiGlobalVariableGuid,
374 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
375 OptionSize,
376 OptionPtr
377 );
378 if (EFI_ERROR (Status) || UpdateBootDevicePath) {
379 gBS->FreePool (OptionPtr);
380 gBS->FreePool (TempOptionPtr);
381 return Status;
382 }
383
384 gBS->FreePool (OptionPtr);
385
386 //
387 // Update the option order variable
388 //
389
390 //
391 // If no BootOrder
392 //
393 if (TempOptionSize == 0) {
394 BootOrderEntry = 0;
395 Status = gRT->SetVariable (
396 VariableName,
397 &gEfiGlobalVariableGuid,
398 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
399 sizeof (UINT16),
400 &BootOrderEntry
401 );
402 if (EFI_ERROR (Status)) {
403 gBS->FreePool (TempOptionPtr);
404 return Status;
405 }
406 return EFI_SUCCESS;
407 }
408
409 if (UpdateBootDevicePath) {
410 //
411 // If just update a old option, the new optionorder size not change
412 //
413 OrderItemNum = (TempOptionSize / sizeof (UINT16)) ;
414 OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
415 CopyMem (OptionOrderPtr, TempOptionPtr, OrderItemNum * sizeof (UINT16));
416 } else {
417 OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;
418 OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
419 CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));
420 }
421
422 OptionOrderPtr[Index] = RegisterOptionNumber;
423
424 Status = gRT->SetVariable (
425 VariableName,
426 &gEfiGlobalVariableGuid,
427 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
428 OrderItemNum * sizeof (UINT16),
429 OptionOrderPtr
430 );
431 if (EFI_ERROR (Status)) {
432 gBS->FreePool (TempOptionPtr);
433 gBS->FreePool (OptionOrderPtr);
434 return Status;
435 }
436
437 gBS->FreePool (TempOptionPtr);
438 gBS->FreePool (OptionOrderPtr);
439
440 return EFI_SUCCESS;
441 }
442
443
444 /**
445 Build the boot#### or driver#### option from the VariableName, the
446 build boot#### or driver#### will also be linked to BdsCommonOptionList
447
448 @param BdsCommonOptionList The header of the boot#### or driver#### option
449 link list
450 @param VariableName EFI Variable name indicate if it is boot#### or
451 driver####
452
453 @retval BDS_COMMON_OPTION Get the option just been created
454 @retval NULL Failed to get the new option
455
456 **/
457 BDS_COMMON_OPTION *
458 BdsLibVariableToOption (
459 IN OUT LIST_ENTRY *BdsCommonOptionList,
460 IN CHAR16 *VariableName
461 )
462 {
463 UINT32 Attribute;
464 UINT16 FilePathSize;
465 UINT8 *Variable;
466 UINT8 *TempPtr;
467 UINTN VariableSize;
468 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
469 BDS_COMMON_OPTION *Option;
470 VOID *LoadOptions;
471 UINT32 LoadOptionsSize;
472 CHAR16 *Description;
473 UINT8 NumOff;
474 //
475 // Read the variable. We will never free this data.
476 //
477 Variable = BdsLibGetVariableAndSize (
478 VariableName,
479 &gEfiGlobalVariableGuid,
480 &VariableSize
481 );
482 if (Variable == NULL) {
483 return NULL;
484 }
485 //
486 // Notes: careful defined the variable of Boot#### or
487 // Driver####, consider use some macro to abstract the code
488 //
489 //
490 // Get the option attribute
491 //
492 TempPtr = Variable;
493 Attribute = *(UINT32 *) Variable;
494 TempPtr += sizeof (UINT32);
495
496 //
497 // Get the option's device path size
498 //
499 FilePathSize = *(UINT16 *) TempPtr;
500 TempPtr += sizeof (UINT16);
501
502 //
503 // Get the option's description string
504 //
505 Description = (CHAR16 *) TempPtr;
506
507 //
508 // Get the option's description string size
509 //
510 TempPtr += StrSize ((CHAR16 *) TempPtr);
511
512 //
513 // Get the option's device path
514 //
515 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
516 TempPtr += FilePathSize;
517
518 LoadOptions = TempPtr;
519 LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
520
521 //
522 // The Console variables may have multiple device paths, so make
523 // an Entry for each one.
524 //
525 Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
526 if (Option == NULL) {
527 return NULL;
528 }
529
530 Option->Signature = BDS_LOAD_OPTION_SIGNATURE;
531 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
532 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
533 Option->Attribute = Attribute;
534 Option->Description = AllocateZeroPool (StrSize (Description));
535 CopyMem (Option->Description, Description, StrSize (Description));
536 Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
537 CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
538 Option->LoadOptionsSize = LoadOptionsSize;
539
540 //
541 // Get the value from VariableName Unicode string
542 // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
543 // Unicode stream to ASCII without any loss in meaning.
544 //
545 if (*VariableName == 'B') {
546 NumOff = sizeof (L"Boot")/sizeof(CHAR16) -1 ;
547 Option->BootCurrent = (UINT16) ((VariableName[NumOff] -'0') * 0x1000);
548 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100));
549 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+2]-'0') * 0x10));
550 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0')));
551 }
552 //
553 // Insert active entry to BdsDeviceList
554 //
555 if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {
556 InsertTailList (BdsCommonOptionList, &Option->Link);
557 gBS->FreePool (Variable);
558 return Option;
559 }
560
561 gBS->FreePool (Variable);
562 gBS->FreePool (Option);
563 return NULL;
564
565 }
566
567
568 /**
569 Process BootOrder, or DriverOrder variables, by calling
570 BdsLibVariableToOption () for each UINT16 in the variables.
571
572 @param BdsCommonOptionList The header of the option list base on variable
573 VariableName
574 @param VariableName EFI Variable name indicate the BootOrder or
575 DriverOrder
576
577 @retval EFI_SUCCESS Success create the boot option or driver option
578 list
579 @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or driver option list
580
581 **/
582 EFI_STATUS
583 BdsLibBuildOptionFromVar (
584 IN LIST_ENTRY *BdsCommonOptionList,
585 IN CHAR16 *VariableName
586 )
587 {
588 UINT16 *OptionOrder;
589 UINTN OptionOrderSize;
590 UINTN Index;
591 BDS_COMMON_OPTION *Option;
592 CHAR16 OptionName[20];
593
594 //
595 // Zero Buffer in order to get all BOOT#### variables
596 //
597 ZeroMem (OptionName, sizeof (OptionName));
598
599 //
600 // Read the BootOrder, or DriverOrder variable.
601 //
602 OptionOrder = BdsLibGetVariableAndSize (
603 VariableName,
604 &gEfiGlobalVariableGuid,
605 &OptionOrderSize
606 );
607 if (OptionOrder == NULL) {
608 return EFI_OUT_OF_RESOURCES;
609 }
610
611 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
612 if (*VariableName == 'B') {
613 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
614 } else {
615 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
616 }
617
618 Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
619 Option->BootCurrent = OptionOrder[Index];
620
621 }
622
623 gBS->FreePool (OptionOrder);
624
625 return EFI_SUCCESS;
626 }
627
628
629 /**
630 Get boot mode by looking up configuration table and parsing HOB list
631
632 @param BootMode Boot mode from PEI handoff HOB.
633
634 @retval EFI_SUCCESS Successfully get boot mode
635 @retval EFI_NOT_FOUND Can not find the current system boot mode
636
637 **/
638 EFI_STATUS
639 BdsLibGetBootMode (
640 OUT EFI_BOOT_MODE *BootMode
641 )
642 {
643 VOID *HobList;
644 EFI_STATUS Status;
645
646 //
647 // Get Hob list
648 //
649 Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
650 if (EFI_ERROR (Status)) {
651 DEBUG ((DEBUG_ERROR, "Hob list not found\n"));
652 *BootMode = 0;
653 return EFI_NOT_FOUND;
654 }
655
656 Status = R8_GetHobBootMode (HobList, BootMode);
657 if (EFI_ERROR (Status)) {
658 return EFI_NOT_FOUND;
659 }
660
661 return EFI_SUCCESS;
662 }
663
664
665 /**
666 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
667 buffer, and the size of the buffer. If failure return NULL.
668
669 @param Name String part of EFI variable name
670 @param VendorGuid GUID part of EFI variable name
671 @param VariableSize Returns the size of the EFI variable that was read
672
673 @return Dynamically allocated memory that contains a copy of the EFI variable.
674 @return Caller is responsible freeing the buffer.
675 @retval NULL Variable was not read
676
677 **/
678 VOID *
679 BdsLibGetVariableAndSize (
680 IN CHAR16 *Name,
681 IN EFI_GUID *VendorGuid,
682 OUT UINTN *VariableSize
683 )
684 {
685 EFI_STATUS Status;
686 UINTN BufferSize;
687 VOID *Buffer;
688
689 Buffer = NULL;
690
691 //
692 // Pass in a zero size buffer to find the required buffer size.
693 //
694 BufferSize = 0;
695 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
696 if (Status == EFI_BUFFER_TOO_SMALL) {
697 //
698 // Allocate the buffer to return
699 //
700 Buffer = AllocateZeroPool (BufferSize);
701 if (Buffer == NULL) {
702 return NULL;
703 }
704 //
705 // Read variable into the allocated buffer.
706 //
707 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
708 if (EFI_ERROR (Status)) {
709 BufferSize = 0;
710 }
711 }
712
713 *VariableSize = BufferSize;
714 return Buffer;
715 }
716
717
718 /**
719 Delete the instance in Multi which matches partly with Single instance
720
721 @param Multi A pointer to a multi-instance device path data
722 structure.
723 @param Single A pointer to a single-instance device path data
724 structure.
725
726 @return This function will remove the device path instances in Multi which partly
727 @return match with the Single, and return the result device path. If there is no
728 @return remaining device path as a result, this function will return NULL.
729
730 **/
731 EFI_DEVICE_PATH_PROTOCOL *
732 BdsLibDelPartMatchInstance (
733 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
734 IN EFI_DEVICE_PATH_PROTOCOL *Single
735 )
736 {
737 EFI_DEVICE_PATH_PROTOCOL *Instance;
738 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
739 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
740 UINTN InstanceSize;
741 UINTN SingleDpSize;
742 UINTN Size;
743
744 NewDevicePath = NULL;
745 TempNewDevicePath = NULL;
746
747 if (Multi == NULL || Single == NULL) {
748 return Multi;
749 }
750
751 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
752 SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
753 InstanceSize -= END_DEVICE_PATH_LENGTH;
754
755 while (Instance != NULL) {
756
757 Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;
758
759 if ((CompareMem (Instance, Single, Size) != 0)) {
760 //
761 // Append the device path instance which does not match with Single
762 //
763 TempNewDevicePath = NewDevicePath;
764 NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
765 SafeFreePool(TempNewDevicePath);
766 }
767 SafeFreePool(Instance);
768 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
769 InstanceSize -= END_DEVICE_PATH_LENGTH;
770 }
771
772 return NewDevicePath;
773 }
774
775
776 /**
777 Function compares a device path data structure to that of all the nodes of a
778 second device path instance.
779
780 @param Multi A pointer to a multi-instance device path data
781 structure.
782 @param Single A pointer to a single-instance device path data
783 structure.
784
785 @retval TRUE If the Single is contained within Multi
786 @retval FALSE The Single is not match within Multi
787
788 **/
789 BOOLEAN
790 BdsLibMatchDevicePaths (
791 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
792 IN EFI_DEVICE_PATH_PROTOCOL *Single
793 )
794 {
795 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
796 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
797 UINTN Size;
798
799 if (!Multi || !Single) {
800 return FALSE;
801 }
802
803 DevicePath = Multi;
804 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
805
806 //
807 // Search for the match of 'Single' in 'Multi'
808 //
809 while (DevicePathInst != NULL) {
810 //
811 // If the single device path is found in multiple device paths,
812 // return success
813 //
814 if (CompareMem (Single, DevicePathInst, Size) == 0) {
815 gBS->FreePool (DevicePathInst);
816 return TRUE;
817 }
818
819 gBS->FreePool (DevicePathInst);
820 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
821 }
822
823 return FALSE;
824 }
825
826
827 /**
828 This function prints a series of strings.
829
830 @param ConOut Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
831 @param ... A variable argument list containing series of
832 strings, the last string must be NULL.
833
834 @retval EFI_SUCCESS Success print out the string using ConOut.
835 @retval EFI_STATUS Return the status of the ConOut->OutputString ().
836
837 **/
838 EFI_STATUS
839 BdsLibOutputStrings (
840 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
841 ...
842 )
843 {
844 VA_LIST args;
845 EFI_STATUS Status;
846 CHAR16 *String;
847
848 Status = EFI_SUCCESS;
849 VA_START (args, ConOut);
850
851 while (!EFI_ERROR (Status)) {
852 //
853 // If String is NULL, then it's the end of the list
854 //
855 String = VA_ARG (args, CHAR16 *);
856 if (!String) {
857 break;
858 }
859
860 Status = ConOut->OutputString (ConOut, String);
861
862 if (EFI_ERROR (Status)) {
863 break;
864 }
865 }
866
867 return Status;
868 }
869
870 //
871 // Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
872 // Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if
873 // user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.
874 //
875
876
877 /**
878 Enable the setup browser reset reminder feature.
879 This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
880
881 VOID
882
883 @return VOID
884
885 **/
886 VOID
887 EnableResetReminderFeature (
888 VOID
889 )
890 {
891 mFeaturerSwitch = TRUE;
892 }
893
894
895 /**
896 Disable the setup browser reset reminder feature.
897 This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
898
899 VOID
900
901 @return VOID
902
903 **/
904 VOID
905 DisableResetReminderFeature (
906 VOID
907 )
908 {
909 mFeaturerSwitch = FALSE;
910 }
911
912
913 /**
914 Record the info that a reset is required.
915 A module boolean variable is used to record whether a reset is required.
916
917 VOID
918
919 @return VOID
920
921 **/
922 VOID
923 EnableResetRequired (
924 VOID
925 )
926 {
927 mResetRequired = TRUE;
928 }
929
930
931 /**
932 Record the info that no reset is required.
933 A module boolean variable is used to record whether a reset is required.
934
935 VOID
936
937 @return VOID
938
939 **/
940 VOID
941 DisableResetRequired (
942 VOID
943 )
944 {
945 mResetRequired = FALSE;
946 }
947
948
949 /**
950 Check whether platform policy enable the reset reminder feature. The default is enabled.
951
952 VOID
953
954 @return VOID
955
956 **/
957 BOOLEAN
958 IsResetReminderFeatureEnable (
959 VOID
960 )
961 {
962 return mFeaturerSwitch;
963 }
964
965
966 /**
967 Check if user changed any option setting which needs a system reset to be effective.
968
969 VOID
970
971 @return VOID
972
973 **/
974 BOOLEAN
975 IsResetRequired (
976 VOID
977 )
978 {
979 return mResetRequired;
980 }
981
982
983 /**
984 Check whether a reset is needed, and finish the reset reminder feature.
985 If a reset is needed, Popup a menu to notice user, and finish the feature
986 according to the user selection.
987
988 VOID
989
990 @return VOID
991
992 **/
993 VOID
994 SetupResetReminder (
995 VOID
996 )
997 {
998 #if (EFI_SPECIFICATION_VERSION < 0x0002000A)
999 EFI_STATUS Status;
1000 EFI_FORM_BROWSER_PROTOCOL *Browser;
1001 #endif
1002 EFI_INPUT_KEY Key;
1003 CHAR16 *StringBuffer1;
1004 CHAR16 *StringBuffer2;
1005
1006
1007 //
1008 //check any reset required change is applied? if yes, reset system
1009 //
1010 if (IsResetReminderFeatureEnable ()) {
1011 if (IsResetRequired ()) {
1012
1013 #if (EFI_SPECIFICATION_VERSION < 0x0002000A)
1014 Status = gBS->LocateProtocol (
1015 &gEfiFormBrowserProtocolGuid,
1016 NULL,
1017 &Browser
1018 );
1019 #endif
1020
1021 StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
1022 ASSERT (StringBuffer1 != NULL);
1023 StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
1024 ASSERT (StringBuffer2 != NULL);
1025 StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now ? ");
1026 StrCpy (StringBuffer2, L"Enter (YES) / Esc (NO)");
1027 //
1028 // Popup a menu to notice user
1029 //
1030 do {
1031 #if (EFI_SPECIFICATION_VERSION < 0x0002000A)
1032 Browser->CreatePopUp (2, TRUE, 0, NULL, &Key, StringBuffer1, StringBuffer2);
1033 #else
1034 IfrLibCreatePopUp (2, &Key, StringBuffer1, StringBuffer2);
1035 #endif
1036 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
1037
1038 gBS->FreePool (StringBuffer1);
1039 gBS->FreePool (StringBuffer2);
1040 //
1041 // If the user hits the YES Response key, reset
1042 //
1043 if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
1044 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
1045 }
1046 gST->ConOut->ClearScreen (gST->ConOut);
1047 }
1048 }
1049 }
1050
1051
1052 /**
1053 Get the headers (dos, image, optional header) from an image
1054
1055 @param Device SimpleFileSystem device handle
1056 @param FileName File name for the image
1057 @param DosHeader Pointer to dos header
1058 @param ImageHeader Pointer to image header
1059 @param OptionalHeader Pointer to optional header
1060
1061 @retval EFI_SUCCESS Successfully get the machine type.
1062 @retval EFI_NOT_FOUND The file is not found.
1063 @retval EFI_LOAD_ERROR File is not a valid image file.
1064
1065 **/
1066 EFI_STATUS
1067 BdsLibGetImageHeader (
1068 IN EFI_HANDLE Device,
1069 IN CHAR16 *FileName,
1070 OUT EFI_IMAGE_DOS_HEADER *DosHeader,
1071 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
1072 )
1073 {
1074 EFI_STATUS Status;
1075 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
1076 EFI_FILE_HANDLE Root;
1077 EFI_FILE_HANDLE ThisFile;
1078 UINTN BufferSize;
1079 UINT64 FileSize;
1080 EFI_FILE_INFO *Info;
1081
1082 Root = NULL;
1083 ThisFile = NULL;
1084 //
1085 // Handle the file system interface to the device
1086 //
1087 Status = gBS->HandleProtocol (
1088 Device,
1089 &gEfiSimpleFileSystemProtocolGuid,
1090 (VOID *) &Volume
1091 );
1092 if (EFI_ERROR (Status)) {
1093 goto Done;
1094 }
1095
1096 Status = Volume->OpenVolume (
1097 Volume,
1098 &Root
1099 );
1100 if (EFI_ERROR (Status)) {
1101 goto Done;
1102 }
1103
1104 Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
1105 if (EFI_ERROR (Status)) {
1106 goto Done;
1107 }
1108
1109 //
1110 // Get file size
1111 //
1112 BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
1113 do {
1114 Info = NULL;
1115 Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
1116 if (EFI_ERROR (Status)) {
1117 goto Done;
1118 }
1119 Status = ThisFile->GetInfo (
1120 ThisFile,
1121 &gEfiFileInfoGuid,
1122 &BufferSize,
1123 Info
1124 );
1125 if (!EFI_ERROR (Status)) {
1126 break;
1127 }
1128 if (Status != EFI_BUFFER_TOO_SMALL) {
1129 goto Done;
1130 }
1131 gBS->FreePool (Info);
1132 } while (TRUE);
1133
1134 FileSize = Info->FileSize;
1135 gBS->FreePool (Info);
1136
1137 //
1138 // Read dos header
1139 //
1140 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
1141 Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
1142 if (EFI_ERROR (Status) ||
1143 BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
1144 FileSize <= DosHeader->e_lfanew ||
1145 DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1146 Status = EFI_LOAD_ERROR;
1147 goto Done;
1148 }
1149
1150 //
1151 // Move to PE signature
1152 //
1153 Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
1154 if (EFI_ERROR (Status)) {
1155 Status = EFI_LOAD_ERROR;
1156 goto Done;
1157 }
1158
1159 //
1160 // Read and check PE signature
1161 //
1162 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
1163 Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
1164 if (EFI_ERROR (Status) ||
1165 BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
1166 Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1167 Status = EFI_LOAD_ERROR;
1168 goto Done;
1169 }
1170
1171 //
1172 // Check PE32 or PE32+ magic
1173 //
1174 if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
1175 Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1176 Status = EFI_LOAD_ERROR;
1177 goto Done;
1178 }
1179
1180 Done:
1181 if (ThisFile != NULL) {
1182 ThisFile->Close (ThisFile);
1183 }
1184 if (Root != NULL) {
1185 Root->Close (Root);
1186 }
1187 return Status;
1188 }
1189
1190 #if (EFI_SPECIFICATION_VERSION < 0x0002000A)
1191 EFI_STATUS
1192 BdsLibGetHiiHandles (
1193 IN EFI_HII_PROTOCOL *Hii,
1194 IN OUT UINT16 *HandleBufferLength,
1195 OUT EFI_HII_HANDLE **HiiHandleBuffer
1196 )
1197 /*++
1198
1199 Routine Description:
1200
1201 Determines the handles that are currently active in the database.
1202 It's the caller's responsibility to free handle buffer.
1203
1204 Arguments:
1205
1206 This - A pointer to the EFI_HII_PROTOCOL instance.
1207 HandleBufferLength - On input, a pointer to the length of the handle buffer. On output,
1208 the length of the handle buffer that is required for the handles found.
1209 HiiHandleBuffer - Pointer to an array of EFI_HII_PROTOCOL instances returned.
1210
1211 Returns:
1212
1213 EFI_SUCCESS - Get an array of EFI_HII_PROTOCOL instances successfully.
1214 EFI_INVALID_PARAMETER - Hii is NULL.
1215 EFI_NOT_FOUND - Database not found.
1216
1217 --*/
1218 {
1219 UINT16 TempBufferLength;
1220 EFI_STATUS Status;
1221
1222 TempBufferLength = 0;
1223
1224 //
1225 // Try to find the actual buffer size for HiiHandle Buffer.
1226 //
1227 Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer);
1228
1229 if (Status == EFI_BUFFER_TOO_SMALL) {
1230 *HiiHandleBuffer = AllocateZeroPool (TempBufferLength);
1231 Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer);
1232 //
1233 // we should not fail here.
1234 //
1235 ASSERT_EFI_ERROR (Status);
1236 }
1237
1238 *HandleBufferLength = TempBufferLength;
1239
1240 return Status;
1241
1242 }
1243 #endif
1244
1245 VOID
1246 EFIAPI
1247 BdsSetMemoryTypeInformationVariable (
1248 EFI_EVENT Event,
1249 VOID *Context
1250 )
1251 /*++
1252
1253 Routine Description:
1254
1255 This routine is a notification function for legayc boot or exit boot
1256 service event. It will adjust the memory information for different
1257 memory type and save them into the variables for next boot
1258
1259 Arguments:
1260
1261 Event - The event that triggered this notification function
1262 Context - Pointer to the notification functions context
1263
1264 Returns:
1265
1266 None.
1267
1268 --*/
1269 {
1270 EFI_STATUS Status;
1271 EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;
1272 EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;
1273 UINTN VariableSize;
1274 BOOLEAN UpdateRequired;
1275 UINTN Index;
1276 UINTN Index1;
1277 UINT32 Previous;
1278 UINT32 Current;
1279 UINT32 Next;
1280 VOID *HobList;
1281
1282 UpdateRequired = FALSE;
1283
1284 //
1285 // Retrieve the current memory usage statistics. If they are not found, then
1286 // no adjustments can be made to the Memory Type Information variable.
1287 //
1288 Status = EfiGetSystemConfigurationTable (
1289 &gEfiMemoryTypeInformationGuid,
1290 (VOID **) &CurrentMemoryTypeInformation
1291 );
1292 if (EFI_ERROR (Status)) {
1293 return;
1294 }
1295
1296 //
1297 // Get the Memory Type Information settings from Hob if they exist,
1298 // PEI is responsible for getting them from variable and build a Hob to save them.
1299 // If the previous Memory Type Information is not available, then set defaults
1300 //
1301 EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
1302 Status = R8_GetNextGuidHob (&HobList, &gEfiMemoryTypeInformationGuid, (VOID **) &PreviousMemoryTypeInformation, &VariableSize);
1303 if (EFI_ERROR (Status) || PreviousMemoryTypeInformation == NULL) {
1304 //
1305 // If Platform has not built Memory Type Info into the Hob, just return.
1306 //
1307 return;
1308 }
1309
1310 //
1311 // Use a heuristic to adjust the Memory Type Information for the next boot
1312 //
1313 for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
1314
1315 Current = 0;
1316 for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
1317 if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
1318 Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;
1319 break;
1320 }
1321 }
1322
1323 if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
1324 continue;
1325 }
1326
1327 Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
1328
1329 //
1330 // Write next varible to 125% * current and Inconsistent Memory Reserved across bootings may lead to S4 fail
1331 //
1332 if (Current > Previous) {
1333 Next = Current + (Current >> 2);
1334 } else {
1335 Next = Previous;
1336 }
1337 if (Next > 0 && Next < 4) {
1338 Next = 4;
1339 }
1340
1341 if (Next != Previous) {
1342 PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
1343 UpdateRequired = TRUE;
1344 }
1345
1346 }
1347
1348 //
1349 // If any changes were made to the Memory Type Information settings, then set the new variable value
1350 //
1351 if (UpdateRequired) {
1352 Status = gRT->SetVariable (
1353 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
1354 &gEfiMemoryTypeInformationGuid,
1355 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1356 VariableSize,
1357 PreviousMemoryTypeInformation
1358 );
1359 }
1360
1361 return;
1362 }
1363
1364
1365 /**
1366 This routine register a function to adjust the different type memory page number just before booting
1367 and save the updated info into the variable for next boot to use
1368
1369 None
1370
1371 @return None.
1372
1373 **/
1374 VOID
1375 EFIAPI
1376 BdsLibSaveMemoryTypeInformation (
1377 VOID
1378 )
1379 {
1380 EFI_STATUS Status;
1381 EFI_EVENT ReadyToBootEvent;
1382
1383 Status = EfiCreateEventReadyToBootEx (
1384 TPL_CALLBACK,
1385 BdsSetMemoryTypeInformationVariable,
1386 NULL,
1387 &ReadyToBootEvent
1388 );
1389 if (EFI_ERROR (Status)) {
1390 DEBUG ((DEBUG_ERROR,"Bds Set Memory Type Informationa Variable Fails\n"));
1391 }
1392
1393 }
1394
1395
1396 /**
1397 return the current TPL, copied from the EDKII glue lib.
1398
1399 VOID
1400
1401 @return Current TPL
1402
1403 **/
1404 EFI_TPL
1405 BdsLibGetCurrentTpl (
1406 VOID
1407 )
1408 {
1409 EFI_TPL Tpl;
1410
1411 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
1412 gBS->RestoreTPL (Tpl);
1413
1414 return Tpl;
1415 }