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