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