VariableSupport.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /** @file
  2. UEFI variable support functions for Firmware Management Protocol based
  3. firmware updates.
  4. Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
  5. Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. #include <PiDxe.h>
  9. #include <Library/DebugLib.h>
  10. #include <Library/UefiBootServicesTableLib.h>
  11. #include <Library/UefiRuntimeServicesTableLib.h>
  12. #include <Library/UefiLib.h>
  13. #include <Library/MemoryAllocationLib.h>
  14. #include <Protocol/VariableLock.h>
  15. #include "VariableSupport.h"
  16. ///
  17. /// Array of UEFI variable names that are locked in LockAllFmpVariables().
  18. ///
  19. const CHAR16 *mFmpVariableLockList[] = {
  20. VARNAME_VERSION,
  21. VARNAME_LSV,
  22. VARNAME_LASTATTEMPTSTATUS,
  23. VARNAME_LASTATTEMPTVERSION
  24. };
  25. /**
  26. Returns the value used to fill in the Version field of the
  27. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  28. service of the Firmware Management Protocol. The value is read from a UEFI
  29. variable. If the UEFI variables does not exist, then a default version value
  30. is returned.
  31. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
  32. @return The version of the firmware image in the firmware device.
  33. **/
  34. UINT32
  35. GetVersionFromVariable (
  36. VOID
  37. )
  38. {
  39. EFI_STATUS Status;
  40. UINT32 *Value;
  41. UINTN Size;
  42. UINT32 Version;
  43. Value = NULL;
  44. Size = 0;
  45. Version = DEFAULT_VERSION;
  46. Status = GetVariable2 (VARNAME_VERSION, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
  47. if (EFI_ERROR (Status) || (Value == NULL)) {
  48. DEBUG ((DEBUG_ERROR, "Failed to get the Version from variable. Status = %r\n", Status));
  49. return Version;
  50. }
  51. //
  52. // No error from call
  53. //
  54. if (Size == sizeof (*Value)) {
  55. //
  56. // Successful read
  57. //
  58. Version = *Value;
  59. } else {
  60. //
  61. // Return default since size was unknown
  62. //
  63. DEBUG ((DEBUG_ERROR, "Getting version Variable returned a size different than expected. Size = 0x%x\n", Size));
  64. }
  65. FreePool (Value);
  66. return Version;
  67. }
  68. /**
  69. Returns the value used to fill in the LowestSupportedVersion field of the
  70. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  71. service of the Firmware Management Protocol. The value is read from a UEFI
  72. variable. If the UEFI variables does not exist, then a default lowest
  73. supported version value is returned.
  74. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"
  75. @return The lowest supported version of the firmware image in the firmware
  76. device.
  77. **/
  78. UINT32
  79. GetLowestSupportedVersionFromVariable (
  80. VOID
  81. )
  82. {
  83. EFI_STATUS Status;
  84. UINT32 *Value;
  85. UINTN Size;
  86. UINT32 Version;
  87. Value = NULL;
  88. Size = 0;
  89. Version = DEFAULT_LOWESTSUPPORTEDVERSION;
  90. Status = GetVariable2 (VARNAME_LSV, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
  91. if (EFI_ERROR (Status) || (Value == NULL)) {
  92. DEBUG ((DEBUG_WARN, "Warning: Failed to get the Lowest Supported Version from variable. Status = %r\n", Status));
  93. return Version;
  94. }
  95. //
  96. // No error from call
  97. //
  98. if (Size == sizeof (*Value)) {
  99. //
  100. // Successful read
  101. //
  102. Version = *Value;
  103. } else {
  104. //
  105. // Return default since size was unknown
  106. //
  107. DEBUG ((DEBUG_ERROR, "Getting LSV Variable returned a size different than expected. Size = 0x%x\n", Size));
  108. }
  109. FreePool (Value);
  110. return Version;
  111. }
  112. /**
  113. Returns the value used to fill in the LastAttemptStatus field of the
  114. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  115. service of the Firmware Management Protocol. The value is read from a UEFI
  116. variable. If the UEFI variables does not exist, then a default last attempt
  117. status value is returned.
  118. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"
  119. @return The last attempt status value for the most recent capsule update.
  120. **/
  121. UINT32
  122. GetLastAttemptStatusFromVariable (
  123. VOID
  124. )
  125. {
  126. EFI_STATUS Status;
  127. UINT32 *Value;
  128. UINTN Size;
  129. UINT32 LastAttemptStatus;
  130. Value = NULL;
  131. Size = 0;
  132. LastAttemptStatus = DEFAULT_LASTATTEMPT;
  133. Status = GetVariable2 (VARNAME_LASTATTEMPTSTATUS, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
  134. if (EFI_ERROR (Status) || (Value == NULL)) {
  135. DEBUG ((DEBUG_WARN, "Warning: Failed to get the Last Attempt Status from variable. Status = %r\n", Status));
  136. return LastAttemptStatus;
  137. }
  138. //
  139. // No error from call
  140. //
  141. if (Size == sizeof (*Value)) {
  142. //
  143. // Successful read
  144. //
  145. LastAttemptStatus = *Value;
  146. } else {
  147. //
  148. // Return default since size was unknown
  149. //
  150. DEBUG (
  151. (DEBUG_ERROR,
  152. "Getting Last Attempt Status Variable returned a size different than expected. Size = 0x%x\n",
  153. Size)
  154. );
  155. }
  156. FreePool (Value);
  157. return LastAttemptStatus;
  158. }
  159. /**
  160. Returns the value used to fill in the LastAttemptVersion field of the
  161. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  162. service of the Firmware Management Protocol. The value is read from a UEFI
  163. variable. If the UEFI variables does not exist, then a default last attempt
  164. version value is returned.
  165. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"
  166. @return The last attempt version value for the most recent capsule update.
  167. **/
  168. UINT32
  169. GetLastAttemptVersionFromVariable (
  170. VOID
  171. )
  172. {
  173. EFI_STATUS Status;
  174. UINT32 *Value;
  175. UINTN Size;
  176. UINT32 Version;
  177. Value = NULL;
  178. Size = 0;
  179. Version = DEFAULT_LASTATTEMPT;
  180. Status = GetVariable2 (VARNAME_LASTATTEMPTVERSION, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
  181. if (EFI_ERROR (Status) || (Value == NULL)) {
  182. DEBUG ((DEBUG_WARN, "Warning: Failed to get the Last Attempt Version from variable. Status = %r\n", Status));
  183. return Version;
  184. }
  185. //
  186. // No error from call
  187. //
  188. if (Size == sizeof (*Value)) {
  189. //
  190. // Successful read
  191. //
  192. Version = *Value;
  193. } else {
  194. //
  195. // Return default since size was unknown
  196. //
  197. DEBUG (
  198. (DEBUG_ERROR,
  199. "Getting Last Attempt Version variable returned a size different than expected. Size = 0x%x\n",
  200. Size)
  201. );
  202. }
  203. FreePool (Value);
  204. return Version;
  205. }
  206. /**
  207. Saves the version current of the firmware image in the firmware device to a
  208. UEFI variable.
  209. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
  210. @param[in] Version The version of the firmware image in the firmware device.
  211. **/
  212. VOID
  213. SetVersionInVariable (
  214. UINT32 Version
  215. )
  216. {
  217. EFI_STATUS Status;
  218. UINT32 Current;
  219. Status = EFI_SUCCESS;
  220. Current = GetVersionFromVariable();
  221. if (Current != Version) {
  222. Status = gRT->SetVariable (
  223. VARNAME_VERSION,
  224. &gEfiCallerIdGuid,
  225. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  226. sizeof (Version),
  227. &Version
  228. );
  229. if (EFI_ERROR (Status)) {
  230. DEBUG ((DEBUG_ERROR, "Failed to set the Version into a variable. Status = %r\n", Status));
  231. }
  232. } else {
  233. DEBUG ((DEBUG_INFO, "Version variable doesn't need to update. Same value as before.\n"));
  234. }
  235. }
  236. /**
  237. Saves the lowest supported version current of the firmware image in the
  238. firmware device to a UEFI variable.
  239. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"
  240. @param[in] LowestSupportedVersion The lowest supported version of the firmware image
  241. in the firmware device.
  242. **/
  243. VOID
  244. SetLowestSupportedVersionInVariable (
  245. UINT32 LowestSupportedVersion
  246. )
  247. {
  248. EFI_STATUS Status;
  249. UINT32 Current;
  250. Status = EFI_SUCCESS;
  251. Current = GetLowestSupportedVersionFromVariable();
  252. if (LowestSupportedVersion > Current) {
  253. Status = gRT->SetVariable (
  254. VARNAME_LSV,
  255. &gEfiCallerIdGuid,
  256. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  257. sizeof (LowestSupportedVersion), &LowestSupportedVersion
  258. );
  259. if (EFI_ERROR (Status)) {
  260. DEBUG ((DEBUG_ERROR, "Failed to set the LSV into a variable. Status = %r\n", Status));
  261. }
  262. } else {
  263. DEBUG ((DEBUG_INFO, "LSV variable doesn't need to update. Same value as before.\n"));
  264. }
  265. }
  266. /**
  267. Saves the last attempt status value of the most recent FMP capsule update to a
  268. UEFI variable.
  269. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"
  270. @param[in] LastAttemptStatus The last attempt status of the most recent FMP
  271. capsule update.
  272. **/
  273. VOID
  274. SetLastAttemptStatusInVariable (
  275. UINT32 LastAttemptStatus
  276. )
  277. {
  278. EFI_STATUS Status;
  279. UINT32 Current;
  280. Status = EFI_SUCCESS;
  281. Current = GetLastAttemptStatusFromVariable();
  282. if (Current != LastAttemptStatus) {
  283. Status = gRT->SetVariable (
  284. VARNAME_LASTATTEMPTSTATUS,
  285. &gEfiCallerIdGuid,
  286. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  287. sizeof (LastAttemptStatus),
  288. &LastAttemptStatus
  289. );
  290. if (EFI_ERROR (Status)) {
  291. DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptStatus into a variable. Status = %r\n", Status));
  292. }
  293. } else {
  294. DEBUG ((DEBUG_INFO, "LastAttemptStatus variable doesn't need to update. Same value as before.\n"));
  295. }
  296. }
  297. /**
  298. Saves the last attempt version value of the most recent FMP capsule update to
  299. a UEFI variable.
  300. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"
  301. @param[in] LastAttemptVersion The last attempt version value of the most
  302. recent FMP capsule update.
  303. **/
  304. VOID
  305. SetLastAttemptVersionInVariable (
  306. UINT32 LastAttemptVersion
  307. )
  308. {
  309. EFI_STATUS Status;
  310. UINT32 Current;
  311. Status = EFI_SUCCESS;
  312. Current = GetLastAttemptVersionFromVariable();
  313. if (Current != LastAttemptVersion) {
  314. Status = gRT->SetVariable (
  315. VARNAME_LASTATTEMPTVERSION,
  316. &gEfiCallerIdGuid,
  317. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  318. sizeof (LastAttemptVersion),
  319. &LastAttemptVersion
  320. );
  321. if (EFI_ERROR (Status)) {
  322. DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptVersion into a variable. Status = %r\n", Status));
  323. }
  324. } else {
  325. DEBUG ((DEBUG_INFO, "LastAttemptVersion variable doesn't need to update. Same value as before.\n"));
  326. }
  327. }
  328. /**
  329. Locks all the UEFI Variables used by this module.
  330. @retval EFI_SUCCESS All UEFI variables are locked.
  331. @retval EFI_UNSUPPORTED Variable Lock Protocol not found.
  332. @retval Other One of the UEFI variables could not be locked.
  333. **/
  334. EFI_STATUS
  335. LockAllFmpVariables (
  336. VOID
  337. )
  338. {
  339. EFI_STATUS Status;
  340. EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
  341. EFI_STATUS ReturnStatus;
  342. UINTN Index;
  343. VariableLock = NULL;
  344. Status = gBS->LocateProtocol (
  345. &gEdkiiVariableLockProtocolGuid,
  346. NULL,
  347. (VOID **)&VariableLock
  348. );
  349. if (EFI_ERROR (Status)) {
  350. DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to locate Variable Lock Protocol (%r).\n", Status));
  351. return EFI_UNSUPPORTED;
  352. }
  353. ReturnStatus = EFI_SUCCESS;
  354. for (Index = 0; Index < ARRAY_SIZE (mFmpVariableLockList); Index++) {
  355. Status = VariableLock->RequestToLock (
  356. VariableLock,
  357. (CHAR16 *)mFmpVariableLockList[Index],
  358. &gEfiCallerIdGuid
  359. );
  360. if (EFI_ERROR (Status)) {
  361. DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variable %g %s. Status = %r\n",
  362. &gEfiCallerIdGuid,
  363. mFmpVariableLockList[Index],
  364. Status
  365. ));
  366. if (!EFI_ERROR (ReturnStatus)) {
  367. ReturnStatus = Status;
  368. }
  369. }
  370. }
  371. return ReturnStatus;
  372. }