]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.c
OvmfPkg: Reproduce builds across source format changes
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLibBhyve / BdsPlatform.c
1 /** @file
2 Platform BDS customizations.
3
4 Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
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 #include <Protocol/BlockIo.h>
17
18 //
19 // Global data
20 //
21
22 VOID *mEfiDevPathNotifyReg;
23 EFI_EVENT mEfiDevPathEvent;
24 VOID *mEmuVariableEventReg;
25 EFI_EVENT mEmuVariableEvent;
26 UINT16 mHostBridgeDevId;
27
28 //
29 // Table of host IRQs matching PCI IRQs A-D
30 // (for configuring PCI Interrupt Line register)
31 //
32 CONST UINT8 PciHostIrqs[] = {
33 0x0a, 0x0a, 0x0b, 0x0b
34 };
35
36 //
37 // Type definitions
38 //
39
40 typedef
41 EFI_STATUS
42 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
43 IN EFI_HANDLE Handle,
44 IN VOID *Instance,
45 IN VOID *Context
46 );
47
48 /**
49 @param[in] Handle - Handle of PCI device instance
50 @param[in] PciIo - PCI IO protocol instance
51 @param[in] Pci - PCI Header register block
52 **/
53 typedef
54 EFI_STATUS
55 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
56 IN EFI_HANDLE Handle,
57 IN EFI_PCI_IO_PROTOCOL *PciIo,
58 IN PCI_TYPE00 *Pci
59 );
60
61
62 //
63 // Function prototypes
64 //
65
66 EFI_STATUS
67 VisitAllInstancesOfProtocol (
68 IN EFI_GUID *Id,
69 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
70 IN VOID *Context
71 );
72
73 EFI_STATUS
74 VisitAllPciInstancesOfProtocol (
75 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
76 );
77
78 VOID
79 InstallDevicePathCallback (
80 VOID
81 );
82
83 VOID
84 PlatformRegisterFvBootOption (
85 EFI_GUID *FileGuid,
86 CHAR16 *Description,
87 UINT32 Attributes
88 )
89 {
90 EFI_STATUS Status;
91 INTN OptionIndex;
92 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
93 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
94 UINTN BootOptionCount;
95 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
96 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
97 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
98
99 Status = gBS->HandleProtocol (
100 gImageHandle,
101 &gEfiLoadedImageProtocolGuid,
102 (VOID **) &LoadedImage
103 );
104 ASSERT_EFI_ERROR (Status);
105
106 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
107 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
108 ASSERT (DevicePath != NULL);
109 DevicePath = AppendDevicePathNode (
110 DevicePath,
111 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
112 );
113 ASSERT (DevicePath != NULL);
114
115 Status = EfiBootManagerInitializeLoadOption (
116 &NewOption,
117 LoadOptionNumberUnassigned,
118 LoadOptionTypeBoot,
119 Attributes,
120 Description,
121 DevicePath,
122 NULL,
123 0
124 );
125 ASSERT_EFI_ERROR (Status);
126 FreePool (DevicePath);
127
128 BootOptions = EfiBootManagerGetLoadOptions (
129 &BootOptionCount, LoadOptionTypeBoot
130 );
131
132 OptionIndex = EfiBootManagerFindLoadOption (
133 &NewOption, BootOptions, BootOptionCount
134 );
135
136 if (OptionIndex == -1) {
137 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
138 ASSERT_EFI_ERROR (Status);
139 }
140 EfiBootManagerFreeLoadOption (&NewOption);
141 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
142 }
143
144 /**
145 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
146 whose device paths do not resolve exactly to an FvFile in the system.
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 keep 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 continue;
185 }
186
187 //
188 // If the second device path node is not FvFile(...), then keep the boot
189 // option.
190 //
191 Node2 = NextDevicePathNode (Node1);
192 if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
193 DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
194 continue;
195 }
196
197 //
198 // Locate the Firmware Volume2 protocol instance that is denoted by the
199 // boot option. If this lookup fails (i.e., the boot option references a
200 // firmware volume that doesn't exist), then we'll proceed to delete the
201 // boot option.
202 //
203 SearchNode = Node1;
204 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
205 &SearchNode, &FvHandle);
206
207 if (!EFI_ERROR (Status)) {
208 //
209 // The firmware volume was found; now let's see if it contains the FvFile
210 // identified by GUID.
211 //
212 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
213 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
214 UINTN BufferSize;
215 EFI_FV_FILETYPE FoundType;
216 EFI_FV_FILE_ATTRIBUTES FileAttributes;
217 UINT32 AuthenticationStatus;
218
219 Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
220 (VOID **)&FvProtocol);
221 ASSERT_EFI_ERROR (Status);
222
223 FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
224 //
225 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
226 // FileAttributes.
227 //
228 Status = FvProtocol->ReadFile (
229 FvProtocol,
230 &FvFileNode->FvFileName, // NameGuid
231 NULL, // Buffer
232 &BufferSize,
233 &FoundType,
234 &FileAttributes,
235 &AuthenticationStatus
236 );
237 if (!EFI_ERROR (Status)) {
238 //
239 // The FvFile was found. Keep the boot option.
240 //
241 continue;
242 }
243 }
244
245 //
246 // Delete the boot option.
247 //
248 Status = EfiBootManagerDeleteLoadOptionVariable (
249 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
250 DEBUG_CODE (
251 CHAR16 *DevicePathString;
252
253 DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
254 FALSE, FALSE);
255 DEBUG ((
256 EFI_ERROR (Status) ? EFI_D_WARN : DEBUG_VERBOSE,
257 "%a: removing stale Boot#%04x %s: %r\n",
258 __FUNCTION__,
259 (UINT32)BootOptions[Index].OptionNumber,
260 DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
261 Status
262 ));
263 if (DevicePathString != NULL) {
264 FreePool (DevicePathString);
265 }
266 );
267 }
268
269 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
270 }
271
272 VOID
273 PlatformRegisterOptionsAndKeys (
274 VOID
275 )
276 {
277 EFI_STATUS Status;
278 EFI_INPUT_KEY Enter;
279 EFI_INPUT_KEY F2;
280 EFI_INPUT_KEY Esc;
281 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
282
283 //
284 // Register ENTER as CONTINUE key
285 //
286 Enter.ScanCode = SCAN_NULL;
287 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
288 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
289 ASSERT_EFI_ERROR (Status);
290
291 //
292 // Map F2 to Boot Manager Menu
293 //
294 F2.ScanCode = SCAN_F2;
295 F2.UnicodeChar = CHAR_NULL;
296 Esc.ScanCode = SCAN_ESC;
297 Esc.UnicodeChar = CHAR_NULL;
298 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
299 ASSERT_EFI_ERROR (Status);
300 Status = EfiBootManagerAddKeyOptionVariable (
301 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
302 );
303 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
304 Status = EfiBootManagerAddKeyOptionVariable (
305 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
306 );
307 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
308 }
309
310 EFI_STATUS
311 EFIAPI
312 ConnectRootBridge (
313 IN EFI_HANDLE RootBridgeHandle,
314 IN VOID *Instance,
315 IN VOID *Context
316 );
317
318 STATIC
319 EFI_STATUS
320 EFIAPI
321 ConnectVirtioPciRng (
322 IN EFI_HANDLE Handle,
323 IN VOID *Instance,
324 IN VOID *Context
325 );
326
327 STATIC
328 VOID
329 SaveS3BootScript (
330 VOID
331 );
332
333 //
334 // BDS Platform Functions
335 //
336 /**
337 Do the platform init, can be customized by OEM/IBV
338
339 Possible things that can be done in PlatformBootManagerBeforeConsole:
340
341 > Update console variable: 1. include hot-plug devices;
342 > 2. Clear ConIn and add SOL for AMT
343 > Register new Driver#### or Boot####
344 > Register new Key####: e.g.: F12
345 > Signal ReadyToLock event
346 > Authentication action: 1. connect Auth devices;
347 > 2. Identify auto logon user.
348 **/
349 VOID
350 EFIAPI
351 PlatformBootManagerBeforeConsole (
352 VOID
353 )
354 {
355 EFI_HANDLE Handle;
356 EFI_STATUS Status;
357
358 DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n"));
359 InstallDevicePathCallback ();
360
361 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
362 ConnectRootBridge, NULL);
363
364 //
365 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
366 //
367 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
368
369 //
370 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
371 // the preparation of S3 system information. That logic has a hard dependency
372 // on the presence of the FACS ACPI table. Since our ACPI tables are only
373 // installed after PCI enumeration completes, we must not trigger the S3 save
374 // earlier, hence we can't signal End-of-Dxe earlier.
375 //
376 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
377
378 // We need to connect all trusted consoles for TCG PP. Here we treat all
379 // consoles in OVMF to be trusted consoles.
380 PlatformInitializeConsole (gPlatformConsole);
381
382 //
383 // Process TPM PPI request
384 //
385 Tcg2PhysicalPresenceLibProcessRequest (NULL);
386
387 //
388 // Prevent further changes to LockBoxes or SMRAM.
389 // Any TPM 2 Physical Presence Interface opcode must be handled before.
390 //
391 Handle = NULL;
392 Status = gBS->InstallProtocolInterface (&Handle,
393 &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
394 NULL);
395 ASSERT_EFI_ERROR (Status);
396
397 //
398 // Dispatch deferred images after EndOfDxe event and ReadyToLock
399 // installation.
400 //
401 EfiBootManagerDispatchDeferredImages ();
402
403 PlatformRegisterOptionsAndKeys ();
404
405 //
406 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
407 // instances on Virtio PCI RNG devices.
408 //
409 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid, ConnectVirtioPciRng,
410 NULL);
411 }
412
413
414 EFI_STATUS
415 EFIAPI
416 ConnectRootBridge (
417 IN EFI_HANDLE RootBridgeHandle,
418 IN VOID *Instance,
419 IN VOID *Context
420 )
421 {
422 EFI_STATUS Status;
423
424 //
425 // Make the PCI bus driver connect the root bridge, non-recursively. This
426 // will produce a number of child handles with PciIo on them.
427 //
428 Status = gBS->ConnectController (
429 RootBridgeHandle, // ControllerHandle
430 NULL, // DriverImageHandle
431 NULL, // RemainingDevicePath -- produce all
432 // children
433 FALSE // Recursive
434 );
435 return Status;
436 }
437
438
439 STATIC
440 EFI_STATUS
441 EFIAPI
442 ConnectVirtioPciRng (
443 IN EFI_HANDLE Handle,
444 IN VOID *Instance,
445 IN VOID *Context
446 )
447 {
448 EFI_PCI_IO_PROTOCOL *PciIo;
449 EFI_STATUS Status;
450 UINT16 VendorId;
451 UINT16 DeviceId;
452 UINT8 RevisionId;
453 BOOLEAN Virtio10;
454 UINT16 SubsystemId;
455
456 PciIo = Instance;
457
458 //
459 // Read and check VendorId.
460 //
461 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,
462 1, &VendorId);
463 if (EFI_ERROR (Status)) {
464 goto Error;
465 }
466 if (VendorId != VIRTIO_VENDOR_ID) {
467 return EFI_SUCCESS;
468 }
469
470 //
471 // Read DeviceId and RevisionId.
472 //
473 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,
474 1, &DeviceId);
475 if (EFI_ERROR (Status)) {
476 goto Error;
477 }
478 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,
479 1, &RevisionId);
480 if (EFI_ERROR (Status)) {
481 goto Error;
482 }
483
484 //
485 // From DeviceId and RevisionId, determine whether the device is a
486 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
487 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
488 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
489 // only be sanity-checked, and SubsystemId will decide.
490 //
491 if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&
492 RevisionId >= 0x01) {
493 Virtio10 = TRUE;
494 } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {
495 Virtio10 = FALSE;
496 } else {
497 return EFI_SUCCESS;
498 }
499
500 //
501 // Read and check SubsystemId as dictated by Virtio10.
502 //
503 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,
504 PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);
505 if (EFI_ERROR (Status)) {
506 goto Error;
507 }
508 if ((Virtio10 && SubsystemId >= 0x40) ||
509 (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
510 Status = gBS->ConnectController (
511 Handle, // ControllerHandle
512 NULL, // DriverImageHandle -- connect all drivers
513 NULL, // RemainingDevicePath -- produce all child handles
514 FALSE // Recursive -- don't follow child handles
515 );
516 if (EFI_ERROR (Status)) {
517 goto Error;
518 }
519 }
520 return EFI_SUCCESS;
521
522 Error:
523 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
524 return Status;
525 }
526
527
528 /**
529 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
530
531 @param[in] DeviceHandle Handle of the LPC Bridge device.
532
533 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
534 ConOut, ConIn, and ErrOut.
535
536 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
537 from DeviceHandle.
538 **/
539 EFI_STATUS
540 PrepareLpcBridgeDevicePath (
541 IN EFI_HANDLE DeviceHandle
542 )
543 {
544 EFI_STATUS Status;
545 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
546 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
547 CHAR16 *DevPathStr;
548
549 DevicePath = NULL;
550 Status = gBS->HandleProtocol (
551 DeviceHandle,
552 &gEfiDevicePathProtocolGuid,
553 (VOID*)&DevicePath
554 );
555 if (EFI_ERROR (Status)) {
556 return Status;
557 }
558 TempDevicePath = DevicePath;
559
560 //
561 // Register Keyboard
562 //
563 DevicePath = AppendDevicePathNode (DevicePath,
564 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
565
566 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
567
568 //
569 // Register COM1
570 //
571 DevicePath = TempDevicePath;
572 gPnp16550ComPortDeviceNode.UID = 0;
573
574 DevicePath = AppendDevicePathNode (DevicePath,
575 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
576 DevicePath = AppendDevicePathNode (DevicePath,
577 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
578 DevicePath = AppendDevicePathNode (DevicePath,
579 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
580
581 //
582 // Print Device Path
583 //
584 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
585 if (DevPathStr != NULL) {
586 DEBUG((
587 DEBUG_INFO,
588 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
589 DEBUG_LINE_NUMBER,
590 gPnp16550ComPortDeviceNode.UID + 1,
591 DevPathStr
592 ));
593 FreePool(DevPathStr);
594 }
595
596 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
597 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
598 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
599
600 // Don't register COM2 which can be used for DBG instead so keep it clean
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 0x7432: // BHYVE (AMD hostbridge)
1078 case 0x1275: // BHYVE (Intel hostbridge)
1079 case INTEL_82441_DEVICE_ID:
1080 Idx -= 1;
1081 break;
1082 case INTEL_Q35_MCH_DEVICE_ID:
1083 //
1084 // SeaBIOS contains the following comment:
1085 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1086 // with a different starting index - see q35-acpi-dsdt.dsl.
1087 //
1088 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1089 //
1090 if (RootSlot > 24) {
1091 //
1092 // in this case, subtract back out RootSlot from Idx
1093 // (SeaBIOS never adds it to begin with, but that would make our
1094 // device path traversal loop above too awkward)
1095 //
1096 Idx -= RootSlot;
1097 }
1098 break;
1099 default:
1100 ASSERT (FALSE); // should never get here
1101 }
1102 Idx %= ARRAY_SIZE (PciHostIrqs);
1103 IrqLine = PciHostIrqs[Idx];
1104
1105 DEBUG_CODE_BEGIN ();
1106 {
1107 CHAR16 *DevPathString;
1108 STATIC CHAR16 Fallback[] = L"<failed to convert>";
1109 UINTN Segment, Bus, Device, Function;
1110
1111 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
1112 if (DevPathString == NULL) {
1113 DevPathString = Fallback;
1114 }
1115 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
1116 ASSERT_EFI_ERROR (Status);
1117
1118 DEBUG ((DEBUG_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
1119 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
1120 IrqLine));
1121
1122 if (DevPathString != Fallback) {
1123 FreePool (DevPathString);
1124 }
1125 }
1126 DEBUG_CODE_END ();
1127
1128 //
1129 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1130 //
1131 Status = PciIo->Pci.Write (
1132 PciIo,
1133 EfiPciIoWidthUint8,
1134 PCI_INT_LINE_OFFSET,
1135 1,
1136 &IrqLine
1137 );
1138 }
1139
1140 return Status;
1141 }
1142
1143
1144 VOID
1145 PciAcpiInitialization (
1146 )
1147 {
1148 UINTN Pmba;
1149
1150 //
1151 // Query Host Bridge DID to determine platform type
1152 //
1153 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
1154 switch (mHostBridgeDevId) {
1155 case 0x7432: // BHYVE (AMD hostbridge)
1156 case 0x1275: // BHYVE (Intel hostbridge)
1157 case INTEL_82441_DEVICE_ID:
1158 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1159 //
1160 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1161 //
1162 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1163 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1164 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1165 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1166 break;
1167 case INTEL_Q35_MCH_DEVICE_ID:
1168 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1169 //
1170 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1171 //
1172 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1173 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1174 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1175 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1176 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1177 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1178 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1179 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1180 break;
1181 default:
1182 DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1183 __FUNCTION__, mHostBridgeDevId));
1184 ASSERT (FALSE);
1185 return;
1186 }
1187
1188 //
1189 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1190 //
1191 VisitAllPciInstances (SetPciIntLine);
1192
1193 //
1194 // Set ACPI SCI_EN bit in PMCNTRL
1195 //
1196 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1197 }
1198
1199 EFI_STATUS
1200 EFIAPI
1201 ConnectRecursivelyIfPciMassStorage (
1202 IN EFI_HANDLE Handle,
1203 IN EFI_PCI_IO_PROTOCOL *Instance,
1204 IN PCI_TYPE00 *PciHeader
1205 )
1206 {
1207 EFI_STATUS Status;
1208 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1209 CHAR16 *DevPathStr;
1210
1211 //
1212 // Recognize PCI Mass Storage, and Xen PCI devices
1213 //
1214 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
1215 DevicePath = NULL;
1216 Status = gBS->HandleProtocol (
1217 Handle,
1218 &gEfiDevicePathProtocolGuid,
1219 (VOID*)&DevicePath
1220 );
1221 if (EFI_ERROR (Status)) {
1222 return Status;
1223 }
1224
1225 //
1226 // Print Device Path
1227 //
1228 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1229 if (DevPathStr != NULL) {
1230 DEBUG((
1231 DEBUG_INFO,
1232 "Found %s device: %s\n",
1233 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?
1234 L"Mass Storage" :
1235 L"Xen"
1236 ),
1237 DevPathStr
1238 ));
1239 FreePool(DevPathStr);
1240 }
1241
1242 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
1243 if (EFI_ERROR (Status)) {
1244 return Status;
1245 }
1246
1247 }
1248
1249 return EFI_SUCCESS;
1250 }
1251
1252
1253 /**
1254 This notification function is invoked when the
1255 EMU Variable FVB has been changed.
1256
1257 @param Event The event that occurred
1258 @param Context For EFI compatibility. Not used.
1259
1260 **/
1261 VOID
1262 EFIAPI
1263 EmuVariablesUpdatedCallback (
1264 IN EFI_EVENT Event,
1265 IN VOID *Context
1266 )
1267 {
1268 DEBUG ((DEBUG_INFO, "EmuVariablesUpdatedCallback\n"));
1269 UpdateNvVarsOnFileSystem ();
1270 }
1271
1272
1273 EFI_STATUS
1274 EFIAPI
1275 VisitingFileSystemInstance (
1276 IN EFI_HANDLE Handle,
1277 IN VOID *Instance,
1278 IN VOID *Context
1279 )
1280 {
1281 EFI_STATUS Status;
1282 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
1283 RETURN_STATUS PcdStatus;
1284
1285 if (ConnectedToFileSystem) {
1286 return EFI_ALREADY_STARTED;
1287 }
1288
1289 Status = ConnectNvVarsToFileSystem (Handle);
1290 if (EFI_ERROR (Status)) {
1291 return Status;
1292 }
1293
1294 ConnectedToFileSystem = TRUE;
1295 mEmuVariableEvent =
1296 EfiCreateProtocolNotifyEvent (
1297 &gEfiDevicePathProtocolGuid,
1298 TPL_CALLBACK,
1299 EmuVariablesUpdatedCallback,
1300 NULL,
1301 &mEmuVariableEventReg
1302 );
1303 PcdStatus = PcdSet64S (PcdEmuVariableEvent,
1304 (UINT64)(UINTN) mEmuVariableEvent);
1305 ASSERT_RETURN_ERROR (PcdStatus);
1306
1307 return EFI_SUCCESS;
1308 }
1309
1310
1311 VOID
1312 PlatformBdsRestoreNvVarsFromHardDisk (
1313 )
1314 {
1315 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1316 VisitAllInstancesOfProtocol (
1317 &gEfiSimpleFileSystemProtocolGuid,
1318 VisitingFileSystemInstance,
1319 NULL
1320 );
1321
1322 }
1323
1324 /**
1325 Connect with predefined platform connect sequence.
1326
1327 The OEM/IBV can customize with their own connect sequence.
1328 **/
1329 VOID
1330 PlatformBdsConnectSequence (
1331 VOID
1332 )
1333 {
1334 UINTN Index;
1335
1336 DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));
1337
1338 Index = 0;
1339
1340 //
1341 // Here we can get the customized platform connect sequence
1342 // Notes: we can connect with new variable which record the
1343 // last time boots connect device path sequence
1344 //
1345 while (gPlatformConnectSequence[Index] != NULL) {
1346 //
1347 // Build the platform boot option
1348 //
1349 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1350 Index++;
1351 }
1352
1353 //
1354 // Just use the simple policy to connect all devices
1355 //
1356 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));
1357 EfiBootManagerConnectAll ();
1358 }
1359
1360 /**
1361 Save the S3 boot script.
1362
1363 Note that DxeSmmReadyToLock must be signaled after this function returns;
1364 otherwise the script wouldn't be saved actually.
1365 **/
1366 #if defined(__GNUC__)
1367 __attribute__((unused))
1368 #endif
1369 STATIC
1370 VOID
1371 SaveS3BootScript (
1372 VOID
1373 )
1374 {
1375 EFI_STATUS Status;
1376 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1377 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1378
1379 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
1380 (VOID **) &BootScript);
1381 ASSERT_EFI_ERROR (Status);
1382
1383 //
1384 // Despite the opcode documentation in the PI spec, the protocol
1385 // implementation embeds a deep copy of the info in the boot script, rather
1386 // than storing just a pointer to runtime or NVS storage.
1387 //
1388 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1389 (UINT32) sizeof Info,
1390 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
1391 ASSERT_EFI_ERROR (Status);
1392 }
1393
1394
1395 /**
1396 Do the platform specific action after the console is ready
1397
1398 Possible things that can be done in PlatformBootManagerAfterConsole:
1399
1400 > Console post action:
1401 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1402 > Signal console ready platform customized event
1403 > Run diagnostics like memory testing
1404 > Connect certain devices
1405 > Dispatch aditional option roms
1406 > Special boot: e.g.: USB boot, enter UI
1407 **/
1408 VOID
1409 EFIAPI
1410 PlatformBootManagerAfterConsole (
1411 VOID
1412 )
1413 {
1414 EFI_BOOT_MODE BootMode;
1415
1416 DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));
1417
1418 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1419 DEBUG ((DEBUG_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1420 "from disk since flash variables appear to be supported.\n"));
1421 } else {
1422 //
1423 // Try to restore variables from the hard disk early so
1424 // they can be used for the other BDS connect operations.
1425 //
1426 /* XXX Calling this causes Keyboard to be removed from ConIn which
1427 results in unresponsive guest boot loaders in the GUI. Restore it
1428 when we figure out what is needed to get NvVars storage done
1429 properly.
1430 */
1431 /*PlatformBdsRestoreNvVarsFromHardDisk ();*/
1432 }
1433
1434 //
1435 // Get current Boot Mode
1436 //
1437 BootMode = GetBootModeHob ();
1438 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));
1439
1440 //
1441 // Go the different platform policy with different boot mode
1442 // Notes: this part code can be change with the table policy
1443 //
1444 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1445
1446 //
1447 // Logo show
1448 //
1449 BootLogoEnableLogo ();
1450
1451 //
1452 // Set PCI Interrupt Line registers and ACPI SCI_EN
1453 //
1454 PciAcpiInitialization ();
1455
1456 //
1457 // Perform some platform specific connect sequence
1458 //
1459 PlatformBdsConnectSequence ();
1460
1461 EfiBootManagerRefreshAllBootOption ();
1462
1463 //
1464 // Register UEFI Shell
1465 //
1466 PlatformRegisterFvBootOption (
1467 &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
1468 );
1469
1470 RemoveStaleFvFileOptions ();
1471
1472 PlatformBmPrintScRegisterHandler ();
1473 }
1474
1475 /**
1476 This notification function is invoked when an instance of the
1477 EFI_DEVICE_PATH_PROTOCOL is produced.
1478
1479 @param Event The event that occurred
1480 @param Context For EFI compatibility. Not used.
1481
1482 **/
1483 VOID
1484 EFIAPI
1485 NotifyDevPath (
1486 IN EFI_EVENT Event,
1487 IN VOID *Context
1488 )
1489 {
1490 EFI_HANDLE Handle;
1491 EFI_STATUS Status;
1492 UINTN BufferSize;
1493 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1494 ATAPI_DEVICE_PATH *Atapi;
1495
1496 //
1497 // Examine all new handles
1498 //
1499 for (;;) {
1500 //
1501 // Get the next handle
1502 //
1503 BufferSize = sizeof (Handle);
1504 Status = gBS->LocateHandle (
1505 ByRegisterNotify,
1506 NULL,
1507 mEfiDevPathNotifyReg,
1508 &BufferSize,
1509 &Handle
1510 );
1511
1512 //
1513 // If not found, we're done
1514 //
1515 if (EFI_NOT_FOUND == Status) {
1516 break;
1517 }
1518
1519 if (EFI_ERROR (Status)) {
1520 continue;
1521 }
1522
1523 //
1524 // Get the DevicePath protocol on that handle
1525 //
1526 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,
1527 (VOID **)&DevPathNode);
1528 ASSERT_EFI_ERROR (Status);
1529
1530 while (!IsDevicePathEnd (DevPathNode)) {
1531 //
1532 // Find the handler to dump this device path node
1533 //
1534 if (
1535 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1536 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1537 ) {
1538 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1539 PciOr16 (
1540 PCI_LIB_ADDRESS (
1541 0,
1542 1,
1543 1,
1544 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1545 ),
1546 BIT15
1547 );
1548 }
1549
1550 //
1551 // Next device path node
1552 //
1553 DevPathNode = NextDevicePathNode (DevPathNode);
1554 }
1555 }
1556
1557 return;
1558 }
1559
1560
1561 VOID
1562 InstallDevicePathCallback (
1563 VOID
1564 )
1565 {
1566 DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));
1567 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1568 &gEfiDevicePathProtocolGuid,
1569 TPL_CALLBACK,
1570 NotifyDevPath,
1571 NULL,
1572 &mEfiDevPathNotifyReg
1573 );
1574 }
1575
1576 /**
1577 This function is called each second during the boot manager waits the
1578 timeout.
1579
1580 @param TimeoutRemain The remaining timeout.
1581 **/
1582 VOID
1583 EFIAPI
1584 PlatformBootManagerWaitCallback (
1585 UINT16 TimeoutRemain
1586 )
1587 {
1588 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
1589 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
1590 UINT16 Timeout;
1591
1592 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1593
1594 Black.Raw = 0x00000000;
1595 White.Raw = 0x00FFFFFF;
1596
1597 BootLogoUpdateProgress (
1598 White.Pixel,
1599 Black.Pixel,
1600 L"Start boot option",
1601 White.Pixel,
1602 (Timeout - TimeoutRemain) * 100 / Timeout,
1603 0
1604 );
1605 }
1606
1607 /**
1608 The function is called when no boot option could be launched,
1609 including platform recovery options and options pointing to applications
1610 built into firmware volumes.
1611
1612 If this function returns, BDS attempts to enter an infinite loop.
1613 **/
1614 VOID
1615 EFIAPI
1616 PlatformBootManagerUnableToBoot (
1617 VOID
1618 )
1619 {
1620 EFI_STATUS Status;
1621 EFI_INPUT_KEY Key;
1622 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
1623 UINTN Index;
1624
1625 //
1626 // BootManagerMenu doesn't contain the correct information when return status
1627 // is EFI_NOT_FOUND.
1628 //
1629 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
1630 if (EFI_ERROR (Status)) {
1631 return;
1632 }
1633 //
1634 // Normally BdsDxe does not print anything to the system console, but this is
1635 // a last resort -- the end-user will likely not see any DEBUG messages
1636 // logged in this situation.
1637 //
1638 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1639 // here to see if it makes sense to request and wait for a keypress.
1640 //
1641 if (gST->ConIn != NULL) {
1642 AsciiPrint (
1643 "%a: No bootable option or device was found.\n"
1644 "%a: Press any key to enter the Boot Manager Menu.\n",
1645 gEfiCallerBaseName,
1646 gEfiCallerBaseName
1647 );
1648 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
1649 ASSERT_EFI_ERROR (Status);
1650 ASSERT (Index == 0);
1651
1652 //
1653 // Drain any queued keys.
1654 //
1655 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
1656 //
1657 // just throw away Key
1658 //
1659 }
1660 }
1661
1662 for (;;) {
1663 EfiBootManagerBoot (&BootManagerMenu);
1664 }
1665 }