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/IoLib.h>
     16 #include <Library/NorFlashPlatformLib.h>
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/MemoryAllocationLib.h>
     19 
     20 #include <Protocol/SimpleFileSystem.h>
     21 
     22 #include "BootMonFsInternal.h"
     23 
     24 UINT32
     25 BootMonFsChecksum (
     26   IN VOID   *Data,
     27   IN UINT32 Size
     28   )
     29 {
     30   UINT32  *Ptr;
     31   UINT32  Word;
     32   UINT32  Checksum;
     33 
     34   ASSERT (Size % 4 == 0);
     35 
     36   Checksum = 0;
     37   Ptr = (UINT32*)Data;
     38 
     39   while (Size > 0) {
     40     Word = *Ptr++;
     41     Size -= 4;
     42 
     43     if (Word > ~Checksum) {
     44       Checksum++;
     45     }
     46 
     47     Checksum += Word;
     48   }
     49 
     50   return ~Checksum;
     51 }
     52 
     53 EFI_STATUS
     54 BootMonFsComputeFooterChecksum (
     55   IN OUT HW_IMAGE_DESCRIPTION *Footer
     56   )
     57 {
     58   HW_IMAGE_DESCRIPTION *Description;
     59   UINT32                Index;
     60 
     61   Footer->Attributes = 1;
     62 
     63   Description = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));
     64   if (Description == NULL) {
     65     DEBUG ((DEBUG_ERROR, "BootMonFsComputeFooterChecksum: Unable to allocate memory.\n"));
     66     return EFI_OUT_OF_RESOURCES;
     67   }
     68 
     69   // Copy over to temporary shim
     70   CopyMem (Description, Footer, sizeof (HW_IMAGE_DESCRIPTION));
     71 
     72   // BootMon doesn't checksum the previous checksum
     73   Description->FooterChecksum = 0;
     74 
     75   // Blank out regions which aren't being used.
     76   for (Index = Footer->RegionCount; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {
     77     Description->Region[Index].Checksum = 0;
     78     Description->Region[Index].LoadAddress = 0;
     79     Description->Region[Index].Offset = 0;
     80     Description->Region[Index].Size = 0;
     81   }
     82 
     83   // Compute the checksum
     84   Footer->FooterChecksum = BootMonFsChecksum (Description, sizeof (HW_IMAGE_DESCRIPTION));
     85 
     86   FreePool (Description);
     87 
     88   return EFI_SUCCESS;
     89 }
     90 
     91 BOOLEAN
     92 BootMonFsIsImageValid (
     93   IN HW_IMAGE_DESCRIPTION  *Desc,
     94   IN EFI_LBA                Lba
     95   )
     96 {
     97   EFI_STATUS            Status;
     98   HW_IMAGE_FOOTER      *Footer;
     99   UINT32                Checksum;
    100 
    101   Footer = &Desc->Footer;
    102 
    103   // Check that the verification bytes are present
    104   if ((Footer->FooterSignature1 != HW_IMAGE_FOOTER_SIGNATURE_1) ||
    105       (Footer->FooterSignature2 != HW_IMAGE_FOOTER_SIGNATURE_2)) {
    106     return FALSE;
    107   }
    108 
    109   if (Footer->Version == HW_IMAGE_FOOTER_VERSION) {
    110     if (Footer->Offset != HW_IMAGE_FOOTER_OFFSET) {
    111       return FALSE;
    112     }
    113   } else if (Footer->Version == HW_IMAGE_FOOTER_VERSION2) {
    114     if (Footer->Offset != HW_IMAGE_FOOTER_OFFSET2) {
    115       return FALSE;
    116     }
    117   } else {
    118     return FALSE;
    119   }
    120 
    121   Checksum = Desc->FooterChecksum;
    122   Status = BootMonFsComputeFooterChecksum (Desc);
    123   if (EFI_ERROR (Status)) {
    124     DEBUG ((DEBUG_ERROR, "Warning: failed to compute checksum for image '%a'\n", Desc->Footer.Filename));
    125   }
    126 
    127   if (Desc->FooterChecksum != Checksum) {
    128     DEBUG ((DEBUG_ERROR, "Warning: image '%a' checksum mismatch.\n", Desc->Footer.Filename));
    129   }
    130 
    131   if ((Desc->BlockEnd != Lba) || (Desc->BlockStart > Desc->BlockEnd)) {
    132     return FALSE;
    133   }
    134 
    135   return TRUE;
    136 }
    137 
    138 STATIC
    139 EFI_STATUS
    140 BootMonFsDiscoverNextImage (
    141   IN     BOOTMON_FS_INSTANCE      *Instance,
    142   IN OUT EFI_LBA                  *LbaStart,
    143   IN OUT BOOTMON_FS_FILE          *File
    144   )
    145 {
    146   EFI_DISK_IO_PROTOCOL  *DiskIo;
    147   EFI_LBA                CurrentLba;
    148   UINT64                 DescOffset;
    149   EFI_STATUS             Status;
    150 
    151   DiskIo = Instance->DiskIo;
    152 
    153   CurrentLba = *LbaStart;
    154 
    155   // Look for images in the rest of this block
    156   while (CurrentLba <= Instance->Media->LastBlock) {
    157     // Work out the byte offset into media of the image description in this block
    158     // If present, the image description is at the very end of the block.
    159     DescOffset = ((CurrentLba + 1) * Instance->Media->BlockSize) - sizeof (HW_IMAGE_DESCRIPTION);
    160 
    161     // Read the image description from media
    162     Status = DiskIo->ReadDisk (DiskIo,
    163                        Instance->Media->MediaId,
    164                        DescOffset,
    165                        sizeof (HW_IMAGE_DESCRIPTION),
    166                        &File->HwDescription
    167                        );
    168     if (EFI_ERROR (Status)) {
    169       return Status;
    170     }
    171 
    172     // If we found a valid image description...
    173     if (BootMonFsIsImageValid (&File->HwDescription, (CurrentLba - Instance->Media->LowestAlignedLba))) {
    174       DEBUG ((EFI_D_ERROR, "Found image: %a in block %d.\n",
    175         &(File->HwDescription.Footer.Filename),
    176         (UINTN)(CurrentLba - Instance->Media->LowestAlignedLba)
    177         ));
    178       File->HwDescAddress = DescOffset;
    179 
    180       *LbaStart = CurrentLba + 1;
    181       return EFI_SUCCESS;
    182     } else {
    183       CurrentLba++;
    184     }
    185   }
    186 
    187   *LbaStart = CurrentLba;
    188   return EFI_NOT_FOUND;
    189 }
    190 
    191 EFI_STATUS
    192 BootMonFsInitialize (
    193   IN BOOTMON_FS_INSTANCE *Instance
    194   )
    195 {
    196   EFI_STATUS               Status;
    197   EFI_LBA                  Lba;
    198   UINT32                   ImageCount;
    199   BOOTMON_FS_FILE          *NewFile;
    200 
    201   ImageCount = 0;
    202   Lba = 0;
    203 
    204   while (1) {
    205     Status = BootMonFsCreateFile (Instance, &NewFile);
    206     if (EFI_ERROR (Status)) {
    207       return Status;
    208     }
    209 
    210     Status = BootMonFsDiscoverNextImage (Instance, &Lba, NewFile);
    211     if (EFI_ERROR (Status)) {
    212       // Free NewFile allocated by BootMonFsCreateFile ()
    213       FreePool (NewFile);
    214       break;
    215     }
    216     InsertTailList (&Instance->RootFile->Link, &NewFile->Link);
    217     ImageCount++;
    218   }
    219 
    220   Instance->Initialized = TRUE;
    221   return EFI_SUCCESS;
    222 }
    223