]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c
OvmfPkg: Reproduce builds across source format changes
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLibGrub / BdsPlatform.c
CommitLineData
b261a30c
JB
1/** @file\r
2 Platform BDS customizations.\r
3\r
4 Copyright (C) 2020 James Bottomley, IBM Corporation.\r
5 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "BdsPlatform.h"\r
11#include <Guid/RootBridgesConnectedEventGroup.h>\r
12#include <Protocol/FirmwareVolume2.h>\r
13#include <Library/PlatformBmPrintScLib.h>\r
14#include <Library/Tcg2PhysicalPresenceLib.h>\r
15\r
16\r
17//\r
18// Global data\r
19//\r
20\r
21VOID *mEfiDevPathNotifyReg;\r
22EFI_EVENT mEfiDevPathEvent;\r
23UINT16 mHostBridgeDevId;\r
24\r
25//\r
26// Table of host IRQs matching PCI IRQs A-D\r
27// (for configuring PCI Interrupt Line register)\r
28//\r
29CONST UINT8 PciHostIrqs[] = {\r
30 0x0a, 0x0a, 0x0b, 0x0b\r
31};\r
32\r
33//\r
34// Type definitions\r
35//\r
36\r
37typedef\r
38EFI_STATUS\r
39(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(\r
40 IN EFI_HANDLE Handle,\r
41 IN VOID *Instance,\r
42 IN VOID *Context\r
43 );\r
44\r
45/**\r
46 @param[in] Handle - Handle of PCI device instance\r
47 @param[in] PciIo - PCI IO protocol instance\r
48 @param[in] Pci - PCI Header register block\r
49**/\r
50typedef\r
51EFI_STATUS\r
52(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(\r
53 IN EFI_HANDLE Handle,\r
54 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
55 IN PCI_TYPE00 *Pci\r
56 );\r
57\r
58\r
59//\r
60// Function prototypes\r
61//\r
62\r
63EFI_STATUS\r
64VisitAllInstancesOfProtocol (\r
65 IN EFI_GUID *Id,\r
66 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
67 IN VOID *Context\r
68 );\r
69\r
70EFI_STATUS\r
71VisitAllPciInstancesOfProtocol (\r
72 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
73 );\r
74\r
75VOID\r
76InstallDevicePathCallback (\r
77 VOID\r
78 );\r
79\r
80VOID\r
81PlatformRegisterFvBootOption (\r
82 EFI_GUID *FileGuid,\r
83 CHAR16 *Description,\r
84 UINT32 Attributes\r
85 )\r
86{\r
87 EFI_STATUS Status;\r
88 INTN OptionIndex;\r
89 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
90 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
91 UINTN BootOptionCount;\r
92 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
93 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
94 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
95\r
96 Status = gBS->HandleProtocol (\r
97 gImageHandle,\r
98 &gEfiLoadedImageProtocolGuid,\r
99 (VOID **) &LoadedImage\r
100 );\r
101 ASSERT_EFI_ERROR (Status);\r
102\r
103 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
104 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);\r
105 ASSERT (DevicePath != NULL);\r
106 DevicePath = AppendDevicePathNode (\r
107 DevicePath,\r
108 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
109 );\r
110 ASSERT (DevicePath != NULL);\r
111\r
112 Status = EfiBootManagerInitializeLoadOption (\r
113 &NewOption,\r
114 LoadOptionNumberUnassigned,\r
115 LoadOptionTypeBoot,\r
116 Attributes,\r
117 Description,\r
118 DevicePath,\r
119 NULL,\r
120 0\r
121 );\r
122 ASSERT_EFI_ERROR (Status);\r
123 FreePool (DevicePath);\r
124\r
125 BootOptions = EfiBootManagerGetLoadOptions (\r
126 &BootOptionCount, LoadOptionTypeBoot\r
127 );\r
128\r
129 OptionIndex = EfiBootManagerFindLoadOption (\r
130 &NewOption, BootOptions, BootOptionCount\r
131 );\r
132\r
133 if (OptionIndex == -1) {\r
134 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
135 ASSERT_EFI_ERROR (Status);\r
136 }\r
137 EfiBootManagerFreeLoadOption (&NewOption);\r
138 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
139}\r
140\r
141/**\r
142 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options\r
143 whose device paths do not resolve exactly to an FvFile in the system.\r
144\r
145 Also strip out every boot option that is not an FvFile, meaning the system\r
146 can only boot either the Grub or (if built) the shell.\r
147\r
148 This removes any boot options that point to binaries built into the firmware\r
149 and have become stale due to any of the following:\r
150 - DXEFV's base address or size changed (historical),\r
151 - DXEFV's FvNameGuid changed,\r
152 - the FILE_GUID of the pointed-to binary changed,\r
153 - the referenced binary is no longer built into the firmware.\r
154\r
155 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only\r
156 avoids exact duplicates.\r
157**/\r
158VOID\r
159RemoveStaleFvFileOptions (\r
160 VOID\r
161 )\r
162{\r
163 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
164 UINTN BootOptionCount;\r
165 UINTN Index;\r
166\r
167 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,\r
168 LoadOptionTypeBoot);\r
169\r
170 for (Index = 0; Index < BootOptionCount; ++Index) {\r
171 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;\r
172 EFI_STATUS Status;\r
173 EFI_HANDLE FvHandle;\r
174\r
175 //\r
176 // If the device path starts with neither MemoryMapped(...) nor Fv(...),\r
177 // then delete the boot option.\r
178 //\r
179 Node1 = BootOptions[Index].FilePath;\r
180 if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&\r
181 DevicePathSubType (Node1) == HW_MEMMAP_DP) &&\r
182 !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&\r
183 DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {\r
184 EfiBootManagerDeleteLoadOptionVariable (\r
185 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
186 continue;\r
187 }\r
188\r
189 //\r
190 // If the second device path node is not FvFile(...), then delete the boot\r
191 // option.\r
192 //\r
193 Node2 = NextDevicePathNode (Node1);\r
194 if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||\r
195 DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {\r
196 EfiBootManagerDeleteLoadOptionVariable (\r
197 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);\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) ? DEBUG_WARN : DEBUG_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
276EFI_STATUS\r
277EFIAPI\r
278ConnectRootBridge (\r
279 IN EFI_HANDLE RootBridgeHandle,\r
280 IN VOID *Instance,\r
281 IN VOID *Context\r
282 );\r
283\r
284STATIC\r
285EFI_STATUS\r
286EFIAPI\r
287ConnectVirtioPciRng (\r
288 IN EFI_HANDLE Handle,\r
289 IN VOID *Instance,\r
290 IN VOID *Context\r
291 );\r
292\r
293//\r
294// BDS Platform Functions\r
295//\r
296/**\r
297 Do the platform init, can be customized by OEM/IBV\r
298\r
299 Possible things that can be done in PlatformBootManagerBeforeConsole:\r
300\r
301 > Update console variable: 1. include hot-plug devices;\r
302 > 2. Clear ConIn and add SOL for AMT\r
303 > Register new Driver#### or Boot####\r
304 > Register new Key####: e.g.: F12\r
305 > Signal ReadyToLock event\r
306 > Authentication action: 1. connect Auth devices;\r
307 > 2. Identify auto logon user.\r
308**/\r
309VOID\r
310EFIAPI\r
311PlatformBootManagerBeforeConsole (\r
312 VOID\r
313 )\r
314{\r
315 EFI_HANDLE Handle;\r
316 EFI_STATUS Status;\r
317 UINT16 FrontPageTimeout;\r
318\r
319 FrontPageTimeout = 0;\r
320\r
321 DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n"));\r
322 InstallDevicePathCallback ();\r
323\r
324 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,\r
325 ConnectRootBridge, NULL);\r
326\r
327 //\r
328 // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
329 //\r
330 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
331\r
332 //\r
333 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers\r
334 // the preparation of S3 system information. That logic has a hard dependency\r
335 // on the presence of the FACS ACPI table. Since our ACPI tables are only\r
336 // installed after PCI enumeration completes, we must not trigger the S3 save\r
337 // earlier, hence we can't signal End-of-Dxe earlier.\r
338 //\r
339 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
340\r
b8675dea
SB
341 // We need to connect all trusted consoles for TCG PP. Here we treat all\r
342 // consoles in OVMF to be trusted consoles.\r
343 PlatformInitializeConsole (gPlatformConsole);\r
344\r
345 //\r
346 // Process TPM PPI request\r
347 //\r
348 Tcg2PhysicalPresenceLibProcessRequest (NULL);\r
349\r
b261a30c
JB
350 //\r
351 // Prevent further changes to LockBoxes or SMRAM.\r
b8675dea 352 // Any TPM 2 Physical Presence Interface opcode must be handled before.\r
b261a30c
JB
353 //\r
354 Handle = NULL;\r
355 Status = gBS->InstallProtocolInterface (&Handle,\r
356 &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,\r
357 NULL);\r
358 ASSERT_EFI_ERROR (Status);\r
359\r
360 //\r
361 // Dispatch deferred images after EndOfDxe event and ReadyToLock\r
362 // installation.\r
363 //\r
364 EfiBootManagerDispatchDeferredImages ();\r
365\r
b261a30c
JB
366 Status = gRT->SetVariable (\r
367 EFI_TIME_OUT_VARIABLE_NAME,\r
368 &gEfiGlobalVariableGuid,\r
369 (EFI_VARIABLE_NON_VOLATILE |\r
370 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
371 EFI_VARIABLE_RUNTIME_ACCESS),\r
372 sizeof FrontPageTimeout,\r
373 &FrontPageTimeout\r
374 );\r
375 //\r
376 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
377 // instances on Virtio PCI RNG devices.\r
378 //\r
379 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid, ConnectVirtioPciRng,\r
380 NULL);\r
381}\r
382\r
383\r
384EFI_STATUS\r
385EFIAPI\r
386ConnectRootBridge (\r
387 IN EFI_HANDLE RootBridgeHandle,\r
388 IN VOID *Instance,\r
389 IN VOID *Context\r
390 )\r
391{\r
392 EFI_STATUS Status;\r
393\r
394 //\r
395 // Make the PCI bus driver connect the root bridge, non-recursively. This\r
396 // will produce a number of child handles with PciIo on them.\r
397 //\r
398 Status = gBS->ConnectController (\r
399 RootBridgeHandle, // ControllerHandle\r
400 NULL, // DriverImageHandle\r
401 NULL, // RemainingDevicePath -- produce all\r
402 // children\r
403 FALSE // Recursive\r
404 );\r
405 return Status;\r
406}\r
407\r
408\r
409STATIC\r
410EFI_STATUS\r
411EFIAPI\r
412ConnectVirtioPciRng (\r
413 IN EFI_HANDLE Handle,\r
414 IN VOID *Instance,\r
415 IN VOID *Context\r
416 )\r
417{\r
418 EFI_PCI_IO_PROTOCOL *PciIo;\r
419 EFI_STATUS Status;\r
420 UINT16 VendorId;\r
421 UINT16 DeviceId;\r
422 UINT8 RevisionId;\r
423 BOOLEAN Virtio10;\r
424 UINT16 SubsystemId;\r
425\r
426 PciIo = Instance;\r
427\r
428 //\r
429 // Read and check VendorId.\r
430 //\r
431 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,\r
432 1, &VendorId);\r
433 if (EFI_ERROR (Status)) {\r
434 goto Error;\r
435 }\r
436 if (VendorId != VIRTIO_VENDOR_ID) {\r
437 return EFI_SUCCESS;\r
438 }\r
439\r
440 //\r
441 // Read DeviceId and RevisionId.\r
442 //\r
443 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,\r
444 1, &DeviceId);\r
445 if (EFI_ERROR (Status)) {\r
446 goto Error;\r
447 }\r
448 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,\r
449 1, &RevisionId);\r
450 if (EFI_ERROR (Status)) {\r
451 goto Error;\r
452 }\r
453\r
454 //\r
455 // From DeviceId and RevisionId, determine whether the device is a\r
456 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
457 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
458 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
459 // only be sanity-checked, and SubsystemId will decide.\r
460 //\r
461 if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&\r
462 RevisionId >= 0x01) {\r
463 Virtio10 = TRUE;\r
464 } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {\r
465 Virtio10 = FALSE;\r
466 } else {\r
467 return EFI_SUCCESS;\r
468 }\r
469\r
470 //\r
471 // Read and check SubsystemId as dictated by Virtio10.\r
472 //\r
473 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,\r
474 PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);\r
475 if (EFI_ERROR (Status)) {\r
476 goto Error;\r
477 }\r
478 if ((Virtio10 && SubsystemId >= 0x40) ||\r
479 (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {\r
480 Status = gBS->ConnectController (\r
481 Handle, // ControllerHandle\r
482 NULL, // DriverImageHandle -- connect all drivers\r
483 NULL, // RemainingDevicePath -- produce all child handles\r
484 FALSE // Recursive -- don't follow child handles\r
485 );\r
486 if (EFI_ERROR (Status)) {\r
487 goto Error;\r
488 }\r
489 }\r
490 return EFI_SUCCESS;\r
491\r
492Error:\r
493 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));\r
494 return Status;\r
495}\r
496\r
497\r
498/**\r
499 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.\r
500\r
501 @param[in] DeviceHandle Handle of the LPC Bridge device.\r
502\r
503 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to\r
504 ConOut, ConIn, and ErrOut.\r
505\r
506 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
507 from DeviceHandle.\r
508**/\r
509EFI_STATUS\r
510PrepareLpcBridgeDevicePath (\r
511 IN EFI_HANDLE DeviceHandle\r
512 )\r
513{\r
514 EFI_STATUS Status;\r
515 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
516 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
517 CHAR16 *DevPathStr;\r
518\r
519 DevicePath = NULL;\r
520 Status = gBS->HandleProtocol (\r
521 DeviceHandle,\r
522 &gEfiDevicePathProtocolGuid,\r
523 (VOID*)&DevicePath\r
524 );\r
525 if (EFI_ERROR (Status)) {\r
526 return Status;\r
527 }\r
528 TempDevicePath = DevicePath;\r
529\r
530 //\r
531 // Register Keyboard\r
532 //\r
533 DevicePath = AppendDevicePathNode (DevicePath,\r
534 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);\r
535\r
536 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
537\r
538 //\r
539 // Register COM1\r
540 //\r
541 DevicePath = TempDevicePath;\r
542 gPnp16550ComPortDeviceNode.UID = 0;\r
543\r
544 DevicePath = AppendDevicePathNode (DevicePath,\r
545 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);\r
546 DevicePath = AppendDevicePathNode (DevicePath,\r
547 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
548 DevicePath = AppendDevicePathNode (DevicePath,\r
549 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
550\r
551 //\r
552 // Print Device Path\r
553 //\r
554 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
555 if (DevPathStr != NULL) {\r
556 DEBUG((\r
557 DEBUG_INFO,\r
558 "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
fd42dcb1 559 DEBUG_LINE_NUMBER,\r
b261a30c
JB
560 gPnp16550ComPortDeviceNode.UID + 1,\r
561 DevPathStr\r
562 ));\r
563 FreePool(DevPathStr);\r
564 }\r
565\r
566 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
567 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
568 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
569\r
570 //\r
571 // Register COM2\r
572 //\r
573 DevicePath = TempDevicePath;\r
574 gPnp16550ComPortDeviceNode.UID = 1;\r
575\r
576 DevicePath = AppendDevicePathNode (DevicePath,\r
577 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);\r
578 DevicePath = AppendDevicePathNode (DevicePath,\r
579 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
580 DevicePath = AppendDevicePathNode (DevicePath,\r
581 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
582\r
583 //\r
584 // Print Device Path\r
585 //\r
586 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
587 if (DevPathStr != NULL) {\r
588 DEBUG((\r
589 DEBUG_INFO,\r
590 "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
fd42dcb1 591 DEBUG_LINE_NUMBER,\r
b261a30c
JB
592 gPnp16550ComPortDeviceNode.UID + 1,\r
593 DevPathStr\r
594 ));\r
595 FreePool(DevPathStr);\r
596 }\r
597\r
598 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
599 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
600 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
601\r
602 return EFI_SUCCESS;\r
603}\r
604\r
605EFI_STATUS\r
606GetGopDevicePath (\r
607 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,\r
608 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath\r
609 )\r
610{\r
611 UINTN Index;\r
612 EFI_STATUS Status;\r
613 EFI_HANDLE PciDeviceHandle;\r
614 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
615 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;\r
616 UINTN GopHandleCount;\r
617 EFI_HANDLE *GopHandleBuffer;\r
618\r
619 if (PciDevicePath == NULL || GopDevicePath == NULL) {\r
620 return EFI_INVALID_PARAMETER;\r
621 }\r
622\r
623 //\r
624 // Initialize the GopDevicePath to be PciDevicePath\r
625 //\r
626 *GopDevicePath = PciDevicePath;\r
627 TempPciDevicePath = PciDevicePath;\r
628\r
629 Status = gBS->LocateDevicePath (\r
630 &gEfiDevicePathProtocolGuid,\r
631 &TempPciDevicePath,\r
632 &PciDeviceHandle\r
633 );\r
634 if (EFI_ERROR (Status)) {\r
635 return Status;\r
636 }\r
637\r
638 //\r
639 // Try to connect this handle, so that GOP driver could start on this\r
640 // device and create child handles with GraphicsOutput Protocol installed\r
641 // on them, then we get device paths of these child handles and select\r
642 // them as possible console device.\r
643 //\r
644 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);\r
645\r
646 Status = gBS->LocateHandleBuffer (\r
647 ByProtocol,\r
648 &gEfiGraphicsOutputProtocolGuid,\r
649 NULL,\r
650 &GopHandleCount,\r
651 &GopHandleBuffer\r
652 );\r
653 if (!EFI_ERROR (Status)) {\r
654 //\r
655 // Add all the child handles as possible Console Device\r
656 //\r
657 for (Index = 0; Index < GopHandleCount; Index++) {\r
658 Status = gBS->HandleProtocol (GopHandleBuffer[Index],\r
659 &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);\r
660 if (EFI_ERROR (Status)) {\r
661 continue;\r
662 }\r
663 if (CompareMem (\r
664 PciDevicePath,\r
665 TempDevicePath,\r
666 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH\r
667 ) == 0) {\r
668 //\r
669 // In current implementation, we only enable one of the child handles\r
670 // as console device, i.e. sotre one of the child handle's device\r
671 // path to variable "ConOut"\r
672 // In future, we could select all child handles to be console device\r
673 //\r
674\r
675 *GopDevicePath = TempDevicePath;\r
676\r
677 //\r
678 // Delete the PCI device's path that added by\r
679 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
680 //\r
681 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
682 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
683 }\r
684 }\r
685 gBS->FreePool (GopHandleBuffer);\r
686 }\r
687\r
688 return EFI_SUCCESS;\r
689}\r
690\r
691/**\r
692 Add PCI display to ConOut.\r
693\r
694 @param[in] DeviceHandle Handle of the PCI display device.\r
695\r
696 @retval EFI_SUCCESS The PCI display device has been added to ConOut.\r
697\r
698 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
699 from DeviceHandle.\r
700**/\r
701EFI_STATUS\r
702PreparePciDisplayDevicePath (\r
703 IN EFI_HANDLE DeviceHandle\r
704 )\r
705{\r
706 EFI_STATUS Status;\r
707 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
708 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;\r
709\r
710 DevicePath = NULL;\r
711 GopDevicePath = NULL;\r
712 Status = gBS->HandleProtocol (\r
713 DeviceHandle,\r
714 &gEfiDevicePathProtocolGuid,\r
715 (VOID*)&DevicePath\r
716 );\r
717 if (EFI_ERROR (Status)) {\r
718 return Status;\r
719 }\r
720\r
721 GetGopDevicePath (DevicePath, &GopDevicePath);\r
722 DevicePath = GopDevicePath;\r
723\r
724 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
725\r
726 return EFI_SUCCESS;\r
727}\r
728\r
729/**\r
730 Add PCI Serial to ConOut, ConIn, ErrOut.\r
731\r
732 @param[in] DeviceHandle Handle of the PCI serial device.\r
733\r
734 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,\r
735 ErrOut.\r
736\r
737 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
738 from DeviceHandle.\r
739**/\r
740EFI_STATUS\r
741PreparePciSerialDevicePath (\r
742 IN EFI_HANDLE DeviceHandle\r
743 )\r
744{\r
745 EFI_STATUS Status;\r
746 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
747\r
748 DevicePath = NULL;\r
749 Status = gBS->HandleProtocol (\r
750 DeviceHandle,\r
751 &gEfiDevicePathProtocolGuid,\r
752 (VOID*)&DevicePath\r
753 );\r
754 if (EFI_ERROR (Status)) {\r
755 return Status;\r
756 }\r
757\r
758 DevicePath = AppendDevicePathNode (DevicePath,\r
759 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
760 DevicePath = AppendDevicePathNode (DevicePath,\r
761 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
762\r
763 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
764 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
765 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
766\r
767 return EFI_SUCCESS;\r
768}\r
769\r
770EFI_STATUS\r
771VisitAllInstancesOfProtocol (\r
772 IN EFI_GUID *Id,\r
773 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
774 IN VOID *Context\r
775 )\r
776{\r
777 EFI_STATUS Status;\r
778 UINTN HandleCount;\r
779 EFI_HANDLE *HandleBuffer;\r
780 UINTN Index;\r
781 VOID *Instance;\r
782\r
783 //\r
784 // Start to check all the PciIo to find all possible device\r
785 //\r
786 HandleCount = 0;\r
787 HandleBuffer = NULL;\r
788 Status = gBS->LocateHandleBuffer (\r
789 ByProtocol,\r
790 Id,\r
791 NULL,\r
792 &HandleCount,\r
793 &HandleBuffer\r
794 );\r
795 if (EFI_ERROR (Status)) {\r
796 return Status;\r
797 }\r
798\r
799 for (Index = 0; Index < HandleCount; Index++) {\r
800 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);\r
801 if (EFI_ERROR (Status)) {\r
802 continue;\r
803 }\r
804\r
805 Status = (*CallBackFunction) (\r
806 HandleBuffer[Index],\r
807 Instance,\r
808 Context\r
809 );\r
810 }\r
811\r
812 gBS->FreePool (HandleBuffer);\r
813\r
814 return EFI_SUCCESS;\r
815}\r
816\r
817\r
818EFI_STATUS\r
819EFIAPI\r
820VisitingAPciInstance (\r
821 IN EFI_HANDLE Handle,\r
822 IN VOID *Instance,\r
823 IN VOID *Context\r
824 )\r
825{\r
826 EFI_STATUS Status;\r
827 EFI_PCI_IO_PROTOCOL *PciIo;\r
828 PCI_TYPE00 Pci;\r
829\r
830 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;\r
831\r
832 //\r
833 // Check for all PCI device\r
834 //\r
835 Status = PciIo->Pci.Read (\r
836 PciIo,\r
837 EfiPciIoWidthUint32,\r
838 0,\r
839 sizeof (Pci) / sizeof (UINT32),\r
840 &Pci\r
841 );\r
842 if (EFI_ERROR (Status)) {\r
843 return Status;\r
844 }\r
845\r
846 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (\r
847 Handle,\r
848 PciIo,\r
849 &Pci\r
850 );\r
851\r
852}\r
853\r
854\r
855\r
856EFI_STATUS\r
857VisitAllPciInstances (\r
858 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
859 )\r
860{\r
861 return VisitAllInstancesOfProtocol (\r
862 &gEfiPciIoProtocolGuid,\r
863 VisitingAPciInstance,\r
864 (VOID*)(UINTN) CallBackFunction\r
865 );\r
866}\r
867\r
868\r
869/**\r
870 Do platform specific PCI Device check and add them to\r
871 ConOut, ConIn, ErrOut.\r
872\r
873 @param[in] Handle - Handle of PCI device instance\r
874 @param[in] PciIo - PCI IO protocol instance\r
875 @param[in] Pci - PCI Header register block\r
876\r
877 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
878 successfully.\r
879 @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
880\r
881**/\r
882EFI_STATUS\r
883EFIAPI\r
884DetectAndPreparePlatformPciDevicePath (\r
885 IN EFI_HANDLE Handle,\r
886 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
887 IN PCI_TYPE00 *Pci\r
888 )\r
889{\r
890 EFI_STATUS Status;\r
891\r
892 Status = PciIo->Attributes (\r
893 PciIo,\r
894 EfiPciIoAttributeOperationEnable,\r
895 EFI_PCI_DEVICE_ENABLE,\r
896 NULL\r
897 );\r
898 ASSERT_EFI_ERROR (Status);\r
899\r
900 //\r
901 // Here we decide whether it is LPC Bridge\r
902 //\r
903 if ((IS_PCI_LPC (Pci)) ||\r
904 ((IS_PCI_ISA_PDECODE (Pci)) &&\r
905 (Pci->Hdr.VendorId == 0x8086) &&\r
906 (Pci->Hdr.DeviceId == 0x7000)\r
907 )\r
908 ) {\r
909 //\r
910 // Add IsaKeyboard to ConIn,\r
911 // add IsaSerial to ConOut, ConIn, ErrOut\r
912 //\r
913 DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));\r
914 PrepareLpcBridgeDevicePath (Handle);\r
915 return EFI_SUCCESS;\r
916 }\r
917 //\r
918 // Here we decide which Serial device to enable in PCI bus\r
919 //\r
920 if (IS_PCI_16550SERIAL (Pci)) {\r
921 //\r
922 // Add them to ConOut, ConIn, ErrOut.\r
923 //\r
924 DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));\r
925 PreparePciSerialDevicePath (Handle);\r
926 return EFI_SUCCESS;\r
927 }\r
928\r
929 //\r
930 // Here we decide which display device to enable in PCI bus\r
931 //\r
932 if (IS_PCI_DISPLAY (Pci)) {\r
933 //\r
934 // Add them to ConOut.\r
935 //\r
936 DEBUG ((DEBUG_INFO, "Found PCI display device\n"));\r
937 PreparePciDisplayDevicePath (Handle);\r
938 return EFI_SUCCESS;\r
939 }\r
940\r
941 return Status;\r
942}\r
943\r
944\r
945/**\r
946 Connect the predefined platform default console device.\r
947\r
948 Always try to find and enable PCI display devices.\r
949\r
950 @param[in] PlatformConsole Predefined platform default console device array.\r
951**/\r
952VOID\r
953PlatformInitializeConsole (\r
954 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
955 )\r
956{\r
957 UINTN Index;\r
958\r
959 //\r
960 // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
961 // ErrOut\r
962 //\r
963 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);\r
964\r
965 //\r
966 // Have chance to connect the platform default console,\r
967 // the platform default console is the minimum device group\r
968 // the platform should support\r
969 //\r
970 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {\r
971 //\r
972 // Update the console variable with the connect type\r
973 //\r
974 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {\r
975 EfiBootManagerUpdateConsoleVariable (ConIn,\r
976 PlatformConsole[Index].DevicePath, NULL);\r
977 }\r
978 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {\r
979 EfiBootManagerUpdateConsoleVariable (ConOut,\r
980 PlatformConsole[Index].DevicePath, NULL);\r
981 }\r
982 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {\r
983 EfiBootManagerUpdateConsoleVariable (ErrOut,\r
984 PlatformConsole[Index].DevicePath, NULL);\r
985 }\r
986 }\r
987}\r
988\r
989\r
990/**\r
991 Configure PCI Interrupt Line register for applicable devices\r
992 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
993\r
994 @param[in] Handle - Handle of PCI device instance\r
995 @param[in] PciIo - PCI IO protocol instance\r
996 @param[in] PciHdr - PCI Header register block\r
997\r
998 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
999\r
1000**/\r
1001EFI_STATUS\r
1002EFIAPI\r
1003SetPciIntLine (\r
1004 IN EFI_HANDLE Handle,\r
1005 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1006 IN PCI_TYPE00 *PciHdr\r
1007 )\r
1008{\r
1009 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1010 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1011 UINTN RootSlot;\r
1012 UINTN Idx;\r
1013 UINT8 IrqLine;\r
1014 EFI_STATUS Status;\r
1015 UINT32 RootBusNumber;\r
1016\r
1017 Status = EFI_SUCCESS;\r
1018\r
1019 if (PciHdr->Device.InterruptPin != 0) {\r
1020\r
1021 DevPathNode = DevicePathFromHandle (Handle);\r
1022 ASSERT (DevPathNode != NULL);\r
1023 DevPath = DevPathNode;\r
1024\r
1025 RootBusNumber = 0;\r
1026 if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&\r
1027 DevicePathSubType (DevPathNode) == ACPI_DP &&\r
1028 ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {\r
1029 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;\r
1030 }\r
1031\r
1032 //\r
1033 // Compute index into PciHostIrqs[] table by walking\r
1034 // the device path and adding up all device numbers\r
1035 //\r
1036 Status = EFI_NOT_FOUND;\r
1037 RootSlot = 0;\r
1038 Idx = PciHdr->Device.InterruptPin - 1;\r
1039 while (!IsDevicePathEnd (DevPathNode)) {\r
1040 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&\r
1041 DevicePathSubType (DevPathNode) == HW_PCI_DP) {\r
1042\r
1043 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1044\r
1045 //\r
1046 // Unlike SeaBIOS, which starts climbing from the leaf device\r
1047 // up toward the root, we traverse the device path starting at\r
1048 // the root moving toward the leaf node.\r
1049 // The slot number of the top-level parent bridge is needed for\r
1050 // Q35 cases with more than 24 slots on the root bus.\r
1051 //\r
1052 if (Status != EFI_SUCCESS) {\r
1053 Status = EFI_SUCCESS;\r
1054 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1055 }\r
1056 }\r
1057\r
1058 DevPathNode = NextDevicePathNode (DevPathNode);\r
1059 }\r
1060 if (EFI_ERROR (Status)) {\r
1061 return Status;\r
1062 }\r
1063 if (RootBusNumber == 0 && RootSlot == 0) {\r
1064 DEBUG((\r
1065 DEBUG_ERROR,\r
1066 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
1067 __FUNCTION__\r
1068 ));\r
1069 ASSERT (FALSE);\r
1070 }\r
1071\r
1072 //\r
1073 // Final PciHostIrqs[] index calculation depends on the platform\r
1074 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
1075 //\r
1076 switch (mHostBridgeDevId) {\r
1077 case INTEL_82441_DEVICE_ID:\r
1078 Idx -= 1;\r
1079 break;\r
1080 case INTEL_Q35_MCH_DEVICE_ID:\r
1081 //\r
1082 // SeaBIOS contains the following comment:\r
1083 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
1084 // with a different starting index - see q35-acpi-dsdt.dsl.\r
1085 //\r
1086 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
1087 //\r
1088 if (RootSlot > 24) {\r
1089 //\r
1090 // in this case, subtract back out RootSlot from Idx\r
1091 // (SeaBIOS never adds it to begin with, but that would make our\r
1092 // device path traversal loop above too awkward)\r
1093 //\r
1094 Idx -= RootSlot;\r
1095 }\r
1096 break;\r
1097 default:\r
1098 ASSERT (FALSE); // should never get here\r
1099 }\r
1100 Idx %= ARRAY_SIZE (PciHostIrqs);\r
1101 IrqLine = PciHostIrqs[Idx];\r
1102\r
1103 DEBUG_CODE_BEGIN ();\r
1104 {\r
1105 CHAR16 *DevPathString;\r
1106 STATIC CHAR16 Fallback[] = L"<failed to convert>";\r
1107 UINTN Segment, Bus, Device, Function;\r
1108\r
1109 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);\r
1110 if (DevPathString == NULL) {\r
1111 DevPathString = Fallback;\r
1112 }\r
1113 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);\r
1114 ASSERT_EFI_ERROR (Status);\r
1115\r
1116 DEBUG ((DEBUG_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,\r
1117 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,\r
1118 IrqLine));\r
1119\r
1120 if (DevPathString != Fallback) {\r
1121 FreePool (DevPathString);\r
1122 }\r
1123 }\r
1124 DEBUG_CODE_END ();\r
1125\r
1126 //\r
1127 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
1128 //\r
1129 Status = PciIo->Pci.Write (\r
1130 PciIo,\r
1131 EfiPciIoWidthUint8,\r
1132 PCI_INT_LINE_OFFSET,\r
1133 1,\r
1134 &IrqLine\r
1135 );\r
1136 }\r
1137\r
1138 return Status;\r
1139}\r
1140\r
1141\r
1142VOID\r
1143PciAcpiInitialization (\r
1144 )\r
1145{\r
1146 UINTN Pmba;\r
1147\r
1148 //\r
1149 // Query Host Bridge DID to determine platform type\r
1150 //\r
1151 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
1152 switch (mHostBridgeDevId) {\r
1153 case INTEL_82441_DEVICE_ID:\r
1154 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
1155 //\r
1156 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets\r
1157 //\r
1158 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A\r
1159 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B\r
1160 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C\r
1161 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D\r
1162 break;\r
1163 case INTEL_Q35_MCH_DEVICE_ID:\r
1164 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
1165 //\r
1166 // 00:1f.0 LPC Bridge (Q35) LNK routing targets\r
1167 //\r
1168 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A\r
1169 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B\r
1170 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C\r
1171 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D\r
1172 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E\r
1173 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F\r
1174 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G\r
1175 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H\r
1176 break;\r
1177 default:\r
1178 DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
1179 __FUNCTION__, mHostBridgeDevId));\r
1180 ASSERT (FALSE);\r
1181 return;\r
1182 }\r
1183\r
1184 //\r
1185 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
1186 //\r
1187 VisitAllPciInstances (SetPciIntLine);\r
1188\r
1189 //\r
1190 // Set ACPI SCI_EN bit in PMCNTRL\r
1191 //\r
1192 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
1193}\r
1194\r
1195EFI_STATUS\r
1196EFIAPI\r
1197ConnectRecursivelyIfPciMassStorage (\r
1198 IN EFI_HANDLE Handle,\r
1199 IN EFI_PCI_IO_PROTOCOL *Instance,\r
1200 IN PCI_TYPE00 *PciHeader\r
1201 )\r
1202{\r
1203 EFI_STATUS Status;\r
1204 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1205 CHAR16 *DevPathStr;\r
1206\r
1207 //\r
1208 // Recognize PCI Mass Storage\r
1209 //\r
1210 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {\r
1211 DevicePath = NULL;\r
1212 Status = gBS->HandleProtocol (\r
1213 Handle,\r
1214 &gEfiDevicePathProtocolGuid,\r
1215 (VOID*)&DevicePath\r
1216 );\r
1217 if (EFI_ERROR (Status)) {\r
1218 return Status;\r
1219 }\r
1220\r
1221 //\r
1222 // Print Device Path\r
1223 //\r
1224 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
1225 if (DevPathStr != NULL) {\r
1226 DEBUG((\r
1227 DEBUG_INFO,\r
1228 "Found Mass Storage device: %s\n",\r
1229 DevPathStr\r
1230 ));\r
1231 FreePool(DevPathStr);\r
1232 }\r
1233\r
1234 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1235 if (EFI_ERROR (Status)) {\r
1236 return Status;\r
1237 }\r
1238\r
1239 }\r
1240\r
1241 return EFI_SUCCESS;\r
1242}\r
1243\r
1244\r
1245/**\r
1246 Connect with predefined platform connect sequence.\r
1247\r
1248 The OEM/IBV can customize with their own connect sequence.\r
1249**/\r
1250VOID\r
1251PlatformBdsConnectSequence (\r
1252 VOID\r
1253 )\r
1254{\r
1255 UINTN Index;\r
1256\r
1257 DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));\r
1258\r
1259 Index = 0;\r
1260\r
1261 //\r
1262 // Here we can get the customized platform connect sequence\r
1263 // Notes: we can connect with new variable which record the\r
1264 // last time boots connect device path sequence\r
1265 //\r
1266 while (gPlatformConnectSequence[Index] != NULL) {\r
1267 //\r
1268 // Build the platform boot option\r
1269 //\r
1270 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
1271 Index++;\r
1272 }\r
1273 EfiBootManagerConnectAll ();\r
1274}\r
1275\r
1276/**\r
1277 Do the platform specific action after the console is ready\r
1278\r
1279 Possible things that can be done in PlatformBootManagerAfterConsole:\r
1280\r
1281 > Console post action:\r
1282 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
1283 > Signal console ready platform customized event\r
1284 > Run diagnostics like memory testing\r
1285 > Connect certain devices\r
1286 > Dispatch aditional option roms\r
1287 > Special boot: e.g.: USB boot, enter UI\r
1288**/\r
1289VOID\r
1290EFIAPI\r
1291PlatformBootManagerAfterConsole (\r
1292 VOID\r
1293 )\r
1294{\r
1295 EFI_BOOT_MODE BootMode;\r
1296\r
1297 DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));\r
1298\r
1299 //\r
1300 // Get current Boot Mode\r
1301 //\r
1302 BootMode = GetBootModeHob ();\r
1303 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
1304\r
1305 //\r
1306 // Go the different platform policy with different boot mode\r
1307 // Notes: this part code can be change with the table policy\r
1308 //\r
1309 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
1310\r
1311 //\r
1312 // Logo show\r
1313 //\r
1314 BootLogoEnableLogo ();\r
1315\r
1316 //\r
1317 // Set PCI Interrupt Line registers and ACPI SCI_EN\r
1318 //\r
1319 PciAcpiInitialization ();\r
1320\r
a26a08dc
JB
1321 //\r
1322 // Process QEMU's -kernel command line option\r
1323 //\r
1324 TryRunningQemuKernel ();\r
1325\r
b261a30c
JB
1326 //\r
1327 // Perform some platform specific connect sequence\r
1328 //\r
1329 PlatformBdsConnectSequence ();\r
1330\r
1331 EfiBootManagerRefreshAllBootOption ();\r
1332\r
1333 //\r
1334 // Register UEFI Shell (Will be removed if the Shell isn't built\r
1335 // which is the default)\r
1336 //\r
1337 PlatformRegisterFvBootOption (\r
1338 &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
1339 );\r
1340\r
1341 //\r
1342 // Register Grub\r
1343 //\r
1344 PlatformRegisterFvBootOption (\r
1345 &gGrubFileGuid, L"Grub Bootloader", LOAD_OPTION_ACTIVE\r
1346 );\r
1347\r
1348 RemoveStaleFvFileOptions ();\r
1349\r
1350 PlatformBmPrintScRegisterHandler ();\r
1351}\r
1352\r
1353/**\r
1354 This notification function is invoked when an instance of the\r
1355 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1356\r
1357 @param Event The event that occurred\r
1358 @param Context For EFI compatibility. Not used.\r
1359\r
1360**/\r
1361VOID\r
1362EFIAPI\r
1363NotifyDevPath (\r
1364 IN EFI_EVENT Event,\r
1365 IN VOID *Context\r
1366 )\r
1367{\r
1368 EFI_HANDLE Handle;\r
1369 EFI_STATUS Status;\r
1370 UINTN BufferSize;\r
1371 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1372 ATAPI_DEVICE_PATH *Atapi;\r
1373\r
1374 //\r
1375 // Examine all new handles\r
1376 //\r
1377 for (;;) {\r
1378 //\r
1379 // Get the next handle\r
1380 //\r
1381 BufferSize = sizeof (Handle);\r
1382 Status = gBS->LocateHandle (\r
1383 ByRegisterNotify,\r
1384 NULL,\r
1385 mEfiDevPathNotifyReg,\r
1386 &BufferSize,\r
1387 &Handle\r
1388 );\r
1389\r
1390 //\r
1391 // If not found, we're done\r
1392 //\r
1393 if (EFI_NOT_FOUND == Status) {\r
1394 break;\r
1395 }\r
1396\r
1397 if (EFI_ERROR (Status)) {\r
1398 continue;\r
1399 }\r
1400\r
1401 //\r
1402 // Get the DevicePath protocol on that handle\r
1403 //\r
1404 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,\r
1405 (VOID **)&DevPathNode);\r
1406 ASSERT_EFI_ERROR (Status);\r
1407\r
1408 while (!IsDevicePathEnd (DevPathNode)) {\r
1409 //\r
1410 // Find the handler to dump this device path node\r
1411 //\r
1412 if (\r
1413 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
1414 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)\r
1415 ) {\r
1416 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;\r
1417 PciOr16 (\r
1418 PCI_LIB_ADDRESS (\r
1419 0,\r
1420 1,\r
1421 1,\r
1422 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40\r
1423 ),\r
1424 BIT15\r
1425 );\r
1426 }\r
1427\r
1428 //\r
1429 // Next device path node\r
1430 //\r
1431 DevPathNode = NextDevicePathNode (DevPathNode);\r
1432 }\r
1433 }\r
1434\r
1435 return;\r
1436}\r
1437\r
1438\r
1439VOID\r
1440InstallDevicePathCallback (\r
1441 VOID\r
1442 )\r
1443{\r
1444 DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));\r
1445 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
1446 &gEfiDevicePathProtocolGuid,\r
1447 TPL_CALLBACK,\r
1448 NotifyDevPath,\r
1449 NULL,\r
1450 &mEfiDevPathNotifyReg\r
1451 );\r
1452}\r
1453\r
1454/**\r
1455 This function is called each second during the boot manager waits the\r
1456 timeout.\r
1457\r
1458 @param TimeoutRemain The remaining timeout.\r
1459**/\r
1460VOID\r
1461EFIAPI\r
1462PlatformBootManagerWaitCallback (\r
1463 UINT16 TimeoutRemain\r
1464 )\r
1465{\r
1466 //\r
1467 // Since the timeout should be forced to zero we should never\r
1468 // Get here\r
1469 //\r
1470 ASSERT (FALSE);\r
1471}\r
1472\r
1473/**\r
1474 The function is called when no boot option could be launched,\r
1475 including platform recovery options and options pointing to applications\r
1476 built into firmware volumes.\r
1477\r
1478 If this function returns, BDS attempts to enter an infinite loop.\r
1479**/\r
1480VOID\r
1481EFIAPI\r
1482PlatformBootManagerUnableToBoot (\r
1483 VOID\r
1484 )\r
1485{\r
1486 //\r
1487 // If we get here something failed about the grub boot but since\r
1488 // We're privy to the secret we must panic and not retry or loop\r
1489 //\r
1490 ASSERT (FALSE);\r
1491 CpuDeadLoop ();\r
1492}\r