blob: ec5060d1eb2c7957ea45728703388b0774e19bf5 [file] [log] [blame]
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +00001/*
2 * This file is part of the flashrom project.
3 *
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00004 * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00008 * the Free Software Foundation; version 2 of the License.
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +00009 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +000014 */
15
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +000016#include <string.h>
17#include <stdlib.h>
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +000018#include <stdio.h>
19#include <ctype.h>
Stefan Tauner5e695ab2012-05-06 17:03:40 +000020#include <errno.h>
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +000021#include "flash.h"
Carl-Daniel Hailfinger1b0ba892010-06-20 10:58:32 +000022#include "chipdrivers.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000023#include "programmer.h"
Namyoon Woo31498222020-08-27 16:03:16 -070024#include "flashchips.h"
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +000025
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +000026/* Remove the #define below if you don't want SPI flash chip emulation. */
27#define EMULATE_SPI_CHIP 1
28
29#if EMULATE_SPI_CHIP
30#define EMULATE_CHIP 1
31#include "spi.h"
32#endif
33
34#if EMULATE_CHIP
35#include <sys/types.h>
36#include <sys/stat.h>
37#endif
38
39#if EMULATE_CHIP
40static uint8_t *flashchip_contents = NULL;
41enum emu_chip {
42 EMULATE_NONE,
43 EMULATE_ST_M25P10_RES,
44 EMULATE_SST_SST25VF040_REMS,
45 EMULATE_SST_SST25VF032B,
Stefan Tauner0b9df972012-05-07 22:12:16 +000046 EMULATE_MACRONIX_MX25L6436,
Nico Huberf9632d82019-01-20 11:23:49 +010047 EMULATE_WINBOND_W25Q128FV,
Namyoon Woo31498222020-08-27 16:03:16 -070048 EMULATE_VARIABLE_SIZE,
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +000049};
Stefan Tauner0b9df972012-05-07 22:12:16 +000050
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +100051struct emu_data {
52 enum emu_chip emu_chip;
53 char *emu_persistent_image;
54 unsigned int emu_chip_size;
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +110055 int erase_to_zero;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +100056 int emu_modified; /* is the image modified since reading it? */
57 uint8_t emu_status;
Edward O'Callaghancb9f3cd2020-09-17 13:32:00 +100058 /* If "freq" parameter is passed in from command line, commands will delay
59 * for this period before returning. */
60 unsigned long int delay_us;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +100061 unsigned int emu_max_byteprogram_size;
62 unsigned int emu_max_aai_size;
63 unsigned int emu_jedec_se_size;
64 unsigned int emu_jedec_be_52_size;
65 unsigned int emu_jedec_be_d8_size;
66 unsigned int emu_jedec_ce_60_size;
67 unsigned int emu_jedec_ce_c7_size;
68 unsigned char spi_blacklist[256];
69 unsigned char spi_ignorelist[256];
70 unsigned int spi_blacklist_size;
71 unsigned int spi_ignorelist_size;
72};
73
74#if EMULATE_SPI_CHIP
Stefan Tauner0b9df972012-05-07 22:12:16 +000075/* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
Stefan Tauner67d163d2013-01-15 17:37:48 +000076static const uint8_t sfdp_table[] = {
Stefan Tauner0b9df972012-05-07 22:12:16 +000077 0x53, 0x46, 0x44, 0x50, // @0x00: SFDP signature
78 0x00, 0x01, 0x01, 0xFF, // @0x04: revision 1.0, 2 headers
79 0x00, 0x00, 0x01, 0x09, // @0x08: JEDEC SFDP header rev. 1.0, 9 DW long
80 0x1C, 0x00, 0x00, 0xFF, // @0x0C: PTP0 = 0x1C (instead of 0x30)
81 0xC2, 0x00, 0x01, 0x04, // @0x10: Macronix header rev. 1.0, 4 DW long
82 0x48, 0x00, 0x00, 0xFF, // @0x14: PTP1 = 0x48 (instead of 0x60)
83 0xFF, 0xFF, 0xFF, 0xFF, // @0x18: hole.
84 0xE5, 0x20, 0xC9, 0xFF, // @0x1C: SFDP parameter table start
85 0xFF, 0xFF, 0xFF, 0x03, // @0x20
86 0x00, 0xFF, 0x08, 0x6B, // @0x24
87 0x08, 0x3B, 0x00, 0xFF, // @0x28
88 0xEE, 0xFF, 0xFF, 0xFF, // @0x2C
89 0xFF, 0xFF, 0x00, 0x00, // @0x30
90 0xFF, 0xFF, 0x00, 0xFF, // @0x34
91 0x0C, 0x20, 0x0F, 0x52, // @0x38
92 0x10, 0xD8, 0x00, 0xFF, // @0x3C: SFDP parameter table end
93 0xFF, 0xFF, 0xFF, 0xFF, // @0x40: hole.
94 0xFF, 0xFF, 0xFF, 0xFF, // @0x44: hole.
95 0x00, 0x36, 0x00, 0x27, // @0x48: Macronix parameter table start
96 0xF4, 0x4F, 0xFF, 0xFF, // @0x4C
97 0xD9, 0xC8, 0xFF, 0xFF, // @0x50
98 0xFF, 0xFF, 0xFF, 0xFF, // @0x54: Macronix parameter table end
99};
100
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000101#endif
102#endif
103
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000104static unsigned int spi_write_256_chunksize = 256;
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100105static enum chipbustype dummy_buses_supported = BUS_NONE;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000106
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100107void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
108{
109 msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
110 __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
111 return (void *)phys_addr;
112}
113
114void dummy_unmap(void *virt_addr, size_t len)
115{
116 msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
117}
118
119static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
120{
121 return spi_write_chunked(flash, buf, start, len,
122 spi_write_256_chunksize);
123}
124
125static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
126{
127 msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%02x\n", __func__, addr, val);
128}
129
130static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
131{
132 msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%04x\n", __func__, addr, val);
133}
134
135static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
136{
137 msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%08x\n", __func__, addr, val);
138}
139
140static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
141{
142 size_t i;
143 msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, writing data (hex):", __func__, addr, len);
144 for (i = 0; i < len; i++) {
145 if ((i % 16) == 0)
146 msg_pspew("\n");
147 msg_pspew("%02x ", buf[i]);
148 }
149}
150
151static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr)
152{
153 msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xff\n", __func__, addr);
154 return 0xff;
155}
156
157static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr)
158{
159 msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffff\n", __func__, addr);
160 return 0xffff;
161}
162
163static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr)
164{
165 msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffffffff\n", __func__, addr);
166 return 0xffffffff;
167}
168
169static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len)
170{
171 msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, returning array of 0xff\n", __func__, addr, len);
172 memset(buf, 0xff, len);
173 return;
174}
175
176static struct emu_data* get_data_from_context(const struct flashctx *flash)
177{
178 if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
179 return (struct emu_data *)flash->mst->par.data;
180 else if (dummy_buses_supported & BUS_SPI)
181 return (struct emu_data *)flash->mst->spi.data;
182
183 return NULL; /* buses was set to BUS_NONE. */
184}
185
186#if EMULATE_SPI_CHIP
187static int emulate_spi_chip_response(unsigned int writecnt,
188 unsigned int readcnt,
189 const unsigned char *writearr,
190 unsigned char *readarr,
191 struct emu_data *data)
192{
193 unsigned int offs, i, toread;
194 static int unsigned aai_offs;
195 const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};
196 const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
197 const unsigned char mx25l6436_rems_response[2] = {0xc2, 0x16};
198 const unsigned char w25q128fv_rems_response[2] = {0xef, 0x17};
199
200 if (writecnt == 0) {
201 msg_perr("No command sent to the chip!\n");
202 return 1;
203 }
204 /* spi_blacklist has precedence over spi_ignorelist. */
205 for (i = 0; i < data->spi_blacklist_size; i++) {
206 if (writearr[0] == data->spi_blacklist[i]) {
207 msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
208 data->spi_blacklist[i]);
209 return SPI_INVALID_OPCODE;
210 }
211 }
212 for (i = 0; i < data->spi_ignorelist_size; i++) {
213 if (writearr[0] == data->spi_ignorelist[i]) {
214 msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
215 data->spi_ignorelist[i]);
216 /* Return success because the command does not fail,
217 * it is simply ignored.
218 */
219 return 0;
220 }
221 }
222
223 if (data->emu_max_aai_size && (data->emu_status & SPI_SR_AAI)) {
224 if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
225 writearr[0] != JEDEC_WRDI &&
226 writearr[0] != JEDEC_RDSR) {
227 msg_perr("Forbidden opcode (0x%02x) attempted during "
228 "AAI sequence!\n", writearr[0]);
229 return 0;
230 }
231 }
232
233 switch (writearr[0]) {
234 case JEDEC_RES:
235 if (writecnt < JEDEC_RES_OUTSIZE)
236 break;
237 /* offs calculation is only needed for SST chips which treat RES like REMS. */
238 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
239 offs += writecnt - JEDEC_REMS_OUTSIZE;
240 switch (data->emu_chip) {
241 case EMULATE_ST_M25P10_RES:
242 if (readcnt > 0)
243 memset(readarr, 0x10, readcnt);
244 break;
245 case EMULATE_SST_SST25VF040_REMS:
246 for (i = 0; i < readcnt; i++)
247 readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
248 break;
249 case EMULATE_SST_SST25VF032B:
250 for (i = 0; i < readcnt; i++)
251 readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
252 break;
253 case EMULATE_MACRONIX_MX25L6436:
254 if (readcnt > 0)
255 memset(readarr, 0x16, readcnt);
256 break;
257 case EMULATE_WINBOND_W25Q128FV:
258 if (readcnt > 0)
259 memset(readarr, 0x17, readcnt);
260 break;
261 default: /* ignore */
262 break;
263 }
264 break;
265 case JEDEC_REMS:
266 /* REMS response has wraparound and uses an address parameter. */
267 if (writecnt < JEDEC_REMS_OUTSIZE)
268 break;
269 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
270 offs += writecnt - JEDEC_REMS_OUTSIZE;
271 switch (data->emu_chip) {
272 case EMULATE_SST_SST25VF040_REMS:
273 for (i = 0; i < readcnt; i++)
274 readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
275 break;
276 case EMULATE_SST_SST25VF032B:
277 for (i = 0; i < readcnt; i++)
278 readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
279 break;
280 case EMULATE_MACRONIX_MX25L6436:
281 for (i = 0; i < readcnt; i++)
282 readarr[i] = mx25l6436_rems_response[(offs + i) % 2];
283 break;
284 case EMULATE_WINBOND_W25Q128FV:
285 for (i = 0; i < readcnt; i++)
286 readarr[i] = w25q128fv_rems_response[(offs + i) % 2];
287 break;
288 default: /* ignore */
289 break;
290 }
291 break;
292 case JEDEC_RDID:
293 switch (data->emu_chip) {
294 case EMULATE_SST_SST25VF032B:
295 if (readcnt > 0)
296 readarr[0] = 0xbf;
297 if (readcnt > 1)
298 readarr[1] = 0x25;
299 if (readcnt > 2)
300 readarr[2] = 0x4a;
301 break;
302 case EMULATE_MACRONIX_MX25L6436:
303 if (readcnt > 0)
304 readarr[0] = 0xc2;
305 if (readcnt > 1)
306 readarr[1] = 0x20;
307 if (readcnt > 2)
308 readarr[2] = 0x17;
309 break;
310 case EMULATE_WINBOND_W25Q128FV:
311 if (readcnt > 0)
312 readarr[0] = 0xef;
313 if (readcnt > 1)
314 readarr[1] = 0x40;
315 if (readcnt > 2)
316 readarr[2] = 0x18;
317 break;
318 case EMULATE_VARIABLE_SIZE:
319 if (readcnt > 0)
320 readarr[0] = (PROGMANUF_ID >> 8) & 0xff;
321 if (readcnt > 1)
322 readarr[1] = PROGMANUF_ID & 0xff;
323 if (readcnt > 2)
324 readarr[2] = (PROGDEV_ID >> 8) & 0xff;
325 if (readcnt > 3)
326 readarr[3] = PROGDEV_ID & 0xff;
327 break;
328 default: /* ignore */
329 break;
330 }
331 break;
332 case JEDEC_RDSR:
333 memset(readarr, data->emu_status, readcnt);
334 break;
335 /* FIXME: this should be chip-specific. */
336 case JEDEC_EWSR:
337 case JEDEC_WREN:
338 data->emu_status |= SPI_SR_WEL;
339 break;
340 case JEDEC_WRSR:
341 if (!(data->emu_status & SPI_SR_WEL)) {
342 msg_perr("WRSR attempted, but WEL is 0!\n");
343 break;
344 }
345 /* FIXME: add some reasonable simulation of the busy flag */
346 data->emu_status = writearr[1] & ~SPI_SR_WIP;
347 msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status);
348 break;
349 case JEDEC_READ:
350 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
351 /* Truncate to emu_chip_size. */
352 offs %= data->emu_chip_size;
353 if (readcnt > 0)
354 memcpy(readarr, flashchip_contents + offs, readcnt);
355 break;
356 case JEDEC_READ_4BA:
357 offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
358 /* Truncate to emu_chip_size. */
359 offs %= data->emu_chip_size;
360 if (readcnt > 0)
361 memcpy(readarr, flashchip_contents + offs, readcnt);
362 break;
363 case JEDEC_BYTE_PROGRAM:
364 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
365 /* Truncate to emu_chip_size. */
366 offs %= data->emu_chip_size;
367 if (writecnt < 5) {
368 msg_perr("BYTE PROGRAM size too short!\n");
369 return 1;
370 }
371 if (writecnt - 4 > data->emu_max_byteprogram_size) {
372 msg_perr("Max BYTE PROGRAM size exceeded!\n");
373 return 1;
374 }
375 memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
376 data->emu_modified = 1;
377 break;
378 case JEDEC_BYTE_PROGRAM_4BA:
379 offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
380 /* Truncate to emu_chip_size. */
381 offs %= data->emu_chip_size;
382 if (writecnt < 6) {
383 msg_perr("BYTE PROGRAM size too short!\n");
384 return 1;
385 }
386 if (writecnt - 5 > data->emu_max_byteprogram_size) {
387 msg_perr("Max BYTE PROGRAM size exceeded!\n");
388 return 1;
389 }
390 memcpy(flashchip_contents + offs, writearr + 5, writecnt - 5);
391 data->emu_modified = 1;
392 break;
393 case JEDEC_AAI_WORD_PROGRAM:
394 if (!data->emu_max_aai_size)
395 break;
396 if (!(data->emu_status & SPI_SR_AAI)) {
397 if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
398 msg_perr("Initial AAI WORD PROGRAM size too "
399 "short!\n");
400 return 1;
401 }
402 if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
403 msg_perr("Initial AAI WORD PROGRAM size too "
404 "long!\n");
405 return 1;
406 }
407 data->emu_status |= SPI_SR_AAI;
408 aai_offs = writearr[1] << 16 | writearr[2] << 8 |
409 writearr[3];
410 /* Truncate to emu_chip_size. */
411 aai_offs %= data->emu_chip_size;
412 memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
413 aai_offs += 2;
414 } else {
415 if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
416 msg_perr("Continuation AAI WORD PROGRAM size "
417 "too short!\n");
418 return 1;
419 }
420 if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
421 msg_perr("Continuation AAI WORD PROGRAM size "
422 "too long!\n");
423 return 1;
424 }
425 memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
426 aai_offs += 2;
427 }
428 data->emu_modified = 1;
429 break;
430 case JEDEC_WRDI:
431 if (data->emu_max_aai_size)
432 data->emu_status &= ~SPI_SR_AAI;
433 break;
434 case JEDEC_SE:
435 if (!data->emu_jedec_se_size)
436 break;
437 if (writecnt != JEDEC_SE_OUTSIZE) {
438 msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
439 return 1;
440 }
441 if (readcnt != JEDEC_SE_INSIZE) {
442 msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
443 return 1;
444 }
445 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
446 if (offs & (data->emu_jedec_se_size - 1))
447 msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
448 offs &= ~(data->emu_jedec_se_size - 1);
449 memset(flashchip_contents + offs, 0xff, data->emu_jedec_se_size);
450 data->emu_modified = 1;
451 break;
452 case JEDEC_BE_52:
453 if (!data->emu_jedec_be_52_size)
454 break;
455 if (writecnt != JEDEC_BE_52_OUTSIZE) {
456 msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
457 return 1;
458 }
459 if (readcnt != JEDEC_BE_52_INSIZE) {
460 msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
461 return 1;
462 }
463 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
464 if (offs & (data->emu_jedec_be_52_size - 1))
465 msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
466 offs &= ~(data->emu_jedec_be_52_size - 1);
467 memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_52_size);
468 data->emu_modified = 1;
469 break;
470 case JEDEC_BE_D8:
471 if (!data->emu_jedec_be_d8_size)
472 break;
473 if (writecnt != JEDEC_BE_D8_OUTSIZE) {
474 msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
475 return 1;
476 }
477 if (readcnt != JEDEC_BE_D8_INSIZE) {
478 msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
479 return 1;
480 }
481 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
482 if (offs & (data->emu_jedec_be_d8_size - 1))
483 msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
484 offs &= ~(data->emu_jedec_be_d8_size - 1);
485 memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_d8_size);
486 data->emu_modified = 1;
487 break;
488 case JEDEC_CE_60:
489 if (!data->emu_jedec_ce_60_size)
490 break;
491 if (writecnt != JEDEC_CE_60_OUTSIZE) {
492 msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
493 return 1;
494 }
495 if (readcnt != JEDEC_CE_60_INSIZE) {
496 msg_perr("CHIP ERASE 0x60 insize invalid!\n");
497 return 1;
498 }
499 /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
500 /* emu_jedec_ce_60_size is emu_chip_size. */
501 memset(flashchip_contents, 0xff, data->emu_jedec_ce_60_size);
502 data->emu_modified = 1;
503 break;
504 case JEDEC_CE_C7:
505 if (!data->emu_jedec_ce_c7_size)
506 break;
507 if (writecnt != JEDEC_CE_C7_OUTSIZE) {
508 msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
509 return 1;
510 }
511 if (readcnt != JEDEC_CE_C7_INSIZE) {
512 msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
513 return 1;
514 }
515 /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
516 /* emu_jedec_ce_c7_size is emu_chip_size. */
517 memset(flashchip_contents, 0xff, data->emu_jedec_ce_c7_size);
518 data->emu_modified = 1;
519 break;
520 case JEDEC_SFDP:
521 if (data->emu_chip != EMULATE_MACRONIX_MX25L6436)
522 break;
523 if (writecnt < 4)
524 break;
525 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
526
527 /* SFDP expects one dummy byte after the address. */
528 if (writecnt == 4) {
529 /* The dummy byte was not written, make sure it is read instead.
530 * Shifting and shortening the read array does achieve this goal.
531 */
532 readarr++;
533 readcnt--;
534 } else {
535 /* The response is shifted if more than 5 bytes are written, because SFDP data is
536 * already shifted out by the chip while those superfluous bytes are written. */
537 offs += writecnt - 5;
538 }
539
540 /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
541 * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
542 * This is a reasonable implementation choice in hardware because it saves a few gates. */
543 if (offs >= sizeof(sfdp_table)) {
544 msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
545 "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
546 offs %= sizeof(sfdp_table);
547 }
548 toread = min(sizeof(sfdp_table) - offs, readcnt);
549 memcpy(readarr, sfdp_table + offs, toread);
550 if (toread < readcnt)
551 msg_pdbg("Crossing the SFDP table boundary in a single "
552 "continuous chunk produces undefined results "
553 "after that point.\n");
554 break;
555 default:
556 /* No special response. */
557 break;
558 }
559 if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
560 data->emu_status &= ~SPI_SR_WEL;
561 return 0;
562}
563#endif
564
565static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
566 unsigned int readcnt,
567 const unsigned char *writearr,
568 unsigned char *readarr)
569{
570 unsigned int i;
571 struct emu_data *emu_data = get_data_from_context(flash);
572 if (!emu_data) {
573 msg_perr("No data in flash context!\n");
574 return 1;
575 }
576
577 msg_pspew("%s:", __func__);
578
579 msg_pspew(" writing %u bytes:", writecnt);
580 for (i = 0; i < writecnt; i++)
581 msg_pspew(" 0x%02x", writearr[i]);
582
583 /* Response for unknown commands and missing chip is 0xff. */
584 memset(readarr, 0xff, readcnt);
585#if EMULATE_SPI_CHIP
586 switch (emu_data->emu_chip) {
587 case EMULATE_ST_M25P10_RES:
588 case EMULATE_SST_SST25VF040_REMS:
589 case EMULATE_SST_SST25VF032B:
590 case EMULATE_MACRONIX_MX25L6436:
591 case EMULATE_WINBOND_W25Q128FV:
592 case EMULATE_VARIABLE_SIZE:
593 if (emulate_spi_chip_response(writecnt, readcnt, writearr,
594 readarr, emu_data)) {
595 msg_pdbg("Invalid command sent to flash chip!\n");
596 return 1;
597 }
598 break;
599 default:
600 break;
601 }
602#endif
603 msg_pspew(" reading %u bytes:", readcnt);
604 for (i = 0; i < readcnt; i++)
605 msg_pspew(" 0x%02x", readarr[i]);
606 msg_pspew("\n");
607
608 programmer_delay((writecnt + readcnt) * emu_data->delay_us);
609 return 0;
610}
611
612
Michael Karcherb9dbe482011-05-11 17:07:07 +0000613
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000614static struct spi_master spi_master_dummyflasher = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100615 .features = SPI_MASTER_4BA,
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000616 .max_data_read = MAX_DATA_READ_UNLIMITED,
617 .max_data_write = MAX_DATA_UNSPECIFIED,
618 .command = dummy_spi_send_command,
619 .multicommand = default_spi_send_multicommand,
620 .read = default_spi_read,
621 .write_256 = dummy_spi_write_256,
Nico Huber7bca1262012-06-15 22:28:12 +0000622 .write_aai = default_spi_write_aai,
Michael Karcherb9dbe482011-05-11 17:07:07 +0000623};
David Hendricks8bb20212011-06-14 01:35:36 +0000624
Namyoon Woof7a08a82020-10-17 20:25:15 -0700625static struct par_master par_master_dummy = {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000626 .chip_readb = dummy_chip_readb,
627 .chip_readw = dummy_chip_readw,
628 .chip_readl = dummy_chip_readl,
629 .chip_readn = dummy_chip_readn,
630 .chip_writeb = dummy_chip_writeb,
631 .chip_writew = dummy_chip_writew,
632 .chip_writel = dummy_chip_writel,
633 .chip_writen = dummy_chip_writen,
634};
635
David Hendricks8bb20212011-06-14 01:35:36 +0000636static int dummy_shutdown(void *data)
637{
638 msg_pspew("%s\n", __func__);
639#if EMULATE_CHIP
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000640 struct emu_data *emu_data = (struct emu_data *)data;
641 if (emu_data->emu_chip != EMULATE_NONE) {
642 if (emu_data->emu_persistent_image && emu_data->emu_modified) {
643 msg_pdbg("Writing %s\n", emu_data->emu_persistent_image);
644 write_buf_to_file(flashchip_contents,
645 emu_data->emu_chip_size,
646 emu_data->emu_persistent_image);
647 free(emu_data->emu_persistent_image);
648 emu_data->emu_persistent_image = NULL;
David Hendricks8bb20212011-06-14 01:35:36 +0000649 }
650 free(flashchip_contents);
651 }
652#endif
Anastasia Klimchuk99100952021-04-21 07:55:21 +1000653 free(data);
David Hendricks8bb20212011-06-14 01:35:36 +0000654 return 0;
655}
656
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +0000657int dummy_init(void)
658{
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000659 char *bustext = NULL;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000660 char *tmp = NULL;
Nico Huber519be662018-12-23 20:03:35 +0100661 unsigned int i;
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000662#if EMULATE_SPI_CHIP
663 char *status = NULL;
Namyoon Woof7a08a82020-10-17 20:25:15 -0700664 int size = -1; /* size for VARIABLE_SIZE chip device */
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000665#endif
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000666#if EMULATE_CHIP
667 struct stat image_stat;
668#endif
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000669
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000670 struct emu_data *data = calloc(1, sizeof(struct emu_data));
671 if (!data) {
672 msg_perr("Out of memory!\n");
673 return 1;
674 }
675 data->emu_chip = EMULATE_NONE;
Edward O'Callaghancb9f3cd2020-09-17 13:32:00 +1000676 data->delay_us = 0;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000677 spi_master_dummyflasher.data = data;
Namyoon Woof7a08a82020-10-17 20:25:15 -0700678 par_master_dummy.data = data;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000679
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000680 msg_pspew("%s\n", __func__);
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000681
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000682 bustext = extract_programmer_param("bus");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000683 msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
684 if (!bustext)
685 bustext = strdup("parallel+lpc+fwh+spi");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000686 /* Convert the parameters to lowercase. */
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000687 tolower_string(bustext);
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000688
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000689 dummy_buses_supported = BUS_NONE;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000690 if (strstr(bustext, "parallel")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000691 dummy_buses_supported |= BUS_PARALLEL;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000692 msg_pdbg("Enabling support for %s flash.\n", "parallel");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000693 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000694 if (strstr(bustext, "lpc")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000695 dummy_buses_supported |= BUS_LPC;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000696 msg_pdbg("Enabling support for %s flash.\n", "LPC");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000697 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000698 if (strstr(bustext, "fwh")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000699 dummy_buses_supported |= BUS_FWH;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000700 msg_pdbg("Enabling support for %s flash.\n", "FWH");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000701 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000702 if (strstr(bustext, "spi")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000703 dummy_buses_supported |= BUS_SPI;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000704 msg_pdbg("Enabling support for %s flash.\n", "SPI");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000705 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000706 if (dummy_buses_supported == BUS_NONE)
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000707 msg_pdbg("Support for all flash bus types disabled.\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000708 free(bustext);
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000709
710 tmp = extract_programmer_param("spi_write_256_chunksize");
711 if (tmp) {
712 spi_write_256_chunksize = atoi(tmp);
713 free(tmp);
714 if (spi_write_256_chunksize < 1) {
715 msg_perr("invalid spi_write_256_chunksize\n");
716 return 1;
717 }
718 }
719
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000720 tmp = extract_programmer_param("spi_blacklist");
721 if (tmp) {
722 i = strlen(tmp);
723 if (!strncmp(tmp, "0x", 2)) {
724 i -= 2;
725 memmove(tmp, tmp + 2, i + 1);
726 }
727 if ((i > 512) || (i % 2)) {
728 msg_perr("Invalid SPI command blacklist length\n");
729 free(tmp);
730 return 1;
731 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000732 data->spi_blacklist_size = i / 2;
733 for (i = 0; i < data->spi_blacklist_size * 2; i++) {
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000734 if (!isxdigit((unsigned char)tmp[i])) {
735 msg_perr("Invalid char \"%c\" in SPI command "
736 "blacklist\n", tmp[i]);
737 free(tmp);
738 return 1;
739 }
740 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000741 for (i = 0; i < data->spi_blacklist_size; i++) {
Carl-Daniel Hailfinger5b554712012-02-16 01:43:06 +0000742 unsigned int tmp2;
743 /* SCNx8 is apparently not supported by MSVC (and thus
744 * MinGW), so work around it with an extra variable
745 */
746 sscanf(tmp + i * 2, "%2x", &tmp2);
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000747 data->spi_blacklist[i] = (uint8_t)tmp2;
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000748 }
749 msg_pdbg("SPI blacklist is ");
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000750 for (i = 0; i < data->spi_blacklist_size; i++)
751 msg_pdbg("%02x ", data->spi_blacklist[i]);
752 msg_pdbg(", size %u\n", data->spi_blacklist_size);
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000753 }
754 free(tmp);
755
756 tmp = extract_programmer_param("spi_ignorelist");
757 if (tmp) {
758 i = strlen(tmp);
759 if (!strncmp(tmp, "0x", 2)) {
760 i -= 2;
761 memmove(tmp, tmp + 2, i + 1);
762 }
763 if ((i > 512) || (i % 2)) {
764 msg_perr("Invalid SPI command ignorelist length\n");
765 free(tmp);
766 return 1;
767 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000768 data->spi_ignorelist_size = i / 2;
769 for (i = 0; i < data->spi_ignorelist_size * 2; i++) {
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000770 if (!isxdigit((unsigned char)tmp[i])) {
771 msg_perr("Invalid char \"%c\" in SPI command "
772 "ignorelist\n", tmp[i]);
773 free(tmp);
774 return 1;
775 }
776 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000777 for (i = 0; i < data->spi_ignorelist_size; i++) {
Carl-Daniel Hailfinger5b554712012-02-16 01:43:06 +0000778 unsigned int tmp2;
779 /* SCNx8 is apparently not supported by MSVC (and thus
780 * MinGW), so work around it with an extra variable
781 */
782 sscanf(tmp + i * 2, "%2x", &tmp2);
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000783 data->spi_ignorelist[i] = (uint8_t)tmp2;
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000784 }
785 msg_pdbg("SPI ignorelist is ");
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000786 for (i = 0; i < data->spi_ignorelist_size; i++)
787 msg_pdbg("%02x ", data->spi_ignorelist[i]);
788 msg_pdbg(", size %u\n", data->spi_ignorelist_size);
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000789 }
790 free(tmp);
791
Edward O'Callaghancb9f3cd2020-09-17 13:32:00 +1000792 /* frequency to emulate in Hz (default), KHz, or MHz */
793 tmp = extract_programmer_param("freq");
794 if (tmp) {
795 unsigned long int freq;
796 char *units = tmp;
797 char *end = tmp + strlen(tmp);
798
799 errno = 0;
800 freq = strtoul(tmp, &units, 0);
801 if (errno) {
802 msg_perr("Invalid frequency \"%s\", %s\n",
803 tmp, strerror(errno));
804 free(tmp);
805 return 1;
806 }
807
808 if ((units > tmp) && (units < end)) {
809 int units_valid = 0;
810
811 if (units < end - 3) {
812 ;
813 } else if (units == end - 2) {
814 if (!strcasecmp(units, "hz"))
815 units_valid = 1;
816 } else if (units == end - 3) {
817 if (!strcasecmp(units, "khz")) {
818 freq *= 1000;
819 units_valid = 1;
820 } else if (!strcasecmp(units, "mhz")) {
821 freq *= 1000000;
822 units_valid = 1;
823 }
824 }
825
826 if (!units_valid) {
827 msg_perr("Invalid units: %s\n", units);
828 free(tmp);
829 return 1;
830 }
831 }
832
833 /* Assume we only work with bytes and transfer at 1 bit/Hz */
834 data->delay_us = (1000000 * 8) / freq;
835 }
836 free(tmp);
837
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000838#if EMULATE_CHIP
Namyoon Woo31498222020-08-27 16:03:16 -0700839#if EMULATE_SPI_CHIP
840 tmp = extract_programmer_param("size");
841 if (tmp) {
Namyoon Woof7a08a82020-10-17 20:25:15 -0700842 size = strtol(tmp, NULL, 10);
Namyoon Woo31498222020-08-27 16:03:16 -0700843 if (size <= 0 || (size % 1024 != 0)) {
844 msg_perr("%s: Chip size is not a multipler of 1024: %s\n",
845 __func__, tmp);
846 free(tmp);
847 return 1;
848 }
849 free(tmp);
Namyoon Woo31498222020-08-27 16:03:16 -0700850 }
851#endif
852
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000853 tmp = extract_programmer_param("emulate");
854 if (!tmp) {
855 msg_pdbg("Not emulating any flash chip.\n");
856 /* Nothing else to do. */
David Hendricks8bb20212011-06-14 01:35:36 +0000857 goto dummy_init_out;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000858 }
859#if EMULATE_SPI_CHIP
860 if (!strcmp(tmp, "M25P10.RES")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000861 data->emu_chip = EMULATE_ST_M25P10_RES;
862 data->emu_chip_size = 128 * 1024;
863 data->emu_max_byteprogram_size = 128;
864 data->emu_max_aai_size = 0;
865 data->emu_jedec_se_size = 0;
866 data->emu_jedec_be_52_size = 0;
867 data->emu_jedec_be_d8_size = 32 * 1024;
868 data->emu_jedec_ce_60_size = 0;
869 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000870 msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
871 "write)\n");
872 }
873 if (!strcmp(tmp, "SST25VF040.REMS")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000874 data->emu_chip = EMULATE_SST_SST25VF040_REMS;
875 data->emu_chip_size = 512 * 1024;
876 data->emu_max_byteprogram_size = 1;
877 data->emu_max_aai_size = 0;
878 data->emu_jedec_se_size = 4 * 1024;
879 data->emu_jedec_be_52_size = 32 * 1024;
880 data->emu_jedec_be_d8_size = 0;
881 data->emu_jedec_ce_60_size = data->emu_chip_size;
882 data->emu_jedec_ce_c7_size = 0;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000883 msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
884 "byte write)\n");
885 }
886 if (!strcmp(tmp, "SST25VF032B")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000887 data->emu_chip = EMULATE_SST_SST25VF032B;
888 data->emu_chip_size = 4 * 1024 * 1024;
889 data->emu_max_byteprogram_size = 1;
890 data->emu_max_aai_size = 2;
891 data->emu_jedec_se_size = 4 * 1024;
892 data->emu_jedec_be_52_size = 32 * 1024;
893 data->emu_jedec_be_d8_size = 64 * 1024;
894 data->emu_jedec_ce_60_size = data->emu_chip_size;
895 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000896 msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
897 "write)\n");
898 }
Stefan Tauner0b9df972012-05-07 22:12:16 +0000899 if (!strcmp(tmp, "MX25L6436")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000900 data->emu_chip = EMULATE_MACRONIX_MX25L6436;
901 data->emu_chip_size = 8 * 1024 * 1024;
902 data->emu_max_byteprogram_size = 256;
903 data->emu_max_aai_size = 0;
904 data->emu_jedec_se_size = 4 * 1024;
905 data->emu_jedec_be_52_size = 32 * 1024;
906 data->emu_jedec_be_d8_size = 64 * 1024;
907 data->emu_jedec_ce_60_size = data->emu_chip_size;
908 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Stefan Tauner0b9df972012-05-07 22:12:16 +0000909 msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
910 "SFDP)\n");
911 }
Nico Huberf9632d82019-01-20 11:23:49 +0100912 if (!strcmp(tmp, "W25Q128FV")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000913 data->emu_chip = EMULATE_WINBOND_W25Q128FV;
914 data->emu_chip_size = 16 * 1024 * 1024;
915 data->emu_max_byteprogram_size = 256;
916 data->emu_max_aai_size = 0;
917 data->emu_jedec_se_size = 4 * 1024;
918 data->emu_jedec_be_52_size = 32 * 1024;
919 data->emu_jedec_be_d8_size = 64 * 1024;
920 data->emu_jedec_ce_60_size = data->emu_chip_size;
921 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Nico Huberf9632d82019-01-20 11:23:49 +0100922 msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID)\n");
923 }
Namyoon Woo31498222020-08-27 16:03:16 -0700924
925 /* The name of variable-size virtual chip. A 4 MiB flash example:
926 * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
927 */
928 if (!strcmp(tmp, "VARIABLE_SIZE")) {
Namyoon Woof7a08a82020-10-17 20:25:15 -0700929 if (size == -1) {
930 msg_perr("%s: the size parameter is not given.\n", __func__);
931 free(tmp);
932 return 1;
933 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000934 data->emu_chip = EMULATE_VARIABLE_SIZE;
935 data->emu_chip_size = size;
936 data->emu_max_byteprogram_size = 256;
937 data->emu_max_aai_size = 0;
938 data->emu_jedec_se_size = 4 * 1024;
939 data->emu_jedec_be_52_size = 32 * 1024;
940 data->emu_jedec_be_d8_size = 64 * 1024;
941 data->emu_jedec_ce_60_size = data->emu_chip_size;
942 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Namyoon Woo31498222020-08-27 16:03:16 -0700943 msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000944 data->emu_chip_size);
Namyoon Woo31498222020-08-27 16:03:16 -0700945 }
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000946#endif
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000947 if (data->emu_chip == EMULATE_NONE) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000948 msg_perr("Invalid chip specified for emulation: %s\n", tmp);
949 free(tmp);
950 return 1;
951 }
952 free(tmp);
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +1100953
954 /* Should emulated flash erase to zero (yes/no)? */
955 tmp = extract_programmer_param("erase_to_zero");
956 if (tmp) {
957 if (!strcmp(tmp, "yes")) {
958 msg_pdbg("Emulated chip will erase to 0x00\n");
959 data->erase_to_zero = 1;
960 } else if (!strcmp(tmp, "no")) {
961 msg_pdbg("Emulated chip will erase to 0xff\n");
962 } else {
963 msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
964 free(tmp);
965 return 1;
966 }
967 }
968 free(tmp);
969
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000970 flashchip_contents = malloc(data->emu_chip_size);
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000971 if (!flashchip_contents) {
972 msg_perr("Out of memory!\n");
973 return 1;
974 }
David Hendricks8bb20212011-06-14 01:35:36 +0000975
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000976#ifdef EMULATE_SPI_CHIP
977 status = extract_programmer_param("spi_status");
978 if (status) {
979 char *endptr;
980 errno = 0;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000981 data->emu_status = strtoul(status, &endptr, 0);
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000982 free(status);
983 if (errno != 0 || status == endptr) {
984 msg_perr("Error: initial status register specified, "
985 "but the value could not be converted.\n");
986 return 1;
987 }
988 msg_pdbg("Initial status register is set to 0x%02x.\n",
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000989 data->emu_status);
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000990 }
991#endif
992
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +1100993 msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
994 data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
995 memset(flashchip_contents, data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000996
Stefan Taunerc2eec2c2014-05-03 21:33:01 +0000997 /* Will be freed by shutdown function if necessary. */
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000998 data->emu_persistent_image = extract_programmer_param("image");
999 if (!data->emu_persistent_image) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001000 /* Nothing else to do. */
David Hendricks8bb20212011-06-14 01:35:36 +00001001 goto dummy_init_out;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001002 }
Stefan Taunerc2eec2c2014-05-03 21:33:01 +00001003 /* We will silently (in default verbosity) ignore the file if it does not exist (yet) or the size does
1004 * not match the emulated chip. */
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001005 if (!stat(data->emu_persistent_image, &image_stat)) {
Stefan Tauner23e10b82016-01-23 16:16:49 +00001006 msg_pdbg("Found persistent image %s, %jd B ",
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001007 data->emu_persistent_image, (intmax_t)image_stat.st_size);
1008 if ((uintmax_t)image_stat.st_size == data->emu_chip_size) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001009 msg_pdbg("matches.\n");
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001010 msg_pdbg("Reading %s\n", data->emu_persistent_image);
1011 if (read_buf_from_file(flashchip_contents, data->emu_chip_size,
1012 data->emu_persistent_image)) {
1013 msg_perr("Unable to read %s\n", data->emu_persistent_image);
Jacob Garberca598da2019-08-12 10:44:17 -06001014 free(flashchip_contents);
1015 return 1;
1016 }
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001017 } else {
1018 msg_pdbg("doesn't match.\n");
1019 }
1020 }
1021#endif
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +00001022
David Hendricks8bb20212011-06-14 01:35:36 +00001023dummy_init_out:
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001024 if (register_shutdown(dummy_shutdown, data)) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001025 free(flashchip_contents);
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001026 free(data);
David Hendricks8bb20212011-06-14 01:35:36 +00001027 return 1;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001028 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +00001029 if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +00001030 register_par_master(&par_master_dummy,
1031 dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH));
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +00001032 if (dummy_buses_supported & BUS_SPI)
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +00001033 register_spi_master(&spi_master_dummyflasher);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +00001034
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +00001035 return 0;
1036}
1037
Namyoon Woo31498222020-08-27 16:03:16 -07001038#if EMULATE_CHIP && EMULATE_SPI_CHIP
1039int probe_variable_size(struct flashctx *flash)
1040{
1041 unsigned int i;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001042 const struct emu_data *emu_data = get_data_from_context(flash);
Namyoon Woo31498222020-08-27 16:03:16 -07001043
1044 /* Skip the probing if we don't emulate this chip. */
Angel Ponsc8df4012020-10-17 15:20:27 +02001045 if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE)
Namyoon Woo31498222020-08-27 16:03:16 -07001046 return 0;
1047
1048 /*
1049 * This will break if one day flashctx becomes read-only.
1050 * Once that happens, we need to have special hacks in functions:
1051 *
1052 * erase_and_write_flash() in flashrom.c
1053 * read_flash_to_file()
1054 * handle_romentries()
1055 * ...
1056 *
1057 * Search "total_size * 1024" in code.
1058 */
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001059 flash->chip->total_size = emu_data->emu_chip_size / 1024;
Namyoon Woo31498222020-08-27 16:03:16 -07001060 msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
1061 flash->chip->total_size);
1062
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +11001063 if (emu_data->erase_to_zero)
1064 flash->chip->feature_bits |= FEATURE_ERASED_ZERO;
1065
Namyoon Woo31498222020-08-27 16:03:16 -07001066 /* Update the first count of each of the block_erasers. */
1067 for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
1068 struct block_eraser *eraser = &flash->chip->block_erasers[i];
1069 if (!eraser->block_erase)
1070 break;
1071
Namyoon Woo79da18f2020-08-27 16:27:49 -07001072 eraser->eraseblocks[0].count = 1;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001073 eraser->eraseblocks[0].size = emu_data->emu_chip_size;
Namyoon Woo31498222020-08-27 16:03:16 -07001074 msg_cdbg("%s: eraser.size=%d, .count=%d\n",
1075 __func__, eraser->eraseblocks[0].size,
1076 eraser->eraseblocks[0].count);
1077 }
1078
1079 return 1;
1080}
1081#endif