FsAccess.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /** @file
  2. File System Access for NvVarsFileLib
  3. Copyright (c) 2004 - 2019 Intel Corporation. All rights reserved. <BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "NvVarsFileLib.h"
  7. #include <Library/BaseMemoryLib.h>
  8. #include <Library/DebugLib.h>
  9. #include <Library/MemoryAllocationLib.h>
  10. /**
  11. Open the NvVars file for reading or writing
  12. @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
  13. @param[in] ReadingFile - TRUE: open the file for reading. FALSE: writing
  14. @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated
  15. with the opened NvVars file.
  16. @return EFI_SUCCESS if the file was opened
  17. **/
  18. EFI_STATUS
  19. GetNvVarsFile (
  20. IN EFI_HANDLE FsHandle,
  21. IN BOOLEAN ReadingFile,
  22. OUT EFI_FILE_HANDLE *NvVarsFile
  23. )
  24. {
  25. EFI_STATUS Status;
  26. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
  27. EFI_FILE_HANDLE Root;
  28. //
  29. // Get the FileSystem protocol on that handle
  30. //
  31. Status = gBS->HandleProtocol (
  32. FsHandle,
  33. &gEfiSimpleFileSystemProtocolGuid,
  34. (VOID **)&Fs
  35. );
  36. if (EFI_ERROR (Status)) {
  37. return Status;
  38. }
  39. //
  40. // Get the volume (the root directory)
  41. //
  42. Status = Fs->OpenVolume (Fs, &Root);
  43. if (EFI_ERROR (Status)) {
  44. return Status;
  45. }
  46. //
  47. // Attempt to open the NvVars file in the root directory
  48. //
  49. Status = Root->Open (
  50. Root,
  51. NvVarsFile,
  52. L"NvVars",
  53. ReadingFile ?
  54. EFI_FILE_MODE_READ :
  55. (
  56. EFI_FILE_MODE_CREATE |
  57. EFI_FILE_MODE_READ |
  58. EFI_FILE_MODE_WRITE
  59. ),
  60. 0
  61. );
  62. return Status;
  63. }
  64. /**
  65. Open the NvVars file for reading or writing
  66. @param[in] File - The file to inspect
  67. @param[out] Exists - Returns whether the file exists
  68. @param[out] Size - Returns the size of the file
  69. (0 if the file does not exist)
  70. **/
  71. VOID
  72. NvVarsFileReadCheckup (
  73. IN EFI_FILE_HANDLE File,
  74. OUT BOOLEAN *Exists,
  75. OUT UINTN *Size
  76. )
  77. {
  78. EFI_FILE_INFO *FileInfo;
  79. *Exists = FALSE;
  80. *Size = 0;
  81. FileInfo = FileHandleGetInfo (File);
  82. if (FileInfo == NULL) {
  83. return;
  84. }
  85. if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
  86. FreePool (FileInfo);
  87. return;
  88. }
  89. *Exists = TRUE;
  90. *Size = (UINTN) FileInfo->FileSize;
  91. FreePool (FileInfo);
  92. }
  93. /**
  94. Open the NvVars file for reading or writing
  95. @param[in] File - The file to inspect
  96. @param[out] Exists - Returns whether the file exists
  97. @param[out] Size - Returns the size of the file
  98. (0 if the file does not exist)
  99. **/
  100. EFI_STATUS
  101. FileHandleEmpty (
  102. IN EFI_FILE_HANDLE File
  103. )
  104. {
  105. EFI_STATUS Status;
  106. EFI_FILE_INFO *FileInfo;
  107. //
  108. // Retrieve the FileInfo structure
  109. //
  110. FileInfo = FileHandleGetInfo (File);
  111. if (FileInfo == NULL) {
  112. return EFI_INVALID_PARAMETER;
  113. }
  114. //
  115. // If the path is a directory, then return an error
  116. //
  117. if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
  118. FreePool (FileInfo);
  119. return EFI_INVALID_PARAMETER;
  120. }
  121. //
  122. // If the file size is already 0, then it is empty, so
  123. // we can return success.
  124. //
  125. if (FileInfo->FileSize == 0) {
  126. FreePool (FileInfo);
  127. return EFI_SUCCESS;
  128. }
  129. //
  130. // Set the file size to 0.
  131. //
  132. FileInfo->FileSize = 0;
  133. Status = FileHandleSetInfo (File, FileInfo);
  134. FreePool (FileInfo);
  135. return Status;
  136. }
  137. /**
  138. Reads a file to a newly allocated buffer
  139. @param[in] File - The file to read
  140. @param[in] ReadSize - The size of data to read from the file
  141. @return Pointer to buffer allocated to hold the file
  142. contents. NULL if an error occurred.
  143. **/
  144. VOID*
  145. FileHandleReadToNewBuffer (
  146. IN EFI_FILE_HANDLE FileHandle,
  147. IN UINTN ReadSize
  148. )
  149. {
  150. EFI_STATUS Status;
  151. UINTN ActualReadSize;
  152. VOID *FileContents;
  153. ActualReadSize = ReadSize;
  154. FileContents = AllocatePool (ReadSize);
  155. if (FileContents != NULL) {
  156. Status = FileHandleRead (
  157. FileHandle,
  158. &ReadSize,
  159. FileContents
  160. );
  161. if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {
  162. FreePool (FileContents);
  163. return NULL;
  164. }
  165. }
  166. return FileContents;
  167. }
  168. /**
  169. Reads the contents of the NvVars file on the file system
  170. @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
  171. @return EFI_STATUS based on the success or failure of the file read
  172. **/
  173. EFI_STATUS
  174. ReadNvVarsFile (
  175. IN EFI_HANDLE FsHandle
  176. )
  177. {
  178. EFI_STATUS Status;
  179. EFI_FILE_HANDLE File;
  180. UINTN FileSize;
  181. BOOLEAN FileExists;
  182. VOID *FileContents;
  183. EFI_HANDLE SerializedVariables;
  184. Status = GetNvVarsFile (FsHandle, TRUE, &File);
  185. if (EFI_ERROR (Status)) {
  186. DEBUG ((EFI_D_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));
  187. return Status;
  188. }
  189. NvVarsFileReadCheckup (File, &FileExists, &FileSize);
  190. if (FileSize == 0) {
  191. FileHandleClose (File);
  192. return EFI_UNSUPPORTED;
  193. }
  194. FileContents = FileHandleReadToNewBuffer (File, FileSize);
  195. if (FileContents == NULL) {
  196. FileHandleClose (File);
  197. return EFI_UNSUPPORTED;
  198. }
  199. DEBUG ((
  200. EFI_D_INFO,
  201. "FsAccess.c: Read %Lu bytes from NV Variables file\n",
  202. (UINT64)FileSize
  203. ));
  204. Status = SerializeVariablesNewInstanceFromBuffer (
  205. &SerializedVariables,
  206. FileContents,
  207. FileSize
  208. );
  209. if (!RETURN_ERROR (Status)) {
  210. Status = SerializeVariablesSetSerializedVariables (SerializedVariables);
  211. }
  212. FreePool (FileContents);
  213. FileHandleClose (File);
  214. return Status;
  215. }
  216. /**
  217. Writes a variable to indicate that the NV variables
  218. have been loaded from the file system.
  219. **/
  220. STATIC
  221. VOID
  222. SetNvVarsVariable (
  223. VOID
  224. )
  225. {
  226. BOOLEAN VarData;
  227. UINTN Size;
  228. //
  229. // Write a variable to indicate we've already loaded the
  230. // variable data. If it is found, we skip the loading on
  231. // subsequent attempts.
  232. //
  233. Size = sizeof (VarData);
  234. VarData = TRUE;
  235. gRT->SetVariable (
  236. L"NvVars",
  237. &gEfiSimpleFileSystemProtocolGuid,
  238. EFI_VARIABLE_NON_VOLATILE |
  239. EFI_VARIABLE_BOOTSERVICE_ACCESS |
  240. EFI_VARIABLE_RUNTIME_ACCESS,
  241. Size,
  242. (VOID*) &VarData
  243. );
  244. }
  245. /**
  246. Loads the non-volatile variables from the NvVars file on the
  247. given file system.
  248. @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
  249. @return EFI_STATUS based on the success or failure of load operation
  250. **/
  251. EFI_STATUS
  252. LoadNvVarsFromFs (
  253. EFI_HANDLE FsHandle
  254. )
  255. {
  256. EFI_STATUS Status;
  257. BOOLEAN VarData;
  258. UINTN Size;
  259. DEBUG ((EFI_D_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));
  260. //
  261. // We write a variable to indicate we've already loaded the
  262. // variable data. If it is found, we skip the loading.
  263. //
  264. // This is relevant if the non-volatile variable have been
  265. // able to survive a reboot operation. In that case, we don't
  266. // want to re-load the file as it would overwrite newer changes
  267. // made to the variables.
  268. //
  269. Size = sizeof (VarData);
  270. VarData = TRUE;
  271. Status = gRT->GetVariable (
  272. L"NvVars",
  273. &gEfiSimpleFileSystemProtocolGuid,
  274. NULL,
  275. &Size,
  276. (VOID*) &VarData
  277. );
  278. if (Status == EFI_SUCCESS) {
  279. DEBUG ((EFI_D_INFO, "NV Variables were already loaded\n"));
  280. return EFI_ALREADY_STARTED;
  281. }
  282. //
  283. // Attempt to restore the variables from the NvVars file.
  284. //
  285. Status = ReadNvVarsFile (FsHandle);
  286. if (EFI_ERROR (Status)) {
  287. DEBUG ((EFI_D_INFO, "Error while restoring NV variable data\n"));
  288. return Status;
  289. }
  290. //
  291. // Write a variable to indicate we've already loaded the
  292. // variable data. If it is found, we skip the loading on
  293. // subsequent attempts.
  294. //
  295. SetNvVarsVariable();
  296. DEBUG ((
  297. EFI_D_INFO,
  298. "FsAccess.c: Read NV Variables file (size=%Lu)\n",
  299. (UINT64)Size
  300. ));
  301. return Status;
  302. }
  303. STATIC
  304. RETURN_STATUS
  305. EFIAPI
  306. IterateVariablesCallbackAddAllNvVariables (
  307. IN VOID *Context,
  308. IN CHAR16 *VariableName,
  309. IN EFI_GUID *VendorGuid,
  310. IN UINT32 Attributes,
  311. IN UINTN DataSize,
  312. IN VOID *Data
  313. )
  314. {
  315. EFI_HANDLE Instance;
  316. Instance = (EFI_HANDLE) Context;
  317. //
  318. // Only save non-volatile variables
  319. //
  320. if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
  321. return RETURN_SUCCESS;
  322. }
  323. return SerializeVariablesAddVariable (
  324. Instance,
  325. VariableName,
  326. VendorGuid,
  327. Attributes,
  328. DataSize,
  329. Data
  330. );
  331. }
  332. /**
  333. Saves the non-volatile variables into the NvVars file on the
  334. given file system.
  335. @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
  336. @return EFI_STATUS based on the success or failure of load operation
  337. **/
  338. EFI_STATUS
  339. SaveNvVarsToFs (
  340. EFI_HANDLE FsHandle
  341. )
  342. {
  343. EFI_STATUS Status;
  344. EFI_FILE_HANDLE File;
  345. UINTN WriteSize;
  346. UINTN VariableDataSize;
  347. VOID *VariableData;
  348. EFI_HANDLE SerializedVariables;
  349. SerializedVariables = NULL;
  350. Status = SerializeVariablesNewInstance (&SerializedVariables);
  351. if (EFI_ERROR (Status)) {
  352. return Status;
  353. }
  354. Status = SerializeVariablesIterateSystemVariables (
  355. IterateVariablesCallbackAddAllNvVariables,
  356. (VOID*) SerializedVariables
  357. );
  358. if (EFI_ERROR (Status)) {
  359. return Status;
  360. }
  361. VariableData = NULL;
  362. VariableDataSize = 0;
  363. Status = SerializeVariablesToBuffer (
  364. SerializedVariables,
  365. NULL,
  366. &VariableDataSize
  367. );
  368. if (Status == RETURN_BUFFER_TOO_SMALL) {
  369. VariableData = AllocatePool (VariableDataSize);
  370. if (VariableData == NULL) {
  371. Status = EFI_OUT_OF_RESOURCES;
  372. } else {
  373. Status = SerializeVariablesToBuffer (
  374. SerializedVariables,
  375. VariableData,
  376. &VariableDataSize
  377. );
  378. }
  379. }
  380. SerializeVariablesFreeInstance (SerializedVariables);
  381. if (EFI_ERROR (Status)) {
  382. return Status;
  383. }
  384. //
  385. // Open the NvVars file for writing.
  386. //
  387. Status = GetNvVarsFile (FsHandle, FALSE, &File);
  388. if (EFI_ERROR (Status)) {
  389. DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));
  390. return Status;
  391. }
  392. //
  393. // Empty the starting file contents.
  394. //
  395. Status = FileHandleEmpty (File);
  396. if (EFI_ERROR (Status)) {
  397. FileHandleClose (File);
  398. return Status;
  399. }
  400. WriteSize = VariableDataSize;
  401. Status = FileHandleWrite (File, &WriteSize, VariableData);
  402. if (EFI_ERROR (Status)) {
  403. return Status;
  404. }
  405. FileHandleClose (File);
  406. if (!EFI_ERROR (Status)) {
  407. //
  408. // Write a variable to indicate we've already loaded the
  409. // variable data. If it is found, we skip the loading on
  410. // subsequent attempts.
  411. //
  412. SetNvVarsVariable();
  413. DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));
  414. }
  415. return Status;
  416. }