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