]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.c
OvmfPkg/PlatformInitLib: Create MemDetect.c
[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
ee1f8262
SB
437 //\r
438 // GPU passthrough only allows Console enablement after ROM image load\r
439 //\r
440 PlatformInitializeConsole (gPlatformConsole);\r
441\r
656419f9
RC
442 PlatformRegisterOptionsAndKeys ();\r
443\r
444 //\r
445 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
446 // instances on Virtio PCI RNG devices.\r
447 //\r
ac0a286f
MK
448 VisitAllInstancesOfProtocol (\r
449 &gEfiPciIoProtocolGuid,\r
450 ConnectVirtioPciRng,\r
451 NULL\r
452 );\r
656419f9
RC
453}\r
454\r
656419f9
RC
455EFI_STATUS\r
456EFIAPI\r
457ConnectRootBridge (\r
458 IN EFI_HANDLE RootBridgeHandle,\r
459 IN VOID *Instance,\r
460 IN VOID *Context\r
461 )\r
462{\r
ac0a286f 463 EFI_STATUS Status;\r
656419f9
RC
464\r
465 //\r
466 // Make the PCI bus driver connect the root bridge, non-recursively. This\r
467 // will produce a number of child handles with PciIo on them.\r
468 //\r
469 Status = gBS->ConnectController (\r
470 RootBridgeHandle, // ControllerHandle\r
471 NULL, // DriverImageHandle\r
472 NULL, // RemainingDevicePath -- produce all\r
473 // children\r
474 FALSE // Recursive\r
475 );\r
476 return Status;\r
477}\r
478\r
656419f9
RC
479STATIC\r
480EFI_STATUS\r
481EFIAPI\r
482ConnectVirtioPciRng (\r
ac0a286f
MK
483 IN EFI_HANDLE Handle,\r
484 IN VOID *Instance,\r
485 IN VOID *Context\r
656419f9
RC
486 )\r
487{\r
ac0a286f
MK
488 EFI_PCI_IO_PROTOCOL *PciIo;\r
489 EFI_STATUS Status;\r
490 UINT16 VendorId;\r
491 UINT16 DeviceId;\r
492 UINT8 RevisionId;\r
493 BOOLEAN Virtio10;\r
494 UINT16 SubsystemId;\r
656419f9
RC
495\r
496 PciIo = Instance;\r
497\r
498 //\r
499 // Read and check VendorId.\r
500 //\r
ac0a286f
MK
501 Status = PciIo->Pci.Read (\r
502 PciIo,\r
503 EfiPciIoWidthUint16,\r
504 PCI_VENDOR_ID_OFFSET,\r
505 1,\r
506 &VendorId\r
507 );\r
656419f9
RC
508 if (EFI_ERROR (Status)) {\r
509 goto Error;\r
510 }\r
ac0a286f 511\r
656419f9
RC
512 if (VendorId != VIRTIO_VENDOR_ID) {\r
513 return EFI_SUCCESS;\r
514 }\r
515\r
516 //\r
517 // Read DeviceId and RevisionId.\r
518 //\r
ac0a286f
MK
519 Status = PciIo->Pci.Read (\r
520 PciIo,\r
521 EfiPciIoWidthUint16,\r
522 PCI_DEVICE_ID_OFFSET,\r
523 1,\r
524 &DeviceId\r
525 );\r
656419f9
RC
526 if (EFI_ERROR (Status)) {\r
527 goto Error;\r
528 }\r
ac0a286f
MK
529\r
530 Status = PciIo->Pci.Read (\r
531 PciIo,\r
532 EfiPciIoWidthUint8,\r
533 PCI_REVISION_ID_OFFSET,\r
534 1,\r
535 &RevisionId\r
536 );\r
656419f9
RC
537 if (EFI_ERROR (Status)) {\r
538 goto Error;\r
539 }\r
540\r
541 //\r
542 // From DeviceId and RevisionId, determine whether the device is a\r
543 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
544 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
545 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
546 // only be sanity-checked, and SubsystemId will decide.\r
547 //\r
ac0a286f
MK
548 if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&\r
549 (RevisionId >= 0x01))\r
550 {\r
656419f9 551 Virtio10 = TRUE;\r
ac0a286f 552 } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {\r
656419f9
RC
553 Virtio10 = FALSE;\r
554 } else {\r
555 return EFI_SUCCESS;\r
556 }\r
557\r
558 //\r
559 // Read and check SubsystemId as dictated by Virtio10.\r
560 //\r
ac0a286f
MK
561 Status = PciIo->Pci.Read (\r
562 PciIo,\r
563 EfiPciIoWidthUint16,\r
564 PCI_SUBSYSTEM_ID_OFFSET,\r
565 1,\r
566 &SubsystemId\r
567 );\r
656419f9
RC
568 if (EFI_ERROR (Status)) {\r
569 goto Error;\r
570 }\r
ac0a286f
MK
571\r
572 if ((Virtio10 && (SubsystemId >= 0x40)) ||\r
573 (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)))\r
574 {\r
656419f9
RC
575 Status = gBS->ConnectController (\r
576 Handle, // ControllerHandle\r
577 NULL, // DriverImageHandle -- connect all drivers\r
578 NULL, // RemainingDevicePath -- produce all child handles\r
579 FALSE // Recursive -- don't follow child handles\r
580 );\r
581 if (EFI_ERROR (Status)) {\r
582 goto Error;\r
583 }\r
584 }\r
ac0a286f 585\r
656419f9
RC
586 return EFI_SUCCESS;\r
587\r
588Error:\r
589 DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));\r
590 return Status;\r
591}\r
592\r
656419f9
RC
593/**\r
594 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.\r
595\r
596 @param[in] DeviceHandle Handle of the LPC Bridge device.\r
597\r
598 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to\r
599 ConOut, ConIn, and ErrOut.\r
600\r
601 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
602 from DeviceHandle.\r
603**/\r
604EFI_STATUS\r
605PrepareLpcBridgeDevicePath (\r
ac0a286f 606 IN EFI_HANDLE DeviceHandle\r
656419f9
RC
607 )\r
608{\r
609 EFI_STATUS Status;\r
610 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
611 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
612 CHAR16 *DevPathStr;\r
613\r
614 DevicePath = NULL;\r
ac0a286f
MK
615 Status = gBS->HandleProtocol (\r
616 DeviceHandle,\r
617 &gEfiDevicePathProtocolGuid,\r
618 (VOID *)&DevicePath\r
619 );\r
656419f9
RC
620 if (EFI_ERROR (Status)) {\r
621 return Status;\r
622 }\r
ac0a286f 623\r
656419f9
RC
624 TempDevicePath = DevicePath;\r
625\r
626 //\r
627 // Register Keyboard\r
628 //\r
ac0a286f
MK
629 DevicePath = AppendDevicePathNode (\r
630 DevicePath,\r
631 (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode\r
632 );\r
656419f9
RC
633\r
634 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
635\r
636 //\r
637 // Register COM1\r
638 //\r
ac0a286f 639 DevicePath = TempDevicePath;\r
656419f9
RC
640 gPnp16550ComPortDeviceNode.UID = 0;\r
641\r
ac0a286f
MK
642 DevicePath = AppendDevicePathNode (\r
643 DevicePath,\r
644 (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode\r
645 );\r
646 DevicePath = AppendDevicePathNode (\r
647 DevicePath,\r
648 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode\r
649 );\r
650 DevicePath = AppendDevicePathNode (\r
651 DevicePath,\r
652 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode\r
653 );\r
656419f9
RC
654\r
655 //\r
656 // Print Device Path\r
657 //\r
658 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
659 if (DevPathStr != NULL) {\r
ac0a286f 660 DEBUG ((\r
656419f9
RC
661 DEBUG_INFO,\r
662 "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
fd42dcb1 663 DEBUG_LINE_NUMBER,\r
656419f9
RC
664 gPnp16550ComPortDeviceNode.UID + 1,\r
665 DevPathStr\r
666 ));\r
ac0a286f 667 FreePool (DevPathStr);\r
656419f9
RC
668 }\r
669\r
670 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
671 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
672 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
673\r
674 // Don't register COM2 which can be used for DBG instead so keep it clean\r
675\r
676 return EFI_SUCCESS;\r
677}\r
678\r
679EFI_STATUS\r
680GetGopDevicePath (\r
ac0a286f
MK
681 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,\r
682 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath\r
683 )\r
656419f9 684{\r
ac0a286f
MK
685 UINTN Index;\r
686 EFI_STATUS Status;\r
687 EFI_HANDLE PciDeviceHandle;\r
688 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
689 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;\r
690 UINTN GopHandleCount;\r
691 EFI_HANDLE *GopHandleBuffer;\r
692\r
693 if ((PciDevicePath == NULL) || (GopDevicePath == NULL)) {\r
656419f9
RC
694 return EFI_INVALID_PARAMETER;\r
695 }\r
696\r
697 //\r
698 // Initialize the GopDevicePath to be PciDevicePath\r
699 //\r
700 *GopDevicePath = PciDevicePath;\r
701 TempPciDevicePath = PciDevicePath;\r
702\r
703 Status = gBS->LocateDevicePath (\r
704 &gEfiDevicePathProtocolGuid,\r
705 &TempPciDevicePath,\r
706 &PciDeviceHandle\r
707 );\r
708 if (EFI_ERROR (Status)) {\r
709 return Status;\r
710 }\r
711\r
712 //\r
713 // Try to connect this handle, so that GOP driver could start on this\r
714 // device and create child handles with GraphicsOutput Protocol installed\r
715 // on them, then we get device paths of these child handles and select\r
716 // them as possible console device.\r
717 //\r
718 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);\r
719\r
720 Status = gBS->LocateHandleBuffer (\r
721 ByProtocol,\r
722 &gEfiGraphicsOutputProtocolGuid,\r
723 NULL,\r
724 &GopHandleCount,\r
725 &GopHandleBuffer\r
726 );\r
727 if (!EFI_ERROR (Status)) {\r
728 //\r
729 // Add all the child handles as possible Console Device\r
730 //\r
731 for (Index = 0; Index < GopHandleCount; Index++) {\r
ac0a286f
MK
732 Status = gBS->HandleProtocol (\r
733 GopHandleBuffer[Index],\r
734 &gEfiDevicePathProtocolGuid,\r
735 (VOID *)&TempDevicePath\r
736 );\r
656419f9
RC
737 if (EFI_ERROR (Status)) {\r
738 continue;\r
739 }\r
ac0a286f 740\r
656419f9
RC
741 if (CompareMem (\r
742 PciDevicePath,\r
743 TempDevicePath,\r
744 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH\r
ac0a286f
MK
745 ) == 0)\r
746 {\r
656419f9
RC
747 //\r
748 // In current implementation, we only enable one of the child handles\r
749 // as console device, i.e. sotre one of the child handle's device\r
750 // path to variable "ConOut"\r
751 // In future, we could select all child handles to be console device\r
752 //\r
753\r
754 *GopDevicePath = TempDevicePath;\r
755\r
756 //\r
757 // Delete the PCI device's path that added by\r
758 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
759 //\r
760 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
761 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
762 }\r
763 }\r
ac0a286f 764\r
656419f9
RC
765 gBS->FreePool (GopHandleBuffer);\r
766 }\r
767\r
768 return EFI_SUCCESS;\r
769}\r
770\r
771/**\r
772 Add PCI display to ConOut.\r
773\r
774 @param[in] DeviceHandle Handle of the PCI display device.\r
775\r
776 @retval EFI_SUCCESS The PCI display device has been added to ConOut.\r
777\r
778 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
779 from DeviceHandle.\r
780**/\r
781EFI_STATUS\r
782PreparePciDisplayDevicePath (\r
ac0a286f 783 IN EFI_HANDLE DeviceHandle\r
656419f9
RC
784 )\r
785{\r
786 EFI_STATUS Status;\r
787 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
788 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;\r
789\r
790 DevicePath = NULL;\r
791 GopDevicePath = NULL;\r
ac0a286f
MK
792 Status = gBS->HandleProtocol (\r
793 DeviceHandle,\r
794 &gEfiDevicePathProtocolGuid,\r
795 (VOID *)&DevicePath\r
796 );\r
656419f9
RC
797 if (EFI_ERROR (Status)) {\r
798 return Status;\r
799 }\r
800\r
801 GetGopDevicePath (DevicePath, &GopDevicePath);\r
802 DevicePath = GopDevicePath;\r
803\r
804 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
805\r
806 return EFI_SUCCESS;\r
807}\r
808\r
809/**\r
810 Add PCI Serial to ConOut, ConIn, ErrOut.\r
811\r
812 @param[in] DeviceHandle Handle of the PCI serial device.\r
813\r
814 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,\r
815 ErrOut.\r
816\r
817 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
818 from DeviceHandle.\r
819**/\r
820EFI_STATUS\r
821PreparePciSerialDevicePath (\r
ac0a286f 822 IN EFI_HANDLE DeviceHandle\r
656419f9
RC
823 )\r
824{\r
825 EFI_STATUS Status;\r
826 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
827\r
828 DevicePath = NULL;\r
ac0a286f
MK
829 Status = gBS->HandleProtocol (\r
830 DeviceHandle,\r
831 &gEfiDevicePathProtocolGuid,\r
832 (VOID *)&DevicePath\r
833 );\r
656419f9
RC
834 if (EFI_ERROR (Status)) {\r
835 return Status;\r
836 }\r
837\r
ac0a286f
MK
838 DevicePath = AppendDevicePathNode (\r
839 DevicePath,\r
840 (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode\r
841 );\r
842 DevicePath = AppendDevicePathNode (\r
843 DevicePath,\r
844 (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode\r
845 );\r
656419f9
RC
846\r
847 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
848 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
849 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
850\r
851 return EFI_SUCCESS;\r
852}\r
853\r
854EFI_STATUS\r
855VisitAllInstancesOfProtocol (\r
856 IN EFI_GUID *Id,\r
857 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
858 IN VOID *Context\r
859 )\r
860{\r
ac0a286f
MK
861 EFI_STATUS Status;\r
862 UINTN HandleCount;\r
863 EFI_HANDLE *HandleBuffer;\r
864 UINTN Index;\r
865 VOID *Instance;\r
656419f9
RC
866\r
867 //\r
868 // Start to check all the PciIo to find all possible device\r
869 //\r
ac0a286f 870 HandleCount = 0;\r
656419f9 871 HandleBuffer = NULL;\r
ac0a286f
MK
872 Status = gBS->LocateHandleBuffer (\r
873 ByProtocol,\r
874 Id,\r
875 NULL,\r
876 &HandleCount,\r
877 &HandleBuffer\r
878 );\r
656419f9
RC
879 if (EFI_ERROR (Status)) {\r
880 return Status;\r
881 }\r
882\r
883 for (Index = 0; Index < HandleCount; Index++) {\r
884 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);\r
885 if (EFI_ERROR (Status)) {\r
886 continue;\r
887 }\r
888\r
ac0a286f
MK
889 Status = (*CallBackFunction)(\r
890 HandleBuffer[Index],\r
891 Instance,\r
892 Context\r
893 );\r
656419f9
RC
894 }\r
895\r
896 gBS->FreePool (HandleBuffer);\r
897\r
898 return EFI_SUCCESS;\r
899}\r
900\r
656419f9
RC
901EFI_STATUS\r
902EFIAPI\r
903VisitingAPciInstance (\r
904 IN EFI_HANDLE Handle,\r
905 IN VOID *Instance,\r
906 IN VOID *Context\r
907 )\r
908{\r
ac0a286f
MK
909 EFI_STATUS Status;\r
910 EFI_PCI_IO_PROTOCOL *PciIo;\r
911 PCI_TYPE00 Pci;\r
656419f9 912\r
ac0a286f 913 PciIo = (EFI_PCI_IO_PROTOCOL *)Instance;\r
656419f9
RC
914\r
915 //\r
916 // Check for all PCI device\r
917 //\r
918 Status = PciIo->Pci.Read (\r
ac0a286f
MK
919 PciIo,\r
920 EfiPciIoWidthUint32,\r
921 0,\r
922 sizeof (Pci) / sizeof (UINT32),\r
923 &Pci\r
924 );\r
656419f9
RC
925 if (EFI_ERROR (Status)) {\r
926 return Status;\r
927 }\r
928\r
ac0a286f
MK
929 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN)Context)(\r
930 Handle,\r
931 PciIo,\r
932 &Pci\r
933 );\r
656419f9
RC
934}\r
935\r
656419f9
RC
936EFI_STATUS\r
937VisitAllPciInstances (\r
ac0a286f 938 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
656419f9
RC
939 )\r
940{\r
941 return VisitAllInstancesOfProtocol (\r
942 &gEfiPciIoProtocolGuid,\r
943 VisitingAPciInstance,\r
ac0a286f 944 (VOID *)(UINTN)CallBackFunction\r
656419f9
RC
945 );\r
946}\r
947\r
656419f9
RC
948/**\r
949 Do platform specific PCI Device check and add them to\r
950 ConOut, ConIn, ErrOut.\r
951\r
952 @param[in] Handle - Handle of PCI device instance\r
953 @param[in] PciIo - PCI IO protocol instance\r
954 @param[in] Pci - PCI Header register block\r
955\r
956 @retval EFI_SUCCESS - PCI Device check and Console variable update\r
957 successfully.\r
958 @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
959\r
960**/\r
961EFI_STATUS\r
962EFIAPI\r
963DetectAndPreparePlatformPciDevicePath (\r
964 IN EFI_HANDLE Handle,\r
965 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
966 IN PCI_TYPE00 *Pci\r
967 )\r
968{\r
ac0a286f 969 EFI_STATUS Status;\r
656419f9
RC
970\r
971 Status = PciIo->Attributes (\r
ac0a286f
MK
972 PciIo,\r
973 EfiPciIoAttributeOperationEnable,\r
974 EFI_PCI_DEVICE_ENABLE,\r
975 NULL\r
976 );\r
656419f9
RC
977 ASSERT_EFI_ERROR (Status);\r
978\r
979 //\r
980 // Here we decide whether it is LPC Bridge\r
981 //\r
982 if ((IS_PCI_LPC (Pci)) ||\r
983 ((IS_PCI_ISA_PDECODE (Pci)) &&\r
984 (Pci->Hdr.VendorId == 0x8086) &&\r
985 (Pci->Hdr.DeviceId == 0x7000)\r
986 )\r
ac0a286f
MK
987 )\r
988 {\r
656419f9
RC
989 //\r
990 // Add IsaKeyboard to ConIn,\r
991 // add IsaSerial to ConOut, ConIn, ErrOut\r
992 //\r
993 DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));\r
994 PrepareLpcBridgeDevicePath (Handle);\r
995 return EFI_SUCCESS;\r
996 }\r
ac0a286f 997\r
656419f9
RC
998 //\r
999 // Here we decide which Serial device to enable in PCI bus\r
1000 //\r
1001 if (IS_PCI_16550SERIAL (Pci)) {\r
1002 //\r
1003 // Add them to ConOut, ConIn, ErrOut.\r
1004 //\r
1005 DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));\r
1006 PreparePciSerialDevicePath (Handle);\r
1007 return EFI_SUCCESS;\r
1008 }\r
1009\r
1010 //\r
1011 // Here we decide which display device to enable in PCI bus\r
1012 //\r
1013 if (IS_PCI_DISPLAY (Pci)) {\r
1014 //\r
1015 // Add them to ConOut.\r
1016 //\r
1017 DEBUG ((DEBUG_INFO, "Found PCI display device\n"));\r
1018 PreparePciDisplayDevicePath (Handle);\r
1019 return EFI_SUCCESS;\r
1020 }\r
1021\r
1022 return Status;\r
1023}\r
1024\r
656419f9
RC
1025/**\r
1026 Connect the predefined platform default console device.\r
1027\r
1028 Always try to find and enable PCI display devices.\r
1029\r
1030 @param[in] PlatformConsole Predefined platform default console device array.\r
1031**/\r
1032VOID\r
1033PlatformInitializeConsole (\r
ac0a286f 1034 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
656419f9
RC
1035 )\r
1036{\r
ac0a286f 1037 UINTN Index;\r
656419f9
RC
1038\r
1039 //\r
1040 // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
1041 // ErrOut\r
1042 //\r
1043 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);\r
1044\r
1045 //\r
1046 // Have chance to connect the platform default console,\r
1047 // the platform default console is the minimum device group\r
1048 // the platform should support\r
1049 //\r
1050 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {\r
1051 //\r
1052 // Update the console variable with the connect type\r
1053 //\r
1054 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {\r
ac0a286f
MK
1055 EfiBootManagerUpdateConsoleVariable (\r
1056 ConIn,\r
1057 PlatformConsole[Index].DevicePath,\r
1058 NULL\r
1059 );\r
656419f9 1060 }\r
ac0a286f 1061\r
656419f9 1062 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {\r
ac0a286f
MK
1063 EfiBootManagerUpdateConsoleVariable (\r
1064 ConOut,\r
1065 PlatformConsole[Index].DevicePath,\r
1066 NULL\r
1067 );\r
656419f9 1068 }\r
ac0a286f 1069\r
656419f9 1070 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {\r
ac0a286f
MK
1071 EfiBootManagerUpdateConsoleVariable (\r
1072 ErrOut,\r
1073 PlatformConsole[Index].DevicePath,\r
1074 NULL\r
1075 );\r
656419f9
RC
1076 }\r
1077 }\r
1078}\r
1079\r
656419f9
RC
1080/**\r
1081 Configure PCI Interrupt Line register for applicable devices\r
1082 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
1083\r
1084 @param[in] Handle - Handle of PCI device instance\r
1085 @param[in] PciIo - PCI IO protocol instance\r
1086 @param[in] PciHdr - PCI Header register block\r
1087\r
1088 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
1089\r
1090**/\r
1091EFI_STATUS\r
1092EFIAPI\r
1093SetPciIntLine (\r
1094 IN EFI_HANDLE Handle,\r
1095 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1096 IN PCI_TYPE00 *PciHdr\r
1097 )\r
1098{\r
1099 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1100 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1101 UINTN RootSlot;\r
1102 UINTN Idx;\r
1103 UINT8 IrqLine;\r
1104 EFI_STATUS Status;\r
1105 UINT32 RootBusNumber;\r
1106\r
1107 Status = EFI_SUCCESS;\r
1108\r
1109 if (PciHdr->Device.InterruptPin != 0) {\r
656419f9
RC
1110 DevPathNode = DevicePathFromHandle (Handle);\r
1111 ASSERT (DevPathNode != NULL);\r
1112 DevPath = DevPathNode;\r
1113\r
1114 RootBusNumber = 0;\r
ac0a286f
MK
1115 if ((DevicePathType (DevPathNode) == ACPI_DEVICE_PATH) &&\r
1116 (DevicePathSubType (DevPathNode) == ACPI_DP) &&\r
1117 (((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID (0x0A03)))\r
1118 {\r
656419f9
RC
1119 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;\r
1120 }\r
1121\r
1122 //\r
1123 // Compute index into PciHostIrqs[] table by walking\r
1124 // the device path and adding up all device numbers\r
1125 //\r
ac0a286f 1126 Status = EFI_NOT_FOUND;\r
656419f9 1127 RootSlot = 0;\r
ac0a286f 1128 Idx = PciHdr->Device.InterruptPin - 1;\r
656419f9 1129 while (!IsDevicePathEnd (DevPathNode)) {\r
ac0a286f
MK
1130 if ((DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH) &&\r
1131 (DevicePathSubType (DevPathNode) == HW_PCI_DP))\r
1132 {\r
656419f9
RC
1133 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1134\r
1135 //\r
1136 // Unlike SeaBIOS, which starts climbing from the leaf device\r
1137 // up toward the root, we traverse the device path starting at\r
1138 // the root moving toward the leaf node.\r
1139 // The slot number of the top-level parent bridge is needed for\r
1140 // Q35 cases with more than 24 slots on the root bus.\r
1141 //\r
1142 if (Status != EFI_SUCCESS) {\r
ac0a286f 1143 Status = EFI_SUCCESS;\r
656419f9
RC
1144 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
1145 }\r
1146 }\r
1147\r
1148 DevPathNode = NextDevicePathNode (DevPathNode);\r
1149 }\r
ac0a286f 1150\r
656419f9
RC
1151 if (EFI_ERROR (Status)) {\r
1152 return Status;\r
1153 }\r
ac0a286f
MK
1154\r
1155 if ((RootBusNumber == 0) && (RootSlot == 0)) {\r
1156 DEBUG ((\r
656419f9
RC
1157 DEBUG_ERROR,\r
1158 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
1159 __FUNCTION__\r
1160 ));\r
1161 ASSERT (FALSE);\r
1162 }\r
1163\r
1164 //\r
1165 // Final PciHostIrqs[] index calculation depends on the platform\r
1166 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
1167 //\r
1168 switch (mHostBridgeDevId) {\r
02967794
RC
1169 case 0x7432: // BHYVE (AMD hostbridge)\r
1170 case 0x1275: // BHYVE (Intel hostbridge)\r
656419f9
RC
1171 case INTEL_82441_DEVICE_ID:\r
1172 Idx -= 1;\r
1173 break;\r
1174 case INTEL_Q35_MCH_DEVICE_ID:\r
1175 //\r
1176 // SeaBIOS contains the following comment:\r
1177 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
1178 // with a different starting index - see q35-acpi-dsdt.dsl.\r
1179 //\r
1180 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
1181 //\r
1182 if (RootSlot > 24) {\r
1183 //\r
1184 // in this case, subtract back out RootSlot from Idx\r
1185 // (SeaBIOS never adds it to begin with, but that would make our\r
1186 // device path traversal loop above too awkward)\r
1187 //\r
1188 Idx -= RootSlot;\r
1189 }\r
ac0a286f 1190\r
656419f9
RC
1191 break;\r
1192 default:\r
1193 ASSERT (FALSE); // should never get here\r
1194 }\r
ac0a286f
MK
1195\r
1196 Idx %= ARRAY_SIZE (PciHostIrqs);\r
656419f9
RC
1197 IrqLine = PciHostIrqs[Idx];\r
1198\r
1199 DEBUG_CODE_BEGIN ();\r
1200 {\r
ac0a286f
MK
1201 CHAR16 *DevPathString;\r
1202 STATIC CHAR16 Fallback[] = L"<failed to convert>";\r
1203 UINTN Segment, Bus, Device, Function;\r
656419f9
RC
1204\r
1205 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);\r
1206 if (DevPathString == NULL) {\r
1207 DevPathString = Fallback;\r
1208 }\r
ac0a286f 1209\r
656419f9
RC
1210 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);\r
1211 ASSERT_EFI_ERROR (Status);\r
1212\r
ac0a286f
MK
1213 DEBUG ((\r
1214 DEBUG_VERBOSE,\r
1215 "%a: [%02x:%02x.%x] %s -> 0x%02x\n",\r
1216 __FUNCTION__,\r
1217 (UINT32)Bus,\r
1218 (UINT32)Device,\r
1219 (UINT32)Function,\r
1220 DevPathString,\r
1221 IrqLine\r
1222 ));\r
656419f9
RC
1223\r
1224 if (DevPathString != Fallback) {\r
1225 FreePool (DevPathString);\r
1226 }\r
1227 }\r
1228 DEBUG_CODE_END ();\r
1229\r
1230 //\r
1231 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
1232 //\r
1233 Status = PciIo->Pci.Write (\r
ac0a286f
MK
1234 PciIo,\r
1235 EfiPciIoWidthUint8,\r
1236 PCI_INT_LINE_OFFSET,\r
1237 1,\r
1238 &IrqLine\r
1239 );\r
656419f9
RC
1240 }\r
1241\r
1242 return Status;\r
1243}\r
1244\r
656419f9
RC
1245VOID\r
1246PciAcpiInitialization (\r
1247 )\r
1248{\r
1249 UINTN Pmba;\r
1250\r
1251 //\r
1252 // Query Host Bridge DID to determine platform type\r
1253 //\r
1254 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
1255 switch (mHostBridgeDevId) {\r
02967794
RC
1256 case 0x7432: // BHYVE (AMD hostbridge)\r
1257 case 0x1275: // BHYVE (Intel hostbridge)\r
656419f9
RC
1258 case INTEL_82441_DEVICE_ID:\r
1259 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
1260 //\r
1261 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets\r
1262 //\r
1263 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A\r
1264 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B\r
1265 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C\r
1266 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D\r
1267 break;\r
1268 case INTEL_Q35_MCH_DEVICE_ID:\r
1269 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
1270 //\r
1271 // 00:1f.0 LPC Bridge (Q35) LNK routing targets\r
1272 //\r
1273 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A\r
1274 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B\r
1275 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C\r
1276 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D\r
1277 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E\r
1278 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F\r
1279 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G\r
1280 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H\r
1281 break;\r
1282 default:\r
ac0a286f
MK
1283 DEBUG ((\r
1284 DEBUG_ERROR,\r
1285 "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
1286 __FUNCTION__,\r
1287 mHostBridgeDevId\r
1288 ));\r
656419f9
RC
1289 ASSERT (FALSE);\r
1290 return;\r
1291 }\r
1292\r
1293 //\r
1294 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
1295 //\r
1296 VisitAllPciInstances (SetPciIntLine);\r
1297\r
1298 //\r
1299 // Set ACPI SCI_EN bit in PMCNTRL\r
1300 //\r
1301 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
1302}\r
1303\r
1304EFI_STATUS\r
1305EFIAPI\r
1306ConnectRecursivelyIfPciMassStorage (\r
1307 IN EFI_HANDLE Handle,\r
1308 IN EFI_PCI_IO_PROTOCOL *Instance,\r
1309 IN PCI_TYPE00 *PciHeader\r
1310 )\r
1311{\r
1312 EFI_STATUS Status;\r
1313 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1314 CHAR16 *DevPathStr;\r
1315\r
1316 //\r
1317 // Recognize PCI Mass Storage, and Xen PCI devices\r
1318 //\r
1319 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {\r
1320 DevicePath = NULL;\r
ac0a286f
MK
1321 Status = gBS->HandleProtocol (\r
1322 Handle,\r
1323 &gEfiDevicePathProtocolGuid,\r
1324 (VOID *)&DevicePath\r
1325 );\r
656419f9
RC
1326 if (EFI_ERROR (Status)) {\r
1327 return Status;\r
1328 }\r
1329\r
1330 //\r
1331 // Print Device Path\r
1332 //\r
1333 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
1334 if (DevPathStr != NULL) {\r
ac0a286f 1335 DEBUG ((\r
656419f9
RC
1336 DEBUG_INFO,\r
1337 "Found %s device: %s\n",\r
1338 (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ?\r
1339 L"Mass Storage" :\r
1340 L"Xen"\r
ac0a286f 1341 ),\r
656419f9
RC
1342 DevPathStr\r
1343 ));\r
ac0a286f 1344 FreePool (DevPathStr);\r
656419f9
RC
1345 }\r
1346\r
1347 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1348 if (EFI_ERROR (Status)) {\r
1349 return Status;\r
1350 }\r
656419f9
RC
1351 }\r
1352\r
1353 return EFI_SUCCESS;\r
1354}\r
1355\r
656419f9
RC
1356/**\r
1357 This notification function is invoked when the\r
1358 EMU Variable FVB has been changed.\r
1359\r
1360 @param Event The event that occurred\r
1361 @param Context For EFI compatibility. Not used.\r
1362\r
1363**/\r
1364VOID\r
1365EFIAPI\r
1366EmuVariablesUpdatedCallback (\r
ac0a286f
MK
1367 IN EFI_EVENT Event,\r
1368 IN VOID *Context\r
656419f9
RC
1369 )\r
1370{\r
1371 DEBUG ((DEBUG_INFO, "EmuVariablesUpdatedCallback\n"));\r
1372 UpdateNvVarsOnFileSystem ();\r
1373}\r
1374\r
656419f9
RC
1375EFI_STATUS\r
1376EFIAPI\r
1377VisitingFileSystemInstance (\r
1378 IN EFI_HANDLE Handle,\r
1379 IN VOID *Instance,\r
1380 IN VOID *Context\r
1381 )\r
1382{\r
1383 EFI_STATUS Status;\r
1384 STATIC BOOLEAN ConnectedToFileSystem = FALSE;\r
1385 RETURN_STATUS PcdStatus;\r
1386\r
1387 if (ConnectedToFileSystem) {\r
1388 return EFI_ALREADY_STARTED;\r
1389 }\r
1390\r
1391 Status = ConnectNvVarsToFileSystem (Handle);\r
1392 if (EFI_ERROR (Status)) {\r
1393 return Status;\r
1394 }\r
1395\r
1396 ConnectedToFileSystem = TRUE;\r
ac0a286f 1397 mEmuVariableEvent =\r
656419f9
RC
1398 EfiCreateProtocolNotifyEvent (\r
1399 &gEfiDevicePathProtocolGuid,\r
1400 TPL_CALLBACK,\r
1401 EmuVariablesUpdatedCallback,\r
1402 NULL,\r
1403 &mEmuVariableEventReg\r
1404 );\r
ac0a286f
MK
1405 PcdStatus = PcdSet64S (\r
1406 PcdEmuVariableEvent,\r
1407 (UINT64)(UINTN)mEmuVariableEvent\r
1408 );\r
656419f9
RC
1409 ASSERT_RETURN_ERROR (PcdStatus);\r
1410\r
1411 return EFI_SUCCESS;\r
1412}\r
1413\r
656419f9
RC
1414VOID\r
1415PlatformBdsRestoreNvVarsFromHardDisk (\r
1416 )\r
1417{\r
1418 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);\r
1419 VisitAllInstancesOfProtocol (\r
1420 &gEfiSimpleFileSystemProtocolGuid,\r
1421 VisitingFileSystemInstance,\r
1422 NULL\r
1423 );\r
656419f9
RC
1424}\r
1425\r
1426/**\r
1427 Connect with predefined platform connect sequence.\r
1428\r
1429 The OEM/IBV can customize with their own connect sequence.\r
1430**/\r
1431VOID\r
1432PlatformBdsConnectSequence (\r
1433 VOID\r
1434 )\r
1435{\r
ac0a286f 1436 UINTN Index;\r
656419f9
RC
1437\r
1438 DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));\r
1439\r
1440 Index = 0;\r
1441\r
1442 //\r
1443 // Here we can get the customized platform connect sequence\r
1444 // Notes: we can connect with new variable which record the\r
1445 // last time boots connect device path sequence\r
1446 //\r
1447 while (gPlatformConnectSequence[Index] != NULL) {\r
1448 //\r
1449 // Build the platform boot option\r
1450 //\r
1451 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
1452 Index++;\r
1453 }\r
1454\r
1455 //\r
1456 // Just use the simple policy to connect all devices\r
1457 //\r
1458 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));\r
1459 EfiBootManagerConnectAll ();\r
1460}\r
1461\r
1462/**\r
1463 Save the S3 boot script.\r
1464\r
1465 Note that DxeSmmReadyToLock must be signaled after this function returns;\r
1466 otherwise the script wouldn't be saved actually.\r
1467**/\r
ac0a286f
MK
1468#if defined (__GNUC__)\r
1469__attribute__ ((unused))\r
656419f9
RC
1470#endif\r
1471STATIC\r
1472VOID\r
1473SaveS3BootScript (\r
1474 VOID\r
1475 )\r
1476{\r
ac0a286f
MK
1477 EFI_STATUS Status;\r
1478 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;\r
1479 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };\r
656419f9 1480\r
ac0a286f
MK
1481 Status = gBS->LocateProtocol (\r
1482 &gEfiS3SaveStateProtocolGuid,\r
1483 NULL,\r
1484 (VOID **)&BootScript\r
1485 );\r
656419f9
RC
1486 ASSERT_EFI_ERROR (Status);\r
1487\r
1488 //\r
1489 // Despite the opcode documentation in the PI spec, the protocol\r
1490 // implementation embeds a deep copy of the info in the boot script, rather\r
1491 // than storing just a pointer to runtime or NVS storage.\r
1492 //\r
ac0a286f
MK
1493 Status = BootScript->Write (\r
1494 BootScript,\r
1495 EFI_BOOT_SCRIPT_INFORMATION_OPCODE,\r
1496 (UINT32)sizeof Info,\r
1497 (EFI_PHYSICAL_ADDRESS)(UINTN)&Info\r
1498 );\r
656419f9
RC
1499 ASSERT_EFI_ERROR (Status);\r
1500}\r
1501\r
656419f9
RC
1502/**\r
1503 Do the platform specific action after the console is ready\r
1504\r
1505 Possible things that can be done in PlatformBootManagerAfterConsole:\r
1506\r
1507 > Console post action:\r
1508 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
1509 > Signal console ready platform customized event\r
1510 > Run diagnostics like memory testing\r
1511 > Connect certain devices\r
1512 > Dispatch aditional option roms\r
1513 > Special boot: e.g.: USB boot, enter UI\r
1514**/\r
1515VOID\r
1516EFIAPI\r
1517PlatformBootManagerAfterConsole (\r
1518 VOID\r
1519 )\r
1520{\r
ac0a286f 1521 EFI_BOOT_MODE BootMode;\r
656419f9
RC
1522\r
1523 DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));\r
1524\r
1525 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {\r
ac0a286f
MK
1526 DEBUG ((\r
1527 DEBUG_INFO,\r
1528 "PlatformBdsPolicyBehavior: not restoring NvVars "\r
1529 "from disk since flash variables appear to be supported.\n"\r
1530 ));\r
656419f9
RC
1531 } else {\r
1532 //\r
1533 // Try to restore variables from the hard disk early so\r
1534 // they can be used for the other BDS connect operations.\r
1535 //\r
ac0a286f 1536\r
656419f9
RC
1537 /* XXX Calling this causes Keyboard to be removed from ConIn which\r
1538 results in unresponsive guest boot loaders in the GUI. Restore it\r
1539 when we figure out what is needed to get NvVars storage done\r
1540 properly.\r
1541 */\r
1542 /*PlatformBdsRestoreNvVarsFromHardDisk ();*/\r
1543 }\r
1544\r
1545 //\r
1546 // Get current Boot Mode\r
1547 //\r
1548 BootMode = GetBootModeHob ();\r
1549 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
1550\r
1551 //\r
1552 // Go the different platform policy with different boot mode\r
1553 // Notes: this part code can be change with the table policy\r
1554 //\r
1555 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
1556\r
1557 //\r
1558 // Logo show\r
1559 //\r
1560 BootLogoEnableLogo ();\r
1561\r
1562 //\r
1563 // Set PCI Interrupt Line registers and ACPI SCI_EN\r
1564 //\r
1565 PciAcpiInitialization ();\r
1566\r
656419f9
RC
1567 //\r
1568 // Perform some platform specific connect sequence\r
1569 //\r
1570 PlatformBdsConnectSequence ();\r
1571\r
1572 EfiBootManagerRefreshAllBootOption ();\r
1573\r
1574 //\r
1575 // Register UEFI Shell\r
1576 //\r
1577 PlatformRegisterFvBootOption (\r
ac0a286f
MK
1578 &gUefiShellFileGuid,\r
1579 L"EFI Internal Shell",\r
1580 LOAD_OPTION_ACTIVE\r
656419f9
RC
1581 );\r
1582\r
1583 RemoveStaleFvFileOptions ();\r
1584\r
1585 PlatformBmPrintScRegisterHandler ();\r
1586}\r
1587\r
1588/**\r
1589 This notification function is invoked when an instance of the\r
1590 EFI_DEVICE_PATH_PROTOCOL is produced.\r
1591\r
1592 @param Event The event that occurred\r
1593 @param Context For EFI compatibility. Not used.\r
1594\r
1595**/\r
1596VOID\r
1597EFIAPI\r
1598NotifyDevPath (\r
ac0a286f
MK
1599 IN EFI_EVENT Event,\r
1600 IN VOID *Context\r
656419f9
RC
1601 )\r
1602{\r
ac0a286f
MK
1603 EFI_HANDLE Handle;\r
1604 EFI_STATUS Status;\r
1605 UINTN BufferSize;\r
1606 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
1607 ATAPI_DEVICE_PATH *Atapi;\r
656419f9
RC
1608\r
1609 //\r
1610 // Examine all new handles\r
1611 //\r
ac0a286f 1612 for ( ; ;) {\r
656419f9
RC
1613 //\r
1614 // Get the next handle\r
1615 //\r
1616 BufferSize = sizeof (Handle);\r
ac0a286f
MK
1617 Status = gBS->LocateHandle (\r
1618 ByRegisterNotify,\r
1619 NULL,\r
1620 mEfiDevPathNotifyReg,\r
1621 &BufferSize,\r
1622 &Handle\r
1623 );\r
656419f9
RC
1624\r
1625 //\r
1626 // If not found, we're done\r
1627 //\r
1628 if (EFI_NOT_FOUND == Status) {\r
1629 break;\r
1630 }\r
1631\r
1632 if (EFI_ERROR (Status)) {\r
1633 continue;\r
1634 }\r
1635\r
1636 //\r
1637 // Get the DevicePath protocol on that handle\r
1638 //\r
ac0a286f
MK
1639 Status = gBS->HandleProtocol (\r
1640 Handle,\r
1641 &gEfiDevicePathProtocolGuid,\r
1642 (VOID **)&DevPathNode\r
1643 );\r
656419f9
RC
1644 ASSERT_EFI_ERROR (Status);\r
1645\r
1646 while (!IsDevicePathEnd (DevPathNode)) {\r
1647 //\r
1648 // Find the handler to dump this device path node\r
1649 //\r
1650 if (\r
ac0a286f
MK
1651 (DevicePathType (DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
1652 (DevicePathSubType (DevPathNode) == MSG_ATAPI_DP)\r
1653 )\r
1654 {\r
1655 Atapi = (ATAPI_DEVICE_PATH *)DevPathNode;\r
656419f9
RC
1656 PciOr16 (\r
1657 PCI_LIB_ADDRESS (\r
1658 0,\r
1659 1,\r
1660 1,\r
ac0a286f 1661 (Atapi->PrimarySecondary == 1) ? 0x42 : 0x40\r
656419f9
RC
1662 ),\r
1663 BIT15\r
1664 );\r
1665 }\r
1666\r
1667 //\r
1668 // Next device path node\r
1669 //\r
1670 DevPathNode = NextDevicePathNode (DevPathNode);\r
1671 }\r
1672 }\r
1673\r
1674 return;\r
1675}\r
1676\r
656419f9
RC
1677VOID\r
1678InstallDevicePathCallback (\r
1679 VOID\r
1680 )\r
1681{\r
1682 DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));\r
1683 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
ac0a286f
MK
1684 &gEfiDevicePathProtocolGuid,\r
1685 TPL_CALLBACK,\r
1686 NotifyDevPath,\r
1687 NULL,\r
1688 &mEfiDevPathNotifyReg\r
1689 );\r
656419f9
RC
1690}\r
1691\r
1692/**\r
1693 This function is called each second during the boot manager waits the\r
1694 timeout.\r
1695\r
1696 @param TimeoutRemain The remaining timeout.\r
1697**/\r
1698VOID\r
1699EFIAPI\r
1700PlatformBootManagerWaitCallback (\r
ac0a286f 1701 UINT16 TimeoutRemain\r
656419f9
RC
1702 )\r
1703{\r
ac0a286f
MK
1704 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;\r
1705 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;\r
1706 UINT16 Timeout;\r
656419f9
RC
1707\r
1708 Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
1709\r
1710 Black.Raw = 0x00000000;\r
1711 White.Raw = 0x00FFFFFF;\r
1712\r
1713 BootLogoUpdateProgress (\r
1714 White.Pixel,\r
1715 Black.Pixel,\r
1716 L"Start boot option",\r
1717 White.Pixel,\r
1718 (Timeout - TimeoutRemain) * 100 / Timeout,\r
1719 0\r
1720 );\r
1721}\r
1722\r
1723/**\r
1724 The function is called when no boot option could be launched,\r
1725 including platform recovery options and options pointing to applications\r
1726 built into firmware volumes.\r
1727\r
1728 If this function returns, BDS attempts to enter an infinite loop.\r
1729**/\r
1730VOID\r
1731EFIAPI\r
1732PlatformBootManagerUnableToBoot (\r
1733 VOID\r
1734 )\r
1735{\r
ac0a286f
MK
1736 EFI_STATUS Status;\r
1737 EFI_INPUT_KEY Key;\r
1738 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
1739 UINTN Index;\r
656419f9
RC
1740\r
1741 //\r
1742 // BootManagerMenu doesn't contain the correct information when return status\r
1743 // is EFI_NOT_FOUND.\r
1744 //\r
1745 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1746 if (EFI_ERROR (Status)) {\r
1747 return;\r
1748 }\r
ac0a286f 1749\r
656419f9
RC
1750 //\r
1751 // Normally BdsDxe does not print anything to the system console, but this is\r
1752 // a last resort -- the end-user will likely not see any DEBUG messages\r
1753 // logged in this situation.\r
1754 //\r
1755 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn\r
1756 // here to see if it makes sense to request and wait for a keypress.\r
1757 //\r
1758 if (gST->ConIn != NULL) {\r
1759 AsciiPrint (\r
1760 "%a: No bootable option or device was found.\n"\r
1761 "%a: Press any key to enter the Boot Manager Menu.\n",\r
1762 gEfiCallerBaseName,\r
1763 gEfiCallerBaseName\r
1764 );\r
1765 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
1766 ASSERT_EFI_ERROR (Status);\r
1767 ASSERT (Index == 0);\r
1768\r
1769 //\r
1770 // Drain any queued keys.\r
1771 //\r
1772 while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {\r
1773 //\r
1774 // just throw away Key\r
1775 //\r
1776 }\r
1777 }\r
1778\r
ac0a286f 1779 for ( ; ;) {\r
656419f9
RC
1780 EfiBootManagerBoot (&BootManagerMenu);\r
1781 }\r
1782}\r