]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
OvmfPkg/PlatformBootManagerLib: wrap overlong lines in "BdsPlatform.c"
[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 are licensed and made available\r
6 under the terms and conditions of the BSD License which accompanies this\r
7 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, WITHOUT\r
11 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 //\r
393 // Dispatch deferred images after EndOfDxe event and ReadyToLock\r
394 // installation.\r
395 //\r
396 EfiBootManagerDispatchDeferredImages ();\r
397\r
398 PlatformInitializeConsole (gPlatformConsole);\r
399 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,\r
400 GetFrontPageTimeoutFromQemu ());\r
401 ASSERT_RETURN_ERROR (PcdStatus);\r
402\r
403 PlatformRegisterOptionsAndKeys ();\r
404}\r
405\r
406\r
407EFI_STATUS\r
408EFIAPI\r
409ConnectRootBridge (\r
410 IN EFI_HANDLE RootBridgeHandle,\r
411 IN VOID *Instance,\r
412 IN VOID *Context\r
413 )\r
414{\r
415 EFI_STATUS Status;\r
416\r
417 //\r
418 // Make the PCI bus driver connect the root bridge, non-recursively. This\r
419 // will produce a number of child handles with PciIo on them.\r
420 //\r
421 Status = gBS->ConnectController (\r
422 RootBridgeHandle, // ControllerHandle\r
423 NULL, // DriverImageHandle\r
424 NULL, // RemainingDevicePath -- produce all\r
425 // children\r
426 FALSE // Recursive\r
427 );\r
428 return Status;\r
429}\r
430\r
431\r
432EFI_STATUS\r
433PrepareLpcBridgeDevicePath (\r
434 IN EFI_HANDLE DeviceHandle\r
435 )\r
436/*++\r
437\r
438Routine Description:\r
439\r
440 Add IsaKeyboard to ConIn,\r
441 add IsaSerial to ConOut, ConIn, ErrOut.\r
442 LPC Bridge: 06 01 00\r
443\r
444Arguments:\r
445\r
446 DeviceHandle - Handle of PCIIO protocol.\r
447\r
448Returns:\r
449\r
450 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.\r
451 EFI_STATUS - No LPC bridge is added.\r
452\r
453--*/\r
454{\r
455 EFI_STATUS Status;\r
456 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
457 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
458 CHAR16 *DevPathStr;\r
459\r
460 DevicePath = NULL;\r
461 Status = gBS->HandleProtocol (\r
462 DeviceHandle,\r
463 &gEfiDevicePathProtocolGuid,\r
464 (VOID*)&DevicePath\r
465 );\r
466 if (EFI_ERROR (Status)) {\r
467 return Status;\r
468 }\r
469 TempDevicePath = DevicePath;\r
470\r
471 //\r
472 // Register Keyboard\r
473 //\r
474 DevicePath = AppendDevicePathNode (DevicePath,\r
475 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);\r
476\r
477 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
478\r
479 //\r
480 // Register COM1\r
481 //\r
482 DevicePath = TempDevicePath;\r
483 gPnp16550ComPortDeviceNode.UID = 0;\r
484\r
485 DevicePath = AppendDevicePathNode (DevicePath,\r
486 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);\r
487 DevicePath = AppendDevicePathNode (DevicePath,\r
488 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
489 DevicePath = AppendDevicePathNode (DevicePath,\r
490 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
491\r
492 //\r
493 // Print Device Path\r
494 //\r
495 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
496 if (DevPathStr != NULL) {\r
497 DEBUG((\r
498 EFI_D_INFO,\r
499 "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
500 __LINE__,\r
501 gPnp16550ComPortDeviceNode.UID + 1,\r
502 DevPathStr\r
503 ));\r
504 FreePool(DevPathStr);\r
505 }\r
506\r
507 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
508 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
509 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
510\r
511 //\r
512 // Register COM2\r
513 //\r
514 DevicePath = TempDevicePath;\r
515 gPnp16550ComPortDeviceNode.UID = 1;\r
516\r
517 DevicePath = AppendDevicePathNode (DevicePath,\r
518 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);\r
519 DevicePath = AppendDevicePathNode (DevicePath,\r
520 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
521 DevicePath = AppendDevicePathNode (DevicePath,\r
522 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
523\r
524 //\r
525 // Print Device Path\r
526 //\r
527 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
528 if (DevPathStr != NULL) {\r
529 DEBUG((\r
530 EFI_D_INFO,\r
531 "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
532 __LINE__,\r
533 gPnp16550ComPortDeviceNode.UID + 1,\r
534 DevPathStr\r
535 ));\r
536 FreePool(DevPathStr);\r
537 }\r
538\r
539 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
540 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
541 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
542\r
543 return EFI_SUCCESS;\r
544}\r
545\r
546EFI_STATUS\r
547GetGopDevicePath (\r
548 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,\r
549 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath\r
550 )\r
551{\r
552 UINTN Index;\r
553 EFI_STATUS Status;\r
554 EFI_HANDLE PciDeviceHandle;\r
555 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
556 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;\r
557 UINTN GopHandleCount;\r
558 EFI_HANDLE *GopHandleBuffer;\r
559\r
560 if (PciDevicePath == NULL || GopDevicePath == NULL) {\r
561 return EFI_INVALID_PARAMETER;\r
562 }\r
563\r
564 //\r
565 // Initialize the GopDevicePath to be PciDevicePath\r
566 //\r
567 *GopDevicePath = PciDevicePath;\r
568 TempPciDevicePath = PciDevicePath;\r
569\r
570 Status = gBS->LocateDevicePath (\r
571 &gEfiDevicePathProtocolGuid,\r
572 &TempPciDevicePath,\r
573 &PciDeviceHandle\r
574 );\r
575 if (EFI_ERROR (Status)) {\r
576 return Status;\r
577 }\r
578\r
579 //\r
580 // Try to connect this handle, so that GOP driver could start on this\r
581 // device and create child handles with GraphicsOutput Protocol installed\r
582 // on them, then we get device paths of these child handles and select\r
583 // them as possible console device.\r
584 //\r
585 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);\r
586\r
587 Status = gBS->LocateHandleBuffer (\r
588 ByProtocol,\r
589 &gEfiGraphicsOutputProtocolGuid,\r
590 NULL,\r
591 &GopHandleCount,\r
592 &GopHandleBuffer\r
593 );\r
594 if (!EFI_ERROR (Status)) {\r
595 //\r
596 // Add all the child handles as possible Console Device\r
597 //\r
598 for (Index = 0; Index < GopHandleCount; Index++) {\r
599 Status = gBS->HandleProtocol (GopHandleBuffer[Index],\r
600 &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);\r
601 if (EFI_ERROR (Status)) {\r
602 continue;\r
603 }\r
604 if (CompareMem (\r
605 PciDevicePath,\r
606 TempDevicePath,\r
607 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH\r
608 ) == 0) {\r
609 //\r
610 // In current implementation, we only enable one of the child handles\r
611 // as console device, i.e. sotre one of the child handle's device\r
612 // path to variable "ConOut"\r
613 // In future, we could select all child handles to be console device\r
614 //\r
615\r
616 *GopDevicePath = TempDevicePath;\r
617\r
618 //\r
619 // Delete the PCI device's path that added by\r
620 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
621 //\r
622 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
623 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
624 }\r
625 }\r
626 gBS->FreePool (GopHandleBuffer);\r
627 }\r
628\r
629 return EFI_SUCCESS;\r
630}\r
631\r
632EFI_STATUS\r
633PreparePciDisplayDevicePath (\r
634 IN EFI_HANDLE DeviceHandle\r
635 )\r
636/*++\r
637\r
638Routine Description:\r
639\r
640 Add PCI VGA to ConOut.\r
641 PCI VGA: 03 00 00\r
642\r
643Arguments:\r
644\r
645 DeviceHandle - Handle of PCIIO protocol.\r
646\r
647Returns:\r
648\r
649 EFI_SUCCESS - PCI VGA is added to ConOut.\r
650 EFI_STATUS - No PCI VGA device is added.\r
651\r
652--*/\r
653{\r
654 EFI_STATUS Status;\r
655 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
656 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;\r
657\r
658 DevicePath = NULL;\r
659 GopDevicePath = NULL;\r
660 Status = gBS->HandleProtocol (\r
661 DeviceHandle,\r
662 &gEfiDevicePathProtocolGuid,\r
663 (VOID*)&DevicePath\r
664 );\r
665 if (EFI_ERROR (Status)) {\r
666 return Status;\r
667 }\r
668\r
669 GetGopDevicePath (DevicePath, &GopDevicePath);\r
670 DevicePath = GopDevicePath;\r
671\r
672 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
673\r
674 return EFI_SUCCESS;\r
675}\r
676\r
677EFI_STATUS\r
678PreparePciSerialDevicePath (\r
679 IN EFI_HANDLE DeviceHandle\r
680 )\r
681/*++\r
682\r
683Routine Description:\r
684\r
685 Add PCI Serial to ConOut, ConIn, ErrOut.\r
686 PCI Serial: 07 00 02\r
687\r
688Arguments:\r
689\r
690 DeviceHandle - Handle of PCIIO protocol.\r
691\r
692Returns:\r
693\r
694 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.\r
695 EFI_STATUS - No PCI Serial device is added.\r
696\r
697--*/\r
698{\r
699 EFI_STATUS Status;\r
700 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
701\r
702 DevicePath = NULL;\r
703 Status = gBS->HandleProtocol (\r
704 DeviceHandle,\r
705 &gEfiDevicePathProtocolGuid,\r
706 (VOID*)&DevicePath\r
707 );\r
708 if (EFI_ERROR (Status)) {\r
709 return Status;\r
710 }\r
711\r
712 DevicePath = AppendDevicePathNode (DevicePath,\r
713 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
714 DevicePath = AppendDevicePathNode (DevicePath,\r
715 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
716\r
717 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
718 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
719 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
720\r
721 return EFI_SUCCESS;\r
722}\r
723\r
724EFI_STATUS\r
725VisitAllInstancesOfProtocol (\r
726 IN EFI_GUID *Id,\r
727 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
728 IN VOID *Context\r
729 )\r
730{\r
731 EFI_STATUS Status;\r
732 UINTN HandleCount;\r
733 EFI_HANDLE *HandleBuffer;\r
734 UINTN Index;\r
735 VOID *Instance;\r
736\r
737 //\r
738 // Start to check all the PciIo to find all possible device\r
739 //\r
740 HandleCount = 0;\r
741 HandleBuffer = NULL;\r
742 Status = gBS->LocateHandleBuffer (\r
743 ByProtocol,\r
744 Id,\r
745 NULL,\r
746 &HandleCount,\r
747 &HandleBuffer\r
748 );\r
749 if (EFI_ERROR (Status)) {\r
750 return Status;\r
751 }\r
752\r
753 for (Index = 0; Index < HandleCount; Index++) {\r
754 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);\r
755 if (EFI_ERROR (Status)) {\r
756 continue;\r
757 }\r
758\r
759 Status = (*CallBackFunction) (\r
760 HandleBuffer[Index],\r
761 Instance,\r
762 Context\r
763 );\r
764 }\r
765\r
766 gBS->FreePool (HandleBuffer);\r
767\r
768 return EFI_SUCCESS;\r
769}\r
770\r
771\r
772EFI_STATUS\r
773EFIAPI\r
774VisitingAPciInstance (\r
775 IN EFI_HANDLE Handle,\r
776 IN VOID *Instance,\r
777 IN VOID *Context\r
778 )\r
779{\r
780 EFI_STATUS Status;\r
781 EFI_PCI_IO_PROTOCOL *PciIo;\r
782 PCI_TYPE00 Pci;\r
783\r
784 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;\r
785\r
786 //\r
787 // Check for all PCI device\r
788 //\r
789 Status = PciIo->Pci.Read (\r
790 PciIo,\r
791 EfiPciIoWidthUint32,\r
792 0,\r
793 sizeof (Pci) / sizeof (UINT32),\r
794 &Pci\r
795 );\r
796 if (EFI_ERROR (Status)) {\r
797 return Status;\r
798 }\r
799\r
800 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (\r
801 Handle,\r
802 PciIo,\r
803 &Pci\r
804 );\r
805\r
806}\r
807\r
808\r
809\r
810EFI_STATUS\r
811VisitAllPciInstances (\r
812 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
813 )\r
814{\r
815 return VisitAllInstancesOfProtocol (\r
816 &gEfiPciIoProtocolGuid,\r
817 VisitingAPciInstance,\r
818 (VOID*)(UINTN) CallBackFunction\r
819 );\r
820}\r
821\r
822\r
823/**\r
824 Do platform specific PCI Device check and add them to\r
825 ConOut, ConIn, ErrOut.\r
826\r
827 @param[in] Handle - Handle of PCI device instance\r
828 @param[in] PciIo - PCI IO protocol instance\r
829 @param[in] Pci - PCI Header register block\r
830\r
831 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
832 successfully.\r
833 @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
834\r
835**/\r
836EFI_STATUS\r
837EFIAPI\r
838DetectAndPreparePlatformPciDevicePath (\r
839 IN EFI_HANDLE Handle,\r
840 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
841 IN PCI_TYPE00 *Pci\r
842 )\r
843{\r
844 EFI_STATUS Status;\r
845\r
846 Status = PciIo->Attributes (\r
847 PciIo,\r
848 EfiPciIoAttributeOperationEnable,\r
849 EFI_PCI_DEVICE_ENABLE,\r
850 NULL\r
851 );\r
852 ASSERT_EFI_ERROR (Status);\r
853\r
854 if (!mDetectVgaOnly) {\r
855 //\r
856 // Here we decide whether it is LPC Bridge\r
857 //\r
858 if ((IS_PCI_LPC (Pci)) ||\r
859 ((IS_PCI_ISA_PDECODE (Pci)) &&\r
860 (Pci->Hdr.VendorId == 0x8086) &&\r
861 (Pci->Hdr.DeviceId == 0x7000)\r
862 )\r
863 ) {\r
864 //\r
865 // Add IsaKeyboard to ConIn,\r
866 // add IsaSerial to ConOut, ConIn, ErrOut\r
867 //\r
868 DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));\r
869 PrepareLpcBridgeDevicePath (Handle);\r
870 return EFI_SUCCESS;\r
871 }\r
872 //\r
873 // Here we decide which Serial device to enable in PCI bus\r
874 //\r
875 if (IS_PCI_16550SERIAL (Pci)) {\r
876 //\r
877 // Add them to ConOut, ConIn, ErrOut.\r
878 //\r
879 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));\r
880 PreparePciSerialDevicePath (Handle);\r
881 return EFI_SUCCESS;\r
882 }\r
883 }\r
884\r
885 //\r
886 // Here we decide which display device to enable in PCI bus\r
887 //\r
888 if (IS_PCI_DISPLAY (Pci)) {\r
889 //\r
890 // Add them to ConOut.\r
891 //\r
892 DEBUG ((EFI_D_INFO, "Found PCI display device\n"));\r
893 PreparePciDisplayDevicePath (Handle);\r
894 return EFI_SUCCESS;\r
895 }\r
896\r
897 return Status;\r
898}\r
899\r
900\r
901/**\r
902 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut\r
903\r
904 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.\r
905\r
906 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
907 successfully.\r
908 @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
909\r
910**/\r
911EFI_STATUS\r
912DetectAndPreparePlatformPciDevicePaths (\r
913 BOOLEAN DetectVgaOnly\r
914 )\r
915{\r
916 mDetectVgaOnly = DetectVgaOnly;\r
917 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);\r
918}\r
919\r
920\r
921VOID\r
922PlatformInitializeConsole (\r
923 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
924 )\r
925/*++\r
926\r
927Routine Description:\r
928\r
929 Connect the predefined platform default console device. Always try to find\r
930 and enable the vga device if have.\r
931\r
932Arguments:\r
933\r
934 PlatformConsole - Predefined platform default console device array.\r
935--*/\r
936{\r
937 UINTN Index;\r
938 EFI_DEVICE_PATH_PROTOCOL *VarConout;\r
939 EFI_DEVICE_PATH_PROTOCOL *VarConin;\r
940\r
941 //\r
942 // Connect RootBridge\r
943 //\r
944 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout,\r
945 NULL);\r
946 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);\r
947\r
948 if (VarConout == NULL || VarConin == NULL) {\r
949 //\r
950 // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
951 // ErrOut\r
952 //\r
953 DetectAndPreparePlatformPciDevicePaths (FALSE);\r
954\r
955 //\r
956 // Have chance to connect the platform default console,\r
957 // the platform default console is the minimum device group\r
958 // the platform should support\r
959 //\r
960 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {\r
961 //\r
962 // Update the console variable with the connect type\r
963 //\r
964 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {\r
965 EfiBootManagerUpdateConsoleVariable (ConIn,\r
966 PlatformConsole[Index].DevicePath, NULL);\r
967 }\r
968 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {\r
969 EfiBootManagerUpdateConsoleVariable (ConOut,\r
970 PlatformConsole[Index].DevicePath, NULL);\r
971 }\r
972 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {\r
973 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
974 PlatformConsole[Index].DevicePath, NULL);\r
975 }\r
976 }\r
977 } else {\r
978 //\r
979 // Only detect VGA device and add them to ConOut\r
980 //\r
981 DetectAndPreparePlatformPciDevicePaths (TRUE);\r
982 }\r
983}\r
984\r
985\r
986/**\r
987 Configure PCI Interrupt Line register for applicable devices\r
988 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
989\r
990 @param[in] Handle - Handle of PCI device instance\r
991 @param[in] PciIo - PCI IO protocol instance\r
992 @param[in] PciHdr - PCI Header register block\r
993\r
994 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
995\r
996**/\r
997EFI_STATUS\r
998EFIAPI\r
999SetPciIntLine (\r
1000 IN EFI_HANDLE Handle,\r
1001 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1002 IN PCI_TYPE00 *PciHdr\r
1003 )\r
1004{\r
1005 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1006 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1007 UINTN RootSlot;\r
1008 UINTN Idx;\r
1009 UINT8 IrqLine;\r
1010 EFI_STATUS Status;\r
1011 UINT32 RootBusNumber;\r
1012\r
1013 Status = EFI_SUCCESS;\r
1014\r
1015 if (PciHdr->Device.InterruptPin != 0) {\r
1016\r
1017 DevPathNode = DevicePathFromHandle (Handle);\r
1018 ASSERT (DevPathNode != NULL);\r
1019 DevPath = DevPathNode;\r
1020\r
1021 RootBusNumber = 0;\r
1022 if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&\r
1023 DevicePathSubType (DevPathNode) == ACPI_DP &&\r
1024 ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {\r
1025 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;\r
1026 }\r
1027\r
1028 //\r
1029 // Compute index into PciHostIrqs[] table by walking\r
1030 // the device path and adding up all device numbers\r
1031 //\r
1032 Status = EFI_NOT_FOUND;\r
1033 RootSlot = 0;\r
1034 Idx = PciHdr->Device.InterruptPin - 1;\r
1035 while (!IsDevicePathEnd (DevPathNode)) {\r
1036 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&\r
1037 DevicePathSubType (DevPathNode) == HW_PCI_DP) {\r
1038\r
1039 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1040\r
1041 //\r
1042 // Unlike SeaBIOS, which starts climbing from the leaf device\r
1043 // up toward the root, we traverse the device path starting at\r
1044 // the root moving toward the leaf node.\r
1045 // The slot number of the top-level parent bridge is needed for\r
1046 // Q35 cases with more than 24 slots on the root bus.\r
1047 //\r
1048 if (Status != EFI_SUCCESS) {\r
1049 Status = EFI_SUCCESS;\r
1050 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1051 }\r
1052 }\r
1053\r
1054 DevPathNode = NextDevicePathNode (DevPathNode);\r
1055 }\r
1056 if (EFI_ERROR (Status)) {\r
1057 return Status;\r
1058 }\r
1059 if (RootBusNumber == 0 && RootSlot == 0) {\r
1060 DEBUG((\r
1061 EFI_D_ERROR,\r
1062 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
1063 __FUNCTION__\r
1064 ));\r
1065 ASSERT (FALSE);\r
1066 }\r
1067\r
1068 //\r
1069 // Final PciHostIrqs[] index calculation depends on the platform\r
1070 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
1071 //\r
1072 switch (mHostBridgeDevId) {\r
1073 case INTEL_82441_DEVICE_ID:\r
1074 Idx -= 1;\r
1075 break;\r
1076 case INTEL_Q35_MCH_DEVICE_ID:\r
1077 //\r
1078 // SeaBIOS contains the following comment:\r
1079 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
1080 // with a different starting index - see q35-acpi-dsdt.dsl.\r
1081 //\r
1082 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
1083 //\r
1084 if (RootSlot > 24) {\r
1085 //\r
1086 // in this case, subtract back out RootSlot from Idx\r
1087 // (SeaBIOS never adds it to begin with, but that would make our\r
1088 // device path traversal loop above too awkward)\r
1089 //\r
1090 Idx -= RootSlot;\r
1091 }\r
1092 break;\r
1093 default:\r
1094 ASSERT (FALSE); // should never get here\r
1095 }\r
1096 Idx %= ARRAY_SIZE (PciHostIrqs);\r
1097 IrqLine = PciHostIrqs[Idx];\r
1098\r
1099 DEBUG_CODE_BEGIN ();\r
1100 {\r
1101 CHAR16 *DevPathString;\r
1102 STATIC CHAR16 Fallback[] = L"<failed to convert>";\r
1103 UINTN Segment, Bus, Device, Function;\r
1104\r
1105 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);\r
1106 if (DevPathString == NULL) {\r
1107 DevPathString = Fallback;\r
1108 }\r
1109 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);\r
1110 ASSERT_EFI_ERROR (Status);\r
1111\r
1112 DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,\r
1113 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,\r
1114 IrqLine));\r
1115\r
1116 if (DevPathString != Fallback) {\r
1117 FreePool (DevPathString);\r
1118 }\r
1119 }\r
1120 DEBUG_CODE_END ();\r
1121\r
1122 //\r
1123 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
1124 //\r
1125 Status = PciIo->Pci.Write (\r
1126 PciIo,\r
1127 EfiPciIoWidthUint8,\r
1128 PCI_INT_LINE_OFFSET,\r
1129 1,\r
1130 &IrqLine\r
1131 );\r
1132 }\r
1133\r
1134 return Status;\r
1135}\r
1136\r
1137\r
1138VOID\r
1139PciAcpiInitialization (\r
1140 )\r
1141{\r
1142 UINTN Pmba;\r
1143\r
1144 //\r
1145 // Query Host Bridge DID to determine platform type\r
1146 //\r
1147 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
1148 switch (mHostBridgeDevId) {\r
1149 case INTEL_82441_DEVICE_ID:\r
1150 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
1151 //\r
1152 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets\r
1153 //\r
1154 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A\r
1155 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B\r
1156 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C\r
1157 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D\r
1158 break;\r
1159 case INTEL_Q35_MCH_DEVICE_ID:\r
1160 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
1161 //\r
1162 // 00:1f.0 LPC Bridge (Q35) LNK routing targets\r
1163 //\r
1164 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A\r
1165 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B\r
1166 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C\r
1167 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D\r
1168 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E\r
1169 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F\r
1170 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G\r
1171 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H\r
1172 break;\r
1173 default:\r
1174 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
1175 __FUNCTION__, mHostBridgeDevId));\r
1176 ASSERT (FALSE);\r
1177 return;\r
1178 }\r
1179\r
1180 //\r
1181 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
1182 //\r
1183 VisitAllPciInstances (SetPciIntLine);\r
1184\r
1185 //\r
1186 // Set ACPI SCI_EN bit in PMCNTRL\r
1187 //\r
1188 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
1189}\r
1190\r
1191/**\r
1192 This function detects if OVMF is running on Xen.\r
1193\r
1194**/\r
1195STATIC\r
1196BOOLEAN\r
1197XenDetected (\r
1198 VOID\r
1199 )\r
1200{\r
1201 EFI_HOB_GUID_TYPE *GuidHob;\r
1202 STATIC INTN FoundHob = -1;\r
1203\r
1204 if (FoundHob == 0) {\r
1205 return FALSE;\r
1206 } else if (FoundHob == 1) {\r
1207 return TRUE;\r
1208 }\r
1209\r
1210 //\r
1211 // See if a XenInfo HOB is available\r
1212 //\r
1213 GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid);\r
1214 if (GuidHob == NULL) {\r
1215 FoundHob = 0;\r
1216 return FALSE;\r
1217 }\r
1218\r
1219 FoundHob = 1;\r
1220 return TRUE;\r
1221}\r
1222\r
1223EFI_STATUS\r
1224EFIAPI\r
1225ConnectRecursivelyIfPciMassStorage (\r
1226 IN EFI_HANDLE Handle,\r
1227 IN EFI_PCI_IO_PROTOCOL *Instance,\r
1228 IN PCI_TYPE00 *PciHeader\r
1229 )\r
1230{\r
1231 EFI_STATUS Status;\r
1232 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1233 CHAR16 *DevPathStr;\r
1234\r
1235 //\r
1236 // Recognize PCI Mass Storage, and Xen PCI devices\r
1237 //\r
1238 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||\r
1239 (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) {\r
1240 DevicePath = NULL;\r
1241 Status = gBS->HandleProtocol (\r
1242 Handle,\r
1243 &gEfiDevicePathProtocolGuid,\r
1244 (VOID*)&DevicePath\r
1245 );\r
1246 if (EFI_ERROR (Status)) {\r
1247 return Status;\r
1248 }\r
1249\r
1250 //\r
1251 // Print Device Path\r
1252 //\r
1253 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
1254 if (DevPathStr != NULL) {\r
1255 DEBUG((\r
1256 EFI_D_INFO,\r
1257 "Found %s device: %s\n",\r
1258 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?\r
1259 L"Mass Storage" :\r
1260 L"Xen"\r
1261 ),\r
1262 DevPathStr\r
1263 ));\r
1264 FreePool(DevPathStr);\r
1265 }\r
1266\r
1267 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1268 if (EFI_ERROR (Status)) {\r
1269 return Status;\r
1270 }\r
1271\r
1272 }\r
1273\r
1274 return EFI_SUCCESS;\r
1275}\r
1276\r
1277\r
1278/**\r
1279 This notification function is invoked when the\r
1280 EMU Variable FVB has been changed.\r
1281\r
1282 @param Event The event that occurred\r
1283 @param Context For EFI compatibility. Not used.\r
1284\r
1285**/\r
1286VOID\r
1287EFIAPI\r
1288EmuVariablesUpdatedCallback (\r
1289 IN EFI_EVENT Event,\r
1290 IN VOID *Context\r
1291 )\r
1292{\r
1293 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));\r
1294 UpdateNvVarsOnFileSystem ();\r
1295}\r
1296\r
1297\r
1298EFI_STATUS\r
1299EFIAPI\r
1300VisitingFileSystemInstance (\r
1301 IN EFI_HANDLE Handle,\r
1302 IN VOID *Instance,\r
1303 IN VOID *Context\r
1304 )\r
1305{\r
1306 EFI_STATUS Status;\r
1307 STATIC BOOLEAN ConnectedToFileSystem = FALSE;\r
1308 RETURN_STATUS PcdStatus;\r
1309\r
1310 if (ConnectedToFileSystem) {\r
1311 return EFI_ALREADY_STARTED;\r
1312 }\r
1313\r
1314 Status = ConnectNvVarsToFileSystem (Handle);\r
1315 if (EFI_ERROR (Status)) {\r
1316 return Status;\r
1317 }\r
1318\r
1319 ConnectedToFileSystem = TRUE;\r
1320 mEmuVariableEvent =\r
1321 EfiCreateProtocolNotifyEvent (\r
1322 &gEfiDevicePathProtocolGuid,\r
1323 TPL_CALLBACK,\r
1324 EmuVariablesUpdatedCallback,\r
1325 NULL,\r
1326 &mEmuVariableEventReg\r
1327 );\r
1328 PcdStatus = PcdSet64S (PcdEmuVariableEvent,\r
1329 (UINT64)(UINTN) mEmuVariableEvent);\r
1330 ASSERT_RETURN_ERROR (PcdStatus);\r
1331\r
1332 return EFI_SUCCESS;\r
1333}\r
1334\r
1335\r
1336VOID\r
1337PlatformBdsRestoreNvVarsFromHardDisk (\r
1338 )\r
1339{\r
1340 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);\r
1341 VisitAllInstancesOfProtocol (\r
1342 &gEfiSimpleFileSystemProtocolGuid,\r
1343 VisitingFileSystemInstance,\r
1344 NULL\r
1345 );\r
1346\r
1347}\r
1348\r
1349VOID\r
1350PlatformBdsConnectSequence (\r
1351 VOID\r
1352 )\r
1353/*++\r
1354\r
1355Routine Description:\r
1356\r
1357 Connect with predefined platform connect sequence,\r
1358 the OEM/IBV can customize with their own connect sequence.\r
1359\r
1360Arguments:\r
1361\r
1362 None.\r
1363\r
1364Returns:\r
1365\r
1366 None.\r
1367\r
1368--*/\r
1369{\r
1370 UINTN Index;\r
1371 RETURN_STATUS Status;\r
1372\r
1373 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));\r
1374\r
1375 Index = 0;\r
1376\r
1377 //\r
1378 // Here we can get the customized platform connect sequence\r
1379 // Notes: we can connect with new variable which record the\r
1380 // last time boots connect device path sequence\r
1381 //\r
1382 while (gPlatformConnectSequence[Index] != NULL) {\r
1383 //\r
1384 // Build the platform boot option\r
1385 //\r
1386 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
1387 Index++;\r
1388 }\r
1389\r
1390 Status = ConnectDevicesFromQemu ();\r
1391 if (RETURN_ERROR (Status)) {\r
1392 //\r
1393 // Just use the simple policy to connect all devices\r
1394 //\r
1395 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));\r
1396 EfiBootManagerConnectAll ();\r
1397 }\r
1398\r
1399 PciAcpiInitialization ();\r
1400}\r
1401\r
1402/**\r
1403 Save the S3 boot script.\r
1404\r
1405 Note that DxeSmmReadyToLock must be signaled after this function returns;\r
1406 otherwise the script wouldn't be saved actually.\r
1407**/\r
1408STATIC\r
1409VOID\r
1410SaveS3BootScript (\r
1411 VOID\r
1412 )\r
1413{\r
1414 EFI_STATUS Status;\r
1415 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;\r
1416 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };\r
1417\r
1418 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,\r
1419 (VOID **) &BootScript);\r
1420 ASSERT_EFI_ERROR (Status);\r
1421\r
1422 //\r
1423 // Despite the opcode documentation in the PI spec, the protocol\r
1424 // implementation embeds a deep copy of the info in the boot script, rather\r
1425 // than storing just a pointer to runtime or NVS storage.\r
1426 //\r
1427 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,\r
1428 (UINT32) sizeof Info,\r
1429 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);\r
1430 ASSERT_EFI_ERROR (Status);\r
1431}\r
1432\r
1433\r
1434VOID\r
1435EFIAPI\r
1436PlatformBootManagerAfterConsole (\r
1437 VOID\r
1438 )\r
1439/*++\r
1440\r
1441Routine Description:\r
1442\r
1443 The function will execute with as the platform policy, current policy\r
1444 is driven by boot mode. IBV/OEM can customize this code for their specific\r
1445 policy action.\r
1446\r
1447--*/\r
1448{\r
1449 EFI_BOOT_MODE BootMode;\r
1450\r
1451 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));\r
1452\r
1453 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {\r
1454 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "\r
1455 "from disk since flash variables appear to be supported.\n"));\r
1456 } else {\r
1457 //\r
1458 // Try to restore variables from the hard disk early so\r
1459 // they can be used for the other BDS connect operations.\r
1460 //\r
1461 PlatformBdsRestoreNvVarsFromHardDisk ();\r
1462 }\r
1463\r
1464 //\r
1465 // Get current Boot Mode\r
1466 //\r
1467 BootMode = GetBootModeHob ();\r
1468 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
1469\r
1470 //\r
1471 // Go the different platform policy with different boot mode\r
1472 // Notes: this part code can be change with the table policy\r
1473 //\r
1474 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
1475\r
1476 //\r
1477 // Logo show\r
1478 //\r
1479 BootLogoEnableLogo ();\r
1480\r
1481 //\r
1482 // Perform some platform specific connect sequence\r
1483 //\r
1484 PlatformBdsConnectSequence ();\r
1485\r
1486 //\r
1487 // Process QEMU's -kernel command line option\r
1488 //\r
1489 TryRunningQemuKernel ();\r
1490\r
1491 EfiBootManagerRefreshAllBootOption ();\r
1492\r
1493 //\r
1494 // Register UEFI Shell\r
1495 //\r
1496 PlatformRegisterFvBootOption (\r
1497 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
1498 );\r
1499\r
1500 RemoveStaleFvFileOptions ();\r
1501 SetBootOrderFromQemu ();\r
1502}\r
1503\r
1504/**\r
1505 This notification function is invoked when an instance of the\r
1506 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1507\r
1508 @param Event The event that occurred\r
1509 @param Context For EFI compatibility. Not used.\r
1510\r
1511**/\r
1512VOID\r
1513EFIAPI\r
1514NotifyDevPath (\r
1515 IN EFI_EVENT Event,\r
1516 IN VOID *Context\r
1517 )\r
1518{\r
1519 EFI_HANDLE Handle;\r
1520 EFI_STATUS Status;\r
1521 UINTN BufferSize;\r
1522 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1523 ATAPI_DEVICE_PATH *Atapi;\r
1524\r
1525 //\r
1526 // Examine all new handles\r
1527 //\r
1528 for (;;) {\r
1529 //\r
1530 // Get the next handle\r
1531 //\r
1532 BufferSize = sizeof (Handle);\r
1533 Status = gBS->LocateHandle (\r
1534 ByRegisterNotify,\r
1535 NULL,\r
1536 mEfiDevPathNotifyReg,\r
1537 &BufferSize,\r
1538 &Handle\r
1539 );\r
1540\r
1541 //\r
1542 // If not found, we're done\r
1543 //\r
1544 if (EFI_NOT_FOUND == Status) {\r
1545 break;\r
1546 }\r
1547\r
1548 if (EFI_ERROR (Status)) {\r
1549 continue;\r
1550 }\r
1551\r
1552 //\r
1553 // Get the DevicePath protocol on that handle\r
1554 //\r
1555 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,\r
1556 (VOID **)&DevPathNode);\r
1557 ASSERT_EFI_ERROR (Status);\r
1558\r
1559 while (!IsDevicePathEnd (DevPathNode)) {\r
1560 //\r
1561 // Find the handler to dump this device path node\r
1562 //\r
1563 if (\r
1564 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
1565 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)\r
1566 ) {\r
1567 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;\r
1568 PciOr16 (\r
1569 PCI_LIB_ADDRESS (\r
1570 0,\r
1571 1,\r
1572 1,\r
1573 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40\r
1574 ),\r
1575 BIT15\r
1576 );\r
1577 }\r
1578\r
1579 //\r
1580 // Next device path node\r
1581 //\r
1582 DevPathNode = NextDevicePathNode (DevPathNode);\r
1583 }\r
1584 }\r
1585\r
1586 return;\r
1587}\r
1588\r
1589\r
1590VOID\r
1591InstallDevicePathCallback (\r
1592 VOID\r
1593 )\r
1594{\r
1595 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));\r
1596 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
1597 &gEfiDevicePathProtocolGuid,\r
1598 TPL_CALLBACK,\r
1599 NotifyDevPath,\r
1600 NULL,\r
1601 &mEfiDevPathNotifyReg\r
1602 );\r
1603}\r
1604\r
1605/**\r
1606 This function is called each second during the boot manager waits the\r
1607 timeout.\r
1608\r
1609 @param TimeoutRemain The remaining timeout.\r
1610**/\r
1611VOID\r
1612EFIAPI\r
1613PlatformBootManagerWaitCallback (\r
1614 UINT16 TimeoutRemain\r
1615 )\r
1616{\r
1617 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
1618 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
1619 UINT16 Timeout;\r
1620\r
1621 Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
1622\r
1623 Black.Raw = 0x00000000;\r
1624 White.Raw = 0x00FFFFFF;\r
1625\r
1626 BootLogoUpdateProgress (\r
1627 White.Pixel,\r
1628 Black.Pixel,\r
1629 L"Start boot option",\r
1630 White.Pixel,\r
1631 (Timeout - TimeoutRemain) * 100 / Timeout,\r
1632 0\r
1633 );\r
1634}\r
1635\r