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