1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker *
4*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2000 Silicon Integrated System Corporation
5*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2004 Tyan Corp <[email protected]>
6*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2005-2008 coresystems GmbH
7*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2008,2009 Carl-Daniel Hailfinger
8*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2016 secunet Security Networks AG
9*0d6140beSAndroid Build Coastguard Worker * (Written by Nico Huber <[email protected]> for secunet)
10*0d6140beSAndroid Build Coastguard Worker *
11*0d6140beSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
12*0d6140beSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
13*0d6140beSAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
14*0d6140beSAndroid Build Coastguard Worker * (at your option) any later version.
15*0d6140beSAndroid Build Coastguard Worker *
16*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
17*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
20*0d6140beSAndroid Build Coastguard Worker */
21*0d6140beSAndroid Build Coastguard Worker
22*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
23*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
24*0d6140beSAndroid Build Coastguard Worker #include <stdint.h>
25*0d6140beSAndroid Build Coastguard Worker #include <sys/types.h>
26*0d6140beSAndroid Build Coastguard Worker #include <string.h>
27*0d6140beSAndroid Build Coastguard Worker #include <unistd.h>
28*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
29*0d6140beSAndroid Build Coastguard Worker #include <errno.h>
30*0d6140beSAndroid Build Coastguard Worker #include <ctype.h>
31*0d6140beSAndroid Build Coastguard Worker
32*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
33*0d6140beSAndroid Build Coastguard Worker #include "flashchips.h"
34*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
35*0d6140beSAndroid Build Coastguard Worker #include "hwaccess_physmap.h"
36*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
37*0d6140beSAndroid Build Coastguard Worker #include "erasure_layout.h"
38*0d6140beSAndroid Build Coastguard Worker
39*0d6140beSAndroid Build Coastguard Worker #include "action_descriptor.h"
40*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
41*0d6140beSAndroid Build Coastguard Worker #include "power.h"
42*0d6140beSAndroid Build Coastguard Worker #include "big_lock.h"
43*0d6140beSAndroid Build Coastguard Worker
44*0d6140beSAndroid Build Coastguard Worker static bool use_legacy_erase_path = false;
45*0d6140beSAndroid Build Coastguard Worker
46*0d6140beSAndroid Build Coastguard Worker const char flashrom_version[] = FLASHROM_VERSION;
47*0d6140beSAndroid Build Coastguard Worker
48*0d6140beSAndroid Build Coastguard Worker #ifndef USE_BIG_LOCK
49*0d6140beSAndroid Build Coastguard Worker #define USE_BIG_LOCK 0
50*0d6140beSAndroid Build Coastguard Worker #endif
51*0d6140beSAndroid Build Coastguard Worker
52*0d6140beSAndroid Build Coastguard Worker #define LOCK_TIMEOUT_SECS 180
53*0d6140beSAndroid Build Coastguard Worker
54*0d6140beSAndroid Build Coastguard Worker static const struct programmer_entry *programmer = NULL;
55*0d6140beSAndroid Build Coastguard Worker
56*0d6140beSAndroid Build Coastguard Worker /*
57*0d6140beSAndroid Build Coastguard Worker * Programmers supporting multiple buses can have differing size limits on
58*0d6140beSAndroid Build Coastguard Worker * each bus. Store the limits for each bus in a common struct.
59*0d6140beSAndroid Build Coastguard Worker */
60*0d6140beSAndroid Build Coastguard Worker struct decode_sizes max_rom_decode;
61*0d6140beSAndroid Build Coastguard Worker
62*0d6140beSAndroid Build Coastguard Worker /* If nonzero, used as the start address of bottom-aligned flash. */
63*0d6140beSAndroid Build Coastguard Worker uintptr_t flashbase;
64*0d6140beSAndroid Build Coastguard Worker
65*0d6140beSAndroid Build Coastguard Worker /* Is writing allowed with this programmer? */
66*0d6140beSAndroid Build Coastguard Worker bool programmer_may_write;
67*0d6140beSAndroid Build Coastguard Worker
68*0d6140beSAndroid Build Coastguard Worker #define SHUTDOWN_MAXFN 32
69*0d6140beSAndroid Build Coastguard Worker static int shutdown_fn_count = 0;
70*0d6140beSAndroid Build Coastguard Worker /** @private */
71*0d6140beSAndroid Build Coastguard Worker static struct shutdown_func_data {
72*0d6140beSAndroid Build Coastguard Worker int (*func) (void *data);
73*0d6140beSAndroid Build Coastguard Worker void *data;
74*0d6140beSAndroid Build Coastguard Worker } shutdown_fn[SHUTDOWN_MAXFN];
75*0d6140beSAndroid Build Coastguard Worker /* Initialize to 0 to make sure nobody registers a shutdown function before
76*0d6140beSAndroid Build Coastguard Worker * programmer init.
77*0d6140beSAndroid Build Coastguard Worker */
78*0d6140beSAndroid Build Coastguard Worker static bool may_register_shutdown = false;
79*0d6140beSAndroid Build Coastguard Worker
80*0d6140beSAndroid Build Coastguard Worker static struct bus_type_info {
81*0d6140beSAndroid Build Coastguard Worker enum chipbustype type;
82*0d6140beSAndroid Build Coastguard Worker const char *name;
83*0d6140beSAndroid Build Coastguard Worker } bustypes[] = {
84*0d6140beSAndroid Build Coastguard Worker { BUS_PARALLEL, "Parallel, " },
85*0d6140beSAndroid Build Coastguard Worker { BUS_LPC, "LPC, " },
86*0d6140beSAndroid Build Coastguard Worker { BUS_FWH, "FWH, " },
87*0d6140beSAndroid Build Coastguard Worker { BUS_SPI, "SPI, " },
88*0d6140beSAndroid Build Coastguard Worker { BUS_PROG, "Programmer-specific, " },
89*0d6140beSAndroid Build Coastguard Worker };
90*0d6140beSAndroid Build Coastguard Worker
91*0d6140beSAndroid Build Coastguard Worker /* Register a function to be executed on programmer shutdown.
92*0d6140beSAndroid Build Coastguard Worker * The advantage over atexit() is that you can supply a void pointer which will
93*0d6140beSAndroid Build Coastguard Worker * be used as parameter to the registered function upon programmer shutdown.
94*0d6140beSAndroid Build Coastguard Worker * This pointer can point to arbitrary data used by said function, e.g. undo
95*0d6140beSAndroid Build Coastguard Worker * information for GPIO settings etc. If unneeded, set data=NULL.
96*0d6140beSAndroid Build Coastguard Worker * Please note that the first (void *data) belongs to the function signature of
97*0d6140beSAndroid Build Coastguard Worker * the function passed as first parameter.
98*0d6140beSAndroid Build Coastguard Worker */
register_shutdown(int (* function)(void * data),void * data)99*0d6140beSAndroid Build Coastguard Worker int register_shutdown(int (*function) (void *data), void *data)
100*0d6140beSAndroid Build Coastguard Worker {
101*0d6140beSAndroid Build Coastguard Worker if (shutdown_fn_count >= SHUTDOWN_MAXFN) {
102*0d6140beSAndroid Build Coastguard Worker msg_perr("Tried to register more than %i shutdown functions.\n",
103*0d6140beSAndroid Build Coastguard Worker SHUTDOWN_MAXFN);
104*0d6140beSAndroid Build Coastguard Worker return 1;
105*0d6140beSAndroid Build Coastguard Worker }
106*0d6140beSAndroid Build Coastguard Worker if (!may_register_shutdown) {
107*0d6140beSAndroid Build Coastguard Worker msg_perr("Tried to register a shutdown function before "
108*0d6140beSAndroid Build Coastguard Worker "programmer init.\n");
109*0d6140beSAndroid Build Coastguard Worker return 1;
110*0d6140beSAndroid Build Coastguard Worker }
111*0d6140beSAndroid Build Coastguard Worker shutdown_fn[shutdown_fn_count].func = function;
112*0d6140beSAndroid Build Coastguard Worker shutdown_fn[shutdown_fn_count].data = data;
113*0d6140beSAndroid Build Coastguard Worker shutdown_fn_count++;
114*0d6140beSAndroid Build Coastguard Worker
115*0d6140beSAndroid Build Coastguard Worker return 0;
116*0d6140beSAndroid Build Coastguard Worker }
117*0d6140beSAndroid Build Coastguard Worker
register_chip_restore(chip_restore_fn_cb_t func,struct flashctx * flash,void * data)118*0d6140beSAndroid Build Coastguard Worker int register_chip_restore(chip_restore_fn_cb_t func,
119*0d6140beSAndroid Build Coastguard Worker struct flashctx *flash, void *data)
120*0d6140beSAndroid Build Coastguard Worker {
121*0d6140beSAndroid Build Coastguard Worker if (flash->chip_restore_fn_count >= MAX_CHIP_RESTORE_FUNCTIONS) {
122*0d6140beSAndroid Build Coastguard Worker msg_perr("Tried to register more than %i chip restore"
123*0d6140beSAndroid Build Coastguard Worker " functions.\n", MAX_CHIP_RESTORE_FUNCTIONS);
124*0d6140beSAndroid Build Coastguard Worker return 1;
125*0d6140beSAndroid Build Coastguard Worker }
126*0d6140beSAndroid Build Coastguard Worker flash->chip_restore_fn[flash->chip_restore_fn_count].func = func;
127*0d6140beSAndroid Build Coastguard Worker flash->chip_restore_fn[flash->chip_restore_fn_count].data = data;
128*0d6140beSAndroid Build Coastguard Worker flash->chip_restore_fn_count++;
129*0d6140beSAndroid Build Coastguard Worker
130*0d6140beSAndroid Build Coastguard Worker return 0;
131*0d6140beSAndroid Build Coastguard Worker }
132*0d6140beSAndroid Build Coastguard Worker
deregister_chip_restore(struct flashctx * flash)133*0d6140beSAndroid Build Coastguard Worker static int deregister_chip_restore(struct flashctx *flash)
134*0d6140beSAndroid Build Coastguard Worker {
135*0d6140beSAndroid Build Coastguard Worker int rc = 0;
136*0d6140beSAndroid Build Coastguard Worker
137*0d6140beSAndroid Build Coastguard Worker while (flash->chip_restore_fn_count > 0) {
138*0d6140beSAndroid Build Coastguard Worker int i = --flash->chip_restore_fn_count;
139*0d6140beSAndroid Build Coastguard Worker rc |= flash->chip_restore_fn[i].func(
140*0d6140beSAndroid Build Coastguard Worker flash, flash->chip_restore_fn[i].data);
141*0d6140beSAndroid Build Coastguard Worker }
142*0d6140beSAndroid Build Coastguard Worker
143*0d6140beSAndroid Build Coastguard Worker return rc;
144*0d6140beSAndroid Build Coastguard Worker }
145*0d6140beSAndroid Build Coastguard Worker
programmer_init(const struct programmer_entry * prog,const char * param)146*0d6140beSAndroid Build Coastguard Worker int programmer_init(const struct programmer_entry *prog, const char *param)
147*0d6140beSAndroid Build Coastguard Worker {
148*0d6140beSAndroid Build Coastguard Worker int ret;
149*0d6140beSAndroid Build Coastguard Worker #if CONFIG_DUMMY == 1
150*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry *dummy_programmer = &programmer_dummy;
151*0d6140beSAndroid Build Coastguard Worker #else
152*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry *dummy_programmer = NULL;
153*0d6140beSAndroid Build Coastguard Worker #endif
154*0d6140beSAndroid Build Coastguard Worker
155*0d6140beSAndroid Build Coastguard Worker if (prog == NULL) {
156*0d6140beSAndroid Build Coastguard Worker msg_perr("Invalid programmer specified!\n");
157*0d6140beSAndroid Build Coastguard Worker return -1;
158*0d6140beSAndroid Build Coastguard Worker }
159*0d6140beSAndroid Build Coastguard Worker
160*0d6140beSAndroid Build Coastguard Worker /* Only acquire the big lock for non-dummy programmer. */
161*0d6140beSAndroid Build Coastguard Worker if (USE_BIG_LOCK && prog != dummy_programmer) {
162*0d6140beSAndroid Build Coastguard Worker /* Get big lock before doing any work that touches hardware. */
163*0d6140beSAndroid Build Coastguard Worker if (acquire_big_lock(LOCK_TIMEOUT_SECS) < 0)
164*0d6140beSAndroid Build Coastguard Worker return 1;
165*0d6140beSAndroid Build Coastguard Worker }
166*0d6140beSAndroid Build Coastguard Worker
167*0d6140beSAndroid Build Coastguard Worker programmer = prog;
168*0d6140beSAndroid Build Coastguard Worker /* Initialize all programmer specific data. */
169*0d6140beSAndroid Build Coastguard Worker /* Default to unlimited decode sizes. */
170*0d6140beSAndroid Build Coastguard Worker max_rom_decode = (const struct decode_sizes) {
171*0d6140beSAndroid Build Coastguard Worker .parallel = 0xffffffff,
172*0d6140beSAndroid Build Coastguard Worker .lpc = 0xffffffff,
173*0d6140beSAndroid Build Coastguard Worker .fwh = 0xffffffff,
174*0d6140beSAndroid Build Coastguard Worker .spi = 0xffffffff,
175*0d6140beSAndroid Build Coastguard Worker };
176*0d6140beSAndroid Build Coastguard Worker /* Default to top aligned flash at 4 GB. */
177*0d6140beSAndroid Build Coastguard Worker flashbase = 0;
178*0d6140beSAndroid Build Coastguard Worker /* Registering shutdown functions is now allowed. */
179*0d6140beSAndroid Build Coastguard Worker may_register_shutdown = true;
180*0d6140beSAndroid Build Coastguard Worker /* Default to allowing writes. Broken programmers set this to 0. */
181*0d6140beSAndroid Build Coastguard Worker programmer_may_write = true;
182*0d6140beSAndroid Build Coastguard Worker
183*0d6140beSAndroid Build Coastguard Worker struct programmer_cfg cfg;
184*0d6140beSAndroid Build Coastguard Worker
185*0d6140beSAndroid Build Coastguard Worker if (param) {
186*0d6140beSAndroid Build Coastguard Worker cfg.params = strdup(param);
187*0d6140beSAndroid Build Coastguard Worker if (!cfg.params) {
188*0d6140beSAndroid Build Coastguard Worker msg_perr("Out of memory!\n");
189*0d6140beSAndroid Build Coastguard Worker return ERROR_FLASHROM_FATAL;
190*0d6140beSAndroid Build Coastguard Worker }
191*0d6140beSAndroid Build Coastguard Worker } else {
192*0d6140beSAndroid Build Coastguard Worker cfg.params = NULL;
193*0d6140beSAndroid Build Coastguard Worker }
194*0d6140beSAndroid Build Coastguard Worker
195*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Initializing %s programmer\n", prog->name);
196*0d6140beSAndroid Build Coastguard Worker ret = prog->init(&cfg);
197*0d6140beSAndroid Build Coastguard Worker if (cfg.params && strlen(cfg.params)) {
198*0d6140beSAndroid Build Coastguard Worker if (ret != 0) {
199*0d6140beSAndroid Build Coastguard Worker /* It is quite possible that any unhandled programmer parameter would have been valid,
200*0d6140beSAndroid Build Coastguard Worker * but an error in actual programmer init happened before the parameter was evaluated.
201*0d6140beSAndroid Build Coastguard Worker */
202*0d6140beSAndroid Build Coastguard Worker msg_pwarn("Unhandled programmer parameters (possibly due to another failure): %s\n",
203*0d6140beSAndroid Build Coastguard Worker cfg.params);
204*0d6140beSAndroid Build Coastguard Worker } else {
205*0d6140beSAndroid Build Coastguard Worker /* Actual programmer init was successful, but the user specified an invalid or unusable
206*0d6140beSAndroid Build Coastguard Worker * (for the current programmer configuration) parameter.
207*0d6140beSAndroid Build Coastguard Worker */
208*0d6140beSAndroid Build Coastguard Worker msg_perr("Unhandled programmer parameters: %s\n", cfg.params);
209*0d6140beSAndroid Build Coastguard Worker msg_perr("Aborting.\n");
210*0d6140beSAndroid Build Coastguard Worker ret = ERROR_FLASHROM_FATAL;
211*0d6140beSAndroid Build Coastguard Worker }
212*0d6140beSAndroid Build Coastguard Worker }
213*0d6140beSAndroid Build Coastguard Worker free(cfg.params);
214*0d6140beSAndroid Build Coastguard Worker
215*0d6140beSAndroid Build Coastguard Worker /* Release lock if initialization is not succseeful. */
216*0d6140beSAndroid Build Coastguard Worker if (USE_BIG_LOCK && ret != 0)
217*0d6140beSAndroid Build Coastguard Worker release_big_lock();
218*0d6140beSAndroid Build Coastguard Worker
219*0d6140beSAndroid Build Coastguard Worker return ret;
220*0d6140beSAndroid Build Coastguard Worker }
221*0d6140beSAndroid Build Coastguard Worker
222*0d6140beSAndroid Build Coastguard Worker /** Calls registered shutdown functions and resets internal programmer-related variables.
223*0d6140beSAndroid Build Coastguard Worker * Calling it is safe even without previous initialization, but further interactions with programmer support
224*0d6140beSAndroid Build Coastguard Worker * require a call to programmer_init() (afterwards).
225*0d6140beSAndroid Build Coastguard Worker *
226*0d6140beSAndroid Build Coastguard Worker * @return The OR-ed result values of all shutdown functions (i.e. 0 on success). */
programmer_shutdown(void)227*0d6140beSAndroid Build Coastguard Worker int programmer_shutdown(void)
228*0d6140beSAndroid Build Coastguard Worker {
229*0d6140beSAndroid Build Coastguard Worker int ret = 0;
230*0d6140beSAndroid Build Coastguard Worker
231*0d6140beSAndroid Build Coastguard Worker /* Registering shutdown functions is no longer allowed. */
232*0d6140beSAndroid Build Coastguard Worker may_register_shutdown = false;
233*0d6140beSAndroid Build Coastguard Worker while (shutdown_fn_count > 0) {
234*0d6140beSAndroid Build Coastguard Worker int i = --shutdown_fn_count;
235*0d6140beSAndroid Build Coastguard Worker ret |= shutdown_fn[i].func(shutdown_fn[i].data);
236*0d6140beSAndroid Build Coastguard Worker }
237*0d6140beSAndroid Build Coastguard Worker registered_master_count = 0;
238*0d6140beSAndroid Build Coastguard Worker
239*0d6140beSAndroid Build Coastguard Worker if (USE_BIG_LOCK)
240*0d6140beSAndroid Build Coastguard Worker release_big_lock();
241*0d6140beSAndroid Build Coastguard Worker
242*0d6140beSAndroid Build Coastguard Worker return ret;
243*0d6140beSAndroid Build Coastguard Worker }
244*0d6140beSAndroid Build Coastguard Worker
master_map_flash_region(const struct registered_master * mst,const char * descr,uintptr_t phys_addr,size_t len)245*0d6140beSAndroid Build Coastguard Worker void *master_map_flash_region(const struct registered_master *mst,
246*0d6140beSAndroid Build Coastguard Worker const char *descr, uintptr_t phys_addr,
247*0d6140beSAndroid Build Coastguard Worker size_t len)
248*0d6140beSAndroid Build Coastguard Worker {
249*0d6140beSAndroid Build Coastguard Worker /* Check the bus master for a specialized map_flash_region; default to
250*0d6140beSAndroid Build Coastguard Worker * fallback if it does not specialize it
251*0d6140beSAndroid Build Coastguard Worker */
252*0d6140beSAndroid Build Coastguard Worker void *(*map_flash_region) (const char *descr, uintptr_t phys_addr, size_t len) = NULL;
253*0d6140beSAndroid Build Coastguard Worker if (mst->buses_supported & BUS_SPI)
254*0d6140beSAndroid Build Coastguard Worker map_flash_region = mst->spi.map_flash_region;
255*0d6140beSAndroid Build Coastguard Worker else if (mst->buses_supported & BUS_NONSPI)
256*0d6140beSAndroid Build Coastguard Worker map_flash_region = mst->par.map_flash_region;
257*0d6140beSAndroid Build Coastguard Worker
258*0d6140beSAndroid Build Coastguard Worker /* A result of NULL causes mapped addresses to be chip physical
259*0d6140beSAndroid Build Coastguard Worker * addresses, assuming only a single region is mapped (the entire flash
260*0d6140beSAndroid Build Coastguard Worker * space). Chips with a second region (like a register map) require a
261*0d6140beSAndroid Build Coastguard Worker * real memory mapping to distinguish the different ranges. Those chips
262*0d6140beSAndroid Build Coastguard Worker * are FWH/LPC, so the bus master provides a real mapping.
263*0d6140beSAndroid Build Coastguard Worker */
264*0d6140beSAndroid Build Coastguard Worker void *ret = NULL;
265*0d6140beSAndroid Build Coastguard Worker if (map_flash_region)
266*0d6140beSAndroid Build Coastguard Worker ret = map_flash_region(descr, phys_addr, len);
267*0d6140beSAndroid Build Coastguard Worker msg_gspew("%s: mapping %s from 0x%0*" PRIxPTR " to 0x%0*" PRIxPTR "\n",
268*0d6140beSAndroid Build Coastguard Worker __func__, descr, PRIxPTR_WIDTH, phys_addr, PRIxPTR_WIDTH, (uintptr_t) ret);
269*0d6140beSAndroid Build Coastguard Worker return ret;
270*0d6140beSAndroid Build Coastguard Worker }
271*0d6140beSAndroid Build Coastguard Worker
master_unmap_flash_region(const struct registered_master * mst,void * virt_addr,size_t len)272*0d6140beSAndroid Build Coastguard Worker void master_unmap_flash_region(const struct registered_master *mst,
273*0d6140beSAndroid Build Coastguard Worker void *virt_addr, size_t len)
274*0d6140beSAndroid Build Coastguard Worker {
275*0d6140beSAndroid Build Coastguard Worker void (*unmap_flash_region) (void *virt_addr, size_t len) = NULL;
276*0d6140beSAndroid Build Coastguard Worker if (mst->buses_supported & BUS_SPI)
277*0d6140beSAndroid Build Coastguard Worker unmap_flash_region = mst->spi.unmap_flash_region;
278*0d6140beSAndroid Build Coastguard Worker else if (mst->buses_supported & BUS_NONSPI)
279*0d6140beSAndroid Build Coastguard Worker unmap_flash_region = mst->par.unmap_flash_region;
280*0d6140beSAndroid Build Coastguard Worker
281*0d6140beSAndroid Build Coastguard Worker if (unmap_flash_region)
282*0d6140beSAndroid Build Coastguard Worker unmap_flash_region(virt_addr, len);
283*0d6140beSAndroid Build Coastguard Worker msg_gspew("%s: unmapped 0x%0*" PRIxPTR "\n", __func__, PRIxPTR_WIDTH, (uintptr_t)virt_addr);
284*0d6140beSAndroid Build Coastguard Worker }
285*0d6140beSAndroid Build Coastguard Worker
master_uses_physmap(const struct registered_master * mst)286*0d6140beSAndroid Build Coastguard Worker static bool master_uses_physmap(const struct registered_master *mst)
287*0d6140beSAndroid Build Coastguard Worker {
288*0d6140beSAndroid Build Coastguard Worker #if CONFIG_INTERNAL == 1
289*0d6140beSAndroid Build Coastguard Worker if (mst->buses_supported & BUS_SPI)
290*0d6140beSAndroid Build Coastguard Worker return mst->spi.map_flash_region == physmap;
291*0d6140beSAndroid Build Coastguard Worker else if (mst->buses_supported & BUS_NONSPI)
292*0d6140beSAndroid Build Coastguard Worker return mst->par.map_flash_region == physmap;
293*0d6140beSAndroid Build Coastguard Worker #endif
294*0d6140beSAndroid Build Coastguard Worker return false;
295*0d6140beSAndroid Build Coastguard Worker }
296*0d6140beSAndroid Build Coastguard Worker
programmer_delay(const struct flashctx * flash,unsigned int usecs)297*0d6140beSAndroid Build Coastguard Worker void programmer_delay(const struct flashctx *flash, unsigned int usecs)
298*0d6140beSAndroid Build Coastguard Worker {
299*0d6140beSAndroid Build Coastguard Worker if (usecs == 0)
300*0d6140beSAndroid Build Coastguard Worker return;
301*0d6140beSAndroid Build Coastguard Worker
302*0d6140beSAndroid Build Coastguard Worker /**
303*0d6140beSAndroid Build Coastguard Worker * Drivers should either use default_delay() directly or their
304*0d6140beSAndroid Build Coastguard Worker * own custom delay. Only core flashrom logic calls programmer_delay()
305*0d6140beSAndroid Build Coastguard Worker * which should always have a valid flash context. A NULL context
306*0d6140beSAndroid Build Coastguard Worker * more than likely indicates a layering violation or BUG however
307*0d6140beSAndroid Build Coastguard Worker * for now dispatch a default_delay() as a safe default for the NULL
308*0d6140beSAndroid Build Coastguard Worker * base case.
309*0d6140beSAndroid Build Coastguard Worker */
310*0d6140beSAndroid Build Coastguard Worker if (!flash) {
311*0d6140beSAndroid Build Coastguard Worker msg_perr("%s called with NULL flash context. "
312*0d6140beSAndroid Build Coastguard Worker "Please report a bug at [email protected]\n",
313*0d6140beSAndroid Build Coastguard Worker __func__);
314*0d6140beSAndroid Build Coastguard Worker return default_delay(usecs);
315*0d6140beSAndroid Build Coastguard Worker }
316*0d6140beSAndroid Build Coastguard Worker
317*0d6140beSAndroid Build Coastguard Worker if (flash->mst->buses_supported & BUS_SPI) {
318*0d6140beSAndroid Build Coastguard Worker if (flash->mst->spi.delay)
319*0d6140beSAndroid Build Coastguard Worker return flash->mst->spi.delay(flash, usecs);
320*0d6140beSAndroid Build Coastguard Worker } else if (flash->mst->buses_supported & BUS_PARALLEL) {
321*0d6140beSAndroid Build Coastguard Worker if (flash->mst->par.delay)
322*0d6140beSAndroid Build Coastguard Worker return flash->mst->par.delay(flash, usecs);
323*0d6140beSAndroid Build Coastguard Worker } else if (flash->mst->buses_supported & BUS_PROG) {
324*0d6140beSAndroid Build Coastguard Worker if (flash->mst->opaque.delay)
325*0d6140beSAndroid Build Coastguard Worker return flash->mst->opaque.delay(flash, usecs);
326*0d6140beSAndroid Build Coastguard Worker }
327*0d6140beSAndroid Build Coastguard Worker
328*0d6140beSAndroid Build Coastguard Worker return default_delay(usecs);
329*0d6140beSAndroid Build Coastguard Worker }
330*0d6140beSAndroid Build Coastguard Worker
read_memmapped(struct flashctx * flash,uint8_t * buf,unsigned int start,int unsigned len)331*0d6140beSAndroid Build Coastguard Worker int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start,
332*0d6140beSAndroid Build Coastguard Worker int unsigned len)
333*0d6140beSAndroid Build Coastguard Worker {
334*0d6140beSAndroid Build Coastguard Worker chip_readn(flash, buf, flash->virtual_memory + start, len);
335*0d6140beSAndroid Build Coastguard Worker
336*0d6140beSAndroid Build Coastguard Worker return 0;
337*0d6140beSAndroid Build Coastguard Worker }
338*0d6140beSAndroid Build Coastguard Worker
339*0d6140beSAndroid Build Coastguard Worker /* This is a somewhat hacked function similar in some ways to strtok().
340*0d6140beSAndroid Build Coastguard Worker * It will look for needle with a subsequent '=' in haystack, return a copy of
341*0d6140beSAndroid Build Coastguard Worker * needle and remove everything from the first occurrence of needle to the next
342*0d6140beSAndroid Build Coastguard Worker * delimiter from haystack.
343*0d6140beSAndroid Build Coastguard Worker */
extract_param(char * const * haystack,const char * needle,const char * delim)344*0d6140beSAndroid Build Coastguard Worker static char *extract_param(char *const *haystack, const char *needle, const char *delim)
345*0d6140beSAndroid Build Coastguard Worker {
346*0d6140beSAndroid Build Coastguard Worker char *param_pos, *opt_pos, *rest;
347*0d6140beSAndroid Build Coastguard Worker char *opt = NULL;
348*0d6140beSAndroid Build Coastguard Worker int optlen;
349*0d6140beSAndroid Build Coastguard Worker int needlelen;
350*0d6140beSAndroid Build Coastguard Worker
351*0d6140beSAndroid Build Coastguard Worker needlelen = strlen(needle);
352*0d6140beSAndroid Build Coastguard Worker if (!needlelen) {
353*0d6140beSAndroid Build Coastguard Worker msg_gerr("%s: empty needle! Please report a bug at "
354*0d6140beSAndroid Build Coastguard Worker "[email protected]\n", __func__);
355*0d6140beSAndroid Build Coastguard Worker return NULL;
356*0d6140beSAndroid Build Coastguard Worker }
357*0d6140beSAndroid Build Coastguard Worker /* No programmer parameters given. */
358*0d6140beSAndroid Build Coastguard Worker if (*haystack == NULL)
359*0d6140beSAndroid Build Coastguard Worker return NULL;
360*0d6140beSAndroid Build Coastguard Worker param_pos = strstr(*haystack, needle);
361*0d6140beSAndroid Build Coastguard Worker do {
362*0d6140beSAndroid Build Coastguard Worker if (!param_pos)
363*0d6140beSAndroid Build Coastguard Worker return NULL;
364*0d6140beSAndroid Build Coastguard Worker /* Needle followed by '='? */
365*0d6140beSAndroid Build Coastguard Worker if (param_pos[needlelen] == '=') {
366*0d6140beSAndroid Build Coastguard Worker /* Beginning of the string? */
367*0d6140beSAndroid Build Coastguard Worker if (param_pos == *haystack)
368*0d6140beSAndroid Build Coastguard Worker break;
369*0d6140beSAndroid Build Coastguard Worker /* After a delimiter? */
370*0d6140beSAndroid Build Coastguard Worker if (strchr(delim, *(param_pos - 1)))
371*0d6140beSAndroid Build Coastguard Worker break;
372*0d6140beSAndroid Build Coastguard Worker }
373*0d6140beSAndroid Build Coastguard Worker /* Continue searching. */
374*0d6140beSAndroid Build Coastguard Worker param_pos++;
375*0d6140beSAndroid Build Coastguard Worker param_pos = strstr(param_pos, needle);
376*0d6140beSAndroid Build Coastguard Worker } while (1);
377*0d6140beSAndroid Build Coastguard Worker
378*0d6140beSAndroid Build Coastguard Worker if (param_pos) {
379*0d6140beSAndroid Build Coastguard Worker /* Get the string after needle and '='. */
380*0d6140beSAndroid Build Coastguard Worker opt_pos = param_pos + needlelen + 1;
381*0d6140beSAndroid Build Coastguard Worker optlen = strcspn(opt_pos, delim);
382*0d6140beSAndroid Build Coastguard Worker /* Return an empty string if the parameter was empty. */
383*0d6140beSAndroid Build Coastguard Worker opt = malloc(optlen + 1);
384*0d6140beSAndroid Build Coastguard Worker if (!opt) {
385*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory!\n");
386*0d6140beSAndroid Build Coastguard Worker return NULL;
387*0d6140beSAndroid Build Coastguard Worker }
388*0d6140beSAndroid Build Coastguard Worker strncpy(opt, opt_pos, optlen);
389*0d6140beSAndroid Build Coastguard Worker opt[optlen] = '\0';
390*0d6140beSAndroid Build Coastguard Worker rest = opt_pos + optlen;
391*0d6140beSAndroid Build Coastguard Worker /* Skip all delimiters after the current parameter. */
392*0d6140beSAndroid Build Coastguard Worker rest += strspn(rest, delim);
393*0d6140beSAndroid Build Coastguard Worker memmove(param_pos, rest, strlen(rest) + 1);
394*0d6140beSAndroid Build Coastguard Worker /* We could shrink haystack, but the effort is not worth it. */
395*0d6140beSAndroid Build Coastguard Worker }
396*0d6140beSAndroid Build Coastguard Worker
397*0d6140beSAndroid Build Coastguard Worker return opt;
398*0d6140beSAndroid Build Coastguard Worker }
399*0d6140beSAndroid Build Coastguard Worker
extract_programmer_param_str(const struct programmer_cfg * cfg,const char * param_name)400*0d6140beSAndroid Build Coastguard Worker char *extract_programmer_param_str(const struct programmer_cfg *cfg, const char *param_name)
401*0d6140beSAndroid Build Coastguard Worker {
402*0d6140beSAndroid Build Coastguard Worker return extract_param(&cfg->params, param_name, ",");
403*0d6140beSAndroid Build Coastguard Worker }
404*0d6140beSAndroid Build Coastguard Worker
get_flash_region(const struct flashctx * flash,int addr,struct flash_region * region)405*0d6140beSAndroid Build Coastguard Worker void get_flash_region(const struct flashctx *flash, int addr, struct flash_region *region)
406*0d6140beSAndroid Build Coastguard Worker {
407*0d6140beSAndroid Build Coastguard Worker if ((flash->mst->buses_supported & BUS_PROG) && flash->mst->opaque.get_region) {
408*0d6140beSAndroid Build Coastguard Worker flash->mst->opaque.get_region(flash, addr, region);
409*0d6140beSAndroid Build Coastguard Worker } else if (flash->mst->buses_supported & BUS_SPI && flash->mst->spi.get_region) {
410*0d6140beSAndroid Build Coastguard Worker flash->mst->spi.get_region(flash, addr, region);
411*0d6140beSAndroid Build Coastguard Worker } else {
412*0d6140beSAndroid Build Coastguard Worker region->name = strdup("");
413*0d6140beSAndroid Build Coastguard Worker region->start = 0;
414*0d6140beSAndroid Build Coastguard Worker region->end = flashrom_flash_getsize(flash);
415*0d6140beSAndroid Build Coastguard Worker region->read_prot = false;
416*0d6140beSAndroid Build Coastguard Worker region->write_prot = false;
417*0d6140beSAndroid Build Coastguard Worker }
418*0d6140beSAndroid Build Coastguard Worker }
419*0d6140beSAndroid Build Coastguard Worker
check_for_unwritable_regions(const struct flashctx * flash,unsigned int start,unsigned int len)420*0d6140beSAndroid Build Coastguard Worker int check_for_unwritable_regions(const struct flashctx *flash, unsigned int start, unsigned int len)
421*0d6140beSAndroid Build Coastguard Worker {
422*0d6140beSAndroid Build Coastguard Worker struct flash_region region;
423*0d6140beSAndroid Build Coastguard Worker for (unsigned int addr = start; addr < start + len; addr = region.end) {
424*0d6140beSAndroid Build Coastguard Worker get_flash_region(flash, addr, ®ion);
425*0d6140beSAndroid Build Coastguard Worker
426*0d6140beSAndroid Build Coastguard Worker if (region.write_prot) {
427*0d6140beSAndroid Build Coastguard Worker msg_gerr("%s: cannot write/erase inside %s region (%#08"PRIx32"..%#08"PRIx32").\n",
428*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1);
429*0d6140beSAndroid Build Coastguard Worker free(region.name);
430*0d6140beSAndroid Build Coastguard Worker return -1;
431*0d6140beSAndroid Build Coastguard Worker }
432*0d6140beSAndroid Build Coastguard Worker free(region.name);
433*0d6140beSAndroid Build Coastguard Worker }
434*0d6140beSAndroid Build Coastguard Worker return 0;
435*0d6140beSAndroid Build Coastguard Worker }
436*0d6140beSAndroid Build Coastguard Worker
437*0d6140beSAndroid Build Coastguard Worker /* special unit-test hook */
438*0d6140beSAndroid Build Coastguard Worker erasefunc_t *g_test_erase_injector;
439*0d6140beSAndroid Build Coastguard Worker
lookup_erase_func_ptr(const struct block_eraser * const eraser)440*0d6140beSAndroid Build Coastguard Worker erasefunc_t *lookup_erase_func_ptr(const struct block_eraser *const eraser)
441*0d6140beSAndroid Build Coastguard Worker {
442*0d6140beSAndroid Build Coastguard Worker switch (eraser->block_erase) {
443*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_EMULATION: return &spi_block_erase_emulation;
444*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_20: return &spi_block_erase_20;
445*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_21: return &spi_block_erase_21;
446*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_40: return NULL; // FIXME unhandled &spi_block_erase_40;
447*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_50: return &spi_block_erase_50;
448*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_52: return &spi_block_erase_52;
449*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_53: return &spi_block_erase_53;
450*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_5C: return &spi_block_erase_5c;
451*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_60: return &spi_block_erase_60;
452*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_62: return &spi_block_erase_62;
453*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_81: return &spi_block_erase_81;
454*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_C4: return &spi_block_erase_c4;
455*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_C7: return &spi_block_erase_c7;
456*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_D7: return &spi_block_erase_d7;
457*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_D8: return &spi_block_erase_d8;
458*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_DB: return &spi_block_erase_db;
459*0d6140beSAndroid Build Coastguard Worker case SPI_BLOCK_ERASE_DC: return &spi_block_erase_dc;
460*0d6140beSAndroid Build Coastguard Worker case S25FL_BLOCK_ERASE: return &s25fl_block_erase;
461*0d6140beSAndroid Build Coastguard Worker case S25FS_BLOCK_ERASE_D8: return &s25fs_block_erase_d8;
462*0d6140beSAndroid Build Coastguard Worker case JEDEC_SECTOR_ERASE: return &erase_sector_jedec; // TODO rename to &jedec_sector_erase;
463*0d6140beSAndroid Build Coastguard Worker case JEDEC_BLOCK_ERASE: return &erase_block_jedec; // TODO rename to &jedec_block_erase;
464*0d6140beSAndroid Build Coastguard Worker case JEDEC_CHIP_BLOCK_ERASE: return &erase_chip_block_jedec; // TODO rename to &jedec_chip_block_erase;
465*0d6140beSAndroid Build Coastguard Worker case OPAQUE_ERASE: return &erase_opaque; // TODO rename to &opqaue_erase;
466*0d6140beSAndroid Build Coastguard Worker case SPI_ERASE_AT45CS_SECTOR: return &spi_erase_at45cs_sector;
467*0d6140beSAndroid Build Coastguard Worker case SPI_ERASE_AT45DB_BLOCK: return &spi_erase_at45db_block;
468*0d6140beSAndroid Build Coastguard Worker case SPI_ERASE_AT45DB_CHIP: return &spi_erase_at45db_chip;
469*0d6140beSAndroid Build Coastguard Worker case SPI_ERASE_AT45DB_PAGE: return &spi_erase_at45db_page;
470*0d6140beSAndroid Build Coastguard Worker case SPI_ERASE_AT45DB_SECTOR: return &spi_erase_at45db_sector;
471*0d6140beSAndroid Build Coastguard Worker case ERASE_CHIP_28SF040: return &erase_chip_28sf040;
472*0d6140beSAndroid Build Coastguard Worker case ERASE_SECTOR_28SF040: return &erase_sector_28sf040;
473*0d6140beSAndroid Build Coastguard Worker case ERASE_BLOCK_82802AB: return &erase_block_82802ab;
474*0d6140beSAndroid Build Coastguard Worker case ERASE_SECTOR_49LFXXXC: return &erase_sector_49lfxxxc;
475*0d6140beSAndroid Build Coastguard Worker case STM50_SECTOR_ERASE: return &erase_sector_stm50; // TODO rename to &stm50_sector_erase;
476*0d6140beSAndroid Build Coastguard Worker case EDI_CHIP_BLOCK_ERASE: return &edi_chip_block_erase;
477*0d6140beSAndroid Build Coastguard Worker case CROS_EC_BLOCK_ERASE: return &cros_ec_block_erase;
478*0d6140beSAndroid Build Coastguard Worker case TEST_ERASE_INJECTOR: return g_test_erase_injector;
479*0d6140beSAndroid Build Coastguard Worker /* default: total function, 0 indicates no erase function set.
480*0d6140beSAndroid Build Coastguard Worker * We explicitly do not want a default catch-all case in the switch
481*0d6140beSAndroid Build Coastguard Worker * to ensure unhandled enum's are compiler warnings.
482*0d6140beSAndroid Build Coastguard Worker */
483*0d6140beSAndroid Build Coastguard Worker case NO_BLOCK_ERASE_FUNC: return NULL;
484*0d6140beSAndroid Build Coastguard Worker };
485*0d6140beSAndroid Build Coastguard Worker
486*0d6140beSAndroid Build Coastguard Worker return NULL;
487*0d6140beSAndroid Build Coastguard Worker }
488*0d6140beSAndroid Build Coastguard Worker
check_block_eraser(const struct flashctx * flash,int k,int log)489*0d6140beSAndroid Build Coastguard Worker int check_block_eraser(const struct flashctx *flash, int k, int log)
490*0d6140beSAndroid Build Coastguard Worker {
491*0d6140beSAndroid Build Coastguard Worker struct block_eraser eraser = flash->chip->block_erasers[k];
492*0d6140beSAndroid Build Coastguard Worker
493*0d6140beSAndroid Build Coastguard Worker if (eraser.block_erase == NO_BLOCK_ERASE_FUNC && !eraser.eraseblocks[0].count) {
494*0d6140beSAndroid Build Coastguard Worker if (log)
495*0d6140beSAndroid Build Coastguard Worker msg_cdbg("not defined. ");
496*0d6140beSAndroid Build Coastguard Worker return 1;
497*0d6140beSAndroid Build Coastguard Worker }
498*0d6140beSAndroid Build Coastguard Worker if (eraser.block_erase == NO_BLOCK_ERASE_FUNC && eraser.eraseblocks[0].count) {
499*0d6140beSAndroid Build Coastguard Worker if (log)
500*0d6140beSAndroid Build Coastguard Worker msg_cdbg("eraseblock layout is known, but matching "
501*0d6140beSAndroid Build Coastguard Worker "block erase function is not implemented. ");
502*0d6140beSAndroid Build Coastguard Worker return 1;
503*0d6140beSAndroid Build Coastguard Worker }
504*0d6140beSAndroid Build Coastguard Worker if (eraser.block_erase != NO_BLOCK_ERASE_FUNC && !eraser.eraseblocks[0].count) {
505*0d6140beSAndroid Build Coastguard Worker if (log)
506*0d6140beSAndroid Build Coastguard Worker msg_cdbg("block erase function found, but "
507*0d6140beSAndroid Build Coastguard Worker "eraseblock layout is not defined. ");
508*0d6140beSAndroid Build Coastguard Worker return 1;
509*0d6140beSAndroid Build Coastguard Worker }
510*0d6140beSAndroid Build Coastguard Worker
511*0d6140beSAndroid Build Coastguard Worker if (flash->mst->buses_supported & BUS_SPI) {
512*0d6140beSAndroid Build Coastguard Worker const uint8_t *opcode = spi_get_opcode_from_erasefn(eraser.block_erase);
513*0d6140beSAndroid Build Coastguard Worker if (opcode)
514*0d6140beSAndroid Build Coastguard Worker for (int i = 0; opcode[i]; i++) {
515*0d6140beSAndroid Build Coastguard Worker if (!spi_probe_opcode(flash, opcode[i])) {
516*0d6140beSAndroid Build Coastguard Worker if (log)
517*0d6140beSAndroid Build Coastguard Worker msg_cdbg("block erase function and layout found "
518*0d6140beSAndroid Build Coastguard Worker "but SPI master doesn't support the function. ");
519*0d6140beSAndroid Build Coastguard Worker return 1;
520*0d6140beSAndroid Build Coastguard Worker }
521*0d6140beSAndroid Build Coastguard Worker }
522*0d6140beSAndroid Build Coastguard Worker }
523*0d6140beSAndroid Build Coastguard Worker // TODO: Once erase functions are annotated with allowed buses, check that as well.
524*0d6140beSAndroid Build Coastguard Worker return 0;
525*0d6140beSAndroid Build Coastguard Worker }
526*0d6140beSAndroid Build Coastguard Worker
527*0d6140beSAndroid Build Coastguard Worker /* Returns the number of well-defined erasers for a chip. */
count_usable_erasers(const struct flashctx * flash)528*0d6140beSAndroid Build Coastguard Worker unsigned int count_usable_erasers(const struct flashctx *flash)
529*0d6140beSAndroid Build Coastguard Worker {
530*0d6140beSAndroid Build Coastguard Worker unsigned int usable_erasefunctions = 0;
531*0d6140beSAndroid Build Coastguard Worker int k;
532*0d6140beSAndroid Build Coastguard Worker for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
533*0d6140beSAndroid Build Coastguard Worker if (!check_block_eraser(flash, k, 0))
534*0d6140beSAndroid Build Coastguard Worker usable_erasefunctions++;
535*0d6140beSAndroid Build Coastguard Worker }
536*0d6140beSAndroid Build Coastguard Worker return usable_erasefunctions;
537*0d6140beSAndroid Build Coastguard Worker }
538*0d6140beSAndroid Build Coastguard Worker
compare_range(const uint8_t * wantbuf,const uint8_t * havebuf,unsigned int start,unsigned int len)539*0d6140beSAndroid Build Coastguard Worker static int compare_range(const uint8_t *wantbuf, const uint8_t *havebuf, unsigned int start, unsigned int len)
540*0d6140beSAndroid Build Coastguard Worker {
541*0d6140beSAndroid Build Coastguard Worker int ret = 0, failcount = 0;
542*0d6140beSAndroid Build Coastguard Worker unsigned int i;
543*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
544*0d6140beSAndroid Build Coastguard Worker if (wantbuf[i] != havebuf[i]) {
545*0d6140beSAndroid Build Coastguard Worker /* Only print the first failure. */
546*0d6140beSAndroid Build Coastguard Worker if (!failcount++)
547*0d6140beSAndroid Build Coastguard Worker msg_cerr("FAILED at 0x%08x! Expected=0x%02x, Found=0x%02x,",
548*0d6140beSAndroid Build Coastguard Worker start + i, wantbuf[i], havebuf[i]);
549*0d6140beSAndroid Build Coastguard Worker }
550*0d6140beSAndroid Build Coastguard Worker }
551*0d6140beSAndroid Build Coastguard Worker if (failcount) {
552*0d6140beSAndroid Build Coastguard Worker msg_cerr(" failed byte count from 0x%08x-0x%08x: 0x%x\n",
553*0d6140beSAndroid Build Coastguard Worker start, start + len - 1, failcount);
554*0d6140beSAndroid Build Coastguard Worker ret = -1;
555*0d6140beSAndroid Build Coastguard Worker }
556*0d6140beSAndroid Build Coastguard Worker return ret;
557*0d6140beSAndroid Build Coastguard Worker }
558*0d6140beSAndroid Build Coastguard Worker
559*0d6140beSAndroid Build Coastguard Worker /* start is an offset to the base address of the flash chip */
check_erased_range(struct flashctx * flash,unsigned int start,unsigned int len)560*0d6140beSAndroid Build Coastguard Worker int check_erased_range(struct flashctx *flash, unsigned int start, unsigned int len)
561*0d6140beSAndroid Build Coastguard Worker {
562*0d6140beSAndroid Build Coastguard Worker int ret;
563*0d6140beSAndroid Build Coastguard Worker const uint8_t erased_value = ERASED_VALUE(flash);
564*0d6140beSAndroid Build Coastguard Worker
565*0d6140beSAndroid Build Coastguard Worker uint8_t *cmpbuf = malloc(len);
566*0d6140beSAndroid Build Coastguard Worker if (!cmpbuf) {
567*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory!\n");
568*0d6140beSAndroid Build Coastguard Worker return -1;
569*0d6140beSAndroid Build Coastguard Worker }
570*0d6140beSAndroid Build Coastguard Worker memset(cmpbuf, erased_value, len);
571*0d6140beSAndroid Build Coastguard Worker ret = verify_range(flash, cmpbuf, start, len);
572*0d6140beSAndroid Build Coastguard Worker
573*0d6140beSAndroid Build Coastguard Worker free(cmpbuf);
574*0d6140beSAndroid Build Coastguard Worker return ret;
575*0d6140beSAndroid Build Coastguard Worker }
576*0d6140beSAndroid Build Coastguard Worker
577*0d6140beSAndroid Build Coastguard Worker /* special unit-test hook */
578*0d6140beSAndroid Build Coastguard Worker read_func_t *g_test_read_injector;
579*0d6140beSAndroid Build Coastguard Worker
lookup_read_func_ptr(const struct flashchip * chip)580*0d6140beSAndroid Build Coastguard Worker static read_func_t *lookup_read_func_ptr(const struct flashchip *chip)
581*0d6140beSAndroid Build Coastguard Worker {
582*0d6140beSAndroid Build Coastguard Worker switch (chip->read) {
583*0d6140beSAndroid Build Coastguard Worker case SPI_CHIP_READ: return &spi_chip_read;
584*0d6140beSAndroid Build Coastguard Worker case READ_OPAQUE: return &read_opaque;
585*0d6140beSAndroid Build Coastguard Worker case READ_MEMMAPPED: return &read_memmapped;
586*0d6140beSAndroid Build Coastguard Worker case EDI_CHIP_READ: return &edi_chip_read;
587*0d6140beSAndroid Build Coastguard Worker case SPI_READ_AT45DB: return spi_read_at45db;
588*0d6140beSAndroid Build Coastguard Worker case SPI_READ_AT45DB_E8: return spi_read_at45db_e8;
589*0d6140beSAndroid Build Coastguard Worker case TEST_READ_INJECTOR: return g_test_read_injector;
590*0d6140beSAndroid Build Coastguard Worker /* default: total function, 0 indicates no read function set.
591*0d6140beSAndroid Build Coastguard Worker * We explicitly do not want a default catch-all case in the switch
592*0d6140beSAndroid Build Coastguard Worker * to ensure unhandled enum's are compiler warnings.
593*0d6140beSAndroid Build Coastguard Worker */
594*0d6140beSAndroid Build Coastguard Worker case NO_READ_FUNC: return NULL;
595*0d6140beSAndroid Build Coastguard Worker };
596*0d6140beSAndroid Build Coastguard Worker
597*0d6140beSAndroid Build Coastguard Worker return NULL;
598*0d6140beSAndroid Build Coastguard Worker }
599*0d6140beSAndroid Build Coastguard Worker
600*0d6140beSAndroid Build Coastguard Worker /*
601*0d6140beSAndroid Build Coastguard Worker * @brief Wrapper for flash->read() with additional high-level policy.
602*0d6140beSAndroid Build Coastguard Worker *
603*0d6140beSAndroid Build Coastguard Worker * @param flash flash chip
604*0d6140beSAndroid Build Coastguard Worker * @param buf buffer to store data in
605*0d6140beSAndroid Build Coastguard Worker * @param start start address
606*0d6140beSAndroid Build Coastguard Worker * @param len number of bytes to read
607*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
608*0d6140beSAndroid Build Coastguard Worker * -1 if any read fails.
609*0d6140beSAndroid Build Coastguard Worker *
610*0d6140beSAndroid Build Coastguard Worker * This wrapper simplifies most cases when the flash chip needs to be read
611*0d6140beSAndroid Build Coastguard Worker * since policy decisions such as non-fatal error handling is centralized.
612*0d6140beSAndroid Build Coastguard Worker */
read_flash(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len)613*0d6140beSAndroid Build Coastguard Worker int read_flash(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
614*0d6140beSAndroid Build Coastguard Worker {
615*0d6140beSAndroid Build Coastguard Worker unsigned int read_len;
616*0d6140beSAndroid Build Coastguard Worker for (unsigned int addr = start; addr < start + len; addr += read_len) {
617*0d6140beSAndroid Build Coastguard Worker struct flash_region region;
618*0d6140beSAndroid Build Coastguard Worker get_flash_region(flash, addr, ®ion);
619*0d6140beSAndroid Build Coastguard Worker
620*0d6140beSAndroid Build Coastguard Worker read_len = min(start + len, region.end) - addr;
621*0d6140beSAndroid Build Coastguard Worker uint8_t *rbuf = buf + addr - start;
622*0d6140beSAndroid Build Coastguard Worker
623*0d6140beSAndroid Build Coastguard Worker if (region.read_prot) {
624*0d6140beSAndroid Build Coastguard Worker if (flash->flags.skip_unreadable_regions) {
625*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: cannot read inside %s region (%#08"PRIx32"..%#08"PRIx32"), "
626*0d6140beSAndroid Build Coastguard Worker "filling (%#08x..%#08x) with erased value instead.\n",
627*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1,
628*0d6140beSAndroid Build Coastguard Worker addr, addr + read_len - 1);
629*0d6140beSAndroid Build Coastguard Worker free(region.name);
630*0d6140beSAndroid Build Coastguard Worker
631*0d6140beSAndroid Build Coastguard Worker memset(rbuf, ERASED_VALUE(flash), read_len);
632*0d6140beSAndroid Build Coastguard Worker continue;
633*0d6140beSAndroid Build Coastguard Worker }
634*0d6140beSAndroid Build Coastguard Worker
635*0d6140beSAndroid Build Coastguard Worker msg_gerr("%s: cannot read inside %s region (%#08"PRIx32"..%#08"PRIx32").\n",
636*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1);
637*0d6140beSAndroid Build Coastguard Worker free(region.name);
638*0d6140beSAndroid Build Coastguard Worker return -1;
639*0d6140beSAndroid Build Coastguard Worker }
640*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is readable, reading range (%#08x..%#08x).\n",
641*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1, addr, addr + read_len - 1);
642*0d6140beSAndroid Build Coastguard Worker free(region.name);
643*0d6140beSAndroid Build Coastguard Worker
644*0d6140beSAndroid Build Coastguard Worker read_func_t *read_func = lookup_read_func_ptr(flash->chip);
645*0d6140beSAndroid Build Coastguard Worker int ret = read_func(flash, rbuf, addr, read_len);
646*0d6140beSAndroid Build Coastguard Worker if (ret) {
647*0d6140beSAndroid Build Coastguard Worker msg_gerr("%s: failed to read (%#08x..%#08x).\n", __func__, addr, addr + read_len - 1);
648*0d6140beSAndroid Build Coastguard Worker return -1;
649*0d6140beSAndroid Build Coastguard Worker }
650*0d6140beSAndroid Build Coastguard Worker
651*0d6140beSAndroid Build Coastguard Worker }
652*0d6140beSAndroid Build Coastguard Worker
653*0d6140beSAndroid Build Coastguard Worker return 0;
654*0d6140beSAndroid Build Coastguard Worker }
655*0d6140beSAndroid Build Coastguard Worker
656*0d6140beSAndroid Build Coastguard Worker /*
657*0d6140beSAndroid Build Coastguard Worker * @cmpbuf buffer to compare against, cmpbuf[0] is expected to match the
658*0d6140beSAndroid Build Coastguard Worker * flash content at location start
659*0d6140beSAndroid Build Coastguard Worker * @start offset to the base address of the flash chip
660*0d6140beSAndroid Build Coastguard Worker * @len length of the verified area
661*0d6140beSAndroid Build Coastguard Worker * @return 0 for success, -1 for failure
662*0d6140beSAndroid Build Coastguard Worker */
verify_range(struct flashctx * flash,const uint8_t * cmpbuf,unsigned int start,unsigned int len)663*0d6140beSAndroid Build Coastguard Worker int verify_range(struct flashctx *flash, const uint8_t *cmpbuf, unsigned int start, unsigned int len)
664*0d6140beSAndroid Build Coastguard Worker {
665*0d6140beSAndroid Build Coastguard Worker if (!len)
666*0d6140beSAndroid Build Coastguard Worker return -1;
667*0d6140beSAndroid Build Coastguard Worker
668*0d6140beSAndroid Build Coastguard Worker if (start + len > flash->chip->total_size * 1024) {
669*0d6140beSAndroid Build Coastguard Worker msg_gerr("Error: %s called with start 0x%x + len 0x%x >"
670*0d6140beSAndroid Build Coastguard Worker " total_size 0x%x\n", __func__, start, len,
671*0d6140beSAndroid Build Coastguard Worker flash->chip->total_size * 1024);
672*0d6140beSAndroid Build Coastguard Worker return -1;
673*0d6140beSAndroid Build Coastguard Worker }
674*0d6140beSAndroid Build Coastguard Worker
675*0d6140beSAndroid Build Coastguard Worker uint8_t *readbuf = malloc(len);
676*0d6140beSAndroid Build Coastguard Worker if (!readbuf) {
677*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory!\n");
678*0d6140beSAndroid Build Coastguard Worker return -1;
679*0d6140beSAndroid Build Coastguard Worker }
680*0d6140beSAndroid Build Coastguard Worker
681*0d6140beSAndroid Build Coastguard Worker int ret = 0;
682*0d6140beSAndroid Build Coastguard Worker
683*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%#06x..%#06x ", start, start + len - 1);
684*0d6140beSAndroid Build Coastguard Worker
685*0d6140beSAndroid Build Coastguard Worker unsigned int read_len;
686*0d6140beSAndroid Build Coastguard Worker for (size_t addr = start; addr < start + len; addr += read_len) {
687*0d6140beSAndroid Build Coastguard Worker struct flash_region region;
688*0d6140beSAndroid Build Coastguard Worker get_flash_region(flash, addr, ®ion);
689*0d6140beSAndroid Build Coastguard Worker read_len = min(start + len, region.end) - addr;
690*0d6140beSAndroid Build Coastguard Worker
691*0d6140beSAndroid Build Coastguard Worker if ((region.write_prot && flash->flags.skip_unwritable_regions) ||
692*0d6140beSAndroid Build Coastguard Worker (region.read_prot && flash->flags.skip_unreadable_regions)) {
693*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: Skipping verification of %s region (%#08"PRIx32"..%#08"PRIx32")\n",
694*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1);
695*0d6140beSAndroid Build Coastguard Worker free(region.name);
696*0d6140beSAndroid Build Coastguard Worker continue;
697*0d6140beSAndroid Build Coastguard Worker }
698*0d6140beSAndroid Build Coastguard Worker
699*0d6140beSAndroid Build Coastguard Worker if (region.read_prot) {
700*0d6140beSAndroid Build Coastguard Worker msg_gerr("%s: Verification imposible because %s region (%#08"PRIx32"..%#08"PRIx32") is unreadable.\n",
701*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1);
702*0d6140beSAndroid Build Coastguard Worker free(region.name);
703*0d6140beSAndroid Build Coastguard Worker goto out_free;
704*0d6140beSAndroid Build Coastguard Worker }
705*0d6140beSAndroid Build Coastguard Worker
706*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: Verifying %s region (%#08"PRIx32"..%#08"PRIx32")\n",
707*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1);
708*0d6140beSAndroid Build Coastguard Worker free(region.name);
709*0d6140beSAndroid Build Coastguard Worker
710*0d6140beSAndroid Build Coastguard Worker ret = read_flash(flash, readbuf, addr, read_len);
711*0d6140beSAndroid Build Coastguard Worker if (ret) {
712*0d6140beSAndroid Build Coastguard Worker msg_gerr("Verification impossible because read failed "
713*0d6140beSAndroid Build Coastguard Worker "at 0x%x (len 0x%x)\n", start, len);
714*0d6140beSAndroid Build Coastguard Worker ret = -1;
715*0d6140beSAndroid Build Coastguard Worker goto out_free;
716*0d6140beSAndroid Build Coastguard Worker }
717*0d6140beSAndroid Build Coastguard Worker
718*0d6140beSAndroid Build Coastguard Worker ret = compare_range(cmpbuf + (addr - start), readbuf, addr, read_len);
719*0d6140beSAndroid Build Coastguard Worker if (ret)
720*0d6140beSAndroid Build Coastguard Worker goto out_free;
721*0d6140beSAndroid Build Coastguard Worker
722*0d6140beSAndroid Build Coastguard Worker }
723*0d6140beSAndroid Build Coastguard Worker
724*0d6140beSAndroid Build Coastguard Worker out_free:
725*0d6140beSAndroid Build Coastguard Worker free(readbuf);
726*0d6140beSAndroid Build Coastguard Worker return ret;
727*0d6140beSAndroid Build Coastguard Worker }
728*0d6140beSAndroid Build Coastguard Worker
729*0d6140beSAndroid Build Coastguard Worker /* Helper function for need_erase() that focuses on granularities of gran bytes. */
need_erase_gran_bytes(const uint8_t * have,const uint8_t * want,unsigned int len,unsigned int gran,const uint8_t erased_value)730*0d6140beSAndroid Build Coastguard Worker static int need_erase_gran_bytes(const uint8_t *have, const uint8_t *want, unsigned int len,
731*0d6140beSAndroid Build Coastguard Worker unsigned int gran, const uint8_t erased_value)
732*0d6140beSAndroid Build Coastguard Worker {
733*0d6140beSAndroid Build Coastguard Worker unsigned int i, j, limit;
734*0d6140beSAndroid Build Coastguard Worker for (j = 0; j < len / gran; j++) {
735*0d6140beSAndroid Build Coastguard Worker limit = min (gran, len - j * gran);
736*0d6140beSAndroid Build Coastguard Worker /* Are 'have' and 'want' identical? */
737*0d6140beSAndroid Build Coastguard Worker if (!memcmp(have + j * gran, want + j * gran, limit))
738*0d6140beSAndroid Build Coastguard Worker continue;
739*0d6140beSAndroid Build Coastguard Worker /* have needs to be in erased state. */
740*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < limit; i++)
741*0d6140beSAndroid Build Coastguard Worker if (have[j * gran + i] != erased_value)
742*0d6140beSAndroid Build Coastguard Worker return 1;
743*0d6140beSAndroid Build Coastguard Worker }
744*0d6140beSAndroid Build Coastguard Worker return 0;
745*0d6140beSAndroid Build Coastguard Worker }
746*0d6140beSAndroid Build Coastguard Worker
747*0d6140beSAndroid Build Coastguard Worker /*
748*0d6140beSAndroid Build Coastguard Worker * Check if the buffer @have can be programmed to the content of @want without
749*0d6140beSAndroid Build Coastguard Worker * erasing. This is only possible if all chunks of size @gran are either kept
750*0d6140beSAndroid Build Coastguard Worker * as-is or changed from an all-ones state to any other state.
751*0d6140beSAndroid Build Coastguard Worker *
752*0d6140beSAndroid Build Coastguard Worker * Warning: This function assumes that @have and @want point to naturally
753*0d6140beSAndroid Build Coastguard Worker * aligned regions.
754*0d6140beSAndroid Build Coastguard Worker *
755*0d6140beSAndroid Build Coastguard Worker * @have buffer with current content
756*0d6140beSAndroid Build Coastguard Worker * @want buffer with desired content
757*0d6140beSAndroid Build Coastguard Worker * @len length of the checked area
758*0d6140beSAndroid Build Coastguard Worker * @gran write granularity (enum, not count)
759*0d6140beSAndroid Build Coastguard Worker * @return 0 if no erase is needed, 1 otherwise
760*0d6140beSAndroid Build Coastguard Worker */
need_erase(const uint8_t * have,const uint8_t * want,unsigned int len,enum write_granularity gran,const uint8_t erased_value)761*0d6140beSAndroid Build Coastguard Worker int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len,
762*0d6140beSAndroid Build Coastguard Worker enum write_granularity gran, const uint8_t erased_value)
763*0d6140beSAndroid Build Coastguard Worker {
764*0d6140beSAndroid Build Coastguard Worker int result = 0;
765*0d6140beSAndroid Build Coastguard Worker unsigned int i;
766*0d6140beSAndroid Build Coastguard Worker
767*0d6140beSAndroid Build Coastguard Worker switch (gran) {
768*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1BIT:
769*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < len; i++)
770*0d6140beSAndroid Build Coastguard Worker if ((have[i] & want[i]) != want[i]) {
771*0d6140beSAndroid Build Coastguard Worker result = 1;
772*0d6140beSAndroid Build Coastguard Worker break;
773*0d6140beSAndroid Build Coastguard Worker }
774*0d6140beSAndroid Build Coastguard Worker break;
775*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1BYTE:
776*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < len; i++)
777*0d6140beSAndroid Build Coastguard Worker if ((have[i] != want[i]) && (have[i] != erased_value)) {
778*0d6140beSAndroid Build Coastguard Worker result = 1;
779*0d6140beSAndroid Build Coastguard Worker break;
780*0d6140beSAndroid Build Coastguard Worker }
781*0d6140beSAndroid Build Coastguard Worker break;
782*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_128BYTES:
783*0d6140beSAndroid Build Coastguard Worker result = need_erase_gran_bytes(have, want, len, 128, erased_value);
784*0d6140beSAndroid Build Coastguard Worker break;
785*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_256BYTES:
786*0d6140beSAndroid Build Coastguard Worker result = need_erase_gran_bytes(have, want, len, 256, erased_value);
787*0d6140beSAndroid Build Coastguard Worker break;
788*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_264BYTES:
789*0d6140beSAndroid Build Coastguard Worker result = need_erase_gran_bytes(have, want, len, 264, erased_value);
790*0d6140beSAndroid Build Coastguard Worker break;
791*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_512BYTES:
792*0d6140beSAndroid Build Coastguard Worker result = need_erase_gran_bytes(have, want, len, 512, erased_value);
793*0d6140beSAndroid Build Coastguard Worker break;
794*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_528BYTES:
795*0d6140beSAndroid Build Coastguard Worker result = need_erase_gran_bytes(have, want, len, 528, erased_value);
796*0d6140beSAndroid Build Coastguard Worker break;
797*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1024BYTES:
798*0d6140beSAndroid Build Coastguard Worker result = need_erase_gran_bytes(have, want, len, 1024, erased_value);
799*0d6140beSAndroid Build Coastguard Worker break;
800*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1056BYTES:
801*0d6140beSAndroid Build Coastguard Worker result = need_erase_gran_bytes(have, want, len, 1056, erased_value);
802*0d6140beSAndroid Build Coastguard Worker break;
803*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1BYTE_IMPLICIT_ERASE:
804*0d6140beSAndroid Build Coastguard Worker /* Do not erase, handle content changes from anything->0xff by writing 0xff. */
805*0d6140beSAndroid Build Coastguard Worker result = 0;
806*0d6140beSAndroid Build Coastguard Worker break;
807*0d6140beSAndroid Build Coastguard Worker default:
808*0d6140beSAndroid Build Coastguard Worker msg_cerr("%s: Unsupported granularity! Please report a bug at "
809*0d6140beSAndroid Build Coastguard Worker "[email protected]\n", __func__);
810*0d6140beSAndroid Build Coastguard Worker }
811*0d6140beSAndroid Build Coastguard Worker return result;
812*0d6140beSAndroid Build Coastguard Worker }
813*0d6140beSAndroid Build Coastguard Worker
814*0d6140beSAndroid Build Coastguard Worker /**
815*0d6140beSAndroid Build Coastguard Worker * Check if the buffer @have needs to be programmed to get the content of @want.
816*0d6140beSAndroid Build Coastguard Worker * If yes, return 1 and fill in first_start with the start address of the
817*0d6140beSAndroid Build Coastguard Worker * write operation and first_len with the length of the first to-be-written
818*0d6140beSAndroid Build Coastguard Worker * chunk. If not, return 0 and leave first_start and first_len undefined.
819*0d6140beSAndroid Build Coastguard Worker *
820*0d6140beSAndroid Build Coastguard Worker * Warning: This function assumes that @have and @want point to naturally
821*0d6140beSAndroid Build Coastguard Worker * aligned regions.
822*0d6140beSAndroid Build Coastguard Worker *
823*0d6140beSAndroid Build Coastguard Worker * @have buffer with current content
824*0d6140beSAndroid Build Coastguard Worker * @want buffer with desired content
825*0d6140beSAndroid Build Coastguard Worker * @len length of the checked area
826*0d6140beSAndroid Build Coastguard Worker * @gran write granularity (enum, not count)
827*0d6140beSAndroid Build Coastguard Worker * @first_start offset of the first byte which needs to be written (passed in
828*0d6140beSAndroid Build Coastguard Worker * value is increased by the offset of the first needed write
829*0d6140beSAndroid Build Coastguard Worker * relative to have/want or unchanged if no write is needed)
830*0d6140beSAndroid Build Coastguard Worker * @return length of the first contiguous area which needs to be written
831*0d6140beSAndroid Build Coastguard Worker * 0 if no write is needed
832*0d6140beSAndroid Build Coastguard Worker *
833*0d6140beSAndroid Build Coastguard Worker * FIXME: This function needs a parameter which tells it about coalescing
834*0d6140beSAndroid Build Coastguard Worker * in relation to the max write length of the programmer and the max write
835*0d6140beSAndroid Build Coastguard Worker * length of the chip.
836*0d6140beSAndroid Build Coastguard Worker */
get_next_write(const uint8_t * have,const uint8_t * want,unsigned int len,unsigned int * first_start,enum write_granularity gran)837*0d6140beSAndroid Build Coastguard Worker unsigned int get_next_write(const uint8_t *have, const uint8_t *want, unsigned int len,
838*0d6140beSAndroid Build Coastguard Worker unsigned int *first_start,
839*0d6140beSAndroid Build Coastguard Worker enum write_granularity gran)
840*0d6140beSAndroid Build Coastguard Worker {
841*0d6140beSAndroid Build Coastguard Worker bool need_write = false;
842*0d6140beSAndroid Build Coastguard Worker unsigned int rel_start = 0, first_len = 0;
843*0d6140beSAndroid Build Coastguard Worker unsigned int i, limit, stride;
844*0d6140beSAndroid Build Coastguard Worker
845*0d6140beSAndroid Build Coastguard Worker switch (gran) {
846*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1BIT:
847*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1BYTE:
848*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1BYTE_IMPLICIT_ERASE:
849*0d6140beSAndroid Build Coastguard Worker stride = 1;
850*0d6140beSAndroid Build Coastguard Worker break;
851*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_128BYTES:
852*0d6140beSAndroid Build Coastguard Worker stride = 128;
853*0d6140beSAndroid Build Coastguard Worker break;
854*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_256BYTES:
855*0d6140beSAndroid Build Coastguard Worker stride = 256;
856*0d6140beSAndroid Build Coastguard Worker break;
857*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_264BYTES:
858*0d6140beSAndroid Build Coastguard Worker stride = 264;
859*0d6140beSAndroid Build Coastguard Worker break;
860*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_512BYTES:
861*0d6140beSAndroid Build Coastguard Worker stride = 512;
862*0d6140beSAndroid Build Coastguard Worker break;
863*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_528BYTES:
864*0d6140beSAndroid Build Coastguard Worker stride = 528;
865*0d6140beSAndroid Build Coastguard Worker break;
866*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1024BYTES:
867*0d6140beSAndroid Build Coastguard Worker stride = 1024;
868*0d6140beSAndroid Build Coastguard Worker break;
869*0d6140beSAndroid Build Coastguard Worker case WRITE_GRAN_1056BYTES:
870*0d6140beSAndroid Build Coastguard Worker stride = 1056;
871*0d6140beSAndroid Build Coastguard Worker break;
872*0d6140beSAndroid Build Coastguard Worker default:
873*0d6140beSAndroid Build Coastguard Worker msg_cerr("%s: Unsupported granularity! Please report a bug at "
874*0d6140beSAndroid Build Coastguard Worker "[email protected]\n", __func__);
875*0d6140beSAndroid Build Coastguard Worker /* Claim that no write was needed. A write with unknown
876*0d6140beSAndroid Build Coastguard Worker * granularity is too dangerous to try.
877*0d6140beSAndroid Build Coastguard Worker */
878*0d6140beSAndroid Build Coastguard Worker return 0;
879*0d6140beSAndroid Build Coastguard Worker }
880*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < len / stride; i++) {
881*0d6140beSAndroid Build Coastguard Worker limit = min(stride, len - i * stride);
882*0d6140beSAndroid Build Coastguard Worker /* Are 'have' and 'want' identical? */
883*0d6140beSAndroid Build Coastguard Worker if (memcmp(have + i * stride, want + i * stride, limit)) {
884*0d6140beSAndroid Build Coastguard Worker if (!need_write) {
885*0d6140beSAndroid Build Coastguard Worker /* First location where have and want differ. */
886*0d6140beSAndroid Build Coastguard Worker need_write = true;
887*0d6140beSAndroid Build Coastguard Worker rel_start = i * stride;
888*0d6140beSAndroid Build Coastguard Worker }
889*0d6140beSAndroid Build Coastguard Worker } else {
890*0d6140beSAndroid Build Coastguard Worker if (need_write) {
891*0d6140beSAndroid Build Coastguard Worker /* First location where have and want
892*0d6140beSAndroid Build Coastguard Worker * do not differ anymore.
893*0d6140beSAndroid Build Coastguard Worker */
894*0d6140beSAndroid Build Coastguard Worker break;
895*0d6140beSAndroid Build Coastguard Worker }
896*0d6140beSAndroid Build Coastguard Worker }
897*0d6140beSAndroid Build Coastguard Worker }
898*0d6140beSAndroid Build Coastguard Worker if (need_write)
899*0d6140beSAndroid Build Coastguard Worker first_len = min(i * stride - rel_start, len);
900*0d6140beSAndroid Build Coastguard Worker *first_start += rel_start;
901*0d6140beSAndroid Build Coastguard Worker return first_len;
902*0d6140beSAndroid Build Coastguard Worker }
903*0d6140beSAndroid Build Coastguard Worker
unmap_flash(struct flashctx * flash)904*0d6140beSAndroid Build Coastguard Worker void unmap_flash(struct flashctx *flash)
905*0d6140beSAndroid Build Coastguard Worker {
906*0d6140beSAndroid Build Coastguard Worker if (flash->virtual_registers != (chipaddr)ERROR_PTR) {
907*0d6140beSAndroid Build Coastguard Worker master_unmap_flash_region(flash->mst, (void *)flash->virtual_registers, flash->chip->total_size * 1024);
908*0d6140beSAndroid Build Coastguard Worker flash->physical_registers = 0;
909*0d6140beSAndroid Build Coastguard Worker flash->virtual_registers = (chipaddr)ERROR_PTR;
910*0d6140beSAndroid Build Coastguard Worker }
911*0d6140beSAndroid Build Coastguard Worker
912*0d6140beSAndroid Build Coastguard Worker if (flash->virtual_memory != (chipaddr)ERROR_PTR) {
913*0d6140beSAndroid Build Coastguard Worker master_unmap_flash_region(flash->mst, (void *)flash->virtual_memory, flash->chip->total_size * 1024);
914*0d6140beSAndroid Build Coastguard Worker flash->physical_memory = 0;
915*0d6140beSAndroid Build Coastguard Worker flash->virtual_memory = (chipaddr)ERROR_PTR;
916*0d6140beSAndroid Build Coastguard Worker }
917*0d6140beSAndroid Build Coastguard Worker }
918*0d6140beSAndroid Build Coastguard Worker
map_flash(struct flashctx * flash)919*0d6140beSAndroid Build Coastguard Worker int map_flash(struct flashctx *flash)
920*0d6140beSAndroid Build Coastguard Worker {
921*0d6140beSAndroid Build Coastguard Worker /* Init pointers to the fail-safe state to distinguish them later from legit values. */
922*0d6140beSAndroid Build Coastguard Worker flash->virtual_memory = (chipaddr)ERROR_PTR;
923*0d6140beSAndroid Build Coastguard Worker flash->virtual_registers = (chipaddr)ERROR_PTR;
924*0d6140beSAndroid Build Coastguard Worker
925*0d6140beSAndroid Build Coastguard Worker /* FIXME: This avoids mapping (and unmapping) of flash chip definitions with size 0.
926*0d6140beSAndroid Build Coastguard Worker * These are used for various probing-related hacks that would not map successfully anyway and should be
927*0d6140beSAndroid Build Coastguard Worker * removed ASAP. */
928*0d6140beSAndroid Build Coastguard Worker if (flash->chip->total_size == 0)
929*0d6140beSAndroid Build Coastguard Worker return 0;
930*0d6140beSAndroid Build Coastguard Worker
931*0d6140beSAndroid Build Coastguard Worker const chipsize_t size = flash->chip->total_size * 1024;
932*0d6140beSAndroid Build Coastguard Worker uintptr_t base = flashbase ? flashbase : (0xffffffff - size + 1);
933*0d6140beSAndroid Build Coastguard Worker void *addr = master_map_flash_region(flash->mst, flash->chip->name, base, size);
934*0d6140beSAndroid Build Coastguard Worker if (addr == ERROR_PTR) {
935*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not map flash chip %s at 0x%0*" PRIxPTR ".\n",
936*0d6140beSAndroid Build Coastguard Worker flash->chip->name, PRIxPTR_WIDTH, base);
937*0d6140beSAndroid Build Coastguard Worker return 1;
938*0d6140beSAndroid Build Coastguard Worker }
939*0d6140beSAndroid Build Coastguard Worker flash->physical_memory = base;
940*0d6140beSAndroid Build Coastguard Worker flash->virtual_memory = (chipaddr)addr;
941*0d6140beSAndroid Build Coastguard Worker
942*0d6140beSAndroid Build Coastguard Worker /* FIXME: Special function registers normally live 4 MByte below flash space, but it might be somewhere
943*0d6140beSAndroid Build Coastguard Worker * completely different on some chips and programmers, or not mappable at all.
944*0d6140beSAndroid Build Coastguard Worker * Ignore these problems for now and always report success. */
945*0d6140beSAndroid Build Coastguard Worker if (flash->chip->feature_bits & FEATURE_REGISTERMAP) {
946*0d6140beSAndroid Build Coastguard Worker base = 0xffffffff - size - 0x400000 + 1;
947*0d6140beSAndroid Build Coastguard Worker addr = master_map_flash_region(flash->mst, "flash chip registers", base, size);
948*0d6140beSAndroid Build Coastguard Worker if (addr == ERROR_PTR) {
949*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("Could not map flash chip registers %s at 0x%0*" PRIxPTR ".\n",
950*0d6140beSAndroid Build Coastguard Worker flash->chip->name, PRIxPTR_WIDTH, base);
951*0d6140beSAndroid Build Coastguard Worker return 0;
952*0d6140beSAndroid Build Coastguard Worker }
953*0d6140beSAndroid Build Coastguard Worker flash->physical_registers = base;
954*0d6140beSAndroid Build Coastguard Worker flash->virtual_registers = (chipaddr)addr;
955*0d6140beSAndroid Build Coastguard Worker }
956*0d6140beSAndroid Build Coastguard Worker return 0;
957*0d6140beSAndroid Build Coastguard Worker }
958*0d6140beSAndroid Build Coastguard Worker
959*0d6140beSAndroid Build Coastguard Worker /*
960*0d6140beSAndroid Build Coastguard Worker * Return a string corresponding to the bustype parameter.
961*0d6140beSAndroid Build Coastguard Worker * Memory to store the string is allocated. The caller is responsible to free memory.
962*0d6140beSAndroid Build Coastguard Worker * If there is not enough memory remaining, then NULL is returned.
963*0d6140beSAndroid Build Coastguard Worker */
flashbuses_to_text(enum chipbustype bustype)964*0d6140beSAndroid Build Coastguard Worker char *flashbuses_to_text(enum chipbustype bustype)
965*0d6140beSAndroid Build Coastguard Worker {
966*0d6140beSAndroid Build Coastguard Worker char *ret, *ptr;
967*0d6140beSAndroid Build Coastguard Worker
968*0d6140beSAndroid Build Coastguard Worker /*
969*0d6140beSAndroid Build Coastguard Worker * FIXME: Once all chipsets and flash chips have been updated, NONSPI
970*0d6140beSAndroid Build Coastguard Worker * will cease to exist and should be eliminated here as well.
971*0d6140beSAndroid Build Coastguard Worker */
972*0d6140beSAndroid Build Coastguard Worker if (bustype == BUS_NONSPI)
973*0d6140beSAndroid Build Coastguard Worker return strdup("Non-SPI");
974*0d6140beSAndroid Build Coastguard Worker if (bustype == BUS_NONE)
975*0d6140beSAndroid Build Coastguard Worker return strdup("None");
976*0d6140beSAndroid Build Coastguard Worker
977*0d6140beSAndroid Build Coastguard Worker ret = calloc(1, 1);
978*0d6140beSAndroid Build Coastguard Worker if (!ret)
979*0d6140beSAndroid Build Coastguard Worker return NULL;
980*0d6140beSAndroid Build Coastguard Worker
981*0d6140beSAndroid Build Coastguard Worker for (unsigned int i = 0; i < ARRAY_SIZE(bustypes); i++)
982*0d6140beSAndroid Build Coastguard Worker {
983*0d6140beSAndroid Build Coastguard Worker if (bustype & bustypes[i].type) {
984*0d6140beSAndroid Build Coastguard Worker ptr = strcat_realloc(ret, bustypes[i].name);
985*0d6140beSAndroid Build Coastguard Worker if (!ptr) {
986*0d6140beSAndroid Build Coastguard Worker free(ret);
987*0d6140beSAndroid Build Coastguard Worker return NULL;
988*0d6140beSAndroid Build Coastguard Worker }
989*0d6140beSAndroid Build Coastguard Worker ret = ptr;
990*0d6140beSAndroid Build Coastguard Worker }
991*0d6140beSAndroid Build Coastguard Worker }
992*0d6140beSAndroid Build Coastguard Worker
993*0d6140beSAndroid Build Coastguard Worker /* Kill last comma. */
994*0d6140beSAndroid Build Coastguard Worker ret[strlen(ret) - 2] = '\0';
995*0d6140beSAndroid Build Coastguard Worker ptr = realloc(ret, strlen(ret) + 1);
996*0d6140beSAndroid Build Coastguard Worker if (!ptr)
997*0d6140beSAndroid Build Coastguard Worker free(ret);
998*0d6140beSAndroid Build Coastguard Worker return ptr;
999*0d6140beSAndroid Build Coastguard Worker }
1000*0d6140beSAndroid Build Coastguard Worker
init_default_layout(struct flashctx * flash)1001*0d6140beSAndroid Build Coastguard Worker static int init_default_layout(struct flashctx *flash)
1002*0d6140beSAndroid Build Coastguard Worker {
1003*0d6140beSAndroid Build Coastguard Worker /* Fill default layout covering the whole chip. */
1004*0d6140beSAndroid Build Coastguard Worker if (flashrom_layout_new(&flash->default_layout) ||
1005*0d6140beSAndroid Build Coastguard Worker flashrom_layout_add_region(flash->default_layout,
1006*0d6140beSAndroid Build Coastguard Worker 0, flash->chip->total_size * 1024 - 1, "complete flash") ||
1007*0d6140beSAndroid Build Coastguard Worker flashrom_layout_include_region(flash->default_layout, "complete flash"))
1008*0d6140beSAndroid Build Coastguard Worker return -1;
1009*0d6140beSAndroid Build Coastguard Worker return 0;
1010*0d6140beSAndroid Build Coastguard Worker }
1011*0d6140beSAndroid Build Coastguard Worker
1012*0d6140beSAndroid Build Coastguard Worker /* special unit-test hook */
1013*0d6140beSAndroid Build Coastguard Worker write_func_t *g_test_write_injector;
1014*0d6140beSAndroid Build Coastguard Worker
lookup_write_func_ptr(const struct flashchip * chip)1015*0d6140beSAndroid Build Coastguard Worker static write_func_t *lookup_write_func_ptr(const struct flashchip *chip)
1016*0d6140beSAndroid Build Coastguard Worker {
1017*0d6140beSAndroid Build Coastguard Worker switch (chip->write) {
1018*0d6140beSAndroid Build Coastguard Worker case WRITE_JEDEC: return &write_jedec;
1019*0d6140beSAndroid Build Coastguard Worker case WRITE_JEDEC1: return &write_jedec_1;
1020*0d6140beSAndroid Build Coastguard Worker case WRITE_OPAQUE: return &write_opaque;
1021*0d6140beSAndroid Build Coastguard Worker case SPI_CHIP_WRITE1: return &spi_chip_write_1;
1022*0d6140beSAndroid Build Coastguard Worker case SPI_CHIP_WRITE256: return &spi_chip_write_256;
1023*0d6140beSAndroid Build Coastguard Worker case SPI_WRITE_AAI: return &spi_aai_write;
1024*0d6140beSAndroid Build Coastguard Worker case SPI_WRITE_AT45DB: return &spi_write_at45db;
1025*0d6140beSAndroid Build Coastguard Worker case WRITE_28SF040: return &write_28sf040;
1026*0d6140beSAndroid Build Coastguard Worker case WRITE_82802AB: return &write_82802ab;
1027*0d6140beSAndroid Build Coastguard Worker case WRITE_EN29LV640B: return &write_en29lv640b;
1028*0d6140beSAndroid Build Coastguard Worker case EDI_CHIP_WRITE: return &edi_chip_write;
1029*0d6140beSAndroid Build Coastguard Worker case TEST_WRITE_INJECTOR: return g_test_write_injector;
1030*0d6140beSAndroid Build Coastguard Worker /* default: total function, 0 indicates no write function set.
1031*0d6140beSAndroid Build Coastguard Worker * We explicitly do not want a default catch-all case in the switch
1032*0d6140beSAndroid Build Coastguard Worker * to ensure unhandled enum's are compiler warnings.
1033*0d6140beSAndroid Build Coastguard Worker */
1034*0d6140beSAndroid Build Coastguard Worker case NO_WRITE_FUNC: return NULL;
1035*0d6140beSAndroid Build Coastguard Worker };
1036*0d6140beSAndroid Build Coastguard Worker
1037*0d6140beSAndroid Build Coastguard Worker return NULL;
1038*0d6140beSAndroid Build Coastguard Worker }
1039*0d6140beSAndroid Build Coastguard Worker
1040*0d6140beSAndroid Build Coastguard Worker /*
1041*0d6140beSAndroid Build Coastguard Worker * write_flash - wrapper for flash->write() with additional high-level policy
1042*0d6140beSAndroid Build Coastguard Worker *
1043*0d6140beSAndroid Build Coastguard Worker * @param flash flash chip
1044*0d6140beSAndroid Build Coastguard Worker * @param buf buffer to write to flash
1045*0d6140beSAndroid Build Coastguard Worker * @param start start address in flash
1046*0d6140beSAndroid Build Coastguard Worker * @param len number of bytes to write
1047*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
1048*0d6140beSAndroid Build Coastguard Worker * -1 if any write fails.
1049*0d6140beSAndroid Build Coastguard Worker *
1050*0d6140beSAndroid Build Coastguard Worker * This wrapper simplifies most cases when the flash chip needs to be written
1051*0d6140beSAndroid Build Coastguard Worker * since policy decisions such as non-fatal error handling is centralized.
1052*0d6140beSAndroid Build Coastguard Worker */
write_flash(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)1053*0d6140beSAndroid Build Coastguard Worker int write_flash(struct flashctx *flash, const uint8_t *buf,
1054*0d6140beSAndroid Build Coastguard Worker unsigned int start, unsigned int len)
1055*0d6140beSAndroid Build Coastguard Worker {
1056*0d6140beSAndroid Build Coastguard Worker if (!flash->flags.skip_unwritable_regions) {
1057*0d6140beSAndroid Build Coastguard Worker if (check_for_unwritable_regions(flash, start, len))
1058*0d6140beSAndroid Build Coastguard Worker return -1;
1059*0d6140beSAndroid Build Coastguard Worker }
1060*0d6140beSAndroid Build Coastguard Worker
1061*0d6140beSAndroid Build Coastguard Worker unsigned int write_len;
1062*0d6140beSAndroid Build Coastguard Worker for (unsigned int addr = start; addr < start + len; addr += write_len) {
1063*0d6140beSAndroid Build Coastguard Worker struct flash_region region;
1064*0d6140beSAndroid Build Coastguard Worker get_flash_region(flash, addr, ®ion);
1065*0d6140beSAndroid Build Coastguard Worker
1066*0d6140beSAndroid Build Coastguard Worker write_len = min(start + len, region.end) - addr;
1067*0d6140beSAndroid Build Coastguard Worker const uint8_t *rbuf = buf + addr - start;
1068*0d6140beSAndroid Build Coastguard Worker
1069*0d6140beSAndroid Build Coastguard Worker if (region.write_prot) {
1070*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: cannot write inside %s region (%#08"PRIx32"..%#08"PRIx32"), skipping (%#08x..%#08x).\n",
1071*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1, addr, addr + write_len - 1);
1072*0d6140beSAndroid Build Coastguard Worker free(region.name);
1073*0d6140beSAndroid Build Coastguard Worker continue;
1074*0d6140beSAndroid Build Coastguard Worker }
1075*0d6140beSAndroid Build Coastguard Worker
1076*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is writable, writing range (%#08x..%#08x).\n",
1077*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1, addr, addr + write_len - 1);
1078*0d6140beSAndroid Build Coastguard Worker
1079*0d6140beSAndroid Build Coastguard Worker write_func_t *write_func = lookup_write_func_ptr(flash->chip);
1080*0d6140beSAndroid Build Coastguard Worker int ret = write_func(flash, rbuf, addr, write_len);
1081*0d6140beSAndroid Build Coastguard Worker if (ret) {
1082*0d6140beSAndroid Build Coastguard Worker msg_gerr("%s: failed to write (%#08x..%#08x).\n", __func__, addr, addr + write_len - 1);
1083*0d6140beSAndroid Build Coastguard Worker free(region.name);
1084*0d6140beSAndroid Build Coastguard Worker return -1;
1085*0d6140beSAndroid Build Coastguard Worker }
1086*0d6140beSAndroid Build Coastguard Worker
1087*0d6140beSAndroid Build Coastguard Worker free(region.name);
1088*0d6140beSAndroid Build Coastguard Worker }
1089*0d6140beSAndroid Build Coastguard Worker
1090*0d6140beSAndroid Build Coastguard Worker return 0;
1091*0d6140beSAndroid Build Coastguard Worker }
1092*0d6140beSAndroid Build Coastguard Worker
1093*0d6140beSAndroid Build Coastguard Worker typedef int (probe_func_t)(struct flashctx *flash);
1094*0d6140beSAndroid Build Coastguard Worker
lookup_probe_func_ptr(const struct flashchip * chip)1095*0d6140beSAndroid Build Coastguard Worker static probe_func_t *lookup_probe_func_ptr(const struct flashchip *chip)
1096*0d6140beSAndroid Build Coastguard Worker {
1097*0d6140beSAndroid Build Coastguard Worker switch (chip->probe) {
1098*0d6140beSAndroid Build Coastguard Worker case PROBE_JEDEC: return &probe_jedec;
1099*0d6140beSAndroid Build Coastguard Worker case PROBE_JEDEC_29GL: return &probe_jedec_29gl;
1100*0d6140beSAndroid Build Coastguard Worker case PROBE_OPAQUE: return &probe_opaque;
1101*0d6140beSAndroid Build Coastguard Worker case PROBE_EDI_KB9012: return &edi_probe_kb9012;
1102*0d6140beSAndroid Build Coastguard Worker case PROBE_AT82802AB: return &probe_82802ab;
1103*0d6140beSAndroid Build Coastguard Worker case PROBE_W29EE011: return &probe_w29ee011;
1104*0d6140beSAndroid Build Coastguard Worker case PROBE_EN29LV640B: return &probe_en29lv640b;
1105*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_AT25F: return &probe_spi_at25f;
1106*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_AT45DB: return &probe_spi_at45db;
1107*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_BIG_SPANSION: return &probe_spi_big_spansion;
1108*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_RDID: return &probe_spi_rdid;
1109*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_RDID4: return &probe_spi_rdid4;
1110*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_REMS: return &probe_spi_rems;
1111*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_RES1: return &probe_spi_res1;
1112*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_RES2: return &probe_spi_res2;
1113*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_SFDP: return &probe_spi_sfdp;
1114*0d6140beSAndroid Build Coastguard Worker case PROBE_SPI_ST95: return &probe_spi_st95;
1115*0d6140beSAndroid Build Coastguard Worker /* default: total function, 0 indicates no probe function set.
1116*0d6140beSAndroid Build Coastguard Worker * We explicitly do not want a default catch-all case in the switch
1117*0d6140beSAndroid Build Coastguard Worker * to ensure unhandled enum's are compiler warnings.
1118*0d6140beSAndroid Build Coastguard Worker */
1119*0d6140beSAndroid Build Coastguard Worker case NO_PROBE_FUNC: return NULL;
1120*0d6140beSAndroid Build Coastguard Worker };
1121*0d6140beSAndroid Build Coastguard Worker
1122*0d6140beSAndroid Build Coastguard Worker return NULL;
1123*0d6140beSAndroid Build Coastguard Worker }
1124*0d6140beSAndroid Build Coastguard Worker
probe_flash(struct registered_master * mst,int startchip,struct flashctx * flash,int force,const char * const chip_to_probe)1125*0d6140beSAndroid Build Coastguard Worker int probe_flash(struct registered_master *mst, int startchip, struct flashctx *flash, int force, const char *const chip_to_probe)
1126*0d6140beSAndroid Build Coastguard Worker {
1127*0d6140beSAndroid Build Coastguard Worker const struct flashchip *chip;
1128*0d6140beSAndroid Build Coastguard Worker enum chipbustype buses_common;
1129*0d6140beSAndroid Build Coastguard Worker char *tmp;
1130*0d6140beSAndroid Build Coastguard Worker
1131*0d6140beSAndroid Build Coastguard Worker for (chip = flashchips + startchip; chip && chip->name; chip++) {
1132*0d6140beSAndroid Build Coastguard Worker if (is_chipname_duplicate(chip))
1133*0d6140beSAndroid Build Coastguard Worker continue;
1134*0d6140beSAndroid Build Coastguard Worker
1135*0d6140beSAndroid Build Coastguard Worker if (chip_to_probe && strcmp(chip->name, chip_to_probe) != 0)
1136*0d6140beSAndroid Build Coastguard Worker continue;
1137*0d6140beSAndroid Build Coastguard Worker buses_common = mst->buses_supported & chip->bustype;
1138*0d6140beSAndroid Build Coastguard Worker if (!buses_common)
1139*0d6140beSAndroid Build Coastguard Worker continue;
1140*0d6140beSAndroid Build Coastguard Worker /* Only probe for SPI25 chips by default. */
1141*0d6140beSAndroid Build Coastguard Worker if (chip->bustype == BUS_SPI && !chip_to_probe && chip->spi_cmd_set != SPI25)
1142*0d6140beSAndroid Build Coastguard Worker continue;
1143*0d6140beSAndroid Build Coastguard Worker msg_gdbg("Probing for %s %s, %d kB: ", chip->vendor, chip->name, chip->total_size);
1144*0d6140beSAndroid Build Coastguard Worker probe_func_t *probe_func = lookup_probe_func_ptr(chip);
1145*0d6140beSAndroid Build Coastguard Worker if (!probe_func && !force) {
1146*0d6140beSAndroid Build Coastguard Worker msg_gdbg("failed! flashrom has no probe function for this flash chip.\n");
1147*0d6140beSAndroid Build Coastguard Worker continue;
1148*0d6140beSAndroid Build Coastguard Worker }
1149*0d6140beSAndroid Build Coastguard Worker
1150*0d6140beSAndroid Build Coastguard Worker /* Start filling in the dynamic data. */
1151*0d6140beSAndroid Build Coastguard Worker flash->chip = calloc(1, sizeof(*flash->chip));
1152*0d6140beSAndroid Build Coastguard Worker if (!flash->chip) {
1153*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory!\n");
1154*0d6140beSAndroid Build Coastguard Worker return -1;
1155*0d6140beSAndroid Build Coastguard Worker }
1156*0d6140beSAndroid Build Coastguard Worker *flash->chip = *chip;
1157*0d6140beSAndroid Build Coastguard Worker flash->mst = mst;
1158*0d6140beSAndroid Build Coastguard Worker
1159*0d6140beSAndroid Build Coastguard Worker if (map_flash(flash) != 0)
1160*0d6140beSAndroid Build Coastguard Worker goto notfound;
1161*0d6140beSAndroid Build Coastguard Worker
1162*0d6140beSAndroid Build Coastguard Worker /* We handle a forced match like a real match, we just avoid probing. Note that probe_flash()
1163*0d6140beSAndroid Build Coastguard Worker * is only called with force=1 after normal probing failed.
1164*0d6140beSAndroid Build Coastguard Worker */
1165*0d6140beSAndroid Build Coastguard Worker if (force)
1166*0d6140beSAndroid Build Coastguard Worker break;
1167*0d6140beSAndroid Build Coastguard Worker
1168*0d6140beSAndroid Build Coastguard Worker if (probe_func == &probe_w29ee011)
1169*0d6140beSAndroid Build Coastguard Worker if (!w29ee011_can_override(flash->chip->name, chip_to_probe))
1170*0d6140beSAndroid Build Coastguard Worker goto notfound;
1171*0d6140beSAndroid Build Coastguard Worker
1172*0d6140beSAndroid Build Coastguard Worker if (probe_func(flash) != 1)
1173*0d6140beSAndroid Build Coastguard Worker goto notfound;
1174*0d6140beSAndroid Build Coastguard Worker
1175*0d6140beSAndroid Build Coastguard Worker /* If this is the first chip found, accept it.
1176*0d6140beSAndroid Build Coastguard Worker * If this is not the first chip found, accept it only if it is
1177*0d6140beSAndroid Build Coastguard Worker * a non-generic match. SFDP and CFI are generic matches.
1178*0d6140beSAndroid Build Coastguard Worker * startchip==0 means this call to probe_flash() is the first
1179*0d6140beSAndroid Build Coastguard Worker * one for this programmer interface (master) and thus no other chip has
1180*0d6140beSAndroid Build Coastguard Worker * been found on this interface.
1181*0d6140beSAndroid Build Coastguard Worker */
1182*0d6140beSAndroid Build Coastguard Worker if (startchip == 0 && flash->chip->model_id == SFDP_DEVICE_ID) {
1183*0d6140beSAndroid Build Coastguard Worker msg_cinfo("===\n"
1184*0d6140beSAndroid Build Coastguard Worker "SFDP has autodetected a flash chip which is "
1185*0d6140beSAndroid Build Coastguard Worker "not natively supported by flashrom yet.\n");
1186*0d6140beSAndroid Build Coastguard Worker if (count_usable_erasers(flash) == 0)
1187*0d6140beSAndroid Build Coastguard Worker msg_cinfo("The standard operations read and "
1188*0d6140beSAndroid Build Coastguard Worker "verify should work, but to support "
1189*0d6140beSAndroid Build Coastguard Worker "erase, write and all other "
1190*0d6140beSAndroid Build Coastguard Worker "possible features");
1191*0d6140beSAndroid Build Coastguard Worker else
1192*0d6140beSAndroid Build Coastguard Worker msg_cinfo("All standard operations (read, "
1193*0d6140beSAndroid Build Coastguard Worker "verify, erase and write) should "
1194*0d6140beSAndroid Build Coastguard Worker "work, but to support all possible "
1195*0d6140beSAndroid Build Coastguard Worker "features");
1196*0d6140beSAndroid Build Coastguard Worker
1197*0d6140beSAndroid Build Coastguard Worker msg_cinfo(" we need to add them manually.\n"
1198*0d6140beSAndroid Build Coastguard Worker "You can help us by mailing us the output of the following command to "
1199*0d6140beSAndroid Build Coastguard Worker "[email protected]:\n"
1200*0d6140beSAndroid Build Coastguard Worker "'flashrom -VV [plus the -p/--programmer parameter]'\n"
1201*0d6140beSAndroid Build Coastguard Worker "Thanks for your help!\n"
1202*0d6140beSAndroid Build Coastguard Worker "===\n");
1203*0d6140beSAndroid Build Coastguard Worker }
1204*0d6140beSAndroid Build Coastguard Worker
1205*0d6140beSAndroid Build Coastguard Worker /* First flash chip detected on this bus. */
1206*0d6140beSAndroid Build Coastguard Worker if (startchip == 0)
1207*0d6140beSAndroid Build Coastguard Worker break;
1208*0d6140beSAndroid Build Coastguard Worker /* Not the first flash chip detected on this bus, but not a generic match either. */
1209*0d6140beSAndroid Build Coastguard Worker if ((flash->chip->model_id != GENERIC_DEVICE_ID) && (flash->chip->model_id != SFDP_DEVICE_ID))
1210*0d6140beSAndroid Build Coastguard Worker break;
1211*0d6140beSAndroid Build Coastguard Worker /* Not the first flash chip detected on this bus, and it's just a generic match. Ignore it. */
1212*0d6140beSAndroid Build Coastguard Worker notfound:
1213*0d6140beSAndroid Build Coastguard Worker unmap_flash(flash);
1214*0d6140beSAndroid Build Coastguard Worker free(flash->chip);
1215*0d6140beSAndroid Build Coastguard Worker flash->chip = NULL;
1216*0d6140beSAndroid Build Coastguard Worker }
1217*0d6140beSAndroid Build Coastguard Worker
1218*0d6140beSAndroid Build Coastguard Worker if (!flash->chip)
1219*0d6140beSAndroid Build Coastguard Worker return -1;
1220*0d6140beSAndroid Build Coastguard Worker
1221*0d6140beSAndroid Build Coastguard Worker if (init_default_layout(flash) < 0)
1222*0d6140beSAndroid Build Coastguard Worker return -1;
1223*0d6140beSAndroid Build Coastguard Worker
1224*0d6140beSAndroid Build Coastguard Worker tmp = flashbuses_to_text(flash->chip->bustype);
1225*0d6140beSAndroid Build Coastguard Worker msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) ", force ? "Assuming" : "Found",
1226*0d6140beSAndroid Build Coastguard Worker flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp ? tmp : "?");
1227*0d6140beSAndroid Build Coastguard Worker free(tmp);
1228*0d6140beSAndroid Build Coastguard Worker if (master_uses_physmap(mst))
1229*0d6140beSAndroid Build Coastguard Worker msg_cinfo("mapped at physical address 0x%0*" PRIxPTR ".\n",
1230*0d6140beSAndroid Build Coastguard Worker PRIxPTR_WIDTH, flash->physical_memory);
1231*0d6140beSAndroid Build Coastguard Worker else
1232*0d6140beSAndroid Build Coastguard Worker msg_cinfo("on %s.\n", programmer->name);
1233*0d6140beSAndroid Build Coastguard Worker
1234*0d6140beSAndroid Build Coastguard Worker /* Flash registers may more likely not be mapped if the chip was forced.
1235*0d6140beSAndroid Build Coastguard Worker * Lock info may be stored in registers, so avoid lock info printing. */
1236*0d6140beSAndroid Build Coastguard Worker if (!force) {
1237*0d6140beSAndroid Build Coastguard Worker printlockfunc_t *printlock = lookup_printlock_func_ptr(flash);
1238*0d6140beSAndroid Build Coastguard Worker if (printlock)
1239*0d6140beSAndroid Build Coastguard Worker printlock(flash);
1240*0d6140beSAndroid Build Coastguard Worker }
1241*0d6140beSAndroid Build Coastguard Worker
1242*0d6140beSAndroid Build Coastguard Worker /* Get out of the way for later runs. */
1243*0d6140beSAndroid Build Coastguard Worker unmap_flash(flash);
1244*0d6140beSAndroid Build Coastguard Worker
1245*0d6140beSAndroid Build Coastguard Worker /* Return position of matching chip. */
1246*0d6140beSAndroid Build Coastguard Worker return chip - flashchips;
1247*0d6140beSAndroid Build Coastguard Worker }
1248*0d6140beSAndroid Build Coastguard Worker
1249*0d6140beSAndroid Build Coastguard Worker /*
1250*0d6140beSAndroid Build Coastguard Worker * Gets the lowest erase granularity; it is used when
1251*0d6140beSAndroid Build Coastguard Worker * deciding if the layout map needs to be adjusted such that erase boundaries
1252*0d6140beSAndroid Build Coastguard Worker * match this granularity. Returns -1 if unsuccessful.
1253*0d6140beSAndroid Build Coastguard Worker */
get_required_erase_size(struct flashctx * flash)1254*0d6140beSAndroid Build Coastguard Worker static int get_required_erase_size(struct flashctx *flash)
1255*0d6140beSAndroid Build Coastguard Worker {
1256*0d6140beSAndroid Build Coastguard Worker int i, erase_size_found = 0;
1257*0d6140beSAndroid Build Coastguard Worker unsigned int required_erase_size;
1258*0d6140beSAndroid Build Coastguard Worker
1259*0d6140beSAndroid Build Coastguard Worker /*
1260*0d6140beSAndroid Build Coastguard Worker * Find eraseable block size for read alignment.
1261*0d6140beSAndroid Build Coastguard Worker * FIXME: This assumes the smallest block erase size is useable
1262*0d6140beSAndroid Build Coastguard Worker * by erase_and_write_flash().
1263*0d6140beSAndroid Build Coastguard Worker */
1264*0d6140beSAndroid Build Coastguard Worker required_erase_size = ~0;
1265*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
1266*0d6140beSAndroid Build Coastguard Worker struct block_eraser eraser = flash->chip->block_erasers[i];
1267*0d6140beSAndroid Build Coastguard Worker int j;
1268*0d6140beSAndroid Build Coastguard Worker
1269*0d6140beSAndroid Build Coastguard Worker for (j = 0; j < NUM_ERASEREGIONS; j++) {
1270*0d6140beSAndroid Build Coastguard Worker unsigned int size = eraser.eraseblocks[j].size;
1271*0d6140beSAndroid Build Coastguard Worker
1272*0d6140beSAndroid Build Coastguard Worker if (size && (size < required_erase_size)) {
1273*0d6140beSAndroid Build Coastguard Worker required_erase_size = size;
1274*0d6140beSAndroid Build Coastguard Worker erase_size_found = 1;
1275*0d6140beSAndroid Build Coastguard Worker }
1276*0d6140beSAndroid Build Coastguard Worker }
1277*0d6140beSAndroid Build Coastguard Worker }
1278*0d6140beSAndroid Build Coastguard Worker
1279*0d6140beSAndroid Build Coastguard Worker /* likely an error in flashchips[] */
1280*0d6140beSAndroid Build Coastguard Worker if (!erase_size_found) {
1281*0d6140beSAndroid Build Coastguard Worker msg_cerr("%s: No usable erase size found.\n", __func__);
1282*0d6140beSAndroid Build Coastguard Worker return -1;
1283*0d6140beSAndroid Build Coastguard Worker }
1284*0d6140beSAndroid Build Coastguard Worker
1285*0d6140beSAndroid Build Coastguard Worker return required_erase_size;
1286*0d6140beSAndroid Build Coastguard Worker }
1287*0d6140beSAndroid Build Coastguard Worker
round_to_erasable_block_boundary(const int required_erase_size,const struct romentry * entry,chipoff_t * rounded_start,chipsize_t * rounded_len)1288*0d6140beSAndroid Build Coastguard Worker static int round_to_erasable_block_boundary(const int required_erase_size,
1289*0d6140beSAndroid Build Coastguard Worker const struct romentry *entry,
1290*0d6140beSAndroid Build Coastguard Worker chipoff_t *rounded_start,
1291*0d6140beSAndroid Build Coastguard Worker chipsize_t* rounded_len) {
1292*0d6140beSAndroid Build Coastguard Worker unsigned int start_align, len_align;
1293*0d6140beSAndroid Build Coastguard Worker const struct flash_region *region = &entry->region;
1294*0d6140beSAndroid Build Coastguard Worker
1295*0d6140beSAndroid Build Coastguard Worker if (required_erase_size < 0)
1296*0d6140beSAndroid Build Coastguard Worker return 1;
1297*0d6140beSAndroid Build Coastguard Worker
1298*0d6140beSAndroid Build Coastguard Worker /* round down to nearest eraseable block boundary */
1299*0d6140beSAndroid Build Coastguard Worker start_align = region->start % required_erase_size;
1300*0d6140beSAndroid Build Coastguard Worker *rounded_start = region->start - start_align;
1301*0d6140beSAndroid Build Coastguard Worker
1302*0d6140beSAndroid Build Coastguard Worker /* round up to nearest eraseable block boundary */
1303*0d6140beSAndroid Build Coastguard Worker *rounded_len = region->end - *rounded_start + 1;
1304*0d6140beSAndroid Build Coastguard Worker len_align = *rounded_len % required_erase_size;
1305*0d6140beSAndroid Build Coastguard Worker if (len_align)
1306*0d6140beSAndroid Build Coastguard Worker *rounded_len = *rounded_len + required_erase_size - len_align;
1307*0d6140beSAndroid Build Coastguard Worker
1308*0d6140beSAndroid Build Coastguard Worker if (start_align || len_align) {
1309*0d6140beSAndroid Build Coastguard Worker msg_gdbg("\n%s: Re-aligned partial read due to eraseable "
1310*0d6140beSAndroid Build Coastguard Worker "block size requirement:\n\tstart: 0x%06x, "
1311*0d6140beSAndroid Build Coastguard Worker "len: 0x%06x, aligned start: 0x%06x, len: 0x%06x\n",
1312*0d6140beSAndroid Build Coastguard Worker __func__, region->start, region->end - region->start + 1,
1313*0d6140beSAndroid Build Coastguard Worker *rounded_start, *rounded_len);
1314*0d6140beSAndroid Build Coastguard Worker }
1315*0d6140beSAndroid Build Coastguard Worker
1316*0d6140beSAndroid Build Coastguard Worker return 0;
1317*0d6140beSAndroid Build Coastguard Worker }
1318*0d6140beSAndroid Build Coastguard Worker
1319*0d6140beSAndroid Build Coastguard Worker /**
1320*0d6140beSAndroid Build Coastguard Worker * @brief Reads the included layout regions into a buffer.
1321*0d6140beSAndroid Build Coastguard Worker *
1322*0d6140beSAndroid Build Coastguard Worker * If there is no layout set in the given flash context, the whole chip will
1323*0d6140beSAndroid Build Coastguard Worker * be read.
1324*0d6140beSAndroid Build Coastguard Worker *
1325*0d6140beSAndroid Build Coastguard Worker * @param flashctx Flash context to be used.
1326*0d6140beSAndroid Build Coastguard Worker * @param buffer Buffer of full chip size to read into.
1327*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
1328*0d6140beSAndroid Build Coastguard Worker * 1 if any read fails.
1329*0d6140beSAndroid Build Coastguard Worker */
read_by_layout(struct flashctx * const flashctx,uint8_t * const buffer,bool align_to_erasable_block_boundary)1330*0d6140beSAndroid Build Coastguard Worker static int read_by_layout(struct flashctx *const flashctx, uint8_t *const buffer,
1331*0d6140beSAndroid Build Coastguard Worker bool align_to_erasable_block_boundary)
1332*0d6140beSAndroid Build Coastguard Worker {
1333*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const layout = get_layout(flashctx);
1334*0d6140beSAndroid Build Coastguard Worker const struct romentry *entry = NULL;
1335*0d6140beSAndroid Build Coastguard Worker int required_erase_size = get_required_erase_size(flashctx);
1336*0d6140beSAndroid Build Coastguard Worker
1337*0d6140beSAndroid Build Coastguard Worker while ((entry = layout_next_included(layout, entry))) {
1338*0d6140beSAndroid Build Coastguard Worker const struct flash_region *region = &entry->region;
1339*0d6140beSAndroid Build Coastguard Worker chipoff_t region_start = region->start;
1340*0d6140beSAndroid Build Coastguard Worker chipsize_t region_len = region->end - region->start + 1;
1341*0d6140beSAndroid Build Coastguard Worker
1342*0d6140beSAndroid Build Coastguard Worker if (align_to_erasable_block_boundary &&
1343*0d6140beSAndroid Build Coastguard Worker round_to_erasable_block_boundary(required_erase_size, entry,
1344*0d6140beSAndroid Build Coastguard Worker ®ion_start, ®ion_len))
1345*0d6140beSAndroid Build Coastguard Worker return 1;
1346*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, buffer + region_start, region_start, region_len))
1347*0d6140beSAndroid Build Coastguard Worker return 1;
1348*0d6140beSAndroid Build Coastguard Worker }
1349*0d6140beSAndroid Build Coastguard Worker return 0;
1350*0d6140beSAndroid Build Coastguard Worker }
1351*0d6140beSAndroid Build Coastguard Worker
1352*0d6140beSAndroid Build Coastguard Worker /* Even if an error is found, the function will keep going and check the rest. */
selfcheck_eraseblocks(const struct flashchip * chip)1353*0d6140beSAndroid Build Coastguard Worker static int selfcheck_eraseblocks(const struct flashchip *chip)
1354*0d6140beSAndroid Build Coastguard Worker {
1355*0d6140beSAndroid Build Coastguard Worker int i, j, k;
1356*0d6140beSAndroid Build Coastguard Worker int ret = 0;
1357*0d6140beSAndroid Build Coastguard Worker unsigned int prev_eraseblock_count = chip->total_size * 1024;
1358*0d6140beSAndroid Build Coastguard Worker
1359*0d6140beSAndroid Build Coastguard Worker for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
1360*0d6140beSAndroid Build Coastguard Worker unsigned int done = 0;
1361*0d6140beSAndroid Build Coastguard Worker struct block_eraser eraser = chip->block_erasers[k];
1362*0d6140beSAndroid Build Coastguard Worker unsigned int curr_eraseblock_count = 0;
1363*0d6140beSAndroid Build Coastguard Worker
1364*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < NUM_ERASEREGIONS; i++) {
1365*0d6140beSAndroid Build Coastguard Worker /* Blocks with zero size are bugs in flashchips.c. */
1366*0d6140beSAndroid Build Coastguard Worker if (eraser.eraseblocks[i].count &&
1367*0d6140beSAndroid Build Coastguard Worker !eraser.eraseblocks[i].size) {
1368*0d6140beSAndroid Build Coastguard Worker msg_gerr("ERROR: Flash chip %s erase function "
1369*0d6140beSAndroid Build Coastguard Worker "%i region %i has size 0. Please report"
1370*0d6140beSAndroid Build Coastguard Worker " a bug at [email protected]\n",
1371*0d6140beSAndroid Build Coastguard Worker chip->name, k, i);
1372*0d6140beSAndroid Build Coastguard Worker ret = 1;
1373*0d6140beSAndroid Build Coastguard Worker }
1374*0d6140beSAndroid Build Coastguard Worker /* Blocks with zero count are bugs in flashchips.c. */
1375*0d6140beSAndroid Build Coastguard Worker if (!eraser.eraseblocks[i].count &&
1376*0d6140beSAndroid Build Coastguard Worker eraser.eraseblocks[i].size) {
1377*0d6140beSAndroid Build Coastguard Worker msg_gerr("ERROR: Flash chip %s erase function "
1378*0d6140beSAndroid Build Coastguard Worker "%i region %i has count 0. Please report"
1379*0d6140beSAndroid Build Coastguard Worker " a bug at [email protected]\n",
1380*0d6140beSAndroid Build Coastguard Worker chip->name, k, i);
1381*0d6140beSAndroid Build Coastguard Worker ret = 1;
1382*0d6140beSAndroid Build Coastguard Worker }
1383*0d6140beSAndroid Build Coastguard Worker done += eraser.eraseblocks[i].count *
1384*0d6140beSAndroid Build Coastguard Worker eraser.eraseblocks[i].size;
1385*0d6140beSAndroid Build Coastguard Worker curr_eraseblock_count += eraser.eraseblocks[i].count;
1386*0d6140beSAndroid Build Coastguard Worker }
1387*0d6140beSAndroid Build Coastguard Worker /* Empty eraseblock definition with erase function. */
1388*0d6140beSAndroid Build Coastguard Worker if (!done && eraser.block_erase)
1389*0d6140beSAndroid Build Coastguard Worker msg_gspew("Strange: Empty eraseblock definition with "
1390*0d6140beSAndroid Build Coastguard Worker "non-empty erase function. Not an error.\n");
1391*0d6140beSAndroid Build Coastguard Worker if (!done)
1392*0d6140beSAndroid Build Coastguard Worker continue;
1393*0d6140beSAndroid Build Coastguard Worker if (done != chip->total_size * 1024) {
1394*0d6140beSAndroid Build Coastguard Worker msg_gerr("ERROR: Flash chip %s erase function %i "
1395*0d6140beSAndroid Build Coastguard Worker "region walking resulted in 0x%06x bytes total,"
1396*0d6140beSAndroid Build Coastguard Worker " expected 0x%06x bytes. Please report a bug at"
1397*0d6140beSAndroid Build Coastguard Worker " [email protected]\n", chip->name, k,
1398*0d6140beSAndroid Build Coastguard Worker done, chip->total_size * 1024);
1399*0d6140beSAndroid Build Coastguard Worker ret = 1;
1400*0d6140beSAndroid Build Coastguard Worker }
1401*0d6140beSAndroid Build Coastguard Worker if (!eraser.block_erase)
1402*0d6140beSAndroid Build Coastguard Worker continue;
1403*0d6140beSAndroid Build Coastguard Worker /* Check if there are identical erase functions for different
1404*0d6140beSAndroid Build Coastguard Worker * layouts. That would imply "magic" erase functions. The
1405*0d6140beSAndroid Build Coastguard Worker * easiest way to check this is with function pointers.
1406*0d6140beSAndroid Build Coastguard Worker */
1407*0d6140beSAndroid Build Coastguard Worker for (j = k + 1; j < NUM_ERASEFUNCTIONS; j++) {
1408*0d6140beSAndroid Build Coastguard Worker if (eraser.block_erase ==
1409*0d6140beSAndroid Build Coastguard Worker chip->block_erasers[j].block_erase) {
1410*0d6140beSAndroid Build Coastguard Worker msg_gerr("ERROR: Flash chip %s erase function "
1411*0d6140beSAndroid Build Coastguard Worker "%i and %i are identical. Please report"
1412*0d6140beSAndroid Build Coastguard Worker " a bug at [email protected]\n",
1413*0d6140beSAndroid Build Coastguard Worker chip->name, k, j);
1414*0d6140beSAndroid Build Coastguard Worker ret = 1;
1415*0d6140beSAndroid Build Coastguard Worker }
1416*0d6140beSAndroid Build Coastguard Worker }
1417*0d6140beSAndroid Build Coastguard Worker if (curr_eraseblock_count > prev_eraseblock_count) {
1418*0d6140beSAndroid Build Coastguard Worker msg_gerr("ERROR: Flash chip %s erase function %i is not "
1419*0d6140beSAndroid Build Coastguard Worker "in order. Please report a bug at [email protected]\n",
1420*0d6140beSAndroid Build Coastguard Worker chip->name, k);
1421*0d6140beSAndroid Build Coastguard Worker ret = 1;
1422*0d6140beSAndroid Build Coastguard Worker }
1423*0d6140beSAndroid Build Coastguard Worker prev_eraseblock_count = curr_eraseblock_count;
1424*0d6140beSAndroid Build Coastguard Worker }
1425*0d6140beSAndroid Build Coastguard Worker return ret;
1426*0d6140beSAndroid Build Coastguard Worker }
1427*0d6140beSAndroid Build Coastguard Worker
1428*0d6140beSAndroid Build Coastguard Worker typedef int (*erasefn_t)(struct flashctx *, unsigned int addr, unsigned int len);
1429*0d6140beSAndroid Build Coastguard Worker /**
1430*0d6140beSAndroid Build Coastguard Worker * @private
1431*0d6140beSAndroid Build Coastguard Worker *
1432*0d6140beSAndroid Build Coastguard Worker * For read-erase-write, `curcontents` and `newcontents` shall point
1433*0d6140beSAndroid Build Coastguard Worker * to buffers of the chip's size. Both are supposed to be prefilled
1434*0d6140beSAndroid Build Coastguard Worker * with at least the included layout regions of the current flash
1435*0d6140beSAndroid Build Coastguard Worker * contents (`curcontents`) and the data to be written to the flash
1436*0d6140beSAndroid Build Coastguard Worker * (`newcontents`).
1437*0d6140beSAndroid Build Coastguard Worker *
1438*0d6140beSAndroid Build Coastguard Worker * For erase, `curcontents` and `newcontents` shall be NULL-pointers.
1439*0d6140beSAndroid Build Coastguard Worker *
1440*0d6140beSAndroid Build Coastguard Worker * The `chipoff_t` values are used internally by `walk_by_layout()`.
1441*0d6140beSAndroid Build Coastguard Worker */
1442*0d6140beSAndroid Build Coastguard Worker struct walk_info {
1443*0d6140beSAndroid Build Coastguard Worker uint8_t *curcontents;
1444*0d6140beSAndroid Build Coastguard Worker const uint8_t *newcontents;
1445*0d6140beSAndroid Build Coastguard Worker chipoff_t region_start;
1446*0d6140beSAndroid Build Coastguard Worker chipoff_t region_end;
1447*0d6140beSAndroid Build Coastguard Worker chipoff_t erase_start;
1448*0d6140beSAndroid Build Coastguard Worker chipoff_t erase_end;
1449*0d6140beSAndroid Build Coastguard Worker };
1450*0d6140beSAndroid Build Coastguard Worker /* returns 0 on success, 1 to retry with another erase function, 2 for immediate abort */
1451*0d6140beSAndroid Build Coastguard Worker typedef int (*per_blockfn_t)(struct flashctx *, const struct walk_info *, erasefn_t, bool *);
1452*0d6140beSAndroid Build Coastguard Worker
walk_eraseblocks(struct flashctx * const flashctx,struct walk_info * const info,const size_t erasefunction,const per_blockfn_t per_blockfn,bool * all_skipped)1453*0d6140beSAndroid Build Coastguard Worker static int walk_eraseblocks(struct flashctx *const flashctx,
1454*0d6140beSAndroid Build Coastguard Worker struct walk_info *const info,
1455*0d6140beSAndroid Build Coastguard Worker const size_t erasefunction, const per_blockfn_t per_blockfn,
1456*0d6140beSAndroid Build Coastguard Worker bool *all_skipped)
1457*0d6140beSAndroid Build Coastguard Worker {
1458*0d6140beSAndroid Build Coastguard Worker int ret;
1459*0d6140beSAndroid Build Coastguard Worker size_t i, j;
1460*0d6140beSAndroid Build Coastguard Worker bool first = true;
1461*0d6140beSAndroid Build Coastguard Worker struct block_eraser *const eraser = &flashctx->chip->block_erasers[erasefunction];
1462*0d6140beSAndroid Build Coastguard Worker
1463*0d6140beSAndroid Build Coastguard Worker info->erase_start = 0;
1464*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < NUM_ERASEREGIONS; ++i) {
1465*0d6140beSAndroid Build Coastguard Worker /* count==0 for all automatically initialized array
1466*0d6140beSAndroid Build Coastguard Worker members so the loop below won't be executed for them. */
1467*0d6140beSAndroid Build Coastguard Worker for (j = 0; j < eraser->eraseblocks[i].count; ++j, info->erase_start = info->erase_end + 1) {
1468*0d6140beSAndroid Build Coastguard Worker info->erase_end = info->erase_start + eraser->eraseblocks[i].size - 1;
1469*0d6140beSAndroid Build Coastguard Worker
1470*0d6140beSAndroid Build Coastguard Worker /* Skip any eraseblock that is completely outside the current region. */
1471*0d6140beSAndroid Build Coastguard Worker if (info->erase_end < info->region_start)
1472*0d6140beSAndroid Build Coastguard Worker continue;
1473*0d6140beSAndroid Build Coastguard Worker if (info->region_end < info->erase_start)
1474*0d6140beSAndroid Build Coastguard Worker break;
1475*0d6140beSAndroid Build Coastguard Worker
1476*0d6140beSAndroid Build Coastguard Worker /* Print this for every block except the first one. */
1477*0d6140beSAndroid Build Coastguard Worker if (first)
1478*0d6140beSAndroid Build Coastguard Worker first = false;
1479*0d6140beSAndroid Build Coastguard Worker else
1480*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", ");
1481*0d6140beSAndroid Build Coastguard Worker msg_cdbg("0x%06"PRIx32"-0x%06"PRIx32":", info->erase_start, info->erase_end);
1482*0d6140beSAndroid Build Coastguard Worker
1483*0d6140beSAndroid Build Coastguard Worker erasefunc_t *erase_func = lookup_erase_func_ptr(eraser);
1484*0d6140beSAndroid Build Coastguard Worker ret = per_blockfn(flashctx, info, erase_func, all_skipped);
1485*0d6140beSAndroid Build Coastguard Worker if (ret)
1486*0d6140beSAndroid Build Coastguard Worker return ret;
1487*0d6140beSAndroid Build Coastguard Worker }
1488*0d6140beSAndroid Build Coastguard Worker if (info->region_end < info->erase_start)
1489*0d6140beSAndroid Build Coastguard Worker break;
1490*0d6140beSAndroid Build Coastguard Worker }
1491*0d6140beSAndroid Build Coastguard Worker msg_cdbg("\n");
1492*0d6140beSAndroid Build Coastguard Worker return 0;
1493*0d6140beSAndroid Build Coastguard Worker }
1494*0d6140beSAndroid Build Coastguard Worker
walk_by_layout(struct flashctx * const flashctx,struct walk_info * const info,const per_blockfn_t per_blockfn,bool * all_skipped)1495*0d6140beSAndroid Build Coastguard Worker static int walk_by_layout(struct flashctx *const flashctx, struct walk_info *const info,
1496*0d6140beSAndroid Build Coastguard Worker const per_blockfn_t per_blockfn, bool *all_skipped)
1497*0d6140beSAndroid Build Coastguard Worker {
1498*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const layout = get_layout(flashctx);
1499*0d6140beSAndroid Build Coastguard Worker const struct romentry *entry = NULL;
1500*0d6140beSAndroid Build Coastguard Worker
1501*0d6140beSAndroid Build Coastguard Worker *all_skipped = true;
1502*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Erasing and writing flash chip... ");
1503*0d6140beSAndroid Build Coastguard Worker
1504*0d6140beSAndroid Build Coastguard Worker while ((entry = layout_next_included(layout, entry))) {
1505*0d6140beSAndroid Build Coastguard Worker const struct flash_region *region = &entry->region;
1506*0d6140beSAndroid Build Coastguard Worker info->region_start = region->start;
1507*0d6140beSAndroid Build Coastguard Worker info->region_end = region->end;
1508*0d6140beSAndroid Build Coastguard Worker
1509*0d6140beSAndroid Build Coastguard Worker size_t j;
1510*0d6140beSAndroid Build Coastguard Worker int error = 1; /* retry as long as it's 1 */
1511*0d6140beSAndroid Build Coastguard Worker for (j = 0; j < NUM_ERASEFUNCTIONS; ++j) {
1512*0d6140beSAndroid Build Coastguard Worker if (j != 0)
1513*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Looking for another erase function.\n");
1514*0d6140beSAndroid Build Coastguard Worker msg_cdbg("Trying erase function %zi... ", j);
1515*0d6140beSAndroid Build Coastguard Worker if (check_block_eraser(flashctx, j, 1))
1516*0d6140beSAndroid Build Coastguard Worker continue;
1517*0d6140beSAndroid Build Coastguard Worker
1518*0d6140beSAndroid Build Coastguard Worker error = walk_eraseblocks(flashctx, info, j, per_blockfn, all_skipped);
1519*0d6140beSAndroid Build Coastguard Worker if (error != 1)
1520*0d6140beSAndroid Build Coastguard Worker break;
1521*0d6140beSAndroid Build Coastguard Worker
1522*0d6140beSAndroid Build Coastguard Worker if (info->curcontents) {
1523*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Reading current flash chip contents... ");
1524*0d6140beSAndroid Build Coastguard Worker if (read_by_layout(flashctx, info->curcontents, false)) {
1525*0d6140beSAndroid Build Coastguard Worker /* Now we are truly screwed. Read failed as well. */
1526*0d6140beSAndroid Build Coastguard Worker msg_cerr("Can't read anymore! Aborting.\n");
1527*0d6140beSAndroid Build Coastguard Worker /* We have no idea about the flash chip contents, so
1528*0d6140beSAndroid Build Coastguard Worker retrying with another erase function is pointless. */
1529*0d6140beSAndroid Build Coastguard Worker error = 2;
1530*0d6140beSAndroid Build Coastguard Worker break;
1531*0d6140beSAndroid Build Coastguard Worker }
1532*0d6140beSAndroid Build Coastguard Worker msg_cinfo("done. ");
1533*0d6140beSAndroid Build Coastguard Worker }
1534*0d6140beSAndroid Build Coastguard Worker }
1535*0d6140beSAndroid Build Coastguard Worker if (error == 1)
1536*0d6140beSAndroid Build Coastguard Worker msg_cinfo("No usable erase functions left.\n");
1537*0d6140beSAndroid Build Coastguard Worker if (error) {
1538*0d6140beSAndroid Build Coastguard Worker msg_cerr("FAILED!\n");
1539*0d6140beSAndroid Build Coastguard Worker return 1;
1540*0d6140beSAndroid Build Coastguard Worker }
1541*0d6140beSAndroid Build Coastguard Worker }
1542*0d6140beSAndroid Build Coastguard Worker if (*all_skipped)
1543*0d6140beSAndroid Build Coastguard Worker msg_cinfo("\nWarning: Chip content is identical to the requested image.\n");
1544*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Erase/write done.\n");
1545*0d6140beSAndroid Build Coastguard Worker return 0;
1546*0d6140beSAndroid Build Coastguard Worker }
1547*0d6140beSAndroid Build Coastguard Worker
erase_block(struct flashctx * const flashctx,const struct walk_info * const info,const erasefn_t erasefn,bool * all_skipped)1548*0d6140beSAndroid Build Coastguard Worker static int erase_block(struct flashctx *const flashctx,
1549*0d6140beSAndroid Build Coastguard Worker const struct walk_info *const info, const erasefn_t erasefn,
1550*0d6140beSAndroid Build Coastguard Worker bool *all_skipped)
1551*0d6140beSAndroid Build Coastguard Worker {
1552*0d6140beSAndroid Build Coastguard Worker const unsigned int erase_len = info->erase_end + 1 - info->erase_start;
1553*0d6140beSAndroid Build Coastguard Worker const bool region_unaligned = info->region_start > info->erase_start ||
1554*0d6140beSAndroid Build Coastguard Worker info->erase_end > info->region_end;
1555*0d6140beSAndroid Build Coastguard Worker uint8_t *backup_contents = NULL, *erased_contents = NULL;
1556*0d6140beSAndroid Build Coastguard Worker int ret = 2;
1557*0d6140beSAndroid Build Coastguard Worker
1558*0d6140beSAndroid Build Coastguard Worker /*
1559*0d6140beSAndroid Build Coastguard Worker * If the region is not erase-block aligned, merge current flash con-
1560*0d6140beSAndroid Build Coastguard Worker * tents into a new buffer `backup_contents`.
1561*0d6140beSAndroid Build Coastguard Worker */
1562*0d6140beSAndroid Build Coastguard Worker if (region_unaligned) {
1563*0d6140beSAndroid Build Coastguard Worker backup_contents = malloc(erase_len);
1564*0d6140beSAndroid Build Coastguard Worker erased_contents = malloc(erase_len);
1565*0d6140beSAndroid Build Coastguard Worker if (!backup_contents || !erased_contents) {
1566*0d6140beSAndroid Build Coastguard Worker msg_cerr("Out of memory!\n");
1567*0d6140beSAndroid Build Coastguard Worker ret = 1;
1568*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1569*0d6140beSAndroid Build Coastguard Worker }
1570*0d6140beSAndroid Build Coastguard Worker memset(backup_contents, ERASED_VALUE(flashctx), erase_len);
1571*0d6140beSAndroid Build Coastguard Worker memset(erased_contents, ERASED_VALUE(flashctx), erase_len);
1572*0d6140beSAndroid Build Coastguard Worker
1573*0d6140beSAndroid Build Coastguard Worker msg_cdbg("R");
1574*0d6140beSAndroid Build Coastguard Worker /* Merge data preceding the current region. */
1575*0d6140beSAndroid Build Coastguard Worker if (info->region_start > info->erase_start) {
1576*0d6140beSAndroid Build Coastguard Worker const chipoff_t start = info->erase_start;
1577*0d6140beSAndroid Build Coastguard Worker const chipsize_t len = info->region_start - info->erase_start;
1578*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, backup_contents, start, len)) {
1579*0d6140beSAndroid Build Coastguard Worker msg_cerr("Can't read! Aborting.\n");
1580*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1581*0d6140beSAndroid Build Coastguard Worker }
1582*0d6140beSAndroid Build Coastguard Worker }
1583*0d6140beSAndroid Build Coastguard Worker /* Merge data following the current region. */
1584*0d6140beSAndroid Build Coastguard Worker if (info->erase_end > info->region_end) {
1585*0d6140beSAndroid Build Coastguard Worker const chipoff_t start = info->region_end + 1;
1586*0d6140beSAndroid Build Coastguard Worker const chipoff_t rel_start = start - info->erase_start; /* within this erase block */
1587*0d6140beSAndroid Build Coastguard Worker const chipsize_t len = info->erase_end - info->region_end;
1588*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, backup_contents + rel_start, start, len)) {
1589*0d6140beSAndroid Build Coastguard Worker msg_cerr("Can't read! Aborting.\n");
1590*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1591*0d6140beSAndroid Build Coastguard Worker }
1592*0d6140beSAndroid Build Coastguard Worker }
1593*0d6140beSAndroid Build Coastguard Worker }
1594*0d6140beSAndroid Build Coastguard Worker
1595*0d6140beSAndroid Build Coastguard Worker ret = 1;
1596*0d6140beSAndroid Build Coastguard Worker *all_skipped = false;
1597*0d6140beSAndroid Build Coastguard Worker
1598*0d6140beSAndroid Build Coastguard Worker msg_cdbg("E");
1599*0d6140beSAndroid Build Coastguard Worker
1600*0d6140beSAndroid Build Coastguard Worker if (!flashctx->flags.skip_unwritable_regions) {
1601*0d6140beSAndroid Build Coastguard Worker if (check_for_unwritable_regions(flashctx, info->erase_start, erase_len))
1602*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1603*0d6140beSAndroid Build Coastguard Worker }
1604*0d6140beSAndroid Build Coastguard Worker
1605*0d6140beSAndroid Build Coastguard Worker unsigned int len;
1606*0d6140beSAndroid Build Coastguard Worker for (unsigned int addr = info->erase_start; addr < info->erase_start + erase_len; addr += len) {
1607*0d6140beSAndroid Build Coastguard Worker struct flash_region region;
1608*0d6140beSAndroid Build Coastguard Worker get_flash_region(flashctx, addr, ®ion);
1609*0d6140beSAndroid Build Coastguard Worker
1610*0d6140beSAndroid Build Coastguard Worker len = min(info->erase_start + erase_len, region.end) - addr;
1611*0d6140beSAndroid Build Coastguard Worker
1612*0d6140beSAndroid Build Coastguard Worker if (region.write_prot) {
1613*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: cannot erase inside %s region (%#08"PRIx32"..%#08"PRIx32"), skipping range (%#08x..%#08x).\n",
1614*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1, addr, addr + len - 1);
1615*0d6140beSAndroid Build Coastguard Worker free(region.name);
1616*0d6140beSAndroid Build Coastguard Worker continue;
1617*0d6140beSAndroid Build Coastguard Worker }
1618*0d6140beSAndroid Build Coastguard Worker
1619*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is writable, erasing range (%#08x..%#08x).\n",
1620*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1, addr, addr + len - 1);
1621*0d6140beSAndroid Build Coastguard Worker free(region.name);
1622*0d6140beSAndroid Build Coastguard Worker
1623*0d6140beSAndroid Build Coastguard Worker if (erasefn(flashctx, addr, len))
1624*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1625*0d6140beSAndroid Build Coastguard Worker if (check_erased_range(flashctx, addr, len)) {
1626*0d6140beSAndroid Build Coastguard Worker msg_cerr("ERASE FAILED!\n");
1627*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1628*0d6140beSAndroid Build Coastguard Worker }
1629*0d6140beSAndroid Build Coastguard Worker }
1630*0d6140beSAndroid Build Coastguard Worker
1631*0d6140beSAndroid Build Coastguard Worker
1632*0d6140beSAndroid Build Coastguard Worker if (region_unaligned) {
1633*0d6140beSAndroid Build Coastguard Worker unsigned int starthere = 0, lenhere = 0, writecount = 0;
1634*0d6140beSAndroid Build Coastguard Worker /* get_next_write() sets starthere to a new value after the call. */
1635*0d6140beSAndroid Build Coastguard Worker while ((lenhere = get_next_write(erased_contents + starthere, backup_contents + starthere,
1636*0d6140beSAndroid Build Coastguard Worker erase_len - starthere, &starthere, flashctx->chip->gran))) {
1637*0d6140beSAndroid Build Coastguard Worker if (!writecount++)
1638*0d6140beSAndroid Build Coastguard Worker msg_cdbg("W");
1639*0d6140beSAndroid Build Coastguard Worker /* Needs the partial write function signature. */
1640*0d6140beSAndroid Build Coastguard Worker if (write_flash(flashctx, backup_contents + starthere,
1641*0d6140beSAndroid Build Coastguard Worker info->erase_start + starthere, lenhere))
1642*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1643*0d6140beSAndroid Build Coastguard Worker starthere += lenhere;
1644*0d6140beSAndroid Build Coastguard Worker }
1645*0d6140beSAndroid Build Coastguard Worker }
1646*0d6140beSAndroid Build Coastguard Worker
1647*0d6140beSAndroid Build Coastguard Worker ret = 0;
1648*0d6140beSAndroid Build Coastguard Worker
1649*0d6140beSAndroid Build Coastguard Worker _free_ret:
1650*0d6140beSAndroid Build Coastguard Worker free(erased_contents);
1651*0d6140beSAndroid Build Coastguard Worker free(backup_contents);
1652*0d6140beSAndroid Build Coastguard Worker return ret;
1653*0d6140beSAndroid Build Coastguard Worker }
1654*0d6140beSAndroid Build Coastguard Worker
1655*0d6140beSAndroid Build Coastguard Worker /**
1656*0d6140beSAndroid Build Coastguard Worker * @brief Erases the included layout regions.
1657*0d6140beSAndroid Build Coastguard Worker *
1658*0d6140beSAndroid Build Coastguard Worker * If there is no layout set in the given flash context, the whole chip will
1659*0d6140beSAndroid Build Coastguard Worker * be erased.
1660*0d6140beSAndroid Build Coastguard Worker *
1661*0d6140beSAndroid Build Coastguard Worker * @param flashctx Flash context to be used.
1662*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
1663*0d6140beSAndroid Build Coastguard Worker * 1 if all available erase functions failed.
1664*0d6140beSAndroid Build Coastguard Worker */
erase_by_layout_legacy(struct flashctx * const flashctx)1665*0d6140beSAndroid Build Coastguard Worker static int erase_by_layout_legacy(struct flashctx *const flashctx)
1666*0d6140beSAndroid Build Coastguard Worker {
1667*0d6140beSAndroid Build Coastguard Worker struct walk_info info = { 0 };
1668*0d6140beSAndroid Build Coastguard Worker bool all_skipped = true;
1669*0d6140beSAndroid Build Coastguard Worker return walk_by_layout(flashctx, &info, &erase_block, &all_skipped);
1670*0d6140beSAndroid Build Coastguard Worker }
1671*0d6140beSAndroid Build Coastguard Worker
erase_by_layout_new(struct flashctx * const flashctx)1672*0d6140beSAndroid Build Coastguard Worker static int erase_by_layout_new(struct flashctx *const flashctx)
1673*0d6140beSAndroid Build Coastguard Worker {
1674*0d6140beSAndroid Build Coastguard Worker bool all_skipped = true;
1675*0d6140beSAndroid Build Coastguard Worker const uint32_t flash_size = flashctx->chip->total_size * 1024;
1676*0d6140beSAndroid Build Coastguard Worker uint8_t* curcontents = malloc(flash_size);
1677*0d6140beSAndroid Build Coastguard Worker uint8_t* newcontents = malloc(flash_size);
1678*0d6140beSAndroid Build Coastguard Worker struct erase_layout *erase_layout;
1679*0d6140beSAndroid Build Coastguard Worker create_erase_layout(flashctx, &erase_layout);
1680*0d6140beSAndroid Build Coastguard Worker int ret = 0;
1681*0d6140beSAndroid Build Coastguard Worker
1682*0d6140beSAndroid Build Coastguard Worker //erase layout creation failed
1683*0d6140beSAndroid Build Coastguard Worker if (!erase_layout) {
1684*0d6140beSAndroid Build Coastguard Worker ret = 1;
1685*0d6140beSAndroid Build Coastguard Worker goto _ret;
1686*0d6140beSAndroid Build Coastguard Worker }
1687*0d6140beSAndroid Build Coastguard Worker
1688*0d6140beSAndroid Build Coastguard Worker //not enough memory
1689*0d6140beSAndroid Build Coastguard Worker if (!curcontents || !newcontents) {
1690*0d6140beSAndroid Build Coastguard Worker ret = 1;
1691*0d6140beSAndroid Build Coastguard Worker goto _ret;
1692*0d6140beSAndroid Build Coastguard Worker }
1693*0d6140beSAndroid Build Coastguard Worker
1694*0d6140beSAndroid Build Coastguard Worker memset(curcontents, ~ERASED_VALUE(flashctx), flash_size);
1695*0d6140beSAndroid Build Coastguard Worker memset(newcontents, ERASED_VALUE(flashctx), flash_size);
1696*0d6140beSAndroid Build Coastguard Worker
1697*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const flash_layout = get_layout(flashctx);
1698*0d6140beSAndroid Build Coastguard Worker const struct romentry *entry = NULL;
1699*0d6140beSAndroid Build Coastguard Worker while ((entry = layout_next_included(flash_layout, entry))) {
1700*0d6140beSAndroid Build Coastguard Worker ret = erase_write(flashctx, entry->region.start, entry->region.end, curcontents, newcontents, erase_layout, &all_skipped);
1701*0d6140beSAndroid Build Coastguard Worker if (ret) {
1702*0d6140beSAndroid Build Coastguard Worker ret = 1;
1703*0d6140beSAndroid Build Coastguard Worker msg_cerr("Erase Failed");
1704*0d6140beSAndroid Build Coastguard Worker goto _ret;
1705*0d6140beSAndroid Build Coastguard Worker }
1706*0d6140beSAndroid Build Coastguard Worker }
1707*0d6140beSAndroid Build Coastguard Worker
1708*0d6140beSAndroid Build Coastguard Worker _ret:
1709*0d6140beSAndroid Build Coastguard Worker free(curcontents);
1710*0d6140beSAndroid Build Coastguard Worker free(newcontents);
1711*0d6140beSAndroid Build Coastguard Worker free_erase_layout(erase_layout, count_usable_erasers(flashctx));
1712*0d6140beSAndroid Build Coastguard Worker return ret;
1713*0d6140beSAndroid Build Coastguard Worker }
1714*0d6140beSAndroid Build Coastguard Worker
erase_by_layout(struct flashctx * const flashctx)1715*0d6140beSAndroid Build Coastguard Worker static int erase_by_layout(struct flashctx *const flashctx)
1716*0d6140beSAndroid Build Coastguard Worker {
1717*0d6140beSAndroid Build Coastguard Worker if (use_legacy_erase_path)
1718*0d6140beSAndroid Build Coastguard Worker return erase_by_layout_legacy(flashctx);
1719*0d6140beSAndroid Build Coastguard Worker return erase_by_layout_new(flashctx);
1720*0d6140beSAndroid Build Coastguard Worker }
1721*0d6140beSAndroid Build Coastguard Worker
read_erase_write_block(struct flashctx * const flashctx,const struct walk_info * const info,const erasefn_t erasefn,bool * all_skipped)1722*0d6140beSAndroid Build Coastguard Worker static int read_erase_write_block(struct flashctx *const flashctx,
1723*0d6140beSAndroid Build Coastguard Worker const struct walk_info *const info, const erasefn_t erasefn,
1724*0d6140beSAndroid Build Coastguard Worker bool *all_skipped)
1725*0d6140beSAndroid Build Coastguard Worker {
1726*0d6140beSAndroid Build Coastguard Worker const chipsize_t erase_len = info->erase_end + 1 - info->erase_start;
1727*0d6140beSAndroid Build Coastguard Worker const bool region_unaligned = info->region_start > info->erase_start ||
1728*0d6140beSAndroid Build Coastguard Worker info->erase_end > info->region_end;
1729*0d6140beSAndroid Build Coastguard Worker const uint8_t *newcontents = NULL;
1730*0d6140beSAndroid Build Coastguard Worker int ret = 2;
1731*0d6140beSAndroid Build Coastguard Worker
1732*0d6140beSAndroid Build Coastguard Worker /*
1733*0d6140beSAndroid Build Coastguard Worker * If the region is not erase-block aligned, merge current flash con-
1734*0d6140beSAndroid Build Coastguard Worker * tents into `info->curcontents` and a new buffer `newc`. The former
1735*0d6140beSAndroid Build Coastguard Worker * is necessary since we have no guarantee that the full erase block
1736*0d6140beSAndroid Build Coastguard Worker * was already read into `info->curcontents`. For the latter a new
1737*0d6140beSAndroid Build Coastguard Worker * buffer is used since `info->newcontents` might contain data for
1738*0d6140beSAndroid Build Coastguard Worker * other unaligned regions that touch this erase block too.
1739*0d6140beSAndroid Build Coastguard Worker */
1740*0d6140beSAndroid Build Coastguard Worker if (region_unaligned) {
1741*0d6140beSAndroid Build Coastguard Worker msg_cdbg("R");
1742*0d6140beSAndroid Build Coastguard Worker uint8_t *const newc = malloc(erase_len);
1743*0d6140beSAndroid Build Coastguard Worker if (!newc) {
1744*0d6140beSAndroid Build Coastguard Worker msg_cerr("Out of memory!\n");
1745*0d6140beSAndroid Build Coastguard Worker return 1;
1746*0d6140beSAndroid Build Coastguard Worker }
1747*0d6140beSAndroid Build Coastguard Worker memcpy(newc, info->newcontents + info->erase_start, erase_len);
1748*0d6140beSAndroid Build Coastguard Worker
1749*0d6140beSAndroid Build Coastguard Worker /* Merge data preceding the current region. */
1750*0d6140beSAndroid Build Coastguard Worker if (info->region_start > info->erase_start) {
1751*0d6140beSAndroid Build Coastguard Worker const chipoff_t start = info->erase_start;
1752*0d6140beSAndroid Build Coastguard Worker const chipsize_t len = info->region_start - info->erase_start;
1753*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, newc, start, len)) {
1754*0d6140beSAndroid Build Coastguard Worker msg_cerr("Can't read! Aborting.\n");
1755*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1756*0d6140beSAndroid Build Coastguard Worker }
1757*0d6140beSAndroid Build Coastguard Worker memcpy(info->curcontents + start, newc, len);
1758*0d6140beSAndroid Build Coastguard Worker }
1759*0d6140beSAndroid Build Coastguard Worker /* Merge data following the current region. */
1760*0d6140beSAndroid Build Coastguard Worker if (info->erase_end > info->region_end) {
1761*0d6140beSAndroid Build Coastguard Worker const chipoff_t start = info->region_end + 1;
1762*0d6140beSAndroid Build Coastguard Worker const chipoff_t rel_start = start - info->erase_start; /* within this erase block */
1763*0d6140beSAndroid Build Coastguard Worker const chipsize_t len = info->erase_end - info->region_end;
1764*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, newc + rel_start, start, len)) {
1765*0d6140beSAndroid Build Coastguard Worker msg_cerr("Can't read! Aborting.\n");
1766*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1767*0d6140beSAndroid Build Coastguard Worker }
1768*0d6140beSAndroid Build Coastguard Worker memcpy(info->curcontents + start, newc + rel_start, len);
1769*0d6140beSAndroid Build Coastguard Worker }
1770*0d6140beSAndroid Build Coastguard Worker
1771*0d6140beSAndroid Build Coastguard Worker newcontents = newc;
1772*0d6140beSAndroid Build Coastguard Worker } else {
1773*0d6140beSAndroid Build Coastguard Worker newcontents = info->newcontents + info->erase_start;
1774*0d6140beSAndroid Build Coastguard Worker }
1775*0d6140beSAndroid Build Coastguard Worker
1776*0d6140beSAndroid Build Coastguard Worker ret = 1;
1777*0d6140beSAndroid Build Coastguard Worker bool skipped = true;
1778*0d6140beSAndroid Build Coastguard Worker uint8_t *const curcontents = info->curcontents + info->erase_start;
1779*0d6140beSAndroid Build Coastguard Worker const uint8_t erased_value = ERASED_VALUE(flashctx);
1780*0d6140beSAndroid Build Coastguard Worker if (!(flashctx->chip->feature_bits & FEATURE_NO_ERASE) &&
1781*0d6140beSAndroid Build Coastguard Worker need_erase(curcontents, newcontents, erase_len, flashctx->chip->gran, erased_value)) {
1782*0d6140beSAndroid Build Coastguard Worker if (erase_block(flashctx, info, erasefn, all_skipped))
1783*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1784*0d6140beSAndroid Build Coastguard Worker /* Erase was successful. Adjust curcontents. */
1785*0d6140beSAndroid Build Coastguard Worker memset(curcontents, erased_value, erase_len);
1786*0d6140beSAndroid Build Coastguard Worker skipped = false;
1787*0d6140beSAndroid Build Coastguard Worker }
1788*0d6140beSAndroid Build Coastguard Worker
1789*0d6140beSAndroid Build Coastguard Worker unsigned int starthere = 0, lenhere = 0, writecount = 0;
1790*0d6140beSAndroid Build Coastguard Worker /* get_next_write() sets starthere to a new value after the call. */
1791*0d6140beSAndroid Build Coastguard Worker while ((lenhere = get_next_write(curcontents + starthere, newcontents + starthere,
1792*0d6140beSAndroid Build Coastguard Worker erase_len - starthere, &starthere, flashctx->chip->gran))) {
1793*0d6140beSAndroid Build Coastguard Worker if (!writecount++)
1794*0d6140beSAndroid Build Coastguard Worker msg_cdbg("W");
1795*0d6140beSAndroid Build Coastguard Worker /* Needs the partial write function signature. */
1796*0d6140beSAndroid Build Coastguard Worker if (write_flash(flashctx, newcontents + starthere,
1797*0d6140beSAndroid Build Coastguard Worker info->erase_start + starthere, lenhere))
1798*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
1799*0d6140beSAndroid Build Coastguard Worker starthere += lenhere;
1800*0d6140beSAndroid Build Coastguard Worker skipped = false;
1801*0d6140beSAndroid Build Coastguard Worker }
1802*0d6140beSAndroid Build Coastguard Worker if (skipped)
1803*0d6140beSAndroid Build Coastguard Worker msg_cdbg("S");
1804*0d6140beSAndroid Build Coastguard Worker else
1805*0d6140beSAndroid Build Coastguard Worker *all_skipped = false;
1806*0d6140beSAndroid Build Coastguard Worker
1807*0d6140beSAndroid Build Coastguard Worker /* Update curcontents, other regions with overlapping erase blocks
1808*0d6140beSAndroid Build Coastguard Worker might rely on this. */
1809*0d6140beSAndroid Build Coastguard Worker memcpy(curcontents, newcontents, erase_len);
1810*0d6140beSAndroid Build Coastguard Worker ret = 0;
1811*0d6140beSAndroid Build Coastguard Worker
1812*0d6140beSAndroid Build Coastguard Worker _free_ret:
1813*0d6140beSAndroid Build Coastguard Worker if (region_unaligned)
1814*0d6140beSAndroid Build Coastguard Worker free((void *)newcontents);
1815*0d6140beSAndroid Build Coastguard Worker return ret;
1816*0d6140beSAndroid Build Coastguard Worker }
1817*0d6140beSAndroid Build Coastguard Worker
1818*0d6140beSAndroid Build Coastguard Worker /**
1819*0d6140beSAndroid Build Coastguard Worker * @brief Writes the included layout regions from a given image.
1820*0d6140beSAndroid Build Coastguard Worker *
1821*0d6140beSAndroid Build Coastguard Worker * If there is no layout set in the given flash context, the whole image
1822*0d6140beSAndroid Build Coastguard Worker * will be written.
1823*0d6140beSAndroid Build Coastguard Worker *
1824*0d6140beSAndroid Build Coastguard Worker * @param flashctx Flash context to be used.
1825*0d6140beSAndroid Build Coastguard Worker * @param curcontents A buffer of full chip size with current chip contents of included regions.
1826*0d6140beSAndroid Build Coastguard Worker * @param newcontents The new image to be written.
1827*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
1828*0d6140beSAndroid Build Coastguard Worker * 1 if anything has gone wrong.
1829*0d6140beSAndroid Build Coastguard Worker */
write_by_layout_legacy(struct flashctx * const flashctx,void * const curcontents,const void * const newcontents,bool * all_skipped)1830*0d6140beSAndroid Build Coastguard Worker static int write_by_layout_legacy(struct flashctx *const flashctx,
1831*0d6140beSAndroid Build Coastguard Worker void *const curcontents, const void *const newcontents,
1832*0d6140beSAndroid Build Coastguard Worker bool *all_skipped)
1833*0d6140beSAndroid Build Coastguard Worker {
1834*0d6140beSAndroid Build Coastguard Worker struct walk_info info;
1835*0d6140beSAndroid Build Coastguard Worker info.curcontents = curcontents;
1836*0d6140beSAndroid Build Coastguard Worker info.newcontents = newcontents;
1837*0d6140beSAndroid Build Coastguard Worker return walk_by_layout(flashctx, &info, read_erase_write_block, all_skipped);
1838*0d6140beSAndroid Build Coastguard Worker }
1839*0d6140beSAndroid Build Coastguard Worker
1840*0d6140beSAndroid Build Coastguard Worker /*
1841*0d6140beSAndroid Build Coastguard Worker * Function to process processing units accumulated in the action descriptor.
1842*0d6140beSAndroid Build Coastguard Worker *
1843*0d6140beSAndroid Build Coastguard Worker * @flash pointer to the flash context to operate on
1844*0d6140beSAndroid Build Coastguard Worker * @per_blockfn helper function which can erase and program a section of the
1845*0d6140beSAndroid Build Coastguard Worker * flash chip. It receives the flash context, offset and length
1846*0d6140beSAndroid Build Coastguard Worker * of the area to erase/program, before and after contents (to
1847*0d6140beSAndroid Build Coastguard Worker * decide what exactly needs to be erased and or programmed)
1848*0d6140beSAndroid Build Coastguard Worker * and a pointer to the erase function which can operate on the
1849*0d6140beSAndroid Build Coastguard Worker * proper granularity.
1850*0d6140beSAndroid Build Coastguard Worker * @descriptor action descriptor including pointers to before and after
1851*0d6140beSAndroid Build Coastguard Worker * contents and an array of processing actions to take.
1852*0d6140beSAndroid Build Coastguard Worker *
1853*0d6140beSAndroid Build Coastguard Worker * Returns zero on success or an error code.
1854*0d6140beSAndroid Build Coastguard Worker */
walk_eraseregions(struct flashctx * flash,const per_blockfn_t per_blockfn,struct action_descriptor * descriptor,bool * all_skipped)1855*0d6140beSAndroid Build Coastguard Worker static int walk_eraseregions(struct flashctx *flash,
1856*0d6140beSAndroid Build Coastguard Worker const per_blockfn_t per_blockfn,
1857*0d6140beSAndroid Build Coastguard Worker struct action_descriptor *descriptor, bool *all_skipped)
1858*0d6140beSAndroid Build Coastguard Worker {
1859*0d6140beSAndroid Build Coastguard Worker struct processing_unit *pu;
1860*0d6140beSAndroid Build Coastguard Worker int rc = 0;
1861*0d6140beSAndroid Build Coastguard Worker static int print_comma;
1862*0d6140beSAndroid Build Coastguard Worker
1863*0d6140beSAndroid Build Coastguard Worker for (pu = descriptor->processing_units; pu->num_blocks; pu++) {
1864*0d6140beSAndroid Build Coastguard Worker unsigned base = pu->offset;
1865*0d6140beSAndroid Build Coastguard Worker unsigned top = pu->offset + pu->block_size * pu->num_blocks;
1866*0d6140beSAndroid Build Coastguard Worker struct block_eraser *const eraser = &flash->chip->block_erasers[pu->block_eraser_index];
1867*0d6140beSAndroid Build Coastguard Worker
1868*0d6140beSAndroid Build Coastguard Worker while (base < top) {
1869*0d6140beSAndroid Build Coastguard Worker
1870*0d6140beSAndroid Build Coastguard Worker if (print_comma)
1871*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", ");
1872*0d6140beSAndroid Build Coastguard Worker else
1873*0d6140beSAndroid Build Coastguard Worker print_comma = 1;
1874*0d6140beSAndroid Build Coastguard Worker
1875*0d6140beSAndroid Build Coastguard Worker msg_cdbg("0x%06x-0x%06zx", base, base + pu->block_size - 1);
1876*0d6140beSAndroid Build Coastguard Worker
1877*0d6140beSAndroid Build Coastguard Worker struct walk_info info = {
1878*0d6140beSAndroid Build Coastguard Worker .curcontents = descriptor->oldcontents + base,
1879*0d6140beSAndroid Build Coastguard Worker .newcontents = descriptor->newcontents + base,
1880*0d6140beSAndroid Build Coastguard Worker .erase_start = base,
1881*0d6140beSAndroid Build Coastguard Worker .erase_end = base + pu->block_size - 1,
1882*0d6140beSAndroid Build Coastguard Worker };
1883*0d6140beSAndroid Build Coastguard Worker erasefunc_t *erase_func = lookup_erase_func_ptr(eraser);
1884*0d6140beSAndroid Build Coastguard Worker rc = per_blockfn(flash, &info, erase_func, all_skipped);
1885*0d6140beSAndroid Build Coastguard Worker if (rc)
1886*0d6140beSAndroid Build Coastguard Worker return rc;
1887*0d6140beSAndroid Build Coastguard Worker
1888*0d6140beSAndroid Build Coastguard Worker base += pu->block_size;
1889*0d6140beSAndroid Build Coastguard Worker }
1890*0d6140beSAndroid Build Coastguard Worker }
1891*0d6140beSAndroid Build Coastguard Worker msg_cdbg("\n");
1892*0d6140beSAndroid Build Coastguard Worker return rc;
1893*0d6140beSAndroid Build Coastguard Worker }
1894*0d6140beSAndroid Build Coastguard Worker
1895*0d6140beSAndroid Build Coastguard Worker /*
1896*0d6140beSAndroid Build Coastguard Worker * Helper function called on each block to be erased and written.
1897*0d6140beSAndroid Build Coastguard Worker *
1898*0d6140beSAndroid Build Coastguard Worker * Returns 0 if erase and write operations succeed or if they are skipped
1899*0d6140beSAndroid Build Coastguard Worker * because the block is in a non-writable region.
1900*0d6140beSAndroid Build Coastguard Worker * Returns non-0 error code if erase or write operations fail unexpectedly.
1901*0d6140beSAndroid Build Coastguard Worker */
erase_and_write_block_helper(struct flashctx * const flash,const struct walk_info * const info,const erasefn_t erasefn,bool * all_skipped)1902*0d6140beSAndroid Build Coastguard Worker static int erase_and_write_block_helper(struct flashctx *const flash,
1903*0d6140beSAndroid Build Coastguard Worker const struct walk_info *const info,
1904*0d6140beSAndroid Build Coastguard Worker const erasefn_t erasefn, bool *all_skipped)
1905*0d6140beSAndroid Build Coastguard Worker {
1906*0d6140beSAndroid Build Coastguard Worker const unsigned int erase_len = info->erase_end + 1 - info->erase_start;
1907*0d6140beSAndroid Build Coastguard Worker unsigned int starthere = 0, lenhere = 0;
1908*0d6140beSAndroid Build Coastguard Worker int ret = 0, writecount = 0;
1909*0d6140beSAndroid Build Coastguard Worker enum write_granularity gran = flash->chip->gran;
1910*0d6140beSAndroid Build Coastguard Worker bool skipped = true;
1911*0d6140beSAndroid Build Coastguard Worker msg_cdbg(":");
1912*0d6140beSAndroid Build Coastguard Worker if (need_erase(info->curcontents, info->newcontents, erase_len, gran, 0xff)) {
1913*0d6140beSAndroid Build Coastguard Worker *all_skipped = false;
1914*0d6140beSAndroid Build Coastguard Worker msg_cdbg(" E");
1915*0d6140beSAndroid Build Coastguard Worker
1916*0d6140beSAndroid Build Coastguard Worker if (!flash->flags.skip_unwritable_regions) {
1917*0d6140beSAndroid Build Coastguard Worker if (check_for_unwritable_regions(flash, info->erase_start, erase_len))
1918*0d6140beSAndroid Build Coastguard Worker return -1;
1919*0d6140beSAndroid Build Coastguard Worker }
1920*0d6140beSAndroid Build Coastguard Worker
1921*0d6140beSAndroid Build Coastguard Worker unsigned int len;
1922*0d6140beSAndroid Build Coastguard Worker for (unsigned int addr = info->erase_start; addr < info->erase_start + erase_len; addr += len) {
1923*0d6140beSAndroid Build Coastguard Worker struct flash_region region;
1924*0d6140beSAndroid Build Coastguard Worker get_flash_region(flash, addr, ®ion);
1925*0d6140beSAndroid Build Coastguard Worker
1926*0d6140beSAndroid Build Coastguard Worker len = min(info->erase_start + erase_len, region.end) - addr;
1927*0d6140beSAndroid Build Coastguard Worker
1928*0d6140beSAndroid Build Coastguard Worker if (region.write_prot) {
1929*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: cannot erase inside %s region (%#08x..%#08x), skipping range (%#08x..%#08x).\n",
1930*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1, addr, addr + len - 1);
1931*0d6140beSAndroid Build Coastguard Worker free(region.name);
1932*0d6140beSAndroid Build Coastguard Worker continue;
1933*0d6140beSAndroid Build Coastguard Worker }
1934*0d6140beSAndroid Build Coastguard Worker
1935*0d6140beSAndroid Build Coastguard Worker msg_gdbg("%s: %s region (%#08x..%#08x) is writable, erasing range (%#08x..%#08x).\n",
1936*0d6140beSAndroid Build Coastguard Worker __func__, region.name, region.start, region.end - 1, addr, addr + len - 1);
1937*0d6140beSAndroid Build Coastguard Worker free(region.name);
1938*0d6140beSAndroid Build Coastguard Worker
1939*0d6140beSAndroid Build Coastguard Worker ret = erasefn(flash, addr, len);
1940*0d6140beSAndroid Build Coastguard Worker if (ret) {
1941*0d6140beSAndroid Build Coastguard Worker msg_cerr(" ERASE_FAILED\n");
1942*0d6140beSAndroid Build Coastguard Worker return ret;
1943*0d6140beSAndroid Build Coastguard Worker }
1944*0d6140beSAndroid Build Coastguard Worker if (!ret && cros_ec_erasure_failed()) { /* from cros_ec erase path. */
1945*0d6140beSAndroid Build Coastguard Worker msg_cdbg(" DENIED");
1946*0d6140beSAndroid Build Coastguard Worker return ret;
1947*0d6140beSAndroid Build Coastguard Worker }
1948*0d6140beSAndroid Build Coastguard Worker if (flash->flags.verify_after_write) { /* FIXME(b/263909055): replace with upstream. */
1949*0d6140beSAndroid Build Coastguard Worker if (check_erased_range(flash, info->erase_start, erase_len)) {
1950*0d6140beSAndroid Build Coastguard Worker msg_cerr(" ERASE_FAILED\n");
1951*0d6140beSAndroid Build Coastguard Worker return -1;
1952*0d6140beSAndroid Build Coastguard Worker }
1953*0d6140beSAndroid Build Coastguard Worker }
1954*0d6140beSAndroid Build Coastguard Worker }
1955*0d6140beSAndroid Build Coastguard Worker
1956*0d6140beSAndroid Build Coastguard Worker /* Erase was successful. Adjust curcontents. */
1957*0d6140beSAndroid Build Coastguard Worker memset(info->curcontents, ERASED_VALUE(flash), erase_len);
1958*0d6140beSAndroid Build Coastguard Worker skipped = false;
1959*0d6140beSAndroid Build Coastguard Worker }
1960*0d6140beSAndroid Build Coastguard Worker /* get_next_write() sets starthere to a new value after the call. */
1961*0d6140beSAndroid Build Coastguard Worker while ((lenhere = get_next_write(info->curcontents + starthere,
1962*0d6140beSAndroid Build Coastguard Worker info->newcontents + starthere,
1963*0d6140beSAndroid Build Coastguard Worker erase_len - starthere, &starthere, gran))) {
1964*0d6140beSAndroid Build Coastguard Worker *all_skipped = false;
1965*0d6140beSAndroid Build Coastguard Worker if (!writecount++)
1966*0d6140beSAndroid Build Coastguard Worker msg_cdbg(" W");
1967*0d6140beSAndroid Build Coastguard Worker
1968*0d6140beSAndroid Build Coastguard Worker /* Needs the partial write function signature. */
1969*0d6140beSAndroid Build Coastguard Worker ret = write_flash(flash, (uint8_t *)info->newcontents + starthere,
1970*0d6140beSAndroid Build Coastguard Worker info->erase_start + starthere, lenhere);
1971*0d6140beSAndroid Build Coastguard Worker if (ret) {
1972*0d6140beSAndroid Build Coastguard Worker return ret;
1973*0d6140beSAndroid Build Coastguard Worker }
1974*0d6140beSAndroid Build Coastguard Worker
1975*0d6140beSAndroid Build Coastguard Worker starthere += lenhere;
1976*0d6140beSAndroid Build Coastguard Worker skipped = false;
1977*0d6140beSAndroid Build Coastguard Worker }
1978*0d6140beSAndroid Build Coastguard Worker if (skipped)
1979*0d6140beSAndroid Build Coastguard Worker msg_cdbg("S");
1980*0d6140beSAndroid Build Coastguard Worker return ret;
1981*0d6140beSAndroid Build Coastguard Worker }
1982*0d6140beSAndroid Build Coastguard Worker
erase_and_write_flash(struct flashctx * flash,void * const curcontents,void * const newcontents,bool * all_skipped)1983*0d6140beSAndroid Build Coastguard Worker static int erase_and_write_flash(struct flashctx *flash,
1984*0d6140beSAndroid Build Coastguard Worker void *const curcontents, void *const newcontents, bool *all_skipped)
1985*0d6140beSAndroid Build Coastguard Worker {
1986*0d6140beSAndroid Build Coastguard Worker int ret = 1;
1987*0d6140beSAndroid Build Coastguard Worker struct action_descriptor *descriptor =
1988*0d6140beSAndroid Build Coastguard Worker prepare_action_descriptor(flash, curcontents, newcontents);
1989*0d6140beSAndroid Build Coastguard Worker
1990*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Erasing and writing flash chip... ");
1991*0d6140beSAndroid Build Coastguard Worker
1992*0d6140beSAndroid Build Coastguard Worker ret = walk_eraseregions(flash, &erase_and_write_block_helper, descriptor, all_skipped);
1993*0d6140beSAndroid Build Coastguard Worker
1994*0d6140beSAndroid Build Coastguard Worker if (ret) {
1995*0d6140beSAndroid Build Coastguard Worker msg_cerr("FAILED!\n");
1996*0d6140beSAndroid Build Coastguard Worker } else {
1997*0d6140beSAndroid Build Coastguard Worker msg_cinfo("SUCCESS.\n");
1998*0d6140beSAndroid Build Coastguard Worker }
1999*0d6140beSAndroid Build Coastguard Worker
2000*0d6140beSAndroid Build Coastguard Worker free(descriptor);
2001*0d6140beSAndroid Build Coastguard Worker return ret;
2002*0d6140beSAndroid Build Coastguard Worker }
2003*0d6140beSAndroid Build Coastguard Worker
write_by_layout_new(struct flashctx * const flashctx,void * const curcontents,const void * const newcontents,bool * all_skipped)2004*0d6140beSAndroid Build Coastguard Worker static int write_by_layout_new(struct flashctx *const flashctx,
2005*0d6140beSAndroid Build Coastguard Worker void *const curcontents, const void *const newcontents,
2006*0d6140beSAndroid Build Coastguard Worker bool *all_skipped)
2007*0d6140beSAndroid Build Coastguard Worker {
2008*0d6140beSAndroid Build Coastguard Worker const int erasefn_count = count_usable_erasers(flashctx);
2009*0d6140beSAndroid Build Coastguard Worker int ret = 1;
2010*0d6140beSAndroid Build Coastguard Worker
2011*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const flash_layout = get_layout(flashctx);
2012*0d6140beSAndroid Build Coastguard Worker struct erase_layout *erase_layout;
2013*0d6140beSAndroid Build Coastguard Worker create_erase_layout(flashctx, &erase_layout);
2014*0d6140beSAndroid Build Coastguard Worker
2015*0d6140beSAndroid Build Coastguard Worker if (!flash_layout) {
2016*0d6140beSAndroid Build Coastguard Worker goto _ret;
2017*0d6140beSAndroid Build Coastguard Worker }
2018*0d6140beSAndroid Build Coastguard Worker if (!erase_layout) {
2019*0d6140beSAndroid Build Coastguard Worker goto _ret;
2020*0d6140beSAndroid Build Coastguard Worker }
2021*0d6140beSAndroid Build Coastguard Worker
2022*0d6140beSAndroid Build Coastguard Worker const struct romentry *entry = NULL;
2023*0d6140beSAndroid Build Coastguard Worker while ((entry = layout_next_included(flash_layout, entry))) {
2024*0d6140beSAndroid Build Coastguard Worker ret = erase_write(flashctx, entry->region.start,
2025*0d6140beSAndroid Build Coastguard Worker entry->region.end,
2026*0d6140beSAndroid Build Coastguard Worker curcontents,
2027*0d6140beSAndroid Build Coastguard Worker (uint8_t *)newcontents,
2028*0d6140beSAndroid Build Coastguard Worker erase_layout, all_skipped);
2029*0d6140beSAndroid Build Coastguard Worker if (ret) {
2030*0d6140beSAndroid Build Coastguard Worker msg_cerr("Write Failed!");
2031*0d6140beSAndroid Build Coastguard Worker goto _ret;
2032*0d6140beSAndroid Build Coastguard Worker }
2033*0d6140beSAndroid Build Coastguard Worker }
2034*0d6140beSAndroid Build Coastguard Worker _ret:
2035*0d6140beSAndroid Build Coastguard Worker free_erase_layout(erase_layout, erasefn_count);
2036*0d6140beSAndroid Build Coastguard Worker return ret;
2037*0d6140beSAndroid Build Coastguard Worker }
2038*0d6140beSAndroid Build Coastguard Worker
write_by_layout(struct flashctx * const flashctx,uint8_t * const curcontents,const uint8_t * const newcontents,bool * all_skipped)2039*0d6140beSAndroid Build Coastguard Worker static int write_by_layout(struct flashctx *const flashctx,
2040*0d6140beSAndroid Build Coastguard Worker uint8_t *const curcontents, const uint8_t *const newcontents,
2041*0d6140beSAndroid Build Coastguard Worker bool *all_skipped)
2042*0d6140beSAndroid Build Coastguard Worker {
2043*0d6140beSAndroid Build Coastguard Worker if (use_legacy_erase_path)
2044*0d6140beSAndroid Build Coastguard Worker return write_by_layout_legacy(flashctx, curcontents, newcontents, all_skipped);
2045*0d6140beSAndroid Build Coastguard Worker return write_by_layout_new(flashctx, curcontents, newcontents, all_skipped);
2046*0d6140beSAndroid Build Coastguard Worker }
2047*0d6140beSAndroid Build Coastguard Worker
2048*0d6140beSAndroid Build Coastguard Worker /**
2049*0d6140beSAndroid Build Coastguard Worker * @brief Compares the included layout regions with content from a buffer.
2050*0d6140beSAndroid Build Coastguard Worker *
2051*0d6140beSAndroid Build Coastguard Worker * If there is no layout set in the given flash context, the whole chip's
2052*0d6140beSAndroid Build Coastguard Worker * contents will be compared.
2053*0d6140beSAndroid Build Coastguard Worker *
2054*0d6140beSAndroid Build Coastguard Worker * @param flashctx Flash context to be used.
2055*0d6140beSAndroid Build Coastguard Worker * @param layout Flash layout information.
2056*0d6140beSAndroid Build Coastguard Worker * @param curcontents A buffer of full chip size to read current chip contents into.
2057*0d6140beSAndroid Build Coastguard Worker * @param newcontents The new image to compare to.
2058*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
2059*0d6140beSAndroid Build Coastguard Worker * 1 if reading failed,
2060*0d6140beSAndroid Build Coastguard Worker * 3 if the contents don't match.
2061*0d6140beSAndroid Build Coastguard Worker */
verify_by_layout(struct flashctx * const flashctx,const struct flashrom_layout * const layout,void * const curcontents,const uint8_t * const newcontents)2062*0d6140beSAndroid Build Coastguard Worker static int verify_by_layout(
2063*0d6140beSAndroid Build Coastguard Worker struct flashctx *const flashctx,
2064*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const layout,
2065*0d6140beSAndroid Build Coastguard Worker void *const curcontents, const uint8_t *const newcontents)
2066*0d6140beSAndroid Build Coastguard Worker {
2067*0d6140beSAndroid Build Coastguard Worker const struct romentry *entry = NULL;
2068*0d6140beSAndroid Build Coastguard Worker int ret = 0;
2069*0d6140beSAndroid Build Coastguard Worker
2070*0d6140beSAndroid Build Coastguard Worker while ((entry = layout_next_included(layout, entry))) {
2071*0d6140beSAndroid Build Coastguard Worker const struct flash_region *region = &entry->region;
2072*0d6140beSAndroid Build Coastguard Worker const chipoff_t region_start = region->start;
2073*0d6140beSAndroid Build Coastguard Worker const chipsize_t region_len = region->end - region->start + 1;
2074*0d6140beSAndroid Build Coastguard Worker
2075*0d6140beSAndroid Build Coastguard Worker if ((ret = verify_range(flashctx, newcontents + region_start,
2076*0d6140beSAndroid Build Coastguard Worker region_start, region_len)))
2077*0d6140beSAndroid Build Coastguard Worker break;
2078*0d6140beSAndroid Build Coastguard Worker }
2079*0d6140beSAndroid Build Coastguard Worker
2080*0d6140beSAndroid Build Coastguard Worker if (ret)
2081*0d6140beSAndroid Build Coastguard Worker msg_gerr("Could not fully verify due to error, aborting\n");
2082*0d6140beSAndroid Build Coastguard Worker return ret;
2083*0d6140beSAndroid Build Coastguard Worker }
2084*0d6140beSAndroid Build Coastguard Worker
is_internal_programmer()2085*0d6140beSAndroid Build Coastguard Worker static bool is_internal_programmer()
2086*0d6140beSAndroid Build Coastguard Worker {
2087*0d6140beSAndroid Build Coastguard Worker #if CONFIG_INTERNAL == 1
2088*0d6140beSAndroid Build Coastguard Worker return programmer == &programmer_internal;
2089*0d6140beSAndroid Build Coastguard Worker #else
2090*0d6140beSAndroid Build Coastguard Worker return false;
2091*0d6140beSAndroid Build Coastguard Worker #endif
2092*0d6140beSAndroid Build Coastguard Worker }
2093*0d6140beSAndroid Build Coastguard Worker
nonfatal_help_message(void)2094*0d6140beSAndroid Build Coastguard Worker static void nonfatal_help_message(void)
2095*0d6140beSAndroid Build Coastguard Worker {
2096*0d6140beSAndroid Build Coastguard Worker msg_gerr("Good, writing to the flash chip apparently didn't do anything.\n");
2097*0d6140beSAndroid Build Coastguard Worker if (is_internal_programmer())
2098*0d6140beSAndroid Build Coastguard Worker msg_gerr("This means we have to add special support for your board, programmer or flash\n"
2099*0d6140beSAndroid Build Coastguard Worker "chip. Please report this to the mailing list at [email protected] or on\n"
2100*0d6140beSAndroid Build Coastguard Worker "IRC (see https://www.flashrom.org/Contact for details), thanks!\n"
2101*0d6140beSAndroid Build Coastguard Worker "-------------------------------------------------------------------------------\n"
2102*0d6140beSAndroid Build Coastguard Worker "You may now reboot or simply leave the machine running.\n");
2103*0d6140beSAndroid Build Coastguard Worker else
2104*0d6140beSAndroid Build Coastguard Worker msg_gerr("Please check the connections (especially those to write protection pins) between\n"
2105*0d6140beSAndroid Build Coastguard Worker "the programmer and the flash chip. If you think the error is caused by flashrom\n"
2106*0d6140beSAndroid Build Coastguard Worker "please report this to the mailing list at [email protected] or on IRC (see\n"
2107*0d6140beSAndroid Build Coastguard Worker "https://www.flashrom.org/Contact for details), thanks!\n");
2108*0d6140beSAndroid Build Coastguard Worker }
2109*0d6140beSAndroid Build Coastguard Worker
emergency_help_message(void)2110*0d6140beSAndroid Build Coastguard Worker void emergency_help_message(void)
2111*0d6140beSAndroid Build Coastguard Worker {
2112*0d6140beSAndroid Build Coastguard Worker msg_gerr("Your flash chip is in an unknown state.\n");
2113*0d6140beSAndroid Build Coastguard Worker if (is_internal_programmer())
2114*0d6140beSAndroid Build Coastguard Worker msg_gerr("Get help on IRC (see https://www.flashrom.org/Contact) or mail\n"
2115*0d6140beSAndroid Build Coastguard Worker "[email protected] with the subject \"FAILED: <your board name>\"!"
2116*0d6140beSAndroid Build Coastguard Worker "-------------------------------------------------------------------------------\n"
2117*0d6140beSAndroid Build Coastguard Worker "DO NOT REBOOT OR POWEROFF!\n");
2118*0d6140beSAndroid Build Coastguard Worker else
2119*0d6140beSAndroid Build Coastguard Worker msg_gerr("Please report this to the mailing list at [email protected] or\n"
2120*0d6140beSAndroid Build Coastguard Worker "on IRC (see https://www.flashrom.org/Contact for details), thanks!\n");
2121*0d6140beSAndroid Build Coastguard Worker }
2122*0d6140beSAndroid Build Coastguard Worker
list_programmers_linebreak(int startcol,int cols,int paren)2123*0d6140beSAndroid Build Coastguard Worker void list_programmers_linebreak(int startcol, int cols, int paren)
2124*0d6140beSAndroid Build Coastguard Worker {
2125*0d6140beSAndroid Build Coastguard Worker const char *pname;
2126*0d6140beSAndroid Build Coastguard Worker int pnamelen;
2127*0d6140beSAndroid Build Coastguard Worker int remaining = 0, firstline = 1;
2128*0d6140beSAndroid Build Coastguard Worker size_t p;
2129*0d6140beSAndroid Build Coastguard Worker int i;
2130*0d6140beSAndroid Build Coastguard Worker
2131*0d6140beSAndroid Build Coastguard Worker for (p = 0; p < programmer_table_size; p++) {
2132*0d6140beSAndroid Build Coastguard Worker pname = programmer_table[p]->name;
2133*0d6140beSAndroid Build Coastguard Worker pnamelen = strlen(pname);
2134*0d6140beSAndroid Build Coastguard Worker if (remaining - pnamelen - 2 < 0) {
2135*0d6140beSAndroid Build Coastguard Worker if (firstline)
2136*0d6140beSAndroid Build Coastguard Worker firstline = 0;
2137*0d6140beSAndroid Build Coastguard Worker else
2138*0d6140beSAndroid Build Coastguard Worker msg_ginfo("\n");
2139*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < startcol; i++)
2140*0d6140beSAndroid Build Coastguard Worker msg_ginfo(" ");
2141*0d6140beSAndroid Build Coastguard Worker remaining = cols - startcol;
2142*0d6140beSAndroid Build Coastguard Worker } else {
2143*0d6140beSAndroid Build Coastguard Worker msg_ginfo(" ");
2144*0d6140beSAndroid Build Coastguard Worker remaining--;
2145*0d6140beSAndroid Build Coastguard Worker }
2146*0d6140beSAndroid Build Coastguard Worker if (paren && (p == 0)) {
2147*0d6140beSAndroid Build Coastguard Worker msg_ginfo("(");
2148*0d6140beSAndroid Build Coastguard Worker remaining--;
2149*0d6140beSAndroid Build Coastguard Worker }
2150*0d6140beSAndroid Build Coastguard Worker msg_ginfo("%s", pname);
2151*0d6140beSAndroid Build Coastguard Worker remaining -= pnamelen;
2152*0d6140beSAndroid Build Coastguard Worker if (p < programmer_table_size - 1) {
2153*0d6140beSAndroid Build Coastguard Worker msg_ginfo(",");
2154*0d6140beSAndroid Build Coastguard Worker remaining--;
2155*0d6140beSAndroid Build Coastguard Worker } else {
2156*0d6140beSAndroid Build Coastguard Worker if (paren)
2157*0d6140beSAndroid Build Coastguard Worker msg_ginfo(")");
2158*0d6140beSAndroid Build Coastguard Worker }
2159*0d6140beSAndroid Build Coastguard Worker }
2160*0d6140beSAndroid Build Coastguard Worker }
2161*0d6140beSAndroid Build Coastguard Worker
selfcheck(void)2162*0d6140beSAndroid Build Coastguard Worker int selfcheck(void)
2163*0d6140beSAndroid Build Coastguard Worker {
2164*0d6140beSAndroid Build Coastguard Worker unsigned int i;
2165*0d6140beSAndroid Build Coastguard Worker int ret = 0;
2166*0d6140beSAndroid Build Coastguard Worker
2167*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < programmer_table_size; i++) {
2168*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry *const p = programmer_table[i];
2169*0d6140beSAndroid Build Coastguard Worker if (p == NULL) {
2170*0d6140beSAndroid Build Coastguard Worker msg_gerr("Programmer with index %d is NULL instead of a valid pointer!\n", i);
2171*0d6140beSAndroid Build Coastguard Worker ret = 1;
2172*0d6140beSAndroid Build Coastguard Worker continue;
2173*0d6140beSAndroid Build Coastguard Worker }
2174*0d6140beSAndroid Build Coastguard Worker if (p->name == NULL) {
2175*0d6140beSAndroid Build Coastguard Worker msg_gerr("All programmers need a valid name, but the one with index %d does not!\n", i);
2176*0d6140beSAndroid Build Coastguard Worker ret = 1;
2177*0d6140beSAndroid Build Coastguard Worker /* This might hide other problems with this programmer, but allows for better error
2178*0d6140beSAndroid Build Coastguard Worker * messages below without jumping through hoops. */
2179*0d6140beSAndroid Build Coastguard Worker continue;
2180*0d6140beSAndroid Build Coastguard Worker }
2181*0d6140beSAndroid Build Coastguard Worker switch (p->type) {
2182*0d6140beSAndroid Build Coastguard Worker case USB:
2183*0d6140beSAndroid Build Coastguard Worker case PCI:
2184*0d6140beSAndroid Build Coastguard Worker case OTHER:
2185*0d6140beSAndroid Build Coastguard Worker if (p->devs.note == NULL) {
2186*0d6140beSAndroid Build Coastguard Worker if (strcmp("internal", p->name) == 0)
2187*0d6140beSAndroid Build Coastguard Worker break; /* This one has its device list stored separately. */
2188*0d6140beSAndroid Build Coastguard Worker msg_gerr("Programmer %s has neither a device list nor a textual description!\n",
2189*0d6140beSAndroid Build Coastguard Worker p->name);
2190*0d6140beSAndroid Build Coastguard Worker ret = 1;
2191*0d6140beSAndroid Build Coastguard Worker }
2192*0d6140beSAndroid Build Coastguard Worker break;
2193*0d6140beSAndroid Build Coastguard Worker default:
2194*0d6140beSAndroid Build Coastguard Worker msg_gerr("Programmer %s does not have a valid type set!\n", p->name);
2195*0d6140beSAndroid Build Coastguard Worker ret = 1;
2196*0d6140beSAndroid Build Coastguard Worker break;
2197*0d6140beSAndroid Build Coastguard Worker }
2198*0d6140beSAndroid Build Coastguard Worker if (p->init == NULL) {
2199*0d6140beSAndroid Build Coastguard Worker msg_gerr("Programmer %s does not have a valid init function!\n", p->name);
2200*0d6140beSAndroid Build Coastguard Worker ret = 1;
2201*0d6140beSAndroid Build Coastguard Worker }
2202*0d6140beSAndroid Build Coastguard Worker }
2203*0d6140beSAndroid Build Coastguard Worker
2204*0d6140beSAndroid Build Coastguard Worker /* It would be favorable if we could check for the correct layout (especially termination) of various
2205*0d6140beSAndroid Build Coastguard Worker * constant arrays: flashchips, chipset_enables, board_matches, boards_known, laptops_known.
2206*0d6140beSAndroid Build Coastguard Worker * They are all defined as externs in this compilation unit so we don't know their sizes which vary
2207*0d6140beSAndroid Build Coastguard Worker * depending on compiler flags, e.g. the target architecture, and can sometimes be 0.
2208*0d6140beSAndroid Build Coastguard Worker * For 'flashchips' we export the size explicitly to work around this and to be able to implement the
2209*0d6140beSAndroid Build Coastguard Worker * checks below. */
2210*0d6140beSAndroid Build Coastguard Worker if (flashchips_size <= 1 || flashchips[flashchips_size - 1].name != NULL) {
2211*0d6140beSAndroid Build Coastguard Worker msg_gerr("Flashchips table miscompilation!\n");
2212*0d6140beSAndroid Build Coastguard Worker ret = 1;
2213*0d6140beSAndroid Build Coastguard Worker } else {
2214*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < flashchips_size - 1; i++) {
2215*0d6140beSAndroid Build Coastguard Worker const struct flashchip *chip = &flashchips[i];
2216*0d6140beSAndroid Build Coastguard Worker if (chip->vendor == NULL || chip->name == NULL || chip->bustype == BUS_NONE) {
2217*0d6140beSAndroid Build Coastguard Worker ret = 1;
2218*0d6140beSAndroid Build Coastguard Worker msg_gerr("ERROR: Some field of flash chip #%d (%s) is misconfigured.\n"
2219*0d6140beSAndroid Build Coastguard Worker "Please report a bug at [email protected]\n", i,
2220*0d6140beSAndroid Build Coastguard Worker chip->name == NULL ? "unnamed" : chip->name);
2221*0d6140beSAndroid Build Coastguard Worker }
2222*0d6140beSAndroid Build Coastguard Worker if (selfcheck_eraseblocks(chip)) {
2223*0d6140beSAndroid Build Coastguard Worker ret = 1;
2224*0d6140beSAndroid Build Coastguard Worker }
2225*0d6140beSAndroid Build Coastguard Worker }
2226*0d6140beSAndroid Build Coastguard Worker }
2227*0d6140beSAndroid Build Coastguard Worker
2228*0d6140beSAndroid Build Coastguard Worker #if CONFIG_INTERNAL == 1
2229*0d6140beSAndroid Build Coastguard Worker ret |= selfcheck_board_enables();
2230*0d6140beSAndroid Build Coastguard Worker #endif
2231*0d6140beSAndroid Build Coastguard Worker
2232*0d6140beSAndroid Build Coastguard Worker /* TODO: implement similar sanity checks for other arrays where deemed necessary. */
2233*0d6140beSAndroid Build Coastguard Worker return ret;
2234*0d6140beSAndroid Build Coastguard Worker }
2235*0d6140beSAndroid Build Coastguard Worker
2236*0d6140beSAndroid Build Coastguard Worker /* FIXME: This function signature needs to be improved once prepare_flash_access()
2237*0d6140beSAndroid Build Coastguard Worker * has a better function signature.
2238*0d6140beSAndroid Build Coastguard Worker */
chip_safety_check(const struct flashctx * flash,int force,int read_it,int write_it,int erase_it,int verify_it)2239*0d6140beSAndroid Build Coastguard Worker static int chip_safety_check(const struct flashctx *flash, int force,
2240*0d6140beSAndroid Build Coastguard Worker int read_it, int write_it, int erase_it, int verify_it)
2241*0d6140beSAndroid Build Coastguard Worker {
2242*0d6140beSAndroid Build Coastguard Worker const struct flashchip *chip = flash->chip;
2243*0d6140beSAndroid Build Coastguard Worker
2244*0d6140beSAndroid Build Coastguard Worker if (!programmer_may_write && (write_it || erase_it)) {
2245*0d6140beSAndroid Build Coastguard Worker msg_perr("Write/erase is not working yet on your programmer in "
2246*0d6140beSAndroid Build Coastguard Worker "its current configuration.\n");
2247*0d6140beSAndroid Build Coastguard Worker /* --force is the wrong approach, but it's the best we can do
2248*0d6140beSAndroid Build Coastguard Worker * until the generic programmer parameter parser is merged.
2249*0d6140beSAndroid Build Coastguard Worker */
2250*0d6140beSAndroid Build Coastguard Worker if (!force)
2251*0d6140beSAndroid Build Coastguard Worker return 1;
2252*0d6140beSAndroid Build Coastguard Worker msg_cerr("Continuing anyway.\n");
2253*0d6140beSAndroid Build Coastguard Worker }
2254*0d6140beSAndroid Build Coastguard Worker
2255*0d6140beSAndroid Build Coastguard Worker if (read_it || erase_it || write_it || verify_it) {
2256*0d6140beSAndroid Build Coastguard Worker /* Everything needs read. */
2257*0d6140beSAndroid Build Coastguard Worker if (chip->tested.read == BAD) {
2258*0d6140beSAndroid Build Coastguard Worker msg_cerr("Read is not working on this chip. ");
2259*0d6140beSAndroid Build Coastguard Worker if (!force)
2260*0d6140beSAndroid Build Coastguard Worker return 1;
2261*0d6140beSAndroid Build Coastguard Worker msg_cerr("Continuing anyway.\n");
2262*0d6140beSAndroid Build Coastguard Worker }
2263*0d6140beSAndroid Build Coastguard Worker if (!lookup_read_func_ptr(chip)) {
2264*0d6140beSAndroid Build Coastguard Worker msg_cerr("flashrom has no read function for this "
2265*0d6140beSAndroid Build Coastguard Worker "flash chip.\n");
2266*0d6140beSAndroid Build Coastguard Worker return 1;
2267*0d6140beSAndroid Build Coastguard Worker }
2268*0d6140beSAndroid Build Coastguard Worker }
2269*0d6140beSAndroid Build Coastguard Worker if (erase_it || write_it) {
2270*0d6140beSAndroid Build Coastguard Worker /* Write needs erase. */
2271*0d6140beSAndroid Build Coastguard Worker if (chip->tested.erase == NA) {
2272*0d6140beSAndroid Build Coastguard Worker msg_cerr("Erase is not possible on this chip.\n");
2273*0d6140beSAndroid Build Coastguard Worker return 1;
2274*0d6140beSAndroid Build Coastguard Worker }
2275*0d6140beSAndroid Build Coastguard Worker if (chip->tested.erase == BAD) {
2276*0d6140beSAndroid Build Coastguard Worker msg_cerr("Erase is not working on this chip. ");
2277*0d6140beSAndroid Build Coastguard Worker if (!force)
2278*0d6140beSAndroid Build Coastguard Worker return 1;
2279*0d6140beSAndroid Build Coastguard Worker msg_cerr("Continuing anyway.\n");
2280*0d6140beSAndroid Build Coastguard Worker }
2281*0d6140beSAndroid Build Coastguard Worker if(count_usable_erasers(flash) == 0) {
2282*0d6140beSAndroid Build Coastguard Worker msg_cerr("flashrom has no erase function for this "
2283*0d6140beSAndroid Build Coastguard Worker "flash chip.\n");
2284*0d6140beSAndroid Build Coastguard Worker return 1;
2285*0d6140beSAndroid Build Coastguard Worker }
2286*0d6140beSAndroid Build Coastguard Worker }
2287*0d6140beSAndroid Build Coastguard Worker if (write_it) {
2288*0d6140beSAndroid Build Coastguard Worker if (chip->tested.write == NA) {
2289*0d6140beSAndroid Build Coastguard Worker msg_cerr("Write is not possible on this chip.\n");
2290*0d6140beSAndroid Build Coastguard Worker return 1;
2291*0d6140beSAndroid Build Coastguard Worker }
2292*0d6140beSAndroid Build Coastguard Worker if (chip->tested.write == BAD) {
2293*0d6140beSAndroid Build Coastguard Worker msg_cerr("Write is not working on this chip. ");
2294*0d6140beSAndroid Build Coastguard Worker if (!force)
2295*0d6140beSAndroid Build Coastguard Worker return 1;
2296*0d6140beSAndroid Build Coastguard Worker msg_cerr("Continuing anyway.\n");
2297*0d6140beSAndroid Build Coastguard Worker }
2298*0d6140beSAndroid Build Coastguard Worker if (!lookup_write_func_ptr(chip)) {
2299*0d6140beSAndroid Build Coastguard Worker msg_cerr("flashrom has no write function for this "
2300*0d6140beSAndroid Build Coastguard Worker "flash chip.\n");
2301*0d6140beSAndroid Build Coastguard Worker return 1;
2302*0d6140beSAndroid Build Coastguard Worker }
2303*0d6140beSAndroid Build Coastguard Worker }
2304*0d6140beSAndroid Build Coastguard Worker return 0;
2305*0d6140beSAndroid Build Coastguard Worker }
2306*0d6140beSAndroid Build Coastguard Worker
restore_flash_wp(struct flashctx * const flash,void * data)2307*0d6140beSAndroid Build Coastguard Worker static int restore_flash_wp(struct flashctx *const flash, void *data)
2308*0d6140beSAndroid Build Coastguard Worker {
2309*0d6140beSAndroid Build Coastguard Worker struct flashrom_wp_cfg *wp_cfg = data;
2310*0d6140beSAndroid Build Coastguard Worker enum flashrom_wp_result ret = flashrom_wp_write_cfg(flash, wp_cfg);
2311*0d6140beSAndroid Build Coastguard Worker flashrom_wp_cfg_release(wp_cfg);
2312*0d6140beSAndroid Build Coastguard Worker
2313*0d6140beSAndroid Build Coastguard Worker return (ret == FLASHROM_WP_OK) ? 0 : -1;
2314*0d6140beSAndroid Build Coastguard Worker }
2315*0d6140beSAndroid Build Coastguard Worker
save_initial_flash_wp(struct flashctx * const flash)2316*0d6140beSAndroid Build Coastguard Worker static int save_initial_flash_wp(struct flashctx *const flash)
2317*0d6140beSAndroid Build Coastguard Worker {
2318*0d6140beSAndroid Build Coastguard Worker struct flashrom_wp_cfg *initial_wp_cfg;
2319*0d6140beSAndroid Build Coastguard Worker if (flashrom_wp_cfg_new(&initial_wp_cfg) != FLASHROM_WP_OK)
2320*0d6140beSAndroid Build Coastguard Worker return -1;
2321*0d6140beSAndroid Build Coastguard Worker
2322*0d6140beSAndroid Build Coastguard Worker if (flashrom_wp_read_cfg(initial_wp_cfg, flash) != FLASHROM_WP_OK) {
2323*0d6140beSAndroid Build Coastguard Worker flashrom_wp_cfg_release(initial_wp_cfg);
2324*0d6140beSAndroid Build Coastguard Worker return -1;
2325*0d6140beSAndroid Build Coastguard Worker }
2326*0d6140beSAndroid Build Coastguard Worker
2327*0d6140beSAndroid Build Coastguard Worker if (register_chip_restore(restore_flash_wp, flash, initial_wp_cfg)) {
2328*0d6140beSAndroid Build Coastguard Worker flashrom_wp_cfg_release(initial_wp_cfg);
2329*0d6140beSAndroid Build Coastguard Worker return -1;
2330*0d6140beSAndroid Build Coastguard Worker }
2331*0d6140beSAndroid Build Coastguard Worker return 0;
2332*0d6140beSAndroid Build Coastguard Worker }
2333*0d6140beSAndroid Build Coastguard Worker
unlock_flash_wp(struct flashctx * const flash,const bool write_it,const bool erase_it)2334*0d6140beSAndroid Build Coastguard Worker static int unlock_flash_wp(struct flashctx *const flash,
2335*0d6140beSAndroid Build Coastguard Worker const bool write_it, const bool erase_it)
2336*0d6140beSAndroid Build Coastguard Worker
2337*0d6140beSAndroid Build Coastguard Worker {
2338*0d6140beSAndroid Build Coastguard Worker int ret = 0;
2339*0d6140beSAndroid Build Coastguard Worker
2340*0d6140beSAndroid Build Coastguard Worker /* WP only disables write protection, so only use WP to unlock
2341*0d6140beSAndroid Build Coastguard Worker * for write/erase operations.
2342*0d6140beSAndroid Build Coastguard Worker *
2343*0d6140beSAndroid Build Coastguard Worker * For read/verify operations, we still call the chip's unlock
2344*0d6140beSAndroid Build Coastguard Worker * function, which may disable read locks if the chip has them.
2345*0d6140beSAndroid Build Coastguard Worker */
2346*0d6140beSAndroid Build Coastguard Worker if (!write_it && !erase_it) {
2347*0d6140beSAndroid Build Coastguard Worker msg_cdbg("Skipping writeprotect-based unlocking for read/verify operations.\n");
2348*0d6140beSAndroid Build Coastguard Worker return -1;
2349*0d6140beSAndroid Build Coastguard Worker }
2350*0d6140beSAndroid Build Coastguard Worker
2351*0d6140beSAndroid Build Coastguard Worker /* Save original WP state to be restored later */
2352*0d6140beSAndroid Build Coastguard Worker if (save_initial_flash_wp(flash)) {
2353*0d6140beSAndroid Build Coastguard Worker ret = -1;
2354*0d6140beSAndroid Build Coastguard Worker goto warn_out;
2355*0d6140beSAndroid Build Coastguard Worker }
2356*0d6140beSAndroid Build Coastguard Worker
2357*0d6140beSAndroid Build Coastguard Worker /* Disable WP */
2358*0d6140beSAndroid Build Coastguard Worker struct flashrom_wp_cfg *unlocked_wp_cfg;
2359*0d6140beSAndroid Build Coastguard Worker if (flashrom_wp_cfg_new(&unlocked_wp_cfg) != FLASHROM_WP_OK) {
2360*0d6140beSAndroid Build Coastguard Worker ret = -1;
2361*0d6140beSAndroid Build Coastguard Worker goto warn_out;
2362*0d6140beSAndroid Build Coastguard Worker }
2363*0d6140beSAndroid Build Coastguard Worker
2364*0d6140beSAndroid Build Coastguard Worker flashrom_wp_set_range(unlocked_wp_cfg, 0, 0);
2365*0d6140beSAndroid Build Coastguard Worker flashrom_wp_set_mode(unlocked_wp_cfg, FLASHROM_WP_MODE_DISABLED);
2366*0d6140beSAndroid Build Coastguard Worker if (flashrom_wp_write_cfg(flash, unlocked_wp_cfg) != FLASHROM_WP_OK) {
2367*0d6140beSAndroid Build Coastguard Worker ret = -1;
2368*0d6140beSAndroid Build Coastguard Worker }
2369*0d6140beSAndroid Build Coastguard Worker
2370*0d6140beSAndroid Build Coastguard Worker flashrom_wp_cfg_release(unlocked_wp_cfg);
2371*0d6140beSAndroid Build Coastguard Worker
2372*0d6140beSAndroid Build Coastguard Worker warn_out:
2373*0d6140beSAndroid Build Coastguard Worker if (ret)
2374*0d6140beSAndroid Build Coastguard Worker msg_cwarn("Failed to unlock flash status reg with wp support.\n");
2375*0d6140beSAndroid Build Coastguard Worker
2376*0d6140beSAndroid Build Coastguard Worker return ret;
2377*0d6140beSAndroid Build Coastguard Worker }
2378*0d6140beSAndroid Build Coastguard Worker
prepare_flash_access(struct flashctx * const flash,const bool read_it,const bool write_it,const bool erase_it,const bool verify_it)2379*0d6140beSAndroid Build Coastguard Worker int prepare_flash_access(struct flashctx *const flash,
2380*0d6140beSAndroid Build Coastguard Worker const bool read_it, const bool write_it,
2381*0d6140beSAndroid Build Coastguard Worker const bool erase_it, const bool verify_it)
2382*0d6140beSAndroid Build Coastguard Worker {
2383*0d6140beSAndroid Build Coastguard Worker if (chip_safety_check(flash, flash->flags.force, read_it, write_it, erase_it, verify_it)) {
2384*0d6140beSAndroid Build Coastguard Worker msg_cerr("Aborting.\n");
2385*0d6140beSAndroid Build Coastguard Worker return 1;
2386*0d6140beSAndroid Build Coastguard Worker }
2387*0d6140beSAndroid Build Coastguard Worker
2388*0d6140beSAndroid Build Coastguard Worker if (layout_sanity_checks(flash)) {
2389*0d6140beSAndroid Build Coastguard Worker msg_cerr("Requested regions can not be handled. Aborting.\n");
2390*0d6140beSAndroid Build Coastguard Worker return 1;
2391*0d6140beSAndroid Build Coastguard Worker }
2392*0d6140beSAndroid Build Coastguard Worker
2393*0d6140beSAndroid Build Coastguard Worker /* FIXME(b/207787495): replace this with locking in futility. */
2394*0d6140beSAndroid Build Coastguard Worker /* Let powerd know that we're updating firmware so machine stays awake. */
2395*0d6140beSAndroid Build Coastguard Worker if (write_it || erase_it) {
2396*0d6140beSAndroid Build Coastguard Worker if (disable_power_management() == 2) /* FIXME(b:314677563): check ret */
2397*0d6140beSAndroid Build Coastguard Worker return 1;
2398*0d6140beSAndroid Build Coastguard Worker }
2399*0d6140beSAndroid Build Coastguard Worker
2400*0d6140beSAndroid Build Coastguard Worker if (map_flash(flash) != 0)
2401*0d6140beSAndroid Build Coastguard Worker return 1;
2402*0d6140beSAndroid Build Coastguard Worker
2403*0d6140beSAndroid Build Coastguard Worker /* Initialize chip_restore_fn_count before chip unlock calls. */
2404*0d6140beSAndroid Build Coastguard Worker flash->chip_restore_fn_count = 0;
2405*0d6140beSAndroid Build Coastguard Worker
2406*0d6140beSAndroid Build Coastguard Worker int ret = 1;
2407*0d6140beSAndroid Build Coastguard Worker if (flash->chip->decode_range != NO_DECODE_RANGE_FUNC ||
2408*0d6140beSAndroid Build Coastguard Worker (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_write_cfg)) {
2409*0d6140beSAndroid Build Coastguard Worker ret = unlock_flash_wp(flash, write_it, erase_it);
2410*0d6140beSAndroid Build Coastguard Worker }
2411*0d6140beSAndroid Build Coastguard Worker /*
2412*0d6140beSAndroid Build Coastguard Worker * Fall back to chip unlock function if we haven't already successfully
2413*0d6140beSAndroid Build Coastguard Worker * unlocked using WP (e.g. WP unlocking failed, chip had no WP support,
2414*0d6140beSAndroid Build Coastguard Worker * WP was skipped for read/verify ops).
2415*0d6140beSAndroid Build Coastguard Worker *
2416*0d6140beSAndroid Build Coastguard Worker * Given the existence of read locks, we want to unlock for read,
2417*0d6140beSAndroid Build Coastguard Worker * erase, write, and verify.
2418*0d6140beSAndroid Build Coastguard Worker */
2419*0d6140beSAndroid Build Coastguard Worker blockprotect_func_t *bp_func = lookup_blockprotect_func_ptr(flash->chip);
2420*0d6140beSAndroid Build Coastguard Worker if (ret && bp_func)
2421*0d6140beSAndroid Build Coastguard Worker bp_func(flash);
2422*0d6140beSAndroid Build Coastguard Worker
2423*0d6140beSAndroid Build Coastguard Worker flash->address_high_byte = -1;
2424*0d6140beSAndroid Build Coastguard Worker flash->in_4ba_mode = false;
2425*0d6140beSAndroid Build Coastguard Worker
2426*0d6140beSAndroid Build Coastguard Worker /* Be careful about 4BA chips and broken masters */
2427*0d6140beSAndroid Build Coastguard Worker if (flash->chip->total_size > 16 * 1024 && spi_master_no_4ba_modes(flash)) {
2428*0d6140beSAndroid Build Coastguard Worker /* If we can't use native instructions, bail out */
2429*0d6140beSAndroid Build Coastguard Worker if ((flash->chip->feature_bits & FEATURE_4BA_NATIVE) != FEATURE_4BA_NATIVE
2430*0d6140beSAndroid Build Coastguard Worker || !spi_master_4ba(flash)) {
2431*0d6140beSAndroid Build Coastguard Worker msg_cerr("Programmer doesn't support this chip. Aborting.\n");
2432*0d6140beSAndroid Build Coastguard Worker return 1;
2433*0d6140beSAndroid Build Coastguard Worker }
2434*0d6140beSAndroid Build Coastguard Worker }
2435*0d6140beSAndroid Build Coastguard Worker
2436*0d6140beSAndroid Build Coastguard Worker /* Enable/disable 4-byte addressing mode if flash chip supports it */
2437*0d6140beSAndroid Build Coastguard Worker if (spi_chip_4ba(flash)) {
2438*0d6140beSAndroid Build Coastguard Worker if (spi_master_4ba(flash))
2439*0d6140beSAndroid Build Coastguard Worker ret = spi_enter_4ba(flash);
2440*0d6140beSAndroid Build Coastguard Worker else
2441*0d6140beSAndroid Build Coastguard Worker ret = spi_exit_4ba(flash);
2442*0d6140beSAndroid Build Coastguard Worker if (ret) {
2443*0d6140beSAndroid Build Coastguard Worker msg_cerr("Failed to set correct 4BA mode! Aborting.\n");
2444*0d6140beSAndroid Build Coastguard Worker return 1;
2445*0d6140beSAndroid Build Coastguard Worker }
2446*0d6140beSAndroid Build Coastguard Worker }
2447*0d6140beSAndroid Build Coastguard Worker
2448*0d6140beSAndroid Build Coastguard Worker return 0;
2449*0d6140beSAndroid Build Coastguard Worker }
2450*0d6140beSAndroid Build Coastguard Worker
finalize_flash_access(struct flashctx * const flash)2451*0d6140beSAndroid Build Coastguard Worker void finalize_flash_access(struct flashctx *const flash)
2452*0d6140beSAndroid Build Coastguard Worker {
2453*0d6140beSAndroid Build Coastguard Worker deregister_chip_restore(flash);
2454*0d6140beSAndroid Build Coastguard Worker unmap_flash(flash);
2455*0d6140beSAndroid Build Coastguard Worker
2456*0d6140beSAndroid Build Coastguard Worker /* FIXME(b/207787495): replace this with locking in futility. */
2457*0d6140beSAndroid Build Coastguard Worker if (restore_power_management()) {
2458*0d6140beSAndroid Build Coastguard Worker msg_gerr("Unable to re-enable power management\n");
2459*0d6140beSAndroid Build Coastguard Worker }
2460*0d6140beSAndroid Build Coastguard Worker }
2461*0d6140beSAndroid Build Coastguard Worker
setup_curcontents(struct flashctx * flashctx,void * curcontents,const void * const refcontents)2462*0d6140beSAndroid Build Coastguard Worker static int setup_curcontents(struct flashctx *flashctx, void *curcontents,
2463*0d6140beSAndroid Build Coastguard Worker const void *const refcontents)
2464*0d6140beSAndroid Build Coastguard Worker {
2465*0d6140beSAndroid Build Coastguard Worker const size_t flash_size = flashctx->chip->total_size * 1024;
2466*0d6140beSAndroid Build Coastguard Worker const bool verify_all = flashctx->flags.verify_whole_chip;
2467*0d6140beSAndroid Build Coastguard Worker
2468*0d6140beSAndroid Build Coastguard Worker memset(curcontents, UNERASED_VALUE(flashctx), flash_size);
2469*0d6140beSAndroid Build Coastguard Worker
2470*0d6140beSAndroid Build Coastguard Worker /* If given, assume flash chip contains same data as `refcontents`. */
2471*0d6140beSAndroid Build Coastguard Worker if (refcontents) {
2472*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Assuming old flash chip contents as ref-file...\n");
2473*0d6140beSAndroid Build Coastguard Worker memcpy(curcontents, refcontents, flash_size);
2474*0d6140beSAndroid Build Coastguard Worker } else {
2475*0d6140beSAndroid Build Coastguard Worker /*
2476*0d6140beSAndroid Build Coastguard Worker * Read the whole chip to be able to check whether regions need to be
2477*0d6140beSAndroid Build Coastguard Worker * erased and to give better diagnostics in case write fails.
2478*0d6140beSAndroid Build Coastguard Worker * The alternative is to read only the regions which are to be
2479*0d6140beSAndroid Build Coastguard Worker * preserved, but in that case we might perform unneeded erase which
2480*0d6140beSAndroid Build Coastguard Worker * takes time as well.
2481*0d6140beSAndroid Build Coastguard Worker */
2482*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Reading old flash chip contents... ");
2483*0d6140beSAndroid Build Coastguard Worker if (verify_all) {
2484*0d6140beSAndroid Build Coastguard Worker if (read_flash(flashctx, curcontents, 0, flash_size)) {
2485*0d6140beSAndroid Build Coastguard Worker msg_cinfo("FAILED.\n");
2486*0d6140beSAndroid Build Coastguard Worker return 1;
2487*0d6140beSAndroid Build Coastguard Worker }
2488*0d6140beSAndroid Build Coastguard Worker } else {
2489*0d6140beSAndroid Build Coastguard Worker /* WARNING: See FIXME on get_required_erase_size() */
2490*0d6140beSAndroid Build Coastguard Worker if (read_by_layout(flashctx, curcontents, true)) {
2491*0d6140beSAndroid Build Coastguard Worker msg_cinfo("FAILED.\n");
2492*0d6140beSAndroid Build Coastguard Worker return 1;
2493*0d6140beSAndroid Build Coastguard Worker }
2494*0d6140beSAndroid Build Coastguard Worker }
2495*0d6140beSAndroid Build Coastguard Worker msg_cinfo("done.\n");
2496*0d6140beSAndroid Build Coastguard Worker }
2497*0d6140beSAndroid Build Coastguard Worker return 0;
2498*0d6140beSAndroid Build Coastguard Worker }
2499*0d6140beSAndroid Build Coastguard Worker
2500*0d6140beSAndroid Build Coastguard Worker static void combine_image_by_layout(const struct flashctx *const flashctx,
2501*0d6140beSAndroid Build Coastguard Worker uint8_t *const newcontents, const uint8_t *const oldcontents);
2502*0d6140beSAndroid Build Coastguard Worker
2503*0d6140beSAndroid Build Coastguard Worker /**
2504*0d6140beSAndroid Build Coastguard Worker * @brief Erases the included layout regions.
2505*0d6140beSAndroid Build Coastguard Worker *
2506*0d6140beSAndroid Build Coastguard Worker * If there is no layout set in the given flash context, the whole chip will
2507*0d6140beSAndroid Build Coastguard Worker * be erased.
2508*0d6140beSAndroid Build Coastguard Worker *
2509*0d6140beSAndroid Build Coastguard Worker * @param flashctx Flash context to be used.
2510*0d6140beSAndroid Build Coastguard Worker * @return 0 on success,
2511*0d6140beSAndroid Build Coastguard Worker * 1 if all available erase functions failed.
2512*0d6140beSAndroid Build Coastguard Worker */
erase_by_layout_downstream(struct flashctx * const flashctx)2513*0d6140beSAndroid Build Coastguard Worker static int erase_by_layout_downstream(struct flashctx *const flashctx)
2514*0d6140beSAndroid Build Coastguard Worker {
2515*0d6140beSAndroid Build Coastguard Worker const size_t flash_size = flashctx->chip->total_size * 1024;
2516*0d6140beSAndroid Build Coastguard Worker int ret = 1;
2517*0d6140beSAndroid Build Coastguard Worker
2518*0d6140beSAndroid Build Coastguard Worker uint8_t *curcontents = malloc(flash_size);
2519*0d6140beSAndroid Build Coastguard Worker uint8_t *newcontents = malloc(flash_size);
2520*0d6140beSAndroid Build Coastguard Worker if (!curcontents || !newcontents) {
2521*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory!\n");
2522*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
2523*0d6140beSAndroid Build Coastguard Worker }
2524*0d6140beSAndroid Build Coastguard Worker
2525*0d6140beSAndroid Build Coastguard Worker if (setup_curcontents(flashctx, curcontents, NULL))
2526*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
2527*0d6140beSAndroid Build Coastguard Worker
2528*0d6140beSAndroid Build Coastguard Worker memset(newcontents, ERASED_VALUE(flashctx), flash_size);
2529*0d6140beSAndroid Build Coastguard Worker combine_image_by_layout(flashctx, newcontents, curcontents);
2530*0d6140beSAndroid Build Coastguard Worker
2531*0d6140beSAndroid Build Coastguard Worker bool all_skipped = true;
2532*0d6140beSAndroid Build Coastguard Worker ret = erase_and_write_flash(flashctx, curcontents, newcontents, &all_skipped);
2533*0d6140beSAndroid Build Coastguard Worker
2534*0d6140beSAndroid Build Coastguard Worker _free_ret:
2535*0d6140beSAndroid Build Coastguard Worker free(curcontents);
2536*0d6140beSAndroid Build Coastguard Worker free(newcontents);
2537*0d6140beSAndroid Build Coastguard Worker return ret;
2538*0d6140beSAndroid Build Coastguard Worker }
2539*0d6140beSAndroid Build Coastguard Worker static bool g_use_upstream_erase_path = false;
2540*0d6140beSAndroid Build Coastguard Worker
flashrom_flash_erase(struct flashctx * const flashctx)2541*0d6140beSAndroid Build Coastguard Worker int flashrom_flash_erase(struct flashctx *const flashctx)
2542*0d6140beSAndroid Build Coastguard Worker {
2543*0d6140beSAndroid Build Coastguard Worker int ret;
2544*0d6140beSAndroid Build Coastguard Worker if (prepare_flash_access(flashctx, false, false, true, false))
2545*0d6140beSAndroid Build Coastguard Worker return 1;
2546*0d6140beSAndroid Build Coastguard Worker
2547*0d6140beSAndroid Build Coastguard Worker if (g_use_upstream_erase_path)
2548*0d6140beSAndroid Build Coastguard Worker ret = erase_by_layout(flashctx);
2549*0d6140beSAndroid Build Coastguard Worker else
2550*0d6140beSAndroid Build Coastguard Worker ret = erase_by_layout_downstream(flashctx);
2551*0d6140beSAndroid Build Coastguard Worker
2552*0d6140beSAndroid Build Coastguard Worker finalize_flash_access(flashctx);
2553*0d6140beSAndroid Build Coastguard Worker
2554*0d6140beSAndroid Build Coastguard Worker return ret;
2555*0d6140beSAndroid Build Coastguard Worker }
2556*0d6140beSAndroid Build Coastguard Worker
flashrom_image_read(struct flashctx * const flashctx,void * const buffer,const size_t buffer_len)2557*0d6140beSAndroid Build Coastguard Worker int flashrom_image_read(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len)
2558*0d6140beSAndroid Build Coastguard Worker {
2559*0d6140beSAndroid Build Coastguard Worker const size_t flash_size = flashctx->chip->total_size * 1024;
2560*0d6140beSAndroid Build Coastguard Worker
2561*0d6140beSAndroid Build Coastguard Worker if (flash_size > buffer_len)
2562*0d6140beSAndroid Build Coastguard Worker return 2;
2563*0d6140beSAndroid Build Coastguard Worker
2564*0d6140beSAndroid Build Coastguard Worker if (prepare_flash_access(flashctx, true, false, false, false))
2565*0d6140beSAndroid Build Coastguard Worker return 1;
2566*0d6140beSAndroid Build Coastguard Worker
2567*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Reading flash... ");
2568*0d6140beSAndroid Build Coastguard Worker
2569*0d6140beSAndroid Build Coastguard Worker int ret = 1;
2570*0d6140beSAndroid Build Coastguard Worker if (read_by_layout(flashctx, buffer, false)) {
2571*0d6140beSAndroid Build Coastguard Worker msg_cerr("Read operation failed!\n");
2572*0d6140beSAndroid Build Coastguard Worker msg_cinfo("FAILED.\n");
2573*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2574*0d6140beSAndroid Build Coastguard Worker }
2575*0d6140beSAndroid Build Coastguard Worker msg_cinfo("done.\n");
2576*0d6140beSAndroid Build Coastguard Worker ret = 0;
2577*0d6140beSAndroid Build Coastguard Worker
2578*0d6140beSAndroid Build Coastguard Worker _finalize_ret:
2579*0d6140beSAndroid Build Coastguard Worker finalize_flash_access(flashctx);
2580*0d6140beSAndroid Build Coastguard Worker return ret;
2581*0d6140beSAndroid Build Coastguard Worker }
2582*0d6140beSAndroid Build Coastguard Worker
combine_image_by_layout(const struct flashctx * const flashctx,uint8_t * const newcontents,const uint8_t * const oldcontents)2583*0d6140beSAndroid Build Coastguard Worker static void combine_image_by_layout(const struct flashctx *const flashctx,
2584*0d6140beSAndroid Build Coastguard Worker uint8_t *const newcontents, const uint8_t *const oldcontents)
2585*0d6140beSAndroid Build Coastguard Worker {
2586*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const layout = get_layout(flashctx);
2587*0d6140beSAndroid Build Coastguard Worker const struct romentry *included;
2588*0d6140beSAndroid Build Coastguard Worker chipoff_t start = 0;
2589*0d6140beSAndroid Build Coastguard Worker
2590*0d6140beSAndroid Build Coastguard Worker while ((included = layout_next_included_region(layout, start))) {
2591*0d6140beSAndroid Build Coastguard Worker const struct flash_region *region = &included->region;
2592*0d6140beSAndroid Build Coastguard Worker if (region->start > start) {
2593*0d6140beSAndroid Build Coastguard Worker /* copy everything up to the start of this included region */
2594*0d6140beSAndroid Build Coastguard Worker memcpy(newcontents + start, oldcontents + start, region->start - start);
2595*0d6140beSAndroid Build Coastguard Worker }
2596*0d6140beSAndroid Build Coastguard Worker /* skip this included region */
2597*0d6140beSAndroid Build Coastguard Worker start = region->end + 1;
2598*0d6140beSAndroid Build Coastguard Worker if (start == 0)
2599*0d6140beSAndroid Build Coastguard Worker return;
2600*0d6140beSAndroid Build Coastguard Worker }
2601*0d6140beSAndroid Build Coastguard Worker
2602*0d6140beSAndroid Build Coastguard Worker /* copy the rest of the chip */
2603*0d6140beSAndroid Build Coastguard Worker const chipsize_t copy_len = flashctx->chip->total_size * 1024 - start;
2604*0d6140beSAndroid Build Coastguard Worker memcpy(newcontents + start, oldcontents + start, copy_len);
2605*0d6140beSAndroid Build Coastguard Worker }
2606*0d6140beSAndroid Build Coastguard Worker
2607*0d6140beSAndroid Build Coastguard Worker static bool g_use_upstream_erasewrite_path = false;
2608*0d6140beSAndroid Build Coastguard Worker
flashrom_image_write(struct flashctx * const flashctx,void * const buffer,const size_t buffer_len,const void * const refbuffer)2609*0d6140beSAndroid Build Coastguard Worker int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len,
2610*0d6140beSAndroid Build Coastguard Worker const void *const refbuffer)
2611*0d6140beSAndroid Build Coastguard Worker {
2612*0d6140beSAndroid Build Coastguard Worker const size_t flash_size = flashctx->chip->total_size * 1024;
2613*0d6140beSAndroid Build Coastguard Worker const bool verify_all = flashctx->flags.verify_whole_chip;
2614*0d6140beSAndroid Build Coastguard Worker const bool verify = flashctx->flags.verify_after_write;
2615*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const verify_layout =
2616*0d6140beSAndroid Build Coastguard Worker verify_all ? get_default_layout(flashctx) : get_layout(flashctx);
2617*0d6140beSAndroid Build Coastguard Worker
2618*0d6140beSAndroid Build Coastguard Worker if (buffer_len != flash_size)
2619*0d6140beSAndroid Build Coastguard Worker return 4;
2620*0d6140beSAndroid Build Coastguard Worker
2621*0d6140beSAndroid Build Coastguard Worker int ret = 1;
2622*0d6140beSAndroid Build Coastguard Worker int tmp = 0;
2623*0d6140beSAndroid Build Coastguard Worker
2624*0d6140beSAndroid Build Coastguard Worker uint8_t *curcontents = malloc(flash_size);
2625*0d6140beSAndroid Build Coastguard Worker uint8_t *newcontents = malloc(flash_size);
2626*0d6140beSAndroid Build Coastguard Worker uint8_t *oldcontents = NULL;
2627*0d6140beSAndroid Build Coastguard Worker if (verify_all)
2628*0d6140beSAndroid Build Coastguard Worker oldcontents = malloc(flash_size);
2629*0d6140beSAndroid Build Coastguard Worker if (!curcontents || !newcontents || (verify_all && !oldcontents)) {
2630*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory!\n");
2631*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
2632*0d6140beSAndroid Build Coastguard Worker }
2633*0d6140beSAndroid Build Coastguard Worker
2634*0d6140beSAndroid Build Coastguard Worker #if CONFIG_INTERNAL == 1
2635*0d6140beSAndroid Build Coastguard Worker if (is_internal_programmer() && cb_check_image(newcontents, flash_size) < 0) {
2636*0d6140beSAndroid Build Coastguard Worker if (flashctx->flags.force_boardmismatch) {
2637*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Proceeding anyway because user forced us to.\n");
2638*0d6140beSAndroid Build Coastguard Worker } else {
2639*0d6140beSAndroid Build Coastguard Worker msg_perr("Aborting. You can override this with "
2640*0d6140beSAndroid Build Coastguard Worker "-p internal:boardmismatch=force.\n");
2641*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
2642*0d6140beSAndroid Build Coastguard Worker }
2643*0d6140beSAndroid Build Coastguard Worker }
2644*0d6140beSAndroid Build Coastguard Worker #endif
2645*0d6140beSAndroid Build Coastguard Worker
2646*0d6140beSAndroid Build Coastguard Worker if (prepare_flash_access(flashctx, false, true, false, verify))
2647*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
2648*0d6140beSAndroid Build Coastguard Worker
2649*0d6140beSAndroid Build Coastguard Worker if (setup_curcontents(flashctx, curcontents, refbuffer))
2650*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2651*0d6140beSAndroid Build Coastguard Worker if (oldcontents)
2652*0d6140beSAndroid Build Coastguard Worker memcpy(oldcontents, curcontents, flash_size);
2653*0d6140beSAndroid Build Coastguard Worker
2654*0d6140beSAndroid Build Coastguard Worker memcpy(newcontents, buffer, flash_size);
2655*0d6140beSAndroid Build Coastguard Worker combine_image_by_layout(flashctx, newcontents, curcontents);
2656*0d6140beSAndroid Build Coastguard Worker
2657*0d6140beSAndroid Build Coastguard Worker // parse the new fmap and disable soft WP if necessary
2658*0d6140beSAndroid Build Coastguard Worker if ((tmp = cros_ec_prepare(flashctx, newcontents, flash_size))) {
2659*0d6140beSAndroid Build Coastguard Worker msg_cerr("CROS_EC prepare failed, ret=%d.\n", tmp);
2660*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2661*0d6140beSAndroid Build Coastguard Worker }
2662*0d6140beSAndroid Build Coastguard Worker
2663*0d6140beSAndroid Build Coastguard Worker bool all_skipped = true;
2664*0d6140beSAndroid Build Coastguard Worker if (g_use_upstream_erasewrite_path)
2665*0d6140beSAndroid Build Coastguard Worker ret = write_by_layout(flashctx, curcontents, newcontents, &all_skipped);
2666*0d6140beSAndroid Build Coastguard Worker else
2667*0d6140beSAndroid Build Coastguard Worker ret = erase_and_write_flash(flashctx, curcontents, newcontents, &all_skipped);
2668*0d6140beSAndroid Build Coastguard Worker if (ret) {
2669*0d6140beSAndroid Build Coastguard Worker msg_cerr("Uh oh. Erase/write failed. ");
2670*0d6140beSAndroid Build Coastguard Worker ret = 2;
2671*0d6140beSAndroid Build Coastguard Worker if (verify_all) {
2672*0d6140beSAndroid Build Coastguard Worker msg_cerr("Checking if anything has changed.\n");
2673*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Reading current flash chip contents... ");
2674*0d6140beSAndroid Build Coastguard Worker if (!read_flash(flashctx, curcontents, 0, flash_size)) {
2675*0d6140beSAndroid Build Coastguard Worker msg_cinfo("done.\n");
2676*0d6140beSAndroid Build Coastguard Worker if (!memcmp(oldcontents, curcontents, flash_size)) {
2677*0d6140beSAndroid Build Coastguard Worker nonfatal_help_message();
2678*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2679*0d6140beSAndroid Build Coastguard Worker }
2680*0d6140beSAndroid Build Coastguard Worker msg_cerr("Apparently at least some data has changed.\n");
2681*0d6140beSAndroid Build Coastguard Worker } else
2682*0d6140beSAndroid Build Coastguard Worker msg_cerr("Can't even read anymore!\n");
2683*0d6140beSAndroid Build Coastguard Worker emergency_help_message();
2684*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2685*0d6140beSAndroid Build Coastguard Worker } else {
2686*0d6140beSAndroid Build Coastguard Worker msg_cerr("\n");
2687*0d6140beSAndroid Build Coastguard Worker }
2688*0d6140beSAndroid Build Coastguard Worker emergency_help_message();
2689*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2690*0d6140beSAndroid Build Coastguard Worker }
2691*0d6140beSAndroid Build Coastguard Worker
2692*0d6140beSAndroid Build Coastguard Worker tmp = cros_ec_need_2nd_pass();
2693*0d6140beSAndroid Build Coastguard Worker if (tmp < 0) {
2694*0d6140beSAndroid Build Coastguard Worker // Jump failed
2695*0d6140beSAndroid Build Coastguard Worker msg_cerr("cros_ec_need_2nd_pass() failed. Stop.\n");
2696*0d6140beSAndroid Build Coastguard Worker emergency_help_message();
2697*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2698*0d6140beSAndroid Build Coastguard Worker } else if (tmp > 0) {
2699*0d6140beSAndroid Build Coastguard Worker // Need 2nd pass. Get the just written content.
2700*0d6140beSAndroid Build Coastguard Worker msg_pdbg("CROS_EC needs 2nd pass.\n");
2701*0d6140beSAndroid Build Coastguard Worker if (setup_curcontents(flashctx, curcontents, NULL)) {
2702*0d6140beSAndroid Build Coastguard Worker emergency_help_message();
2703*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2704*0d6140beSAndroid Build Coastguard Worker }
2705*0d6140beSAndroid Build Coastguard Worker
2706*0d6140beSAndroid Build Coastguard Worker // write 2nd pass
2707*0d6140beSAndroid Build Coastguard Worker if (g_use_upstream_erasewrite_path)
2708*0d6140beSAndroid Build Coastguard Worker ret = write_by_layout(flashctx, curcontents, newcontents, &all_skipped);
2709*0d6140beSAndroid Build Coastguard Worker else
2710*0d6140beSAndroid Build Coastguard Worker ret = erase_and_write_flash(flashctx, curcontents, newcontents, &all_skipped);
2711*0d6140beSAndroid Build Coastguard Worker if (ret) {
2712*0d6140beSAndroid Build Coastguard Worker msg_cerr("Uh oh. CROS_EC 2nd pass failed.\n");
2713*0d6140beSAndroid Build Coastguard Worker ret = 2;
2714*0d6140beSAndroid Build Coastguard Worker emergency_help_message();
2715*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2716*0d6140beSAndroid Build Coastguard Worker }
2717*0d6140beSAndroid Build Coastguard Worker }
2718*0d6140beSAndroid Build Coastguard Worker
2719*0d6140beSAndroid Build Coastguard Worker /* Verify only if we actually changed something. */
2720*0d6140beSAndroid Build Coastguard Worker if (verify && !all_skipped) {
2721*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Verifying flash... ");
2722*0d6140beSAndroid Build Coastguard Worker
2723*0d6140beSAndroid Build Coastguard Worker /*
2724*0d6140beSAndroid Build Coastguard Worker * Work around chips which "need some time to calm down."
2725*0d6140beSAndroid Build Coastguard Worker *
2726*0d6140beSAndroid Build Coastguard Worker * Frankly, it's not 100% clear why this delay is here at all,
2727*0d6140beSAndroid Build Coastguard Worker * except for a terse message from 2009 of "a few reports where
2728*0d6140beSAndroid Build Coastguard Worker * verify directly after erase had unpleasant side effects like
2729*0d6140beSAndroid Build Coastguard Worker * corrupting flash or at least getting incorrect verify
2730*0d6140beSAndroid Build Coastguard Worker * results". Ideally, if there were a few known problematic
2731*0d6140beSAndroid Build Coastguard Worker * chips or programmers, we could add quirks flags for those
2732*0d6140beSAndroid Build Coastguard Worker * specific implementations without penalizing all other
2733*0d6140beSAndroid Build Coastguard Worker * flashrom users. But alas, we don't know which systems
2734*0d6140beSAndroid Build Coastguard Worker * experienced those issues.
2735*0d6140beSAndroid Build Coastguard Worker *
2736*0d6140beSAndroid Build Coastguard Worker * Out of an extreme abundance of caution, we retain this
2737*0d6140beSAndroid Build Coastguard Worker * delay, but only for a few non-SPI bus types that were the
2738*0d6140beSAndroid Build Coastguard Worker * likely prevalent targets at the time. This is a complete
2739*0d6140beSAndroid Build Coastguard Worker * guess, which conveniently avoids wasting time on common
2740*0d6140beSAndroid Build Coastguard Worker * BUS_SPI and BUS_PROG systems.
2741*0d6140beSAndroid Build Coastguard Worker *
2742*0d6140beSAndroid Build Coastguard Worker * Background thread:
2743*0d6140beSAndroid Build Coastguard Worker * Subject: RFC: removing 1 second verification delay
2744*0d6140beSAndroid Build Coastguard Worker * https://mail.coreboot.org/hyperkitty/list/[email protected]/thread/SFV3OJBVVMDKRLI3FQA3DDDGEXJ7W4ED/
2745*0d6140beSAndroid Build Coastguard Worker */
2746*0d6140beSAndroid Build Coastguard Worker if (flashctx->chip->bustype & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
2747*0d6140beSAndroid Build Coastguard Worker programmer_delay(flashctx, 1000*1000);
2748*0d6140beSAndroid Build Coastguard Worker
2749*0d6140beSAndroid Build Coastguard Worker ret = verify_by_layout(flashctx, verify_layout, curcontents, newcontents);
2750*0d6140beSAndroid Build Coastguard Worker /* If we tried to write, and verification now fails, we
2751*0d6140beSAndroid Build Coastguard Worker might have an emergency situation. */
2752*0d6140beSAndroid Build Coastguard Worker if (ret) {
2753*0d6140beSAndroid Build Coastguard Worker emergency_help_message();
2754*0d6140beSAndroid Build Coastguard Worker goto _finalize_ret;
2755*0d6140beSAndroid Build Coastguard Worker }
2756*0d6140beSAndroid Build Coastguard Worker else
2757*0d6140beSAndroid Build Coastguard Worker msg_cinfo("VERIFIED.\n");
2758*0d6140beSAndroid Build Coastguard Worker } else {
2759*0d6140beSAndroid Build Coastguard Worker /* We didn't change anything. */
2760*0d6140beSAndroid Build Coastguard Worker ret = 0;
2761*0d6140beSAndroid Build Coastguard Worker }
2762*0d6140beSAndroid Build Coastguard Worker
2763*0d6140beSAndroid Build Coastguard Worker if (cros_ec_finish() < 0) {
2764*0d6140beSAndroid Build Coastguard Worker msg_cerr("cros_ec_finish() failed. Stop.\n");
2765*0d6140beSAndroid Build Coastguard Worker ret = 1;
2766*0d6140beSAndroid Build Coastguard Worker emergency_help_message();
2767*0d6140beSAndroid Build Coastguard Worker }
2768*0d6140beSAndroid Build Coastguard Worker
2769*0d6140beSAndroid Build Coastguard Worker _finalize_ret:
2770*0d6140beSAndroid Build Coastguard Worker finalize_flash_access(flashctx);
2771*0d6140beSAndroid Build Coastguard Worker _free_ret:
2772*0d6140beSAndroid Build Coastguard Worker free(oldcontents);
2773*0d6140beSAndroid Build Coastguard Worker free(curcontents);
2774*0d6140beSAndroid Build Coastguard Worker free(newcontents);
2775*0d6140beSAndroid Build Coastguard Worker return ret;
2776*0d6140beSAndroid Build Coastguard Worker }
2777*0d6140beSAndroid Build Coastguard Worker
flashrom_image_verify(struct flashctx * const flashctx,const void * const buffer,const size_t buffer_len)2778*0d6140beSAndroid Build Coastguard Worker int flashrom_image_verify(struct flashctx *const flashctx, const void *const buffer, const size_t buffer_len)
2779*0d6140beSAndroid Build Coastguard Worker {
2780*0d6140beSAndroid Build Coastguard Worker const struct flashrom_layout *const layout = get_layout(flashctx);
2781*0d6140beSAndroid Build Coastguard Worker const size_t flash_size = flashctx->chip->total_size * 1024;
2782*0d6140beSAndroid Build Coastguard Worker
2783*0d6140beSAndroid Build Coastguard Worker if (buffer_len != flash_size)
2784*0d6140beSAndroid Build Coastguard Worker return 2;
2785*0d6140beSAndroid Build Coastguard Worker
2786*0d6140beSAndroid Build Coastguard Worker const uint8_t *const newcontents = buffer;
2787*0d6140beSAndroid Build Coastguard Worker uint8_t *const curcontents = malloc(flash_size);
2788*0d6140beSAndroid Build Coastguard Worker if (!curcontents) {
2789*0d6140beSAndroid Build Coastguard Worker msg_gerr("Out of memory!\n");
2790*0d6140beSAndroid Build Coastguard Worker return 1;
2791*0d6140beSAndroid Build Coastguard Worker }
2792*0d6140beSAndroid Build Coastguard Worker
2793*0d6140beSAndroid Build Coastguard Worker int ret = 1;
2794*0d6140beSAndroid Build Coastguard Worker
2795*0d6140beSAndroid Build Coastguard Worker if (prepare_flash_access(flashctx, false, false, false, true))
2796*0d6140beSAndroid Build Coastguard Worker goto _free_ret;
2797*0d6140beSAndroid Build Coastguard Worker
2798*0d6140beSAndroid Build Coastguard Worker msg_cinfo("Verifying flash... ");
2799*0d6140beSAndroid Build Coastguard Worker ret = verify_by_layout(flashctx, layout, curcontents, newcontents);
2800*0d6140beSAndroid Build Coastguard Worker if (!ret)
2801*0d6140beSAndroid Build Coastguard Worker msg_cinfo("VERIFIED.\n");
2802*0d6140beSAndroid Build Coastguard Worker
2803*0d6140beSAndroid Build Coastguard Worker finalize_flash_access(flashctx);
2804*0d6140beSAndroid Build Coastguard Worker _free_ret:
2805*0d6140beSAndroid Build Coastguard Worker free(curcontents);
2806*0d6140beSAndroid Build Coastguard Worker return ret;
2807*0d6140beSAndroid Build Coastguard Worker }
2808