]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/GenericBdsLib/BdsMisc.c
Fix a bug introduced when removing the SafeFreePool. Pointer should be checked before...
[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 if (TempOptionPtr != NULL) {
309 FreePool (TempOptionPtr);
310 }
311 return EFI_SUCCESS;
312 } else {
313 //
314 // Option description changed, need update.
315 //
316 UpdateDescription = TRUE;
317 FreePool (OptionPtr);
318 break;
319 }
320 }
321
322 FreePool (OptionPtr);
323 }
324
325 OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);
326 OptionSize += GetDevicePathSize (DevicePath);
327 OptionPtr = AllocateZeroPool (OptionSize);
328 ASSERT (OptionPtr != NULL);
329
330 TempPtr = OptionPtr;
331 *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
332 TempPtr += sizeof (UINT32);
333 *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
334 TempPtr += sizeof (UINT16);
335 CopyMem (TempPtr, String, StrSize (String));
336 TempPtr += StrSize (String);
337 CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
338
339 if (UpdateDescription) {
340 //
341 // The number in option#### to be updated
342 //
343 RegisterOptionNumber = TempOptionPtr[Index];
344 } else {
345 //
346 // The new option#### number
347 //
348 RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);
349 }
350
351 if (*VariableName == 'B') {
352 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
353 } else {
354 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
355 }
356
357 Status = gRT->SetVariable (
358 OptionName,
359 &gEfiGlobalVariableGuid,
360 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
361 OptionSize,
362 OptionPtr
363 );
364 //
365 // Return if only need to update a changed description or fail to set option.
366 //
367 if (EFI_ERROR (Status) || UpdateDescription) {
368 FreePool (OptionPtr);
369 if (TempOptionPtr != NULL) {
370 FreePool (TempOptionPtr);
371 }
372 return Status;
373 }
374
375 FreePool (OptionPtr);
376
377 //
378 // Update the option order variable
379 //
380
381 //
382 // If no option order
383 //
384 if (TempOptionSize == 0) {
385 BootOrderEntry = 0;
386 Status = gRT->SetVariable (
387 VariableName,
388 &gEfiGlobalVariableGuid,
389 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
390 sizeof (UINT16),
391 &BootOrderEntry
392 );
393 if (TempOptionPtr != NULL) {
394 FreePool (TempOptionPtr);
395 }
396 return Status;
397 }
398
399 //
400 // Append the new option number to the original option order
401 //
402 OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;
403 OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
404 ASSERT (OptionOrderPtr!= NULL);
405
406 CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));
407
408 OptionOrderPtr[Index] = RegisterOptionNumber;
409
410 Status = gRT->SetVariable (
411 VariableName,
412 &gEfiGlobalVariableGuid,
413 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
414 OrderItemNum * sizeof (UINT16),
415 OptionOrderPtr
416 );
417 FreePool (TempOptionPtr);
418 FreePool (OptionOrderPtr);
419
420 return Status;
421 }
422
423
424 /**
425 Build the boot#### or driver#### option from the VariableName, the
426 build boot#### or driver#### will also be linked to BdsCommonOptionList.
427
428 @param BdsCommonOptionList The header of the boot#### or driver#### option
429 link list
430 @param VariableName EFI Variable name indicate if it is boot#### or
431 driver####
432
433 @retval BDS_COMMON_OPTION Get the option just been created
434 @retval NULL Failed to get the new option
435
436 **/
437 BDS_COMMON_OPTION *
438 EFIAPI
439 BdsLibVariableToOption (
440 IN OUT LIST_ENTRY *BdsCommonOptionList,
441 IN CHAR16 *VariableName
442 )
443 {
444 UINT32 Attribute;
445 UINT16 FilePathSize;
446 UINT8 *Variable;
447 UINT8 *TempPtr;
448 UINTN VariableSize;
449 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
450 BDS_COMMON_OPTION *Option;
451 VOID *LoadOptions;
452 UINT32 LoadOptionsSize;
453 CHAR16 *Description;
454 UINT8 NumOff;
455 //
456 // Read the variable. We will never free this data.
457 //
458 Variable = BdsLibGetVariableAndSize (
459 VariableName,
460 &gEfiGlobalVariableGuid,
461 &VariableSize
462 );
463 if (Variable == NULL) {
464 return NULL;
465 }
466 //
467 // Notes: careful defined the variable of Boot#### or
468 // Driver####, consider use some macro to abstract the code
469 //
470 //
471 // Get the option attribute
472 //
473 TempPtr = Variable;
474 Attribute = *(UINT32 *) Variable;
475 TempPtr += sizeof (UINT32);
476
477 //
478 // Get the option's device path size
479 //
480 FilePathSize = *(UINT16 *) TempPtr;
481 TempPtr += sizeof (UINT16);
482
483 //
484 // Get the option's description string
485 //
486 Description = (CHAR16 *) TempPtr;
487
488 //
489 // Get the option's description string size
490 //
491 TempPtr += StrSize ((CHAR16 *) TempPtr);
492
493 //
494 // Get the option's device path
495 //
496 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
497 TempPtr += FilePathSize;
498
499 LoadOptions = TempPtr;
500 LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
501
502 //
503 // The Console variables may have multiple device paths, so make
504 // an Entry for each one.
505 //
506 Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
507 if (Option == NULL) {
508 return NULL;
509 }
510
511 Option->Signature = BDS_LOAD_OPTION_SIGNATURE;
512 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
513 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
514 Option->Attribute = Attribute;
515 Option->Description = AllocateZeroPool (StrSize (Description));
516 CopyMem (Option->Description, Description, StrSize (Description));
517 Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
518 CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
519 Option->LoadOptionsSize = LoadOptionsSize;
520
521 //
522 // Get the value from VariableName Unicode string
523 // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
524 // Unicode stream to ASCII without any loss in meaning.
525 //
526 if (*VariableName == 'B') {
527 NumOff = sizeof (L"Boot")/sizeof(CHAR16) -1 ;
528 Option->BootCurrent = (UINT16) ((VariableName[NumOff] -'0') * 0x1000);
529 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100));
530 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+2]-'0') * 0x10));
531 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0')));
532 }
533 //
534 // Insert active entry to BdsDeviceList
535 //
536 if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {
537 InsertTailList (BdsCommonOptionList, &Option->Link);
538 FreePool (Variable);
539 return Option;
540 }
541
542 FreePool (Variable);
543 FreePool (Option);
544 return NULL;
545
546 }
547
548 /**
549 Process BootOrder, or DriverOrder variables, by calling
550 BdsLibVariableToOption () for each UINT16 in the variables.
551
552 @param BdsCommonOptionList The header of the option list base on variable
553 VariableName
554 @param VariableName EFI Variable name indicate the BootOrder or
555 DriverOrder
556
557 @retval EFI_SUCCESS Success create the boot option or driver option
558 list
559 @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or driver option list
560
561 **/
562 EFI_STATUS
563 EFIAPI
564 BdsLibBuildOptionFromVar (
565 IN LIST_ENTRY *BdsCommonOptionList,
566 IN CHAR16 *VariableName
567 )
568 {
569 UINT16 *OptionOrder;
570 UINTN OptionOrderSize;
571 UINTN Index;
572 BDS_COMMON_OPTION *Option;
573 CHAR16 OptionName[20];
574
575 //
576 // Zero Buffer in order to get all BOOT#### variables
577 //
578 ZeroMem (OptionName, sizeof (OptionName));
579
580 //
581 // Read the BootOrder, or DriverOrder variable.
582 //
583 OptionOrder = BdsLibGetVariableAndSize (
584 VariableName,
585 &gEfiGlobalVariableGuid,
586 &OptionOrderSize
587 );
588 if (OptionOrder == NULL) {
589 return EFI_OUT_OF_RESOURCES;
590 }
591
592 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
593 if (*VariableName == 'B') {
594 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
595 } else {
596 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
597 }
598
599 Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
600 Option->BootCurrent = OptionOrder[Index];
601
602 }
603
604 FreePool (OptionOrder);
605
606 return EFI_SUCCESS;
607 }
608
609 /**
610 Get boot mode by looking up configuration table and parsing HOB list
611
612 @param BootMode Boot mode from PEI handoff HOB.
613
614 @retval EFI_SUCCESS Successfully get boot mode
615
616 **/
617 EFI_STATUS
618 EFIAPI
619 BdsLibGetBootMode (
620 OUT EFI_BOOT_MODE *BootMode
621 )
622 {
623 *BootMode = GetBootModeHob ();
624
625 return EFI_SUCCESS;
626 }
627
628 /**
629 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
630 buffer, and the size of the buffer. If failure return NULL.
631
632 @param Name String part of EFI variable name
633 @param VendorGuid GUID part of EFI variable name
634 @param VariableSize Returns the size of the EFI variable that was read
635
636 @return Dynamically allocated memory that contains a copy of the EFI variable.
637 @return Caller is responsible freeing the buffer.
638 @retval NULL Variable was not read
639
640 **/
641 VOID *
642 EFIAPI
643 BdsLibGetVariableAndSize (
644 IN CHAR16 *Name,
645 IN EFI_GUID *VendorGuid,
646 OUT UINTN *VariableSize
647 )
648 {
649 EFI_STATUS Status;
650 UINTN BufferSize;
651 VOID *Buffer;
652
653 Buffer = NULL;
654
655 //
656 // Pass in a zero size buffer to find the required buffer size.
657 //
658 BufferSize = 0;
659 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
660 if (Status == EFI_BUFFER_TOO_SMALL) {
661 //
662 // Allocate the buffer to return
663 //
664 Buffer = AllocateZeroPool (BufferSize);
665 if (Buffer == NULL) {
666 return NULL;
667 }
668 //
669 // Read variable into the allocated buffer.
670 //
671 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
672 if (EFI_ERROR (Status)) {
673 BufferSize = 0;
674 }
675 }
676
677 *VariableSize = BufferSize;
678 return Buffer;
679 }
680
681 /**
682 Delete the instance in Multi which matches partly with Single instance
683
684 @param Multi A pointer to a multi-instance device path data
685 structure.
686 @param Single A pointer to a single-instance device path data
687 structure.
688
689 @return This function will remove the device path instances in Multi which partly
690 match with the Single, and return the result device path. If there is no
691 remaining device path as a result, this function will return NULL.
692
693 **/
694 EFI_DEVICE_PATH_PROTOCOL *
695 EFIAPI
696 BdsLibDelPartMatchInstance (
697 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
698 IN EFI_DEVICE_PATH_PROTOCOL *Single
699 )
700 {
701 EFI_DEVICE_PATH_PROTOCOL *Instance;
702 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
703 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
704 UINTN InstanceSize;
705 UINTN SingleDpSize;
706 UINTN Size;
707
708 NewDevicePath = NULL;
709 TempNewDevicePath = NULL;
710
711 if (Multi == NULL || Single == NULL) {
712 return Multi;
713 }
714
715 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
716 SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
717 InstanceSize -= END_DEVICE_PATH_LENGTH;
718
719 while (Instance != NULL) {
720
721 Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;
722
723 if ((CompareMem (Instance, Single, Size) != 0)) {
724 //
725 // Append the device path instance which does not match with Single
726 //
727 TempNewDevicePath = NewDevicePath;
728 NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
729 if (TempNewDevicePath != NULL) {
730 FreePool(TempNewDevicePath);
731 }
732 }
733 FreePool(Instance);
734 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
735 InstanceSize -= END_DEVICE_PATH_LENGTH;
736 }
737
738 return NewDevicePath;
739 }
740
741 /**
742 Function compares a device path data structure to that of all the nodes of a
743 second device path instance.
744
745 @param Multi A pointer to a multi-instance device path data
746 structure.
747 @param Single A pointer to a single-instance device path data
748 structure.
749
750 @retval TRUE If the Single is contained within Multi
751 @retval FALSE The Single is not match within Multi
752
753 **/
754 BOOLEAN
755 EFIAPI
756 BdsLibMatchDevicePaths (
757 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
758 IN EFI_DEVICE_PATH_PROTOCOL *Single
759 )
760 {
761 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
762 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
763 UINTN Size;
764
765 if (Multi != NULL || Single != NULL) {
766 return FALSE;
767 }
768
769 DevicePath = Multi;
770 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
771
772 //
773 // Search for the match of 'Single' in 'Multi'
774 //
775 while (DevicePathInst != NULL) {
776 //
777 // If the single device path is found in multiple device paths,
778 // return success
779 //
780 if (CompareMem (Single, DevicePathInst, Size) == 0) {
781 FreePool (DevicePathInst);
782 return TRUE;
783 }
784
785 FreePool (DevicePathInst);
786 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
787 }
788
789 return FALSE;
790 }
791
792 /**
793 This function prints a series of strings.
794
795 @param ConOut Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
796 @param ... A variable argument list containing series of
797 strings, the last string must be NULL.
798
799 @retval EFI_SUCCESS Success print out the string using ConOut.
800 @retval EFI_STATUS Return the status of the ConOut->OutputString ().
801
802 **/
803 EFI_STATUS
804 EFIAPI
805 BdsLibOutputStrings (
806 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
807 ...
808 )
809 {
810 VA_LIST Args;
811 EFI_STATUS Status;
812 CHAR16 *String;
813
814 Status = EFI_SUCCESS;
815 VA_START (Args, ConOut);
816
817 while (!EFI_ERROR (Status)) {
818 //
819 // If String is NULL, then it's the end of the list
820 //
821 String = VA_ARG (Args, CHAR16 *);
822 if (String != NULL) {
823 break;
824 }
825
826 Status = ConOut->OutputString (ConOut, String);
827
828 if (EFI_ERROR (Status)) {
829 break;
830 }
831 }
832
833 return Status;
834 }
835
836 //
837 // Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
838 // Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if
839 // user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.
840 //
841
842
843 /**
844 Enable the setup browser reset reminder feature.
845 This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
846
847 **/
848 VOID
849 EFIAPI
850 EnableResetReminderFeature (
851 VOID
852 )
853 {
854 mFeaturerSwitch = TRUE;
855 }
856
857
858 /**
859 Disable the setup browser reset reminder feature.
860 This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
861
862 **/
863 VOID
864 EFIAPI
865 DisableResetReminderFeature (
866 VOID
867 )
868 {
869 mFeaturerSwitch = FALSE;
870 }
871
872
873 /**
874 Record the info that a reset is required.
875 A module boolean variable is used to record whether a reset is required.
876
877 **/
878 VOID
879 EFIAPI
880 EnableResetRequired (
881 VOID
882 )
883 {
884 mResetRequired = TRUE;
885 }
886
887
888 /**
889 Record the info that no reset is required.
890 A module boolean variable is used to record whether a reset is required.
891
892 **/
893 VOID
894 EFIAPI
895 DisableResetRequired (
896 VOID
897 )
898 {
899 mResetRequired = FALSE;
900 }
901
902
903 /**
904 Check whether platform policy enable the reset reminder feature. The default is enabled.
905
906 **/
907 BOOLEAN
908 EFIAPI
909 IsResetReminderFeatureEnable (
910 VOID
911 )
912 {
913 return mFeaturerSwitch;
914 }
915
916
917 /**
918 Check if user changed any option setting which needs a system reset to be effective.
919
920 **/
921 BOOLEAN
922 EFIAPI
923 IsResetRequired (
924 VOID
925 )
926 {
927 return mResetRequired;
928 }
929
930
931 /**
932 Check whether a reset is needed, and finish the reset reminder feature.
933 If a reset is needed, Popup a menu to notice user, and finish the feature
934 according to the user selection.
935
936 **/
937 VOID
938 EFIAPI
939 SetupResetReminder (
940 VOID
941 )
942 {
943 EFI_INPUT_KEY Key;
944 CHAR16 *StringBuffer1;
945 CHAR16 *StringBuffer2;
946
947
948 //
949 //check any reset required change is applied? if yes, reset system
950 //
951 if (IsResetReminderFeatureEnable ()) {
952 if (IsResetRequired ()) {
953
954 StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
955 ASSERT (StringBuffer1 != NULL);
956 StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
957 ASSERT (StringBuffer2 != NULL);
958 StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now ? ");
959 StrCpy (StringBuffer2, L"Enter (YES) / Esc (NO)");
960 //
961 // Popup a menu to notice user
962 //
963 do {
964 IfrLibCreatePopUp (2, &Key, StringBuffer1, StringBuffer2);
965 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
966
967 FreePool (StringBuffer1);
968 FreePool (StringBuffer2);
969 //
970 // If the user hits the YES Response key, reset
971 //
972 if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
973 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
974 }
975 gST->ConOut->ClearScreen (gST->ConOut);
976 }
977 }
978 }
979
980 /**
981 Get the headers (dos, image, optional header) from an image.
982
983 @param Device SimpleFileSystem device handle
984 @param FileName File name for the image
985 @param DosHeader Pointer to dos header
986 @param Hdr Pointer to optional header
987
988 @retval EFI_SUCCESS Successfully get the machine type.
989 @retval EFI_NOT_FOUND The file is not found.
990 @retval EFI_LOAD_ERROR File is not a valid image file.
991
992 **/
993 EFI_STATUS
994 EFIAPI
995 BdsLibGetImageHeader (
996 IN EFI_HANDLE Device,
997 IN CHAR16 *FileName,
998 OUT EFI_IMAGE_DOS_HEADER *DosHeader,
999 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
1000 )
1001 {
1002 EFI_STATUS Status;
1003 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
1004 EFI_FILE_HANDLE Root;
1005 EFI_FILE_HANDLE ThisFile;
1006 UINTN BufferSize;
1007 UINT64 FileSize;
1008 EFI_FILE_INFO *Info;
1009
1010 Root = NULL;
1011 ThisFile = NULL;
1012 //
1013 // Handle the file system interface to the device
1014 //
1015 Status = gBS->HandleProtocol (
1016 Device,
1017 &gEfiSimpleFileSystemProtocolGuid,
1018 (VOID *) &Volume
1019 );
1020 if (EFI_ERROR (Status)) {
1021 goto Done;
1022 }
1023
1024 Status = Volume->OpenVolume (
1025 Volume,
1026 &Root
1027 );
1028 if (EFI_ERROR (Status)) {
1029 Root = NULL;
1030 goto Done;
1031 }
1032
1033 Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
1034 if (EFI_ERROR (Status)) {
1035 goto Done;
1036 }
1037
1038 //
1039 // Get file size
1040 //
1041 BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
1042 do {
1043 Info = NULL;
1044 Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
1045 if (EFI_ERROR (Status)) {
1046 goto Done;
1047 }
1048 Status = ThisFile->GetInfo (
1049 ThisFile,
1050 &gEfiFileInfoGuid,
1051 &BufferSize,
1052 Info
1053 );
1054 if (!EFI_ERROR (Status)) {
1055 break;
1056 }
1057 if (Status != EFI_BUFFER_TOO_SMALL) {
1058 FreePool (Info);
1059 goto Done;
1060 }
1061 FreePool (Info);
1062 } while (TRUE);
1063
1064 FileSize = Info->FileSize;
1065 FreePool (Info);
1066
1067 //
1068 // Read dos header
1069 //
1070 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
1071 Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
1072 if (EFI_ERROR (Status) ||
1073 BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
1074 FileSize <= DosHeader->e_lfanew ||
1075 DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1076 Status = EFI_LOAD_ERROR;
1077 goto Done;
1078 }
1079
1080 //
1081 // Move to PE signature
1082 //
1083 Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
1084 if (EFI_ERROR (Status)) {
1085 Status = EFI_LOAD_ERROR;
1086 goto Done;
1087 }
1088
1089 //
1090 // Read and check PE signature
1091 //
1092 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
1093 Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
1094 if (EFI_ERROR (Status) ||
1095 BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
1096 Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1097 Status = EFI_LOAD_ERROR;
1098 goto Done;
1099 }
1100
1101 //
1102 // Check PE32 or PE32+ magic
1103 //
1104 if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
1105 Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1106 Status = EFI_LOAD_ERROR;
1107 goto Done;
1108 }
1109
1110 Done:
1111 if (ThisFile != NULL) {
1112 ThisFile->Close (ThisFile);
1113 }
1114 if (Root != NULL) {
1115 Root->Close (Root);
1116 }
1117 return Status;
1118 }
1119
1120 /**
1121
1122 This routine is a notification function for legayc boot or exit boot
1123 service event. It will adjust the memory information for different
1124 memory type and save them into the variables for next boot.
1125
1126
1127 @param Event The event that triggered this notification function.
1128 @param Context Pointer to the notification functions context.
1129
1130 **/
1131 VOID
1132 EFIAPI
1133 BdsSetMemoryTypeInformationVariable (
1134 EFI_EVENT Event,
1135 VOID *Context
1136 )
1137 {
1138 EFI_STATUS Status;
1139 EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;
1140 EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;
1141 UINTN VariableSize;
1142 BOOLEAN UpdateRequired;
1143 UINTN Index;
1144 UINTN Index1;
1145 UINT32 Previous;
1146 UINT32 Current;
1147 UINT32 Next;
1148 EFI_HOB_GUID_TYPE *GuidHob;
1149
1150 UpdateRequired = FALSE;
1151
1152 //
1153 // Retrieve the current memory usage statistics. If they are not found, then
1154 // no adjustments can be made to the Memory Type Information variable.
1155 //
1156 Status = EfiGetSystemConfigurationTable (
1157 &gEfiMemoryTypeInformationGuid,
1158 (VOID **) &CurrentMemoryTypeInformation
1159 );
1160 if (EFI_ERROR (Status)) {
1161 return;
1162 }
1163
1164 //
1165 // Get the Memory Type Information settings from Hob if they exist,
1166 // PEI is responsible for getting them from variable and build a Hob to save them.
1167 // If the previous Memory Type Information is not available, then set defaults
1168 //
1169 GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
1170 if (GuidHob == NULL) {
1171 //
1172 // If Platform has not built Memory Type Info into the Hob, just return.
1173 //
1174 return;
1175 }
1176 PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
1177 VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
1178
1179 //
1180 // Use a heuristic to adjust the Memory Type Information for the next boot
1181 //
1182 for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
1183
1184 Current = 0;
1185 for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
1186 if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
1187 Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;
1188 break;
1189 }
1190 }
1191
1192 if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
1193 continue;
1194 }
1195
1196 Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
1197
1198 //
1199 // Write next varible to 125% * current and Inconsistent Memory Reserved across bootings may lead to S4 fail
1200 //
1201 if (Current > Previous) {
1202 Next = Current + (Current >> 2);
1203 } else {
1204 Next = Previous;
1205 }
1206 if (Next > 0 && Next < 4) {
1207 Next = 4;
1208 }
1209
1210 if (Next != Previous) {
1211 PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
1212 UpdateRequired = TRUE;
1213 }
1214
1215 }
1216
1217 //
1218 // If any changes were made to the Memory Type Information settings, then set the new variable value
1219 //
1220 if (UpdateRequired) {
1221 Status = gRT->SetVariable (
1222 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
1223 &gEfiMemoryTypeInformationGuid,
1224 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1225 VariableSize,
1226 PreviousMemoryTypeInformation
1227 );
1228 }
1229
1230 return;
1231 }
1232
1233 /**
1234 This routine register a function to adjust the different type memory page number just before booting
1235 and save the updated info into the variable for next boot to use.
1236
1237 **/
1238 VOID
1239 EFIAPI
1240 BdsLibSaveMemoryTypeInformation (
1241 VOID
1242 )
1243 {
1244 EFI_STATUS Status;
1245 EFI_EVENT ReadyToBootEvent;
1246
1247 Status = EfiCreateEventReadyToBootEx (
1248 TPL_CALLBACK,
1249 BdsSetMemoryTypeInformationVariable,
1250 NULL,
1251 &ReadyToBootEvent
1252 );
1253 if (EFI_ERROR (Status)) {
1254 DEBUG ((DEBUG_ERROR,"Bds Set Memory Type Informationa Variable Fails\n"));
1255 }
1256
1257 }
1258
1259