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