Implement NvVarsFileLib to save and restore non-volatile variables using a file.
[mirror_edk2.git] / OvmfPkg / Library / NvVarsFileLib / VarBuffer.c
1 /** @file
2 File System Access
3
4 Copyright (c) 2004 - 2009, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "NvVarsFileLib.h"
16
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UefiRuntimeServicesTableLib.h>
21
22
23 /**
24 Writes the variable into the file so it can be restored from
25 the file on future boots of the system.
26
27 @param[in] File - The file to write to
28 @param[in] Name - Variable name string
29 @param[in] NameSize - Size of Name in bytes
30 @param[in] Guid - GUID of variable
31 @param[in] Attributes - Attributes of variable
32 @param[in] Data - Buffer containing Data for variable
33 @param[in] DataSize - Size of Data in bytes
34
35 @return EFI_STATUS based on the success or failure of the operation
36
37 **/
38 EFI_STATUS
39 PackVariableIntoFile (
40 IN EFI_FILE_HANDLE File,
41 IN CHAR16 *Name,
42 IN UINT32 NameSize,
43 IN EFI_GUID *Guid,
44 IN UINT32 Attributes,
45 IN VOID *Data,
46 IN UINT32 DataSize
47 )
48 {
49 EFI_STATUS Status;
50 UINTN WriteSize;
51
52 WriteSize = sizeof (NameSize);
53 Status = FileHandleWrite (File, &WriteSize, &NameSize);
54 if (EFI_ERROR (Status)) {
55 return Status;
56 }
57
58 WriteSize = NameSize;
59 Status = FileHandleWrite (File, &WriteSize, (VOID*) Name);
60 if (EFI_ERROR (Status)) {
61 return Status;
62 }
63
64 WriteSize = sizeof (*Guid);
65 Status = FileHandleWrite (File, &WriteSize, (VOID*) Guid);
66 if (EFI_ERROR (Status)) {
67 return Status;
68 }
69
70 WriteSize = sizeof (Attributes);
71 Status = FileHandleWrite (File, &WriteSize, &Attributes);
72 if (EFI_ERROR (Status)) {
73 return Status;
74 }
75
76 WriteSize = sizeof (DataSize);
77 Status = FileHandleWrite (File, &WriteSize, &DataSize);
78 if (EFI_ERROR (Status)) {
79 return Status;
80 }
81
82 WriteSize = DataSize;
83 Status = FileHandleWrite (File, &WriteSize, Data);
84
85 return Status;
86 }
87
88
89 /**
90 Unpacks the next variable from the NvVars file data
91
92 @param[in] Buffer - Buffer pointing to the next variable instance
93 On subsequent calls, the pointer should be incremented
94 by the returned SizeUsed value.
95 @param[in] MaxSize - Max allowable size for the variable data
96 On subsequent calls, this should be decremented
97 by the returned SizeUsed value.
98 @param[out] Name - Variable name string (address in Buffer)
99 @param[out] NameSize - Size of Name in bytes
100 @param[out] Guid - GUID of variable (address in Buffer)
101 @param[out] Attributes - Attributes of variable
102 @param[out] Data - Buffer containing Data for variable (address in Buffer)
103 @param[out] DataSize - Size of Data in bytes
104 @param[out] SizeUsed - Total size used for this variable instance in Buffer
105
106 @return EFI_STATUS based on the success or failure of the operation
107
108 **/
109 EFI_STATUS
110 UnpackVariableFromBuffer (
111 IN VOID *Buffer,
112 IN UINTN MaxSize,
113 OUT CHAR16 **Name,
114 OUT UINT32 *NameSize,
115 OUT EFI_GUID **Guid,
116 OUT UINT32 *Attributes,
117 OUT UINT32 *DataSize,
118 OUT VOID **Data,
119 OUT UINTN *SizeUsed
120 )
121 {
122 UINT8 *BytePtr;
123 UINTN Offset;
124
125 BytePtr = (UINT8*)Buffer;
126 Offset = 0;
127
128 *NameSize = *(UINT32*) (BytePtr + Offset);
129 Offset = Offset + sizeof (UINT32);
130
131 if (Offset > MaxSize) {
132 return EFI_INVALID_PARAMETER;
133 }
134
135 *Name = (CHAR16*) (BytePtr + Offset);
136 Offset = Offset + *(UINT32*)BytePtr;
137 if (Offset > MaxSize) {
138 return EFI_INVALID_PARAMETER;
139 }
140
141 *Guid = (EFI_GUID*) (BytePtr + Offset);
142 Offset = Offset + sizeof (EFI_GUID);
143 if (Offset > MaxSize) {
144 return EFI_INVALID_PARAMETER;
145 }
146
147 *Attributes = *(UINT32*) (BytePtr + Offset);
148 Offset = Offset + sizeof (UINT32);
149 if (Offset > MaxSize) {
150 return EFI_INVALID_PARAMETER;
151 }
152
153 *DataSize = *(UINT32*) (BytePtr + Offset);
154 Offset = Offset + sizeof (UINT32);
155 if (Offset > MaxSize) {
156 return EFI_INVALID_PARAMETER;
157 }
158
159 *Data = (VOID*) (BytePtr + Offset);
160 Offset = Offset + *DataSize;
161 if (Offset > MaxSize) {
162 return EFI_INVALID_PARAMETER;
163 }
164
165 *SizeUsed = Offset;
166
167 return EFI_SUCCESS;
168 }
169
170
171 /**
172 Examines the NvVars file contents, and updates variables based on it.
173
174 @param[in] Buffer - Buffer with NvVars data
175 @param[in] MaxSize - Size of Buffer in bytes
176 @param[in] DryRun - If TRUE, then no variable modifications should be made
177 (If TRUE, the Buffer is still parsed for validity.)
178
179 @return EFI_STATUS based on the success or failure of the operation
180
181 **/
182 EFI_STATUS
183 UnpackVariablesFromBuffer (
184 IN VOID *Buffer,
185 IN UINTN MaxSize,
186 IN BOOLEAN DryRun
187 )
188 {
189 EFI_STATUS Status;
190 UINTN Count;
191 UINTN TotalSizeUsed;
192 UINTN SizeUsed;
193
194 CHAR16 *Name;
195 UINT32 NameSize;
196 CHAR16 *AlignedName;
197 UINT32 AlignedNameMaxSize;
198 EFI_GUID *Guid;
199 UINT32 Attributes;
200 UINT32 DataSize;
201 VOID *Data;
202
203 AlignedName = NULL;
204 AlignedNameMaxSize = 0;
205
206 for (
207 Status = EFI_SUCCESS, Count = 0, TotalSizeUsed = 0;
208 !EFI_ERROR (Status) && (TotalSizeUsed < MaxSize);
209 ) {
210 Status = UnpackVariableFromBuffer (
211 (VOID*) ((UINT8*) Buffer + TotalSizeUsed),
212 (MaxSize - TotalSizeUsed),
213 &Name,
214 &NameSize,
215 &Guid,
216 &Attributes,
217 &DataSize,
218 &Data,
219 &SizeUsed
220 );
221 if (EFI_ERROR (Status)) {
222 return Status;
223 }
224
225 //
226 // We copy the name to a separately allocated buffer,
227 // to be sure it is 16-bit aligned.
228 //
229 if (NameSize > AlignedNameMaxSize) {
230 if (AlignedName != NULL) {
231 FreePool (AlignedName);
232 }
233 AlignedName = AllocatePool (NameSize);
234 }
235 if (AlignedName == NULL) {
236 return EFI_OUT_OF_RESOURCES;
237 }
238 CopyMem (AlignedName, Name, NameSize);
239
240 DEBUG ((
241 EFI_D_INFO,
242 "Unpacked variable %g:%s\n",
243 Guid,
244 AlignedName
245 ));
246
247 TotalSizeUsed = TotalSizeUsed + SizeUsed;
248
249 DEBUG ((
250 EFI_D_INFO,
251 "TotalSizeUsed(%d); MaxSize(%d)\n",
252 TotalSizeUsed,
253 MaxSize
254 ));
255
256 if (!DryRun) {
257 //
258 // Set the variable contents
259 //
260 gRT->SetVariable (
261 AlignedName,
262 Guid,
263 Attributes,
264 DataSize,
265 Data
266 );
267
268 Count++;
269
270 DEBUG ((
271 EFI_D_INFO,
272 "Restored variable %g:%s\n",
273 Guid,
274 AlignedName
275 ));
276 }
277
278 }
279
280 if (AlignedName != NULL) {
281 FreePool (AlignedName);
282 }
283
284 //
285 // Make sure the entire buffer was used, or else return an error
286 //
287 if (TotalSizeUsed != MaxSize) {
288 DEBUG ((
289 EFI_D_INFO,
290 "TotalSizeUsed(%d) != MaxSize(%d)\n",
291 TotalSizeUsed,
292 MaxSize
293 ));
294 return EFI_INVALID_PARAMETER;
295 }
296
297 if (Count > 0) {
298 DEBUG ((
299 EFI_D_INFO,
300 "Restored %d Variables\n",
301 Count
302 ));
303 }
304
305 return EFI_SUCCESS;
306 }
307
308
309 /**
310 Examines the NvVars file contents, and updates variables based on it.
311
312 @param[in] VarsBuffer - Buffer with NvVars data
313 @param[in] VarsBufferSize - Size of VarsBuffer in bytes
314
315 @return EFI_STATUS based on the success or failure of the operation
316
317 **/
318 EFI_STATUS
319 SetVariablesFromBuffer (
320 IN VOID *VarsBuffer,
321 IN UINTN VarsBufferSize
322 )
323 {
324 EFI_STATUS Status;
325
326 //
327 // First test to make sure the entire buffer is in a good state
328 //
329 Status = UnpackVariablesFromBuffer (VarsBuffer, VarsBufferSize, TRUE);
330 if (EFI_ERROR (Status)) {
331 DEBUG ((EFI_D_INFO, "NvVars buffer format was invalid\n"));
332 return Status;
333 }
334
335 //
336 // Now, actually restore the variables.
337 //
338 Status = UnpackVariablesFromBuffer (VarsBuffer, VarsBufferSize, FALSE);
339 if (EFI_ERROR (Status)) {
340 return Status;
341 }
342
343 return Status;
344 }
345