PlatformBm.c 26 KB

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