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