QemuFwCfgLib.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. /** @file
  2. Stateful and implicitly initialized fw_cfg library implementation.
  3. Copyright (C) 2013 - 2014, Red Hat, Inc.
  4. Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <Uefi.h>
  8. #include <Library/BaseLib.h>
  9. #include <Library/BaseMemoryLib.h>
  10. #include <Library/DebugLib.h>
  11. #include <Library/IoLib.h>
  12. #include <Library/QemuFwCfgLib.h>
  13. #include <Library/UefiBootServicesTableLib.h>
  14. #include <Protocol/FdtClient.h>
  15. STATIC UINTN mFwCfgSelectorAddress;
  16. STATIC UINTN mFwCfgDataAddress;
  17. STATIC UINTN mFwCfgDmaAddress;
  18. /**
  19. Reads firmware configuration bytes into a buffer
  20. @param[in] Size Size in bytes to read
  21. @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)
  22. **/
  23. typedef
  24. VOID (EFIAPI READ_BYTES_FUNCTION) (
  25. IN UINTN Size,
  26. IN VOID *Buffer OPTIONAL
  27. );
  28. /**
  29. Writes bytes from a buffer to firmware configuration
  30. @param[in] Size Size in bytes to write
  31. @param[in] Buffer Buffer to transfer data from (OPTIONAL if Size is 0)
  32. **/
  33. typedef
  34. VOID (EFIAPI WRITE_BYTES_FUNCTION) (
  35. IN UINTN Size,
  36. IN VOID *Buffer OPTIONAL
  37. );
  38. /**
  39. Skips bytes in firmware configuration
  40. @param[in] Size Size in bytes to skip
  41. **/
  42. typedef
  43. VOID (EFIAPI SKIP_BYTES_FUNCTION) (
  44. IN UINTN Size
  45. );
  46. //
  47. // Forward declaration of the two implementations we have.
  48. //
  49. STATIC READ_BYTES_FUNCTION MmioReadBytes;
  50. STATIC WRITE_BYTES_FUNCTION MmioWriteBytes;
  51. STATIC SKIP_BYTES_FUNCTION MmioSkipBytes;
  52. STATIC READ_BYTES_FUNCTION DmaReadBytes;
  53. STATIC WRITE_BYTES_FUNCTION DmaWriteBytes;
  54. STATIC SKIP_BYTES_FUNCTION DmaSkipBytes;
  55. //
  56. // These correspond to the implementation we detect at runtime.
  57. //
  58. STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;
  59. STATIC WRITE_BYTES_FUNCTION *InternalQemuFwCfgWriteBytes = MmioWriteBytes;
  60. STATIC SKIP_BYTES_FUNCTION *InternalQemuFwCfgSkipBytes = MmioSkipBytes;
  61. /**
  62. Returns a boolean indicating if the firmware configuration interface
  63. is available or not.
  64. This function may change fw_cfg state.
  65. @retval TRUE The interface is available
  66. @retval FALSE The interface is not available
  67. **/
  68. BOOLEAN
  69. EFIAPI
  70. QemuFwCfgIsAvailable (
  71. VOID
  72. )
  73. {
  74. return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);
  75. }
  76. RETURN_STATUS
  77. EFIAPI
  78. QemuFwCfgInitialize (
  79. VOID
  80. )
  81. {
  82. EFI_STATUS Status;
  83. FDT_CLIENT_PROTOCOL *FdtClient;
  84. CONST UINT64 *Reg;
  85. UINT32 RegSize;
  86. UINTN AddressCells, SizeCells;
  87. UINT64 FwCfgSelectorAddress;
  88. UINT64 FwCfgSelectorSize;
  89. UINT64 FwCfgDataAddress;
  90. UINT64 FwCfgDataSize;
  91. UINT64 FwCfgDmaAddress;
  92. UINT64 FwCfgDmaSize;
  93. Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,
  94. (VOID **)&FdtClient);
  95. ASSERT_EFI_ERROR (Status);
  96. Status = FdtClient->FindCompatibleNodeReg (FdtClient, "qemu,fw-cfg-mmio",
  97. (CONST VOID **)&Reg, &AddressCells, &SizeCells,
  98. &RegSize);
  99. if (EFI_ERROR (Status)) {
  100. DEBUG ((EFI_D_WARN,
  101. "%a: No 'qemu,fw-cfg-mmio' compatible DT node found (Status == %r)\n",
  102. __FUNCTION__, Status));
  103. return EFI_SUCCESS;
  104. }
  105. ASSERT (AddressCells == 2);
  106. ASSERT (SizeCells == 2);
  107. ASSERT (RegSize == 2 * sizeof (UINT64));
  108. FwCfgDataAddress = SwapBytes64 (Reg[0]);
  109. FwCfgDataSize = 8;
  110. FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
  111. FwCfgSelectorSize = 2;
  112. //
  113. // The following ASSERT()s express
  114. //
  115. // Address + Size - 1 <= MAX_UINTN
  116. //
  117. // for both registers, that is, that the last byte in each MMIO range is
  118. // expressible as a MAX_UINTN. The form below is mathematically
  119. // equivalent, and it also prevents any unsigned overflow before the
  120. // comparison.
  121. //
  122. ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
  123. ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
  124. mFwCfgSelectorAddress = FwCfgSelectorAddress;
  125. mFwCfgDataAddress = FwCfgDataAddress;
  126. DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
  127. FwCfgDataAddress));
  128. if (SwapBytes64 (Reg[1]) >= 0x18) {
  129. FwCfgDmaAddress = FwCfgDataAddress + 0x10;
  130. FwCfgDmaSize = 0x08;
  131. //
  132. // See explanation above.
  133. //
  134. ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);
  135. DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));
  136. } else {
  137. FwCfgDmaAddress = 0;
  138. }
  139. if (QemuFwCfgIsAvailable ()) {
  140. UINT32 Signature;
  141. QemuFwCfgSelectItem (QemuFwCfgItemSignature);
  142. Signature = QemuFwCfgRead32 ();
  143. if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
  144. //
  145. // For DMA support, we require the DTB to advertise the register, and the
  146. // feature bitmap (which we read without DMA) to confirm the feature.
  147. //
  148. if (FwCfgDmaAddress != 0) {
  149. UINT32 Features;
  150. QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
  151. Features = QemuFwCfgRead32 ();
  152. if ((Features & FW_CFG_F_DMA) != 0) {
  153. mFwCfgDmaAddress = FwCfgDmaAddress;
  154. InternalQemuFwCfgReadBytes = DmaReadBytes;
  155. InternalQemuFwCfgWriteBytes = DmaWriteBytes;
  156. InternalQemuFwCfgSkipBytes = DmaSkipBytes;
  157. }
  158. }
  159. } else {
  160. mFwCfgSelectorAddress = 0;
  161. mFwCfgDataAddress = 0;
  162. }
  163. }
  164. return RETURN_SUCCESS;
  165. }
  166. /**
  167. Selects a firmware configuration item for reading.
  168. Following this call, any data read from this item will start from the
  169. beginning of the configuration item's data.
  170. @param[in] QemuFwCfgItem Firmware Configuration item to read
  171. **/
  172. VOID
  173. EFIAPI
  174. QemuFwCfgSelectItem (
  175. IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
  176. )
  177. {
  178. if (QemuFwCfgIsAvailable ()) {
  179. MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));
  180. }
  181. }
  182. /**
  183. Slow READ_BYTES_FUNCTION.
  184. **/
  185. STATIC
  186. VOID
  187. EFIAPI
  188. MmioReadBytes (
  189. IN UINTN Size,
  190. IN VOID *Buffer OPTIONAL
  191. )
  192. {
  193. UINTN Left;
  194. UINT8 *Ptr;
  195. UINT8 *End;
  196. #ifdef MDE_CPU_AARCH64
  197. Left = Size & 7;
  198. #else
  199. Left = Size & 3;
  200. #endif
  201. Size -= Left;
  202. Ptr = Buffer;
  203. End = Ptr + Size;
  204. #ifdef MDE_CPU_AARCH64
  205. while (Ptr < End) {
  206. *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);
  207. Ptr += 8;
  208. }
  209. if (Left & 4) {
  210. *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
  211. Ptr += 4;
  212. }
  213. #else
  214. while (Ptr < End) {
  215. *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
  216. Ptr += 4;
  217. }
  218. #endif
  219. if (Left & 2) {
  220. *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);
  221. Ptr += 2;
  222. }
  223. if (Left & 1) {
  224. *Ptr = MmioRead8 (mFwCfgDataAddress);
  225. }
  226. }
  227. /**
  228. Transfer an array of bytes, or skip a number of bytes, using the DMA
  229. interface.
  230. @param[in] Size Size in bytes to transfer or skip.
  231. @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
  232. and may be NULL, if Size is zero, or Control is
  233. FW_CFG_DMA_CTL_SKIP.
  234. @param[in] Control One of the following:
  235. FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
  236. FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
  237. FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
  238. **/
  239. STATIC
  240. VOID
  241. DmaTransferBytes (
  242. IN UINTN Size,
  243. IN OUT VOID *Buffer OPTIONAL,
  244. IN UINT32 Control
  245. )
  246. {
  247. volatile FW_CFG_DMA_ACCESS Access;
  248. UINT32 Status;
  249. ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
  250. Control == FW_CFG_DMA_CTL_SKIP);
  251. if (Size == 0) {
  252. return;
  253. }
  254. ASSERT (Size <= MAX_UINT32);
  255. Access.Control = SwapBytes32 (Control);
  256. Access.Length = SwapBytes32 ((UINT32)Size);
  257. Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);
  258. //
  259. // We shouldn't start the transfer before setting up Access.
  260. //
  261. MemoryFence ();
  262. //
  263. // This will fire off the transfer.
  264. //
  265. #ifdef MDE_CPU_AARCH64
  266. MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));
  267. #else
  268. MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));
  269. #endif
  270. //
  271. // We shouldn't look at Access.Control before starting the transfer.
  272. //
  273. MemoryFence ();
  274. do {
  275. Status = SwapBytes32 (Access.Control);
  276. ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
  277. } while (Status != 0);
  278. //
  279. // The caller will want to access the transferred data.
  280. //
  281. MemoryFence ();
  282. }
  283. /**
  284. Fast READ_BYTES_FUNCTION.
  285. **/
  286. STATIC
  287. VOID
  288. EFIAPI
  289. DmaReadBytes (
  290. IN UINTN Size,
  291. IN VOID *Buffer OPTIONAL
  292. )
  293. {
  294. DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_READ);
  295. }
  296. /**
  297. Reads firmware configuration bytes into a buffer
  298. If called multiple times, then the data read will continue at the offset of
  299. the firmware configuration item where the previous read ended.
  300. @param[in] Size Size in bytes to read
  301. @param[in] Buffer Buffer to store data into
  302. **/
  303. VOID
  304. EFIAPI
  305. QemuFwCfgReadBytes (
  306. IN UINTN Size,
  307. IN VOID *Buffer
  308. )
  309. {
  310. if (QemuFwCfgIsAvailable ()) {
  311. InternalQemuFwCfgReadBytes (Size, Buffer);
  312. } else {
  313. ZeroMem (Buffer, Size);
  314. }
  315. }
  316. /**
  317. Slow WRITE_BYTES_FUNCTION.
  318. **/
  319. STATIC
  320. VOID
  321. EFIAPI
  322. MmioWriteBytes (
  323. IN UINTN Size,
  324. IN VOID *Buffer OPTIONAL
  325. )
  326. {
  327. UINTN Idx;
  328. for (Idx = 0; Idx < Size; ++Idx) {
  329. MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
  330. }
  331. }
  332. /**
  333. Fast WRITE_BYTES_FUNCTION.
  334. **/
  335. STATIC
  336. VOID
  337. EFIAPI
  338. DmaWriteBytes (
  339. IN UINTN Size,
  340. IN VOID *Buffer OPTIONAL
  341. )
  342. {
  343. DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_WRITE);
  344. }
  345. /**
  346. Write firmware configuration bytes from a buffer
  347. If called multiple times, then the data written will continue at the offset
  348. of the firmware configuration item where the previous write ended.
  349. @param[in] Size Size in bytes to write
  350. @param[in] Buffer Buffer to read data from
  351. **/
  352. VOID
  353. EFIAPI
  354. QemuFwCfgWriteBytes (
  355. IN UINTN Size,
  356. IN VOID *Buffer
  357. )
  358. {
  359. if (QemuFwCfgIsAvailable ()) {
  360. InternalQemuFwCfgWriteBytes (Size, Buffer);
  361. }
  362. }
  363. /**
  364. Slow SKIP_BYTES_FUNCTION.
  365. **/
  366. STATIC
  367. VOID
  368. EFIAPI
  369. MmioSkipBytes (
  370. IN UINTN Size
  371. )
  372. {
  373. UINTN ChunkSize;
  374. UINT8 SkipBuffer[256];
  375. //
  376. // Emulate the skip by reading data in chunks, and throwing it away. The
  377. // implementation below doesn't affect the static data footprint for client
  378. // modules. Large skips are not expected, therefore this fallback is not
  379. // performance critical. The size of SkipBuffer is thought not to exert a
  380. // large pressure on the stack.
  381. //
  382. while (Size > 0) {
  383. ChunkSize = MIN (Size, sizeof SkipBuffer);
  384. MmioReadBytes (ChunkSize, SkipBuffer);
  385. Size -= ChunkSize;
  386. }
  387. }
  388. /**
  389. Fast SKIP_BYTES_FUNCTION.
  390. **/
  391. STATIC
  392. VOID
  393. EFIAPI
  394. DmaSkipBytes (
  395. IN UINTN Size
  396. )
  397. {
  398. DmaTransferBytes (Size, NULL, FW_CFG_DMA_CTL_SKIP);
  399. }
  400. /**
  401. Skip bytes in the firmware configuration item.
  402. Increase the offset of the firmware configuration item without transferring
  403. bytes between the item and a caller-provided buffer. Subsequent read, write
  404. or skip operations will commence at the increased offset.
  405. @param[in] Size Number of bytes to skip.
  406. **/
  407. VOID
  408. EFIAPI
  409. QemuFwCfgSkipBytes (
  410. IN UINTN Size
  411. )
  412. {
  413. if (QemuFwCfgIsAvailable ()) {
  414. InternalQemuFwCfgSkipBytes (Size);
  415. }
  416. }
  417. /**
  418. Reads a UINT8 firmware configuration value
  419. @return Value of Firmware Configuration item read
  420. **/
  421. UINT8
  422. EFIAPI
  423. QemuFwCfgRead8 (
  424. VOID
  425. )
  426. {
  427. UINT8 Result;
  428. QemuFwCfgReadBytes (sizeof Result, &Result);
  429. return Result;
  430. }
  431. /**
  432. Reads a UINT16 firmware configuration value
  433. @return Value of Firmware Configuration item read
  434. **/
  435. UINT16
  436. EFIAPI
  437. QemuFwCfgRead16 (
  438. VOID
  439. )
  440. {
  441. UINT16 Result;
  442. QemuFwCfgReadBytes (sizeof Result, &Result);
  443. return Result;
  444. }
  445. /**
  446. Reads a UINT32 firmware configuration value
  447. @return Value of Firmware Configuration item read
  448. **/
  449. UINT32
  450. EFIAPI
  451. QemuFwCfgRead32 (
  452. VOID
  453. )
  454. {
  455. UINT32 Result;
  456. QemuFwCfgReadBytes (sizeof Result, &Result);
  457. return Result;
  458. }
  459. /**
  460. Reads a UINT64 firmware configuration value
  461. @return Value of Firmware Configuration item read
  462. **/
  463. UINT64
  464. EFIAPI
  465. QemuFwCfgRead64 (
  466. VOID
  467. )
  468. {
  469. UINT64 Result;
  470. QemuFwCfgReadBytes (sizeof Result, &Result);
  471. return Result;
  472. }
  473. /**
  474. Find the configuration item corresponding to the firmware configuration file.
  475. @param[in] Name Name of file to look up.
  476. @param[out] Item Configuration item corresponding to the file, to be passed
  477. to QemuFwCfgSelectItem ().
  478. @param[out] Size Number of bytes in the file.
  479. @retval RETURN_SUCCESS If file is found.
  480. @retval RETURN_NOT_FOUND If file is not found.
  481. @retval RETURN_UNSUPPORTED If firmware configuration is unavailable.
  482. **/
  483. RETURN_STATUS
  484. EFIAPI
  485. QemuFwCfgFindFile (
  486. IN CONST CHAR8 *Name,
  487. OUT FIRMWARE_CONFIG_ITEM *Item,
  488. OUT UINTN *Size
  489. )
  490. {
  491. UINT32 Count;
  492. UINT32 Idx;
  493. if (!QemuFwCfgIsAvailable ()) {
  494. return RETURN_UNSUPPORTED;
  495. }
  496. QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
  497. Count = SwapBytes32 (QemuFwCfgRead32 ());
  498. for (Idx = 0; Idx < Count; ++Idx) {
  499. UINT32 FileSize;
  500. UINT16 FileSelect;
  501. CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];
  502. FileSize = QemuFwCfgRead32 ();
  503. FileSelect = QemuFwCfgRead16 ();
  504. QemuFwCfgRead16 (); // skip the field called "reserved"
  505. InternalQemuFwCfgReadBytes (sizeof (FName), FName);
  506. if (AsciiStrCmp (Name, FName) == 0) {
  507. *Item = (FIRMWARE_CONFIG_ITEM) SwapBytes16 (FileSelect);
  508. *Size = SwapBytes32 (FileSize);
  509. return RETURN_SUCCESS;
  510. }
  511. }
  512. return RETURN_NOT_FOUND;
  513. }