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