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