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