]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c
1c5405f620e762fff7efe112ba52d5ad4d293bb8
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLibGrub / BdsPlatform.c
1 /** @file
2 Platform BDS customizations.
3
4 Copyright (C) 2020 James Bottomley, IBM Corporation.
5 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "BdsPlatform.h"
11 #include <Guid/RootBridgesConnectedEventGroup.h>
12 #include <Protocol/FirmwareVolume2.h>
13 #include <Library/PlatformBmPrintScLib.h>
14 #include <Library/Tcg2PhysicalPresenceLib.h>
15
16
17 //
18 // Global data
19 //
20
21 VOID *mEfiDevPathNotifyReg;
22 EFI_EVENT mEfiDevPathEvent;
23 UINT16 mHostBridgeDevId;
24
25 //
26 // Table of host IRQs matching PCI IRQs A-D
27 // (for configuring PCI Interrupt Line register)
28 //
29 CONST UINT8 PciHostIrqs[] = {
30 0x0a, 0x0a, 0x0b, 0x0b
31 };
32
33 //
34 // Type definitions
35 //
36
37 typedef
38 EFI_STATUS
39 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
40 IN EFI_HANDLE Handle,
41 IN VOID *Instance,
42 IN VOID *Context
43 );
44
45 /**
46 @param[in] Handle - Handle of PCI device instance
47 @param[in] PciIo - PCI IO protocol instance
48 @param[in] Pci - PCI Header register block
49 **/
50 typedef
51 EFI_STATUS
52 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
53 IN EFI_HANDLE Handle,
54 IN EFI_PCI_IO_PROTOCOL *PciIo,
55 IN PCI_TYPE00 *Pci
56 );
57
58
59 //
60 // Function prototypes
61 //
62
63 EFI_STATUS
64 VisitAllInstancesOfProtocol (
65 IN EFI_GUID *Id,
66 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
67 IN VOID *Context
68 );
69
70 EFI_STATUS
71 VisitAllPciInstancesOfProtocol (
72 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
73 );
74
75 VOID
76 InstallDevicePathCallback (
77 VOID
78 );
79
80 VOID
81 PlatformRegisterFvBootOption (
82 EFI_GUID *FileGuid,
83 CHAR16 *Description,
84 UINT32 Attributes
85 )
86 {
87 EFI_STATUS Status;
88 INTN OptionIndex;
89 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
90 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
91 UINTN BootOptionCount;
92 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
93 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
94 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
95
96 Status = gBS->HandleProtocol (
97 gImageHandle,
98 &gEfiLoadedImageProtocolGuid,
99 (VOID **) &LoadedImage
100 );
101 ASSERT_EFI_ERROR (Status);
102
103 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
104 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
105 ASSERT (DevicePath != NULL);
106 DevicePath = AppendDevicePathNode (
107 DevicePath,
108 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
109 );
110 ASSERT (DevicePath != NULL);
111
112 Status = EfiBootManagerInitializeLoadOption (
113 &NewOption,
114 LoadOptionNumberUnassigned,
115 LoadOptionTypeBoot,
116 Attributes,
117 Description,
118 DevicePath,
119 NULL,
120 0
121 );
122 ASSERT_EFI_ERROR (Status);
123 FreePool (DevicePath);
124
125 BootOptions = EfiBootManagerGetLoadOptions (
126 &BootOptionCount, LoadOptionTypeBoot
127 );
128
129 OptionIndex = EfiBootManagerFindLoadOption (
130 &NewOption, BootOptions, BootOptionCount
131 );
132
133 if (OptionIndex == -1) {
134 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
135 ASSERT_EFI_ERROR (Status);
136 }
137 EfiBootManagerFreeLoadOption (&NewOption);
138 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
139 }
140
141 /**
142 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
143 whose device paths do not resolve exactly to an FvFile in the system.
144
145 Also strip out every boot option that is not an FvFile, meaning the system
146 can only boot either the Grub or (if built) the shell.
147
148 This removes any boot options that point to binaries built into the firmware
149 and have become stale due to any of the following:
150 - DXEFV's base address or size changed (historical),
151 - DXEFV's FvNameGuid changed,
152 - the FILE_GUID of the pointed-to binary changed,
153 - the referenced binary is no longer built into the firmware.
154
155 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
156 avoids exact duplicates.
157 **/
158 VOID
159 RemoveStaleFvFileOptions (
160 VOID
161 )
162 {
163 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
164 UINTN BootOptionCount;
165 UINTN Index;
166
167 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
168 LoadOptionTypeBoot);
169
170 for (Index = 0; Index < BootOptionCount; ++Index) {
171 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
172 EFI_STATUS Status;
173 EFI_HANDLE FvHandle;
174
175 //
176 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
177 // then delete the boot option.
178 //
179 Node1 = BootOptions[Index].FilePath;
180 if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
181 DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
182 !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
183 DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
184 EfiBootManagerDeleteLoadOptionVariable (
185 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
186 continue;
187 }
188
189 //
190 // If the second device path node is not FvFile(...), then delete the boot
191 // option.
192 //
193 Node2 = NextDevicePathNode (Node1);
194 if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
195 DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
196 EfiBootManagerDeleteLoadOptionVariable (
197 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
198 continue;
199 }
200
201 //
202 // Locate the Firmware Volume2 protocol instance that is denoted by the
203 // boot option. If this lookup fails (i.e., the boot option references a
204 // firmware volume that doesn't exist), then we'll proceed to delete the
205 // boot option.
206 //
207 SearchNode = Node1;
208 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
209 &SearchNode, &FvHandle);
210
211 if (!EFI_ERROR (Status)) {
212 //
213 // The firmware volume was found; now let's see if it contains the FvFile
214 // identified by GUID.
215 //
216 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
217 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
218 UINTN BufferSize;
219 EFI_FV_FILETYPE FoundType;
220 EFI_FV_FILE_ATTRIBUTES FileAttributes;
221 UINT32 AuthenticationStatus;
222
223 Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
224 (VOID **)&FvProtocol);
225 ASSERT_EFI_ERROR (Status);
226
227 FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
228 //
229 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
230 // FileAttributes.
231 //
232 Status = FvProtocol->ReadFile (
233 FvProtocol,
234 &FvFileNode->FvFileName, // NameGuid
235 NULL, // Buffer
236 &BufferSize,
237 &FoundType,
238 &FileAttributes,
239 &AuthenticationStatus
240 );
241 if (!EFI_ERROR (Status)) {
242 //
243 // The FvFile was found. Keep the boot option.
244 //
245 continue;
246 }
247 }
248
249 //
250 // Delete the boot option.
251 //
252 Status = EfiBootManagerDeleteLoadOptionVariable (
253 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
254 DEBUG_CODE (
255 CHAR16 *DevicePathString;
256
257 DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
258 FALSE, FALSE);
259 DEBUG ((
260 EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
261 "%a: removing stale Boot#%04x %s: %r\n",
262 __FUNCTION__,
263 (UINT32)BootOptions[Index].OptionNumber,
264 DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
265 Status
266 ));
267 if (DevicePathString != NULL) {
268 FreePool (DevicePathString);
269 }
270 );
271 }
272
273 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
274 }
275
276 EFI_STATUS
277 EFIAPI
278 ConnectRootBridge (
279 IN EFI_HANDLE RootBridgeHandle,
280 IN VOID *Instance,
281 IN VOID *Context
282 );
283
284 STATIC
285 EFI_STATUS
286 EFIAPI
287 ConnectVirtioPciRng (
288 IN EFI_HANDLE Handle,
289 IN VOID *Instance,
290 IN VOID *Context
291 );
292
293 //
294 // BDS Platform Functions
295 //
296 /**
297 Do the platform init, can be customized by OEM/IBV
298
299 Possible things that can be done in PlatformBootManagerBeforeConsole:
300
301 > Update console variable: 1. include hot-plug devices;
302 > 2. Clear ConIn and add SOL for AMT
303 > Register new Driver#### or Boot####
304 > Register new Key####: e.g.: F12
305 > Signal ReadyToLock event
306 > Authentication action: 1. connect Auth devices;
307 > 2. Identify auto logon user.
308 **/
309 VOID
310 EFIAPI
311 PlatformBootManagerBeforeConsole (
312 VOID
313 )
314 {
315 EFI_HANDLE Handle;
316 EFI_STATUS Status;
317 UINT16 FrontPageTimeout;
318
319 FrontPageTimeout = 0;
320
321 DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n"));
322 InstallDevicePathCallback ();
323
324 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
325 ConnectRootBridge, NULL);
326
327 //
328 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
329 //
330 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
331
332 //
333 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
334 // the preparation of S3 system information. That logic has a hard dependency
335 // on the presence of the FACS ACPI table. Since our ACPI tables are only
336 // installed after PCI enumeration completes, we must not trigger the S3 save
337 // earlier, hence we can't signal End-of-Dxe earlier.
338 //
339 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
340
341 // We need to connect all trusted consoles for TCG PP. Here we treat all
342 // consoles in OVMF to be trusted consoles.
343 PlatformInitializeConsole (gPlatformConsole);
344
345 //
346 // Process TPM PPI request
347 //
348 Tcg2PhysicalPresenceLibProcessRequest (NULL);
349
350 //
351 // Prevent further changes to LockBoxes or SMRAM.
352 // Any TPM 2 Physical Presence Interface opcode must be handled before.
353 //
354 Handle = NULL;
355 Status = gBS->InstallProtocolInterface (&Handle,
356 &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
357 NULL);
358 ASSERT_EFI_ERROR (Status);
359
360 //
361 // Dispatch deferred images after EndOfDxe event and ReadyToLock
362 // installation.
363 //
364 EfiBootManagerDispatchDeferredImages ();
365
366 Status = gRT->SetVariable (
367 EFI_TIME_OUT_VARIABLE_NAME,
368 &gEfiGlobalVariableGuid,
369 (EFI_VARIABLE_NON_VOLATILE |
370 EFI_VARIABLE_BOOTSERVICE_ACCESS |
371 EFI_VARIABLE_RUNTIME_ACCESS),
372 sizeof FrontPageTimeout,
373 &FrontPageTimeout
374 );
375 //
376 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
377 // instances on Virtio PCI RNG devices.
378 //
379 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid, ConnectVirtioPciRng,
380 NULL);
381 }
382
383
384 EFI_STATUS
385 EFIAPI
386 ConnectRootBridge (
387 IN EFI_HANDLE RootBridgeHandle,
388 IN VOID *Instance,
389 IN VOID *Context
390 )
391 {
392 EFI_STATUS Status;
393
394 //
395 // Make the PCI bus driver connect the root bridge, non-recursively. This
396 // will produce a number of child handles with PciIo on them.
397 //
398 Status = gBS->ConnectController (
399 RootBridgeHandle, // ControllerHandle
400 NULL, // DriverImageHandle
401 NULL, // RemainingDevicePath -- produce all
402 // children
403 FALSE // Recursive
404 );
405 return Status;
406 }
407
408
409 STATIC
410 EFI_STATUS
411 EFIAPI
412 ConnectVirtioPciRng (
413 IN EFI_HANDLE Handle,
414 IN VOID *Instance,
415 IN VOID *Context
416 )
417 {
418 EFI_PCI_IO_PROTOCOL *PciIo;
419 EFI_STATUS Status;
420 UINT16 VendorId;
421 UINT16 DeviceId;
422 UINT8 RevisionId;
423 BOOLEAN Virtio10;
424 UINT16 SubsystemId;
425
426 PciIo = Instance;
427
428 //
429 // Read and check VendorId.
430 //
431 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,
432 1, &VendorId);
433 if (EFI_ERROR (Status)) {
434 goto Error;
435 }
436 if (VendorId != VIRTIO_VENDOR_ID) {
437 return EFI_SUCCESS;
438 }
439
440 //
441 // Read DeviceId and RevisionId.
442 //
443 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,
444 1, &DeviceId);
445 if (EFI_ERROR (Status)) {
446 goto Error;
447 }
448 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,
449 1, &RevisionId);
450 if (EFI_ERROR (Status)) {
451 goto Error;
452 }
453
454 //
455 // From DeviceId and RevisionId, determine whether the device is a
456 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
457 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
458 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
459 // only be sanity-checked, and SubsystemId will decide.
460 //
461 if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&
462 RevisionId >= 0x01) {
463 Virtio10 = TRUE;
464 } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {
465 Virtio10 = FALSE;
466 } else {
467 return EFI_SUCCESS;
468 }
469
470 //
471 // Read and check SubsystemId as dictated by Virtio10.
472 //
473 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,
474 PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);
475 if (EFI_ERROR (Status)) {
476 goto Error;
477 }
478 if ((Virtio10 && SubsystemId >= 0x40) ||
479 (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
480 Status = gBS->ConnectController (
481 Handle, // ControllerHandle
482 NULL, // DriverImageHandle -- connect all drivers
483 NULL, // RemainingDevicePath -- produce all child handles
484 FALSE // Recursive -- don't follow child handles
485 );
486 if (EFI_ERROR (Status)) {
487 goto Error;
488 }
489 }
490 return EFI_SUCCESS;
491
492 Error:
493 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
494 return Status;
495 }
496
497
498 /**
499 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
500
501 @param[in] DeviceHandle Handle of the LPC Bridge device.
502
503 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
504 ConOut, ConIn, and ErrOut.
505
506 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
507 from DeviceHandle.
508 **/
509 EFI_STATUS
510 PrepareLpcBridgeDevicePath (
511 IN EFI_HANDLE DeviceHandle
512 )
513 {
514 EFI_STATUS Status;
515 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
516 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
517 CHAR16 *DevPathStr;
518
519 DevicePath = NULL;
520 Status = gBS->HandleProtocol (
521 DeviceHandle,
522 &gEfiDevicePathProtocolGuid,
523 (VOID*)&DevicePath
524 );
525 if (EFI_ERROR (Status)) {
526 return Status;
527 }
528 TempDevicePath = DevicePath;
529
530 //
531 // Register Keyboard
532 //
533 DevicePath = AppendDevicePathNode (DevicePath,
534 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
535
536 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
537
538 //
539 // Register COM1
540 //
541 DevicePath = TempDevicePath;
542 gPnp16550ComPortDeviceNode.UID = 0;
543
544 DevicePath = AppendDevicePathNode (DevicePath,
545 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
546 DevicePath = AppendDevicePathNode (DevicePath,
547 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
548 DevicePath = AppendDevicePathNode (DevicePath,
549 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
550
551 //
552 // Print Device Path
553 //
554 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
555 if (DevPathStr != NULL) {
556 DEBUG((
557 DEBUG_INFO,
558 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
559 __LINE__,
560 gPnp16550ComPortDeviceNode.UID + 1,
561 DevPathStr
562 ));
563 FreePool(DevPathStr);
564 }
565
566 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
567 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
568 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
569
570 //
571 // Register COM2
572 //
573 DevicePath = TempDevicePath;
574 gPnp16550ComPortDeviceNode.UID = 1;
575
576 DevicePath = AppendDevicePathNode (DevicePath,
577 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
578 DevicePath = AppendDevicePathNode (DevicePath,
579 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
580 DevicePath = AppendDevicePathNode (DevicePath,
581 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
582
583 //
584 // Print Device Path
585 //
586 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
587 if (DevPathStr != NULL) {
588 DEBUG((
589 DEBUG_INFO,
590 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
591 __LINE__,
592 gPnp16550ComPortDeviceNode.UID + 1,
593 DevPathStr
594 ));
595 FreePool(DevPathStr);
596 }
597
598 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
599 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
600 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
601
602 return EFI_SUCCESS;
603 }
604
605 EFI_STATUS
606 GetGopDevicePath (
607 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
608 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
609 )
610 {
611 UINTN Index;
612 EFI_STATUS Status;
613 EFI_HANDLE PciDeviceHandle;
614 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
615 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
616 UINTN GopHandleCount;
617 EFI_HANDLE *GopHandleBuffer;
618
619 if (PciDevicePath == NULL || GopDevicePath == NULL) {
620 return EFI_INVALID_PARAMETER;
621 }
622
623 //
624 // Initialize the GopDevicePath to be PciDevicePath
625 //
626 *GopDevicePath = PciDevicePath;
627 TempPciDevicePath = PciDevicePath;
628
629 Status = gBS->LocateDevicePath (
630 &gEfiDevicePathProtocolGuid,
631 &TempPciDevicePath,
632 &PciDeviceHandle
633 );
634 if (EFI_ERROR (Status)) {
635 return Status;
636 }
637
638 //
639 // Try to connect this handle, so that GOP driver could start on this
640 // device and create child handles with GraphicsOutput Protocol installed
641 // on them, then we get device paths of these child handles and select
642 // them as possible console device.
643 //
644 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
645
646 Status = gBS->LocateHandleBuffer (
647 ByProtocol,
648 &gEfiGraphicsOutputProtocolGuid,
649 NULL,
650 &GopHandleCount,
651 &GopHandleBuffer
652 );
653 if (!EFI_ERROR (Status)) {
654 //
655 // Add all the child handles as possible Console Device
656 //
657 for (Index = 0; Index < GopHandleCount; Index++) {
658 Status = gBS->HandleProtocol (GopHandleBuffer[Index],
659 &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
660 if (EFI_ERROR (Status)) {
661 continue;
662 }
663 if (CompareMem (
664 PciDevicePath,
665 TempDevicePath,
666 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
667 ) == 0) {
668 //
669 // In current implementation, we only enable one of the child handles
670 // as console device, i.e. sotre one of the child handle's device
671 // path to variable "ConOut"
672 // In future, we could select all child handles to be console device
673 //
674
675 *GopDevicePath = TempDevicePath;
676
677 //
678 // Delete the PCI device's path that added by
679 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
680 //
681 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
682 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
683 }
684 }
685 gBS->FreePool (GopHandleBuffer);
686 }
687
688 return EFI_SUCCESS;
689 }
690
691 /**
692 Add PCI display to ConOut.
693
694 @param[in] DeviceHandle Handle of the PCI display device.
695
696 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
697
698 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
699 from DeviceHandle.
700 **/
701 EFI_STATUS
702 PreparePciDisplayDevicePath (
703 IN EFI_HANDLE DeviceHandle
704 )
705 {
706 EFI_STATUS Status;
707 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
708 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
709
710 DevicePath = NULL;
711 GopDevicePath = NULL;
712 Status = gBS->HandleProtocol (
713 DeviceHandle,
714 &gEfiDevicePathProtocolGuid,
715 (VOID*)&DevicePath
716 );
717 if (EFI_ERROR (Status)) {
718 return Status;
719 }
720
721 GetGopDevicePath (DevicePath, &GopDevicePath);
722 DevicePath = GopDevicePath;
723
724 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
725
726 return EFI_SUCCESS;
727 }
728
729 /**
730 Add PCI Serial to ConOut, ConIn, ErrOut.
731
732 @param[in] DeviceHandle Handle of the PCI serial device.
733
734 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
735 ErrOut.
736
737 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
738 from DeviceHandle.
739 **/
740 EFI_STATUS
741 PreparePciSerialDevicePath (
742 IN EFI_HANDLE DeviceHandle
743 )
744 {
745 EFI_STATUS Status;
746 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
747
748 DevicePath = NULL;
749 Status = gBS->HandleProtocol (
750 DeviceHandle,
751 &gEfiDevicePathProtocolGuid,
752 (VOID*)&DevicePath
753 );
754 if (EFI_ERROR (Status)) {
755 return Status;
756 }
757
758 DevicePath = AppendDevicePathNode (DevicePath,
759 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
760 DevicePath = AppendDevicePathNode (DevicePath,
761 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
762
763 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
764 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
765 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
766
767 return EFI_SUCCESS;
768 }
769
770 EFI_STATUS
771 VisitAllInstancesOfProtocol (
772 IN EFI_GUID *Id,
773 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
774 IN VOID *Context
775 )
776 {
777 EFI_STATUS Status;
778 UINTN HandleCount;
779 EFI_HANDLE *HandleBuffer;
780 UINTN Index;
781 VOID *Instance;
782
783 //
784 // Start to check all the PciIo to find all possible device
785 //
786 HandleCount = 0;
787 HandleBuffer = NULL;
788 Status = gBS->LocateHandleBuffer (
789 ByProtocol,
790 Id,
791 NULL,
792 &HandleCount,
793 &HandleBuffer
794 );
795 if (EFI_ERROR (Status)) {
796 return Status;
797 }
798
799 for (Index = 0; Index < HandleCount; Index++) {
800 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
801 if (EFI_ERROR (Status)) {
802 continue;
803 }
804
805 Status = (*CallBackFunction) (
806 HandleBuffer[Index],
807 Instance,
808 Context
809 );
810 }
811
812 gBS->FreePool (HandleBuffer);
813
814 return EFI_SUCCESS;
815 }
816
817
818 EFI_STATUS
819 EFIAPI
820 VisitingAPciInstance (
821 IN EFI_HANDLE Handle,
822 IN VOID *Instance,
823 IN VOID *Context
824 )
825 {
826 EFI_STATUS Status;
827 EFI_PCI_IO_PROTOCOL *PciIo;
828 PCI_TYPE00 Pci;
829
830 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
831
832 //
833 // Check for all PCI device
834 //
835 Status = PciIo->Pci.Read (
836 PciIo,
837 EfiPciIoWidthUint32,
838 0,
839 sizeof (Pci) / sizeof (UINT32),
840 &Pci
841 );
842 if (EFI_ERROR (Status)) {
843 return Status;
844 }
845
846 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
847 Handle,
848 PciIo,
849 &Pci
850 );
851
852 }
853
854
855
856 EFI_STATUS
857 VisitAllPciInstances (
858 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
859 )
860 {
861 return VisitAllInstancesOfProtocol (
862 &gEfiPciIoProtocolGuid,
863 VisitingAPciInstance,
864 (VOID*)(UINTN) CallBackFunction
865 );
866 }
867
868
869 /**
870 Do platform specific PCI Device check and add them to
871 ConOut, ConIn, ErrOut.
872
873 @param[in] Handle - Handle of PCI device instance
874 @param[in] PciIo - PCI IO protocol instance
875 @param[in] Pci - PCI Header register block
876
877 @retval EFI_SUCCESS - PCI Device check and Console variable update
878 successfully.
879 @retval EFI_STATUS - PCI Device check or Console variable update fail.
880
881 **/
882 EFI_STATUS
883 EFIAPI
884 DetectAndPreparePlatformPciDevicePath (
885 IN EFI_HANDLE Handle,
886 IN EFI_PCI_IO_PROTOCOL *PciIo,
887 IN PCI_TYPE00 *Pci
888 )
889 {
890 EFI_STATUS Status;
891
892 Status = PciIo->Attributes (
893 PciIo,
894 EfiPciIoAttributeOperationEnable,
895 EFI_PCI_DEVICE_ENABLE,
896 NULL
897 );
898 ASSERT_EFI_ERROR (Status);
899
900 //
901 // Here we decide whether it is LPC Bridge
902 //
903 if ((IS_PCI_LPC (Pci)) ||
904 ((IS_PCI_ISA_PDECODE (Pci)) &&
905 (Pci->Hdr.VendorId == 0x8086) &&
906 (Pci->Hdr.DeviceId == 0x7000)
907 )
908 ) {
909 //
910 // Add IsaKeyboard to ConIn,
911 // add IsaSerial to ConOut, ConIn, ErrOut
912 //
913 DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));
914 PrepareLpcBridgeDevicePath (Handle);
915 return EFI_SUCCESS;
916 }
917 //
918 // Here we decide which Serial device to enable in PCI bus
919 //
920 if (IS_PCI_16550SERIAL (Pci)) {
921 //
922 // Add them to ConOut, ConIn, ErrOut.
923 //
924 DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));
925 PreparePciSerialDevicePath (Handle);
926 return EFI_SUCCESS;
927 }
928
929 //
930 // Here we decide which display device to enable in PCI bus
931 //
932 if (IS_PCI_DISPLAY (Pci)) {
933 //
934 // Add them to ConOut.
935 //
936 DEBUG ((DEBUG_INFO, "Found PCI display device\n"));
937 PreparePciDisplayDevicePath (Handle);
938 return EFI_SUCCESS;
939 }
940
941 return Status;
942 }
943
944
945 /**
946 Connect the predefined platform default console device.
947
948 Always try to find and enable PCI display devices.
949
950 @param[in] PlatformConsole Predefined platform default console device array.
951 **/
952 VOID
953 PlatformInitializeConsole (
954 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
955 )
956 {
957 UINTN Index;
958
959 //
960 // Do platform specific PCI Device check and add them to ConOut, ConIn,
961 // ErrOut
962 //
963 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
964
965 //
966 // Have chance to connect the platform default console,
967 // the platform default console is the minimum device group
968 // the platform should support
969 //
970 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
971 //
972 // Update the console variable with the connect type
973 //
974 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
975 EfiBootManagerUpdateConsoleVariable (ConIn,
976 PlatformConsole[Index].DevicePath, NULL);
977 }
978 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
979 EfiBootManagerUpdateConsoleVariable (ConOut,
980 PlatformConsole[Index].DevicePath, NULL);
981 }
982 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
983 EfiBootManagerUpdateConsoleVariable (ErrOut,
984 PlatformConsole[Index].DevicePath, NULL);
985 }
986 }
987 }
988
989
990 /**
991 Configure PCI Interrupt Line register for applicable devices
992 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
993
994 @param[in] Handle - Handle of PCI device instance
995 @param[in] PciIo - PCI IO protocol instance
996 @param[in] PciHdr - PCI Header register block
997
998 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
999
1000 **/
1001 EFI_STATUS
1002 EFIAPI
1003 SetPciIntLine (
1004 IN EFI_HANDLE Handle,
1005 IN EFI_PCI_IO_PROTOCOL *PciIo,
1006 IN PCI_TYPE00 *PciHdr
1007 )
1008 {
1009 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1010 EFI_DEVICE_PATH_PROTOCOL *DevPath;
1011 UINTN RootSlot;
1012 UINTN Idx;
1013 UINT8 IrqLine;
1014 EFI_STATUS Status;
1015 UINT32 RootBusNumber;
1016
1017 Status = EFI_SUCCESS;
1018
1019 if (PciHdr->Device.InterruptPin != 0) {
1020
1021 DevPathNode = DevicePathFromHandle (Handle);
1022 ASSERT (DevPathNode != NULL);
1023 DevPath = DevPathNode;
1024
1025 RootBusNumber = 0;
1026 if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
1027 DevicePathSubType (DevPathNode) == ACPI_DP &&
1028 ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
1029 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
1030 }
1031
1032 //
1033 // Compute index into PciHostIrqs[] table by walking
1034 // the device path and adding up all device numbers
1035 //
1036 Status = EFI_NOT_FOUND;
1037 RootSlot = 0;
1038 Idx = PciHdr->Device.InterruptPin - 1;
1039 while (!IsDevicePathEnd (DevPathNode)) {
1040 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
1041 DevicePathSubType (DevPathNode) == HW_PCI_DP) {
1042
1043 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1044
1045 //
1046 // Unlike SeaBIOS, which starts climbing from the leaf device
1047 // up toward the root, we traverse the device path starting at
1048 // the root moving toward the leaf node.
1049 // The slot number of the top-level parent bridge is needed for
1050 // Q35 cases with more than 24 slots on the root bus.
1051 //
1052 if (Status != EFI_SUCCESS) {
1053 Status = EFI_SUCCESS;
1054 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1055 }
1056 }
1057
1058 DevPathNode = NextDevicePathNode (DevPathNode);
1059 }
1060 if (EFI_ERROR (Status)) {
1061 return Status;
1062 }
1063 if (RootBusNumber == 0 && RootSlot == 0) {
1064 DEBUG((
1065 DEBUG_ERROR,
1066 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1067 __FUNCTION__
1068 ));
1069 ASSERT (FALSE);
1070 }
1071
1072 //
1073 // Final PciHostIrqs[] index calculation depends on the platform
1074 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1075 //
1076 switch (mHostBridgeDevId) {
1077 case INTEL_82441_DEVICE_ID:
1078 Idx -= 1;
1079 break;
1080 case INTEL_Q35_MCH_DEVICE_ID:
1081 //
1082 // SeaBIOS contains the following comment:
1083 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1084 // with a different starting index - see q35-acpi-dsdt.dsl.
1085 //
1086 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1087 //
1088 if (RootSlot > 24) {
1089 //
1090 // in this case, subtract back out RootSlot from Idx
1091 // (SeaBIOS never adds it to begin with, but that would make our
1092 // device path traversal loop above too awkward)
1093 //
1094 Idx -= RootSlot;
1095 }
1096 break;
1097 default:
1098 ASSERT (FALSE); // should never get here
1099 }
1100 Idx %= ARRAY_SIZE (PciHostIrqs);
1101 IrqLine = PciHostIrqs[Idx];
1102
1103 DEBUG_CODE_BEGIN ();
1104 {
1105 CHAR16 *DevPathString;
1106 STATIC CHAR16 Fallback[] = L"<failed to convert>";
1107 UINTN Segment, Bus, Device, Function;
1108
1109 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
1110 if (DevPathString == NULL) {
1111 DevPathString = Fallback;
1112 }
1113 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
1114 ASSERT_EFI_ERROR (Status);
1115
1116 DEBUG ((DEBUG_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
1117 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
1118 IrqLine));
1119
1120 if (DevPathString != Fallback) {
1121 FreePool (DevPathString);
1122 }
1123 }
1124 DEBUG_CODE_END ();
1125
1126 //
1127 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1128 //
1129 Status = PciIo->Pci.Write (
1130 PciIo,
1131 EfiPciIoWidthUint8,
1132 PCI_INT_LINE_OFFSET,
1133 1,
1134 &IrqLine
1135 );
1136 }
1137
1138 return Status;
1139 }
1140
1141
1142 VOID
1143 PciAcpiInitialization (
1144 )
1145 {
1146 UINTN Pmba;
1147
1148 //
1149 // Query Host Bridge DID to determine platform type
1150 //
1151 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
1152 switch (mHostBridgeDevId) {
1153 case INTEL_82441_DEVICE_ID:
1154 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1155 //
1156 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1157 //
1158 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1159 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1160 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1161 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1162 break;
1163 case INTEL_Q35_MCH_DEVICE_ID:
1164 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1165 //
1166 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1167 //
1168 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1169 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1170 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1171 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1172 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1173 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1174 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1175 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1176 break;
1177 default:
1178 DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1179 __FUNCTION__, mHostBridgeDevId));
1180 ASSERT (FALSE);
1181 return;
1182 }
1183
1184 //
1185 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1186 //
1187 VisitAllPciInstances (SetPciIntLine);
1188
1189 //
1190 // Set ACPI SCI_EN bit in PMCNTRL
1191 //
1192 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1193 }
1194
1195 EFI_STATUS
1196 EFIAPI
1197 ConnectRecursivelyIfPciMassStorage (
1198 IN EFI_HANDLE Handle,
1199 IN EFI_PCI_IO_PROTOCOL *Instance,
1200 IN PCI_TYPE00 *PciHeader
1201 )
1202 {
1203 EFI_STATUS Status;
1204 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1205 CHAR16 *DevPathStr;
1206
1207 //
1208 // Recognize PCI Mass Storage
1209 //
1210 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
1211 DevicePath = NULL;
1212 Status = gBS->HandleProtocol (
1213 Handle,
1214 &gEfiDevicePathProtocolGuid,
1215 (VOID*)&DevicePath
1216 );
1217 if (EFI_ERROR (Status)) {
1218 return Status;
1219 }
1220
1221 //
1222 // Print Device Path
1223 //
1224 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1225 if (DevPathStr != NULL) {
1226 DEBUG((
1227 DEBUG_INFO,
1228 "Found Mass Storage device: %s\n",
1229 DevPathStr
1230 ));
1231 FreePool(DevPathStr);
1232 }
1233
1234 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
1235 if (EFI_ERROR (Status)) {
1236 return Status;
1237 }
1238
1239 }
1240
1241 return EFI_SUCCESS;
1242 }
1243
1244
1245 /**
1246 Connect with predefined platform connect sequence.
1247
1248 The OEM/IBV can customize with their own connect sequence.
1249 **/
1250 VOID
1251 PlatformBdsConnectSequence (
1252 VOID
1253 )
1254 {
1255 UINTN Index;
1256
1257 DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));
1258
1259 Index = 0;
1260
1261 //
1262 // Here we can get the customized platform connect sequence
1263 // Notes: we can connect with new variable which record the
1264 // last time boots connect device path sequence
1265 //
1266 while (gPlatformConnectSequence[Index] != NULL) {
1267 //
1268 // Build the platform boot option
1269 //
1270 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1271 Index++;
1272 }
1273 EfiBootManagerConnectAll ();
1274 }
1275
1276 /**
1277 Do the platform specific action after the console is ready
1278
1279 Possible things that can be done in PlatformBootManagerAfterConsole:
1280
1281 > Console post action:
1282 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1283 > Signal console ready platform customized event
1284 > Run diagnostics like memory testing
1285 > Connect certain devices
1286 > Dispatch aditional option roms
1287 > Special boot: e.g.: USB boot, enter UI
1288 **/
1289 VOID
1290 EFIAPI
1291 PlatformBootManagerAfterConsole (
1292 VOID
1293 )
1294 {
1295 EFI_BOOT_MODE BootMode;
1296
1297 DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));
1298
1299 //
1300 // Get current Boot Mode
1301 //
1302 BootMode = GetBootModeHob ();
1303 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));
1304
1305 //
1306 // Go the different platform policy with different boot mode
1307 // Notes: this part code can be change with the table policy
1308 //
1309 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1310
1311 //
1312 // Logo show
1313 //
1314 BootLogoEnableLogo ();
1315
1316 //
1317 // Set PCI Interrupt Line registers and ACPI SCI_EN
1318 //
1319 PciAcpiInitialization ();
1320
1321 //
1322 // Process QEMU's -kernel command line option
1323 //
1324 TryRunningQemuKernel ();
1325
1326 //
1327 // Perform some platform specific connect sequence
1328 //
1329 PlatformBdsConnectSequence ();
1330
1331 EfiBootManagerRefreshAllBootOption ();
1332
1333 //
1334 // Register UEFI Shell (Will be removed if the Shell isn't built
1335 // which is the default)
1336 //
1337 PlatformRegisterFvBootOption (
1338 &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
1339 );
1340
1341 //
1342 // Register Grub
1343 //
1344 PlatformRegisterFvBootOption (
1345 &gGrubFileGuid, L"Grub Bootloader", LOAD_OPTION_ACTIVE
1346 );
1347
1348 RemoveStaleFvFileOptions ();
1349
1350 PlatformBmPrintScRegisterHandler ();
1351 }
1352
1353 /**
1354 This notification function is invoked when an instance of the
1355 EFI_DEVICE_PATH_PROTOCOL is produced.
1356
1357 @param Event The event that occurred
1358 @param Context For EFI compatibility. Not used.
1359
1360 **/
1361 VOID
1362 EFIAPI
1363 NotifyDevPath (
1364 IN EFI_EVENT Event,
1365 IN VOID *Context
1366 )
1367 {
1368 EFI_HANDLE Handle;
1369 EFI_STATUS Status;
1370 UINTN BufferSize;
1371 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1372 ATAPI_DEVICE_PATH *Atapi;
1373
1374 //
1375 // Examine all new handles
1376 //
1377 for (;;) {
1378 //
1379 // Get the next handle
1380 //
1381 BufferSize = sizeof (Handle);
1382 Status = gBS->LocateHandle (
1383 ByRegisterNotify,
1384 NULL,
1385 mEfiDevPathNotifyReg,
1386 &BufferSize,
1387 &Handle
1388 );
1389
1390 //
1391 // If not found, we're done
1392 //
1393 if (EFI_NOT_FOUND == Status) {
1394 break;
1395 }
1396
1397 if (EFI_ERROR (Status)) {
1398 continue;
1399 }
1400
1401 //
1402 // Get the DevicePath protocol on that handle
1403 //
1404 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,
1405 (VOID **)&DevPathNode);
1406 ASSERT_EFI_ERROR (Status);
1407
1408 while (!IsDevicePathEnd (DevPathNode)) {
1409 //
1410 // Find the handler to dump this device path node
1411 //
1412 if (
1413 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1414 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1415 ) {
1416 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1417 PciOr16 (
1418 PCI_LIB_ADDRESS (
1419 0,
1420 1,
1421 1,
1422 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1423 ),
1424 BIT15
1425 );
1426 }
1427
1428 //
1429 // Next device path node
1430 //
1431 DevPathNode = NextDevicePathNode (DevPathNode);
1432 }
1433 }
1434
1435 return;
1436 }
1437
1438
1439 VOID
1440 InstallDevicePathCallback (
1441 VOID
1442 )
1443 {
1444 DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));
1445 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1446 &gEfiDevicePathProtocolGuid,
1447 TPL_CALLBACK,
1448 NotifyDevPath,
1449 NULL,
1450 &mEfiDevPathNotifyReg
1451 );
1452 }
1453
1454 /**
1455 This function is called each second during the boot manager waits the
1456 timeout.
1457
1458 @param TimeoutRemain The remaining timeout.
1459 **/
1460 VOID
1461 EFIAPI
1462 PlatformBootManagerWaitCallback (
1463 UINT16 TimeoutRemain
1464 )
1465 {
1466 //
1467 // Since the timeout should be forced to zero we should never
1468 // Get here
1469 //
1470 ASSERT (FALSE);
1471 }
1472
1473 /**
1474 The function is called when no boot option could be launched,
1475 including platform recovery options and options pointing to applications
1476 built into firmware volumes.
1477
1478 If this function returns, BDS attempts to enter an infinite loop.
1479 **/
1480 VOID
1481 EFIAPI
1482 PlatformBootManagerUnableToBoot (
1483 VOID
1484 )
1485 {
1486 //
1487 // If we get here something failed about the grub boot but since
1488 // We're privy to the secret we must panic and not retry or loop
1489 //
1490 ASSERT (FALSE);
1491 CpuDeadLoop ();
1492 }