]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
OvmfPkg/PlatformBootManagerLib: rejuvenate old-style function comments
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLib / BdsPlatform.c
... / ...
CommitLineData
1/** @file\r
2 Platform BDS customizations.\r
3\r
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials are licensed and made available\r
6 under the terms and conditions of the BSD License which accompanies this\r
7 distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
11 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "BdsPlatform.h"\r
16#include <Guid/XenInfo.h>\r
17#include <Guid/RootBridgesConnectedEventGroup.h>\r
18#include <Protocol/FirmwareVolume2.h>\r
19\r
20\r
21//\r
22// Global data\r
23//\r
24\r
25VOID *mEfiDevPathNotifyReg;\r
26EFI_EVENT mEfiDevPathEvent;\r
27VOID *mEmuVariableEventReg;\r
28EFI_EVENT mEmuVariableEvent;\r
29BOOLEAN mDetectVgaOnly;\r
30UINT16 mHostBridgeDevId;\r
31\r
32//\r
33// Table of host IRQs matching PCI IRQs A-D\r
34// (for configuring PCI Interrupt Line register)\r
35//\r
36CONST UINT8 PciHostIrqs[] = {\r
37 0x0a, 0x0a, 0x0b, 0x0b\r
38};\r
39\r
40//\r
41// Type definitions\r
42//\r
43\r
44typedef\r
45EFI_STATUS\r
46(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(\r
47 IN EFI_HANDLE Handle,\r
48 IN VOID *Instance,\r
49 IN VOID *Context\r
50 );\r
51\r
52/**\r
53 @param[in] Handle - Handle of PCI device instance\r
54 @param[in] PciIo - PCI IO protocol instance\r
55 @param[in] Pci - PCI Header register block\r
56**/\r
57typedef\r
58EFI_STATUS\r
59(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(\r
60 IN EFI_HANDLE Handle,\r
61 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
62 IN PCI_TYPE00 *Pci\r
63 );\r
64\r
65\r
66//\r
67// Function prototypes\r
68//\r
69\r
70EFI_STATUS\r
71VisitAllInstancesOfProtocol (\r
72 IN EFI_GUID *Id,\r
73 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
74 IN VOID *Context\r
75 );\r
76\r
77EFI_STATUS\r
78VisitAllPciInstancesOfProtocol (\r
79 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
80 );\r
81\r
82VOID\r
83InstallDevicePathCallback (\r
84 VOID\r
85 );\r
86\r
87VOID\r
88PlatformRegisterFvBootOption (\r
89 EFI_GUID *FileGuid,\r
90 CHAR16 *Description,\r
91 UINT32 Attributes\r
92 )\r
93{\r
94 EFI_STATUS Status;\r
95 INTN OptionIndex;\r
96 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
97 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
98 UINTN BootOptionCount;\r
99 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
100 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
101 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
102\r
103 Status = gBS->HandleProtocol (\r
104 gImageHandle,\r
105 &gEfiLoadedImageProtocolGuid,\r
106 (VOID **) &LoadedImage\r
107 );\r
108 ASSERT_EFI_ERROR (Status);\r
109\r
110 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
111 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);\r
112 ASSERT (DevicePath != NULL);\r
113 DevicePath = AppendDevicePathNode (\r
114 DevicePath,\r
115 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
116 );\r
117 ASSERT (DevicePath != NULL);\r
118\r
119 Status = EfiBootManagerInitializeLoadOption (\r
120 &NewOption,\r
121 LoadOptionNumberUnassigned,\r
122 LoadOptionTypeBoot,\r
123 Attributes,\r
124 Description,\r
125 DevicePath,\r
126 NULL,\r
127 0\r
128 );\r
129 ASSERT_EFI_ERROR (Status);\r
130 FreePool (DevicePath);\r
131\r
132 BootOptions = EfiBootManagerGetLoadOptions (\r
133 &BootOptionCount, LoadOptionTypeBoot\r
134 );\r
135\r
136 OptionIndex = EfiBootManagerFindLoadOption (\r
137 &NewOption, BootOptions, BootOptionCount\r
138 );\r
139\r
140 if (OptionIndex == -1) {\r
141 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
142 ASSERT_EFI_ERROR (Status);\r
143 }\r
144 EfiBootManagerFreeLoadOption (&NewOption);\r
145 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
146}\r
147\r
148/**\r
149 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options\r
150 whose device paths do not resolve exactly to an FvFile in the system.\r
151\r
152 This removes any boot options that point to binaries built into the firmware\r
153 and have become stale due to any of the following:\r
154 - DXEFV's base address or size changed (historical),\r
155 - DXEFV's FvNameGuid changed,\r
156 - the FILE_GUID of the pointed-to binary changed,\r
157 - the referenced binary is no longer built into the firmware.\r
158\r
159 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only\r
160 avoids exact duplicates.\r
161**/\r
162VOID\r
163RemoveStaleFvFileOptions (\r
164 VOID\r
165 )\r
166{\r
167 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
168 UINTN BootOptionCount;\r
169 UINTN Index;\r
170\r
171 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,\r
172 LoadOptionTypeBoot);\r
173\r
174 for (Index = 0; Index < BootOptionCount; ++Index) {\r
175 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;\r
176 EFI_STATUS Status;\r
177 EFI_HANDLE FvHandle;\r
178\r
179 //\r
180 // If the device path starts with neither MemoryMapped(...) nor Fv(...),\r
181 // then keep the boot option.\r
182 //\r
183 Node1 = BootOptions[Index].FilePath;\r
184 if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&\r
185 DevicePathSubType (Node1) == HW_MEMMAP_DP) &&\r
186 !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&\r
187 DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {\r
188 continue;\r
189 }\r
190\r
191 //\r
192 // If the second device path node is not FvFile(...), then keep the boot\r
193 // option.\r
194 //\r
195 Node2 = NextDevicePathNode (Node1);\r
196 if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||\r
197 DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {\r
198 continue;\r
199 }\r
200\r
201 //\r
202 // Locate the Firmware Volume2 protocol instance that is denoted by the\r
203 // boot option. If this lookup fails (i.e., the boot option references a\r
204 // firmware volume that doesn't exist), then we'll proceed to delete the\r
205 // boot option.\r
206 //\r
207 SearchNode = Node1;\r
208 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,\r
209 &SearchNode, &FvHandle);\r
210\r
211 if (!EFI_ERROR (Status)) {\r
212 //\r
213 // The firmware volume was found; now let's see if it contains the FvFile\r
214 // identified by GUID.\r
215 //\r
216 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;\r
217 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;\r
218 UINTN BufferSize;\r
219 EFI_FV_FILETYPE FoundType;\r
220 EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
221 UINT32 AuthenticationStatus;\r
222\r
223 Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,\r
224 (VOID **)&FvProtocol);\r
225 ASSERT_EFI_ERROR (Status);\r
226\r
227 FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;\r
228 //\r
229 // Buffer==NULL means we request metadata only: BufferSize, FoundType,\r
230 // FileAttributes.\r
231 //\r
232 Status = FvProtocol->ReadFile (\r
233 FvProtocol,\r
234 &FvFileNode->FvFileName, // NameGuid\r
235 NULL, // Buffer\r
236 &BufferSize,\r
237 &FoundType,\r
238 &FileAttributes,\r
239 &AuthenticationStatus\r
240 );\r
241 if (!EFI_ERROR (Status)) {\r
242 //\r
243 // The FvFile was found. Keep the boot option.\r
244 //\r
245 continue;\r
246 }\r
247 }\r
248\r
249 //\r
250 // Delete the boot option.\r
251 //\r
252 Status = EfiBootManagerDeleteLoadOptionVariable (\r
253 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
254 DEBUG_CODE (\r
255 CHAR16 *DevicePathString;\r
256\r
257 DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,\r
258 FALSE, FALSE);\r
259 DEBUG ((\r
260 EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,\r
261 "%a: removing stale Boot#%04x %s: %r\n",\r
262 __FUNCTION__,\r
263 (UINT32)BootOptions[Index].OptionNumber,\r
264 DevicePathString == NULL ? L"<unavailable>" : DevicePathString,\r
265 Status\r
266 ));\r
267 if (DevicePathString != NULL) {\r
268 FreePool (DevicePathString);\r
269 }\r
270 );\r
271 }\r
272\r
273 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
274}\r
275\r
276VOID\r
277PlatformRegisterOptionsAndKeys (\r
278 VOID\r
279 )\r
280{\r
281 EFI_STATUS Status;\r
282 EFI_INPUT_KEY Enter;\r
283 EFI_INPUT_KEY F2;\r
284 EFI_INPUT_KEY Esc;\r
285 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
286\r
287 //\r
288 // Register ENTER as CONTINUE key\r
289 //\r
290 Enter.ScanCode = SCAN_NULL;\r
291 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
292 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
293 ASSERT_EFI_ERROR (Status);\r
294\r
295 //\r
296 // Map F2 to Boot Manager Menu\r
297 //\r
298 F2.ScanCode = SCAN_F2;\r
299 F2.UnicodeChar = CHAR_NULL;\r
300 Esc.ScanCode = SCAN_ESC;\r
301 Esc.UnicodeChar = CHAR_NULL;\r
302 Status = EfiBootManagerGetBootManagerMenu (&BootOption);\r
303 ASSERT_EFI_ERROR (Status);\r
304 Status = EfiBootManagerAddKeyOptionVariable (\r
305 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL\r
306 );\r
307 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
308 Status = EfiBootManagerAddKeyOptionVariable (\r
309 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL\r
310 );\r
311 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
312}\r
313\r
314EFI_STATUS\r
315EFIAPI\r
316ConnectRootBridge (\r
317 IN EFI_HANDLE RootBridgeHandle,\r
318 IN VOID *Instance,\r
319 IN VOID *Context\r
320 );\r
321\r
322STATIC\r
323VOID\r
324SaveS3BootScript (\r
325 VOID\r
326 );\r
327\r
328//\r
329// BDS Platform Functions\r
330//\r
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
344VOID\r
345EFIAPI\r
346PlatformBootManagerBeforeConsole (\r
347 VOID\r
348 )\r
349{\r
350 EFI_HANDLE Handle;\r
351 EFI_STATUS Status;\r
352 RETURN_STATUS PcdStatus;\r
353\r
354 DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));\r
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
390\r
391 //\r
392 // Dispatch deferred images after EndOfDxe event and ReadyToLock\r
393 // installation.\r
394 //\r
395 EfiBootManagerDispatchDeferredImages ();\r
396\r
397 PlatformInitializeConsole (gPlatformConsole);\r
398 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,\r
399 GetFrontPageTimeoutFromQemu ());\r
400 ASSERT_RETURN_ERROR (PcdStatus);\r
401\r
402 PlatformRegisterOptionsAndKeys ();\r
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
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
442EFI_STATUS\r
443PrepareLpcBridgeDevicePath (\r
444 IN EFI_HANDLE DeviceHandle\r
445 )\r
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
466 DevicePath = AppendDevicePathNode (DevicePath,\r
467 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);\r
468\r
469 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
470\r
471 //\r
472 // Register COM1\r
473 //\r
474 DevicePath = TempDevicePath;\r
475 gPnp16550ComPortDeviceNode.UID = 0;\r
476\r
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
483\r
484 //\r
485 // Print Device Path\r
486 //\r
487 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
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
499 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
500 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
501 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
502\r
503 //\r
504 // Register COM2\r
505 //\r
506 DevicePath = TempDevicePath;\r
507 gPnp16550ComPortDeviceNode.UID = 1;\r
508\r
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
515\r
516 //\r
517 // Print Device Path\r
518 //\r
519 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
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
531 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
532 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
533 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
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
572 // Try to connect this handle, so that GOP driver could start on this\r
573 // device and create child handles with GraphicsOutput Protocol installed\r
574 // on them, then we get device paths of these child handles and select\r
575 // them as possible console device.\r
576 //\r
577 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);\r
578\r
579 Status = gBS->LocateHandleBuffer (\r
580 ByProtocol,\r
581 &gEfiGraphicsOutputProtocolGuid,\r
582 NULL,\r
583 &GopHandleCount,\r
584 &GopHandleBuffer\r
585 );\r
586 if (!EFI_ERROR (Status)) {\r
587 //\r
588 // Add all the child handles as possible Console Device\r
589 //\r
590 for (Index = 0; Index < GopHandleCount; Index++) {\r
591 Status = gBS->HandleProtocol (GopHandleBuffer[Index],\r
592 &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);\r
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
605 // In future, we could select all child handles to be console device\r
606 //\r
607\r
608 *GopDevicePath = TempDevicePath;\r
609\r
610 //\r
611 // Delete the PCI device's path that added by\r
612 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
613 //\r
614 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
615 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
616 }\r
617 }\r
618 gBS->FreePool (GopHandleBuffer);\r
619 }\r
620\r
621 return EFI_SUCCESS;\r
622}\r
623\r
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
634EFI_STATUS\r
635PreparePciDisplayDevicePath (\r
636 IN EFI_HANDLE DeviceHandle\r
637 )\r
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
657 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
658\r
659 return EFI_SUCCESS;\r
660}\r
661\r
662/**\r
663 Add PCI Serial to ConOut, ConIn, ErrOut.\r
664\r
665 @param[in] DeviceHandle Handle of the PCI serial device.\r
666\r
667 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,\r
668 ErrOut.\r
669\r
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
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
691 DevicePath = AppendDevicePathNode (DevicePath,\r
692 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
693 DevicePath = AppendDevicePathNode (DevicePath,\r
694 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
695\r
696 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
697 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
698 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
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
810 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
811 successfully.\r
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
865 // Here we decide which display device to enable in PCI bus\r
866 //\r
867 if (IS_PCI_DISPLAY (Pci)) {\r
868 //\r
869 // Add them to ConOut.\r
870 //\r
871 DEBUG ((EFI_D_INFO, "Found PCI display device\n"));\r
872 PreparePciDisplayDevicePath (Handle);\r
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
885 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
886 successfully.\r
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
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
907VOID\r
908PlatformInitializeConsole (\r
909 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
910 )\r
911{\r
912 UINTN Index;\r
913 EFI_DEVICE_PATH_PROTOCOL *VarConout;\r
914 EFI_DEVICE_PATH_PROTOCOL *VarConin;\r
915\r
916 //\r
917 // Connect RootBridge\r
918 //\r
919 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout,\r
920 NULL);\r
921 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);\r
922\r
923 if (VarConout == NULL || VarConin == NULL) {\r
924 //\r
925 // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
926 // ErrOut\r
927 //\r
928 DetectAndPreparePlatformPciDevicePaths (FALSE);\r
929\r
930 //\r
931 // Have chance to connect the platform default console,\r
932 // the platform default console is the minimum device group\r
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
940 EfiBootManagerUpdateConsoleVariable (ConIn,\r
941 PlatformConsole[Index].DevicePath, NULL);\r
942 }\r
943 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {\r
944 EfiBootManagerUpdateConsoleVariable (ConOut,\r
945 PlatformConsole[Index].DevicePath, NULL);\r
946 }\r
947 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {\r
948 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
949 PlatformConsole[Index].DevicePath, NULL);\r
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
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
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
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
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
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
1228 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
1229 if (DevPathStr != NULL) {\r
1230 DEBUG((\r
1231 EFI_D_INFO,\r
1232 "Found %s device: %s\n",\r
1233 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?\r
1234 L"Mass Storage" :\r
1235 L"Xen"\r
1236 ),\r
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
1257 @param Event The event that occurred\r
1258 @param Context For EFI compatibility. Not used.\r
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
1283 RETURN_STATUS PcdStatus;\r
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
1303 PcdStatus = PcdSet64S (PcdEmuVariableEvent,\r
1304 (UINT64)(UINTN) mEmuVariableEvent);\r
1305 ASSERT_RETURN_ERROR (PcdStatus);\r
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
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
1329VOID\r
1330PlatformBdsConnectSequence (\r
1331 VOID\r
1332 )\r
1333{\r
1334 UINTN Index;\r
1335 RETURN_STATUS Status;\r
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
1350 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
1351 Index++;\r
1352 }\r
1353\r
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
1362\r
1363 PciAcpiInitialization ();\r
1364}\r
1365\r
1366/**\r
1367 Save the S3 boot script.\r
1368\r
1369 Note that DxeSmmReadyToLock must be signaled after this function returns;\r
1370 otherwise the script wouldn't be saved actually.\r
1371**/\r
1372STATIC\r
1373VOID\r
1374SaveS3BootScript (\r
1375 VOID\r
1376 )\r
1377{\r
1378 EFI_STATUS Status;\r
1379 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;\r
1380 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };\r
1381\r
1382 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,\r
1383 (VOID **) &BootScript);\r
1384 ASSERT_EFI_ERROR (Status);\r
1385\r
1386 //\r
1387 // Despite the opcode documentation in the PI spec, the protocol\r
1388 // implementation embeds a deep copy of the info in the boot script, rather\r
1389 // than storing just a pointer to runtime or NVS storage.\r
1390 //\r
1391 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,\r
1392 (UINT32) sizeof Info,\r
1393 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);\r
1394 ASSERT_EFI_ERROR (Status);\r
1395}\r
1396\r
1397\r
1398/**\r
1399 Do the platform specific action after the console is ready\r
1400\r
1401 Possible things that can be done in PlatformBootManagerAfterConsole:\r
1402\r
1403 > Console post action:\r
1404 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
1405 > Signal console ready platform customized event\r
1406 > Run diagnostics like memory testing\r
1407 > Connect certain devices\r
1408 > Dispatch aditional option roms\r
1409 > Special boot: e.g.: USB boot, enter UI\r
1410**/\r
1411VOID\r
1412EFIAPI\r
1413PlatformBootManagerAfterConsole (\r
1414 VOID\r
1415 )\r
1416{\r
1417 EFI_BOOT_MODE BootMode;\r
1418\r
1419 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));\r
1420\r
1421 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {\r
1422 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "\r
1423 "from disk since flash variables appear to be supported.\n"));\r
1424 } else {\r
1425 //\r
1426 // Try to restore variables from the hard disk early so\r
1427 // they can be used for the other BDS connect operations.\r
1428 //\r
1429 PlatformBdsRestoreNvVarsFromHardDisk ();\r
1430 }\r
1431\r
1432 //\r
1433 // Get current Boot Mode\r
1434 //\r
1435 BootMode = GetBootModeHob ();\r
1436 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
1437\r
1438 //\r
1439 // Go the different platform policy with different boot mode\r
1440 // Notes: this part code can be change with the table policy\r
1441 //\r
1442 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
1443\r
1444 //\r
1445 // Logo show\r
1446 //\r
1447 BootLogoEnableLogo ();\r
1448\r
1449 //\r
1450 // Perform some platform specific connect sequence\r
1451 //\r
1452 PlatformBdsConnectSequence ();\r
1453\r
1454 //\r
1455 // Process QEMU's -kernel command line option\r
1456 //\r
1457 TryRunningQemuKernel ();\r
1458\r
1459 EfiBootManagerRefreshAllBootOption ();\r
1460\r
1461 //\r
1462 // Register UEFI Shell\r
1463 //\r
1464 PlatformRegisterFvBootOption (\r
1465 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
1466 );\r
1467\r
1468 RemoveStaleFvFileOptions ();\r
1469 SetBootOrderFromQemu ();\r
1470}\r
1471\r
1472/**\r
1473 This notification function is invoked when an instance of the\r
1474 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1475\r
1476 @param Event The event that occurred\r
1477 @param Context For EFI compatibility. Not used.\r
1478\r
1479**/\r
1480VOID\r
1481EFIAPI\r
1482NotifyDevPath (\r
1483 IN EFI_EVENT Event,\r
1484 IN VOID *Context\r
1485 )\r
1486{\r
1487 EFI_HANDLE Handle;\r
1488 EFI_STATUS Status;\r
1489 UINTN BufferSize;\r
1490 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1491 ATAPI_DEVICE_PATH *Atapi;\r
1492\r
1493 //\r
1494 // Examine all new handles\r
1495 //\r
1496 for (;;) {\r
1497 //\r
1498 // Get the next handle\r
1499 //\r
1500 BufferSize = sizeof (Handle);\r
1501 Status = gBS->LocateHandle (\r
1502 ByRegisterNotify,\r
1503 NULL,\r
1504 mEfiDevPathNotifyReg,\r
1505 &BufferSize,\r
1506 &Handle\r
1507 );\r
1508\r
1509 //\r
1510 // If not found, we're done\r
1511 //\r
1512 if (EFI_NOT_FOUND == Status) {\r
1513 break;\r
1514 }\r
1515\r
1516 if (EFI_ERROR (Status)) {\r
1517 continue;\r
1518 }\r
1519\r
1520 //\r
1521 // Get the DevicePath protocol on that handle\r
1522 //\r
1523 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,\r
1524 (VOID **)&DevPathNode);\r
1525 ASSERT_EFI_ERROR (Status);\r
1526\r
1527 while (!IsDevicePathEnd (DevPathNode)) {\r
1528 //\r
1529 // Find the handler to dump this device path node\r
1530 //\r
1531 if (\r
1532 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
1533 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)\r
1534 ) {\r
1535 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;\r
1536 PciOr16 (\r
1537 PCI_LIB_ADDRESS (\r
1538 0,\r
1539 1,\r
1540 1,\r
1541 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40\r
1542 ),\r
1543 BIT15\r
1544 );\r
1545 }\r
1546\r
1547 //\r
1548 // Next device path node\r
1549 //\r
1550 DevPathNode = NextDevicePathNode (DevPathNode);\r
1551 }\r
1552 }\r
1553\r
1554 return;\r
1555}\r
1556\r
1557\r
1558VOID\r
1559InstallDevicePathCallback (\r
1560 VOID\r
1561 )\r
1562{\r
1563 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));\r
1564 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
1565 &gEfiDevicePathProtocolGuid,\r
1566 TPL_CALLBACK,\r
1567 NotifyDevPath,\r
1568 NULL,\r
1569 &mEfiDevPathNotifyReg\r
1570 );\r
1571}\r
1572\r
1573/**\r
1574 This function is called each second during the boot manager waits the\r
1575 timeout.\r
1576\r
1577 @param TimeoutRemain The remaining timeout.\r
1578**/\r
1579VOID\r
1580EFIAPI\r
1581PlatformBootManagerWaitCallback (\r
1582 UINT16 TimeoutRemain\r
1583 )\r
1584{\r
1585 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
1586 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
1587 UINT16 Timeout;\r
1588\r
1589 Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
1590\r
1591 Black.Raw = 0x00000000;\r
1592 White.Raw = 0x00FFFFFF;\r
1593\r
1594 BootLogoUpdateProgress (\r
1595 White.Pixel,\r
1596 Black.Pixel,\r
1597 L"Start boot option",\r
1598 White.Pixel,\r
1599 (Timeout - TimeoutRemain) * 100 / Timeout,\r
1600 0\r
1601 );\r
1602}\r
1603\r