fsvars.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. fsvars.c
  5. Abstract:
  6. This module implements loading EFI variables from the file system.
  7. Author:
  8. Evan Green 27-Mar-2014
  9. Environment:
  10. Firmware
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "ueficore.h"
  16. #include <minoca/uefi/protocol/sfilesys.h>
  17. #include "fileinfo.h"
  18. #include "varback.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // ------------------------------------------------------ Data Type Definitions
  24. //
  25. //
  26. // ----------------------------------------------- Internal Function Prototypes
  27. //
  28. EFI_STATUS
  29. EfipCoreLoadVariablesFromFileSystem (
  30. EFI_HANDLE Handle
  31. );
  32. EFI_STATUS
  33. EfipCoreSaveVariablesToFileSystem (
  34. EFI_HANDLE Handle
  35. );
  36. EFI_STATUS
  37. EfipCoreGetFileInformation (
  38. EFI_FILE_PROTOCOL *File,
  39. EFI_FILE_INFO **FileInformation,
  40. UINTN *FileInformationSize
  41. );
  42. EFI_STATUS
  43. EfipCoreGetVariablesFile (
  44. EFI_HANDLE Handle,
  45. BOOLEAN OpenForRead,
  46. EFI_FILE_PROTOCOL **File
  47. );
  48. VOID
  49. EfipSetVariablesFileVariable (
  50. BOOLEAN Delete
  51. );
  52. //
  53. // -------------------------------------------------------------------- Globals
  54. //
  55. BOOLEAN EfiFileSystemVariablesLoaded = FALSE;
  56. EFI_GUID EfiVariableBackendProtocolGuid = EFI_VARIABLE_BACKEND_PROTOCOL_GUID;
  57. //
  58. // ------------------------------------------------------------------ Functions
  59. //
  60. VOID
  61. EfiCoreLoadVariablesFromFileSystem (
  62. VOID
  63. )
  64. /*++
  65. Routine Description:
  66. This routine loads variable data from the EFI system partition(s).
  67. Arguments:
  68. None.
  69. Return Value:
  70. None. Failure here is not fatal.
  71. --*/
  72. {
  73. UINTN DataSize;
  74. VOID *DummyValue;
  75. UINTN HandleCount;
  76. EFI_HANDLE *Handles;
  77. UINTN Index;
  78. EFI_STATUS Status;
  79. if (EfiFileSystemVariablesLoaded != FALSE) {
  80. return;
  81. }
  82. //
  83. // Check a variable to see if the file system variables have already been
  84. // loaded. This is important for allowing variables to survive a reboot.
  85. //
  86. DataSize = sizeof(DummyValue);
  87. Status = EfiGetVariable(L"NvVars",
  88. &EfiSimpleFileSystemProtocolGuid,
  89. NULL,
  90. &DataSize,
  91. &DummyValue);
  92. ASSERT(Status != EFI_BUFFER_TOO_SMALL);
  93. //
  94. // If this volatile variable is already present, then the volatile
  95. // variables probably survived a reboot.
  96. //
  97. if (!EFI_ERROR(Status)) {
  98. EfiFileSystemVariablesLoaded = TRUE;
  99. return;
  100. }
  101. HandleCount = 0;
  102. Handles = NULL;
  103. Status = EfiLocateHandleBuffer(ByProtocol,
  104. &EfiSimpleFileSystemProtocolGuid,
  105. NULL,
  106. &HandleCount,
  107. &Handles);
  108. if (EFI_ERROR(Status)) {
  109. return;
  110. }
  111. //
  112. // Loop through every handle that supports the simple file system protocol.
  113. //
  114. for (Index = 0; Index < HandleCount; Index += 1) {
  115. //
  116. // Skip any handles that are not also an EFI system partition.
  117. //
  118. Status = EfiHandleProtocol(Handles[Index],
  119. &EfiPartitionTypeSystemPartitionGuid,
  120. &DummyValue);
  121. if (EFI_ERROR(Status)) {
  122. continue;
  123. }
  124. EfipCoreLoadVariablesFromFileSystem(Handles[Index]);
  125. }
  126. if (HandleCount != 0) {
  127. EfiFreePool(Handles);
  128. }
  129. EfiFileSystemVariablesLoaded = TRUE;
  130. return;
  131. }
  132. VOID
  133. EfiCoreSaveVariablesToFileSystem (
  134. VOID
  135. )
  136. /*++
  137. Routine Description:
  138. This routine saves variable data to the EFI system partition(s).
  139. Arguments:
  140. None.
  141. Return Value:
  142. None. Failure here is not fatal.
  143. --*/
  144. {
  145. VOID *DummyValue;
  146. UINTN HandleCount;
  147. EFI_HANDLE *Handles;
  148. UINTN Index;
  149. EFI_STATUS Status;
  150. HandleCount = 0;
  151. Handles = NULL;
  152. Status = EfiLocateHandleBuffer(ByProtocol,
  153. &EfiSimpleFileSystemProtocolGuid,
  154. NULL,
  155. &HandleCount,
  156. &Handles);
  157. if (EFI_ERROR(Status)) {
  158. return;
  159. }
  160. //
  161. // Loop through every handle that supports the simple file system protocol.
  162. //
  163. for (Index = 0; Index < HandleCount; Index += 1) {
  164. //
  165. // Skip any handles that are not also an EFI system partition.
  166. //
  167. Status = EfiHandleProtocol(Handles[Index],
  168. &EfiPartitionTypeSystemPartitionGuid,
  169. &DummyValue);
  170. if (EFI_ERROR(Status)) {
  171. continue;
  172. }
  173. EfipCoreSaveVariablesToFileSystem(Handles[Index]);
  174. }
  175. if (HandleCount != 0) {
  176. EfiFreePool(Handles);
  177. }
  178. return;
  179. }
  180. //
  181. // --------------------------------------------------------- Internal Functions
  182. //
  183. EFI_STATUS
  184. EfipCoreLoadVariablesFromFileSystem (
  185. EFI_HANDLE Handle
  186. )
  187. /*++
  188. Routine Description:
  189. This routine loads variable data from the given file system interface
  190. handle.
  191. Arguments:
  192. Handle - Supplies the handle that contains the simple file system interface.
  193. Return Value:
  194. EFI status code.
  195. --*/
  196. {
  197. EFI_FILE_PROTOCOL *File;
  198. VOID *FileData;
  199. EFI_FILE_INFO *FileInformation;
  200. UINTN FileInformationSize;
  201. UINTN FileSize;
  202. UINTN HandleCount;
  203. EFI_HANDLE *Handles;
  204. EFI_STATUS Status;
  205. EFI_VARIABLE_BACKEND_PROTOCOL *VariableBackend;
  206. File = NULL;
  207. FileData = NULL;
  208. FileInformation = NULL;
  209. Handles = NULL;
  210. Status = EfipCoreGetVariablesFile(Handle, TRUE, &File);
  211. if (EFI_ERROR(Status)) {
  212. goto CoreLoadVariablesFromFileSystemEnd;
  213. }
  214. //
  215. // Get the file information.
  216. //
  217. Status = EfipCoreGetFileInformation(File,
  218. &FileInformation,
  219. &FileInformationSize);
  220. if (EFI_ERROR(Status)) {
  221. goto CoreLoadVariablesFromFileSystemEnd;
  222. }
  223. //
  224. // Skip it if it's a directory, that's not right.
  225. //
  226. if ((FileInformation->Attribute & EFI_FILE_DIRECTORY) != 0) {
  227. Status = EFI_NOT_FOUND;
  228. goto CoreLoadVariablesFromFileSystemEnd;
  229. }
  230. //
  231. // Allocate data for the file contents, and read the contents in.
  232. //
  233. FileSize = FileInformation->FileSize;
  234. FileData = EfiCoreAllocateBootPool(FileSize);
  235. if (FileData == NULL) {
  236. Status = EFI_OUT_OF_RESOURCES;
  237. goto CoreLoadVariablesFromFileSystemEnd;
  238. }
  239. Status = File->Read(File, &FileSize, FileData);
  240. if (EFI_ERROR(Status)) {
  241. goto CoreLoadVariablesFromFileSystemEnd;
  242. }
  243. //
  244. // Open up the variable backend protocol.
  245. //
  246. HandleCount = 0;
  247. Status = EfiLocateHandleBuffer(ByProtocol,
  248. &EfiVariableBackendProtocolGuid,
  249. NULL,
  250. &HandleCount,
  251. &Handles);
  252. if (EFI_ERROR(Status)) {
  253. goto CoreLoadVariablesFromFileSystemEnd;
  254. }
  255. if (HandleCount != 0) {
  256. Status = EfiHandleProtocol(Handles[0],
  257. &EfiVariableBackendProtocolGuid,
  258. (VOID **)&VariableBackend);
  259. if (EFI_ERROR(Status)) {
  260. goto CoreLoadVariablesFromFileSystemEnd;
  261. }
  262. }
  263. //
  264. // Add these variables to the current EFI variables via the backend
  265. // protocol.
  266. //
  267. Status = VariableBackend->SetData(VariableBackend,
  268. FileData,
  269. FileSize,
  270. FALSE);
  271. if (EFI_ERROR(Status)) {
  272. goto CoreLoadVariablesFromFileSystemEnd;
  273. }
  274. EfipSetVariablesFileVariable(FALSE);
  275. CoreLoadVariablesFromFileSystemEnd:
  276. if (FileInformation != NULL) {
  277. EfiFreePool(FileInformation);
  278. }
  279. if (File != NULL) {
  280. File->Close(File);
  281. }
  282. if (Handles != NULL) {
  283. EfiFreePool(Handles);
  284. }
  285. if (FileData != NULL) {
  286. EfiFreePool(FileData);
  287. }
  288. return Status;
  289. }
  290. EFI_STATUS
  291. EfipCoreSaveVariablesToFileSystem (
  292. EFI_HANDLE Handle
  293. )
  294. /*++
  295. Routine Description:
  296. This routine saves variable data to the given file system interface
  297. handle.
  298. Arguments:
  299. Handle - Supplies the handle that contains the simple file system interface.
  300. Return Value:
  301. EFI status code.
  302. --*/
  303. {
  304. EFI_FILE_PROTOCOL *File;
  305. VOID *FileData;
  306. UINTN FileSize;
  307. UINTN HandleCount;
  308. EFI_HANDLE *Handles;
  309. EFI_STATUS Status;
  310. EFI_VARIABLE_BACKEND_PROTOCOL *VariableBackend;
  311. //
  312. // Open up the file.
  313. //
  314. File = NULL;
  315. FileData = NULL;
  316. Handles = NULL;
  317. Status = EfipCoreGetVariablesFile(Handle, FALSE, &File);
  318. if (EFI_ERROR(Status)) {
  319. goto CoreWriteVariablesToFileSystemEnd;
  320. }
  321. //
  322. // Open up the variable backend protocol.
  323. //
  324. HandleCount = 0;
  325. Status = EfiLocateHandleBuffer(ByProtocol,
  326. &EfiVariableBackendProtocolGuid,
  327. NULL,
  328. &HandleCount,
  329. &Handles);
  330. if (EFI_ERROR(Status)) {
  331. goto CoreWriteVariablesToFileSystemEnd;
  332. }
  333. if (HandleCount != 0) {
  334. Status = EfiHandleProtocol(Handles[0],
  335. &EfiVariableBackendProtocolGuid,
  336. (VOID **)&VariableBackend);
  337. if (EFI_ERROR(Status)) {
  338. goto CoreWriteVariablesToFileSystemEnd;
  339. }
  340. }
  341. //
  342. // Get the current variable data
  343. //
  344. FileData = NULL;
  345. FileSize = 0;
  346. Status = VariableBackend->GetData(VariableBackend,
  347. &FileData,
  348. &FileSize);
  349. if (EFI_ERROR(Status)) {
  350. goto CoreWriteVariablesToFileSystemEnd;
  351. }
  352. //
  353. // Try to write it out.
  354. //
  355. Status = File->Write(File, &FileSize, FileData);
  356. if (EFI_ERROR(Status)) {
  357. goto CoreWriteVariablesToFileSystemEnd;
  358. }
  359. CoreWriteVariablesToFileSystemEnd:
  360. if (Handles != NULL) {
  361. EfiFreePool(Handles);
  362. }
  363. if (File != NULL) {
  364. File->Close(File);
  365. }
  366. return Status;
  367. }
  368. EFI_STATUS
  369. EfipCoreGetFileInformation (
  370. EFI_FILE_PROTOCOL *File,
  371. EFI_FILE_INFO **FileInformation,
  372. UINTN *FileInformationSize
  373. )
  374. /*++
  375. Routine Description:
  376. This routine returns the file information, allocated from pool.
  377. Arguments:
  378. File - Supplies the open file protocol instance.
  379. FileInformation - Supplies a pointer where a pointer to the file
  380. information will be returned on success. The caller is responsible
  381. for freeing this buffer.
  382. FileInformationSize - Supplies a pointer where the size of the file
  383. information will be returned on success.
  384. Return Value:
  385. EFI status code.
  386. --*/
  387. {
  388. EFI_FILE_INFO *Information;
  389. UINTN InformationSize;
  390. EFI_STATUS Status;
  391. Information = NULL;
  392. InformationSize = 0;
  393. Status = File->GetInfo(File,
  394. &EfiFileInformationGuid,
  395. &InformationSize,
  396. NULL);
  397. if (Status == EFI_BUFFER_TOO_SMALL) {
  398. Information = EfiCoreAllocateBootPool(InformationSize);
  399. if (Information == NULL) {
  400. return EFI_OUT_OF_RESOURCES;
  401. }
  402. EfiSetMem(Information, InformationSize, 0);
  403. Status = File->GetInfo(File,
  404. &EfiFileInformationGuid,
  405. &InformationSize,
  406. Information);
  407. if (EFI_ERROR(Status)) {
  408. EfiFreePool(Information);
  409. InformationSize = 0;
  410. }
  411. }
  412. *FileInformation = Information;
  413. *FileInformationSize = InformationSize;
  414. return Status;
  415. }
  416. EFI_STATUS
  417. EfipCoreGetVariablesFile (
  418. EFI_HANDLE Handle,
  419. BOOLEAN OpenForRead,
  420. EFI_FILE_PROTOCOL **File
  421. )
  422. /*++
  423. Routine Description:
  424. This routine opens the variables file for reading or writing.
  425. Arguments:
  426. Handle - Supplies the handle that supports the simple file system protocol.
  427. OpenForRead - Supplies a boolean indicating whether to open the file for
  428. reading (TRUE) or writing (FALSE).
  429. File - Supplies a pointer where the opened file protocol will be returned.
  430. Return Value:
  431. EFI status code.
  432. --*/
  433. {
  434. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
  435. UINT64 OpenMode;
  436. EFI_FILE_PROTOCOL *Root;
  437. EFI_STATUS Status;
  438. Status = EfiHandleProtocol(Handle,
  439. &EfiSimpleFileSystemProtocolGuid,
  440. (VOID **)&FileSystem);
  441. if (EFI_ERROR(Status)) {
  442. return Status;
  443. }
  444. Status = FileSystem->OpenVolume(FileSystem, &Root);
  445. if (EFI_ERROR(Status)) {
  446. return Status;
  447. }
  448. if (OpenForRead != FALSE) {
  449. OpenMode = EFI_FILE_MODE_READ;
  450. //
  451. // If opening the file to write, first open and delete it.
  452. //
  453. } else {
  454. OpenMode = EFI_FILE_MODE_WRITE;
  455. }
  456. Status = Root->Open(Root,
  457. File,
  458. L"EFI\\NvVars",
  459. OpenMode,
  460. 0);
  461. //
  462. // If opening for write, delete the file if it opened successfully, and
  463. // then reopen with create. Deleting closes the file handle too.
  464. //
  465. if (OpenForRead == FALSE) {
  466. if (!EFI_ERROR(Status)) {
  467. (*File)->Delete(*File);
  468. }
  469. OpenMode = EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ |
  470. EFI_FILE_MODE_WRITE;
  471. Status = Root->Open(Root,
  472. File,
  473. L"EFI\\NvVars",
  474. OpenMode,
  475. 0);
  476. }
  477. Root->Close(Root);
  478. return Status;
  479. }
  480. VOID
  481. EfipSetVariablesFileVariable (
  482. BOOLEAN Delete
  483. )
  484. /*++
  485. Routine Description:
  486. This routine sets a volatile variable to indicate that variables have been
  487. loaded from a file. This way if variables survive a reboot, they won't be
  488. smashed by older data from the file sysetm later.
  489. Arguments:
  490. Delete - Supplies a boolean indicating whether to delete or set the
  491. variable.
  492. Return Value:
  493. None.
  494. --*/
  495. {
  496. UINT32 Attributes;
  497. VOID *DataPointer;
  498. VOID *DummyData;
  499. UINTN Size;
  500. Attributes = EFI_VARIABLE_NON_VOLATILE |
  501. EFI_VARIABLE_BOOTSERVICE_ACCESS |
  502. EFI_VARIABLE_RUNTIME_ACCESS;
  503. DummyData = NULL;
  504. if (Delete != FALSE) {
  505. DataPointer = NULL;
  506. } else {
  507. DataPointer = &DummyData;
  508. Size = sizeof(DummyData);
  509. }
  510. EfiSetVariable(L"NvVars",
  511. &EfiSimpleFileSystemProtocolGuid,
  512. Attributes,
  513. Size,
  514. DataPointer);
  515. return;
  516. }