Home | History | Annotate | Download | only in BootMonFs
      1 /** @file
      2 *
      3 *  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
      4 *
      5 *  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 <Library/BaseMemoryLib.h>
     16 #include <Library/DevicePathLib.h>
     17 #include <Library/MemoryAllocationLib.h>
     18 #include <Library/PrintLib.h>
     19 #include <Library/UefiBootServicesTableLib.h>
     20 
     21 #include <Protocol/DevicePathFromText.h>
     22 #include <Protocol/DriverBinding.h>
     23 
     24 #include "BootMonFsInternal.h"
     25 
     26 EFI_DEVICE_PATH* mBootMonFsSupportedDevicePaths;
     27 LIST_ENTRY       mInstances;
     28 
     29 EFI_FILE_PROTOCOL mBootMonFsRootTemplate = {
     30   EFI_FILE_PROTOCOL_REVISION,
     31   BootMonFsOpenFile,
     32   BootMonFsCloseFile,
     33   BootMonFsDeleteFail,
     34   BootMonFsReadDirectory,
     35   BootMonFsWriteFile,
     36   BootMonFsGetPositionUnsupported,  // UEFI Spec: GetPosition not valid on dirs
     37   BootMonFsSetDirPosition,
     38   BootMonFsGetInfo,
     39   BootMonFsSetInfo,
     40   BootMonFsFlushDirectory
     41 };
     42 
     43 EFI_FILE_PROTOCOL mBootMonFsFileTemplate = {
     44   EFI_FILE_PROTOCOL_REVISION,
     45   BootMonFsOpenFile,
     46   BootMonFsCloseFile,
     47   BootMonFsDelete,
     48   BootMonFsReadFile,
     49   BootMonFsWriteFile,
     50   BootMonFsGetPosition,
     51   BootMonFsSetPosition,
     52   BootMonFsGetInfo,
     53   BootMonFsSetInfo,
     54   BootMonFsFlushFile
     55 };
     56 
     57 /**
     58   Search for a file given its name coded in Ascii.
     59 
     60   When searching through the files of the volume, if a file is currently not
     61   open, its name was written on the media and is kept in RAM in the
     62   "HwDescription.Footer.Filename[]" field of the file's description.
     63 
     64   If a file is currently open, its name might not have been written on the
     65   media yet, and as the "HwDescription" is a mirror in RAM of what is on the
     66   media the "HwDescription.Footer.Filename[]" might be outdated. In that case,
     67   the up to date name of the file is stored in the "Info" field of the file's
     68   description.
     69 
     70   @param[in]   Instance       Pointer to the description of the volume in which
     71                               the file has to be search for.
     72   @param[in]   AsciiFileName  Name of the file.
     73 
     74   @param[out]  File           Pointer to the description of the file if the
     75                               file was found.
     76 
     77   @retval  EFI_SUCCESS    The file was found.
     78   @retval  EFI_NOT_FOUND  The file was not found.
     79 
     80 **/
     81 EFI_STATUS
     82 BootMonGetFileFromAsciiFileName (
     83   IN  BOOTMON_FS_INSTANCE   *Instance,
     84   IN  CHAR8*                AsciiFileName,
     85   OUT BOOTMON_FS_FILE       **File
     86   )
     87 {
     88   LIST_ENTRY       *Entry;
     89   BOOTMON_FS_FILE  *FileEntry;
     90   CHAR8            OpenFileAsciiFileName[MAX_NAME_LENGTH];
     91   CHAR8            *AsciiFileNameToCompare;
     92 
     93   // Go through all the files in the list and return the file handle
     94   for (Entry = GetFirstNode (&Instance->RootFile->Link);
     95        !IsNull (&Instance->RootFile->Link, Entry);
     96        Entry = GetNextNode (&Instance->RootFile->Link, Entry)
     97        )
     98   {
     99     FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
    100     if (FileEntry->Info != NULL) {
    101       UnicodeStrToAsciiStr (FileEntry->Info->FileName, OpenFileAsciiFileName);
    102       AsciiFileNameToCompare = OpenFileAsciiFileName;
    103     } else {
    104       AsciiFileNameToCompare = FileEntry->HwDescription.Footer.Filename;
    105     }
    106 
    107     if (AsciiStrCmp (AsciiFileNameToCompare, AsciiFileName) == 0) {
    108       *File = FileEntry;
    109       return EFI_SUCCESS;
    110     }
    111   }
    112   return EFI_NOT_FOUND;
    113 }
    114 
    115 EFI_STATUS
    116 BootMonGetFileFromPosition (
    117   IN  BOOTMON_FS_INSTANCE   *Instance,
    118   IN  UINTN                 Position,
    119   OUT BOOTMON_FS_FILE       **File
    120   )
    121 {
    122   LIST_ENTRY        *Entry;
    123   BOOTMON_FS_FILE   *FileEntry;
    124 
    125   // Go through all the files in the list and return the file handle
    126   for (Entry = GetFirstNode (&Instance->RootFile->Link);
    127        !IsNull (&Instance->RootFile->Link, Entry) && (&Instance->RootFile->Link != Entry);
    128        Entry = GetNextNode (&Instance->RootFile->Link, Entry)
    129        )
    130   {
    131     if (Position == 0) {
    132       FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
    133       *File = FileEntry;
    134       return EFI_SUCCESS;
    135     }
    136     Position--;
    137   }
    138   return EFI_NOT_FOUND;
    139 }
    140 
    141 EFI_STATUS
    142 BootMonFsCreateFile (
    143   IN  BOOTMON_FS_INSTANCE *Instance,
    144   OUT BOOTMON_FS_FILE     **File
    145   )
    146 {
    147   BOOTMON_FS_FILE *NewFile;
    148 
    149   NewFile = (BOOTMON_FS_FILE*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE));
    150   if (NewFile == NULL) {
    151     return EFI_OUT_OF_RESOURCES;
    152   }
    153 
    154   NewFile->Signature = BOOTMON_FS_FILE_SIGNATURE;
    155   InitializeListHead (&NewFile->Link);
    156   InitializeListHead (&NewFile->RegionToFlushLink);
    157   NewFile->Instance = Instance;
    158 
    159   // If the created file is the root file then create a directory EFI_FILE_PROTOCOL
    160   if (Instance->RootFile == *File) {
    161     CopyMem (&NewFile->File, &mBootMonFsRootTemplate, sizeof (mBootMonFsRootTemplate));
    162   } else {
    163     CopyMem (&NewFile->File, &mBootMonFsFileTemplate, sizeof (mBootMonFsFileTemplate));
    164   }
    165   *File = NewFile;
    166   return EFI_SUCCESS;
    167 }
    168 
    169 STATIC
    170 EFI_STATUS
    171 SupportedDevicePathsInit (
    172   VOID
    173   )
    174 {
    175   EFI_STATUS                          Status;
    176   CHAR16*                             DevicePathListStr;
    177   CHAR16*                             DevicePathStr;
    178   CHAR16*                             NextDevicePathStr;
    179   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
    180   EFI_DEVICE_PATH_PROTOCOL           *Instance;
    181 
    182   Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
    183   ASSERT_EFI_ERROR (Status);
    184 
    185   // Initialize Variable
    186   DevicePathListStr = (CHAR16*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths);
    187   mBootMonFsSupportedDevicePaths = NULL;
    188 
    189   // Extract the Device Path instances from the multi-device path string
    190   while ((DevicePathListStr != NULL) && (DevicePathListStr[0] != L'\0')) {
    191     NextDevicePathStr = StrStr (DevicePathListStr, L";");
    192     if (NextDevicePathStr == NULL) {
    193       DevicePathStr = DevicePathListStr;
    194       DevicePathListStr = NULL;
    195     } else {
    196       DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DevicePathListStr + 1) * sizeof (CHAR16), DevicePathListStr);
    197       if (DevicePathStr == NULL) {
    198         return EFI_OUT_OF_RESOURCES;
    199       }
    200       *(DevicePathStr + (NextDevicePathStr - DevicePathListStr)) = L'\0';
    201       DevicePathListStr = NextDevicePathStr;
    202       if (DevicePathListStr[0] == L';') {
    203         DevicePathListStr++;
    204       }
    205     }
    206 
    207     Instance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
    208     ASSERT (Instance != NULL);
    209     mBootMonFsSupportedDevicePaths = AppendDevicePathInstance (mBootMonFsSupportedDevicePaths, Instance);
    210 
    211     if (NextDevicePathStr != NULL) {
    212       FreePool (DevicePathStr);
    213     }
    214     FreePool (Instance);
    215   }
    216 
    217   if (mBootMonFsSupportedDevicePaths == NULL) {
    218     return EFI_UNSUPPORTED;
    219   } else {
    220     return EFI_SUCCESS;
    221   }
    222 }
    223 
    224 EFI_STATUS
    225 EFIAPI
    226 BootMonFsDriverSupported (
    227   IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
    228   IN        EFI_HANDLE                   ControllerHandle,
    229   IN        EFI_DEVICE_PATH_PROTOCOL    *DevicePath OPTIONAL
    230   )
    231 {
    232   EFI_DISK_IO_PROTOCOL  *DiskIo;
    233   EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;
    234   EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePath;
    235   EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePaths;
    236   EFI_STATUS Status;
    237   UINTN Size1;
    238   UINTN Size2;
    239 
    240   //
    241   // Open the IO Abstraction(s) needed to perform the supported test
    242   //
    243   Status = gBS->OpenProtocol (
    244                   ControllerHandle,
    245                   &gEfiDiskIoProtocolGuid,
    246                   (VOID **) &DiskIo,
    247                   gImageHandle,
    248                   ControllerHandle,
    249                   EFI_OPEN_PROTOCOL_BY_DRIVER
    250                   );
    251 
    252   if (EFI_ERROR (Status)) {
    253     return Status;
    254   }
    255   //
    256   // Close the I/O Abstraction(s) used to perform the supported test
    257   //
    258   gBS->CloseProtocol (
    259          ControllerHandle,
    260          &gEfiDiskIoProtocolGuid,
    261          gImageHandle,
    262          ControllerHandle
    263          );
    264 
    265   // Check that BlockIo protocol instance exists
    266   Status = gBS->OpenProtocol (
    267                   ControllerHandle,
    268                   &gEfiBlockIoProtocolGuid,
    269                   NULL,
    270                   gImageHandle,
    271                   ControllerHandle,
    272                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    273                   );
    274   if (EFI_ERROR (Status)) {
    275     return Status;
    276   }
    277 
    278   // Check if a DevicePath is attached to the handle
    279   Status = gBS->OpenProtocol (
    280                   ControllerHandle,
    281                   &gEfiDevicePathProtocolGuid,
    282                   (VOID **)&DevicePathProtocol,
    283                   gImageHandle,
    284                   ControllerHandle,
    285                   EFI_OPEN_PROTOCOL_BY_DRIVER
    286                   );
    287   if (EFI_ERROR (Status)) {
    288     return Status;
    289   }
    290 
    291   // Check if the Device Path is the one which contains the Boot Monitor File System
    292   Size1 = GetDevicePathSize (DevicePathProtocol);
    293 
    294   // Go through the list of Device Path Instances
    295   Status = EFI_UNSUPPORTED;
    296   SupportedDevicePaths = mBootMonFsSupportedDevicePaths;
    297   while (SupportedDevicePaths != NULL) {
    298     SupportedDevicePath = GetNextDevicePathInstance (&SupportedDevicePaths, &Size2);
    299 
    300     if ((Size1 == Size2) && (CompareMem (DevicePathProtocol, SupportedDevicePath, Size1) == 0)) {
    301       // The Device Path is supported
    302       Status = EFI_SUCCESS;
    303       break;
    304     }
    305   }
    306 
    307   gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, gImageHandle, ControllerHandle);
    308   return Status;
    309 }
    310 
    311 EFI_STATUS
    312 EFIAPI
    313 BootMonFsDriverStart (
    314   IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
    315   IN        EFI_HANDLE                   ControllerHandle,
    316   IN        EFI_DEVICE_PATH_PROTOCOL    *DevicePath OPTIONAL
    317   )
    318 {
    319   BOOTMON_FS_INSTANCE *Instance;
    320   EFI_STATUS           Status;
    321   UINTN                VolumeNameSize;
    322   EFI_FILE_INFO       *Info;
    323 
    324   Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));
    325   if (Instance == NULL) {
    326     return EFI_OUT_OF_RESOURCES;
    327   }
    328 
    329   // Initialize the BlockIo of the Instance
    330   Status = gBS->OpenProtocol (
    331                   ControllerHandle,
    332                   &gEfiBlockIoProtocolGuid,
    333                   (VOID **)&(Instance->BlockIo),
    334                   gImageHandle,
    335                   ControllerHandle,
    336                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    337                   );
    338   if (EFI_ERROR (Status)) {
    339     goto Error;
    340   }
    341 
    342   Status = gBS->OpenProtocol (
    343                   ControllerHandle,
    344                   &gEfiDiskIoProtocolGuid,
    345                   (VOID **)&(Instance->DiskIo),
    346                   gImageHandle,
    347                   ControllerHandle,
    348                   EFI_OPEN_PROTOCOL_BY_DRIVER
    349                   );
    350   if (EFI_ERROR (Status)) {
    351     goto Error;
    352   }
    353 
    354   //
    355   // Initialize the attributes of the Instance
    356   //
    357   Instance->Signature = BOOTMON_FS_SIGNATURE;
    358   Instance->ControllerHandle = ControllerHandle;
    359   Instance->Media = Instance->BlockIo->Media;
    360   Instance->Binding = DriverBinding;
    361 
    362     // Initialize the Simple File System Protocol
    363   Instance->Fs.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
    364   Instance->Fs.OpenVolume = OpenBootMonFsOpenVolume;
    365 
    366   // Volume name + L' ' + '2' digit number
    367   VolumeNameSize = StrSize (BOOTMON_FS_VOLUME_LABEL) + (3 * sizeof (CHAR16));
    368 
    369   // Initialize FileSystem Information
    370   Instance->FsInfo.Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + VolumeNameSize;
    371   Instance->FsInfo.BlockSize = Instance->Media->BlockSize;
    372   Instance->FsInfo.ReadOnly = FALSE;
    373   Instance->FsInfo.VolumeSize =
    374     Instance->Media->BlockSize * (Instance->Media->LastBlock - Instance->Media->LowestAlignedLba);
    375   CopyMem (Instance->FsInfo.VolumeLabel, BOOTMON_FS_VOLUME_LABEL, StrSize (BOOTMON_FS_VOLUME_LABEL));
    376 
    377   // Initialize the root file
    378   Status = BootMonFsCreateFile (Instance, &Instance->RootFile);
    379   if (EFI_ERROR (Status)) {
    380     goto Error;
    381   }
    382 
    383   Info = AllocateZeroPool (sizeof (EFI_FILE_INFO));
    384   if (Info == NULL) {
    385     Status = EFI_OUT_OF_RESOURCES;
    386     goto Error;
    387   }
    388   Instance->RootFile->Info = Info;
    389 
    390   // Initialize the DevicePath of the Instance
    391   Status = gBS->OpenProtocol (
    392                   ControllerHandle,
    393                   &gEfiDevicePathProtocolGuid,
    394                   (VOID **)&(Instance->DevicePath),
    395                   gImageHandle,
    396                   ControllerHandle,
    397                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    398                   );
    399   if (EFI_ERROR (Status)) {
    400     goto Error;
    401   }
    402 
    403   //
    404   // Install the Simple File System Protocol
    405   //
    406   Status = gBS->InstallMultipleProtocolInterfaces (
    407                       &ControllerHandle,
    408                       &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
    409                       NULL
    410                       );
    411   if (EFI_ERROR (Status)) {
    412     goto Error;
    413   }
    414 
    415   InsertTailList (&mInstances, &Instance->Link);
    416 
    417   return EFI_SUCCESS;
    418 
    419 Error:
    420 
    421     if (Instance->RootFile != NULL) {
    422       if (Instance->RootFile->Info != NULL) {
    423         FreePool (Instance->RootFile->Info);
    424       }
    425       FreePool (Instance->RootFile);
    426     }
    427     FreePool (Instance);
    428 
    429   return Status;
    430 }
    431 
    432 
    433 EFI_STATUS
    434 EFIAPI
    435 BootMonFsDriverStop (
    436   IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
    437   IN        EFI_HANDLE                   ControllerHandle,
    438   IN        UINTN                        NumberOfChildren,
    439   IN        EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
    440   )
    441 {
    442   BOOTMON_FS_INSTANCE *Instance;
    443   LIST_ENTRY          *Link;
    444   EFI_STATUS           Status;
    445   BOOLEAN              InstanceFound;
    446 
    447   // Find instance from ControllerHandle.
    448   Instance = NULL;
    449   InstanceFound = FALSE;
    450   // For each instance in mInstances:
    451   for (Link = GetFirstNode (&mInstances); !IsNull (&mInstances, Link); Link = GetNextNode (&mInstances, Link)) {
    452     Instance = BOOTMON_FS_FROM_LINK (Link);
    453 
    454     if (Instance->ControllerHandle == ControllerHandle) {
    455       InstanceFound = TRUE;
    456       break;
    457     }
    458   }
    459   ASSERT (InstanceFound == TRUE);
    460 
    461   gBS->CloseProtocol (
    462       ControllerHandle,
    463       &gEfiDevicePathProtocolGuid,
    464       DriverBinding->ImageHandle,
    465       ControllerHandle);
    466 
    467   gBS->CloseProtocol (
    468       ControllerHandle,
    469       &gEfiDiskIoProtocolGuid,
    470       DriverBinding->ImageHandle,
    471       ControllerHandle);
    472 
    473   gBS->CloseProtocol (
    474       ControllerHandle,
    475       &gEfiBlockIoProtocolGuid,
    476       DriverBinding->ImageHandle,
    477       ControllerHandle);
    478 
    479   Status = gBS->UninstallMultipleProtocolInterfaces (
    480       &ControllerHandle,
    481       &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
    482       NULL);
    483 
    484   FreePool (Instance->RootFile->Info);
    485   FreePool (Instance->RootFile);
    486   FreePool (Instance);
    487 
    488   return Status;
    489 }
    490 
    491 //
    492 // Simple Network Protocol Driver Global Variables
    493 //
    494 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding = {
    495   BootMonFsDriverSupported,
    496   BootMonFsDriverStart,
    497   BootMonFsDriverStop,
    498   0xa,
    499   NULL,
    500   NULL
    501 };
    502 
    503 EFI_STATUS
    504 EFIAPI
    505 BootMonFsEntryPoint (
    506   IN EFI_HANDLE                            ImageHandle,
    507   IN EFI_SYSTEM_TABLE                      *SystemTable
    508   )
    509 {
    510   EFI_STATUS  Status;
    511 
    512   InitializeListHead (&mInstances);
    513 
    514   // Initialize the list of Device Paths that could support BootMonFs
    515   Status = SupportedDevicePathsInit ();
    516   if (!EFI_ERROR (Status)) {
    517     Status = gBS->InstallMultipleProtocolInterfaces (
    518                     &ImageHandle,
    519                     &gEfiDriverBindingProtocolGuid, &mBootMonFsDriverBinding,
    520                     NULL
    521                     );
    522     ASSERT_EFI_ERROR (Status);
    523   } else {
    524     DEBUG((EFI_D_ERROR,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));
    525   }
    526 
    527   return Status;
    528 }
    529