PlatformBm.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. /** @file
  2. Implementation for PlatformBootManagerLib library class interfaces.
  3. Copyright (C) 2015-2016, Red Hat, Inc.
  4. Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
  5. Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. #include <IndustryStandard/Pci22.h>
  9. #include <IndustryStandard/Virtio095.h>
  10. #include <Library/BootLogoLib.h>
  11. #include <Library/DevicePathLib.h>
  12. #include <Library/PcdLib.h>
  13. #include <Library/PlatformBmPrintScLib.h>
  14. #include <Library/QemuBootOrderLib.h>
  15. #include <Library/TpmPlatformHierarchyLib.h>
  16. #include <Library/UefiBootManagerLib.h>
  17. #include <Protocol/DevicePath.h>
  18. #include <Protocol/FirmwareVolume2.h>
  19. #include <Protocol/GraphicsOutput.h>
  20. #include <Protocol/LoadedImage.h>
  21. #include <Protocol/PciIo.h>
  22. #include <Protocol/PciRootBridgeIo.h>
  23. #include <Protocol/VirtioDevice.h>
  24. #include <Guid/EventGroup.h>
  25. #include <Guid/GlobalVariable.h>
  26. #include <Guid/RootBridgesConnectedEventGroup.h>
  27. #include <Guid/SerialPortLibVendor.h>
  28. #include "PlatformBm.h"
  29. #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
  30. #pragma pack (1)
  31. typedef struct {
  32. VENDOR_DEVICE_PATH SerialDxe;
  33. UART_DEVICE_PATH Uart;
  34. VENDOR_DEFINED_DEVICE_PATH TermType;
  35. EFI_DEVICE_PATH_PROTOCOL End;
  36. } PLATFORM_SERIAL_CONSOLE;
  37. #pragma pack ()
  38. STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
  39. //
  40. // VENDOR_DEVICE_PATH SerialDxe
  41. //
  42. {
  43. { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
  44. EDKII_SERIAL_PORT_LIB_VENDOR_GUID
  45. },
  46. //
  47. // UART_DEVICE_PATH Uart
  48. //
  49. {
  50. { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
  51. 0, // Reserved
  52. FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
  53. FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
  54. FixedPcdGet8 (PcdUartDefaultParity), // Parity
  55. FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
  56. },
  57. //
  58. // VENDOR_DEFINED_DEVICE_PATH TermType
  59. //
  60. {
  61. {
  62. MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
  63. DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
  64. }
  65. //
  66. // Guid to be filled in dynamically
  67. //
  68. },
  69. //
  70. // EFI_DEVICE_PATH_PROTOCOL End
  71. //
  72. {
  73. END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
  74. DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
  75. }
  76. };
  77. #pragma pack (1)
  78. typedef struct {
  79. USB_CLASS_DEVICE_PATH Keyboard;
  80. EFI_DEVICE_PATH_PROTOCOL End;
  81. } PLATFORM_USB_KEYBOARD;
  82. #pragma pack ()
  83. STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
  84. //
  85. // USB_CLASS_DEVICE_PATH Keyboard
  86. //
  87. {
  88. {
  89. MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
  90. DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
  91. },
  92. 0xFFFF, // VendorId: any
  93. 0xFFFF, // ProductId: any
  94. 3, // DeviceClass: HID
  95. 1, // DeviceSubClass: boot
  96. 1 // DeviceProtocol: keyboard
  97. },
  98. //
  99. // EFI_DEVICE_PATH_PROTOCOL End
  100. //
  101. {
  102. END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
  103. DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
  104. }
  105. };
  106. /**
  107. Check if the handle satisfies a particular condition.
  108. @param[in] Handle The handle to check.
  109. @param[in] ReportText A caller-allocated string passed in for reporting
  110. purposes. It must never be NULL.
  111. @retval TRUE The condition is satisfied.
  112. @retval FALSE Otherwise. This includes the case when the condition could not
  113. be fully evaluated due to an error.
  114. **/
  115. typedef
  116. BOOLEAN
  117. (EFIAPI *FILTER_FUNCTION)(
  118. IN EFI_HANDLE Handle,
  119. IN CONST CHAR16 *ReportText
  120. );
  121. /**
  122. Process a handle.
  123. @param[in] Handle The handle to process.
  124. @param[in] ReportText A caller-allocated string passed in for reporting
  125. purposes. It must never be NULL.
  126. **/
  127. typedef
  128. VOID
  129. (EFIAPI *CALLBACK_FUNCTION)(
  130. IN EFI_HANDLE Handle,
  131. IN CONST CHAR16 *ReportText
  132. );
  133. /**
  134. Locate all handles that carry the specified protocol, filter them with a
  135. callback function, and pass each handle that passes the filter to another
  136. callback.
  137. @param[in] ProtocolGuid The protocol to look for.
  138. @param[in] Filter The filter function to pass each handle to. If this
  139. parameter is NULL, then all handles are processed.
  140. @param[in] Process The callback function to pass each handle to that
  141. clears the filter.
  142. **/
  143. STATIC
  144. VOID
  145. FilterAndProcess (
  146. IN EFI_GUID *ProtocolGuid,
  147. IN FILTER_FUNCTION Filter OPTIONAL,
  148. IN CALLBACK_FUNCTION Process
  149. )
  150. {
  151. EFI_STATUS Status;
  152. EFI_HANDLE *Handles;
  153. UINTN NoHandles;
  154. UINTN Idx;
  155. Status = gBS->LocateHandleBuffer (
  156. ByProtocol,
  157. ProtocolGuid,
  158. NULL /* SearchKey */,
  159. &NoHandles,
  160. &Handles
  161. );
  162. if (EFI_ERROR (Status)) {
  163. //
  164. // This is not an error, just an informative condition.
  165. //
  166. DEBUG ((
  167. DEBUG_VERBOSE,
  168. "%a: %g: %r\n",
  169. __FUNCTION__,
  170. ProtocolGuid,
  171. Status
  172. ));
  173. return;
  174. }
  175. ASSERT (NoHandles > 0);
  176. for (Idx = 0; Idx < NoHandles; ++Idx) {
  177. CHAR16 *DevicePathText;
  178. STATIC CHAR16 Fallback[] = L"<device path unavailable>";
  179. //
  180. // The ConvertDevicePathToText() function handles NULL input transparently.
  181. //
  182. DevicePathText = ConvertDevicePathToText (
  183. DevicePathFromHandle (Handles[Idx]),
  184. FALSE, // DisplayOnly
  185. FALSE // AllowShortcuts
  186. );
  187. if (DevicePathText == NULL) {
  188. DevicePathText = Fallback;
  189. }
  190. if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {
  191. Process (Handles[Idx], DevicePathText);
  192. }
  193. if (DevicePathText != Fallback) {
  194. FreePool (DevicePathText);
  195. }
  196. }
  197. gBS->FreePool (Handles);
  198. }
  199. /**
  200. This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
  201. **/
  202. STATIC
  203. BOOLEAN
  204. EFIAPI
  205. IsPciDisplay (
  206. IN EFI_HANDLE Handle,
  207. IN CONST CHAR16 *ReportText
  208. )
  209. {
  210. EFI_STATUS Status;
  211. EFI_PCI_IO_PROTOCOL *PciIo;
  212. PCI_TYPE00 Pci;
  213. Status = gBS->HandleProtocol (
  214. Handle,
  215. &gEfiPciIoProtocolGuid,
  216. (VOID **)&PciIo
  217. );
  218. if (EFI_ERROR (Status)) {
  219. //
  220. // This is not an error worth reporting.
  221. //
  222. return FALSE;
  223. }
  224. Status = PciIo->Pci.Read (
  225. PciIo,
  226. EfiPciIoWidthUint32,
  227. 0 /* Offset */,
  228. sizeof Pci / sizeof (UINT32),
  229. &Pci
  230. );
  231. if (EFI_ERROR (Status)) {
  232. DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
  233. return FALSE;
  234. }
  235. return IS_PCI_DISPLAY (&Pci);
  236. }
  237. /**
  238. This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
  239. the VIRTIO_DEVICE_PROTOCOL level.
  240. **/
  241. STATIC
  242. BOOLEAN
  243. EFIAPI
  244. IsVirtioRng (
  245. IN EFI_HANDLE Handle,
  246. IN CONST CHAR16 *ReportText
  247. )
  248. {
  249. EFI_STATUS Status;
  250. VIRTIO_DEVICE_PROTOCOL *VirtIo;
  251. Status = gBS->HandleProtocol (
  252. Handle,
  253. &gVirtioDeviceProtocolGuid,
  254. (VOID **)&VirtIo
  255. );
  256. if (EFI_ERROR (Status)) {
  257. return FALSE;
  258. }
  259. return (BOOLEAN)(VirtIo->SubSystemDeviceId ==
  260. VIRTIO_SUBSYSTEM_ENTROPY_SOURCE);
  261. }
  262. /**
  263. This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
  264. the EFI_PCI_IO_PROTOCOL level.
  265. **/
  266. STATIC
  267. BOOLEAN
  268. EFIAPI
  269. IsVirtioPciRng (
  270. IN EFI_HANDLE Handle,
  271. IN CONST CHAR16 *ReportText
  272. )
  273. {
  274. EFI_STATUS Status;
  275. EFI_PCI_IO_PROTOCOL *PciIo;
  276. UINT16 VendorId;
  277. UINT16 DeviceId;
  278. UINT8 RevisionId;
  279. BOOLEAN Virtio10;
  280. UINT16 SubsystemId;
  281. Status = gBS->HandleProtocol (
  282. Handle,
  283. &gEfiPciIoProtocolGuid,
  284. (VOID **)&PciIo
  285. );
  286. if (EFI_ERROR (Status)) {
  287. return FALSE;
  288. }
  289. //
  290. // Read and check VendorId.
  291. //
  292. Status = PciIo->Pci.Read (
  293. PciIo,
  294. EfiPciIoWidthUint16,
  295. PCI_VENDOR_ID_OFFSET,
  296. 1,
  297. &VendorId
  298. );
  299. if (EFI_ERROR (Status)) {
  300. goto PciError;
  301. }
  302. if (VendorId != VIRTIO_VENDOR_ID) {
  303. return FALSE;
  304. }
  305. //
  306. // Read DeviceId and RevisionId.
  307. //
  308. Status = PciIo->Pci.Read (
  309. PciIo,
  310. EfiPciIoWidthUint16,
  311. PCI_DEVICE_ID_OFFSET,
  312. 1,
  313. &DeviceId
  314. );
  315. if (EFI_ERROR (Status)) {
  316. goto PciError;
  317. }
  318. Status = PciIo->Pci.Read (
  319. PciIo,
  320. EfiPciIoWidthUint8,
  321. PCI_REVISION_ID_OFFSET,
  322. 1,
  323. &RevisionId
  324. );
  325. if (EFI_ERROR (Status)) {
  326. goto PciError;
  327. }
  328. //
  329. // From DeviceId and RevisionId, determine whether the device is a
  330. // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
  331. // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
  332. // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
  333. // only be sanity-checked, and SubsystemId will decide.
  334. //
  335. if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
  336. (RevisionId >= 0x01))
  337. {
  338. Virtio10 = TRUE;
  339. } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
  340. Virtio10 = FALSE;
  341. } else {
  342. return FALSE;
  343. }
  344. //
  345. // Read and check SubsystemId as dictated by Virtio10.
  346. //
  347. Status = PciIo->Pci.Read (
  348. PciIo,
  349. EfiPciIoWidthUint16,
  350. PCI_SUBSYSTEM_ID_OFFSET,
  351. 1,
  352. &SubsystemId
  353. );
  354. if (EFI_ERROR (Status)) {
  355. goto PciError;
  356. }
  357. if (Virtio10 && (SubsystemId >= 0x40)) {
  358. return TRUE;
  359. }
  360. if (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
  361. return TRUE;
  362. }
  363. return FALSE;
  364. PciError:
  365. DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
  366. return FALSE;
  367. }
  368. /**
  369. This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
  370. the matching driver to produce all first-level child handles.
  371. **/
  372. STATIC
  373. VOID
  374. EFIAPI
  375. Connect (
  376. IN EFI_HANDLE Handle,
  377. IN CONST CHAR16 *ReportText
  378. )
  379. {
  380. EFI_STATUS Status;
  381. Status = gBS->ConnectController (
  382. Handle, // ControllerHandle
  383. NULL, // DriverImageHandle
  384. NULL, // RemainingDevicePath -- produce all children
  385. FALSE // Recursive
  386. );
  387. DEBUG ((
  388. EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
  389. "%a: %s: %r\n",
  390. __FUNCTION__,
  391. ReportText,
  392. Status
  393. ));
  394. }
  395. /**
  396. This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
  397. handle, and adds it to ConOut and ErrOut.
  398. **/
  399. STATIC
  400. VOID
  401. EFIAPI
  402. AddOutput (
  403. IN EFI_HANDLE Handle,
  404. IN CONST CHAR16 *ReportText
  405. )
  406. {
  407. EFI_STATUS Status;
  408. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  409. DevicePath = DevicePathFromHandle (Handle);
  410. if (DevicePath == NULL) {
  411. DEBUG ((
  412. DEBUG_ERROR,
  413. "%a: %s: handle %p: device path not found\n",
  414. __FUNCTION__,
  415. ReportText,
  416. Handle
  417. ));
  418. return;
  419. }
  420. Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
  421. if (EFI_ERROR (Status)) {
  422. DEBUG ((
  423. DEBUG_ERROR,
  424. "%a: %s: adding to ConOut: %r\n",
  425. __FUNCTION__,
  426. ReportText,
  427. Status
  428. ));
  429. return;
  430. }
  431. Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
  432. if (EFI_ERROR (Status)) {
  433. DEBUG ((
  434. DEBUG_ERROR,
  435. "%a: %s: adding to ErrOut: %r\n",
  436. __FUNCTION__,
  437. ReportText,
  438. Status
  439. ));
  440. return;
  441. }
  442. DEBUG ((
  443. DEBUG_VERBOSE,
  444. "%a: %s: added to ConOut and ErrOut\n",
  445. __FUNCTION__,
  446. ReportText
  447. ));
  448. }
  449. STATIC
  450. VOID
  451. PlatformRegisterFvBootOption (
  452. EFI_GUID *FileGuid,
  453. CHAR16 *Description,
  454. UINT32 Attributes
  455. )
  456. {
  457. EFI_STATUS Status;
  458. INTN OptionIndex;
  459. EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
  460. EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
  461. UINTN BootOptionCount;
  462. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
  463. EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
  464. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  465. Status = gBS->HandleProtocol (
  466. gImageHandle,
  467. &gEfiLoadedImageProtocolGuid,
  468. (VOID **)&LoadedImage
  469. );
  470. ASSERT_EFI_ERROR (Status);
  471. EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
  472. DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
  473. ASSERT (DevicePath != NULL);
  474. DevicePath = AppendDevicePathNode (
  475. DevicePath,
  476. (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
  477. );
  478. ASSERT (DevicePath != NULL);
  479. Status = EfiBootManagerInitializeLoadOption (
  480. &NewOption,
  481. LoadOptionNumberUnassigned,
  482. LoadOptionTypeBoot,
  483. Attributes,
  484. Description,
  485. DevicePath,
  486. NULL,
  487. 0
  488. );
  489. ASSERT_EFI_ERROR (Status);
  490. FreePool (DevicePath);
  491. BootOptions = EfiBootManagerGetLoadOptions (
  492. &BootOptionCount,
  493. LoadOptionTypeBoot
  494. );
  495. OptionIndex = EfiBootManagerFindLoadOption (
  496. &NewOption,
  497. BootOptions,
  498. BootOptionCount
  499. );
  500. if (OptionIndex == -1) {
  501. Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
  502. ASSERT_EFI_ERROR (Status);
  503. }
  504. EfiBootManagerFreeLoadOption (&NewOption);
  505. EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
  506. }
  507. /**
  508. Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
  509. whose device paths do not resolve exactly to an FvFile in the system.
  510. This removes any boot options that point to binaries built into the firmware
  511. and have become stale due to any of the following:
  512. - FvMain's base address or size changed (historical),
  513. - FvMain's FvNameGuid changed,
  514. - the FILE_GUID of the pointed-to binary changed,
  515. - the referenced binary is no longer built into the firmware.
  516. EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
  517. avoids exact duplicates.
  518. **/
  519. STATIC
  520. VOID
  521. RemoveStaleFvFileOptions (
  522. VOID
  523. )
  524. {
  525. EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
  526. UINTN BootOptionCount;
  527. UINTN Index;
  528. BootOptions = EfiBootManagerGetLoadOptions (
  529. &BootOptionCount,
  530. LoadOptionTypeBoot
  531. );
  532. for (Index = 0; Index < BootOptionCount; ++Index) {
  533. EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
  534. EFI_STATUS Status;
  535. EFI_HANDLE FvHandle;
  536. //
  537. // If the device path starts with neither MemoryMapped(...) nor Fv(...),
  538. // then keep the boot option.
  539. //
  540. Node1 = BootOptions[Index].FilePath;
  541. if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
  542. (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
  543. !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
  544. (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
  545. {
  546. continue;
  547. }
  548. //
  549. // If the second device path node is not FvFile(...), then keep the boot
  550. // option.
  551. //
  552. Node2 = NextDevicePathNode (Node1);
  553. if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
  554. (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
  555. {
  556. continue;
  557. }
  558. //
  559. // Locate the Firmware Volume2 protocol instance that is denoted by the
  560. // boot option. If this lookup fails (i.e., the boot option references a
  561. // firmware volume that doesn't exist), then we'll proceed to delete the
  562. // boot option.
  563. //
  564. SearchNode = Node1;
  565. Status = gBS->LocateDevicePath (
  566. &gEfiFirmwareVolume2ProtocolGuid,
  567. &SearchNode,
  568. &FvHandle
  569. );
  570. if (!EFI_ERROR (Status)) {
  571. //
  572. // The firmware volume was found; now let's see if it contains the FvFile
  573. // identified by GUID.
  574. //
  575. EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
  576. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
  577. UINTN BufferSize;
  578. EFI_FV_FILETYPE FoundType;
  579. EFI_FV_FILE_ATTRIBUTES FileAttributes;
  580. UINT32 AuthenticationStatus;
  581. Status = gBS->HandleProtocol (
  582. FvHandle,
  583. &gEfiFirmwareVolume2ProtocolGuid,
  584. (VOID **)&FvProtocol
  585. );
  586. ASSERT_EFI_ERROR (Status);
  587. FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
  588. //
  589. // Buffer==NULL means we request metadata only: BufferSize, FoundType,
  590. // FileAttributes.
  591. //
  592. Status = FvProtocol->ReadFile (
  593. FvProtocol,
  594. &FvFileNode->FvFileName, // NameGuid
  595. NULL, // Buffer
  596. &BufferSize,
  597. &FoundType,
  598. &FileAttributes,
  599. &AuthenticationStatus
  600. );
  601. if (!EFI_ERROR (Status)) {
  602. //
  603. // The FvFile was found. Keep the boot option.
  604. //
  605. continue;
  606. }
  607. }
  608. //
  609. // Delete the boot option.
  610. //
  611. Status = EfiBootManagerDeleteLoadOptionVariable (
  612. BootOptions[Index].OptionNumber,
  613. LoadOptionTypeBoot
  614. );
  615. DEBUG_CODE_BEGIN ();
  616. CHAR16 *DevicePathString;
  617. DevicePathString = ConvertDevicePathToText (
  618. BootOptions[Index].FilePath,
  619. FALSE,
  620. FALSE
  621. );
  622. DEBUG ((
  623. EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
  624. "%a: removing stale Boot#%04x %s: %r\n",
  625. __FUNCTION__,
  626. (UINT32)BootOptions[Index].OptionNumber,
  627. DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
  628. Status
  629. ));
  630. if (DevicePathString != NULL) {
  631. FreePool (DevicePathString);
  632. }
  633. DEBUG_CODE_END ();
  634. }
  635. EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
  636. }
  637. STATIC
  638. VOID
  639. PlatformRegisterOptionsAndKeys (
  640. VOID
  641. )
  642. {
  643. EFI_STATUS Status;
  644. EFI_INPUT_KEY Enter;
  645. EFI_INPUT_KEY F2;
  646. EFI_INPUT_KEY Esc;
  647. EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
  648. //
  649. // Register ENTER as CONTINUE key
  650. //
  651. Enter.ScanCode = SCAN_NULL;
  652. Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
  653. Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
  654. ASSERT_EFI_ERROR (Status);
  655. //
  656. // Map F2 and ESC to Boot Manager Menu
  657. //
  658. F2.ScanCode = SCAN_F2;
  659. F2.UnicodeChar = CHAR_NULL;
  660. Esc.ScanCode = SCAN_ESC;
  661. Esc.UnicodeChar = CHAR_NULL;
  662. Status = EfiBootManagerGetBootManagerMenu (&BootOption);
  663. ASSERT_EFI_ERROR (Status);
  664. Status = EfiBootManagerAddKeyOptionVariable (
  665. NULL,
  666. (UINT16)BootOption.OptionNumber,
  667. 0,
  668. &F2,
  669. NULL
  670. );
  671. ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
  672. Status = EfiBootManagerAddKeyOptionVariable (
  673. NULL,
  674. (UINT16)BootOption.OptionNumber,
  675. 0,
  676. &Esc,
  677. NULL
  678. );
  679. ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
  680. }
  681. //
  682. // BDS Platform Functions
  683. //
  684. /**
  685. Do the platform init, can be customized by OEM/IBV
  686. Possible things that can be done in PlatformBootManagerBeforeConsole:
  687. > Update console variable: 1. include hot-plug devices;
  688. > 2. Clear ConIn and add SOL for AMT
  689. > Register new Driver#### or Boot####
  690. > Register new Key####: e.g.: F12
  691. > Signal ReadyToLock event
  692. > Authentication action: 1. connect Auth devices;
  693. > 2. Identify auto logon user.
  694. **/
  695. VOID
  696. EFIAPI
  697. PlatformBootManagerBeforeConsole (
  698. VOID
  699. )
  700. {
  701. UINT16 FrontPageTimeout;
  702. RETURN_STATUS PcdStatus;
  703. EFI_STATUS Status;
  704. //
  705. // Signal EndOfDxe PI Event
  706. //
  707. EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
  708. //
  709. // Disable the TPM 2 platform hierarchy
  710. //
  711. ConfigureTpmPlatformHierarchy ();
  712. //
  713. // Dispatch deferred images after EndOfDxe event.
  714. //
  715. EfiBootManagerDispatchDeferredImages ();
  716. //
  717. // Locate the PCI root bridges and make the PCI bus driver connect each,
  718. // non-recursively. This will produce a number of child handles with PciIo on
  719. // them.
  720. //
  721. FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
  722. //
  723. // Signal the ACPI platform driver that it can download QEMU ACPI tables.
  724. //
  725. EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
  726. //
  727. // Find all display class PCI devices (using the handles from the previous
  728. // step), and connect them non-recursively. This should produce a number of
  729. // child handles with GOPs on them.
  730. //
  731. FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
  732. //
  733. // Now add the device path of all handles with GOP on them to ConOut and
  734. // ErrOut.
  735. //
  736. FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
  737. //
  738. // Add the hardcoded short-form USB keyboard device path to ConIn.
  739. //
  740. EfiBootManagerUpdateConsoleVariable (
  741. ConIn,
  742. (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,
  743. NULL
  744. );
  745. //
  746. // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
  747. //
  748. CopyGuid (
  749. &mSerialConsole.TermType.Guid,
  750. PcdGetPtr (PcdTerminalTypeGuidBuffer)
  751. );
  752. EfiBootManagerUpdateConsoleVariable (
  753. ConIn,
  754. (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
  755. NULL
  756. );
  757. EfiBootManagerUpdateConsoleVariable (
  758. ConOut,
  759. (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
  760. NULL
  761. );
  762. EfiBootManagerUpdateConsoleVariable (
  763. ErrOut,
  764. (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
  765. NULL
  766. );
  767. //
  768. // Set the front page timeout from the QEMU configuration.
  769. //
  770. FrontPageTimeout = GetFrontPageTimeoutFromQemu ();
  771. PcdStatus = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);
  772. ASSERT_RETURN_ERROR (PcdStatus);
  773. //
  774. // Reflect the PCD in the standard Timeout variable.
  775. //
  776. Status = gRT->SetVariable (
  777. EFI_TIME_OUT_VARIABLE_NAME,
  778. &gEfiGlobalVariableGuid,
  779. (EFI_VARIABLE_NON_VOLATILE |
  780. EFI_VARIABLE_BOOTSERVICE_ACCESS |
  781. EFI_VARIABLE_RUNTIME_ACCESS),
  782. sizeof FrontPageTimeout,
  783. &FrontPageTimeout
  784. );
  785. DEBUG ((
  786. EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
  787. "%a: SetVariable(%s, %u): %r\n",
  788. __FUNCTION__,
  789. EFI_TIME_OUT_VARIABLE_NAME,
  790. FrontPageTimeout,
  791. Status
  792. ));
  793. //
  794. // Register platform-specific boot options and keyboard shortcuts.
  795. //
  796. PlatformRegisterOptionsAndKeys ();
  797. //
  798. // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO
  799. // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices.
  800. //
  801. FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect);
  802. //
  803. // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
  804. // instances on Virtio PCI RNG devices.
  805. //
  806. FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);
  807. }
  808. /**
  809. Do the platform specific action after the console is ready
  810. Possible things that can be done in PlatformBootManagerAfterConsole:
  811. > Console post action:
  812. > Dynamically switch output mode from 100x31 to 80x25 for certain scenario
  813. > Signal console ready platform customized event
  814. > Run diagnostics like memory testing
  815. > Connect certain devices
  816. > Dispatch additional option roms
  817. > Special boot: e.g.: USB boot, enter UI
  818. **/
  819. VOID
  820. EFIAPI
  821. PlatformBootManagerAfterConsole (
  822. VOID
  823. )
  824. {
  825. RETURN_STATUS Status;
  826. //
  827. // Show the splash screen.
  828. //
  829. BootLogoEnableLogo ();
  830. //
  831. // Process QEMU's -kernel command line option. The kernel booted this way
  832. // will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we
  833. // connected any and all PCI root bridges, and then signaled the ACPI
  834. // platform driver.
  835. //
  836. TryRunningQemuKernel ();
  837. //
  838. // Connect the purported boot devices.
  839. //
  840. Status = ConnectDevicesFromQemu ();
  841. if (RETURN_ERROR (Status)) {
  842. //
  843. // Connect the rest of the devices.
  844. //
  845. EfiBootManagerConnectAll ();
  846. }
  847. //
  848. // Enumerate all possible boot options, then filter and reorder them based on
  849. // the QEMU configuration.
  850. //
  851. EfiBootManagerRefreshAllBootOption ();
  852. //
  853. // Register UEFI Shell
  854. //
  855. PlatformRegisterFvBootOption (
  856. &gUefiShellFileGuid,
  857. L"EFI Internal Shell",
  858. LOAD_OPTION_ACTIVE
  859. );
  860. RemoveStaleFvFileOptions ();
  861. SetBootOrderFromQemu ();
  862. PlatformBmPrintScRegisterHandler ();
  863. }
  864. /**
  865. This function is called each second during the boot manager waits the
  866. timeout.
  867. @param TimeoutRemain The remaining timeout.
  868. **/
  869. VOID
  870. EFIAPI
  871. PlatformBootManagerWaitCallback (
  872. UINT16 TimeoutRemain
  873. )
  874. {
  875. EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
  876. EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
  877. UINT16 TimeoutInitial;
  878. TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
  879. //
  880. // If PcdPlatformBootTimeOut is set to zero, then we consider
  881. // that no progress update should be enacted.
  882. //
  883. if (TimeoutInitial == 0) {
  884. return;
  885. }
  886. Black.Raw = 0x00000000;
  887. White.Raw = 0x00FFFFFF;
  888. BootLogoUpdateProgress (
  889. White.Pixel,
  890. Black.Pixel,
  891. L"Start boot option",
  892. White.Pixel,
  893. (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
  894. 0
  895. );
  896. }
  897. /**
  898. The function is called when no boot option could be launched,
  899. including platform recovery options and options pointing to applications
  900. built into firmware volumes.
  901. If this function returns, BDS attempts to enter an infinite loop.
  902. **/
  903. VOID
  904. EFIAPI
  905. PlatformBootManagerUnableToBoot (
  906. VOID
  907. )
  908. {
  909. EFI_STATUS Status;
  910. EFI_INPUT_KEY Key;
  911. EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
  912. UINTN Index;
  913. //
  914. // BootManagerMenu doesn't contain the correct information when return status
  915. // is EFI_NOT_FOUND.
  916. //
  917. Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
  918. if (EFI_ERROR (Status)) {
  919. return;
  920. }
  921. //
  922. // Normally BdsDxe does not print anything to the system console, but this is
  923. // a last resort -- the end-user will likely not see any DEBUG messages
  924. // logged in this situation.
  925. //
  926. // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
  927. // here to see if it makes sense to request and wait for a keypress.
  928. //
  929. if (gST->ConIn != NULL) {
  930. AsciiPrint (
  931. "%a: No bootable option or device was found.\n"
  932. "%a: Press any key to enter the Boot Manager Menu.\n",
  933. gEfiCallerBaseName,
  934. gEfiCallerBaseName
  935. );
  936. Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
  937. ASSERT_EFI_ERROR (Status);
  938. ASSERT (Index == 0);
  939. //
  940. // Drain any queued keys.
  941. //
  942. while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
  943. //
  944. // just throw away Key
  945. //
  946. }
  947. }
  948. for ( ; ;) {
  949. EfiBootManagerBoot (&BootManagerMenu);
  950. }
  951. }