]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/GenericBdsLib/BdsBoot.c
30d3a50d906076feba4a713f8d773e76ac6508c6
[mirror_edk2.git] / MdeModulePkg / Library / GenericBdsLib / BdsBoot.c
1 /** @file
2 BDS Lib functions which relate with create or process the boot
3 option.
4
5 Copyright (c) 2004 - 2008, Intel Corporation. <BR>
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "InternalBdsLib.h"
17
18 BOOLEAN mEnumBootDevice = FALSE;
19
20 ///
21 /// This GUID is used for an EFI Variable that stores the front device pathes
22 /// for a partial device path that starts with the HD node.
23 ///
24 EFI_GUID mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };
25
26
27
28 /**
29 Boot the legacy system with the boot option
30
31 @param Option The legacy boot option which have BBS device path
32
33 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
34 legacy boot.
35 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
36
37 **/
38 EFI_STATUS
39 BdsLibDoLegacyBoot (
40 IN BDS_COMMON_OPTION *Option
41 )
42 {
43 EFI_STATUS Status;
44 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
45
46 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
47 if (EFI_ERROR (Status)) {
48 //
49 // If no LegacyBios protocol we do not support legacy boot
50 //
51 return EFI_UNSUPPORTED;
52 }
53 //
54 // Notes: if we seperate the int 19, then we don't need to refresh BBS
55 //
56 BdsRefreshBbsTableForBoot (Option);
57
58 //
59 // Write boot to OS performance data to a file
60 //
61 PERF_CODE (
62 WriteBootToOsPerformanceData ();
63 );
64
65 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
66 return LegacyBios->LegacyBoot (
67 LegacyBios,
68 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
69 Option->LoadOptionsSize,
70 Option->LoadOptions
71 );
72 }
73
74
75 /**
76 Process the boot option follow the EFI 1.1 specification and
77 special treat the legacy boot option with BBS_DEVICE_PATH.
78
79 @param Option The boot option need to be processed
80 @param DevicePath The device path which describe where to load the
81 boot image or the legcy BBS device path to boot
82 the legacy OS
83 @param ExitDataSize Returned directly from gBS->StartImage ()
84 @param ExitData Returned directly from gBS->StartImage ()
85
86 @retval EFI_SUCCESS Status from gBS->StartImage ()
87 @retval EFI_NOT_FOUND If the Device Path is not found in the system
88
89 **/
90 EFI_STATUS
91 EFIAPI
92 BdsLibBootViaBootOption (
93 IN BDS_COMMON_OPTION * Option,
94 IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,
95 OUT UINTN *ExitDataSize,
96 OUT CHAR16 **ExitData OPTIONAL
97 )
98 {
99 EFI_STATUS Status;
100 EFI_HANDLE Handle;
101 EFI_HANDLE ImageHandle;
102 EFI_DEVICE_PATH_PROTOCOL *FilePath;
103 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
104 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
105 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
106 LIST_ENTRY TempBootLists;
107
108 //
109 // Record the performance data for End of BDS
110 //
111 PERF_END (0, BDS_TOK, NULL, 0);
112
113 *ExitDataSize = 0;
114 *ExitData = NULL;
115
116 //
117 // Notes: put EFI64 ROM Shadow Solution
118 //
119 EFI64_SHADOW_ALL_LEGACY_ROM ();
120
121 //
122 // Notes: this code can be remove after the s3 script table
123 // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or
124 // EFI_EVENT_SIGNAL_LEGACY_BOOT
125 //
126 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
127 if (!EFI_ERROR (Status)) {
128 AcpiS3Save->S3Save (AcpiS3Save, NULL);
129 }
130 //
131 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
132 // full device path
133 //
134 WorkingDevicePath = NULL;
135 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
136 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
137 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
138 (HARDDRIVE_DEVICE_PATH *)DevicePath
139 );
140 if (WorkingDevicePath != NULL) {
141 DevicePath = WorkingDevicePath;
142 }
143 }
144 //
145 // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event
146 //
147 EfiSignalEventReadyToBoot();
148
149
150 //
151 // Set Boot Current
152 //
153 gRT->SetVariable (
154 L"BootCurrent",
155 &gEfiGlobalVariableGuid,
156 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
157 sizeof (UINT16),
158 &Option->BootCurrent
159 );
160
161 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
162 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
163 ) {
164 //
165 // Check to see if we should legacy BOOT. If yes then do the legacy boot
166 //
167 return BdsLibDoLegacyBoot (Option);
168 }
169
170 //
171 // If the boot option point to Internal FV shell, make sure it is valid
172 //
173 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);
174 if (!EFI_ERROR(Status)) {
175 if (Option->DevicePath != NULL) {
176 SafeFreePool(Option->DevicePath);
177 }
178 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
179 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
180 //
181 // Update the shell boot option
182 //
183 InitializeListHead (&TempBootLists);
184 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
185
186 //
187 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
188 //
189 SafeFreePool (DevicePath);
190 DevicePath = Option->DevicePath;
191 }
192
193 //
194 // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION
195 //
196 gBS->RestoreTPL (TPL_APPLICATION);
197
198 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
199
200 Status = gBS->LoadImage (
201 TRUE,
202 mBdsImageHandle,
203 DevicePath,
204 NULL,
205 0,
206 &ImageHandle
207 );
208
209 //
210 // If we didn't find an image directly, we need to try as if it is a removable device boot opotion
211 // and load the image according to the default boot behavior for removable device.
212 //
213 if (EFI_ERROR (Status)) {
214 //
215 // check if there is a bootable removable media could be found in this device path ,
216 // and get the bootable media handle
217 //
218 Handle = BdsLibGetBootableHandle(DevicePath);
219 if (Handle == NULL) {
220 goto Done;
221 }
222 //
223 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
224 // machinename is ia32, ia64, x64, ...
225 //
226 FilePath = FileDevicePath (Handle, (CONST CHAR16*)PcdGetPtr(PcdDefaultBootFileName));
227 if (FilePath != NULL) {
228 Status = gBS->LoadImage (
229 TRUE,
230 mBdsImageHandle,
231 FilePath,
232 NULL,
233 0,
234 &ImageHandle
235 );
236 if (EFI_ERROR (Status)) {
237 //
238 // The DevicePath failed, and it's not a valid
239 // removable media device.
240 //
241 goto Done;
242 }
243 }
244 }
245
246 if (EFI_ERROR (Status)) {
247 //
248 // It there is any error from the Boot attempt exit now.
249 //
250 goto Done;
251 }
252 //
253 // Provide the image with it's load options
254 //
255 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
256 ASSERT_EFI_ERROR (Status);
257
258 if (Option->LoadOptionsSize != 0) {
259 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
260 ImageInfo->LoadOptions = Option->LoadOptions;
261 }
262 //
263 // Before calling the image, enable the Watchdog Timer for
264 // the 5 Minute period
265 //
266 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
267
268 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
269 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
270
271 //
272 // Clear the Watchdog Timer after the image returns
273 //
274 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
275
276 Done:
277 //
278 // Clear Boot Current
279 //
280 gRT->SetVariable (
281 L"BootCurrent",
282 &gEfiGlobalVariableGuid,
283 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
284 0,
285 &Option->BootCurrent
286 );
287
288 //
289 // Raise the TPL level back to TPL_APPLICATION
290 //
291 gBS->RaiseTPL (TPL_APPLICATION);
292
293 return Status;
294 }
295
296
297 /**
298 Expand a device path that starts with a hard drive media device path node to be a
299 full device path that includes the full hardware path to the device. We need
300 to do this so it can be booted. As an optimizaiton the front match (the part point
301 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
302 so a connect all is not required on every boot. All successful history device path
303 which point to partition node (the front part) will be saved.
304
305 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
306 drive media device path.
307 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
308 cannot be found.
309
310 **/
311 EFI_DEVICE_PATH_PROTOCOL *
312 EFIAPI
313 BdsExpandPartitionPartialDevicePathToFull (
314 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
315 )
316 {
317 EFI_STATUS Status;
318 UINTN BlockIoHandleCount;
319 EFI_HANDLE *BlockIoBuffer;
320 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
321 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
322 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
323 UINTN Index;
324 UINTN InstanceNum;
325 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
326 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
327 UINTN CachedDevicePathSize;
328 BOOLEAN DeviceExist;
329 BOOLEAN NeedAdjust;
330 EFI_DEVICE_PATH_PROTOCOL *Instance;
331 UINTN Size;
332
333 FullDevicePath = NULL;
334 //
335 // Check if there is prestore 'HDDP' variable.
336 // If exist, search the front path which point to partition node in the variable instants.
337 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
338 //
339 CachedDevicePath = BdsLibGetVariableAndSize (
340 L"HDDP",
341 &mHdBootVariablePrivateGuid,
342 &CachedDevicePathSize
343 );
344
345 if (CachedDevicePath != NULL) {
346 TempNewDevicePath = CachedDevicePath;
347 DeviceExist = FALSE;
348 NeedAdjust = FALSE;
349 do {
350 //
351 // Check every instance of the variable
352 // First, check wheather the instance contain the partition node, which is needed for distinguishing multi
353 // partial partition boot option. Second, check wheather the instance could be connected.
354 //
355 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
356 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
357 //
358 // Connect the device path instance, the device path point to hard drive media device path node
359 // e.g. ACPI() /PCI()/ATA()/Partition()
360 //
361 Status = BdsLibConnectDevicePath (Instance);
362 if (!EFI_ERROR (Status)) {
363 DeviceExist = TRUE;
364 break;
365 }
366 }
367 //
368 // Come here means the first instance is not matched
369 //
370 NeedAdjust = TRUE;
371 SafeFreePool(Instance);
372 } while (TempNewDevicePath != NULL);
373
374 if (DeviceExist) {
375 //
376 // Find the matched device path.
377 // Append the file path infomration from the boot option and return the fully expanded device path.
378 //
379 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
380 FullDevicePath = AppendDevicePath (Instance, DevicePath);
381
382 //
383 // Adjust the 'HDDP' instances sequense if the matched one is not first one.
384 //
385 if (NeedAdjust) {
386 //
387 // First delete the matched instance.
388 //
389 TempNewDevicePath = CachedDevicePath;
390 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
391 SafeFreePool (TempNewDevicePath);
392
393 //
394 // Second, append the remaining parth after the matched instance
395 //
396 TempNewDevicePath = CachedDevicePath;
397 CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
398 SafeFreePool (TempNewDevicePath);
399 //
400 // Save the matching Device Path so we don't need to do a connect all next time
401 //
402 Status = gRT->SetVariable (
403 L"HDDP",
404 &mHdBootVariablePrivateGuid,
405 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
406 GetDevicePathSize (CachedDevicePath),
407 CachedDevicePath
408 );
409 }
410
411 SafeFreePool (Instance);
412 SafeFreePool (CachedDevicePath);
413 return FullDevicePath;
414 }
415 }
416
417 //
418 // If we get here we fail to find or 'HDDP' not exist, and now we need
419 // to seach all devices in the system for a matched partition
420 //
421 BdsLibConnectAllDriversToAllControllers ();
422 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
423 if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {
424 //
425 // If there was an error or there are no device handles that support
426 // the BLOCK_IO Protocol, then return.
427 //
428 return NULL;
429 }
430 //
431 // Loop through all the device handles that support the BLOCK_IO Protocol
432 //
433 for (Index = 0; Index < BlockIoHandleCount; Index++) {
434
435 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
436 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
437 continue;
438 }
439
440 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
441 //
442 // Find the matched partition device path
443 //
444 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
445 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
446
447 //
448 // Save the matched patition device path in 'HDDP' variable
449 //
450 if (CachedDevicePath != NULL) {
451 //
452 // Save the matched patition device path as first instance of 'HDDP' variable
453 //
454 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
455 TempNewDevicePath = CachedDevicePath;
456 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
457 SafeFreePool(TempNewDevicePath);
458
459 TempNewDevicePath = CachedDevicePath;
460 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
461 SafeFreePool(TempNewDevicePath);
462 } else {
463 TempNewDevicePath = CachedDevicePath;
464 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
465 SafeFreePool(TempNewDevicePath);
466 }
467 //
468 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
469 // If the user try to boot many OS in different HDs or partitions, in theary, the 'HDDP' variable maybe become larger and larger.
470 //
471 InstanceNum = 0;
472 TempNewDevicePath = CachedDevicePath;
473 while (!IsDevicePathEnd (TempNewDevicePath)) {
474 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
475 //
476 // Parse one instance
477 //
478 while (!IsDevicePathEndType (TempNewDevicePath)) {
479 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
480 }
481 InstanceNum++;
482 //
483 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
484 //
485 if (InstanceNum >= 12) {
486 SetDevicePathEndNode (TempNewDevicePath);
487 break;
488 }
489 }
490 } else {
491 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
492 }
493
494 //
495 // Save the matching Device Path so we don't need to do a connect all next time
496 //
497 Status = gRT->SetVariable (
498 L"HDDP",
499 &mHdBootVariablePrivateGuid,
500 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
501 GetDevicePathSize (CachedDevicePath),
502 CachedDevicePath
503 );
504
505 break;
506 }
507 }
508
509 SafeFreePool (CachedDevicePath);
510 SafeFreePool (BlockIoBuffer);
511 return FullDevicePath;
512 }
513
514 /**
515 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
516 instances, has the same partition node with HardDriveDevicePath device path
517
518 @param BlockIoDevicePath Multi device path instances which need to check
519 @param HardDriveDevicePath A device path which starts with a hard drive media
520 device path.
521
522 @retval TRUE There is a matched device path instance FALSE
523 @retval FALSE There is no matched device path instance
524
525 **/
526 BOOLEAN
527 EFIAPI
528 MatchPartitionDevicePathNode (
529 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
530 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
531 )
532 {
533 HARDDRIVE_DEVICE_PATH *TmpHdPath;
534 HARDDRIVE_DEVICE_PATH *TempPath;
535 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
536 BOOLEAN Match;
537 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
538
539 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
540 return FALSE;
541 }
542
543 //
544 // Make PreviousDevicePath == the device path node before the end node
545 //
546 DevicePath = BlockIoDevicePath;
547 BlockIoHdDevicePathNode = NULL;
548
549 //
550 // find the partition device path node
551 //
552 while (!IsDevicePathEnd (DevicePath)) {
553 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
554 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
555 ) {
556 BlockIoHdDevicePathNode = DevicePath;
557 break;
558 }
559
560 DevicePath = NextDevicePathNode (DevicePath);
561 }
562
563 if (BlockIoHdDevicePathNode == NULL) {
564 return FALSE;
565 }
566 //
567 // See if the harddrive device path in blockio matches the orig Hard Drive Node
568 //
569 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
570 TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
571 Match = FALSE;
572
573 //
574 // Check for the match
575 //
576 if ((TmpHdPath->MBRType == TempPath->MBRType) &&
577 (TmpHdPath->SignatureType == TempPath->SignatureType)) {
578 switch (TmpHdPath->SignatureType) {
579 case SIGNATURE_TYPE_GUID:
580 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)TempPath->Signature);
581 break;
582 case SIGNATURE_TYPE_MBR:
583 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == *(UINT32 *)(&(TempPath->Signature[0])));
584 break;
585 default:
586 Match = FALSE;
587 break;
588 }
589 }
590
591 return Match;
592 }
593
594 /**
595 Delete the boot option associated with the handle passed in.
596
597 @param Handle The handle which present the device path to create
598 boot option
599
600 @retval EFI_SUCCESS Delete the boot option success
601 @retval EFI_NOT_FOUND If the Device Path is not found in the system
602 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
603 @retval Other Error return value from SetVariable()
604
605 **/
606 EFI_STATUS
607 BdsLibDeleteOptionFromHandle (
608 IN EFI_HANDLE Handle
609 )
610 {
611 UINT16 *BootOrder;
612 UINT8 *BootOptionVar;
613 UINTN BootOrderSize;
614 UINTN BootOptionSize;
615 EFI_STATUS Status;
616 UINTN Index;
617 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
618 UINTN DevicePathSize;
619 UINTN OptionDevicePathSize;
620 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
621 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
622 UINT8 *TempPtr;
623
624 Status = EFI_SUCCESS;
625 BootOrder = NULL;
626 BootOrderSize = 0;
627
628 //
629 // Check "BootOrder" variable, if no, means there is no any boot order.
630 //
631 BootOrder = BdsLibGetVariableAndSize (
632 L"BootOrder",
633 &gEfiGlobalVariableGuid,
634 &BootOrderSize
635 );
636 if (BootOrder == NULL) {
637 return EFI_NOT_FOUND;
638 }
639
640 //
641 // Convert device handle to device path protocol instance
642 //
643 DevicePath = DevicePathFromHandle (Handle);
644 if (DevicePath == NULL) {
645 return EFI_NOT_FOUND;
646 }
647 DevicePathSize = GetDevicePathSize (DevicePath);
648
649 //
650 // Loop all boot order variable and find the matching device path
651 //
652 Index = 0;
653 while (Index < BootOrderSize / sizeof (UINT16)) {
654 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
655 BootOptionVar = BdsLibGetVariableAndSize (
656 BootOption,
657 &gEfiGlobalVariableGuid,
658 &BootOptionSize
659 );
660
661 if (BootOptionVar == NULL) {
662 SafeFreePool (BootOrder);
663 return EFI_OUT_OF_RESOURCES;
664 }
665
666 TempPtr = BootOptionVar;
667 TempPtr += sizeof (UINT32) + sizeof (UINT16);
668 TempPtr += StrSize ((CHAR16 *) TempPtr);
669 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
670 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
671
672 //
673 // Check whether the device path match
674 //
675 if ((OptionDevicePathSize == DevicePathSize) &&
676 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
677 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
678 SafeFreePool (BootOptionVar);
679 break;
680 }
681
682 SafeFreePool (BootOptionVar);
683 Index++;
684 }
685
686 //
687 // Adjust number of boot option for "BootOrder" variable.
688 //
689 Status = gRT->SetVariable (
690 L"BootOrder",
691 &gEfiGlobalVariableGuid,
692 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
693 BootOrderSize,
694 BootOrder
695 );
696
697 SafeFreePool (BootOrder);
698
699 return Status;
700 }
701
702
703 /**
704 Delete all invalid EFI boot options. The probable invalid boot option could
705 be Removable media or Network boot device.
706
707 @retval EFI_SUCCESS Delete all invalid boot option success
708 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
709 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
710 @retval Other Error return value from SetVariable()
711
712 **/
713 EFI_STATUS
714 BdsDeleteAllInvalidEfiBootOption (
715 VOID
716 )
717 {
718 UINT16 *BootOrder;
719 UINT8 *BootOptionVar;
720 UINTN BootOrderSize;
721 UINTN BootOptionSize;
722 EFI_STATUS Status;
723 UINTN Index;
724 UINTN Index2;
725 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
726 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
727 UINT8 *TempPtr;
728
729 Status = EFI_SUCCESS;
730 BootOrder = NULL;
731 BootOrderSize = 0;
732
733 //
734 // Check "BootOrder" variable firstly, this variable hold the number of boot options
735 //
736 BootOrder = BdsLibGetVariableAndSize (
737 L"BootOrder",
738 &gEfiGlobalVariableGuid,
739 &BootOrderSize
740 );
741 if (NULL == BootOrder) {
742 return EFI_NOT_FOUND;
743 }
744
745 Index = 0;
746 while (Index < BootOrderSize / sizeof (UINT16)) {
747 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
748 BootOptionVar = BdsLibGetVariableAndSize (
749 BootOption,
750 &gEfiGlobalVariableGuid,
751 &BootOptionSize
752 );
753 if (NULL == BootOptionVar) {
754 SafeFreePool (BootOrder);
755 return EFI_OUT_OF_RESOURCES;
756 }
757
758 TempPtr = BootOptionVar;
759 TempPtr += sizeof (UINT32) + sizeof (UINT16);
760 TempPtr += StrSize ((CHAR16 *) TempPtr);
761 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
762
763 //
764 // Skip legacy boot option (BBS boot device)
765 //
766 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
767 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
768 SafeFreePool (BootOptionVar);
769 Index++;
770 continue;
771 }
772
773 if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath, FALSE)) {
774 //
775 // Delete this invalid boot option "Boot####"
776 //
777 Status = gRT->SetVariable (
778 BootOption,
779 &gEfiGlobalVariableGuid,
780 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
781 0,
782 NULL
783 );
784 //
785 // Mark this boot option in boot order as deleted
786 //
787 BootOrder[Index] = 0xffff;
788 }
789
790 SafeFreePool (BootOptionVar);
791 Index++;
792 }
793
794 //
795 // Adjust boot order array
796 //
797 Index2 = 0;
798 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
799 if (BootOrder[Index] != 0xffff) {
800 BootOrder[Index2] = BootOrder[Index];
801 Index2 ++;
802 }
803 }
804 Status = gRT->SetVariable (
805 L"BootOrder",
806 &gEfiGlobalVariableGuid,
807 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
808 Index2 * sizeof (UINT16),
809 BootOrder
810 );
811
812 SafeFreePool (BootOrder);
813
814 return Status;
815 }
816
817
818 /**
819 This function will enumerate all possible boot device in the system,
820 it will only excute once of every boot.
821
822 @param BdsBootOptionList The header of the link list which indexed all
823 current boot options
824
825 @retval EFI_SUCCESS Finished all the boot device enumerate and create
826 the boot option base on that boot device
827
828 **/
829 EFI_STATUS
830 EFIAPI
831 BdsLibEnumerateAllBootOption (
832 IN OUT LIST_ENTRY *BdsBootOptionList
833 )
834 {
835 EFI_STATUS Status;
836 UINT16 FloppyNumber;
837 UINT16 CdromNumber;
838 UINT16 UsbNumber;
839 UINT16 MiscNumber;
840 UINT16 NonBlockNumber;
841 UINTN NumberBlockIoHandles;
842 EFI_HANDLE *BlockIoHandles;
843 EFI_BLOCK_IO_PROTOCOL *BlkIo;
844 UINTN Index;
845 UINTN NumberSimpleNetworkHandles;
846 EFI_HANDLE *SimpleNetworkHandles;
847 UINTN FvHandleCount;
848 EFI_HANDLE *FvHandleBuffer;
849 EFI_FV_FILETYPE Type;
850 UINTN Size;
851 EFI_FV_FILE_ATTRIBUTES Attributes;
852 UINT32 AuthenticationStatus;
853 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
854 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
855 UINTN DevicePathType;
856 CHAR16 Buffer[40];
857 EFI_HANDLE *FileSystemHandles;
858 UINTN NumberFileSystemHandles;
859 BOOLEAN NeedDelete;
860 EFI_IMAGE_DOS_HEADER DosHeader;
861 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
862 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
863
864 FloppyNumber = 0;
865 CdromNumber = 0;
866 UsbNumber = 0;
867 MiscNumber = 0;
868 ZeroMem (Buffer, sizeof (Buffer));
869
870 //
871 // If the boot device enumerate happened, just get the boot
872 // device from the boot order variable
873 //
874 if (mEnumBootDevice) {
875 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
876 return EFI_SUCCESS;
877 }
878
879 //
880 // Notes: this dirty code is to get the legacy boot option from the
881 // BBS table and create to variable as the EFI boot option, it should
882 // be removed after the CSM can provide legacy boot option directly
883 //
884 REFRESH_LEGACY_BOOT_OPTIONS;
885
886 //
887 // Delete invalid boot option
888 //
889 BdsDeleteAllInvalidEfiBootOption ();
890
891 //
892 // Parse removable media
893 //
894 gBS->LocateHandleBuffer (
895 ByProtocol,
896 &gEfiBlockIoProtocolGuid,
897 NULL,
898 &NumberBlockIoHandles,
899 &BlockIoHandles
900 );
901
902 for (Index = 0; Index < NumberBlockIoHandles; Index++) {
903 Status = gBS->HandleProtocol (
904 BlockIoHandles[Index],
905 &gEfiBlockIoProtocolGuid,
906 (VOID **) &BlkIo
907 );
908 if (!EFI_ERROR (Status)) {
909 if (!BlkIo->Media->RemovableMedia) {
910 //
911 // skip the non-removable block devices
912 //
913 continue;
914 }
915 }
916 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);
917 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
918
919 switch (DevicePathType) {
920 case BDS_EFI_ACPI_FLOPPY_BOOT:
921 if (FloppyNumber == 0) {
922 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy");
923 } else {
924 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy %d", FloppyNumber);
925 }
926 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
927 FloppyNumber++;
928 break;
929
930 case BDS_EFI_MESSAGE_ATAPI_BOOT:
931 if (CdromNumber == 0) {
932 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM");
933 } else {
934 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM %d", CdromNumber);
935 }
936 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
937 CdromNumber++;
938 break;
939
940 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
941 if (UsbNumber == 0) {
942 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device");
943 } else {
944 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device %d", UsbNumber);
945 }
946 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
947 UsbNumber++;
948 break;
949
950 case BDS_EFI_MESSAGE_SCSI_BOOT:
951 if (UsbNumber == 0) {
952 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device");
953 } else {
954 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device %d", UsbNumber);
955 }
956 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
957 UsbNumber++;
958 break;
959
960 case BDS_EFI_MESSAGE_MISC_BOOT:
961 if (MiscNumber == 0) {
962 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device");
963 } else {
964 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device %d", MiscNumber);
965 }
966 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
967 MiscNumber++;
968 break;
969
970 default:
971 break;
972 }
973 }
974
975 if (NumberBlockIoHandles != 0) {
976 SafeFreePool (BlockIoHandles);
977 }
978
979 //
980 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
981 //
982 NonBlockNumber = 0;
983 gBS->LocateHandleBuffer (
984 ByProtocol,
985 &gEfiSimpleFileSystemProtocolGuid,
986 NULL,
987 &NumberFileSystemHandles,
988 &FileSystemHandles
989 );
990 for (Index = 0; Index < NumberFileSystemHandles; Index++) {
991 Status = gBS->HandleProtocol (
992 FileSystemHandles[Index],
993 &gEfiBlockIoProtocolGuid,
994 (VOID **) &BlkIo
995 );
996 if (!EFI_ERROR (Status)) {
997 //
998 // Skip if the file system handle supports a BlkIo protocol,
999 //
1000 continue;
1001 }
1002
1003 //
1004 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
1005 // machinename is ia32, ia64, x64, ...
1006 //
1007 Hdr.Union = &HdrData;
1008 NeedDelete = TRUE;
1009 Status = BdsLibGetImageHeader (
1010 FileSystemHandles[Index],
1011 (CHAR16*)PcdGetPtr (PcdDefaultBootFileName),
1012 &DosHeader,
1013 Hdr
1014 );
1015 if (!EFI_ERROR (Status) &&
1016 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
1017 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1018 NeedDelete = FALSE;
1019 }
1020
1021 if (NeedDelete) {
1022 //
1023 // No such file or the file is not a EFI application, delete this boot option
1024 //
1025 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
1026 } else {
1027 if (NonBlockNumber == 0) {
1028 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device");
1029 } else {
1030 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device %d", NonBlockNumber);
1031 }
1032 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
1033 NonBlockNumber++;
1034 }
1035 }
1036
1037 if (NumberFileSystemHandles != 0) {
1038 SafeFreePool (FileSystemHandles);
1039 }
1040
1041 //
1042 // Parse Network Boot Device
1043 //
1044 gBS->LocateHandleBuffer (
1045 ByProtocol,
1046 &gEfiSimpleNetworkProtocolGuid,
1047 NULL,
1048 &NumberSimpleNetworkHandles,
1049 &SimpleNetworkHandles
1050 );
1051 for (Index = 0; Index < NumberSimpleNetworkHandles; Index++) {
1052 if (Index == 0) {
1053 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network");
1054 } else {
1055 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network %d", Index);
1056 }
1057 BdsLibBuildOptionFromHandle (SimpleNetworkHandles[Index], BdsBootOptionList, Buffer);
1058 }
1059
1060 if (NumberSimpleNetworkHandles != 0) {
1061 SafeFreePool (SimpleNetworkHandles);
1062 }
1063
1064 //
1065 // Check if we have on flash shell
1066 //
1067 gBS->LocateHandleBuffer (
1068 ByProtocol,
1069 &gEfiFirmwareVolume2ProtocolGuid,
1070 NULL,
1071 &FvHandleCount,
1072 &FvHandleBuffer
1073 );
1074 for (Index = 0; Index < FvHandleCount; Index++) {
1075 //
1076 // Only care the dispatched FV. If no dispatch protocol on the FV, it is not dispatched, then skip it.
1077 //
1078 Status = gBS->HandleProtocol (
1079 FvHandleBuffer[Index],
1080 &gEfiFirmwareVolumeDispatchProtocolGuid,
1081 (VOID **) &Fv
1082 );
1083 if (EFI_ERROR (Status)) {
1084 continue;
1085 }
1086
1087 gBS->HandleProtocol (
1088 FvHandleBuffer[Index],
1089 &gEfiFirmwareVolume2ProtocolGuid,
1090 (VOID **) &Fv
1091 );
1092
1093 Status = Fv->ReadFile (
1094 Fv,
1095 &gEfiShellFileGuid,
1096 NULL,
1097 &Size,
1098 &Type,
1099 &Attributes,
1100 &AuthenticationStatus
1101 );
1102 if (EFI_ERROR (Status)) {
1103 //
1104 // Skip if no shell file in the FV
1105 //
1106 continue;
1107 }
1108 //
1109 // Build the shell boot option
1110 //
1111 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
1112 }
1113
1114 if (FvHandleCount != 0) {
1115 SafeFreePool (FvHandleBuffer);
1116 }
1117 //
1118 // Make sure every boot only have one time
1119 // boot device enumerate
1120 //
1121 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
1122 mEnumBootDevice = TRUE;
1123
1124 return EFI_SUCCESS;
1125 }
1126
1127 /**
1128 Build the boot option with the handle parsed in.
1129
1130 @param Handle The handle which present the device path to create
1131 boot option
1132 @param BdsBootOptionList The header of the link list which indexed all
1133 current boot options
1134 @param String Boot option name.
1135
1136 **/
1137 VOID
1138 EFIAPI
1139 BdsLibBuildOptionFromHandle (
1140 IN EFI_HANDLE Handle,
1141 IN LIST_ENTRY *BdsBootOptionList,
1142 IN CHAR16 *String
1143 )
1144 {
1145 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1146
1147 DevicePath = DevicePathFromHandle (Handle);
1148
1149 //
1150 // Create and register new boot option
1151 //
1152 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
1153 }
1154
1155
1156 /**
1157 Build the on flash shell boot option with the handle parsed in.
1158
1159 @param Handle The handle which present the device path to create
1160 on flash shell boot option
1161 @param BdsBootOptionList The header of the link list which indexed all
1162 current boot options
1163
1164 **/
1165 VOID
1166 EFIAPI
1167 BdsLibBuildOptionFromShell (
1168 IN EFI_HANDLE Handle,
1169 IN OUT LIST_ENTRY *BdsBootOptionList
1170 )
1171 {
1172 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1173 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
1174
1175 DevicePath = DevicePathFromHandle (Handle);
1176
1177 //
1178 // Build the shell device path
1179 //
1180 EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);
1181
1182 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
1183
1184 //
1185 // Create and register the shell boot option
1186 //
1187 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
1188
1189 }
1190
1191 /**
1192 Boot from the EFI1.1 spec defined "BootNext" variable
1193
1194 **/
1195 VOID
1196 EFIAPI
1197 BdsLibBootNext (
1198 VOID
1199 )
1200 {
1201 UINT16 *BootNext;
1202 UINTN BootNextSize;
1203 CHAR16 Buffer[20];
1204 BDS_COMMON_OPTION *BootOption;
1205 LIST_ENTRY TempList;
1206 UINTN ExitDataSize;
1207 CHAR16 *ExitData;
1208
1209 //
1210 // Init the boot option name buffer and temp link list
1211 //
1212 InitializeListHead (&TempList);
1213 ZeroMem (Buffer, sizeof (Buffer));
1214
1215 BootNext = BdsLibGetVariableAndSize (
1216 L"BootNext",
1217 &gEfiGlobalVariableGuid,
1218 &BootNextSize
1219 );
1220
1221 //
1222 // Clear the boot next variable first
1223 //
1224 if (BootNext != NULL) {
1225 gRT->SetVariable (
1226 L"BootNext",
1227 &gEfiGlobalVariableGuid,
1228 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1229 0,
1230 BootNext
1231 );
1232
1233 //
1234 // Start to build the boot option and try to boot
1235 //
1236 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
1237 BootOption = BdsLibVariableToOption (&TempList, Buffer);
1238 BdsLibConnectDevicePath (BootOption->DevicePath);
1239 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
1240 }
1241
1242 }
1243
1244 /**
1245 Return the bootable media handle.
1246 First, check the device is connected
1247 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
1248 Third, detect the the default boot file in the Media, and return the removable Media handle.
1249
1250 @param DevicePath Device Path to a bootable device
1251
1252 @retval NULL The device path points to an EFI bootable Media
1253 @retval NULL The media on the DevicePath is not bootable
1254
1255 **/
1256 EFI_HANDLE
1257 EFIAPI
1258 BdsLibGetBootableHandle (
1259 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1260 )
1261 {
1262 EFI_STATUS Status;
1263 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
1264 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
1265 EFI_HANDLE Handle;
1266 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1267 VOID *Buffer;
1268 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1269 UINTN Size;
1270 UINTN TempSize;
1271 EFI_HANDLE ReturnHandle;
1272 EFI_HANDLE *SimpleFileSystemHandles;
1273
1274 UINTN NumberSimpleFileSystemHandles;
1275 UINTN Index;
1276 EFI_IMAGE_DOS_HEADER DosHeader;
1277 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
1278 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1279
1280 UpdatedDevicePath = DevicePath;
1281
1282 //
1283 // Check whether the device is connected
1284 //
1285 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
1286 if (EFI_ERROR (Status)) {
1287 //
1288 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
1289 //
1290 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
1291 if (EFI_ERROR (Status)) {
1292 //
1293 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1294 //
1295 UpdatedDevicePath = DevicePath;
1296 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1297 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1298 }
1299 } else {
1300 //
1301 // Get BlockIo protocal and check removable attribute
1302 //
1303 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1304 //
1305 // Issue a dummy read to the device to check for media change.
1306 // When the removable media is changed, any Block IO read/write will
1307 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1308 // returned. After the Block IO protocol is reinstalled, subsequent
1309 // Block IO read/write will success.
1310 //
1311 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1312 if (Buffer != NULL) {
1313 BlockIo->ReadBlocks (
1314 BlockIo,
1315 BlockIo->Media->MediaId,
1316 0,
1317 BlockIo->Media->BlockSize,
1318 Buffer
1319 );
1320 SafeFreePool(Buffer);
1321 }
1322 }
1323
1324 //
1325 // Detect the the default boot file from removable Media
1326 //
1327
1328 //
1329 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
1330 // Try to locate the USB node device path first, if fail then use its previour PCI node to search
1331 //
1332 DupDevicePath = DuplicateDevicePath (DevicePath);
1333 UpdatedDevicePath = DupDevicePath;
1334 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1335 //
1336 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
1337 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
1338 //
1339 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
1340 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
1341 //
1342 // Remove the usb node, let the device path only point to PCI node
1343 //
1344 SetDevicePathEndNode (UpdatedDevicePath);
1345 UpdatedDevicePath = DupDevicePath;
1346 } else {
1347 UpdatedDevicePath = DevicePath;
1348 }
1349
1350 //
1351 // Get the device path size of boot option
1352 //
1353 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1354 ReturnHandle = NULL;
1355 gBS->LocateHandleBuffer (
1356 ByProtocol,
1357 &gEfiSimpleFileSystemProtocolGuid,
1358 NULL,
1359 &NumberSimpleFileSystemHandles,
1360 &SimpleFileSystemHandles
1361 );
1362 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1363 //
1364 // Get the device path size of SimpleFileSystem handle
1365 //
1366 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1367 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1368 //
1369 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1370 //
1371 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
1372 //
1373 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1374 // machinename is ia32, ia64, x64, ...
1375 //
1376 Hdr.Union = &HdrData;
1377 Status = BdsLibGetImageHeader (
1378 SimpleFileSystemHandles[Index],
1379 (CHAR16*)PcdGetPtr(PcdDefaultBootFileName),
1380 &DosHeader,
1381 Hdr
1382 );
1383 if (!EFI_ERROR (Status) &&
1384 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
1385 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1386 ReturnHandle = SimpleFileSystemHandles[Index];
1387 break;
1388 }
1389 }
1390 }
1391
1392 SafeFreePool(DupDevicePath);
1393
1394 SafeFreePool(SimpleFileSystemHandles);
1395
1396 return ReturnHandle;
1397 }
1398
1399 /**
1400 Check to see if the network cable is plugged in. If the DevicePath is not
1401 connected it will be connected.
1402
1403 @param DevicePath Device Path to check
1404
1405 @retval TRUE DevicePath points to an Network that is connected
1406 @retval FALSE DevicePath does not point to a bootable network
1407
1408 **/
1409 BOOLEAN
1410 BdsLibNetworkBootWithMediaPresent (
1411 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1412 )
1413 {
1414 EFI_STATUS Status;
1415 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
1416 EFI_HANDLE Handle;
1417 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
1418 BOOLEAN MediaPresent;
1419
1420 MediaPresent = FALSE;
1421
1422 UpdatedDevicePath = DevicePath;
1423 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
1424 if (EFI_ERROR (Status)) {
1425 //
1426 // Device not present so see if we need to connect it
1427 //
1428 Status = BdsLibConnectDevicePath (DevicePath);
1429 if (!EFI_ERROR (Status)) {
1430 //
1431 // This one should work after we did the connect
1432 //
1433 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
1434 }
1435 }
1436
1437 if (!EFI_ERROR (Status)) {
1438 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
1439 if (!EFI_ERROR (Status)) {
1440 if (Snp->Mode->MediaPresentSupported) {
1441 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
1442 //
1443 // In case some one else is using the SNP check to see if it's connected
1444 //
1445 MediaPresent = Snp->Mode->MediaPresent;
1446 } else {
1447 //
1448 // No one is using SNP so we need to Start and Initialize so
1449 // MediaPresent will be valid.
1450 //
1451 Status = Snp->Start (Snp);
1452 if (!EFI_ERROR (Status)) {
1453 Status = Snp->Initialize (Snp, 0, 0);
1454 if (!EFI_ERROR (Status)) {
1455 MediaPresent = Snp->Mode->MediaPresent;
1456 Snp->Shutdown (Snp);
1457 }
1458 Snp->Stop (Snp);
1459 }
1460 }
1461 } else {
1462 MediaPresent = TRUE;
1463 }
1464 }
1465 }
1466
1467 return MediaPresent;
1468 }
1469
1470 /**
1471 For a bootable Device path, return its boot type.
1472
1473 @param DevicePath The bootable device Path to check
1474
1475 @retval BDS_EFI_MEDIA_HD_BOOT If the device path contains any media deviec path node, it is media boot type
1476 For the floppy node, handle it as media node
1477 @retval BDS_EFI_MEDIA_CDROM_BOOT If the device path contains any media deviec path node, it is media boot type
1478 For the floppy node, handle it as media node
1479 @retval BDS_EFI_ACPI_FLOPPY_BOOT If the device path contains any media deviec path node, it is media boot type
1480 For the floppy node, handle it as media node
1481 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If the device path not contains any media deviec path node, and
1482 its last device path node point to a message device path node, it is
1483
1484 @retval BDS_EFI_MESSAGE_SCSI_BOOT If the device path not contains any media deviec path node, and
1485 its last device path node point to a message device path node, it is
1486 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If the device path not contains any media deviec path node, and
1487 its last device path node point to a message device path node, it is
1488 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media deviec path node, and
1489 its last device path node point to a message device path node, it is
1490 @retval BDS_LEGACY_BBS_BOOT Legacy boot type
1491 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message devie,
1492
1493 **/
1494 UINT32
1495 EFIAPI
1496 BdsGetBootTypeFromDevicePath (
1497 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1498 )
1499 {
1500 ACPI_HID_DEVICE_PATH *Acpi;
1501 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1502 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1503
1504
1505 if (NULL == DevicePath) {
1506 return BDS_EFI_UNSUPPORT;
1507 }
1508
1509 TempDevicePath = DevicePath;
1510
1511 while (!IsDevicePathEndType (TempDevicePath)) {
1512 switch (DevicePathType (TempDevicePath)) {
1513 case BBS_DEVICE_PATH:
1514 return BDS_LEGACY_BBS_BOOT;
1515 case MEDIA_DEVICE_PATH:
1516 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
1517 return BDS_EFI_MEDIA_HD_BOOT;
1518 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
1519 return BDS_EFI_MEDIA_CDROM_BOOT;
1520 }
1521 break;
1522 case ACPI_DEVICE_PATH:
1523 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
1524 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
1525 return BDS_EFI_ACPI_FLOPPY_BOOT;
1526 }
1527 break;
1528 case MESSAGING_DEVICE_PATH:
1529 //
1530 // Get the last device path node
1531 //
1532 LastDeviceNode = NextDevicePathNode (TempDevicePath);
1533 if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
1534 //
1535 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
1536 // skit it
1537 //
1538 LastDeviceNode = NextDevicePathNode (LastDeviceNode);
1539 }
1540 //
1541 // if the device path not only point to driver device, it is not a messaging device path,
1542 //
1543 if (!IsDevicePathEndType (LastDeviceNode)) {
1544 break;
1545 }
1546
1547 if (DevicePathSubType(TempDevicePath) == MSG_ATAPI_DP) {
1548 return BDS_EFI_MESSAGE_ATAPI_BOOT;
1549 } else if (DevicePathSubType(TempDevicePath) == MSG_USB_DP) {
1550 return BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
1551 } else if (DevicePathSubType(TempDevicePath) == MSG_SCSI_DP) {
1552 return BDS_EFI_MESSAGE_SCSI_BOOT;
1553 }
1554 return BDS_EFI_MESSAGE_MISC_BOOT;
1555 default:
1556 break;
1557 }
1558 TempDevicePath = NextDevicePathNode (TempDevicePath);
1559 }
1560
1561 return BDS_EFI_UNSUPPORT;
1562 }
1563
1564 /**
1565 Check whether the Device path in a boot option point to a valide bootable device,
1566 And if CheckMedia is true, check the device is ready to boot now.
1567
1568 @param DevPath the Device path in a boot option
1569 @param CheckMedia if true, check the device is ready to boot now.
1570
1571 @retval TRUE the Device path is valide
1572 @retval FALSE the Device path is invalide .
1573
1574 **/
1575 BOOLEAN
1576 EFIAPI
1577 BdsLibIsValidEFIBootOptDevicePath (
1578 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
1579 IN BOOLEAN CheckMedia
1580 )
1581 {
1582 EFI_STATUS Status;
1583 EFI_HANDLE Handle;
1584 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1585 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1586 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1587
1588 TempDevicePath = DevPath;
1589 LastDeviceNode = DevPath;
1590
1591 //
1592 // Check if it's a valid boot option for network boot device
1593 // Only check if there is SimpleNetworkProtocol installed. If yes, that means
1594 // there is the network card there.
1595 //
1596 Status = gBS->LocateDevicePath (
1597 &gEfiSimpleNetworkProtocolGuid,
1598 &TempDevicePath,
1599 &Handle
1600 );
1601 if (EFI_ERROR (Status)) {
1602 //
1603 // Device not present so see if we need to connect it
1604 //
1605 TempDevicePath = DevPath;
1606 BdsLibConnectDevicePath (TempDevicePath);
1607 Status = gBS->LocateDevicePath (
1608 &gEfiSimpleNetworkProtocolGuid,
1609 &TempDevicePath,
1610 &Handle
1611 );
1612 }
1613
1614 if (!EFI_ERROR (Status)) {
1615 if (CheckMedia) {
1616 //
1617 // Test if it is ready to boot now
1618 //
1619 if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
1620 return TRUE;
1621 }
1622 } else {
1623 return TRUE;
1624 }
1625 }
1626
1627 //
1628 // If the boot option point to a file, it is a valid EFI boot option,
1629 // and assume it is ready to boot now
1630 //
1631 while (!EfiIsDevicePathEnd (TempDevicePath)) {
1632 LastDeviceNode = TempDevicePath;
1633 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
1634 }
1635 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
1636 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
1637 return TRUE;
1638 }
1639
1640 //
1641 // Check if it's a valid boot option for internal Shell
1642 //
1643 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
1644 //
1645 // If the boot option point to Internal FV shell, make sure it is valid
1646 //
1647 TempDevicePath = DevPath;
1648 Status = BdsLibUpdateFvFileDevicePath (&TempDevicePath, &gEfiShellFileGuid);
1649 if (Status == EFI_ALREADY_STARTED) {
1650 return TRUE;
1651 } else {
1652 if (Status == EFI_SUCCESS) {
1653 SafeFreePool (TempDevicePath);
1654 }
1655 return FALSE;
1656 }
1657 }
1658
1659 //
1660 // If the boot option point to a blockIO device, no matter whether or not it is a removeable device, it is a valid EFI boot option
1661 //
1662 TempDevicePath = DevPath;
1663 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1664 if (EFI_ERROR (Status)) {
1665 //
1666 // Device not present so see if we need to connect it
1667 //
1668 Status = BdsLibConnectDevicePath (DevPath);
1669 if (!EFI_ERROR (Status)) {
1670 //
1671 // Try again to get the Block Io protocol after we did the connect
1672 //
1673 TempDevicePath = DevPath;
1674 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1675 }
1676 }
1677
1678 if (!EFI_ERROR (Status)) {
1679 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1680 if (!EFI_ERROR (Status)) {
1681 if (CheckMedia) {
1682 //
1683 // Test if it is ready to boot now
1684 //
1685 if (BdsLibGetBootableHandle (DevPath) != NULL) {
1686 return TRUE;
1687 }
1688 } else {
1689 return TRUE;
1690 }
1691 }
1692 } else {
1693 //
1694 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
1695 //
1696 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
1697 if (!EFI_ERROR (Status)) {
1698 if (CheckMedia) {
1699 //
1700 // Test if it is ready to boot now
1701 //
1702 if (BdsLibGetBootableHandle (DevPath) != NULL) {
1703 return TRUE;
1704 }
1705 } else {
1706 return TRUE;
1707 }
1708 }
1709 }
1710
1711 return FALSE;
1712 }
1713
1714
1715 /**
1716 According to a file guild, check a Fv file device path is valid. If it is invalid,
1717 try to return the valid device path.
1718 FV address maybe changes for memory layout adjust from time to time, use this funciton
1719 could promise the Fv file device path is right.
1720
1721 @param DevicePath on input, the Fv file device path need to check on
1722 output, the updated valid Fv file device path
1723 @param FileGuid the Fv file guild
1724
1725 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
1726 parameter
1727 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
1728 guild at all
1729 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
1730 valid
1731 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
1732 and return the updated device path in DevicePath
1733
1734 **/
1735 EFI_STATUS
1736 EFIAPI
1737 BdsLibUpdateFvFileDevicePath (
1738 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
1739 IN EFI_GUID *FileGuid
1740 )
1741 {
1742 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1743 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1744 EFI_STATUS Status;
1745 EFI_GUID *GuidPoint;
1746 UINTN Index;
1747 UINTN FvHandleCount;
1748 EFI_HANDLE *FvHandleBuffer;
1749 EFI_FV_FILETYPE Type;
1750 UINTN Size;
1751 EFI_FV_FILE_ATTRIBUTES Attributes;
1752 UINT32 AuthenticationStatus;
1753 BOOLEAN FindFvFile;
1754 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1755 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1756 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
1757 EFI_HANDLE FoundFvHandle;
1758 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
1759
1760 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
1761 return EFI_INVALID_PARAMETER;
1762 }
1763 if (FileGuid == NULL) {
1764 return EFI_INVALID_PARAMETER;
1765 }
1766
1767 //
1768 // Check whether the device path point to the default the input Fv file
1769 //
1770 TempDevicePath = *DevicePath;
1771 LastDeviceNode = TempDevicePath;
1772 while (!EfiIsDevicePathEnd (TempDevicePath)) {
1773 LastDeviceNode = TempDevicePath;
1774 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
1775 }
1776 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
1777 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
1778 );
1779 if (GuidPoint == NULL) {
1780 //
1781 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
1782 //
1783 return EFI_UNSUPPORTED;
1784 }
1785 if (!CompareGuid (GuidPoint, FileGuid)) {
1786 //
1787 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
1788 //
1789 return EFI_UNSUPPORTED;
1790 }
1791
1792 //
1793 // Check whether the input Fv file device path is valid
1794 //
1795 TempDevicePath = *DevicePath;
1796 FoundFvHandle = NULL;
1797 Status = gBS->LocateDevicePath (
1798 &gEfiFirmwareVolume2ProtocolGuid,
1799 &TempDevicePath,
1800 &FoundFvHandle
1801 );
1802 if (!EFI_ERROR (Status)) {
1803 Status = gBS->HandleProtocol (
1804 FoundFvHandle,
1805 &gEfiFirmwareVolume2ProtocolGuid,
1806 (VOID **) &Fv
1807 );
1808 if (!EFI_ERROR (Status)) {
1809 //
1810 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
1811 //
1812 Status = Fv->ReadFile (
1813 Fv,
1814 FileGuid,
1815 NULL,
1816 &Size,
1817 &Type,
1818 &Attributes,
1819 &AuthenticationStatus
1820 );
1821 if (!EFI_ERROR (Status)) {
1822 return EFI_ALREADY_STARTED;
1823 }
1824 }
1825 }
1826
1827 //
1828 // Look for the input wanted FV file in current FV
1829 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
1830 //
1831 FindFvFile = FALSE;
1832 FoundFvHandle = NULL;
1833 Status = gBS->HandleProtocol (
1834 mBdsImageHandle,
1835 &gEfiLoadedImageProtocolGuid,
1836 (VOID **) &LoadedImage
1837 );
1838 if (!EFI_ERROR (Status)) {
1839 Status = gBS->HandleProtocol (
1840 LoadedImage->DeviceHandle,
1841 &gEfiFirmwareVolume2ProtocolGuid,
1842 (VOID **) &Fv
1843 );
1844 if (!EFI_ERROR (Status)) {
1845 Status = Fv->ReadFile (
1846 Fv,
1847 FileGuid,
1848 NULL,
1849 &Size,
1850 &Type,
1851 &Attributes,
1852 &AuthenticationStatus
1853 );
1854 if (!EFI_ERROR (Status)) {
1855 FindFvFile = TRUE;
1856 FoundFvHandle = LoadedImage->DeviceHandle;
1857 }
1858 }
1859 }
1860 //
1861 // Second, if fail to find, try to enumerate all FV
1862 //
1863 if (!FindFvFile) {
1864 FvHandleBuffer = NULL;
1865 gBS->LocateHandleBuffer (
1866 ByProtocol,
1867 &gEfiFirmwareVolume2ProtocolGuid,
1868 NULL,
1869 &FvHandleCount,
1870 &FvHandleBuffer
1871 );
1872 for (Index = 0; Index < FvHandleCount; Index++) {
1873 gBS->HandleProtocol (
1874 FvHandleBuffer[Index],
1875 &gEfiFirmwareVolume2ProtocolGuid,
1876 (VOID **) &Fv
1877 );
1878
1879 Status = Fv->ReadFile (
1880 Fv,
1881 FileGuid,
1882 NULL,
1883 &Size,
1884 &Type,
1885 &Attributes,
1886 &AuthenticationStatus
1887 );
1888 if (EFI_ERROR (Status)) {
1889 //
1890 // Skip if input Fv file not in the FV
1891 //
1892 continue;
1893 }
1894 FindFvFile = TRUE;
1895 FoundFvHandle = FvHandleBuffer[Index];
1896 break;
1897 }
1898
1899 SafeFreePool (FvHandleBuffer);
1900 }
1901
1902 if (FindFvFile) {
1903 //
1904 // Build the shell device path
1905 //
1906 NewDevicePath = DevicePathFromHandle (FoundFvHandle);
1907 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
1908 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
1909 *DevicePath = NewDevicePath;
1910 return EFI_SUCCESS;
1911 }
1912 return EFI_NOT_FOUND;
1913 }