xref: /aosp_15_r20/external/flashrom/fmap.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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