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