]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/FSVariable/FileStorage.c
Fix some bugs in FSVariable and BdsPlatform for duet platform.
[mirror_edk2.git] / DuetPkg / FSVariable / FileStorage.c
CommitLineData
9071550e 1/*++\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 FileStorage.c\r
15\r
16Abstract:\r
17\r
18 handles variable store/reads on file\r
19\r
20Revision History\r
21\r
22--*/\r
23#include "FSVariable.h"\r
24\r
25VOID *mSFSRegistration;\r
26\r
27//\r
28// Prototypes\r
29//\r
30\r
31STATIC\r
32VOID\r
33EFIAPI\r
34OnVirtualAddressChange (\r
35 IN EFI_EVENT Event,\r
36 IN VOID *Context\r
37 );\r
38\r
39STATIC\r
40EFI_STATUS\r
41EFIAPI\r
42FileEraseStore(\r
43 IN VARIABLE_STORAGE *This\r
44 );\r
45\r
46STATIC\r
47EFI_STATUS\r
48EFIAPI\r
49FileWriteStore (\r
50 IN VARIABLE_STORAGE *This,\r
51 IN UINTN Offset,\r
52 IN UINTN BufferSize,\r
53 IN VOID *Buffer\r
54 );\r
55\r
56STATIC\r
57EFI_STATUS\r
58OpenStore (\r
59 IN EFI_DEVICE_PATH_PROTOCOL *Device,\r
60 IN CHAR16 *FilePathName,\r
61 IN UINT64 OpenMode,\r
62 OUT EFI_FILE **File\r
63 );\r
64\r
65//\r
66// Implementation below:\r
67//\r
68STATIC\r
69VOID\r
70FileClose (\r
71 IN EFI_FILE *File\r
72 )\r
73{\r
74 EFI_STATUS Status;\r
75\r
76 Status = File->Flush (File);\r
77 ASSERT_EFI_ERROR (Status);\r
78\r
79 Status = File->Close (File);\r
80 ASSERT_EFI_ERROR (Status);\r
81}\r
82\r
83EFI_STATUS\r
84CheckStore (\r
85 IN EFI_HANDLE SimpleFileSystemHandle,\r
86 IN UINT32 VolumeId,\r
87 OUT EFI_DEVICE_PATH_PROTOCOL **Device\r
88 )\r
89{\r
90#define BLOCK_SIZE 0x200\r
91#define FAT16_VOLUME_ID_OFFSET 39\r
92#define FAT32_VOLUME_ID_OFFSET 67\r
93 EFI_STATUS Status;\r
94 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
95 UINT8 BootSector[BLOCK_SIZE];\r
96\r
97 *Device = NULL;\r
98 Status = gBS->HandleProtocol (\r
99 SimpleFileSystemHandle,\r
100 &gEfiBlockIoProtocolGuid, // BlockIo should be supported if it supports SimpleFileSystem\r
101 (VOID*)&BlkIo\r
102 );\r
103\r
104 if (EFI_ERROR (Status)) {\r
105 goto ErrHandle;\r
106 }\r
107 if (!BlkIo->Media->MediaPresent) {\r
108 DEBUG ((EFI_D_ERROR, "FileStorage: Media not present!\n"));\r
109 Status = EFI_NO_MEDIA;\r
110 goto ErrHandle;\r
111 }\r
112 if (BlkIo->Media->ReadOnly) {\r
113 DEBUG ((EFI_D_ERROR, "FileStorage: Media is read-only!\n"));\r
114 Status = EFI_ACCESS_DENIED;\r
115 goto ErrHandle;\r
116 }\r
117\r
118 Status = BlkIo->ReadBlocks(\r
119 BlkIo,\r
120 BlkIo->Media->MediaId,\r
121 0,\r
122 BLOCK_SIZE,\r
123 BootSector\r
124 );\r
125 ASSERT_EFI_ERROR (Status);\r
126 if ((*(UINT32 *) &BootSector[FAT16_VOLUME_ID_OFFSET] != VolumeId) &&\r
127 (*(UINT32 *) &BootSector[FAT32_VOLUME_ID_OFFSET] != VolumeId)\r
128 ) {\r
129 Status = EFI_NOT_FOUND;\r
130 goto ErrHandle;\r
131 }\r
132\r
133 *Device = DuplicateDevicePath (DevicePathFromHandle (SimpleFileSystemHandle));\r
134 ASSERT (*Device != NULL);\r
135\r
136ErrHandle:\r
137 return Status;\r
138}\r
139\r
140EFI_STATUS\r
141CheckStoreExists (\r
142 IN EFI_DEVICE_PATH_PROTOCOL *Device\r
143 )\r
144{\r
145 EFI_HANDLE Handle;\r
146 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
147 EFI_STATUS Status;\r
148\r
149 Status = gBS->LocateDevicePath (\r
150 &gEfiSimpleFileSystemProtocolGuid,\r
151 &Device, \r
152 &Handle\r
153 );\r
154\r
155 if (EFI_ERROR (Status)) {\r
156 return Status;\r
157 }\r
158\r
159 Status = gBS->HandleProtocol (\r
160 Handle,\r
161 &gEfiSimpleFileSystemProtocolGuid,\r
162 &Volume\r
163 );\r
164 if (EFI_ERROR (Status)) {\r
165 return Status;\r
166 }\r
167\r
168 return EFI_SUCCESS;\r
169}\r
170\r
171// this routine is still running in BS period, no limitation\r
172// call FileInitStorage(), which load variable content file to memory\r
173// read the store_header, init store_header if it has not been inited (read sth. about format/heathy)\r
174// reclaim space using scratch memory\r
175\r
176STATIC\r
177VOID\r
178EFIAPI\r
179OnSimpleFileSystemInstall (\r
180 IN EFI_EVENT Event,\r
181 IN VOID *Context\r
182 )\r
183{\r
184 EFI_STATUS Status;\r
185 UINTN HandleSize;\r
186 EFI_HANDLE Handle;\r
187 EFI_DEVICE_PATH_PROTOCOL *Device;\r
188 VS_DEV *Dev;\r
189 EFI_FILE *File;\r
190 UINTN NumBytes;\r
191\r
192 Dev = (VS_DEV *) Context;\r
193 \r
194 if (VAR_FILE_DEVICEPATH (Dev) != NULL &&\r
195 !EFI_ERROR (CheckStoreExists (VAR_FILE_DEVICEPATH (Dev)))\r
196 ) {\r
197 DEBUG ((EFI_D_ERROR, "FileStorage: Already mapped!\n"));\r
198 return ;\r
199 }\r
200\r
201 while (TRUE) {\r
202 HandleSize = sizeof (EFI_HANDLE);\r
203 Status = gBS->LocateHandle (\r
204 ByRegisterNotify,\r
205 NULL,\r
206 mSFSRegistration,\r
207 &HandleSize,\r
208 &Handle\r
209 );\r
210 if (EFI_ERROR (Status)) {\r
211 return ;\r
212 }\r
213 \r
214 Status = CheckStore (Handle, VAR_FILE_VOLUMEID (Dev), &Device);\r
215 if (!EFI_ERROR (Status)) {\r
216 break;\r
217 }\r
218 }\r
219\r
220 VAR_FILE_DEVICEPATH (Dev) = Device;\r
221 Status = OpenStore (\r
222 VAR_FILE_DEVICEPATH (Dev), \r
223 VAR_FILE_FILEPATH (Dev), \r
224 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE,\r
225 &File\r
226 );\r
227 ASSERT_EFI_ERROR (Status);\r
228 \r
229 NumBytes = Dev->Size;\r
230 Status = File->Write (File, &NumBytes, VAR_DATA_PTR (Dev));\r
231 ASSERT_EFI_ERROR (Status);\r
232 FileClose (File);\r
233 DEBUG ((EFI_D_ERROR, "FileStorage: Mapped to file!\n"));\r
234}\r
235\r
236EFI_STATUS\r
237FileStorageConstructor (\r
238 OUT VARIABLE_STORAGE **VarStore,\r
239 OUT EFI_EVENT_NOTIFY *GoVirtualEvent,\r
240 IN EFI_PHYSICAL_ADDRESS NvStorageBase,\r
241 IN UINTN Size,\r
242 IN UINT32 VolumeId,\r
243 IN CHAR16 *FilePath\r
244 )\r
245{\r
246 VS_DEV *Dev;\r
247 EFI_STATUS Status;\r
248 EFI_EVENT Event;\r
249\r
250 Status = gBS->AllocatePool (EfiRuntimeServicesData, sizeof(VS_DEV), &Dev);\r
251 ASSERT_EFI_ERROR (Status);\r
252 ZeroMem (Dev, sizeof(VS_DEV));\r
253\r
254 Dev->Signature = VARIABLE_STORE_SIGNATURE;\r
255 Dev->Size = Size;\r
256 VAR_DATA_PTR (Dev) = (UINT8 *) (UINTN) NvStorageBase;\r
257 VAR_FILE_VOLUMEID (Dev) = VolumeId;\r
258 StrCpy (VAR_FILE_FILEPATH (Dev), FilePath);\r
259 Dev->VarStore.Erase = FileEraseStore;\r
260 Dev->VarStore.Write = FileWriteStore;\r
261\r
262 DEBUG ((EFI_D_ERROR, "FileStorageConstructor(0x%0x:0x%0x): added!\n", NvStorageBase, Size));\r
263\r
264 // add notify on SFS's installation.\r
265\r
266 Status = gBS->CreateEvent (\r
267 EFI_EVENT_NOTIFY_SIGNAL,\r
268 TPL_CALLBACK,\r
269 OnSimpleFileSystemInstall,\r
270 Dev,\r
271 &Event\r
272 );\r
273 ASSERT_EFI_ERROR (Status);\r
274\r
275 Status = gBS->RegisterProtocolNotify (\r
276 &gEfiSimpleFileSystemProtocolGuid,\r
277 Event,\r
278 &mSFSRegistration\r
279 );\r
280 ASSERT_EFI_ERROR (Status);\r
281\r
282 *VarStore = &Dev->VarStore;\r
283 *GoVirtualEvent = OnVirtualAddressChange;\r
284 return EFI_SUCCESS;\r
285}\r
286\r
287STATIC\r
288EFI_STATUS\r
289EFIAPI\r
290FileEraseStore(\r
291 IN VARIABLE_STORAGE *This\r
292 )\r
293{\r
294 EFI_STATUS Status;\r
295 VS_DEV *Dev;\r
296 EFI_FILE *File;\r
297 UINTN NumBytes;\r
298\r
299 Status = EFI_SUCCESS;\r
300 Dev = DEV_FROM_THIS(This);\r
301\r
302 SetMem (VAR_DATA_PTR (Dev), Dev->Size, VAR_DEFAULT_VALUE);\r
303\r
304 if (!EfiAtRuntime () && VAR_FILE_DEVICEPATH (Dev) != NULL) {\r
305 Status = OpenStore (\r
306 VAR_FILE_DEVICEPATH (Dev), \r
307 VAR_FILE_FILEPATH (Dev), \r
308 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ,\r
309 &File\r
310 );\r
311 ASSERT_EFI_ERROR (Status);\r
312 NumBytes = Dev->Size;\r
313 Status = File->Write (File, &NumBytes, VAR_DATA_PTR (Dev));\r
314 ASSERT_EFI_ERROR (Status);\r
315 FileClose (File);\r
316 }\r
317 \r
318 return Status;\r
319}\r
320\r
321STATIC\r
322EFI_STATUS\r
323EFIAPI\r
324FileWriteStore (\r
325 IN VARIABLE_STORAGE *This,\r
326 IN UINTN Offset,\r
327 IN UINTN BufferSize,\r
328 IN VOID *Buffer\r
329 )\r
330{\r
331 EFI_STATUS Status;\r
332 VS_DEV *Dev;\r
333 EFI_FILE *File;\r
334\r
335 Status = EFI_SUCCESS;\r
336 Dev = DEV_FROM_THIS(This);\r
337\r
338 ASSERT (Buffer != NULL);\r
339 ASSERT (Offset + BufferSize <= Dev->Size);\r
340\r
341 CopyMem (VAR_DATA_PTR (Dev) + Offset, Buffer, BufferSize);\r
342 \r
343 if (!EfiAtRuntime () && VAR_FILE_DEVICEPATH (Dev) != NULL) {\r
344 Status = OpenStore (\r
345 VAR_FILE_DEVICEPATH (Dev), \r
346 VAR_FILE_FILEPATH (Dev), \r
347 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ,\r
348 &File\r
349 );\r
350 Status = File->SetPosition (File, Offset);\r
351 ASSERT_EFI_ERROR (Status);\r
352 Status = File->Write (File, &BufferSize, Buffer);\r
353 ASSERT_EFI_ERROR (Status);\r
354 FileClose (File);\r
355 }\r
356 return Status;\r
357}\r
358\r
359STATIC\r
360VOID\r
361EFIAPI\r
362OnVirtualAddressChange (\r
363 IN EFI_EVENT Event,\r
364 IN VOID *Context\r
365 )\r
366{\r
367 VS_DEV *Dev;\r
368\r
369 Dev = DEV_FROM_THIS (Context);\r
370\r
371 EfiConvertPointer (0, &VAR_DATA_PTR (Dev));\r
372 EfiConvertPointer (0, (VOID **) &Dev->VarStore.Erase);\r
373 EfiConvertPointer (0, (VOID **) &Dev->VarStore.Write);\r
374}\r
375\r
376STATIC\r
377EFI_STATUS\r
378OpenStore (\r
379 IN EFI_DEVICE_PATH_PROTOCOL *Device,\r
380 IN CHAR16 *FilePathName,\r
381 IN UINT64 OpenMode,\r
382 OUT EFI_FILE **File\r
383 )\r
384{\r
385 EFI_HANDLE Handle;\r
386 EFI_FILE_HANDLE Root;\r
387 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
388 EFI_STATUS Status;\r
389\r
390 *File = NULL;\r
391\r
392 Status = gBS->LocateDevicePath (\r
393 &gEfiSimpleFileSystemProtocolGuid,\r
394 &Device, \r
395 &Handle\r
396 );\r
397\r
398 if (EFI_ERROR (Status)) {\r
399 return Status;\r
400 }\r
401\r
402 Status = gBS->HandleProtocol (\r
403 Handle,\r
404 &gEfiSimpleFileSystemProtocolGuid,\r
405 &Volume\r
406 );\r
407 if (EFI_ERROR (Status)) {\r
408 return Status;\r
409 }\r
410 \r
411 //\r
412 // Open the root directory of the volume\r
413 //\r
414 Root = NULL;\r
415 Status = Volume->OpenVolume (\r
416 Volume,\r
417 &Root\r
418 );\r
419 ASSERT_EFI_ERROR (Status);\r
420 ASSERT (Root != NULL);\r
421\r
422 //\r
423 // Open file\r
424 //\r
425 Status = Root->Open (\r
426 Root,\r
427 File,\r
428 FilePathName,\r
429 OpenMode,\r
430 0\r
431 );\r
432 if (EFI_ERROR (Status)) {\r
433 *File = NULL;\r
434 }\r
435\r
436 //\r
437 // Close the Root directory\r
438 //\r
439 Root->Close (Root);\r
440 return Status;\r
441}\r