BootMonFsImages.c revision 79e12331ef1e7c24b5be70d7bc79977ca103bab4
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
24UINT32
25BootMonFsChecksum (
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
53EFI_STATUS
54BootMonFsComputeFooterChecksum (
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
91BOOLEAN
92BootMonFsIsImageValid (
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
138STATIC
139EFI_STATUS
140BootMonFsDiscoverNextImage (
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
191EFI_STATUS
192BootMonFsInitialize (
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