1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker * Copyright 2010, Google LLC.
3*0d6140beSAndroid Build Coastguard Worker * Copyright 2018-present, Facebook Inc.
4*0d6140beSAndroid Build Coastguard Worker * All rights reserved.
5*0d6140beSAndroid Build Coastguard Worker *
6*0d6140beSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
7*0d6140beSAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are
8*0d6140beSAndroid Build Coastguard Worker * met:
9*0d6140beSAndroid Build Coastguard Worker *
10*0d6140beSAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright
11*0d6140beSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
12*0d6140beSAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above
13*0d6140beSAndroid Build Coastguard Worker * copyright notice, this list of conditions and the following disclaimer
14*0d6140beSAndroid Build Coastguard Worker * in the documentation and/or other materials provided with the
15*0d6140beSAndroid Build Coastguard Worker * distribution.
16*0d6140beSAndroid Build Coastguard Worker * * Neither the name of Google Inc. nor the names of its
17*0d6140beSAndroid Build Coastguard Worker * contributors may be used to endorse or promote products derived from
18*0d6140beSAndroid Build Coastguard Worker * this software without specific prior written permission.
19*0d6140beSAndroid Build Coastguard Worker *
20*0d6140beSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*0d6140beSAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*0d6140beSAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*0d6140beSAndroid Build Coastguard Worker * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*0d6140beSAndroid Build Coastguard Worker * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*0d6140beSAndroid Build Coastguard Worker * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*0d6140beSAndroid Build Coastguard Worker * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*0d6140beSAndroid Build Coastguard Worker * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*0d6140beSAndroid Build Coastguard Worker * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*0d6140beSAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*0d6140beSAndroid Build Coastguard Worker * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*0d6140beSAndroid Build Coastguard Worker *
32*0d6140beSAndroid Build Coastguard Worker * Alternatively, this software may be distributed under the terms of the
33*0d6140beSAndroid Build Coastguard Worker * GNU General Public License ("GPL") version 2 as published by the Free
34*0d6140beSAndroid Build Coastguard Worker * Software Foundation.
35*0d6140beSAndroid Build Coastguard Worker */
36*0d6140beSAndroid Build Coastguard Worker
37*0d6140beSAndroid Build Coastguard Worker #include <ctype.h>
38*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
39*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
40*0d6140beSAndroid Build Coastguard Worker #include <string.h>
41*0d6140beSAndroid Build Coastguard Worker #include <sys/types.h>
42*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
43*0d6140beSAndroid Build Coastguard Worker #include "fmap.h"
44*0d6140beSAndroid Build Coastguard Worker
fmap_size(const struct fmap * fmap)45*0d6140beSAndroid Build Coastguard Worker static size_t fmap_size(const struct fmap *fmap)
46*0d6140beSAndroid Build Coastguard Worker {
47*0d6140beSAndroid Build Coastguard Worker return sizeof(*fmap) + (fmap->nareas * sizeof(struct fmap_area));
48*0d6140beSAndroid Build Coastguard Worker }
49*0d6140beSAndroid Build Coastguard Worker
50*0d6140beSAndroid Build Coastguard Worker /* Make a best-effort assessment if the given fmap is real */
is_valid_fmap(const struct fmap * fmap)51*0d6140beSAndroid Build Coastguard Worker static int is_valid_fmap(const struct fmap *fmap)
52*0d6140beSAndroid Build Coastguard Worker {
53*0d6140beSAndroid Build Coastguard Worker if (memcmp(fmap, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE)) != 0)
54*0d6140beSAndroid Build Coastguard Worker return 0;
55*0d6140beSAndroid Build Coastguard Worker /* strings containing the magic tend to fail here */
56*0d6140beSAndroid Build Coastguard Worker if (fmap->ver_major != FMAP_VER_MAJOR)
57*0d6140beSAndroid Build Coastguard Worker return 0;
58*0d6140beSAndroid Build Coastguard Worker /* a basic consistency check: flash address space size should be larger
59*0d6140beSAndroid Build Coastguard Worker * than the size of the fmap data structure */
60*0d6140beSAndroid Build Coastguard Worker if (fmap->size < fmap_size(fmap))
61*0d6140beSAndroid Build Coastguard Worker return 0;
62*0d6140beSAndroid Build Coastguard Worker
63*0d6140beSAndroid Build Coastguard Worker /* fmap-alikes along binary data tend to fail on having a valid,
64*0d6140beSAndroid Build Coastguard Worker * null-terminated string in the name field.*/
65*0d6140beSAndroid Build Coastguard Worker int i;
66*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < FMAP_STRLEN; i++) {
67*0d6140beSAndroid Build Coastguard Worker if (fmap->name[i] == 0)
68*0d6140beSAndroid Build Coastguard Worker break;
69*0d6140beSAndroid Build Coastguard Worker if (!isgraph(fmap->name[i]))
70*0d6140beSAndroid Build Coastguard Worker return 0;
71*0d6140beSAndroid Build Coastguard Worker if (i == FMAP_STRLEN - 1) {
72*0d6140beSAndroid Build Coastguard Worker /* name is specified to be null terminated single-word string
73*0d6140beSAndroid Build Coastguard Worker * without spaces. We did not break in the 0 test, we know it
74*0d6140beSAndroid Build Coastguard Worker * is a printable spaceless string but we're seeing FMAP_STRLEN
75*0d6140beSAndroid Build Coastguard Worker * symbols, which is one too many.
76*0d6140beSAndroid Build Coastguard Worker */
77*0d6140beSAndroid Build Coastguard Worker return 0;
78*0d6140beSAndroid Build Coastguard Worker }
79*0d6140beSAndroid Build Coastguard Worker }
80*0d6140beSAndroid Build Coastguard Worker return 1;
81*0d6140beSAndroid Build Coastguard Worker
82*0d6140beSAndroid Build Coastguard Worker }
83*0d6140beSAndroid Build Coastguard Worker
84*0d6140beSAndroid Build Coastguard Worker /**
85*0d6140beSAndroid Build Coastguard Worker * @brief Do a brute-force linear search for fmap in provided buffer
86*0d6140beSAndroid Build Coastguard Worker *
87*0d6140beSAndroid Build Coastguard Worker * @param[in] buffer The buffer to search
88*0d6140beSAndroid Build Coastguard Worker * @param[in] len Length (in bytes) to search
89*0d6140beSAndroid Build Coastguard Worker *
90*0d6140beSAndroid Build Coastguard Worker * @return offset in buffer where fmap is found if successful
91*0d6140beSAndroid Build Coastguard Worker * -1 to indicate that fmap was not found
92*0d6140beSAndroid Build Coastguard Worker * -2 to indicate fmap is truncated or exceeds buffer + len
93*0d6140beSAndroid Build Coastguard Worker */
fmap_lsearch(const uint8_t * buf,size_t len)94*0d6140beSAndroid Build Coastguard Worker static ssize_t fmap_lsearch(const uint8_t *buf, size_t len)
95*0d6140beSAndroid Build Coastguard Worker {
96*0d6140beSAndroid Build Coastguard Worker ssize_t offset;
97*0d6140beSAndroid Build Coastguard Worker bool fmap_found = false;
98*0d6140beSAndroid Build Coastguard Worker
99*0d6140beSAndroid Build Coastguard Worker if (len < sizeof(struct fmap))
100*0d6140beSAndroid Build Coastguard Worker return -1;
101*0d6140beSAndroid Build Coastguard Worker
102*0d6140beSAndroid Build Coastguard Worker for (offset = 0; offset <= (ssize_t)(len - sizeof(struct fmap)); offset++) {
103*0d6140beSAndroid Build Coastguard Worker if (is_valid_fmap((struct fmap *)&buf[offset])) {
104*0d6140beSAndroid Build Coastguard Worker fmap_found = true;
105*0d6140beSAndroid Build Coastguard Worker break;
106*0d6140beSAndroid Build Coastguard Worker }
107*0d6140beSAndroid Build Coastguard Worker }
108*0d6140beSAndroid Build Coastguard Worker
109*0d6140beSAndroid Build Coastguard Worker if (!fmap_found)
110*0d6140beSAndroid Build Coastguard Worker return -1;
111*0d6140beSAndroid Build Coastguard Worker
112*0d6140beSAndroid Build Coastguard Worker if (offset + fmap_size((struct fmap *)&buf[offset]) > len) {
113*0d6140beSAndroid Build Coastguard Worker msg_gerr("fmap size exceeds buffer boundary.\n");
114*0d6140beSAndroid Build Coastguard Worker return -2;
115*0d6140beSAndroid Build Coastguard Worker }
116*0d6140beSAndroid Build Coastguard Worker
117*0d6140beSAndroid Build Coastguard Worker return offset;
118*0d6140beSAndroid Build Coastguard Worker }
119*0d6140beSAndroid Build Coastguard Worker
120*0d6140beSAndroid Build Coastguard Worker /**
121*0d6140beSAndroid Build Coastguard Worker * @brief Read fmap from provided buffer and copy it to fmap_out
122*0d6140beSAndroid Build Coastguard Worker *
123*0d6140beSAndroid Build Coastguard Worker * @param[out] fmap_out Double-pointer to location to store fmap contents.
124*0d6140beSAndroid Build Coastguard Worker * Caller must free allocated fmap contents.
125*0d6140beSAndroid Build Coastguard Worker * @param[in] buf Buffer to search
126*0d6140beSAndroid Build Coastguard Worker * @param[in] len Length (in bytes) to search
127*0d6140beSAndroid Build Coastguard Worker *
128*0d6140beSAndroid Build Coastguard Worker * @return 0 if successful
129*0d6140beSAndroid Build Coastguard Worker * 1 to indicate error
130*0d6140beSAndroid Build Coastguard Worker * 2 to indicate fmap is not found
131*0d6140beSAndroid Build Coastguard Worker */
fmap_read_from_buffer(struct fmap ** fmap_out,const uint8_t * const buf,size_t len)132*0d6140beSAndroid Build Coastguard Worker int fmap_read_from_buffer(struct fmap **fmap_out, const uint8_t *const buf, size_t len)
133*0d6140beSAndroid Build Coastguard Worker {
134*0d6140beSAndroid Build Coastguard Worker ssize_t offset = fmap_lsearch(buf, len);
135*0d6140beSAndroid Build Coastguard Worker if (offset < 0) {
136*0d6140beSAndroid Build Coastguard Worker msg_gdbg("Unable to find fmap in provided buffer.\n");
137*0d6140beSAndroid Build Coastguard Worker return 2;
138*0d6140beSAndroid Build Coastguard Worker }
139*0d6140beSAndroid Build Coastguard Worker msg_gdbg("Found fmap at offset 0x%06zx\n", (size_t)offset);
140*0d6140beSAndroid Build Coastguard Worker
141*0d6140beSAndroid Build Coastguard Worker const struct fmap *fmap = (const struct fmap *)(buf + offset);
142*0d6140beSAndroid Build Coastguard Worker *fmap_out = malloc(fmap_size(fmap));
143*0d6140beSAndroid Build Coastguard Worker if (*fmap_out == NULL) {
144*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory.\n");
145*0d6140beSAndroid Build Coastguard Worker return 1;
146*0d6140beSAndroid Build Coastguard Worker }
147*0d6140beSAndroid Build Coastguard Worker
148*0d6140beSAndroid Build Coastguard Worker memcpy(*fmap_out, fmap, fmap_size(fmap));
149*0d6140beSAndroid Build Coastguard Worker return 0;
150*0d6140beSAndroid Build Coastguard Worker }
151*0d6140beSAndroid Build Coastguard Worker
fmap_lsearch_rom(struct fmap ** fmap_out,struct flashctx * const flashctx,size_t rom_offset,size_t len)152*0d6140beSAndroid Build Coastguard Worker static int fmap_lsearch_rom(struct fmap **fmap_out,
153*0d6140beSAndroid Build Coastguard Worker struct flashctx *const flashctx, size_t rom_offset, size_t len)
154*0d6140beSAndroid Build Coastguard Worker {
155*0d6140beSAndroid Build Coastguard Worker int ret = -1;
156*0d6140beSAndroid Build Coastguard Worker uint8_t *buf;
157*0d6140beSAndroid Build Coastguard Worker
158*0d6140beSAndroid Build Coastguard Worker if (prepare_flash_access(flashctx, true, false, false, false))
159*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
160*0d6140beSAndroid Build Coastguard Worker
161*0d6140beSAndroid Build Coastguard Worker /* likely more memory than we need, but it simplifies handling and
162*0d6140beSAndroid Build Coastguard Worker * printing offsets to keep them uniform with what's on the ROM */
163*0d6140beSAndroid Build Coastguard Worker buf = malloc(rom_offset + len);
164*0d6140beSAndroid Build Coastguard Worker if (!buf) {
165*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory.\n");
166*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
167*0d6140beSAndroid Build Coastguard Worker }
168*0d6140beSAndroid Build Coastguard Worker
169*0d6140beSAndroid Build Coastguard Worker ret = read_flash(flashctx, buf + rom_offset, rom_offset, len);
170*0d6140beSAndroid Build Coastguard Worker if (ret) {
171*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Cannot read ROM contents.\n");
172*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
173*0d6140beSAndroid Build Coastguard Worker }
174*0d6140beSAndroid Build Coastguard Worker
175*0d6140beSAndroid Build Coastguard Worker ret = fmap_read_from_buffer(fmap_out, buf + rom_offset, len);
176*0d6140beSAndroid Build Coastguard Worker _free_ret:
177*0d6140beSAndroid Build Coastguard Worker free(buf);
178*0d6140beSAndroid Build Coastguard Worker _finalize_ret:
179*0d6140beSAndroid Build Coastguard Worker finalize_flash_access(flashctx);
180*0d6140beSAndroid Build Coastguard Worker return ret;
181*0d6140beSAndroid Build Coastguard Worker }
182*0d6140beSAndroid Build Coastguard Worker
fmap_bsearch_rom(struct fmap ** fmap_out,struct flashctx * const flashctx,size_t rom_offset,size_t len,size_t min_stride)183*0d6140beSAndroid Build Coastguard Worker static int fmap_bsearch_rom(struct fmap **fmap_out, struct flashctx *const flashctx,
184*0d6140beSAndroid Build Coastguard Worker size_t rom_offset, size_t len, size_t min_stride)
185*0d6140beSAndroid Build Coastguard Worker {
186*0d6140beSAndroid Build Coastguard Worker size_t stride, fmap_len = 0;
187*0d6140beSAndroid Build Coastguard Worker int ret = 1;
188*0d6140beSAndroid Build Coastguard Worker bool fmap_found = false;
189*0d6140beSAndroid Build Coastguard Worker bool check_offset_0 = true;
190*0d6140beSAndroid Build Coastguard Worker struct fmap *fmap;
191*0d6140beSAndroid Build Coastguard Worker const unsigned int chip_size = flashctx->chip->total_size * 1024;
192*0d6140beSAndroid Build Coastguard Worker const int sig_len = strlen(FMAP_SIGNATURE);
193*0d6140beSAndroid Build Coastguard Worker
194*0d6140beSAndroid Build Coastguard Worker if (rom_offset + len > flashctx->chip->total_size * 1024)
195*0d6140beSAndroid Build Coastguard Worker return 1;
196*0d6140beSAndroid Build Coastguard Worker
197*0d6140beSAndroid Build Coastguard Worker if (len < sizeof(*fmap))
198*0d6140beSAndroid Build Coastguard Worker return 1;
199*0d6140beSAndroid Build Coastguard Worker
200*0d6140beSAndroid Build Coastguard Worker if (prepare_flash_access(flashctx, true, false, false, false))
201*0d6140beSAndroid Build Coastguard Worker return 1;
202*0d6140beSAndroid Build Coastguard Worker
203*0d6140beSAndroid Build Coastguard Worker fmap = malloc(sizeof(*fmap));
204*0d6140beSAndroid Build Coastguard Worker if (!fmap) {
205*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory.\n");
206*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
207*0d6140beSAndroid Build Coastguard Worker }
208*0d6140beSAndroid Build Coastguard Worker
209*0d6140beSAndroid Build Coastguard Worker /*
210*0d6140beSAndroid Build Coastguard Worker * For efficient operation, we start with the largest stride possible
211*0d6140beSAndroid Build Coastguard Worker * and then decrease the stride on each iteration. Also, check for a
212*0d6140beSAndroid Build Coastguard Worker * remainder when modding the offset with the previous stride. This
213*0d6140beSAndroid Build Coastguard Worker * makes it so that each offset is only checked once.
214*0d6140beSAndroid Build Coastguard Worker *
215*0d6140beSAndroid Build Coastguard Worker * Zero (rom_offset == 0) is a special case and is handled using a
216*0d6140beSAndroid Build Coastguard Worker * variable to track whether or not we've checked it.
217*0d6140beSAndroid Build Coastguard Worker */
218*0d6140beSAndroid Build Coastguard Worker size_t offset;
219*0d6140beSAndroid Build Coastguard Worker for (stride = chip_size / 2; stride >= min_stride; stride /= 2) {
220*0d6140beSAndroid Build Coastguard Worker if (stride > len)
221*0d6140beSAndroid Build Coastguard Worker continue;
222*0d6140beSAndroid Build Coastguard Worker
223*0d6140beSAndroid Build Coastguard Worker for (offset = rom_offset;
224*0d6140beSAndroid Build Coastguard Worker offset <= rom_offset + len - sizeof(struct fmap);
225*0d6140beSAndroid Build Coastguard Worker offset += stride) {
226*0d6140beSAndroid Build Coastguard Worker if ((offset % (stride * 2) == 0) && (offset != 0))
227*0d6140beSAndroid Build Coastguard Worker continue;
228*0d6140beSAndroid Build Coastguard Worker if (offset == 0 && !check_offset_0)
229*0d6140beSAndroid Build Coastguard Worker continue;
230*0d6140beSAndroid Build Coastguard Worker check_offset_0 = false;
231*0d6140beSAndroid Build Coastguard Worker
232*0d6140beSAndroid Build Coastguard Worker /* Read errors are considered non-fatal since we may
233*0d6140beSAndroid Build Coastguard Worker * encounter locked regions and want to continue. */
234*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, (uint8_t *)fmap, offset, sig_len)) {
235*0d6140beSAndroid Build Coastguard Worker /*
236*0d6140beSAndroid Build Coastguard Worker * Print in verbose mode only to avoid excessive
237*0d6140beSAndroid Build Coastguard Worker * messages for benign errors. Subsequent error
238*0d6140beSAndroid Build Coastguard Worker * prints should be done as usual.
239*0d6140beSAndroid Build Coastguard Worker */
240*0d6140beSAndroid Build Coastguard Worker msg_cdbg("Cannot read %d bytes at offset %zu\n", sig_len, offset);
241*0d6140beSAndroid Build Coastguard Worker continue;
242*0d6140beSAndroid Build Coastguard Worker }
243*0d6140beSAndroid Build Coastguard Worker
244*0d6140beSAndroid Build Coastguard Worker if (memcmp(fmap, FMAP_SIGNATURE, sig_len) != 0)
245*0d6140beSAndroid Build Coastguard Worker continue;
246*0d6140beSAndroid Build Coastguard Worker
247*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, (uint8_t *)fmap + sig_len,
248*0d6140beSAndroid Build Coastguard Worker offset + sig_len, sizeof(*fmap) - sig_len)) {
249*0d6140beSAndroid Build Coastguard Worker msg_cerr("Cannot read %zu bytes at offset %06zx\n",
250*0d6140beSAndroid Build Coastguard Worker sizeof(*fmap) - sig_len, offset + sig_len);
251*0d6140beSAndroid Build Coastguard Worker continue;
252*0d6140beSAndroid Build Coastguard Worker }
253*0d6140beSAndroid Build Coastguard Worker
254*0d6140beSAndroid Build Coastguard Worker if (is_valid_fmap(fmap)) {
255*0d6140beSAndroid Build Coastguard Worker msg_gdbg("fmap found at offset 0x%06zx\n", offset);
256*0d6140beSAndroid Build Coastguard Worker fmap_found = true;
257*0d6140beSAndroid Build Coastguard Worker break;
258*0d6140beSAndroid Build Coastguard Worker }
259*0d6140beSAndroid Build Coastguard Worker msg_gerr("fmap signature found at %zu but header is invalid.\n", offset);
260*0d6140beSAndroid Build Coastguard Worker ret = 2;
261*0d6140beSAndroid Build Coastguard Worker }
262*0d6140beSAndroid Build Coastguard Worker
263*0d6140beSAndroid Build Coastguard Worker if (fmap_found)
264*0d6140beSAndroid Build Coastguard Worker break;
265*0d6140beSAndroid Build Coastguard Worker }
266*0d6140beSAndroid Build Coastguard Worker
267*0d6140beSAndroid Build Coastguard Worker if (!fmap_found)
268*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
269*0d6140beSAndroid Build Coastguard Worker
270*0d6140beSAndroid Build Coastguard Worker fmap_len = fmap_size(fmap);
271*0d6140beSAndroid Build Coastguard Worker struct fmap *tmp = fmap;
272*0d6140beSAndroid Build Coastguard Worker fmap = realloc(fmap, fmap_len);
273*0d6140beSAndroid Build Coastguard Worker if (!fmap) {
274*0d6140beSAndroid Build Coastguard Worker msg_gerr("Failed to realloc.\n");
275*0d6140beSAndroid Build Coastguard Worker free(tmp);
276*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
277*0d6140beSAndroid Build Coastguard Worker }
278*0d6140beSAndroid Build Coastguard Worker
279*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, (uint8_t *)fmap + sizeof(*fmap),
280*0d6140beSAndroid Build Coastguard Worker offset + sizeof(*fmap), fmap_len - sizeof(*fmap))) {
281*0d6140beSAndroid Build Coastguard Worker msg_cerr("Cannot read %zu bytes at offset %06zx\n",
282*0d6140beSAndroid Build Coastguard Worker fmap_len - sizeof(*fmap), offset + sizeof(*fmap));
283*0d6140beSAndroid Build Coastguard Worker /* Treat read failure to be fatal since this
284*0d6140beSAndroid Build Coastguard Worker * should be a valid, usable fmap. */
285*0d6140beSAndroid Build Coastguard Worker ret = 2;
286*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
287*0d6140beSAndroid Build Coastguard Worker }
288*0d6140beSAndroid Build Coastguard Worker
289*0d6140beSAndroid Build Coastguard Worker *fmap_out = fmap;
290*0d6140beSAndroid Build Coastguard Worker ret = 0;
291*0d6140beSAndroid Build Coastguard Worker _free_ret:
292*0d6140beSAndroid Build Coastguard Worker if (ret)
293*0d6140beSAndroid Build Coastguard Worker free(fmap);
294*0d6140beSAndroid Build Coastguard Worker finalize_flash_access(flashctx);
295*0d6140beSAndroid Build Coastguard Worker return ret;
296*0d6140beSAndroid Build Coastguard Worker }
297*0d6140beSAndroid Build Coastguard Worker
298*0d6140beSAndroid Build Coastguard Worker /**
299*0d6140beSAndroid Build Coastguard Worker * @brief Read fmap from ROM
300*0d6140beSAndroid Build Coastguard Worker *
301*0d6140beSAndroid Build Coastguard Worker * @param[out] fmap_out Double-pointer to location to store fmap contents.
302*0d6140beSAndroid Build Coastguard Worker * Caller must free allocated fmap contents.
303*0d6140beSAndroid Build Coastguard Worker * @param[in] flashctx Flash context
304*0d6140beSAndroid Build Coastguard Worker * @param[in] rom_offset Offset in ROM to begin search
305*0d6140beSAndroid Build Coastguard Worker * @param[in] len Length to search relative to rom_offset
306*0d6140beSAndroid Build Coastguard Worker *
307*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
308*0d6140beSAndroid Build Coastguard Worker * 2 if the fmap couldn't be read,
309*0d6140beSAndroid Build Coastguard Worker * 1 on any other error.
310*0d6140beSAndroid Build Coastguard Worker */
fmap_read_from_rom(struct fmap ** fmap_out,struct flashctx * const flashctx,size_t rom_offset,size_t len)311*0d6140beSAndroid Build Coastguard Worker int fmap_read_from_rom(struct fmap **fmap_out,
312*0d6140beSAndroid Build Coastguard Worker struct flashctx *const flashctx, size_t rom_offset, size_t len)
313*0d6140beSAndroid Build Coastguard Worker {
314*0d6140beSAndroid Build Coastguard Worker int ret;
315*0d6140beSAndroid Build Coastguard Worker
316*0d6140beSAndroid Build Coastguard Worker if (!flashctx || !flashctx->chip)
317*0d6140beSAndroid Build Coastguard Worker return 1;
318*0d6140beSAndroid Build Coastguard Worker
319*0d6140beSAndroid Build Coastguard Worker /*
320*0d6140beSAndroid Build Coastguard Worker * Binary search is used at first to see if we can find an fmap quickly
321*0d6140beSAndroid Build Coastguard Worker * in a usual location (often at a power-of-2 offset). However, once we
322*0d6140beSAndroid Build Coastguard Worker * reach a small enough stride the transaction overhead will reverse the
323*0d6140beSAndroid Build Coastguard Worker * speed benefit of using bsearch at which point we need to use brute-
324*0d6140beSAndroid Build Coastguard Worker * force instead.
325*0d6140beSAndroid Build Coastguard Worker *
326*0d6140beSAndroid Build Coastguard Worker * TODO: Since flashrom is often used with high-latency external
327*0d6140beSAndroid Build Coastguard Worker * programmers we should not be overly aggressive with bsearch.
328*0d6140beSAndroid Build Coastguard Worker */
329*0d6140beSAndroid Build Coastguard Worker ret = fmap_bsearch_rom(fmap_out, flashctx, rom_offset, len, 256);
330*0d6140beSAndroid Build Coastguard Worker if (ret) {
331*0d6140beSAndroid Build Coastguard Worker msg_gdbg("Binary search failed, trying linear search...\n");
332*0d6140beSAndroid Build Coastguard Worker ret = fmap_lsearch_rom(fmap_out, flashctx, rom_offset, len);
333*0d6140beSAndroid Build Coastguard Worker }
334*0d6140beSAndroid Build Coastguard Worker
335*0d6140beSAndroid Build Coastguard Worker return ret;
336*0d6140beSAndroid Build Coastguard Worker }
337