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