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