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