blob: 346c360292eb1ec0b65b54f14e9a066814706a9d [file] [log] [blame]
/** @file
*
* Copyright (c) 2012-2014, ARM Limited. All rights reserved.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/
#include <Library/IoLib.h>
#include <Library/NorFlashPlatformLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/SimpleFileSystem.h>
#include "BootMonFsInternal.h"
UINT32
BootMonFsChecksum (
IN VOID *Data,
IN UINT32 Size
)
{
UINT32 *Ptr;
UINT32 Word;
UINT32 Checksum;
ASSERT (Size % 4 == 0);
Checksum = 0;
Ptr = (UINT32*)Data;
while (Size > 0) {
Word = *Ptr++;
Size -= 4;
if (Word > ~Checksum) {
Checksum++;
}
Checksum += Word;
}
return ~Checksum;
}
EFI_STATUS
BootMonFsComputeFooterChecksum (
IN OUT HW_IMAGE_DESCRIPTION *Footer
)
{
HW_IMAGE_DESCRIPTION *Description;
UINT32 Index;
Footer->Attributes = 1;
Description = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));
if (Description == NULL) {
DEBUG ((DEBUG_ERROR, "BootMonFsComputeFooterChecksum: Unable to allocate memory.\n"));
return EFI_OUT_OF_RESOURCES;
}
// Copy over to temporary shim
CopyMem (Description, Footer, sizeof (HW_IMAGE_DESCRIPTION));
// BootMon doesn't checksum the previous checksum
Description->FooterChecksum = 0;
// Blank out regions which aren't being used.
for (Index = Footer->RegionCount; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {
Description->Region[Index].Checksum = 0;
Description->Region[Index].LoadAddress = 0;
Description->Region[Index].Offset = 0;
Description->Region[Index].Size = 0;
}
// Compute the checksum
Footer->FooterChecksum = BootMonFsChecksum (Description, sizeof (HW_IMAGE_DESCRIPTION));
FreePool (Description);
return EFI_SUCCESS;
}
BOOLEAN
BootMonFsIsImageValid (
IN HW_IMAGE_DESCRIPTION *Desc,
IN EFI_LBA Lba
)
{
EFI_STATUS Status;
HW_IMAGE_FOOTER *Footer;
UINT32 Checksum;
Footer = &Desc->Footer;
// Check that the verification bytes are present
if ((Footer->FooterSignature1 != HW_IMAGE_FOOTER_SIGNATURE_1) ||
(Footer->FooterSignature2 != HW_IMAGE_FOOTER_SIGNATURE_2)) {
return FALSE;
}
if (Footer->Version == HW_IMAGE_FOOTER_VERSION) {
if (Footer->Offset != HW_IMAGE_FOOTER_OFFSET) {
return FALSE;
}
} else if (Footer->Version == HW_IMAGE_FOOTER_VERSION2) {
if (Footer->Offset != HW_IMAGE_FOOTER_OFFSET2) {
return FALSE;
}
} else {
return FALSE;
}
Checksum = Desc->FooterChecksum;
Status = BootMonFsComputeFooterChecksum (Desc);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Warning: failed to compute checksum for image '%a'\n", Desc->Footer.Filename));
}
if (Desc->FooterChecksum != Checksum) {
DEBUG ((DEBUG_ERROR, "Warning: image '%a' checksum mismatch.\n", Desc->Footer.Filename));
}
if ((Desc->BlockEnd != Lba) || (Desc->BlockStart > Desc->BlockEnd)) {
return FALSE;
}
return TRUE;
}
STATIC
EFI_STATUS
BootMonFsDiscoverNextImage (
IN BOOTMON_FS_INSTANCE *Instance,
IN OUT EFI_LBA *LbaStart,
IN OUT BOOTMON_FS_FILE *File
)
{
EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_LBA CurrentLba;
UINT64 DescOffset;
EFI_STATUS Status;
DiskIo = Instance->DiskIo;
CurrentLba = *LbaStart;
// Look for images in the rest of this block
while (CurrentLba <= Instance->Media->LastBlock) {
// Work out the byte offset into media of the image description in this block
// If present, the image description is at the very end of the block.
DescOffset = ((CurrentLba + 1) * Instance->Media->BlockSize) - sizeof (HW_IMAGE_DESCRIPTION);
// Read the image description from media
Status = DiskIo->ReadDisk (DiskIo,
Instance->Media->MediaId,
DescOffset,
sizeof (HW_IMAGE_DESCRIPTION),
&File->HwDescription
);
if (EFI_ERROR (Status)) {
return Status;
}
// If we found a valid image description...
if (BootMonFsIsImageValid (&File->HwDescription, (CurrentLba - Instance->Media->LowestAlignedLba))) {
DEBUG ((EFI_D_ERROR, "Found image: %a in block %d.\n",
&(File->HwDescription.Footer.Filename),
(UINTN)(CurrentLba - Instance->Media->LowestAlignedLba)
));
File->HwDescAddress = DescOffset;
*LbaStart = CurrentLba + 1;
return EFI_SUCCESS;
} else {
CurrentLba++;
}
}
*LbaStart = CurrentLba;
return EFI_NOT_FOUND;
}
EFI_STATUS
BootMonFsInitialize (
IN BOOTMON_FS_INSTANCE *Instance
)
{
EFI_STATUS Status;
EFI_LBA Lba;
UINT32 ImageCount;
BOOTMON_FS_FILE *NewFile;
ImageCount = 0;
Lba = 0;
while (1) {
Status = BootMonFsCreateFile (Instance, &NewFile);
if (EFI_ERROR (Status)) {
return Status;
}
Status = BootMonFsDiscoverNextImage (Instance, &Lba, NewFile);
if (EFI_ERROR (Status)) {
// Free NewFile allocated by BootMonFsCreateFile ()
FreePool (NewFile);
break;
}
InsertTailList (&Instance->RootFile->Link, &NewFile->Link);
ImageCount++;
}
Instance->Initialized = TRUE;
return EFI_SUCCESS;
}