blob: d434eec34c33dd02442909c1f2aa35f1765e6b2d [file] [log] [blame]
hailfingera9df33c2009-05-09 00:54:55 +00001/*
2 * This file is part of the flashrom project.
3 *
hailfinger6ead7222010-11-01 22:07:04 +00004 * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
hailfingera9df33c2009-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
hailfinger6ead7222010-11-01 22:07:04 +00008 * the Free Software Foundation; version 2 of the License.
hailfingera9df33c2009-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.
hailfingera9df33c2009-05-09 00:54:55 +000014 */
15
hailfingera9df33c2009-05-09 00:54:55 +000016#include <string.h>
17#include <stdlib.h>
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -070018#include <stdio.h>
19#include <ctype.h>
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +100020#include <errno.h>
hailfingera9df33c2009-05-09 00:54:55 +000021#include "flash.h"
hailfingera8727712010-06-20 10:58:32 +000022#include "chipdrivers.h"
hailfinger428f6852010-07-27 22:41:39 +000023#include "programmer.h"
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080024#include "flashchips.h"
hailfingera9df33c2009-05-09 00:54:55 +000025
hailfinger6ead7222010-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,
Stuart Langley78cacf72020-04-23 11:48:01 +100046 EMULATE_MACRONIX_MX25L6436,
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +100047 EMULATE_WINBOND_W25Q128FV,
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080048 EMULATE_VARIABLE_SIZE,
hailfinger6ead7222010-11-01 22:07:04 +000049};
Stuart Langley78cacf72020-04-23 11:48:01 +100050
Lachlan Bishopbf1476e2020-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;
55 int erase_to_zero;
56 int emu_modified; /* is the image modified since reading it? */
57 uint8_t emu_status;
Edward O'Callaghan0037f452020-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 Bishopbf1476e2020-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
Stuart Langley78cacf72020-04-23 11:48:01 +100075/* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
76static const uint8_t sfdp_table[] = {
77 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
hailfinger6ead7222010-11-01 22:07:04 +0000101#endif
102#endif
103
stefanctc5eb8a92011-11-23 09:13:48 +0000104static unsigned int spi_write_256_chunksize = 256;
Anastasia Klimchukcffc3a62021-02-15 14:57:56 +1100105static enum chipbustype dummy_buses_supported = BUS_NONE;
hailfinger6ead7222010-11-01 22:07:04 +0000106
Anastasia Klimchukcffc3a62021-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
mkarcherd264e9e2011-05-11 17:07:07 +0000613
Nico Huber2ef004f2021-05-11 17:53:34 +0200614static const struct spi_master spi_master_dummyflasher = {
Edward O'Callaghana6673bd2019-06-24 15:22:28 +1000615 .features = SPI_MASTER_4BA,
uwe8d342eb2011-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,
Edward O'Callaghaneeaac6b2020-10-12 19:51:56 +1100622 .write_aai = default_spi_write_aai,
mkarcherd264e9e2011-05-11 17:07:07 +0000623};
dhendrix0ffc2eb2011-06-14 01:35:36 +0000624
Namyoon Wooc429efb2020-10-17 20:25:15 -0700625static struct par_master par_master_dummy = {
hailfinger76bb7e92011-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 Hendricks93784b42016-08-09 17:00:38 -0700636static int dummy_shutdown(void *data)
dhendrix0ffc2eb2011-06-14 01:35:36 +0000637{
638 msg_pspew("%s\n", __func__);
639#if EMULATE_CHIP
Lachlan Bishopbf1476e2020-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;
dhendrix0ffc2eb2011-06-14 01:35:36 +0000649 }
650 free(flashchip_contents);
651 }
652#endif
Anastasia Klimchukf3036662021-04-21 07:55:21 +1000653 free(data);
dhendrix0ffc2eb2011-06-14 01:35:36 +0000654 return 0;
655}
656
David Hendricksac1d25c2016-08-09 17:00:58 -0700657int dummy_init(void)
hailfingera9df33c2009-05-09 00:54:55 +0000658{
hailfinger1ef766d2010-07-06 09:55:48 +0000659 char *bustext = NULL;
hailfinger6ead7222010-11-01 22:07:04 +0000660 char *tmp = NULL;
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000661 unsigned int i;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800662#if EMULATE_SPI_CHIP
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000663 char *status = NULL;
Edward O'Callaghan602fbab2020-11-23 12:27:57 +1100664 int size = -1; /* size for VARIABLE_SIZE chip device */
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800665#endif
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000666#if EMULATE_CHIP
667 struct stat image_stat;
hailfinger6ead7222010-11-01 22:07:04 +0000668#endif
hailfinger1ef766d2010-07-06 09:55:48 +0000669
Lachlan Bishopbf1476e2020-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'Callaghan0037f452020-09-17 13:32:00 +1000676 data->delay_us = 0;
Namyoon Wooc429efb2020-10-17 20:25:15 -0700677 par_master_dummy.data = data;
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000678
hailfinger50c335f2010-01-09 04:32:23 +0000679 msg_pspew("%s\n", __func__);
hailfinger668f3502009-06-01 00:02:11 +0000680
hailfingerddeb4ac2010-07-08 10:13:37 +0000681 bustext = extract_programmer_param("bus");
hailfinger1ef766d2010-07-06 09:55:48 +0000682 msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
683 if (!bustext)
684 bustext = strdup("parallel+lpc+fwh+spi");
hailfinger668f3502009-06-01 00:02:11 +0000685 /* Convert the parameters to lowercase. */
hailfinger1ef766d2010-07-06 09:55:48 +0000686 tolower_string(bustext);
hailfinger668f3502009-06-01 00:02:11 +0000687
hailfinger76bb7e92011-11-09 23:40:00 +0000688 dummy_buses_supported = BUS_NONE;
hailfinger1ef766d2010-07-06 09:55:48 +0000689 if (strstr(bustext, "parallel")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000690 dummy_buses_supported |= BUS_PARALLEL;
hailfinger50c335f2010-01-09 04:32:23 +0000691 msg_pdbg("Enabling support for %s flash.\n", "parallel");
hailfinger668f3502009-06-01 00:02:11 +0000692 }
hailfinger1ef766d2010-07-06 09:55:48 +0000693 if (strstr(bustext, "lpc")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000694 dummy_buses_supported |= BUS_LPC;
hailfinger50c335f2010-01-09 04:32:23 +0000695 msg_pdbg("Enabling support for %s flash.\n", "LPC");
hailfinger668f3502009-06-01 00:02:11 +0000696 }
hailfinger1ef766d2010-07-06 09:55:48 +0000697 if (strstr(bustext, "fwh")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000698 dummy_buses_supported |= BUS_FWH;
hailfinger50c335f2010-01-09 04:32:23 +0000699 msg_pdbg("Enabling support for %s flash.\n", "FWH");
hailfinger668f3502009-06-01 00:02:11 +0000700 }
hailfinger1ef766d2010-07-06 09:55:48 +0000701 if (strstr(bustext, "spi")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000702 dummy_buses_supported |= BUS_SPI;
hailfinger50c335f2010-01-09 04:32:23 +0000703 msg_pdbg("Enabling support for %s flash.\n", "SPI");
hailfinger668f3502009-06-01 00:02:11 +0000704 }
hailfinger76bb7e92011-11-09 23:40:00 +0000705 if (dummy_buses_supported == BUS_NONE)
hailfinger50c335f2010-01-09 04:32:23 +0000706 msg_pdbg("Support for all flash bus types disabled.\n");
hailfinger1ef766d2010-07-06 09:55:48 +0000707 free(bustext);
hailfinger6ead7222010-11-01 22:07:04 +0000708
709 tmp = extract_programmer_param("spi_write_256_chunksize");
710 if (tmp) {
711 spi_write_256_chunksize = atoi(tmp);
712 free(tmp);
713 if (spi_write_256_chunksize < 1) {
714 msg_perr("invalid spi_write_256_chunksize\n");
715 return 1;
716 }
717 }
718
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700719 tmp = extract_programmer_param("spi_blacklist");
720 if (tmp) {
721 i = strlen(tmp);
722 if (!strncmp(tmp, "0x", 2)) {
723 i -= 2;
724 memmove(tmp, tmp + 2, i + 1);
725 }
726 if ((i > 512) || (i % 2)) {
727 msg_perr("Invalid SPI command blacklist length\n");
728 free(tmp);
729 return 1;
730 }
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000731 data->spi_blacklist_size = i / 2;
732 for (i = 0; i < data->spi_blacklist_size * 2; i++) {
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700733 if (!isxdigit((unsigned char)tmp[i])) {
734 msg_perr("Invalid char \"%c\" in SPI command "
735 "blacklist\n", tmp[i]);
736 free(tmp);
737 return 1;
738 }
739 }
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000740 for (i = 0; i < data->spi_blacklist_size; i++) {
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700741 unsigned int tmp2;
742 /* SCNx8 is apparently not supported by MSVC (and thus
743 * MinGW), so work around it with an extra variable
744 */
745 sscanf(tmp + i * 2, "%2x", &tmp2);
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000746 data->spi_blacklist[i] = (uint8_t)tmp2;
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700747 }
748 msg_pdbg("SPI blacklist is ");
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000749 for (i = 0; i < data->spi_blacklist_size; i++)
750 msg_pdbg("%02x ", data->spi_blacklist[i]);
751 msg_pdbg(", size %u\n", data->spi_blacklist_size);
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700752 }
753 free(tmp);
754
755 tmp = extract_programmer_param("spi_ignorelist");
756 if (tmp) {
757 i = strlen(tmp);
758 if (!strncmp(tmp, "0x", 2)) {
759 i -= 2;
760 memmove(tmp, tmp + 2, i + 1);
761 }
762 if ((i > 512) || (i % 2)) {
763 msg_perr("Invalid SPI command ignorelist length\n");
764 free(tmp);
765 return 1;
766 }
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000767 data->spi_ignorelist_size = i / 2;
768 for (i = 0; i < data->spi_ignorelist_size * 2; i++) {
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700769 if (!isxdigit((unsigned char)tmp[i])) {
770 msg_perr("Invalid char \"%c\" in SPI command "
771 "ignorelist\n", tmp[i]);
772 free(tmp);
773 return 1;
774 }
775 }
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000776 for (i = 0; i < data->spi_ignorelist_size; i++) {
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700777 unsigned int tmp2;
778 /* SCNx8 is apparently not supported by MSVC (and thus
779 * MinGW), so work around it with an extra variable
780 */
781 sscanf(tmp + i * 2, "%2x", &tmp2);
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000782 data->spi_ignorelist[i] = (uint8_t)tmp2;
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700783 }
784 msg_pdbg("SPI ignorelist is ");
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000785 for (i = 0; i < data->spi_ignorelist_size; i++)
786 msg_pdbg("%02x ", data->spi_ignorelist[i]);
787 msg_pdbg(", size %u\n", data->spi_ignorelist_size);
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700788 }
789 free(tmp);
790
David Hendricks84377002014-09-09 16:09:31 -0700791 /* frequency to emulate in Hz (default), KHz, or MHz */
792 tmp = extract_programmer_param("freq");
793 if (tmp) {
794 unsigned long int freq;
795 char *units = tmp;
796 char *end = tmp + strlen(tmp);
797
798 errno = 0;
799 freq = strtoul(tmp, &units, 0);
800 if (errno) {
801 msg_perr("Invalid frequency \"%s\", %s\n",
802 tmp, strerror(errno));
Edward O'Callaghan0037f452020-09-17 13:32:00 +1000803 free(tmp);
804 return 1;
David Hendricks84377002014-09-09 16:09:31 -0700805 }
806
807 if ((units > tmp) && (units < end)) {
808 int units_valid = 0;
809
810 if (units < end - 3) {
811 ;
812 } else if (units == end - 2) {
813 if (!strcasecmp(units, "hz"))
814 units_valid = 1;
815 } else if (units == end - 3) {
816 if (!strcasecmp(units, "khz")) {
817 freq *= 1000;
818 units_valid = 1;
819 } else if (!strcasecmp(units, "mhz")) {
820 freq *= 1000000;
821 units_valid = 1;
822 }
823 }
824
825 if (!units_valid) {
826 msg_perr("Invalid units: %s\n", units);
Edward O'Callaghan0037f452020-09-17 13:32:00 +1000827 free(tmp);
David Hendricks84377002014-09-09 16:09:31 -0700828 return 1;
829 }
830 }
831
832 /* Assume we only work with bytes and transfer at 1 bit/Hz */
Edward O'Callaghan0037f452020-09-17 13:32:00 +1000833 data->delay_us = (1000000 * 8) / freq;
David Hendricks84377002014-09-09 16:09:31 -0700834 }
Edward O'Callaghan0037f452020-09-17 13:32:00 +1000835 free(tmp);
David Hendricks84377002014-09-09 16:09:31 -0700836
hailfinger6ead7222010-11-01 22:07:04 +0000837#if EMULATE_CHIP
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800838#if EMULATE_SPI_CHIP
839 tmp = extract_programmer_param("size");
840 if (tmp) {
Edward O'Callaghan602fbab2020-11-23 12:27:57 +1100841 size = strtol(tmp, NULL, 10);
842 if (size <= 0 || (size % 1024 != 0)) {
843 msg_perr("%s: Chip size is not a multipler of 1024: %s\n",
844 __func__, tmp);
845 free(tmp);
846 return 1;
Namyoon Wooc429efb2020-10-17 20:25:15 -0700847 }
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000848 free(tmp);
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800849 }
850#endif
851
hailfinger6ead7222010-11-01 22:07:04 +0000852 tmp = extract_programmer_param("emulate");
853 if (!tmp) {
854 msg_pdbg("Not emulating any flash chip.\n");
855 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +0000856 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +0000857 }
858#if EMULATE_SPI_CHIP
859 if (!strcmp(tmp, "M25P10.RES")) {
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000860 data->emu_chip = EMULATE_ST_M25P10_RES;
861 data->emu_chip_size = 128 * 1024;
862 data->emu_max_byteprogram_size = 128;
863 data->emu_max_aai_size = 0;
864 data->emu_jedec_se_size = 0;
865 data->emu_jedec_be_52_size = 0;
866 data->emu_jedec_be_d8_size = 32 * 1024;
867 data->emu_jedec_ce_60_size = 0;
868 data->emu_jedec_ce_c7_size = data->emu_chip_size;
hailfinger6ead7222010-11-01 22:07:04 +0000869 msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
870 "write)\n");
871 }
872 if (!strcmp(tmp, "SST25VF040.REMS")) {
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000873 data->emu_chip = EMULATE_SST_SST25VF040_REMS;
874 data->emu_chip_size = 512 * 1024;
875 data->emu_max_byteprogram_size = 1;
876 data->emu_max_aai_size = 0;
877 data->emu_jedec_se_size = 4 * 1024;
878 data->emu_jedec_be_52_size = 32 * 1024;
879 data->emu_jedec_be_d8_size = 0;
880 data->emu_jedec_ce_60_size = data->emu_chip_size;
881 data->emu_jedec_ce_c7_size = 0;
hailfinger6ead7222010-11-01 22:07:04 +0000882 msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
883 "byte write)\n");
884 }
885 if (!strcmp(tmp, "SST25VF032B")) {
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000886 data->emu_chip = EMULATE_SST_SST25VF032B;
887 data->emu_chip_size = 4 * 1024 * 1024;
888 data->emu_max_byteprogram_size = 1;
889 data->emu_max_aai_size = 2;
890 data->emu_jedec_se_size = 4 * 1024;
891 data->emu_jedec_be_52_size = 32 * 1024;
892 data->emu_jedec_be_d8_size = 64 * 1024;
893 data->emu_jedec_ce_60_size = data->emu_chip_size;
894 data->emu_jedec_ce_c7_size = data->emu_chip_size;
hailfinger6ead7222010-11-01 22:07:04 +0000895 msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
896 "write)\n");
897 }
Stuart Langley78cacf72020-04-23 11:48:01 +1000898 if (!strcmp(tmp, "MX25L6436")) {
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000899 data->emu_chip = EMULATE_MACRONIX_MX25L6436;
900 data->emu_chip_size = 8 * 1024 * 1024;
901 data->emu_max_byteprogram_size = 256;
902 data->emu_max_aai_size = 0;
903 data->emu_jedec_se_size = 4 * 1024;
904 data->emu_jedec_be_52_size = 32 * 1024;
905 data->emu_jedec_be_d8_size = 64 * 1024;
906 data->emu_jedec_ce_60_size = data->emu_chip_size;
907 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Stuart Langley78cacf72020-04-23 11:48:01 +1000908 msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
909 "SFDP)\n");
910 }
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000911 if (!strcmp(tmp, "W25Q128FV")) {
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000912 data->emu_chip = EMULATE_WINBOND_W25Q128FV;
913 data->emu_chip_size = 16 * 1024 * 1024;
914 data->emu_max_byteprogram_size = 256;
915 data->emu_max_aai_size = 0;
916 data->emu_jedec_se_size = 4 * 1024;
917 data->emu_jedec_be_52_size = 32 * 1024;
918 data->emu_jedec_be_d8_size = 64 * 1024;
919 data->emu_jedec_ce_60_size = data->emu_chip_size;
920 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000921 msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID)\n");
922 }
Simon Glassd2c64a22013-07-03 22:05:21 +0900923
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000924 /* The name of variable-size virtual chip. A 4 MiB flash example:
925 * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
926 */
927 if (!strcmp(tmp, "VARIABLE_SIZE")) {
Edward O'Callaghan602fbab2020-11-23 12:27:57 +1100928 if (size == -1) {
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000929 msg_perr("%s: the size parameter is not given.\n", __func__);
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800930 free(tmp);
931 return 1;
932 }
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000933 data->emu_chip = EMULATE_VARIABLE_SIZE;
934 data->emu_chip_size = size;
935 data->emu_max_byteprogram_size = 256;
936 data->emu_max_aai_size = 0;
937 data->emu_jedec_se_size = 4 * 1024;
938 data->emu_jedec_be_52_size = 32 * 1024;
939 data->emu_jedec_be_d8_size = 64 * 1024;
940 data->emu_jedec_ce_60_size = data->emu_chip_size;
941 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800942 msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000943 data->emu_chip_size);
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800944 }
hailfinger6ead7222010-11-01 22:07:04 +0000945#endif
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000946 if (data->emu_chip == EMULATE_NONE) {
hailfinger6ead7222010-11-01 22:07:04 +0000947 msg_perr("Invalid chip specified for emulation: %s\n", tmp);
948 free(tmp);
949 return 1;
950 }
Edward O'Callaghan1b267722020-11-23 22:35:20 +1100951 free(tmp);
David Hendricks0eda2a82014-09-12 16:32:05 -0700952
953 /* Should emulated flash erase to zero (yes/no)? */
954 tmp = extract_programmer_param("erase_to_zero");
955 if (tmp) {
956 if (!strcmp(tmp, "yes")) {
957 msg_pdbg("Emulated chip will erase to 0x00\n");
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000958 data->erase_to_zero = 1;
David Hendricks0eda2a82014-09-12 16:32:05 -0700959 } else if (!strcmp(tmp, "no")) {
960 msg_pdbg("Emulated chip will erase to 0xff\n");
961 } else {
962 msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
Edward O'Callaghan1b267722020-11-23 22:35:20 +1100963 free(tmp);
David Hendricks0eda2a82014-09-12 16:32:05 -0700964 return 1;
965 }
966 }
hailfinger6ead7222010-11-01 22:07:04 +0000967 free(tmp);
Edward O'Callaghan1b267722020-11-23 22:35:20 +1100968
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000969 flashchip_contents = malloc(data->emu_chip_size);
hailfinger6ead7222010-11-01 22:07:04 +0000970 if (!flashchip_contents) {
971 msg_perr("Out of memory!\n");
972 return 1;
973 }
dhendrix0ffc2eb2011-06-14 01:35:36 +0000974
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000975#ifdef EMULATE_SPI_CHIP
976 status = extract_programmer_param("spi_status");
977 if (status) {
978 char *endptr;
979 errno = 0;
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000980 data->emu_status = strtoul(status, &endptr, 0);
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000981 free(status);
982 if (errno != 0 || status == endptr) {
983 msg_perr("Error: initial status register specified, "
984 "but the value could not be converted.\n");
985 return 1;
986 }
987 msg_pdbg("Initial status register is set to 0x%02x.\n",
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000988 data->emu_status);
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +1000989 }
990#endif
991
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000992 msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
993 data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
994 memset(flashchip_contents, data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
995
996 /* Will be freed by shutdown function if necessary. */
Edward O'Callaghan602fbab2020-11-23 12:27:57 +1100997 data->emu_persistent_image = extract_programmer_param("image");
Lachlan Bishopbf1476e2020-09-10 14:57:05 +1000998 if (!data->emu_persistent_image) {
hailfinger6ead7222010-11-01 22:07:04 +0000999 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +00001000 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +00001001 }
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +10001002 /* We will silently (in default verbosity) ignore the file if it does not exist (yet) or the size does
1003 * not match the emulated chip. */
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001004 if (!stat(data->emu_persistent_image, &image_stat)) {
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +10001005 msg_pdbg("Found persistent image %s, %jd B ",
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001006 data->emu_persistent_image, (intmax_t)image_stat.st_size);
1007 if ((uintmax_t)image_stat.st_size == data->emu_chip_size) {
hailfinger6ead7222010-11-01 22:07:04 +00001008 msg_pdbg("matches.\n");
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001009 msg_pdbg("Reading %s\n", data->emu_persistent_image);
1010 if (read_buf_from_file(flashchip_contents, data->emu_chip_size,
1011 data->emu_persistent_image)) {
1012 msg_perr("Unable to read %s\n", data->emu_persistent_image);
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +10001013 free(flashchip_contents);
1014 return 1;
1015 }
hailfinger6ead7222010-11-01 22:07:04 +00001016 } else {
1017 msg_pdbg("doesn't match.\n");
1018 }
1019 }
1020#endif
hailfingera9df33c2009-05-09 00:54:55 +00001021
dhendrix0ffc2eb2011-06-14 01:35:36 +00001022dummy_init_out:
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001023 if (register_shutdown(dummy_shutdown, data)) {
hailfinger6ead7222010-11-01 22:07:04 +00001024 free(flashchip_contents);
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001025 free(data);
dhendrix0ffc2eb2011-06-14 01:35:36 +00001026 return 1;
hailfinger6ead7222010-11-01 22:07:04 +00001027 }
hailfinger76bb7e92011-11-09 23:40:00 +00001028 if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
Patrick Georgi0a9533a2017-02-03 19:28:38 +01001029 register_par_master(&par_master_dummy,
Stuart langleyc98e43f2020-03-26 20:27:36 +11001030 dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH));
hailfinger76bb7e92011-11-09 23:40:00 +00001031 if (dummy_buses_supported & BUS_SPI)
Nico Huber2ef004f2021-05-11 17:53:34 +02001032 register_spi_master(&spi_master_dummyflasher, data);
hailfinger76bb7e92011-11-09 23:40:00 +00001033
hailfingera9df33c2009-05-09 00:54:55 +00001034 return 0;
1035}
1036
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001037#if EMULATE_CHIP && EMULATE_SPI_CHIP
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001038int probe_variable_size(struct flashctx *flash)
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001039{
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +10001040 unsigned int i;
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001041 const struct emu_data *emu_data = get_data_from_context(flash);
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001042
1043 /* Skip the probing if we don't emulate this chip. */
Angel Pons7971a732020-10-17 15:20:27 +02001044 if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE)
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001045 return 0;
1046
1047 /*
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001048 * This will break if one day flashctx becomes read-only.
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001049 * Once that happens, we need to have special hacks in functions:
1050 *
1051 * erase_and_write_flash() in flashrom.c
1052 * read_flash_to_file()
1053 * handle_romentries()
1054 * ...
1055 *
1056 * Search "total_size * 1024" in code.
1057 */
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001058 flash->chip->total_size = emu_data->emu_chip_size / 1024;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001059 msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01001060 flash->chip->total_size);
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001061
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001062 if (emu_data->erase_to_zero)
Alan Greendbeec2b2019-09-16 14:36:52 +10001063 flash->chip->feature_bits |= FEATURE_ERASED_ZERO;
David Hendricks0eda2a82014-09-12 16:32:05 -07001064
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +10001065 /* Update the first count of each of the block_erasers. */
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001066 for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
Patrick Georgif3fa2992017-02-02 16:24:44 +01001067 struct block_eraser *eraser = &flash->chip->block_erasers[i];
Edward O'Callaghanec8b0d92020-09-17 17:27:45 +10001068 if (!eraser->block_erase)
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001069 break;
1070
Namyoon Woob71a2962020-08-27 16:27:49 -07001071 eraser->eraseblocks[0].count = 1;
Lachlan Bishopbf1476e2020-09-10 14:57:05 +10001072 eraser->eraseblocks[0].size = emu_data->emu_chip_size;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +08001073 msg_cdbg("%s: eraser.size=%d, .count=%d\n",
1074 __func__, eraser->eraseblocks[0].size,
1075 eraser->eraseblocks[0].count);
1076 }
1077
1078 return 1;
1079}
1080#endif