QemuFwCfgPeiLib.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /** @file
  2. Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. @par Glossary:
  5. - FwCfg - firmWare Configure
  6. - CTL - Control
  7. **/
  8. #include "Uefi.h"
  9. #include <Library/BaseLib.h>
  10. #include <Library/BaseMemoryLib.h>
  11. #include <Library/DebugLib.h>
  12. #include <Library/IoLib.h>
  13. #include <Library/QemuFwCfgLib.h>
  14. #include <Library/MemoryAllocationLib.h>
  15. #include <Library/UefiBootServicesTableLib.h>
  16. #include <Library/PcdLib.h>
  17. #include <libfdt.h>
  18. #include "QemuFwCfgLibInternal.h"
  19. STATIC UINTN mFwCfgSelectorAddress;
  20. STATIC UINTN mFwCfgDataAddress;
  21. /**
  22. To get firmware configure selector address.
  23. @param VOID
  24. @retval firmware configure selector address
  25. **/
  26. UINTN
  27. EFIAPI
  28. QemuGetFwCfgSelectorAddress (
  29. VOID
  30. )
  31. {
  32. UINTN FwCfgSelectorAddress = mFwCfgSelectorAddress;
  33. if (FwCfgSelectorAddress == 0) {
  34. FwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);
  35. }
  36. return FwCfgSelectorAddress;
  37. }
  38. /**
  39. To get firmware configure Data address.
  40. @param VOID
  41. @retval firmware configure data address
  42. **/
  43. UINTN
  44. EFIAPI
  45. QemuGetFwCfgDataAddress (
  46. VOID
  47. )
  48. {
  49. UINTN FwCfgDataAddress = mFwCfgDataAddress;
  50. if (FwCfgDataAddress == 0) {
  51. FwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress);
  52. }
  53. return FwCfgDataAddress;
  54. }
  55. /**
  56. Selects a firmware configuration item for reading.
  57. Following this call, any data read from this item will start from
  58. the beginning of the configuration item's data.
  59. @param[in] QemuFwCfgItem - Firmware Configuration item to read
  60. **/
  61. VOID
  62. EFIAPI
  63. QemuFwCfgSelectItem (
  64. IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
  65. )
  66. {
  67. UINTN FwCfgSelectorAddress;
  68. FwCfgSelectorAddress = QemuGetFwCfgSelectorAddress ();
  69. MmioWrite16 (FwCfgSelectorAddress, SwapBytes16((UINT16) (UINTN)QemuFwCfgItem));
  70. }
  71. /**
  72. Slow READ_BYTES_FUNCTION.
  73. @param[in] The size of the data to be read.
  74. @param[in] Buffer The buffer that stores the readout data.
  75. **/
  76. VOID
  77. EFIAPI
  78. MmioReadBytes (
  79. IN UINTN Size,
  80. IN VOID *Buffer OPTIONAL
  81. )
  82. {
  83. UINTN Left;
  84. UINT8 *Ptr;
  85. UINT8 *End;
  86. UINTN FwCfgDataAddress;
  87. Left = Size & 7;
  88. Size -= Left;
  89. Ptr = Buffer;
  90. End = Ptr + Size;
  91. FwCfgDataAddress = QemuGetFwCfgDataAddress ();
  92. while (Ptr < End) {
  93. *(UINT64 *)Ptr = MmioRead64 (FwCfgDataAddress);
  94. Ptr += 8;
  95. }
  96. if (Left & 4) {
  97. *(UINT32 *)Ptr = MmioRead32 (FwCfgDataAddress);
  98. Ptr += 4;
  99. }
  100. if (Left & 2) {
  101. *(UINT16 *)Ptr = MmioRead16 (FwCfgDataAddress);
  102. Ptr += 2;
  103. }
  104. if (Left & 1) {
  105. *Ptr = MmioRead8 (FwCfgDataAddress);
  106. }
  107. }
  108. /**
  109. Slow WRITE_BYTES_FUNCTION.
  110. @param[in] The size of the data to be write.
  111. @param[in] Buffer The buffer that stores the writein data.
  112. **/
  113. VOID
  114. EFIAPI
  115. MmioWriteBytes (
  116. IN UINTN Size,
  117. IN VOID *Buffer OPTIONAL
  118. )
  119. {
  120. UINTN Idx;
  121. UINTN FwCfgDataAddress;
  122. FwCfgDataAddress = QemuGetFwCfgDataAddress ();
  123. for (Idx = 0; Idx < Size; ++Idx) {
  124. MmioWrite8 (FwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
  125. }
  126. }
  127. /**
  128. Reads firmware configuration bytes into a buffer
  129. @param[in] Size - Size in bytes to read
  130. @param[in] Buffer - Buffer to store data into (OPTIONAL if Size is 0)
  131. **/
  132. VOID
  133. EFIAPI
  134. InternalQemuFwCfgReadBytes (
  135. IN UINTN Size,
  136. IN VOID *Buffer OPTIONAL
  137. )
  138. {
  139. if ((InternalQemuFwCfgDmaIsAvailable ())
  140. && (Size <= MAX_UINT32))
  141. {
  142. InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_READ);
  143. return;
  144. }
  145. MmioReadBytes (Size, Buffer);
  146. }
  147. /**
  148. Reads firmware configuration bytes into a buffer
  149. If called multiple times, then the data read will
  150. continue at the offset of the firmware configuration
  151. item where the previous read ended.
  152. @param[in] Size - Size in bytes to read
  153. @param[in] Buffer - Buffer to store data into
  154. **/
  155. VOID
  156. EFIAPI
  157. QemuFwCfgReadBytes (
  158. IN UINTN Size,
  159. IN VOID *Buffer
  160. )
  161. {
  162. if (InternalQemuFwCfgIsAvailable ()) {
  163. InternalQemuFwCfgReadBytes (Size, Buffer);
  164. } else {
  165. ZeroMem (Buffer, Size);
  166. }
  167. }
  168. /**
  169. Write firmware configuration bytes from a buffer
  170. If called multiple times, then the data written will
  171. continue at the offset of the firmware configuration
  172. item where the previous write ended.
  173. @param[in] Size - Size in bytes to write
  174. @param[in] Buffer - Buffer to read data from
  175. **/
  176. VOID
  177. EFIAPI
  178. QemuFwCfgWriteBytes (
  179. IN UINTN Size,
  180. IN VOID *Buffer
  181. )
  182. {
  183. if (InternalQemuFwCfgIsAvailable ()) {
  184. if ((InternalQemuFwCfgDmaIsAvailable ())
  185. && (Size <= MAX_UINT32))
  186. {
  187. InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_WRITE);
  188. return;
  189. }
  190. MmioWriteBytes (Size, Buffer);
  191. }
  192. }
  193. /**
  194. Skip bytes in the firmware configuration item.
  195. Increase the offset of the firmware configuration item without transferring
  196. bytes between the item and a caller-provided buffer. Subsequent read, write
  197. or skip operations will commence at the increased offset.
  198. @param[in] Size Number of bytes to skip.
  199. **/
  200. VOID
  201. EFIAPI
  202. QemuFwCfgSkipBytes (
  203. IN UINTN Size
  204. )
  205. {
  206. UINTN ChunkSize;
  207. UINT8 SkipBuffer[256];
  208. if (!InternalQemuFwCfgIsAvailable ()) {
  209. return;
  210. }
  211. if ((InternalQemuFwCfgDmaIsAvailable ())
  212. && (Size <= MAX_UINT32))
  213. {
  214. InternalQemuFwCfgDmaBytes ((UINT32)Size, NULL, FW_CFG_DMA_CTL_SKIP);
  215. return;
  216. }
  217. //
  218. // Emulate the skip by reading data in chunks, and throwing it away. The
  219. // implementation below is suitable even for phases where RAM or dynamic
  220. // allocation is not available or appropriate. It also doesn't affect the
  221. // static data footprint for client modules. Large skips are not expected,
  222. // therefore this fallback is not performance critical. The size of
  223. // SkipBuffer is thought not to exert a large pressure on the stack in any
  224. // phase.
  225. //
  226. while (Size > 0) {
  227. ChunkSize = MIN (Size, sizeof SkipBuffer);
  228. MmioReadBytes (ChunkSize, SkipBuffer);
  229. Size -= ChunkSize;
  230. }
  231. }
  232. /**
  233. Reads a UINT8 firmware configuration value
  234. @return Value of Firmware Configuration item read
  235. **/
  236. UINT8
  237. EFIAPI
  238. QemuFwCfgRead8 (
  239. VOID
  240. )
  241. {
  242. UINT8 Result;
  243. QemuFwCfgReadBytes (sizeof (Result), &Result);
  244. return Result;
  245. }
  246. /**
  247. Reads a UINT16 firmware configuration value
  248. @return Value of Firmware Configuration item read
  249. **/
  250. UINT16
  251. EFIAPI
  252. QemuFwCfgRead16 (
  253. VOID
  254. )
  255. {
  256. UINT16 Result;
  257. QemuFwCfgReadBytes (sizeof (Result), &Result);
  258. return Result;
  259. }
  260. /**
  261. Reads a UINT32 firmware configuration value
  262. @return Value of Firmware Configuration item read
  263. **/
  264. UINT32
  265. EFIAPI
  266. QemuFwCfgRead32 (
  267. VOID
  268. )
  269. {
  270. UINT32 Result;
  271. QemuFwCfgReadBytes (sizeof (Result), &Result);
  272. return Result;
  273. }
  274. /**
  275. Reads a UINT64 firmware configuration value
  276. @return Value of Firmware Configuration item read
  277. **/
  278. UINT64
  279. EFIAPI
  280. QemuFwCfgRead64 (
  281. VOID
  282. )
  283. {
  284. UINT64 Result;
  285. QemuFwCfgReadBytes (sizeof (Result), &Result);
  286. return Result;
  287. }
  288. /**
  289. Find the configuration item corresponding to the firmware configuration file.
  290. @param[in] Name - Name of file to look up.
  291. @param[out] Item - Configuration item corresponding to the file, to be passed
  292. to QemuFwCfgSelectItem ().
  293. @param[out] Size - Number of bytes in the file.
  294. @return RETURN_SUCCESS If file is found.
  295. RETURN_NOT_FOUND If file is not found.
  296. RETURN_UNSUPPORTED If firmware configuration is unavailable.
  297. **/
  298. RETURN_STATUS
  299. EFIAPI
  300. QemuFwCfgFindFile (
  301. IN CONST CHAR8 *Name,
  302. OUT FIRMWARE_CONFIG_ITEM *Item,
  303. OUT UINTN *Size
  304. )
  305. {
  306. UINT32 Count;
  307. UINT32 Idx;
  308. if (!InternalQemuFwCfgIsAvailable ()) {
  309. return RETURN_UNSUPPORTED;
  310. }
  311. QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
  312. Count = SwapBytes32 (QemuFwCfgRead32 ());
  313. for (Idx = 0; Idx < Count; ++Idx) {
  314. UINT32 FileSize;
  315. UINT16 FileSelect;
  316. CHAR8 FileName[QEMU_FW_CFG_FNAME_SIZE];
  317. FileSize = QemuFwCfgRead32 ();
  318. FileSelect = QemuFwCfgRead16 ();
  319. QemuFwCfgRead16 (); // skip the field called "reserved"
  320. InternalQemuFwCfgReadBytes (sizeof (FileName), FileName);
  321. if (AsciiStrCmp (Name, FileName) == 0) {
  322. *Item = SwapBytes16 (FileSelect);
  323. *Size = SwapBytes32 (FileSize);
  324. return RETURN_SUCCESS;
  325. }
  326. }
  327. return RETURN_NOT_FOUND;
  328. }
  329. /**
  330. firmware config initialize.
  331. @param VOID
  332. @return RETURN_SUCCESS Initialization succeeded.
  333. **/
  334. RETURN_STATUS
  335. EFIAPI
  336. QemuFwCfgInitialize (
  337. VOID
  338. )
  339. {
  340. VOID *DeviceTreeBase;
  341. INT32 Node;
  342. INT32 Prev;
  343. CONST CHAR8 *Type;
  344. INT32 Len;
  345. CONST UINT64 *RegProp;
  346. UINT64 FwCfgSelectorAddress;
  347. UINT64 FwCfgDataAddress;
  348. UINT64 FwCfgDataSize;
  349. RETURN_STATUS PcdStatus;
  350. DeviceTreeBase = (VOID *) (UINTN)PcdGet64 (PcdDeviceTreeBase);
  351. ASSERT (DeviceTreeBase != NULL);
  352. //
  353. // Make sure we have a valid device tree blob
  354. //
  355. ASSERT (fdt_check_header (DeviceTreeBase) == 0);
  356. for (Prev = 0;; Prev = Node) {
  357. Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
  358. if (Node < 0) {
  359. break;
  360. }
  361. //
  362. // Check for memory node
  363. //
  364. Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
  365. if ((Type)
  366. && (AsciiStrnCmp (Type, "qemu,fw-cfg-mmio", Len) == 0))
  367. {
  368. //
  369. // Get the 'reg' property of this node. For now, we will assume
  370. // two 8 byte quantities for base and size, respectively.
  371. //
  372. RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
  373. if ((RegProp != 0)
  374. && (Len == (2 * sizeof (UINT64))))
  375. {
  376. FwCfgDataAddress = SwapBytes64 (RegProp[0]);
  377. FwCfgDataSize = 8;
  378. FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
  379. mFwCfgSelectorAddress = FwCfgSelectorAddress;
  380. mFwCfgDataAddress = FwCfgDataAddress;
  381. PcdStatus = PcdSet64S (
  382. PcdFwCfgSelectorAddress,
  383. FwCfgSelectorAddress
  384. );
  385. ASSERT_RETURN_ERROR (PcdStatus);
  386. PcdStatus = PcdSet64S (
  387. PcdFwCfgDataAddress,
  388. FwCfgDataAddress
  389. );
  390. ASSERT_RETURN_ERROR (PcdStatus);
  391. break;
  392. } else {
  393. DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT QemuCfg node\n",
  394. __FUNCTION__));
  395. break;
  396. }
  397. }
  398. }
  399. return RETURN_SUCCESS;
  400. }