Home | History | Annotate | Download | only in FSVariable
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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