OvmfPkg/PlatformBootManagerLib: wrap overlong lines in "BdsPlatform.c"
[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
18064510
LE
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
30541881
RN
8 http://opensource.org/licenses/bsd-license.php\r
9\r
18064510
LE
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
30541881
RN
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 392 //\r
18064510
LE
393 // Dispatch deferred images after EndOfDxe event and ReadyToLock\r
394 // installation.\r
9789894e
RN
395 //\r
396 EfiBootManagerDispatchDeferredImages ();\r
397\r
e9e9ad64 398 PlatformInitializeConsole (gPlatformConsole);\r
579afd6b
LE
399 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,\r
400 GetFrontPageTimeoutFromQemu ());\r
401 ASSERT_RETURN_ERROR (PcdStatus);\r
07dd96e8
RN
402\r
403 PlatformRegisterOptionsAndKeys ();\r
30541881
RN
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
18064510
LE
474 DevicePath = AppendDevicePathNode (DevicePath,\r
475 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);\r
30541881 476\r
9dc08ec6 477 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
30541881
RN
478\r
479 //\r
480 // Register COM1\r
481 //\r
482 DevicePath = TempDevicePath;\r
483 gPnp16550ComPortDeviceNode.UID = 0;\r
484\r
18064510
LE
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
30541881
RN
491\r
492 //\r
493 // Print Device Path\r
494 //\r
77f47588 495 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881
RN
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
9dc08ec6
RN
507 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
508 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
509 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
510\r
511 //\r
512 // Register COM2\r
513 //\r
514 DevicePath = TempDevicePath;\r
515 gPnp16550ComPortDeviceNode.UID = 1;\r
516\r
18064510
LE
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
30541881
RN
523\r
524 //\r
525 // Print Device Path\r
526 //\r
77f47588 527 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881
RN
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
9dc08ec6
RN
539 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
540 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
541 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
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
f17c0ab6 580 // Try to connect this handle, so that GOP driver could start on this\r
30541881
RN
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
18064510
LE
599 Status = gBS->HandleProtocol (GopHandleBuffer[Index],\r
600 &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);\r
30541881
RN
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
f17c0ab6 613 // In future, we could select all child handles to be console device\r
30541881
RN
614 //\r
615\r
616 *GopDevicePath = TempDevicePath;\r
617\r
618 //\r
18064510
LE
619 // Delete the PCI device's path that added by\r
620 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
30541881 621 //\r
9dc08ec6
RN
622 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
623 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
30541881
RN
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
4fdb585c 633PreparePciDisplayDevicePath (\r
30541881
RN
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
9dc08ec6 672 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
30541881
RN
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
18064510
LE
712 DevicePath = AppendDevicePathNode (DevicePath,\r
713 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
714 DevicePath = AppendDevicePathNode (DevicePath,\r
715 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
30541881 716\r
9dc08ec6
RN
717 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
718 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
719 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
30541881
RN
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
18064510
LE
831 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
832 successfully.\r
30541881
RN
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
4fdb585c 886 // Here we decide which display device to enable in PCI bus\r
30541881 887 //\r
4fdb585c 888 if (IS_PCI_DISPLAY (Pci)) {\r
30541881
RN
889 //\r
890 // Add them to ConOut.\r
891 //\r
4fdb585c
LE
892 DEBUG ((EFI_D_INFO, "Found PCI display device\n"));\r
893 PreparePciDisplayDevicePath (Handle);\r
30541881
RN
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
18064510
LE
906 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
907 successfully.\r
30541881
RN
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
e9e9ad64
RN
921VOID\r
922PlatformInitializeConsole (\r
923 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
30541881
RN
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
f17c0ab6 934 PlatformConsole - Predefined platform default console device array.\r
30541881
RN
935--*/\r
936{\r
30541881
RN
937 UINTN Index;\r
938 EFI_DEVICE_PATH_PROTOCOL *VarConout;\r
939 EFI_DEVICE_PATH_PROTOCOL *VarConin;\r
30541881
RN
940\r
941 //\r
942 // Connect RootBridge\r
943 //\r
18064510
LE
944 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout,\r
945 NULL);\r
e9e9ad64 946 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);\r
30541881
RN
947\r
948 if (VarConout == NULL || VarConin == NULL) {\r
949 //\r
18064510
LE
950 // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
951 // ErrOut\r
30541881
RN
952 //\r
953 DetectAndPreparePlatformPciDevicePaths (FALSE);\r
954\r
955 //\r
956 // Have chance to connect the platform default console,\r
f17c0ab6 957 // the platform default console is the minimum device group\r
30541881
RN
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
18064510
LE
965 EfiBootManagerUpdateConsoleVariable (ConIn,\r
966 PlatformConsole[Index].DevicePath, NULL);\r
30541881
RN
967 }\r
968 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {\r
18064510
LE
969 EfiBootManagerUpdateConsoleVariable (ConOut,\r
970 PlatformConsole[Index].DevicePath, NULL);\r
30541881
RN
971 }\r
972 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {\r
18064510
LE
973 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
974 PlatformConsole[Index].DevicePath, NULL);\r
30541881
RN
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
30541881
RN
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
da2369d2
GL
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
30541881
RN
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
da2369d2
GL
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
30541881
RN
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
77f47588 1253 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
30541881
RN
1254 if (DevPathStr != NULL) {\r
1255 DEBUG((\r
1256 EFI_D_INFO,\r
da2369d2 1257 "Found %s device: %s\n",\r
18064510
LE
1258 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?\r
1259 L"Mass Storage" :\r
1260 L"Xen"\r
1261 ),\r
30541881
RN
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
8c0b0b34
TH
1282 @param Event The event that occurred\r
1283 @param Context For EFI compatibility. Not used.\r
30541881
RN
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
579afd6b 1308 RETURN_STATUS PcdStatus;\r
30541881
RN
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
579afd6b
LE
1328 PcdStatus = PcdSet64S (PcdEmuVariableEvent,\r
1329 (UINT64)(UINTN) mEmuVariableEvent);\r
1330 ASSERT_RETURN_ERROR (PcdStatus);\r
30541881
RN
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
30541881
RN
1349VOID\r
1350PlatformBdsConnectSequence (\r
1351 VOID\r
1352 )\r
1353/*++\r
1354\r
1355Routine Description:\r
1356\r
f17c0ab6 1357 Connect with predefined platform connect sequence,\r
30541881
RN
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
245c643c
LE
1370 UINTN Index;\r
1371 RETURN_STATUS Status;\r
30541881
RN
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
fed691a6 1386 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
30541881
RN
1387 Index++;\r
1388 }\r
1389\r
245c643c
LE
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
30541881
RN
1398\r
1399 PciAcpiInitialization ();\r
30541881
RN
1400}\r
1401\r
30541881
RN
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
a7566234
RN
1436PlatformBootManagerAfterConsole (\r
1437 VOID\r
30541881
RN
1438 )\r
1439/*++\r
1440\r
1441Routine Description:\r
1442\r
f17c0ab6 1443 The function will execute with as the platform policy, current policy\r
30541881
RN
1444 is driven by boot mode. IBV/OEM can customize this code for their specific\r
1445 policy action.\r
1446\r
30541881
RN
1447--*/\r
1448{\r
30541881
RN
1449 EFI_BOOT_MODE BootMode;\r
1450\r
a7566234 1451 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));\r
30541881
RN
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
30541881
RN
1464 //\r
1465 // Get current Boot Mode\r
1466 //\r
30edcbf5 1467 BootMode = GetBootModeHob ();\r
837d9eea 1468 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
30541881
RN
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
30541881
RN
1475\r
1476 //\r
e64a2ebe 1477 // Logo show\r
30541881 1478 //\r
ab970515 1479 BootLogoEnableLogo ();\r
30541881
RN
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
30541881 1490\r
04fe914b
RN
1491 EfiBootManagerRefreshAllBootOption ();\r
1492\r
14b2ebc3
GL
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
2eb35898 1500 RemoveStaleFvFileOptions ();\r
2542feea 1501 SetBootOrderFromQemu ();\r
30541881
RN
1502}\r
1503\r
30541881
RN
1504/**\r
1505 This notification function is invoked when an instance of the\r
1506 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1507\r
8c0b0b34
TH
1508 @param Event The event that occurred\r
1509 @param Context For EFI compatibility. Not used.\r
30541881
RN
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
18064510
LE
1555 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,\r
1556 (VOID **)&DevPathNode);\r
30541881
RN
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
a7566234 1605/**\r
18064510
LE
1606 This function is called each second during the boot manager waits the\r
1607 timeout.\r
a7566234
RN
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
fd096a99
LE
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
a7566234
RN
1634}\r
1635\r