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
BootMonFsChecksum(IN VOID * Data,IN UINT32 Size)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
BootMonFsComputeFooterChecksum(IN OUT HW_IMAGE_DESCRIPTION * Footer)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
BootMonFsIsImageValid(IN HW_IMAGE_DESCRIPTION * Desc,IN EFI_LBA Lba)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
BootMonFsDiscoverNextImage(IN BOOTMON_FS_INSTANCE * Instance,IN OUT EFI_LBA * LbaStart,IN OUT BOOTMON_FS_FILE * File)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
BootMonFsInitialize(IN BOOTMON_FS_INSTANCE * Instance)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