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