VariableSupport.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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 - 2021, Intel Corporation. All rights reserved.<BR>
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. #include "FmpDxe.h"
  9. #include "VariableSupport.h"
  10. /**
  11. Retrieve the value of a 32-bit UEFI Variable specified by VariableName and
  12. a GUID of gEfiCallerIdGuid.
  13. @param[in] VariableName Pointer to the UEFI Variable name to retrieve.
  14. @param[out] Valid Set to TRUE if UEFI Variable is present and the size
  15. of the UEFI Variable value is 32-bits. Otherwise
  16. FALSE.
  17. @param[out] Value If Valid is set to TRUE, then the 32-bit value of
  18. the UEFI Variable. Otherwise 0.
  19. **/
  20. static
  21. VOID
  22. GetFmpVariable (
  23. IN CHAR16 *VariableName,
  24. OUT BOOLEAN *Valid,
  25. OUT UINT32 *Value
  26. )
  27. {
  28. EFI_STATUS Status;
  29. UINTN Size;
  30. UINT32 *Buffer;
  31. *Valid = FALSE;
  32. *Value = 0;
  33. Size = 0;
  34. Buffer = NULL;
  35. Status = GetVariable2 (
  36. VariableName,
  37. &gEfiCallerIdGuid,
  38. (VOID **)&Buffer,
  39. &Size
  40. );
  41. if (!EFI_ERROR (Status) && (Size == sizeof (*Value)) && (Buffer != NULL)) {
  42. *Valid = TRUE;
  43. *Value = *Buffer;
  44. }
  45. if (Buffer != NULL) {
  46. FreePool (Buffer);
  47. }
  48. }
  49. /**
  50. Delete the UEFI Variable with name specified by VariableName and GUID of
  51. gEfiCallerIdGuid. If the variable can not be deleted, then print a
  52. DEBUG_ERROR message.
  53. @param[in] VariableName Pointer to the UEFI Variable name to delete.
  54. **/
  55. static
  56. VOID
  57. DeleteFmpVariable (
  58. IN CHAR16 *VariableName
  59. )
  60. {
  61. EFI_STATUS Status;
  62. BOOLEAN Valid;
  63. UINT32 Value;
  64. GetFmpVariable (VariableName, &Valid, &Value);
  65. if (Valid) {
  66. Status = gRT->SetVariable (VariableName, &gEfiCallerIdGuid, 0, 0, NULL);
  67. if (EFI_ERROR (Status)) {
  68. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to delete variable %s. Status = %r\n", mImageIdName, VariableName, Status));
  69. } else {
  70. DEBUG ((DEBUG_INFO, "FmpDxe(%s): Deleted variable %s\n", mImageIdName, VariableName));
  71. }
  72. }
  73. }
  74. /**
  75. Retrieve the FMP Controller State UEFI Variable value. Return NULL if
  76. the variable does not exist or if the size of the UEFI Variable is not the
  77. size of FMP_CONTROLLER_STATE. The buffer for the UEFI Variable value
  78. if allocated using the UEFI Boot Service AllocatePool().
  79. @param[in] Private Private context structure for the managed controller.
  80. @return Pointer to the allocated FMP Controller State. Returns NULL
  81. if the variable does not exist or is a different size than expected.
  82. **/
  83. static
  84. FMP_CONTROLLER_STATE *
  85. GetFmpControllerState (
  86. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private
  87. )
  88. {
  89. EFI_STATUS Status;
  90. FMP_CONTROLLER_STATE *FmpControllerState;
  91. UINTN Size;
  92. FmpControllerState = NULL;
  93. Size = 0;
  94. Status = GetVariable2 (
  95. Private->FmpStateVariableName,
  96. &gEfiCallerIdGuid,
  97. (VOID **)&FmpControllerState,
  98. &Size
  99. );
  100. if (EFI_ERROR (Status) || (FmpControllerState == NULL)) {
  101. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to get the controller state. Status = %r\n", mImageIdName, Status));
  102. } else {
  103. if (Size == sizeof (*FmpControllerState)) {
  104. return FmpControllerState;
  105. }
  106. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Getting controller state returned a size different than expected. Size = 0x%x\n", mImageIdName, Size));
  107. }
  108. if (FmpControllerState != NULL) {
  109. FreePool (FmpControllerState);
  110. }
  111. return NULL;
  112. }
  113. /**
  114. Generates a Null-terminated Unicode string UEFI Variable name from a base name
  115. and a hardware instance. If the hardware instance value is 0, then the base
  116. name is returned. If the hardware instance value is non-zero, then the 64-bit
  117. hardware instance value is converted to a 16 character hex string and appended
  118. to base name. The UEFI Variable name returned is allocated using the UEFI
  119. Boot Service AllocatePool().
  120. @param[in] HardwareInstance 64-bit hardware instance value.
  121. @param[in] BaseVariableName Null-terminated Unicode string that is the base
  122. name of the UEFI Variable.
  123. @return Pointer to the allocated UEFI Variable name. Returns NULL if the
  124. UEFI Variable can not be allocated.
  125. **/
  126. static
  127. CHAR16 *
  128. GenerateFmpVariableName (
  129. IN UINT64 HardwareInstance,
  130. IN CHAR16 *BaseVariableName
  131. )
  132. {
  133. UINTN Size;
  134. CHAR16 *VariableName;
  135. //
  136. // Allocate Unicode string with room for BaseVariableName and a 16 digit
  137. // hexadecimal value for the HardwareInstance value.
  138. //
  139. Size = StrSize (BaseVariableName) + 16 * sizeof (CHAR16);
  140. VariableName = AllocateCopyPool (Size, BaseVariableName);
  141. if (VariableName == NULL) {
  142. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to generate variable name %s.\n", mImageIdName, BaseVariableName));
  143. return VariableName;
  144. }
  145. if (HardwareInstance == 0) {
  146. return VariableName;
  147. }
  148. UnicodeValueToStringS (
  149. &VariableName[StrLen (BaseVariableName)],
  150. Size,
  151. PREFIX_ZERO | RADIX_HEX,
  152. HardwareInstance,
  153. 16
  154. );
  155. return VariableName;
  156. }
  157. /**
  158. Generate the names of the UEFI Variables used to store state information for
  159. a managed controller. The UEFI Variables names are a combination of a base
  160. name and an optional hardware instance value as a 16 character hex value. If
  161. the hardware instance value is 0, then the 16 character hex value is not
  162. included. These storage for the UEFI Variable names are allocated using the
  163. UEFI Boot Service AllocatePool() and the pointers are stored in the Private.
  164. The following are examples of variable names produces for hardware instance
  165. value 0 and value 0x1234567812345678.
  166. FmpVersion
  167. FmpLsv
  168. LastAttemptStatus
  169. LastAttemptVersion
  170. FmpState
  171. FmpVersion1234567812345678
  172. FmpLsv1234567812345678
  173. LastAttemptStatus1234567812345678
  174. LastAttemptVersion1234567812345678
  175. FmpState1234567812345678
  176. @param[in,out] Private Private context structure for the managed controller.
  177. **/
  178. VOID
  179. GenerateFmpVariableNames (
  180. IN OUT FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private
  181. )
  182. {
  183. EFI_STATUS Status;
  184. VOID *Buffer;
  185. FMP_CONTROLLER_STATE FmpControllerState;
  186. if (Private->VersionVariableName != NULL) {
  187. FreePool (Private->VersionVariableName);
  188. }
  189. if (Private->LsvVariableName != NULL) {
  190. FreePool (Private->LsvVariableName);
  191. }
  192. if (Private->LastAttemptStatusVariableName != NULL) {
  193. FreePool (Private->LastAttemptStatusVariableName);
  194. }
  195. if (Private->LastAttemptVersionVariableName != NULL) {
  196. FreePool (Private->LastAttemptVersionVariableName);
  197. }
  198. if (Private->FmpStateVariableName != NULL) {
  199. FreePool (Private->FmpStateVariableName);
  200. }
  201. Private->VersionVariableName = GenerateFmpVariableName (
  202. Private->Descriptor.HardwareInstance,
  203. VARNAME_VERSION
  204. );
  205. Private->LsvVariableName = GenerateFmpVariableName (
  206. Private->Descriptor.HardwareInstance,
  207. VARNAME_LSV
  208. );
  209. Private->LastAttemptStatusVariableName = GenerateFmpVariableName (
  210. Private->Descriptor.HardwareInstance,
  211. VARNAME_LASTATTEMPTSTATUS
  212. );
  213. Private->LastAttemptVersionVariableName = GenerateFmpVariableName (
  214. Private->Descriptor.HardwareInstance,
  215. VARNAME_LASTATTEMPTVERSION
  216. );
  217. Private->FmpStateVariableName = GenerateFmpVariableName (
  218. Private->Descriptor.HardwareInstance,
  219. VARNAME_FMPSTATE
  220. );
  221. DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->VersionVariableName));
  222. DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LsvVariableName));
  223. DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LastAttemptStatusVariableName));
  224. DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LastAttemptVersionVariableName));
  225. DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->FmpStateVariableName));
  226. Buffer = GetFmpControllerState (Private);
  227. if (Buffer != NULL) {
  228. //
  229. // FMP Controller State was found with correct size.
  230. // Delete old variables if they exist.
  231. //
  232. FreePool (Buffer);
  233. DeleteFmpVariable (Private->VersionVariableName);
  234. DeleteFmpVariable (Private->LsvVariableName);
  235. DeleteFmpVariable (Private->LastAttemptStatusVariableName);
  236. DeleteFmpVariable (Private->LastAttemptVersionVariableName);
  237. return;
  238. }
  239. //
  240. // FMP Controller State was either not found or is wrong size.
  241. // Create a new FMP Controller State variable with the correct size.
  242. //
  243. DEBUG ((DEBUG_INFO, "FmpDxe(%s): Create controller state\n", mImageIdName));
  244. GetFmpVariable (
  245. Private->VersionVariableName,
  246. &FmpControllerState.VersionValid,
  247. &FmpControllerState.Version
  248. );
  249. GetFmpVariable (
  250. Private->LsvVariableName,
  251. &FmpControllerState.LsvValid,
  252. &FmpControllerState.Lsv
  253. );
  254. GetFmpVariable (
  255. Private->LastAttemptStatusVariableName,
  256. &FmpControllerState.LastAttemptStatusValid,
  257. &FmpControllerState.LastAttemptStatus
  258. );
  259. GetFmpVariable (
  260. Private->LastAttemptVersionVariableName,
  261. &FmpControllerState.LastAttemptVersionValid,
  262. &FmpControllerState.LastAttemptVersion
  263. );
  264. Status = gRT->SetVariable (
  265. Private->FmpStateVariableName,
  266. &gEfiCallerIdGuid,
  267. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  268. sizeof (FmpControllerState),
  269. &FmpControllerState
  270. );
  271. if (EFI_ERROR (Status)) {
  272. //
  273. // Failed to create FMP Controller State. In this case, do not
  274. // delete the individual variables. They can be used again on next boot
  275. // to create the FMP Controller State.
  276. //
  277. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to create controller state. Status = %r\n", mImageIdName, Status));
  278. } else {
  279. DeleteFmpVariable (Private->VersionVariableName);
  280. DeleteFmpVariable (Private->LsvVariableName);
  281. DeleteFmpVariable (Private->LastAttemptStatusVariableName);
  282. DeleteFmpVariable (Private->LastAttemptVersionVariableName);
  283. }
  284. }
  285. /**
  286. Returns the value used to fill in the Version field of the
  287. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  288. service of the Firmware Management Protocol. The value is read from a UEFI
  289. variable. If the UEFI variables does not exist, then a default version value
  290. is returned.
  291. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  292. @param[in] Private Private context structure for the managed controller.
  293. @return The version of the firmware image in the firmware device.
  294. **/
  295. UINT32
  296. GetVersionFromVariable (
  297. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private
  298. )
  299. {
  300. FMP_CONTROLLER_STATE *FmpControllerState;
  301. UINT32 Value;
  302. Value = DEFAULT_VERSION;
  303. FmpControllerState = GetFmpControllerState (Private);
  304. if (FmpControllerState != NULL) {
  305. if (FmpControllerState->VersionValid) {
  306. Value = FmpControllerState->Version;
  307. DEBUG ((
  308. DEBUG_INFO,
  309. "FmpDxe(%s): Get variable %g %s Version %08x\n",
  310. mImageIdName,
  311. &gEfiCallerIdGuid,
  312. Private->FmpStateVariableName,
  313. Value
  314. ));
  315. }
  316. FreePool (FmpControllerState);
  317. }
  318. return Value;
  319. }
  320. /**
  321. Returns the value used to fill in the LowestSupportedVersion field of the
  322. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  323. service of the Firmware Management Protocol. The value is read from a UEFI
  324. variable. If the UEFI variables does not exist, then a default lowest
  325. supported version value is returned.
  326. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  327. @param[in] Private Private context structure for the managed controller.
  328. @return The lowest supported version of the firmware image in the firmware
  329. device.
  330. **/
  331. UINT32
  332. GetLowestSupportedVersionFromVariable (
  333. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private
  334. )
  335. {
  336. FMP_CONTROLLER_STATE *FmpControllerState;
  337. UINT32 Value;
  338. Value = DEFAULT_LOWESTSUPPORTEDVERSION;
  339. FmpControllerState = GetFmpControllerState (Private);
  340. if (FmpControllerState != NULL) {
  341. if (FmpControllerState->LsvValid) {
  342. Value = FmpControllerState->Lsv;
  343. DEBUG ((
  344. DEBUG_INFO,
  345. "FmpDxe(%s): Get variable %g %s LowestSupportedVersion %08x\n",
  346. mImageIdName,
  347. &gEfiCallerIdGuid,
  348. Private->FmpStateVariableName,
  349. Value
  350. ));
  351. }
  352. FreePool (FmpControllerState);
  353. }
  354. return Value;
  355. }
  356. /**
  357. Returns the value used to fill in the LastAttemptStatus field of the
  358. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  359. service of the Firmware Management Protocol. The value is read from a UEFI
  360. variable. If the UEFI variables does not exist, then a default last attempt
  361. status value is returned.
  362. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  363. @param[in] Private Private context structure for the managed controller.
  364. @return The last attempt status value for the most recent capsule update.
  365. **/
  366. UINT32
  367. GetLastAttemptStatusFromVariable (
  368. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private
  369. )
  370. {
  371. FMP_CONTROLLER_STATE *FmpControllerState;
  372. UINT32 Value;
  373. Value = DEFAULT_LASTATTEMPTSTATUS;
  374. FmpControllerState = GetFmpControllerState (Private);
  375. if (FmpControllerState != NULL) {
  376. if (FmpControllerState->LastAttemptStatusValid) {
  377. Value = FmpControllerState->LastAttemptStatus;
  378. DEBUG ((
  379. DEBUG_INFO,
  380. "FmpDxe(%s): Get variable %g %s LastAttemptStatus %08x\n",
  381. mImageIdName,
  382. &gEfiCallerIdGuid,
  383. Private->FmpStateVariableName,
  384. Value
  385. ));
  386. }
  387. FreePool (FmpControllerState);
  388. }
  389. return Value;
  390. }
  391. /**
  392. Returns the value used to fill in the LastAttemptVersion field of the
  393. EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
  394. service of the Firmware Management Protocol. The value is read from a UEFI
  395. variable. If the UEFI variables does not exist, then a default last attempt
  396. version value is returned.
  397. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  398. @param[in] Private Private context structure for the managed controller.
  399. @return The last attempt version value for the most recent capsule update.
  400. **/
  401. UINT32
  402. GetLastAttemptVersionFromVariable (
  403. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private
  404. )
  405. {
  406. FMP_CONTROLLER_STATE *FmpControllerState;
  407. UINT32 Value;
  408. Value = DEFAULT_LASTATTEMPTVERSION;
  409. FmpControllerState = GetFmpControllerState (Private);
  410. if (FmpControllerState != NULL) {
  411. if (FmpControllerState->LastAttemptVersionValid) {
  412. Value = FmpControllerState->LastAttemptVersion;
  413. DEBUG ((
  414. DEBUG_INFO,
  415. "FmpDxe(%s): Get variable %g %s LastAttemptVersion %08x\n",
  416. mImageIdName,
  417. &gEfiCallerIdGuid,
  418. Private->FmpStateVariableName,
  419. Value
  420. ));
  421. }
  422. FreePool (FmpControllerState);
  423. }
  424. return Value;
  425. }
  426. /**
  427. Saves the version current of the firmware image in the firmware device to a
  428. UEFI variable.
  429. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  430. @param[in] Private Private context structure for the managed controller.
  431. @param[in] Version The version of the firmware image in the firmware device.
  432. **/
  433. VOID
  434. SetVersionInVariable (
  435. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,
  436. IN UINT32 Version
  437. )
  438. {
  439. EFI_STATUS Status;
  440. FMP_CONTROLLER_STATE *FmpControllerState;
  441. BOOLEAN Update;
  442. FmpControllerState = GetFmpControllerState (Private);
  443. if (FmpControllerState == NULL) {
  444. //
  445. // Can not update value if FMP Controller State does not exist.
  446. // This variable is guaranteed to be created by GenerateFmpVariableNames().
  447. //
  448. return;
  449. }
  450. Update = FALSE;
  451. if (!FmpControllerState->VersionValid) {
  452. Update = TRUE;
  453. }
  454. if (FmpControllerState->Version != Version) {
  455. Update = TRUE;
  456. }
  457. if (!Update) {
  458. DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));
  459. } else {
  460. FmpControllerState->VersionValid = TRUE;
  461. FmpControllerState->Version = Version;
  462. Status = gRT->SetVariable (
  463. Private->FmpStateVariableName,
  464. &gEfiCallerIdGuid,
  465. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  466. sizeof (*FmpControllerState),
  467. FmpControllerState
  468. );
  469. if (EFI_ERROR (Status)) {
  470. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));
  471. } else {
  472. DEBUG ((
  473. DEBUG_INFO,
  474. "FmpDxe(%s): Set variable %g %s Version %08x\n",
  475. mImageIdName,
  476. &gEfiCallerIdGuid,
  477. Private->FmpStateVariableName,
  478. Version
  479. ));
  480. }
  481. }
  482. FreePool (FmpControllerState);
  483. }
  484. /**
  485. Saves the lowest supported version current of the firmware image in the
  486. firmware device to a UEFI variable.
  487. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  488. @param[in] Private Private context structure for the managed
  489. controller.
  490. @param[in] LowestSupportedVersion The lowest supported version of the
  491. firmware image in the firmware device.
  492. **/
  493. VOID
  494. SetLowestSupportedVersionInVariable (
  495. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,
  496. IN UINT32 LowestSupportedVersion
  497. )
  498. {
  499. EFI_STATUS Status;
  500. FMP_CONTROLLER_STATE *FmpControllerState;
  501. BOOLEAN Update;
  502. FmpControllerState = GetFmpControllerState (Private);
  503. if (FmpControllerState == NULL) {
  504. //
  505. // Can not update value if FMP Controller State does not exist.
  506. // This variable is guaranteed to be created by GenerateFmpVariableNames().
  507. //
  508. return;
  509. }
  510. Update = FALSE;
  511. if (!FmpControllerState->LsvValid) {
  512. Update = TRUE;
  513. }
  514. if (FmpControllerState->Lsv < LowestSupportedVersion) {
  515. Update = TRUE;
  516. }
  517. if (!Update) {
  518. DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));
  519. } else {
  520. FmpControllerState->LsvValid = TRUE;
  521. FmpControllerState->Lsv = LowestSupportedVersion;
  522. Status = gRT->SetVariable (
  523. Private->FmpStateVariableName,
  524. &gEfiCallerIdGuid,
  525. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  526. sizeof (*FmpControllerState),
  527. FmpControllerState
  528. );
  529. if (EFI_ERROR (Status)) {
  530. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));
  531. } else {
  532. DEBUG ((
  533. DEBUG_INFO,
  534. "FmpDxe(%s): Set variable %g %s LowestSupportedVersion %08x\n",
  535. mImageIdName,
  536. &gEfiCallerIdGuid,
  537. Private->FmpStateVariableName,
  538. LowestSupportedVersion
  539. ));
  540. }
  541. }
  542. FreePool (FmpControllerState);
  543. }
  544. /**
  545. Saves the last attempt status value of the most recent FMP capsule update to a
  546. UEFI variable.
  547. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  548. @param[in] Private Private context structure for the managed
  549. controller.
  550. @param[in] LastAttemptStatus The last attempt status of the most recent FMP
  551. capsule update.
  552. **/
  553. VOID
  554. SetLastAttemptStatusInVariable (
  555. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,
  556. IN UINT32 LastAttemptStatus
  557. )
  558. {
  559. EFI_STATUS Status;
  560. FMP_CONTROLLER_STATE *FmpControllerState;
  561. BOOLEAN Update;
  562. FmpControllerState = GetFmpControllerState (Private);
  563. if (FmpControllerState == NULL) {
  564. //
  565. // Can not update value if FMP Controller State does not exist.
  566. // This variable is guaranteed to be created by GenerateFmpVariableNames().
  567. //
  568. return;
  569. }
  570. Update = FALSE;
  571. if (!FmpControllerState->LastAttemptStatusValid) {
  572. Update = TRUE;
  573. }
  574. if (FmpControllerState->LastAttemptStatus != LastAttemptStatus) {
  575. Update = TRUE;
  576. }
  577. if (!Update) {
  578. DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));
  579. } else {
  580. FmpControllerState->LastAttemptStatusValid = TRUE;
  581. FmpControllerState->LastAttemptStatus = LastAttemptStatus;
  582. Status = gRT->SetVariable (
  583. Private->FmpStateVariableName,
  584. &gEfiCallerIdGuid,
  585. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  586. sizeof (*FmpControllerState),
  587. FmpControllerState
  588. );
  589. if (EFI_ERROR (Status)) {
  590. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));
  591. } else {
  592. DEBUG ((
  593. DEBUG_INFO,
  594. "FmpDxe(%s): Set variable %g %s LastAttemptStatus %08x\n",
  595. mImageIdName,
  596. &gEfiCallerIdGuid,
  597. Private->FmpStateVariableName,
  598. LastAttemptStatus
  599. ));
  600. }
  601. }
  602. FreePool (FmpControllerState);
  603. }
  604. /**
  605. Saves the last attempt version value of the most recent FMP capsule update to
  606. a UEFI variable.
  607. UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
  608. @param[in] Private Private context structure for the managed
  609. controller.
  610. @param[in] LastAttemptVersion The last attempt version value of the most
  611. recent FMP capsule update.
  612. **/
  613. VOID
  614. SetLastAttemptVersionInVariable (
  615. IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,
  616. IN UINT32 LastAttemptVersion
  617. )
  618. {
  619. EFI_STATUS Status;
  620. FMP_CONTROLLER_STATE *FmpControllerState;
  621. BOOLEAN Update;
  622. FmpControllerState = GetFmpControllerState (Private);
  623. if (FmpControllerState == NULL) {
  624. //
  625. // Can not update value if FMP Controller State does not exist.
  626. // This variable is guaranteed to be created by GenerateFmpVariableNames().
  627. //
  628. return;
  629. }
  630. Update = FALSE;
  631. if (!FmpControllerState->LastAttemptVersionValid) {
  632. Update = TRUE;
  633. }
  634. if (FmpControllerState->LastAttemptVersion != LastAttemptVersion) {
  635. Update = TRUE;
  636. }
  637. if (!Update) {
  638. DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));
  639. } else {
  640. FmpControllerState->LastAttemptVersionValid = TRUE;
  641. FmpControllerState->LastAttemptVersion = LastAttemptVersion;
  642. Status = gRT->SetVariable (
  643. Private->FmpStateVariableName,
  644. &gEfiCallerIdGuid,
  645. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  646. sizeof (*FmpControllerState),
  647. FmpControllerState
  648. );
  649. if (EFI_ERROR (Status)) {
  650. DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));
  651. } else {
  652. DEBUG ((
  653. DEBUG_INFO,
  654. "FmpDxe(%s): Set variable %g %s LastAttemptVersion %08x\n",
  655. mImageIdName,
  656. &gEfiCallerIdGuid,
  657. Private->FmpStateVariableName,
  658. LastAttemptVersion
  659. ));
  660. }
  661. }
  662. FreePool (FmpControllerState);
  663. }
  664. /**
  665. Attempts to lock a single UEFI Variable propagating the error state of the
  666. first lock attempt that fails. Uses gEfiCallerIdGuid as the variable GUID.
  667. @param[in] PreviousStatus The previous UEFI Variable lock attempt status.
  668. @param[in] VariableLock The EDK II Variable Lock Protocol instance.
  669. @param[in] VariableName The name of the UEFI Variable to lock.
  670. @retval EFI_SUCCESS The UEFI Variable was locked and the previous variable
  671. lock attempt also succeeded.
  672. @retval Other The UEFI Variable could not be locked or the previous
  673. variable lock attempt failed.
  674. **/
  675. static
  676. EFI_STATUS
  677. LockFmpVariable (
  678. IN EFI_STATUS PreviousStatus,
  679. IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy,
  680. IN CHAR16 *VariableName
  681. )
  682. {
  683. EFI_STATUS Status;
  684. // If success, go ahead and set the policies to protect the target variables.
  685. Status = RegisterBasicVariablePolicy (
  686. VariablePolicy,
  687. &gEfiCallerIdGuid,
  688. VariableName,
  689. VARIABLE_POLICY_NO_MIN_SIZE,
  690. VARIABLE_POLICY_NO_MAX_SIZE,
  691. VARIABLE_POLICY_NO_MUST_ATTR,
  692. VARIABLE_POLICY_NO_CANT_ATTR,
  693. VARIABLE_POLICY_TYPE_LOCK_NOW
  694. );
  695. if (EFI_ERROR (Status)) {
  696. DEBUG ((
  697. DEBUG_ERROR,
  698. "FmpDxe(%s): Failed to lock variable %g %s. Status = %r\n",
  699. mImageIdName,
  700. &gEfiCallerIdGuid,
  701. VariableName,
  702. Status
  703. ));
  704. }
  705. if (EFI_ERROR (PreviousStatus)) {
  706. return PreviousStatus;
  707. }
  708. return Status;
  709. }
  710. /**
  711. Locks all the UEFI Variables that use gEfiCallerIdGuid of the currently
  712. executing module.
  713. @param[in] Private Private context structure for the managed controller.
  714. @retval EFI_SUCCESS All UEFI variables are locked.
  715. @retval EFI_UNSUPPORTED Variable Lock Protocol not found.
  716. @retval Other One of the UEFI variables could not be locked.
  717. **/
  718. EFI_STATUS
  719. LockAllFmpVariables (
  720. FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private
  721. )
  722. {
  723. EFI_STATUS Status;
  724. EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy;
  725. // Locate the VariablePolicy protocol.
  726. Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);
  727. if (EFI_ERROR (Status)) {
  728. DEBUG ((DEBUG_ERROR, "FmpDxe %a - Could not locate VariablePolicy protocol! %r\n", __FUNCTION__, Status));
  729. return Status;
  730. }
  731. Status = EFI_SUCCESS;
  732. Status = LockFmpVariable (Status, VariablePolicy, Private->VersionVariableName);
  733. Status = LockFmpVariable (Status, VariablePolicy, Private->LsvVariableName);
  734. Status = LockFmpVariable (Status, VariablePolicy, Private->LastAttemptStatusVariableName);
  735. Status = LockFmpVariable (Status, VariablePolicy, Private->LastAttemptVersionVariableName);
  736. Status = LockFmpVariable (Status, VariablePolicy, Private->FmpStateVariableName);
  737. return Status;
  738. }