1
0

fsvars.c 15 KB

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