OvmfPkg/PlatformBootManagerLib: process "-kernel" before boot devices
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLib / BdsPlatform.c
1 /** @file
2 Platform BDS customizations.
3
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
11 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "BdsPlatform.h"
16 #include <Guid/XenInfo.h>
17 #include <Guid/RootBridgesConnectedEventGroup.h>
18 #include <Protocol/FirmwareVolume2.h>
19
20
21 //
22 // Global data
23 //
24
25 VOID *mEfiDevPathNotifyReg;
26 EFI_EVENT mEfiDevPathEvent;
27 VOID *mEmuVariableEventReg;
28 EFI_EVENT mEmuVariableEvent;
29 BOOLEAN mDetectVgaOnly;
30 UINT16 mHostBridgeDevId;
31
32 //
33 // Table of host IRQs matching PCI IRQs A-D
34 // (for configuring PCI Interrupt Line register)
35 //
36 CONST UINT8 PciHostIrqs[] = {
37 0x0a, 0x0a, 0x0b, 0x0b
38 };
39
40 //
41 // Type definitions
42 //
43
44 typedef
45 EFI_STATUS
46 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
47 IN EFI_HANDLE Handle,
48 IN VOID *Instance,
49 IN VOID *Context
50 );
51
52 /**
53 @param[in] Handle - Handle of PCI device instance
54 @param[in] PciIo - PCI IO protocol instance
55 @param[in] Pci - PCI Header register block
56 **/
57 typedef
58 EFI_STATUS
59 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
60 IN EFI_HANDLE Handle,
61 IN EFI_PCI_IO_PROTOCOL *PciIo,
62 IN PCI_TYPE00 *Pci
63 );
64
65
66 //
67 // Function prototypes
68 //
69
70 EFI_STATUS
71 VisitAllInstancesOfProtocol (
72 IN EFI_GUID *Id,
73 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
74 IN VOID *Context
75 );
76
77 EFI_STATUS
78 VisitAllPciInstancesOfProtocol (
79 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
80 );
81
82 VOID
83 InstallDevicePathCallback (
84 VOID
85 );
86
87 VOID
88 PlatformRegisterFvBootOption (
89 EFI_GUID *FileGuid,
90 CHAR16 *Description,
91 UINT32 Attributes
92 )
93 {
94 EFI_STATUS Status;
95 INTN OptionIndex;
96 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
97 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
98 UINTN BootOptionCount;
99 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
100 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
101 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
102
103 Status = gBS->HandleProtocol (
104 gImageHandle,
105 &gEfiLoadedImageProtocolGuid,
106 (VOID **) &LoadedImage
107 );
108 ASSERT_EFI_ERROR (Status);
109
110 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
111 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
112 ASSERT (DevicePath != NULL);
113 DevicePath = AppendDevicePathNode (
114 DevicePath,
115 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
116 );
117 ASSERT (DevicePath != NULL);
118
119 Status = EfiBootManagerInitializeLoadOption (
120 &NewOption,
121 LoadOptionNumberUnassigned,
122 LoadOptionTypeBoot,
123 Attributes,
124 Description,
125 DevicePath,
126 NULL,
127 0
128 );
129 ASSERT_EFI_ERROR (Status);
130 FreePool (DevicePath);
131
132 BootOptions = EfiBootManagerGetLoadOptions (
133 &BootOptionCount, LoadOptionTypeBoot
134 );
135
136 OptionIndex = EfiBootManagerFindLoadOption (
137 &NewOption, BootOptions, BootOptionCount
138 );
139
140 if (OptionIndex == -1) {
141 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
142 ASSERT_EFI_ERROR (Status);
143 }
144 EfiBootManagerFreeLoadOption (&NewOption);
145 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
146 }
147
148 /**
149 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
150 whose device paths do not resolve exactly to an FvFile in the system.
151
152 This removes any boot options that point to binaries built into the firmware
153 and have become stale due to any of the following:
154 - DXEFV's base address or size changed (historical),
155 - DXEFV's FvNameGuid changed,
156 - the FILE_GUID of the pointed-to binary changed,
157 - the referenced binary is no longer built into the firmware.
158
159 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
160 avoids exact duplicates.
161 **/
162 VOID
163 RemoveStaleFvFileOptions (
164 VOID
165 )
166 {
167 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
168 UINTN BootOptionCount;
169 UINTN Index;
170
171 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
172 LoadOptionTypeBoot);
173
174 for (Index = 0; Index < BootOptionCount; ++Index) {
175 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
176 EFI_STATUS Status;
177 EFI_HANDLE FvHandle;
178
179 //
180 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
181 // then keep the boot option.
182 //
183 Node1 = BootOptions[Index].FilePath;
184 if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
185 DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
186 !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
187 DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
188 continue;
189 }
190
191 //
192 // If the second device path node is not FvFile(...), then keep the boot
193 // option.
194 //
195 Node2 = NextDevicePathNode (Node1);
196 if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
197 DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
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) ? EFI_D_WARN : EFI_D_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 VOID
277 PlatformRegisterOptionsAndKeys (
278 VOID
279 )
280 {
281 EFI_STATUS Status;
282 EFI_INPUT_KEY Enter;
283 EFI_INPUT_KEY F2;
284 EFI_INPUT_KEY Esc;
285 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
286
287 //
288 // Register ENTER as CONTINUE key
289 //
290 Enter.ScanCode = SCAN_NULL;
291 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
292 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
293 ASSERT_EFI_ERROR (Status);
294
295 //
296 // Map F2 to Boot Manager Menu
297 //
298 F2.ScanCode = SCAN_F2;
299 F2.UnicodeChar = CHAR_NULL;
300 Esc.ScanCode = SCAN_ESC;
301 Esc.UnicodeChar = CHAR_NULL;
302 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
303 ASSERT_EFI_ERROR (Status);
304 Status = EfiBootManagerAddKeyOptionVariable (
305 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
306 );
307 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
308 Status = EfiBootManagerAddKeyOptionVariable (
309 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
310 );
311 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
312 }
313
314 EFI_STATUS
315 EFIAPI
316 ConnectRootBridge (
317 IN EFI_HANDLE RootBridgeHandle,
318 IN VOID *Instance,
319 IN VOID *Context
320 );
321
322 STATIC
323 VOID
324 SaveS3BootScript (
325 VOID
326 );
327
328 //
329 // BDS Platform Functions
330 //
331 /**
332 Do the platform init, can be customized by OEM/IBV
333
334 Possible things that can be done in PlatformBootManagerBeforeConsole:
335
336 > Update console variable: 1. include hot-plug devices;
337 > 2. Clear ConIn and add SOL for AMT
338 > Register new Driver#### or Boot####
339 > Register new Key####: e.g.: F12
340 > Signal ReadyToLock event
341 > Authentication action: 1. connect Auth devices;
342 > 2. Identify auto logon user.
343 **/
344 VOID
345 EFIAPI
346 PlatformBootManagerBeforeConsole (
347 VOID
348 )
349 {
350 EFI_HANDLE Handle;
351 EFI_STATUS Status;
352 RETURN_STATUS PcdStatus;
353
354 DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));
355 InstallDevicePathCallback ();
356
357 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
358 ConnectRootBridge, NULL);
359
360 //
361 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
362 //
363 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
364
365 //
366 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
367 // the preparation of S3 system information. That logic has a hard dependency
368 // on the presence of the FACS ACPI table. Since our ACPI tables are only
369 // installed after PCI enumeration completes, we must not trigger the S3 save
370 // earlier, hence we can't signal End-of-Dxe earlier.
371 //
372 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
373
374 if (QemuFwCfgS3Enabled ()) {
375 //
376 // Save the boot script too. Note that this will require us to emit the
377 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
378 //
379 SaveS3BootScript ();
380 }
381
382 //
383 // Prevent further changes to LockBoxes or SMRAM.
384 //
385 Handle = NULL;
386 Status = gBS->InstallProtocolInterface (&Handle,
387 &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
388 NULL);
389 ASSERT_EFI_ERROR (Status);
390
391 //
392 // Dispatch deferred images after EndOfDxe event and ReadyToLock
393 // installation.
394 //
395 EfiBootManagerDispatchDeferredImages ();
396
397 PlatformInitializeConsole (gPlatformConsole);
398 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,
399 GetFrontPageTimeoutFromQemu ());
400 ASSERT_RETURN_ERROR (PcdStatus);
401
402 PlatformRegisterOptionsAndKeys ();
403 }
404
405
406 EFI_STATUS
407 EFIAPI
408 ConnectRootBridge (
409 IN EFI_HANDLE RootBridgeHandle,
410 IN VOID *Instance,
411 IN VOID *Context
412 )
413 {
414 EFI_STATUS Status;
415
416 //
417 // Make the PCI bus driver connect the root bridge, non-recursively. This
418 // will produce a number of child handles with PciIo on them.
419 //
420 Status = gBS->ConnectController (
421 RootBridgeHandle, // ControllerHandle
422 NULL, // DriverImageHandle
423 NULL, // RemainingDevicePath -- produce all
424 // children
425 FALSE // Recursive
426 );
427 return Status;
428 }
429
430
431 /**
432 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
433
434 @param[in] DeviceHandle Handle of the LPC Bridge device.
435
436 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
437 ConOut, ConIn, and ErrOut.
438
439 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
440 from DeviceHandle.
441 **/
442 EFI_STATUS
443 PrepareLpcBridgeDevicePath (
444 IN EFI_HANDLE DeviceHandle
445 )
446 {
447 EFI_STATUS Status;
448 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
449 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
450 CHAR16 *DevPathStr;
451
452 DevicePath = NULL;
453 Status = gBS->HandleProtocol (
454 DeviceHandle,
455 &gEfiDevicePathProtocolGuid,
456 (VOID*)&DevicePath
457 );
458 if (EFI_ERROR (Status)) {
459 return Status;
460 }
461 TempDevicePath = DevicePath;
462
463 //
464 // Register Keyboard
465 //
466 DevicePath = AppendDevicePathNode (DevicePath,
467 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
468
469 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
470
471 //
472 // Register COM1
473 //
474 DevicePath = TempDevicePath;
475 gPnp16550ComPortDeviceNode.UID = 0;
476
477 DevicePath = AppendDevicePathNode (DevicePath,
478 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
479 DevicePath = AppendDevicePathNode (DevicePath,
480 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
481 DevicePath = AppendDevicePathNode (DevicePath,
482 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
483
484 //
485 // Print Device Path
486 //
487 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
488 if (DevPathStr != NULL) {
489 DEBUG((
490 EFI_D_INFO,
491 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
492 __LINE__,
493 gPnp16550ComPortDeviceNode.UID + 1,
494 DevPathStr
495 ));
496 FreePool(DevPathStr);
497 }
498
499 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
500 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
501 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
502
503 //
504 // Register COM2
505 //
506 DevicePath = TempDevicePath;
507 gPnp16550ComPortDeviceNode.UID = 1;
508
509 DevicePath = AppendDevicePathNode (DevicePath,
510 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
511 DevicePath = AppendDevicePathNode (DevicePath,
512 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
513 DevicePath = AppendDevicePathNode (DevicePath,
514 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
515
516 //
517 // Print Device Path
518 //
519 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
520 if (DevPathStr != NULL) {
521 DEBUG((
522 EFI_D_INFO,
523 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
524 __LINE__,
525 gPnp16550ComPortDeviceNode.UID + 1,
526 DevPathStr
527 ));
528 FreePool(DevPathStr);
529 }
530
531 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
532 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
533 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
534
535 return EFI_SUCCESS;
536 }
537
538 EFI_STATUS
539 GetGopDevicePath (
540 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
541 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
542 )
543 {
544 UINTN Index;
545 EFI_STATUS Status;
546 EFI_HANDLE PciDeviceHandle;
547 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
548 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
549 UINTN GopHandleCount;
550 EFI_HANDLE *GopHandleBuffer;
551
552 if (PciDevicePath == NULL || GopDevicePath == NULL) {
553 return EFI_INVALID_PARAMETER;
554 }
555
556 //
557 // Initialize the GopDevicePath to be PciDevicePath
558 //
559 *GopDevicePath = PciDevicePath;
560 TempPciDevicePath = PciDevicePath;
561
562 Status = gBS->LocateDevicePath (
563 &gEfiDevicePathProtocolGuid,
564 &TempPciDevicePath,
565 &PciDeviceHandle
566 );
567 if (EFI_ERROR (Status)) {
568 return Status;
569 }
570
571 //
572 // Try to connect this handle, so that GOP driver could start on this
573 // device and create child handles with GraphicsOutput Protocol installed
574 // on them, then we get device paths of these child handles and select
575 // them as possible console device.
576 //
577 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
578
579 Status = gBS->LocateHandleBuffer (
580 ByProtocol,
581 &gEfiGraphicsOutputProtocolGuid,
582 NULL,
583 &GopHandleCount,
584 &GopHandleBuffer
585 );
586 if (!EFI_ERROR (Status)) {
587 //
588 // Add all the child handles as possible Console Device
589 //
590 for (Index = 0; Index < GopHandleCount; Index++) {
591 Status = gBS->HandleProtocol (GopHandleBuffer[Index],
592 &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
593 if (EFI_ERROR (Status)) {
594 continue;
595 }
596 if (CompareMem (
597 PciDevicePath,
598 TempDevicePath,
599 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
600 ) == 0) {
601 //
602 // In current implementation, we only enable one of the child handles
603 // as console device, i.e. sotre one of the child handle's device
604 // path to variable "ConOut"
605 // In future, we could select all child handles to be console device
606 //
607
608 *GopDevicePath = TempDevicePath;
609
610 //
611 // Delete the PCI device's path that added by
612 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
613 //
614 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
615 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
616 }
617 }
618 gBS->FreePool (GopHandleBuffer);
619 }
620
621 return EFI_SUCCESS;
622 }
623
624 /**
625 Add PCI display to ConOut.
626
627 @param[in] DeviceHandle Handle of the PCI display device.
628
629 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
630
631 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
632 from DeviceHandle.
633 **/
634 EFI_STATUS
635 PreparePciDisplayDevicePath (
636 IN EFI_HANDLE DeviceHandle
637 )
638 {
639 EFI_STATUS Status;
640 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
641 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
642
643 DevicePath = NULL;
644 GopDevicePath = NULL;
645 Status = gBS->HandleProtocol (
646 DeviceHandle,
647 &gEfiDevicePathProtocolGuid,
648 (VOID*)&DevicePath
649 );
650 if (EFI_ERROR (Status)) {
651 return Status;
652 }
653
654 GetGopDevicePath (DevicePath, &GopDevicePath);
655 DevicePath = GopDevicePath;
656
657 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
658
659 return EFI_SUCCESS;
660 }
661
662 /**
663 Add PCI Serial to ConOut, ConIn, ErrOut.
664
665 @param[in] DeviceHandle Handle of the PCI serial device.
666
667 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
668 ErrOut.
669
670 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
671 from DeviceHandle.
672 **/
673 EFI_STATUS
674 PreparePciSerialDevicePath (
675 IN EFI_HANDLE DeviceHandle
676 )
677 {
678 EFI_STATUS Status;
679 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
680
681 DevicePath = NULL;
682 Status = gBS->HandleProtocol (
683 DeviceHandle,
684 &gEfiDevicePathProtocolGuid,
685 (VOID*)&DevicePath
686 );
687 if (EFI_ERROR (Status)) {
688 return Status;
689 }
690
691 DevicePath = AppendDevicePathNode (DevicePath,
692 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
693 DevicePath = AppendDevicePathNode (DevicePath,
694 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
695
696 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
697 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
698 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
699
700 return EFI_SUCCESS;
701 }
702
703 EFI_STATUS
704 VisitAllInstancesOfProtocol (
705 IN EFI_GUID *Id,
706 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
707 IN VOID *Context
708 )
709 {
710 EFI_STATUS Status;
711 UINTN HandleCount;
712 EFI_HANDLE *HandleBuffer;
713 UINTN Index;
714 VOID *Instance;
715
716 //
717 // Start to check all the PciIo to find all possible device
718 //
719 HandleCount = 0;
720 HandleBuffer = NULL;
721 Status = gBS->LocateHandleBuffer (
722 ByProtocol,
723 Id,
724 NULL,
725 &HandleCount,
726 &HandleBuffer
727 );
728 if (EFI_ERROR (Status)) {
729 return Status;
730 }
731
732 for (Index = 0; Index < HandleCount; Index++) {
733 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
734 if (EFI_ERROR (Status)) {
735 continue;
736 }
737
738 Status = (*CallBackFunction) (
739 HandleBuffer[Index],
740 Instance,
741 Context
742 );
743 }
744
745 gBS->FreePool (HandleBuffer);
746
747 return EFI_SUCCESS;
748 }
749
750
751 EFI_STATUS
752 EFIAPI
753 VisitingAPciInstance (
754 IN EFI_HANDLE Handle,
755 IN VOID *Instance,
756 IN VOID *Context
757 )
758 {
759 EFI_STATUS Status;
760 EFI_PCI_IO_PROTOCOL *PciIo;
761 PCI_TYPE00 Pci;
762
763 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
764
765 //
766 // Check for all PCI device
767 //
768 Status = PciIo->Pci.Read (
769 PciIo,
770 EfiPciIoWidthUint32,
771 0,
772 sizeof (Pci) / sizeof (UINT32),
773 &Pci
774 );
775 if (EFI_ERROR (Status)) {
776 return Status;
777 }
778
779 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
780 Handle,
781 PciIo,
782 &Pci
783 );
784
785 }
786
787
788
789 EFI_STATUS
790 VisitAllPciInstances (
791 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
792 )
793 {
794 return VisitAllInstancesOfProtocol (
795 &gEfiPciIoProtocolGuid,
796 VisitingAPciInstance,
797 (VOID*)(UINTN) CallBackFunction
798 );
799 }
800
801
802 /**
803 Do platform specific PCI Device check and add them to
804 ConOut, ConIn, ErrOut.
805
806 @param[in] Handle - Handle of PCI device instance
807 @param[in] PciIo - PCI IO protocol instance
808 @param[in] Pci - PCI Header register block
809
810 @retval EFI_SUCCESS - PCI Device check and Console variable update
811 successfully.
812 @retval EFI_STATUS - PCI Device check or Console variable update fail.
813
814 **/
815 EFI_STATUS
816 EFIAPI
817 DetectAndPreparePlatformPciDevicePath (
818 IN EFI_HANDLE Handle,
819 IN EFI_PCI_IO_PROTOCOL *PciIo,
820 IN PCI_TYPE00 *Pci
821 )
822 {
823 EFI_STATUS Status;
824
825 Status = PciIo->Attributes (
826 PciIo,
827 EfiPciIoAttributeOperationEnable,
828 EFI_PCI_DEVICE_ENABLE,
829 NULL
830 );
831 ASSERT_EFI_ERROR (Status);
832
833 if (!mDetectVgaOnly) {
834 //
835 // Here we decide whether it is LPC Bridge
836 //
837 if ((IS_PCI_LPC (Pci)) ||
838 ((IS_PCI_ISA_PDECODE (Pci)) &&
839 (Pci->Hdr.VendorId == 0x8086) &&
840 (Pci->Hdr.DeviceId == 0x7000)
841 )
842 ) {
843 //
844 // Add IsaKeyboard to ConIn,
845 // add IsaSerial to ConOut, ConIn, ErrOut
846 //
847 DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
848 PrepareLpcBridgeDevicePath (Handle);
849 return EFI_SUCCESS;
850 }
851 //
852 // Here we decide which Serial device to enable in PCI bus
853 //
854 if (IS_PCI_16550SERIAL (Pci)) {
855 //
856 // Add them to ConOut, ConIn, ErrOut.
857 //
858 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
859 PreparePciSerialDevicePath (Handle);
860 return EFI_SUCCESS;
861 }
862 }
863
864 //
865 // Here we decide which display device to enable in PCI bus
866 //
867 if (IS_PCI_DISPLAY (Pci)) {
868 //
869 // Add them to ConOut.
870 //
871 DEBUG ((EFI_D_INFO, "Found PCI display device\n"));
872 PreparePciDisplayDevicePath (Handle);
873 return EFI_SUCCESS;
874 }
875
876 return Status;
877 }
878
879
880 /**
881 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
882
883 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
884
885 @retval EFI_SUCCESS - PCI Device check and Console variable update
886 successfully.
887 @retval EFI_STATUS - PCI Device check or Console variable update fail.
888
889 **/
890 EFI_STATUS
891 DetectAndPreparePlatformPciDevicePaths (
892 BOOLEAN DetectVgaOnly
893 )
894 {
895 mDetectVgaOnly = DetectVgaOnly;
896 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
897 }
898
899
900 /**
901 Connect the predefined platform default console device.
902
903 Always try to find and enable PCI display devices.
904
905 @param[in] PlatformConsole Predefined platform default console device array.
906 **/
907 VOID
908 PlatformInitializeConsole (
909 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
910 )
911 {
912 UINTN Index;
913 EFI_DEVICE_PATH_PROTOCOL *VarConout;
914 EFI_DEVICE_PATH_PROTOCOL *VarConin;
915
916 //
917 // Connect RootBridge
918 //
919 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout,
920 NULL);
921 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);
922
923 if (VarConout == NULL || VarConin == NULL) {
924 //
925 // Do platform specific PCI Device check and add them to ConOut, ConIn,
926 // ErrOut
927 //
928 DetectAndPreparePlatformPciDevicePaths (FALSE);
929
930 //
931 // Have chance to connect the platform default console,
932 // the platform default console is the minimum device group
933 // the platform should support
934 //
935 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
936 //
937 // Update the console variable with the connect type
938 //
939 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
940 EfiBootManagerUpdateConsoleVariable (ConIn,
941 PlatformConsole[Index].DevicePath, NULL);
942 }
943 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
944 EfiBootManagerUpdateConsoleVariable (ConOut,
945 PlatformConsole[Index].DevicePath, NULL);
946 }
947 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
948 EfiBootManagerUpdateConsoleVariable (ErrOut,
949 PlatformConsole[Index].DevicePath, NULL);
950 }
951 }
952 } else {
953 //
954 // Only detect VGA device and add them to ConOut
955 //
956 DetectAndPreparePlatformPciDevicePaths (TRUE);
957 }
958 }
959
960
961 /**
962 Configure PCI Interrupt Line register for applicable devices
963 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
964
965 @param[in] Handle - Handle of PCI device instance
966 @param[in] PciIo - PCI IO protocol instance
967 @param[in] PciHdr - PCI Header register block
968
969 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
970
971 **/
972 EFI_STATUS
973 EFIAPI
974 SetPciIntLine (
975 IN EFI_HANDLE Handle,
976 IN EFI_PCI_IO_PROTOCOL *PciIo,
977 IN PCI_TYPE00 *PciHdr
978 )
979 {
980 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
981 EFI_DEVICE_PATH_PROTOCOL *DevPath;
982 UINTN RootSlot;
983 UINTN Idx;
984 UINT8 IrqLine;
985 EFI_STATUS Status;
986 UINT32 RootBusNumber;
987
988 Status = EFI_SUCCESS;
989
990 if (PciHdr->Device.InterruptPin != 0) {
991
992 DevPathNode = DevicePathFromHandle (Handle);
993 ASSERT (DevPathNode != NULL);
994 DevPath = DevPathNode;
995
996 RootBusNumber = 0;
997 if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
998 DevicePathSubType (DevPathNode) == ACPI_DP &&
999 ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
1000 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
1001 }
1002
1003 //
1004 // Compute index into PciHostIrqs[] table by walking
1005 // the device path and adding up all device numbers
1006 //
1007 Status = EFI_NOT_FOUND;
1008 RootSlot = 0;
1009 Idx = PciHdr->Device.InterruptPin - 1;
1010 while (!IsDevicePathEnd (DevPathNode)) {
1011 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
1012 DevicePathSubType (DevPathNode) == HW_PCI_DP) {
1013
1014 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1015
1016 //
1017 // Unlike SeaBIOS, which starts climbing from the leaf device
1018 // up toward the root, we traverse the device path starting at
1019 // the root moving toward the leaf node.
1020 // The slot number of the top-level parent bridge is needed for
1021 // Q35 cases with more than 24 slots on the root bus.
1022 //
1023 if (Status != EFI_SUCCESS) {
1024 Status = EFI_SUCCESS;
1025 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1026 }
1027 }
1028
1029 DevPathNode = NextDevicePathNode (DevPathNode);
1030 }
1031 if (EFI_ERROR (Status)) {
1032 return Status;
1033 }
1034 if (RootBusNumber == 0 && RootSlot == 0) {
1035 DEBUG((
1036 EFI_D_ERROR,
1037 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1038 __FUNCTION__
1039 ));
1040 ASSERT (FALSE);
1041 }
1042
1043 //
1044 // Final PciHostIrqs[] index calculation depends on the platform
1045 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1046 //
1047 switch (mHostBridgeDevId) {
1048 case INTEL_82441_DEVICE_ID:
1049 Idx -= 1;
1050 break;
1051 case INTEL_Q35_MCH_DEVICE_ID:
1052 //
1053 // SeaBIOS contains the following comment:
1054 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1055 // with a different starting index - see q35-acpi-dsdt.dsl.
1056 //
1057 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1058 //
1059 if (RootSlot > 24) {
1060 //
1061 // in this case, subtract back out RootSlot from Idx
1062 // (SeaBIOS never adds it to begin with, but that would make our
1063 // device path traversal loop above too awkward)
1064 //
1065 Idx -= RootSlot;
1066 }
1067 break;
1068 default:
1069 ASSERT (FALSE); // should never get here
1070 }
1071 Idx %= ARRAY_SIZE (PciHostIrqs);
1072 IrqLine = PciHostIrqs[Idx];
1073
1074 DEBUG_CODE_BEGIN ();
1075 {
1076 CHAR16 *DevPathString;
1077 STATIC CHAR16 Fallback[] = L"<failed to convert>";
1078 UINTN Segment, Bus, Device, Function;
1079
1080 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
1081 if (DevPathString == NULL) {
1082 DevPathString = Fallback;
1083 }
1084 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
1085 ASSERT_EFI_ERROR (Status);
1086
1087 DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
1088 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
1089 IrqLine));
1090
1091 if (DevPathString != Fallback) {
1092 FreePool (DevPathString);
1093 }
1094 }
1095 DEBUG_CODE_END ();
1096
1097 //
1098 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1099 //
1100 Status = PciIo->Pci.Write (
1101 PciIo,
1102 EfiPciIoWidthUint8,
1103 PCI_INT_LINE_OFFSET,
1104 1,
1105 &IrqLine
1106 );
1107 }
1108
1109 return Status;
1110 }
1111
1112
1113 VOID
1114 PciAcpiInitialization (
1115 )
1116 {
1117 UINTN Pmba;
1118
1119 //
1120 // Query Host Bridge DID to determine platform type
1121 //
1122 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
1123 switch (mHostBridgeDevId) {
1124 case INTEL_82441_DEVICE_ID:
1125 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1126 //
1127 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1128 //
1129 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1130 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1131 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1132 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1133 break;
1134 case INTEL_Q35_MCH_DEVICE_ID:
1135 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1136 //
1137 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1138 //
1139 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1140 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1141 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1142 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1143 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1144 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1145 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1146 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1147 break;
1148 default:
1149 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1150 __FUNCTION__, mHostBridgeDevId));
1151 ASSERT (FALSE);
1152 return;
1153 }
1154
1155 //
1156 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1157 //
1158 VisitAllPciInstances (SetPciIntLine);
1159
1160 //
1161 // Set ACPI SCI_EN bit in PMCNTRL
1162 //
1163 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1164 }
1165
1166 /**
1167 This function detects if OVMF is running on Xen.
1168
1169 **/
1170 STATIC
1171 BOOLEAN
1172 XenDetected (
1173 VOID
1174 )
1175 {
1176 EFI_HOB_GUID_TYPE *GuidHob;
1177 STATIC INTN FoundHob = -1;
1178
1179 if (FoundHob == 0) {
1180 return FALSE;
1181 } else if (FoundHob == 1) {
1182 return TRUE;
1183 }
1184
1185 //
1186 // See if a XenInfo HOB is available
1187 //
1188 GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid);
1189 if (GuidHob == NULL) {
1190 FoundHob = 0;
1191 return FALSE;
1192 }
1193
1194 FoundHob = 1;
1195 return TRUE;
1196 }
1197
1198 EFI_STATUS
1199 EFIAPI
1200 ConnectRecursivelyIfPciMassStorage (
1201 IN EFI_HANDLE Handle,
1202 IN EFI_PCI_IO_PROTOCOL *Instance,
1203 IN PCI_TYPE00 *PciHeader
1204 )
1205 {
1206 EFI_STATUS Status;
1207 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1208 CHAR16 *DevPathStr;
1209
1210 //
1211 // Recognize PCI Mass Storage, and Xen PCI devices
1212 //
1213 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||
1214 (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) {
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 EFI_D_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 ((EFI_D_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 RETURN_STATUS Status;
1336
1337 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
1338
1339 Index = 0;
1340
1341 //
1342 // Here we can get the customized platform connect sequence
1343 // Notes: we can connect with new variable which record the
1344 // last time boots connect device path sequence
1345 //
1346 while (gPlatformConnectSequence[Index] != NULL) {
1347 //
1348 // Build the platform boot option
1349 //
1350 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1351 Index++;
1352 }
1353
1354 Status = ConnectDevicesFromQemu ();
1355 if (RETURN_ERROR (Status)) {
1356 //
1357 // Just use the simple policy to connect all devices
1358 //
1359 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));
1360 EfiBootManagerConnectAll ();
1361 }
1362 }
1363
1364 /**
1365 Save the S3 boot script.
1366
1367 Note that DxeSmmReadyToLock must be signaled after this function returns;
1368 otherwise the script wouldn't be saved actually.
1369 **/
1370 STATIC
1371 VOID
1372 SaveS3BootScript (
1373 VOID
1374 )
1375 {
1376 EFI_STATUS Status;
1377 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1378 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1379
1380 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
1381 (VOID **) &BootScript);
1382 ASSERT_EFI_ERROR (Status);
1383
1384 //
1385 // Despite the opcode documentation in the PI spec, the protocol
1386 // implementation embeds a deep copy of the info in the boot script, rather
1387 // than storing just a pointer to runtime or NVS storage.
1388 //
1389 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1390 (UINT32) sizeof Info,
1391 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
1392 ASSERT_EFI_ERROR (Status);
1393 }
1394
1395
1396 /**
1397 Do the platform specific action after the console is ready
1398
1399 Possible things that can be done in PlatformBootManagerAfterConsole:
1400
1401 > Console post action:
1402 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1403 > Signal console ready platform customized event
1404 > Run diagnostics like memory testing
1405 > Connect certain devices
1406 > Dispatch aditional option roms
1407 > Special boot: e.g.: USB boot, enter UI
1408 **/
1409 VOID
1410 EFIAPI
1411 PlatformBootManagerAfterConsole (
1412 VOID
1413 )
1414 {
1415 EFI_BOOT_MODE BootMode;
1416
1417 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
1418
1419 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1420 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1421 "from disk since flash variables appear to be supported.\n"));
1422 } else {
1423 //
1424 // Try to restore variables from the hard disk early so
1425 // they can be used for the other BDS connect operations.
1426 //
1427 PlatformBdsRestoreNvVarsFromHardDisk ();
1428 }
1429
1430 //
1431 // Get current Boot Mode
1432 //
1433 BootMode = GetBootModeHob ();
1434 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));
1435
1436 //
1437 // Go the different platform policy with different boot mode
1438 // Notes: this part code can be change with the table policy
1439 //
1440 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1441
1442 //
1443 // Logo show
1444 //
1445 BootLogoEnableLogo ();
1446
1447 //
1448 // Set PCI Interrupt Line registers and ACPI SCI_EN
1449 //
1450 PciAcpiInitialization ();
1451
1452 //
1453 // Process QEMU's -kernel command line option
1454 //
1455 TryRunningQemuKernel ();
1456
1457 //
1458 // Perform some platform specific connect sequence
1459 //
1460 PlatformBdsConnectSequence ();
1461
1462 EfiBootManagerRefreshAllBootOption ();
1463
1464 //
1465 // Register UEFI Shell
1466 //
1467 PlatformRegisterFvBootOption (
1468 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
1469 );
1470
1471 RemoveStaleFvFileOptions ();
1472 SetBootOrderFromQemu ();
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 ((EFI_D_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