]> git.proxmox.com Git - mirror_edk2.git/blame - Nt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c
1) Remove Protocol/AcpiS3Save.h from IntelFrameworkPkg, which should be defined in...
[mirror_edk2.git] / Nt32Pkg / Library / EdkGenericBdsLib / BdsBoot.c
CommitLineData
869f8e34 1/*++\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 BdsBoot.c\r
15\r
16Abstract:\r
17\r
18 BDS Lib functions which relate with create or process the boot\r
19 option.\r
20\r
21--*/\r
869f8e34 22\r
f2569572 23#include <EdkGenericBdsLibInternal.h>\r
869f8e34 24\r
25BOOLEAN mEnumBootDevice = FALSE;\r
26\r
27EFI_STATUS\r
28BdsLibDoLegacyBoot (\r
29 IN BDS_COMMON_OPTION *Option\r
30 )\r
31/*++\r
32\r
33Routine Description:\r
34\r
35 Boot the legacy system with the boot option\r
36\r
37Arguments:\r
38\r
39 Option - The legacy boot option which have BBS device path\r
40\r
41Returns:\r
42\r
43 EFI_UNSUPPORTED - There is no legacybios protocol, do not support\r
44 legacy boot.\r
45\r
46 EFI_STATUS - Return the status of LegacyBios->LegacyBoot ().\r
47\r
48--*/\r
49{\r
50 EFI_STATUS Status;\r
51 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
52\r
53 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios);\r
54 if (EFI_ERROR (Status)) {\r
55 //\r
56 // If no LegacyBios protocol we do not support legacy boot\r
57 //\r
58 return EFI_UNSUPPORTED;\r
59 }\r
60 //\r
61 // Notes: if we seperate the int 19, then we don't need to refresh BBS\r
62 //\r
63 BdsRefreshBbsTableForBoot (Option);\r
64\r
65 //\r
66 // Write boot to OS performance data to a file\r
67 //\r
68 PERF_CODE (\r
69 WriteBootToOsPerformanceData ();\r
70 );\r
71\r
72\r
73 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description));\r
74 return LegacyBios->LegacyBoot (\r
75 LegacyBios,\r
76 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,\r
77 Option->LoadOptionsSize,\r
78 Option->LoadOptions\r
79 );\r
80}\r
81\r
82EFI_STATUS\r
83BdsLibBootViaBootOption (\r
84 IN BDS_COMMON_OPTION * Option,\r
85 IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,\r
86 OUT UINTN *ExitDataSize,\r
87 OUT CHAR16 **ExitData OPTIONAL\r
88 )\r
89/*++\r
90\r
91Routine Description:\r
92\r
93 Process the boot option follow the EFI 1.1 specification and\r
94 special treat the legacy boot option with BBS_DEVICE_PATH.\r
95\r
96Arguments:\r
97\r
98 Option - The boot option need to be processed\r
99\r
100 DevicePath - The device path which describe where to load\r
101 the boot image or the legcy BBS device path\r
102 to boot the legacy OS\r
103\r
104 ExitDataSize - Returned directly from gBS->StartImage ()\r
105\r
106 ExitData - Returned directly from gBS->StartImage ()\r
107\r
108Returns:\r
109\r
110 EFI_SUCCESS - Status from gBS->StartImage (),\r
111 or BdsBootByDiskSignatureAndPartition ()\r
112\r
113 EFI_NOT_FOUND - If the Device Path is not found in the system\r
114\r
115--*/\r
116{\r
117 EFI_STATUS Status;\r
118 EFI_HANDLE Handle;\r
119 EFI_HANDLE ImageHandle;\r
120 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
121 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
122 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
869f8e34 123 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
124 VOID *Buffer;\r
125\r
126 //\r
127 // Record the performance data for End of BDS\r
128 //\r
129 PERF_END (0, BDS_TOK, NULL, 0);\r
130\r
131 *ExitDataSize = 0;\r
132 *ExitData = NULL;\r
133\r
134 //\r
135 // Notes: put EFI64 ROM Shadow Solution\r
136 //\r
137 EFI64_SHADOW_ALL_LEGACY_ROM ();\r
138\r
869f8e34 139 //\r
140 // If it's Device Path that starts with a hard drive path,\r
141 // this routine will do the booting.\r
142 //\r
143 Status = BdsBootByDiskSignatureAndPartition (\r
144 Option,\r
145 (HARDDRIVE_DEVICE_PATH *) DevicePath,\r
146 Option->LoadOptionsSize,\r
147 Option->LoadOptions,\r
148 ExitDataSize,\r
149 ExitData\r
150 );\r
151 if (!EFI_ERROR (Status)) {\r
152 //\r
153 // If we found a disk signature and partition device path return success\r
154 //\r
155 return EFI_SUCCESS;\r
156 }\r
157 //\r
158 // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event\r
159 //\r
160 EfiSignalEventReadyToBoot ();\r
161\r
162 //\r
163 // Set Boot Current\r
164 //\r
165 gRT->SetVariable (\r
166 L"BootCurrent",\r
167 &gEfiGlobalVariableGuid,\r
168 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
169 sizeof (UINT16),\r
170 &Option->BootCurrent\r
171 );\r
172\r
173 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&\r
174 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)\r
175 ) {\r
176 //\r
177 // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
178 //\r
179 return BdsLibDoLegacyBoot (Option);\r
180 }\r
181\r
182 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description));\r
183\r
184 Status = gBS->LoadImage (\r
185 TRUE,\r
186 mBdsImageHandle,\r
187 DevicePath,\r
188 NULL,\r
189 0,\r
190 &ImageHandle\r
191 );\r
192\r
193 //\r
194 // If we didn't find an image, we may need to load the default\r
195 // boot behavior for the device.\r
196 //\r
197 if (EFI_ERROR (Status)) {\r
198 //\r
199 // Find a Simple File System protocol on the device path. If the remaining\r
200 // device path is set to end then no Files are being specified, so try\r
201 // the removable media file name.\r
202 //\r
203 TempDevicePath = DevicePath;\r
204 Status = gBS->LocateDevicePath (\r
205 &gEfiSimpleFileSystemProtocolGuid,\r
206 &TempDevicePath,\r
207 &Handle\r
208 );\r
209 if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) {\r
210 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
211 if (FilePath) {\r
212 //\r
213 // Issue a dummy read to the device to check for media change.\r
214 // When the removable media is changed, any Block IO read/write will\r
215 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
216 // returned. After the Block IO protocol is reinstalled, subsequent\r
217 // Block IO read/write will success.\r
218 //\r
219 Status = gBS->HandleProtocol (\r
220 Handle,\r
221 &gEfiBlockIoProtocolGuid,\r
222 (VOID **) &BlkIo\r
223 );\r
224 if (!EFI_ERROR (Status)) {\r
225 Buffer = AllocatePool (BlkIo->Media->BlockSize);\r
226 if (Buffer != NULL) {\r
227 BlkIo->ReadBlocks (\r
228 BlkIo,\r
229 BlkIo->Media->MediaId,\r
230 0,\r
231 BlkIo->Media->BlockSize,\r
232 Buffer\r
233 );\r
234 FreePool (Buffer);\r
235 }\r
236 }\r
237\r
238 Status = gBS->LoadImage (\r
239 TRUE,\r
240 mBdsImageHandle,\r
241 FilePath,\r
242 NULL,\r
243 0,\r
244 &ImageHandle\r
245 );\r
246 if (EFI_ERROR (Status)) {\r
247 //\r
248 // The DevicePath failed, and it's not a valid\r
249 // removable media device.\r
250 //\r
251 goto Done;\r
252 }\r
253 }\r
254 } else {\r
255 Status = EFI_NOT_FOUND;\r
256 }\r
257 }\r
258\r
259 if (EFI_ERROR (Status)) {\r
260 //\r
261 // It there is any error from the Boot attempt exit now.\r
262 //\r
263 goto Done;\r
264 }\r
265 //\r
266 // Provide the image with it's load options\r
267 //\r
268 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo);\r
269 ASSERT_EFI_ERROR (Status);\r
270\r
271 if (Option->LoadOptionsSize != 0) {\r
272 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;\r
273 ImageInfo->LoadOptions = Option->LoadOptions;\r
274 }\r
275 //\r
276 // Before calling the image, enable the Watchdog Timer for\r
277 // the 5 Minute period\r
278 //\r
279 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
280\r
281 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);\r
282 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));\r
283\r
284 //\r
285 // Clear the Watchdog Timer after the image returns\r
286 //\r
287 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
288\r
289Done:\r
290 //\r
291 // Clear Boot Current\r
292 //\r
293 gRT->SetVariable (\r
294 L"BootCurrent",\r
295 &gEfiGlobalVariableGuid,\r
296 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
297 0,\r
298 &Option->BootCurrent\r
299 );\r
300\r
301 return Status;\r
302}\r
303\r
304EFI_STATUS\r
305BdsBootByDiskSignatureAndPartition (\r
306 IN BDS_COMMON_OPTION * Option,\r
307 IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath,\r
308 IN UINT32 LoadOptionsSize,\r
309 IN VOID *LoadOptions,\r
310 OUT UINTN *ExitDataSize,\r
311 OUT CHAR16 **ExitData OPTIONAL\r
312 )\r
313/*++\r
314\r
315Routine Description:\r
316\r
317 Check to see if a hard ware device path was passed in. If it was then search\r
318 all the block IO devices for the passed in hard drive device path.\r
319\r
320Arguments:\r
321\r
322 Option - The current processing boot option.\r
323\r
324 HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard\r
325 drive device path.\r
326\r
327 LoadOptionsSize - Passed into gBS->StartImage ()\r
328 via the loaded image protocol.\r
329\r
330 LoadOptions - Passed into gBS->StartImage ()\r
331 via the loaded image protocol.\r
332\r
333 ExitDataSize - returned directly from gBS->StartImage ()\r
334\r
335 ExitData - returned directly from gBS->StartImage ()\r
336\r
337Returns:\r
338\r
339 EFI_SUCCESS - Status from gBS->StartImage (),\r
340 or BootByDiskSignatureAndPartition ()\r
341\r
342 EFI_NOT_FOUND - If the Device Path is not found in the system\r
343\r
344--*/\r
345{\r
346 EFI_STATUS Status;\r
347 UINTN BlockIoHandleCount;\r
348 EFI_HANDLE *BlockIoBuffer;\r
349 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;\r
350 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePath;\r
351 HARDDRIVE_DEVICE_PATH *TmpHdPath;\r
352 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
353 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
354 UINTN Index;\r
355 BOOLEAN DevicePathMatch;\r
356 HARDDRIVE_DEVICE_PATH *TempPath;\r
357\r
358 *ExitDataSize = 0;\r
359 *ExitData = NULL;\r
360\r
361 if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&\r
362 (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))\r
363 ) {\r
364 //\r
365 // If the HardDriveDevicePath does not start with a Hard Drive Device Path\r
366 // exit.\r
367 //\r
368 return EFI_NOT_FOUND;\r
369 }\r
370 //\r
371 // The boot device have already been connected\r
372 //\r
373 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
374 if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {\r
375 //\r
376 // If there was an error or there are no device handles that support\r
377 // the BLOCK_IO Protocol, then return.\r
378 //\r
379 return EFI_NOT_FOUND;\r
380 }\r
381 //\r
382 // Loop through all the device handles that support the BLOCK_IO Protocol\r
383 //\r
384 for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
385\r
386 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);\r
387 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {\r
388 continue;\r
389 }\r
390 //\r
391 // Make PreviousDevicePath == the device path node before the end node\r
392 //\r
393 DevicePath = BlockIoDevicePath;\r
394 BlockIoHdDevicePath = NULL;\r
395\r
396 //\r
397 // find HardDriver device path node\r
398 //\r
399 while (!IsDevicePathEnd (DevicePath)) {\r
400 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
401 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)\r
402 ) {\r
403 BlockIoHdDevicePath = DevicePath;\r
404 break;\r
405 }\r
406\r
407 DevicePath = NextDevicePathNode (DevicePath);\r
408 }\r
409\r
410 if (BlockIoHdDevicePath == NULL) {\r
411 continue;\r
412 }\r
413 //\r
414 // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
415 //\r
416 DevicePathMatch = FALSE;\r
417\r
418 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath;\r
419 TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
420\r
421 //\r
422 // Only several fields will be checked. NOT whole NODE\r
423 //\r
424 if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber &&\r
425 TmpHdPath->MBRType == TempPath->MBRType &&\r
426 TmpHdPath->SignatureType == TempPath->SignatureType &&\r
427 CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) {\r
428 //\r
429 // Get the matched device path\r
430 //\r
431 DevicePathMatch = TRUE;\r
432 }\r
433 //\r
434 // Only do the boot, when devicepath match\r
435 //\r
436 if (DevicePathMatch) {\r
437 //\r
438 // Combine the Block IO and Hard Drive Device path together and try\r
439 // to boot from it.\r
440 //\r
441 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
442 NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);\r
443\r
444 //\r
445 // Recursive boot with new device path\r
446 //\r
447 Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData);\r
448 if (!EFI_ERROR (Status)) {\r
449 break;\r
450 }\r
451 }\r
452 }\r
453\r
454 FreePool (BlockIoBuffer);\r
455 return Status;\r
456}\r
457\r
458EFI_STATUS\r
459BdsLibDeleteOptionFromHandle (\r
460 IN EFI_HANDLE Handle\r
461 )\r
462/*++\r
463\r
464Routine Description:\r
465\r
466 Delete the boot option associated with the handle passed in\r
467\r
468Arguments:\r
469\r
470 Handle - The handle which present the device path to create boot option\r
471\r
472Returns:\r
473\r
474 EFI_SUCCESS - Delete the boot option success\r
475\r
476 EFI_NOT_FOUND - If the Device Path is not found in the system\r
477\r
478 EFI_OUT_OF_RESOURCES - Lack of memory resource\r
479\r
480 Other - Error return value from SetVariable()\r
481\r
482--*/\r
483{\r
484 UINT16 *BootOrder;\r
485 UINT8 *BootOptionVar;\r
486 UINTN BootOrderSize;\r
487 UINTN BootOptionSize;\r
488 EFI_STATUS Status;\r
489 UINTN Index;\r
490 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
491 UINTN DevicePathSize;\r
492 UINTN OptionDevicePathSize;\r
493 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
494 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
495 UINT8 *TempPtr;\r
496 CHAR16 *Description;\r
497\r
498 Status = EFI_SUCCESS;\r
499 BootOrder = NULL;\r
500 BootOrderSize = 0;\r
501\r
502 BootOrder = BdsLibGetVariableAndSize (\r
503 L"BootOrder",\r
504 &gEfiGlobalVariableGuid,\r
505 &BootOrderSize\r
506 );\r
507 if (NULL == BootOrder) {\r
508 return EFI_NOT_FOUND;\r
509 }\r
510\r
511 DevicePath = DevicePathFromHandle (Handle);\r
512 if (DevicePath == NULL) {\r
513 return EFI_NOT_FOUND;\r
514 }\r
515 DevicePathSize = GetDevicePathSize (DevicePath);\r
516\r
517 Index = 0;\r
518 while (Index < BootOrderSize / sizeof (UINT16)) {\r
519 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
520 BootOptionVar = BdsLibGetVariableAndSize (\r
521 BootOption,\r
522 &gEfiGlobalVariableGuid,\r
523 &BootOptionSize\r
524 );\r
525 if (NULL == BootOptionVar) {\r
526 FreePool (BootOrder);\r
527 return EFI_OUT_OF_RESOURCES;\r
528 }\r
529\r
530 TempPtr = BootOptionVar;\r
531 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
532 Description = (CHAR16 *) TempPtr;\r
533 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
534 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
535 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
536\r
537 //\r
538 // Check whether the device path match\r
539 //\r
540 if ((OptionDevicePathSize == DevicePathSize) &&\r
541 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {\r
542 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
543 FreePool (BootOptionVar);\r
544 break;\r
545 }\r
546\r
547 FreePool (BootOptionVar);\r
548 Index++;\r
549 }\r
550\r
551 Status = gRT->SetVariable (\r
552 L"BootOrder",\r
553 &gEfiGlobalVariableGuid,\r
554 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
555 BootOrderSize,\r
556 BootOrder\r
557 );\r
558\r
559 FreePool (BootOrder);\r
560\r
561 return Status;\r
562}\r
563\r
564EFI_STATUS\r
565BdsDeleteAllInvalidEfiBootOption (\r
566 VOID\r
567 )\r
568/*++\r
569\r
570Routine Description:\r
571\r
572 Delete all invalid EFI boot options. The probable invalid boot option could\r
573 be Removable media or Network boot device.\r
574\r
575Arguments:\r
576\r
577 VOID\r
578\r
579Returns:\r
580\r
581 EFI_SUCCESS - Delete all invalid boot option success\r
582\r
583 EFI_NOT_FOUND - Variable "BootOrder" is not found\r
584\r
585 EFI_OUT_OF_RESOURCES - Lack of memory resource\r
586\r
587 Other - Error return value from SetVariable()\r
588\r
589--*/\r
590{\r
591 UINT16 *BootOrder;\r
592 UINT8 *BootOptionVar;\r
593 UINTN BootOrderSize;\r
594 UINTN BootOptionSize;\r
595 EFI_STATUS Status;\r
596 UINTN Index;\r
597 UINTN Index2;\r
598 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
599 UINTN OptionDevicePathSize;\r
600 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
601 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
602 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
603 UINT8 *TempPtr;\r
604 CHAR16 *Description;\r
605 EFI_HANDLE Handle;\r
606 BOOLEAN NeedDelete;\r
607\r
608 Status = EFI_SUCCESS;\r
609 BootOrder = NULL;\r
610 BootOrderSize = 0;\r
611\r
612 BootOrder = BdsLibGetVariableAndSize (\r
613 L"BootOrder",\r
614 &gEfiGlobalVariableGuid,\r
615 &BootOrderSize\r
616 );\r
617 if (NULL == BootOrder) {\r
618 return EFI_NOT_FOUND;\r
619 }\r
620\r
621 Index = 0;\r
622 while (Index < BootOrderSize / sizeof (UINT16)) {\r
623 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
624 BootOptionVar = BdsLibGetVariableAndSize (\r
625 BootOption,\r
626 &gEfiGlobalVariableGuid,\r
627 &BootOptionSize\r
628 );\r
629 if (NULL == BootOptionVar) {\r
630 FreePool (BootOrder);\r
631 return EFI_OUT_OF_RESOURCES;\r
632 }\r
633\r
634 TempPtr = BootOptionVar;\r
635 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
636 Description = (CHAR16 *) TempPtr;\r
637 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
638 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
639 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
640\r
641 //\r
642 // Skip legacy boot option (BBS boot device)\r
643 //\r
644 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
645 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
646 FreePool (BootOptionVar);\r
647 Index++;\r
648 continue;\r
649 }\r
650\r
651 TempDevicePath = OptionDevicePath;\r
652 LastDeviceNode = OptionDevicePath;\r
653 while (!EfiIsDevicePathEnd (TempDevicePath)) {\r
654 LastDeviceNode = TempDevicePath;\r
655 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);\r
656 }\r
657 //\r
658 // Skip the boot option that point to a file, since the device path in\r
659 // removable media boot option doesn't contains a file name.\r
660 //\r
661 if (((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
662 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) ||\r
663 //\r
664 // Skip boot option for internal Shell, it's always valid\r
665 //\r
666 (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL)) {\r
667 FreePool (BootOptionVar);\r
668 Index++;\r
669 continue;\r
670 }\r
671\r
672 NeedDelete = TRUE;\r
673 //\r
674 // Check if it's a valid boot option for removable media\r
675 //\r
676 TempDevicePath = OptionDevicePath;\r
677 Status = gBS->LocateDevicePath (\r
678 &gEfiSimpleFileSystemProtocolGuid,\r
679 &TempDevicePath,\r
680 &Handle\r
681 );\r
682 if (!EFI_ERROR (Status)) {\r
683 NeedDelete = FALSE;\r
684 }\r
685 //\r
686 // Check if it's a valid boot option for network boot device\r
687 //\r
688 TempDevicePath = OptionDevicePath;\r
689 Status = gBS->LocateDevicePath (\r
690 &gEfiLoadFileProtocolGuid,\r
691 &TempDevicePath,\r
692 &Handle\r
693 );\r
694 if (!EFI_ERROR (Status)) {\r
695 NeedDelete = FALSE;\r
696 }\r
697\r
698 if (NeedDelete) {\r
699 //\r
700 // Delete this invalid boot option "Boot####"\r
701 //\r
702 Status = gRT->SetVariable (\r
703 BootOption,\r
704 &gEfiGlobalVariableGuid,\r
705 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
706 0,\r
707 NULL\r
708 );\r
709 //\r
710 // Mark this boot option in boot order as deleted\r
711 //\r
712 BootOrder[Index] = 0xffff;\r
713 }\r
714\r
715 FreePool (BootOptionVar);\r
716 Index++;\r
717 }\r
718\r
719 //\r
720 // Adjust boot order array\r
721 //\r
722 Index2 = 0;\r
723 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
724 if (BootOrder[Index] != 0xffff) {\r
725 BootOrder[Index2] = BootOrder[Index];\r
726 Index2 ++;\r
727 }\r
728 }\r
729 Status = gRT->SetVariable (\r
730 L"BootOrder",\r
731 &gEfiGlobalVariableGuid,\r
732 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
733 Index2 * sizeof (UINT16),\r
734 BootOrder\r
735 );\r
736\r
737 FreePool (BootOrder);\r
738\r
739 return Status;\r
740}\r
741\r
742EFI_STATUS\r
743BdsLibEnumerateAllBootOption (\r
744 IN OUT LIST_ENTRY *BdsBootOptionList\r
745 )\r
746/*++\r
747\r
748Routine Description:\r
749\r
750 This function will enumerate all possible boot device in the system,\r
751 it will only excute once of every boot.\r
752\r
753Arguments:\r
754\r
755 BdsBootOptionList - The header of the link list which indexed all\r
756 current boot options\r
757\r
758Returns:\r
759\r
760 EFI_SUCCESS - Finished all the boot device enumerate and create\r
761 the boot option base on that boot device\r
762\r
763--*/\r
764{\r
765 EFI_STATUS Status;\r
766 UINT16 BootOptionNumber;\r
767 UINTN NumberFileSystemHandles;\r
768 EFI_HANDLE *FileSystemHandles;\r
769 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
770 UINTN Index;\r
771 UINTN NumberLoadFileHandles;\r
772 EFI_HANDLE *LoadFileHandles;\r
773 VOID *ProtocolInstance;\r
774 EFI_FIRMWARE_VOLUME_PROTOCOL *Fv;\r
775 UINTN FvHandleCount;\r
776 EFI_HANDLE *FvHandleBuffer;\r
777 EFI_FV_FILETYPE Type;\r
778 UINTN Size;\r
779 EFI_FV_FILE_ATTRIBUTES Attributes;\r
780 UINT32 AuthenticationStatus;\r
781 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
782 EFI_HANDLE ImageHandle;\r
783 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
784 BOOLEAN NeedDelete;\r
785\r
786 BootOptionNumber = 0;\r
787\r
788 //\r
789 // If the boot device enumerate happened, just get the boot\r
790 // device from the boot order variable\r
791 //\r
792 if (mEnumBootDevice) {\r
793 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
794 return EFI_SUCCESS;\r
795 }\r
796 //\r
797 // Notes: this dirty code is to get the legacy boot option from the\r
798 // BBS table and create to variable as the EFI boot option, it should\r
799 // be removed after the CSM can provide legacy boot option directly\r
800 //\r
801 REFRESH_LEGACY_BOOT_OPTIONS;\r
802\r
803 //\r
804 // Delete invalid boot option\r
805 //\r
806 BdsDeleteAllInvalidEfiBootOption ();\r
807 //\r
808 // Parse removable media\r
809 //\r
810 gBS->LocateHandleBuffer (\r
811 ByProtocol,\r
812 &gEfiSimpleFileSystemProtocolGuid,\r
813 NULL,\r
814 &NumberFileSystemHandles,\r
815 &FileSystemHandles\r
816 );\r
817 for (Index = 0; Index < NumberFileSystemHandles; Index++) {\r
818 Status = gBS->HandleProtocol (\r
819 FileSystemHandles[Index],\r
820 &gEfiBlockIoProtocolGuid,\r
821 (VOID **) &BlkIo\r
822 );\r
823 if (!EFI_ERROR (Status)) {\r
824 if (!BlkIo->Media->RemovableMedia) {\r
825 //\r
826 // If the file system handle supports a BlkIo protocol,\r
827 // skip the removable media devices\r
828 //\r
829 continue;\r
830 }\r
831 }\r
832\r
833 //\r
834 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI\r
835 // machinename is ia32, ia64, x64, ...\r
836 //\r
837 FilePath = FileDevicePath (FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
838 NeedDelete = TRUE;\r
839 Status = gBS->LoadImage (\r
840 TRUE,\r
841 mBdsImageHandle,\r
842 FilePath,\r
843 NULL,\r
844 0,\r
845 &ImageHandle\r
846 );\r
847 if (!EFI_ERROR(Status)) {\r
848 //\r
849 // Verify the image is a EFI application (and not a driver)\r
850 //\r
851 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
852 ASSERT (!EFI_ERROR(Status));\r
853\r
854 if (ImageInfo->ImageCodeType == EfiLoaderCode) {\r
855 NeedDelete = FALSE;\r
856 }\r
857 }\r
858\r
859 if (NeedDelete) {\r
860 //\r
861 // No such file or the file is not a EFI application, delete this boot option\r
862 //\r
863 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);\r
864 } else {\r
865 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList);\r
866 BootOptionNumber++;\r
867 }\r
868 }\r
869\r
870 if (NumberFileSystemHandles) {\r
871 FreePool (FileSystemHandles);\r
872 }\r
873 //\r
874 // Parse Network Boot Device\r
875 //\r
876 gBS->LocateHandleBuffer (\r
877 ByProtocol,\r
878 &gEfiSimpleNetworkProtocolGuid,\r
879 NULL,\r
880 &NumberLoadFileHandles,\r
881 &LoadFileHandles\r
882 );\r
883 for (Index = 0; Index < NumberLoadFileHandles; Index++) {\r
884 Status = gBS->HandleProtocol (\r
885 LoadFileHandles[Index],\r
886 &gEfiLoadFileProtocolGuid,\r
887 (VOID **) &ProtocolInstance\r
888 );\r
889 if (EFI_ERROR (Status)) {\r
890 continue;\r
891 }\r
892\r
893 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList);\r
894 BootOptionNumber++;\r
895 }\r
896\r
897 if (NumberLoadFileHandles) {\r
898 FreePool (LoadFileHandles);\r
899 }\r
900 //\r
901 // Check if we have on flash shell\r
902 //\r
903 gBS->LocateHandleBuffer (\r
904 ByProtocol,\r
905 &gEfiFirmwareVolumeProtocolGuid,\r
906 NULL,\r
907 &FvHandleCount,\r
908 &FvHandleBuffer\r
909 );\r
910 for (Index = 0; Index < FvHandleCount; Index++) {\r
911 gBS->HandleProtocol (\r
912 FvHandleBuffer[Index],\r
913 &gEfiFirmwareVolumeProtocolGuid,\r
914 (VOID **) &Fv\r
915 );\r
916\r
917 Status = Fv->ReadFile (\r
918 Fv,\r
919 &gEfiShellFileGuid,\r
920 NULL,\r
921 &Size,\r
922 &Type,\r
923 &Attributes,\r
924 &AuthenticationStatus\r
925 );\r
926 if (EFI_ERROR (Status)) {\r
927 //\r
928 // Skip if no shell file in the FV\r
929 //\r
930 continue;\r
931 }\r
932 //\r
933 // Build the shell boot option\r
934 //\r
935 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);\r
936 BootOptionNumber++;\r
937 }\r
938\r
939 if (FvHandleCount) {\r
940 FreePool (FvHandleBuffer);\r
941 }\r
942 //\r
943 // Make sure every boot only have one time\r
944 // boot device enumerate\r
945 //\r
946 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
947 mEnumBootDevice = TRUE;\r
948\r
949 return EFI_SUCCESS;\r
950}\r
951\r
952VOID\r
953BdsLibBuildOptionFromHandle (\r
954 IN EFI_HANDLE Handle,\r
955 IN LIST_ENTRY *BdsBootOptionList\r
956 )\r
957/*++\r
958\r
959Routine Description:\r
960\r
961 Build the boot option with the handle parsed in\r
962\r
963Arguments:\r
964\r
965 Handle - The handle which present the device path to create boot option\r
966\r
967 BdsBootOptionList - The header of the link list which indexed all current\r
968 boot options\r
969\r
970Returns:\r
971\r
972 VOID\r
973\r
974--*/\r
975{\r
976 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
977 CHAR16 *TempString;\r
978\r
979 DevicePath = DevicePathFromHandle (Handle);\r
980 TempString = DevicePathToStr (DevicePath);\r
981\r
982 //\r
983 // Create and register new boot option\r
984 //\r
985 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder");\r
986}\r
987\r
988VOID\r
989BdsLibBuildOptionFromShell (\r
990 IN EFI_HANDLE Handle,\r
991 IN OUT LIST_ENTRY *BdsBootOptionList\r
992 )\r
993/*++\r
994\r
995Routine Description:\r
996\r
997 Build the on flash shell boot option with the handle parsed in\r
998\r
999Arguments:\r
1000\r
1001 Handle - The handle which present the device path to create on flash shell\r
1002 boot option\r
1003\r
1004 BdsBootOptionList - The header of the link list which indexed all current\r
1005 boot options\r
1006\r
1007Returns:\r
1008\r
1009 None\r
1010\r
1011--*/\r
1012{\r
1013 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1014 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;\r
1015\r
1016 DevicePath = DevicePathFromHandle (Handle);\r
1017\r
1018 //\r
1019 // Build the shell device path\r
1020 //\r
1021 EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);\r
1022 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);\r
1023\r
1024 //\r
1025 // Create and register the shell boot option\r
1026 //\r
1027 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder");\r
1028\r
1029}\r
1030\r
1031VOID\r
1032BdsLibBootNext (\r
1033 VOID\r
1034 )\r
1035/*++\r
1036\r
1037Routine Description:\r
1038\r
1039 Boot from the EFI1.1 spec defined "BootNext" variable\r
1040\r
1041Arguments:\r
1042\r
1043 None\r
1044\r
1045Returns:\r
1046\r
1047 None\r
1048\r
1049--*/\r
1050{\r
1051 UINT16 *BootNext;\r
1052 UINTN BootNextSize;\r
1053 CHAR16 Buffer[20];\r
1054 BDS_COMMON_OPTION *BootOption;\r
1055 LIST_ENTRY TempList;\r
1056 UINTN ExitDataSize;\r
1057 CHAR16 *ExitData;\r
1058\r
1059 //\r
1060 // Init the boot option name buffer and temp link list\r
1061 //\r
1062 InitializeListHead (&TempList);\r
1063 ZeroMem (Buffer, sizeof (Buffer));\r
1064\r
1065 BootNext = BdsLibGetVariableAndSize (\r
1066 L"BootNext",\r
1067 &gEfiGlobalVariableGuid,\r
1068 &BootNextSize\r
1069 );\r
1070\r
1071 //\r
1072 // Clear the boot next variable first\r
1073 //\r
1074 if (BootNext != NULL) {\r
1075 gRT->SetVariable (\r
1076 L"BootNext",\r
1077 &gEfiGlobalVariableGuid,\r
1078 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1079 0,\r
1080 BootNext\r
1081 );\r
1082\r
1083 //\r
1084 // Start to build the boot option and try to boot\r
1085 //\r
1086 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);\r
1087 BootOption = BdsLibVariableToOption (&TempList, Buffer);\r
1088 BdsLibConnectDevicePath (BootOption->DevicePath);\r
1089 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
1090 }\r
1091\r
1092}\r