]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c
Clean up: update "EFI" to "UEFI" if applicable.
[mirror_edk2.git] / Nt32Pkg / Library / EdkGenericBdsLib / BdsBoot.c
1 /*++
2
3 Copyright (c) 2006 - 2007, 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
23 #include "EdkGenericBdsLibInternal.h"
24
25 BOOLEAN mEnumBootDevice = FALSE;
26
27 EFI_STATUS
28 BdsLibDoLegacyBoot (
29 IN BDS_COMMON_OPTION *Option
30 )
31 /*++
32
33 Routine Description:
34
35 Boot the legacy system with the boot option
36
37 Arguments:
38
39 Option - The legacy boot option which have BBS device path
40
41 Returns:
42
43 EFI_UNSUPPORTED - There is no legacybios protocol, do not support
44 legacy boot.
45
46 EFI_STATUS - Return the status of LegacyBios->LegacyBoot ().
47
48 --*/
49 {
50 EFI_STATUS Status;
51 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
52
53 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &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 UEFI 2.0 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_BLOCK_IO_PROTOCOL *BlkIo;
124 VOID *Buffer;
125 LIST_ENTRY TempBootLists;
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 // If it's Device Path that starts with a hard drive path,
142 // this routine will do the booting.
143 //
144 Status = BdsBootByDiskSignatureAndPartition (
145 Option,
146 (HARDDRIVE_DEVICE_PATH *) DevicePath,
147 Option->LoadOptionsSize,
148 Option->LoadOptions,
149 ExitDataSize,
150 ExitData
151 );
152 if (!EFI_ERROR (Status)) {
153 //
154 // If we found a disk signature and partition device path return success
155 //
156 return EFI_SUCCESS;
157 }
158 //
159 // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event
160 //
161 EfiSignalEventReadyToBoot ();
162
163 //
164 // Set Boot Current
165 //
166 gRT->SetVariable (
167 L"BootCurrent",
168 &gEfiGlobalVariableGuid,
169 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
170 sizeof (UINT16),
171 &Option->BootCurrent
172 );
173
174 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
175 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
176 ) {
177 //
178 // Check to see if we should legacy BOOT. If yes then do the legacy boot
179 //
180 return BdsLibDoLegacyBoot (Option);
181 }
182
183 //
184 // If the boot option point to Internal FV shell, make sure it is valid
185 //
186 Status = UpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);
187 if (!EFI_ERROR(Status)) {
188 if (Option->DevicePath != NULL) {
189 FreePool (Option->DevicePath);
190 }
191 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
192 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
193 //
194 // Update the shell boot option
195 //
196 InitializeListHead (&TempBootLists);
197 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
198 }
199
200 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting UEFI 2.0 way %S\n", Option->Description));
201
202 Status = gBS->LoadImage (
203 TRUE,
204 mBdsImageHandle,
205 DevicePath,
206 NULL,
207 0,
208 &ImageHandle
209 );
210
211 //
212 // If we didn't find an image, we may need to load the default
213 // boot behavior for the device.
214 //
215 if (EFI_ERROR (Status)) {
216 //
217 // Find a Simple File System protocol on the device path. If the remaining
218 // device path is set to end then no Files are being specified, so try
219 // the removable media file name.
220 //
221 TempDevicePath = DevicePath;
222 Status = gBS->LocateDevicePath (
223 &gEfiSimpleFileSystemProtocolGuid,
224 &TempDevicePath,
225 &Handle
226 );
227 if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) {
228 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
229 if (FilePath) {
230 //
231 // Issue a dummy read to the device to check for media change.
232 // When the removable media is changed, any Block IO read/write will
233 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
234 // returned. After the Block IO protocol is reinstalled, subsequent
235 // Block IO read/write will success.
236 //
237 Status = gBS->HandleProtocol (
238 Handle,
239 &gEfiBlockIoProtocolGuid,
240 (VOID **) &BlkIo
241 );
242 if (!EFI_ERROR (Status)) {
243 Buffer = AllocatePool (BlkIo->Media->BlockSize);
244 if (Buffer != NULL) {
245 BlkIo->ReadBlocks (
246 BlkIo,
247 BlkIo->Media->MediaId,
248 0,
249 BlkIo->Media->BlockSize,
250 Buffer
251 );
252 FreePool (Buffer);
253 }
254 }
255
256 Status = gBS->LoadImage (
257 TRUE,
258 mBdsImageHandle,
259 FilePath,
260 NULL,
261 0,
262 &ImageHandle
263 );
264 if (EFI_ERROR (Status)) {
265 //
266 // The DevicePath failed, and it's not a valid
267 // removable media device.
268 //
269 goto Done;
270 }
271 }
272 } else {
273 Status = EFI_NOT_FOUND;
274 }
275 }
276
277 if (EFI_ERROR (Status)) {
278 //
279 // It there is any error from the Boot attempt exit now.
280 //
281 goto Done;
282 }
283 //
284 // Provide the image with it's load options
285 //
286 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo);
287 ASSERT_EFI_ERROR (Status);
288
289 if (Option->LoadOptionsSize != 0) {
290 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
291 ImageInfo->LoadOptions = Option->LoadOptions;
292 }
293 //
294 // Before calling the image, enable the Watchdog Timer for
295 // the 5 Minute period
296 //
297 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
298
299 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
300 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));
301
302 //
303 // Clear the Watchdog Timer after the image returns
304 //
305 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
306
307 Done:
308 //
309 // Clear Boot Current
310 //
311 gRT->SetVariable (
312 L"BootCurrent",
313 &gEfiGlobalVariableGuid,
314 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
315 0,
316 &Option->BootCurrent
317 );
318
319 return Status;
320 }
321
322 EFI_STATUS
323 BdsBootByDiskSignatureAndPartition (
324 IN BDS_COMMON_OPTION * Option,
325 IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath,
326 IN UINT32 LoadOptionsSize,
327 IN VOID *LoadOptions,
328 OUT UINTN *ExitDataSize,
329 OUT CHAR16 **ExitData OPTIONAL
330 )
331 /*++
332
333 Routine Description:
334
335 Check to see if a hard ware device path was passed in. If it was then search
336 all the block IO devices for the passed in hard drive device path.
337
338 Arguments:
339
340 Option - The current processing boot option.
341
342 HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard
343 drive device path.
344
345 LoadOptionsSize - Passed into gBS->StartImage ()
346 via the loaded image protocol.
347
348 LoadOptions - Passed into gBS->StartImage ()
349 via the loaded image protocol.
350
351 ExitDataSize - returned directly from gBS->StartImage ()
352
353 ExitData - returned directly from gBS->StartImage ()
354
355 Returns:
356
357 EFI_SUCCESS - Status from gBS->StartImage (),
358 or BootByDiskSignatureAndPartition ()
359
360 EFI_NOT_FOUND - If the Device Path is not found in the system
361
362 --*/
363 {
364 EFI_STATUS Status;
365 UINTN BlockIoHandleCount;
366 EFI_HANDLE *BlockIoBuffer;
367 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
368 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePath;
369 HARDDRIVE_DEVICE_PATH *TmpHdPath;
370 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
371 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
372 UINTN Index;
373 BOOLEAN DevicePathMatch;
374 HARDDRIVE_DEVICE_PATH *TempPath;
375
376 *ExitDataSize = 0;
377 *ExitData = NULL;
378
379 if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&
380 (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))
381 ) {
382 //
383 // If the HardDriveDevicePath does not start with a Hard Drive Device Path
384 // exit.
385 //
386 return EFI_NOT_FOUND;
387 }
388 //
389 // The boot device have already been connected
390 //
391 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
392 if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {
393 //
394 // If there was an error or there are no device handles that support
395 // the BLOCK_IO Protocol, then return.
396 //
397 return EFI_NOT_FOUND;
398 }
399 //
400 // Loop through all the device handles that support the BLOCK_IO Protocol
401 //
402 for (Index = 0; Index < BlockIoHandleCount; Index++) {
403
404 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
405 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
406 continue;
407 }
408 //
409 // Make PreviousDevicePath == the device path node before the end node
410 //
411 DevicePath = BlockIoDevicePath;
412 BlockIoHdDevicePath = NULL;
413
414 //
415 // find HardDriver device path node
416 //
417 while (!IsDevicePathEnd (DevicePath)) {
418 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
419 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
420 ) {
421 BlockIoHdDevicePath = DevicePath;
422 break;
423 }
424
425 DevicePath = NextDevicePathNode (DevicePath);
426 }
427
428 if (BlockIoHdDevicePath == NULL) {
429 continue;
430 }
431 //
432 // See if the harddrive device path in blockio matches the orig Hard Drive Node
433 //
434 DevicePathMatch = FALSE;
435
436 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath;
437 TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
438
439 //
440 // Only several fields will be checked. NOT whole NODE
441 //
442 if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber &&
443 TmpHdPath->MBRType == TempPath->MBRType &&
444 TmpHdPath->SignatureType == TempPath->SignatureType &&
445 CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) {
446 //
447 // Get the matched device path
448 //
449 DevicePathMatch = TRUE;
450 }
451 //
452 // Only do the boot, when devicepath match
453 //
454 if (DevicePathMatch) {
455 //
456 // Combine the Block IO and Hard Drive Device path together and try
457 // to boot from it.
458 //
459 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
460 NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
461
462 //
463 // Recursive boot with new device path
464 //
465 Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData);
466 if (!EFI_ERROR (Status)) {
467 break;
468 }
469 }
470 }
471
472 FreePool (BlockIoBuffer);
473 return Status;
474 }
475
476 EFI_STATUS
477 BdsLibDeleteOptionFromHandle (
478 IN EFI_HANDLE Handle
479 )
480 /*++
481
482 Routine Description:
483
484 Delete the boot option associated with the handle passed in
485
486 Arguments:
487
488 Handle - The handle which present the device path to create boot option
489
490 Returns:
491
492 EFI_SUCCESS - Delete the boot option success
493
494 EFI_NOT_FOUND - If the Device Path is not found in the system
495
496 EFI_OUT_OF_RESOURCES - Lack of memory resource
497
498 Other - Error return value from SetVariable()
499
500 --*/
501 {
502 UINT16 *BootOrder;
503 UINT8 *BootOptionVar;
504 UINTN BootOrderSize;
505 UINTN BootOptionSize;
506 EFI_STATUS Status;
507 UINTN Index;
508 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
509 UINTN DevicePathSize;
510 UINTN OptionDevicePathSize;
511 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
512 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
513 UINT8 *TempPtr;
514 CHAR16 *Description;
515
516 Status = EFI_SUCCESS;
517 BootOrder = NULL;
518 BootOrderSize = 0;
519
520 BootOrder = BdsLibGetVariableAndSize (
521 L"BootOrder",
522 &gEfiGlobalVariableGuid,
523 &BootOrderSize
524 );
525 if (NULL == BootOrder) {
526 return EFI_NOT_FOUND;
527 }
528
529 DevicePath = DevicePathFromHandle (Handle);
530 if (DevicePath == NULL) {
531 return EFI_NOT_FOUND;
532 }
533 DevicePathSize = GetDevicePathSize (DevicePath);
534
535 Index = 0;
536 while (Index < BootOrderSize / sizeof (UINT16)) {
537 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
538 BootOptionVar = BdsLibGetVariableAndSize (
539 BootOption,
540 &gEfiGlobalVariableGuid,
541 &BootOptionSize
542 );
543 if (NULL == BootOptionVar) {
544 FreePool (BootOrder);
545 return EFI_OUT_OF_RESOURCES;
546 }
547
548 TempPtr = BootOptionVar;
549 TempPtr += sizeof (UINT32) + sizeof (UINT16);
550 Description = (CHAR16 *) TempPtr;
551 TempPtr += StrSize ((CHAR16 *) TempPtr);
552 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
553 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
554
555 //
556 // Check whether the device path match
557 //
558 if ((OptionDevicePathSize == DevicePathSize) &&
559 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
560 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
561 FreePool (BootOptionVar);
562 break;
563 }
564
565 FreePool (BootOptionVar);
566 Index++;
567 }
568
569 Status = gRT->SetVariable (
570 L"BootOrder",
571 &gEfiGlobalVariableGuid,
572 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
573 BootOrderSize,
574 BootOrder
575 );
576
577 FreePool (BootOrder);
578
579 return Status;
580 }
581
582 EFI_STATUS
583 BdsDeleteAllInvalidEfiBootOption (
584 VOID
585 )
586 /*++
587
588 Routine Description:
589
590 Delete all invalid EFI boot options. The probable invalid boot option could
591 be Removable media or Network boot device.
592
593 Arguments:
594
595 VOID
596
597 Returns:
598
599 EFI_SUCCESS - Delete all invalid boot option success
600
601 EFI_NOT_FOUND - Variable "BootOrder" is not found
602
603 EFI_OUT_OF_RESOURCES - Lack of memory resource
604
605 Other - Error return value from SetVariable()
606
607 --*/
608 {
609 UINT16 *BootOrder;
610 UINT8 *BootOptionVar;
611 UINTN BootOrderSize;
612 UINTN BootOptionSize;
613 EFI_STATUS Status;
614 UINTN Index;
615 UINTN Index2;
616 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
617 UINTN OptionDevicePathSize;
618 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
619 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
620 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
621 UINT8 *TempPtr;
622 CHAR16 *Description;
623 EFI_HANDLE Handle;
624 BOOLEAN NeedDelete;
625
626 Status = EFI_SUCCESS;
627 BootOrder = NULL;
628 BootOrderSize = 0;
629
630 BootOrder = BdsLibGetVariableAndSize (
631 L"BootOrder",
632 &gEfiGlobalVariableGuid,
633 &BootOrderSize
634 );
635 if (NULL == BootOrder) {
636 return EFI_NOT_FOUND;
637 }
638
639 Index = 0;
640 while (Index < BootOrderSize / sizeof (UINT16)) {
641 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
642 BootOptionVar = BdsLibGetVariableAndSize (
643 BootOption,
644 &gEfiGlobalVariableGuid,
645 &BootOptionSize
646 );
647 if (NULL == BootOptionVar) {
648 FreePool (BootOrder);
649 return EFI_OUT_OF_RESOURCES;
650 }
651
652 TempPtr = BootOptionVar;
653 TempPtr += sizeof (UINT32) + sizeof (UINT16);
654 Description = (CHAR16 *) TempPtr;
655 TempPtr += StrSize ((CHAR16 *) TempPtr);
656 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
657 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
658
659 //
660 // Skip legacy boot option (BBS boot device)
661 //
662 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
663 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
664 FreePool (BootOptionVar);
665 Index++;
666 continue;
667 }
668
669 TempDevicePath = OptionDevicePath;
670 LastDeviceNode = OptionDevicePath;
671 while (!EfiIsDevicePathEnd (TempDevicePath)) {
672 LastDeviceNode = TempDevicePath;
673 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
674 }
675 //
676 // Skip the boot option that point to a file, since the device path in
677 // removable media boot option doesn't contains a file name.
678 //
679 if (((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
680 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) ||
681 //
682 // Skip boot option for internal Shell, it's always valid
683 //
684 (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL)) {
685 FreePool (BootOptionVar);
686 Index++;
687 continue;
688 }
689
690 NeedDelete = TRUE;
691 //
692 // Check if it's a valid boot option for removable media
693 //
694 TempDevicePath = OptionDevicePath;
695 Status = gBS->LocateDevicePath (
696 &gEfiSimpleFileSystemProtocolGuid,
697 &TempDevicePath,
698 &Handle
699 );
700 if (!EFI_ERROR (Status)) {
701 NeedDelete = FALSE;
702 }
703 //
704 // Check if it's a valid boot option for network boot device
705 //
706 TempDevicePath = OptionDevicePath;
707 Status = gBS->LocateDevicePath (
708 &gEfiLoadFileProtocolGuid,
709 &TempDevicePath,
710 &Handle
711 );
712 if (!EFI_ERROR (Status)) {
713 NeedDelete = FALSE;
714 }
715
716 if (NeedDelete) {
717 //
718 // Delete this invalid boot option "Boot####"
719 //
720 Status = gRT->SetVariable (
721 BootOption,
722 &gEfiGlobalVariableGuid,
723 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
724 0,
725 NULL
726 );
727 //
728 // Mark this boot option in boot order as deleted
729 //
730 BootOrder[Index] = 0xffff;
731 }
732
733 FreePool (BootOptionVar);
734 Index++;
735 }
736
737 //
738 // Adjust boot order array
739 //
740 Index2 = 0;
741 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
742 if (BootOrder[Index] != 0xffff) {
743 BootOrder[Index2] = BootOrder[Index];
744 Index2 ++;
745 }
746 }
747 Status = gRT->SetVariable (
748 L"BootOrder",
749 &gEfiGlobalVariableGuid,
750 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
751 Index2 * sizeof (UINT16),
752 BootOrder
753 );
754
755 FreePool (BootOrder);
756
757 return Status;
758 }
759
760 EFI_STATUS
761 BdsLibEnumerateAllBootOption (
762 IN OUT LIST_ENTRY *BdsBootOptionList
763 )
764 /*++
765
766 Routine Description:
767
768 This function will enumerate all possible boot device in the system,
769 it will only excute once of every boot.
770
771 Arguments:
772
773 BdsBootOptionList - The header of the link list which indexed all
774 current boot options
775
776 Returns:
777
778 EFI_SUCCESS - Finished all the boot device enumerate and create
779 the boot option base on that boot device
780
781 --*/
782 {
783 EFI_STATUS Status;
784 UINT16 BootOptionNumber;
785 UINTN NumberFileSystemHandles;
786 EFI_HANDLE *FileSystemHandles;
787 EFI_BLOCK_IO_PROTOCOL *BlkIo;
788 UINTN Index;
789 UINTN NumberLoadFileHandles;
790 EFI_HANDLE *LoadFileHandles;
791 VOID *ProtocolInstance;
792 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
793 UINTN FvHandleCount;
794 EFI_HANDLE *FvHandleBuffer;
795 EFI_FV_FILETYPE Type;
796 UINTN Size;
797 EFI_FV_FILE_ATTRIBUTES Attributes;
798 UINT32 AuthenticationStatus;
799 EFI_DEVICE_PATH_PROTOCOL *FilePath;
800 EFI_HANDLE ImageHandle;
801 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
802 BOOLEAN NeedDelete;
803
804 BootOptionNumber = 0;
805
806 //
807 // If the boot device enumerate happened, just get the boot
808 // device from the boot order variable
809 //
810 if (mEnumBootDevice) {
811 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
812 return EFI_SUCCESS;
813 }
814 //
815 // Notes: this dirty code is to get the legacy boot option from the
816 // BBS table and create to variable as the EFI boot option, it should
817 // be removed after the CSM can provide legacy boot option directly
818 //
819 REFRESH_LEGACY_BOOT_OPTIONS;
820
821 //
822 // Delete invalid boot option
823 //
824 BdsDeleteAllInvalidEfiBootOption ();
825 //
826 // Parse removable media
827 //
828 gBS->LocateHandleBuffer (
829 ByProtocol,
830 &gEfiSimpleFileSystemProtocolGuid,
831 NULL,
832 &NumberFileSystemHandles,
833 &FileSystemHandles
834 );
835 for (Index = 0; Index < NumberFileSystemHandles; Index++) {
836 Status = gBS->HandleProtocol (
837 FileSystemHandles[Index],
838 &gEfiBlockIoProtocolGuid,
839 (VOID **) &BlkIo
840 );
841 if (!EFI_ERROR (Status)) {
842 if (!BlkIo->Media->RemovableMedia) {
843 //
844 // If the file system handle supports a BlkIo protocol,
845 // skip the removable media devices
846 //
847 continue;
848 }
849 }
850
851 //
852 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
853 // machinename is ia32, ia64, x64, ...
854 //
855 FilePath = FileDevicePath (FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
856 NeedDelete = TRUE;
857 Status = gBS->LoadImage (
858 TRUE,
859 mBdsImageHandle,
860 FilePath,
861 NULL,
862 0,
863 &ImageHandle
864 );
865 if (!EFI_ERROR(Status)) {
866 //
867 // Verify the image is a EFI application (and not a driver)
868 //
869 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
870 ASSERT (!EFI_ERROR(Status));
871
872 if (ImageInfo->ImageCodeType == EfiLoaderCode) {
873 NeedDelete = FALSE;
874 }
875 }
876
877 if (NeedDelete) {
878 //
879 // No such file or the file is not a EFI application, delete this boot option
880 //
881 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
882 } else {
883 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList);
884 BootOptionNumber++;
885 }
886 }
887
888 if (NumberFileSystemHandles) {
889 FreePool (FileSystemHandles);
890 }
891 //
892 // Parse Network Boot Device
893 //
894 gBS->LocateHandleBuffer (
895 ByProtocol,
896 &gEfiSimpleNetworkProtocolGuid,
897 NULL,
898 &NumberLoadFileHandles,
899 &LoadFileHandles
900 );
901 for (Index = 0; Index < NumberLoadFileHandles; Index++) {
902 Status = gBS->HandleProtocol (
903 LoadFileHandles[Index],
904 &gEfiLoadFileProtocolGuid,
905 (VOID **) &ProtocolInstance
906 );
907 if (EFI_ERROR (Status)) {
908 continue;
909 }
910
911 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList);
912 BootOptionNumber++;
913 }
914
915 if (NumberLoadFileHandles) {
916 FreePool (LoadFileHandles);
917 }
918 //
919 // Check if we have on flash shell
920 //
921 gBS->LocateHandleBuffer (
922 ByProtocol,
923 &gEfiFirmwareVolume2ProtocolGuid,
924 NULL,
925 &FvHandleCount,
926 &FvHandleBuffer
927 );
928 for (Index = 0; Index < FvHandleCount; Index++) {
929 gBS->HandleProtocol (
930 FvHandleBuffer[Index],
931 &gEfiFirmwareVolume2ProtocolGuid,
932 (VOID **) &Fv
933 );
934
935 Status = Fv->ReadFile (
936 Fv,
937 &gEfiShellFileGuid,
938 NULL,
939 &Size,
940 &Type,
941 &Attributes,
942 &AuthenticationStatus
943 );
944 if (EFI_ERROR (Status)) {
945 //
946 // Skip if no shell file in the FV
947 //
948 continue;
949 }
950 //
951 // Build the shell boot option
952 //
953 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
954 BootOptionNumber++;
955 }
956
957 if (FvHandleCount) {
958 FreePool (FvHandleBuffer);
959 }
960 //
961 // Make sure every boot only have one time
962 // boot device enumerate
963 //
964 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
965 mEnumBootDevice = TRUE;
966
967 return EFI_SUCCESS;
968 }
969
970 VOID
971 BdsLibBuildOptionFromHandle (
972 IN EFI_HANDLE Handle,
973 IN LIST_ENTRY *BdsBootOptionList
974 )
975 /*++
976
977 Routine Description:
978
979 Build the boot option with the handle parsed in
980
981 Arguments:
982
983 Handle - The handle which present the device path to create boot option
984
985 BdsBootOptionList - The header of the link list which indexed all current
986 boot options
987
988 Returns:
989
990 VOID
991
992 --*/
993 {
994 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
995 CHAR16 *TempString;
996
997 DevicePath = DevicePathFromHandle (Handle);
998 TempString = DevicePathToStr (DevicePath);
999
1000 //
1001 // Create and register new boot option
1002 //
1003 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder");
1004 }
1005
1006 VOID
1007 BdsLibBuildOptionFromShell (
1008 IN EFI_HANDLE Handle,
1009 IN OUT LIST_ENTRY *BdsBootOptionList
1010 )
1011 /*++
1012
1013 Routine Description:
1014
1015 Build the on flash shell boot option with the handle parsed in
1016
1017 Arguments:
1018
1019 Handle - The handle which present the device path to create on flash shell
1020 boot option
1021
1022 BdsBootOptionList - The header of the link list which indexed all current
1023 boot options
1024
1025 Returns:
1026
1027 None
1028
1029 --*/
1030 {
1031 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1032 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
1033
1034 DevicePath = DevicePathFromHandle (Handle);
1035
1036 //
1037 // Build the shell device path
1038 //
1039 EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);
1040 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
1041
1042 //
1043 // Create and register the shell boot option
1044 //
1045 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder");
1046
1047 }
1048
1049 VOID
1050 BdsLibBootNext (
1051 VOID
1052 )
1053 /*++
1054
1055 Routine Description:
1056
1057 Boot from the EFI1.1 spec defined "BootNext" variable
1058
1059 Arguments:
1060
1061 None
1062
1063 Returns:
1064
1065 None
1066
1067 --*/
1068 {
1069 UINT16 *BootNext;
1070 UINTN BootNextSize;
1071 CHAR16 Buffer[20];
1072 BDS_COMMON_OPTION *BootOption;
1073 LIST_ENTRY TempList;
1074 UINTN ExitDataSize;
1075 CHAR16 *ExitData;
1076
1077 //
1078 // Init the boot option name buffer and temp link list
1079 //
1080 InitializeListHead (&TempList);
1081 ZeroMem (Buffer, sizeof (Buffer));
1082
1083 BootNext = BdsLibGetVariableAndSize (
1084 L"BootNext",
1085 &gEfiGlobalVariableGuid,
1086 &BootNextSize
1087 );
1088
1089 //
1090 // Clear the boot next variable first
1091 //
1092 if (BootNext != NULL) {
1093 gRT->SetVariable (
1094 L"BootNext",
1095 &gEfiGlobalVariableGuid,
1096 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1097 0,
1098 BootNext
1099 );
1100
1101 //
1102 // Start to build the boot option and try to boot
1103 //
1104 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
1105 BootOption = BdsLibVariableToOption (&TempList, Buffer);
1106 BdsLibConnectDevicePath (BootOption->DevicePath);
1107 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
1108 }
1109
1110 }
1111
1112 EFI_STATUS
1113 EFIAPI
1114 UpdateFvFileDevicePath (
1115 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
1116 IN EFI_GUID *FileGuid
1117 )
1118 /*++
1119
1120 Routine Description:
1121 According to a file guild, check a Fv file device path is valid. If it is invalid,
1122 try to return the valid device path.
1123 FV address maybe changes for memory layout adjust from time to time, use this funciton
1124 could promise the Fv file device path is right.
1125
1126 Arguments:
1127 DevicePath - on input, the Fv file device path need to check
1128 on output, the updated valid Fv file device path
1129
1130 FileGuid - the Fv file guild
1131
1132 Returns:
1133 EFI_INVALID_PARAMETER - the input DevicePath or FileGuid is invalid parameter
1134 EFI_UNSUPPORTED - the input DevicePath does not contain Fv file guild at all
1135 EFI_ALREADY_STARTED - the input DevicePath has pointed to Fv file, it is valid
1136 EFI_SUCCESS - has successfully updated the invalid DevicePath, and return the updated
1137 device path in DevicePath
1138
1139 --*/
1140 {
1141 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1142 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1143 EFI_STATUS Status;
1144 EFI_GUID *GuidPoint;
1145 UINTN Index;
1146 UINTN FvHandleCount;
1147 EFI_HANDLE *FvHandleBuffer;
1148 EFI_FV_FILETYPE Type;
1149 UINTN Size;
1150 EFI_FV_FILE_ATTRIBUTES Attributes;
1151 UINT32 AuthenticationStatus;
1152 BOOLEAN FindFvFile;
1153 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1154 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1155 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
1156 EFI_HANDLE FoundFvHandle;
1157 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
1158
1159 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
1160 return EFI_INVALID_PARAMETER;
1161 }
1162 if (FileGuid == NULL) {
1163 return EFI_INVALID_PARAMETER;
1164 }
1165 //
1166 // Check whether the device path point to the default the input Fv file
1167 //
1168 TempDevicePath = *DevicePath;
1169 LastDeviceNode = TempDevicePath;
1170 while (!EfiIsDevicePathEnd (TempDevicePath)) {
1171 LastDeviceNode = TempDevicePath;
1172 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
1173 }
1174
1175 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LastDeviceNode);
1176
1177 if (GuidPoint == NULL) {
1178 //
1179 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
1180 //
1181 return EFI_UNSUPPORTED;
1182 }
1183
1184 if (!CompareGuid (GuidPoint, FileGuid)) {
1185 //
1186 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
1187 //
1188 return EFI_UNSUPPORTED;
1189 }
1190
1191 //
1192 // Check whether the input Fv file device path is valid
1193 //
1194 TempDevicePath = *DevicePath;
1195 FoundFvHandle = NULL;
1196 Status = gBS->LocateDevicePath (
1197 &gEfiFirmwareVolume2ProtocolGuid,
1198 &TempDevicePath,
1199 &FoundFvHandle
1200 );
1201 if (!EFI_ERROR (Status)) {
1202 Status = gBS->HandleProtocol (
1203 FoundFvHandle,
1204 &gEfiFirmwareVolume2ProtocolGuid,
1205 (VOID **) &Fv
1206 );
1207 if (!EFI_ERROR (Status)) {
1208 //
1209 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
1210 //
1211 Status = Fv->ReadFile (
1212 Fv,
1213 FileGuid,
1214 NULL,
1215 &Size,
1216 &Type,
1217 &Attributes,
1218 &AuthenticationStatus
1219 );
1220 if (!EFI_ERROR (Status)) {
1221 return EFI_ALREADY_STARTED;
1222 }
1223 }
1224 }
1225
1226 //
1227 // Look for the input wanted FV file in current FV
1228 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
1229 //
1230 FindFvFile = FALSE;
1231 FoundFvHandle = NULL;
1232 Status = gBS->HandleProtocol (
1233 mBdsImageHandle,
1234 &gEfiLoadedImageProtocolGuid,
1235 (VOID **) &LoadedImage
1236 );
1237 if (!EFI_ERROR (Status)) {
1238 Status = gBS->HandleProtocol (
1239 LoadedImage->DeviceHandle,
1240 &gEfiFirmwareVolume2ProtocolGuid,
1241 (VOID **) &Fv
1242 );
1243 if (!EFI_ERROR (Status)) {
1244 Status = Fv->ReadFile (
1245 Fv,
1246 FileGuid,
1247 NULL,
1248 &Size,
1249 &Type,
1250 &Attributes,
1251 &AuthenticationStatus
1252 );
1253 if (!EFI_ERROR (Status)) {
1254 FindFvFile = TRUE;
1255 FoundFvHandle = LoadedImage->DeviceHandle;
1256 }
1257 }
1258 }
1259 //
1260 // Second, if fail to find, try to enumerate all FV
1261 //
1262 if (!FindFvFile) {
1263 gBS->LocateHandleBuffer (
1264 ByProtocol,
1265 &gEfiFirmwareVolume2ProtocolGuid,
1266 NULL,
1267 &FvHandleCount,
1268 &FvHandleBuffer
1269 );
1270 for (Index = 0; Index < FvHandleCount; Index++) {
1271 gBS->HandleProtocol (
1272 FvHandleBuffer[Index],
1273 &gEfiFirmwareVolume2ProtocolGuid,
1274 (VOID **) &Fv
1275 );
1276
1277 Status = Fv->ReadFile (
1278 Fv,
1279 FileGuid,
1280 NULL,
1281 &Size,
1282 &Type,
1283 &Attributes,
1284 &AuthenticationStatus
1285 );
1286 if (EFI_ERROR (Status)) {
1287 //
1288 // Skip if input Fv file not in the FV
1289 //
1290 continue;
1291 }
1292 FindFvFile = TRUE;
1293 FoundFvHandle = FvHandleBuffer[Index];
1294 break;
1295 }
1296 }
1297
1298 if (FindFvFile) {
1299 //
1300 // Build the shell device path
1301 //
1302 NewDevicePath = DevicePathFromHandle (FoundFvHandle);
1303 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
1304 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
1305 *DevicePath = NewDevicePath;
1306 return EFI_SUCCESS;
1307 }
1308
1309 return EFI_NOT_FOUND;
1310 }