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