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