NorFlashKvmtool.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /** @file
  2. An instance of the NorFlashPlatformLib for Kvmtool platform.
  3. Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Library/BaseLib.h>
  7. #include <Library/DebugLib.h>
  8. #include <Library/NorFlashPlatformLib.h>
  9. #include <Library/UefiBootServicesTableLib.h>
  10. #include <Protocol/FdtClient.h>
  11. /** Macro defining the NOR block size configured in Kvmtool.
  12. */
  13. #define KVMTOOL_NOR_BLOCK_SIZE SIZE_64KB
  14. /** Macro defining the maximum number of Flash devices.
  15. */
  16. #define MAX_FLASH_DEVICES 4
  17. /** Macro defining the cfi-flash label describing the UEFI variable store.
  18. */
  19. #define LABEL_UEFI_VAR_STORE "System-firmware"
  20. STATIC NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_DEVICES];
  21. STATIC UINTN mNorFlashDeviceCount = 0;
  22. STATIC INT32 mUefiVarStoreNode = MAX_INT32;
  23. STATIC FDT_CLIENT_PROTOCOL *mFdtClient;
  24. /** This function performs platform specific actions to initialise
  25. the NOR flash, if required.
  26. @retval EFI_SUCCESS Success.
  27. **/
  28. EFI_STATUS
  29. NorFlashPlatformInitialization (
  30. VOID
  31. )
  32. {
  33. EFI_STATUS Status;
  34. DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
  35. if ((mNorFlashDeviceCount > 0) && (mUefiVarStoreNode != MAX_INT32)) {
  36. //
  37. // UEFI takes ownership of the cfi-flash hardware, and exposes its
  38. // functionality through the UEFI Runtime Variable Service. This means we
  39. // need to disable it in the device tree to prevent the OS from attaching
  40. // its device driver as well.
  41. // Note: This library is loaded twice. First by FaultTolerantWriteDxe to
  42. // setup the PcdFlashNvStorageFtw* and later by NorFlashDxe to provide the
  43. // NorFlashPlatformLib interfaces. If the node is disabled when the library
  44. // is first loaded, then during the subsequent loading of the library the
  45. // call to FindNextCompatibleNode() from the library constructor skips the
  46. // FDT node used for UEFI storage variable. Due to this we cannot setup the
  47. // NOR flash device description i.e. mNorFlashDevices[].
  48. // Since NorFlashPlatformInitialization() is called only by NorFlashDxe,
  49. // we know it is safe to disable the node here.
  50. //
  51. Status = mFdtClient->SetNodeProperty (
  52. mFdtClient,
  53. mUefiVarStoreNode,
  54. "status",
  55. "disabled",
  56. sizeof ("disabled")
  57. );
  58. if (EFI_ERROR (Status)) {
  59. DEBUG ((DEBUG_WARN, "Failed to set cfi-flash status to 'disabled'\n"));
  60. }
  61. } else {
  62. Status = EFI_NOT_FOUND;
  63. DEBUG ((DEBUG_ERROR, "Flash device for UEFI variable storage not found\n"));
  64. }
  65. return Status;
  66. }
  67. /** Initialise Non volatile Flash storage variables.
  68. @param [in] FlashDevice Pointer to the NOR Flash device.
  69. @retval EFI_SUCCESS Success.
  70. @retval EFI_INVALID_PARAMETER A parameter is invalid.
  71. @retval EFI_OUT_OF_RESOURCES Insufficient flash storage space.
  72. **/
  73. STATIC
  74. EFI_STATUS
  75. SetupVariableStore (
  76. IN NOR_FLASH_DESCRIPTION *FlashDevice
  77. )
  78. {
  79. UINTN FlashRegion;
  80. UINTN FlashNvStorageVariableBase;
  81. UINTN FlashNvStorageFtwWorkingBase;
  82. UINTN FlashNvStorageFtwSpareBase;
  83. UINTN FlashNvStorageVariableSize;
  84. UINTN FlashNvStorageFtwWorkingSize;
  85. UINTN FlashNvStorageFtwSpareSize;
  86. FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
  87. FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
  88. FlashNvStorageFtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize);
  89. if ((FlashNvStorageVariableSize == 0) ||
  90. (FlashNvStorageFtwWorkingSize == 0) ||
  91. (FlashNvStorageFtwSpareSize == 0))
  92. {
  93. DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
  94. return EFI_INVALID_PARAMETER;
  95. }
  96. // Setup the variable store
  97. FlashRegion = FlashDevice->DeviceBaseAddress;
  98. FlashNvStorageVariableBase = FlashRegion;
  99. FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);
  100. FlashNvStorageFtwWorkingBase = FlashRegion;
  101. FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
  102. FlashNvStorageFtwSpareBase = FlashRegion;
  103. FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);
  104. if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {
  105. DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
  106. return EFI_OUT_OF_RESOURCES;
  107. }
  108. PcdSet32S (
  109. PcdFlashNvStorageVariableBase,
  110. FlashNvStorageVariableBase
  111. );
  112. PcdSet32S (
  113. PcdFlashNvStorageFtwWorkingBase,
  114. FlashNvStorageFtwWorkingBase
  115. );
  116. PcdSet32S (
  117. PcdFlashNvStorageFtwSpareBase,
  118. FlashNvStorageFtwSpareBase
  119. );
  120. DEBUG ((
  121. DEBUG_INFO,
  122. "PcdFlashNvStorageVariableBase = 0x%x\n",
  123. FlashNvStorageVariableBase
  124. ));
  125. DEBUG ((
  126. DEBUG_INFO,
  127. "PcdFlashNvStorageVariableSize = 0x%x\n",
  128. FlashNvStorageVariableSize
  129. ));
  130. DEBUG ((
  131. DEBUG_INFO,
  132. "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
  133. FlashNvStorageFtwWorkingBase
  134. ));
  135. DEBUG ((
  136. DEBUG_INFO,
  137. "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
  138. FlashNvStorageFtwWorkingSize
  139. ));
  140. DEBUG ((
  141. DEBUG_INFO,
  142. "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
  143. FlashNvStorageFtwSpareBase
  144. ));
  145. DEBUG ((
  146. DEBUG_INFO,
  147. "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
  148. FlashNvStorageFtwSpareSize
  149. ));
  150. return EFI_SUCCESS;
  151. }
  152. /** Return the Flash devices on the platform.
  153. @param [out] NorFlashDescriptions Pointer to the Flash device description.
  154. @param [out] Count Number of Flash devices.
  155. @retval EFI_SUCCESS Success.
  156. @retval EFI_NOT_FOUND Flash device not found.
  157. **/
  158. EFI_STATUS
  159. NorFlashPlatformGetDevices (
  160. OUT NOR_FLASH_DESCRIPTION **NorFlashDescriptions,
  161. OUT UINT32 *Count
  162. )
  163. {
  164. if (mNorFlashDeviceCount > 0) {
  165. *NorFlashDescriptions = mNorFlashDevices;
  166. *Count = mNorFlashDeviceCount;
  167. return EFI_SUCCESS;
  168. }
  169. return EFI_NOT_FOUND;
  170. }
  171. /** Entrypoint for NorFlashPlatformLib.
  172. @param [in] ImageHandle The handle to the image.
  173. @param [in] SystemTable Pointer to the System Table.
  174. @retval EFI_SUCCESS Success.
  175. @retval EFI_INVALID_PARAMETER A parameter is invalid.
  176. @retval EFI_NOT_FOUND Flash device not found.
  177. **/
  178. EFI_STATUS
  179. EFIAPI
  180. NorFlashPlatformLibConstructor (
  181. IN EFI_HANDLE ImageHandle,
  182. IN EFI_SYSTEM_TABLE *SystemTable
  183. )
  184. {
  185. INT32 Node;
  186. EFI_STATUS Status;
  187. EFI_STATUS FindNodeStatus;
  188. CONST UINT32 *Reg;
  189. UINT32 PropSize;
  190. UINT64 Base;
  191. UINT64 Size;
  192. UINTN UefiVarStoreIndex;
  193. CONST CHAR8 *Label;
  194. UINT32 LabelLen;
  195. if (mNorFlashDeviceCount != 0) {
  196. return EFI_SUCCESS;
  197. }
  198. Status = gBS->LocateProtocol (
  199. &gFdtClientProtocolGuid,
  200. NULL,
  201. (VOID **)&mFdtClient
  202. );
  203. ASSERT_EFI_ERROR (Status);
  204. UefiVarStoreIndex = MAX_UINTN;
  205. for (FindNodeStatus = mFdtClient->FindCompatibleNode (
  206. mFdtClient,
  207. "cfi-flash",
  208. &Node
  209. );
  210. !EFI_ERROR (FindNodeStatus) &&
  211. (mNorFlashDeviceCount < MAX_FLASH_DEVICES);
  212. FindNodeStatus = mFdtClient->FindNextCompatibleNode (
  213. mFdtClient,
  214. "cfi-flash",
  215. Node,
  216. &Node
  217. ))
  218. {
  219. Status = mFdtClient->GetNodeProperty (
  220. mFdtClient,
  221. Node,
  222. "label",
  223. (CONST VOID **)&Label,
  224. &LabelLen
  225. );
  226. if (EFI_ERROR (Status)) {
  227. DEBUG ((
  228. DEBUG_ERROR,
  229. "%a: GetNodeProperty ('label') failed (Status == %r)\n",
  230. __FUNCTION__,
  231. Status
  232. ));
  233. } else if (AsciiStrCmp (Label, LABEL_UEFI_VAR_STORE) == 0) {
  234. UefiVarStoreIndex = mNorFlashDeviceCount;
  235. mUefiVarStoreNode = Node;
  236. }
  237. Status = mFdtClient->GetNodeProperty (
  238. mFdtClient,
  239. Node,
  240. "reg",
  241. (CONST VOID **)&Reg,
  242. &PropSize
  243. );
  244. if (EFI_ERROR (Status)) {
  245. DEBUG ((
  246. DEBUG_ERROR,
  247. "%a: GetNodeProperty () failed (Status == %r)\n",
  248. __FUNCTION__,
  249. Status
  250. ));
  251. continue;
  252. }
  253. ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
  254. while ((PropSize >= (4 * sizeof (UINT32))) &&
  255. (mNorFlashDeviceCount < MAX_FLASH_DEVICES))
  256. {
  257. Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
  258. Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
  259. Reg += 4;
  260. PropSize -= 4 * sizeof (UINT32);
  261. //
  262. // Disregard any flash devices that overlap with the primary FV.
  263. // The firmware is not updatable from inside the guest anyway.
  264. //
  265. if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
  266. ((Base + Size) > PcdGet64 (PcdFvBaseAddress)))
  267. {
  268. continue;
  269. }
  270. DEBUG ((
  271. DEBUG_INFO,
  272. "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
  273. mNorFlashDeviceCount,
  274. Base,
  275. Size
  276. ));
  277. mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;
  278. mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;
  279. mNorFlashDevices[mNorFlashDeviceCount].Size = (UINTN)Size;
  280. mNorFlashDevices[mNorFlashDeviceCount].BlockSize = KVMTOOL_NOR_BLOCK_SIZE;
  281. mNorFlashDeviceCount++;
  282. }
  283. } // for
  284. // Setup the variable store in the last device
  285. if (mNorFlashDeviceCount > 0) {
  286. if (UefiVarStoreIndex == MAX_UINTN) {
  287. // We did not find a label matching the UEFI Variable store. Default to
  288. // using the last cfi-flash device as the variable store.
  289. UefiVarStoreIndex = mNorFlashDeviceCount - 1;
  290. mUefiVarStoreNode = Node;
  291. }
  292. if (mNorFlashDevices[UefiVarStoreIndex].DeviceBaseAddress != 0) {
  293. return SetupVariableStore (&mNorFlashDevices[UefiVarStoreIndex]);
  294. }
  295. }
  296. return EFI_NOT_FOUND;
  297. }