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