blob: dcf97b5c8232cb007f6353f5d5fbede74f2574d7 [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
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +000040enum emu_chip {
41 EMULATE_NONE,
42 EMULATE_ST_M25P10_RES,
43 EMULATE_SST_SST25VF040_REMS,
44 EMULATE_SST_SST25VF032B,
Stefan Tauner0b9df972012-05-07 22:12:16 +000045 EMULATE_MACRONIX_MX25L6436,
Nico Huberf9632d82019-01-20 11:23:49 +010046 EMULATE_WINBOND_W25Q128FV,
Namyoon Woo31498222020-08-27 16:03:16 -070047 EMULATE_VARIABLE_SIZE,
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +000048};
Stefan Tauner0b9df972012-05-07 22:12:16 +000049
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +100050struct emu_data {
51 enum emu_chip emu_chip;
52 char *emu_persistent_image;
53 unsigned int emu_chip_size;
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +110054 int erase_to_zero;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +100055 int emu_modified; /* is the image modified since reading it? */
56 uint8_t emu_status;
Edward O'Callaghancb9f3cd2020-09-17 13:32:00 +100057 /* If "freq" parameter is passed in from command line, commands will delay
58 * for this period before returning. */
59 unsigned long int delay_us;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +100060 unsigned int emu_max_byteprogram_size;
61 unsigned int emu_max_aai_size;
62 unsigned int emu_jedec_se_size;
63 unsigned int emu_jedec_be_52_size;
64 unsigned int emu_jedec_be_d8_size;
65 unsigned int emu_jedec_ce_60_size;
66 unsigned int emu_jedec_ce_c7_size;
67 unsigned char spi_blacklist[256];
68 unsigned char spi_ignorelist[256];
69 unsigned int spi_blacklist_size;
70 unsigned int spi_ignorelist_size;
Edward O'Callaghan653eb692021-05-20 20:27:59 +100071
72 unsigned int spi_write_256_chunksize;
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +100073 uint8_t *flashchip_contents;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +100074};
75
76#if EMULATE_SPI_CHIP
Stefan Tauner0b9df972012-05-07 22:12:16 +000077/* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
Stefan Tauner67d163d2013-01-15 17:37:48 +000078static const uint8_t sfdp_table[] = {
Stefan Tauner0b9df972012-05-07 22:12:16 +000079 0x53, 0x46, 0x44, 0x50, // @0x00: SFDP signature
80 0x00, 0x01, 0x01, 0xFF, // @0x04: revision 1.0, 2 headers
81 0x00, 0x00, 0x01, 0x09, // @0x08: JEDEC SFDP header rev. 1.0, 9 DW long
82 0x1C, 0x00, 0x00, 0xFF, // @0x0C: PTP0 = 0x1C (instead of 0x30)
83 0xC2, 0x00, 0x01, 0x04, // @0x10: Macronix header rev. 1.0, 4 DW long
84 0x48, 0x00, 0x00, 0xFF, // @0x14: PTP1 = 0x48 (instead of 0x60)
85 0xFF, 0xFF, 0xFF, 0xFF, // @0x18: hole.
86 0xE5, 0x20, 0xC9, 0xFF, // @0x1C: SFDP parameter table start
87 0xFF, 0xFF, 0xFF, 0x03, // @0x20
88 0x00, 0xFF, 0x08, 0x6B, // @0x24
89 0x08, 0x3B, 0x00, 0xFF, // @0x28
90 0xEE, 0xFF, 0xFF, 0xFF, // @0x2C
91 0xFF, 0xFF, 0x00, 0x00, // @0x30
92 0xFF, 0xFF, 0x00, 0xFF, // @0x34
93 0x0C, 0x20, 0x0F, 0x52, // @0x38
94 0x10, 0xD8, 0x00, 0xFF, // @0x3C: SFDP parameter table end
95 0xFF, 0xFF, 0xFF, 0xFF, // @0x40: hole.
96 0xFF, 0xFF, 0xFF, 0xFF, // @0x44: hole.
97 0x00, 0x36, 0x00, 0x27, // @0x48: Macronix parameter table start
98 0xF4, 0x4F, 0xFF, 0xFF, // @0x4C
99 0xD9, 0xC8, 0xFF, 0xFF, // @0x50
100 0xFF, 0xFF, 0xFF, 0xFF, // @0x54: Macronix parameter table end
101};
102
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000103#endif
104#endif
105
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100106void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
107{
108 msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
109 __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
110 return (void *)phys_addr;
111}
112
113void dummy_unmap(void *virt_addr, size_t len)
114{
115 msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
116}
117
118static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
119{
Edward O'Callaghan52c02752021-05-25 20:47:02 +1000120 struct emu_data *emu_data = flash->mst->spi.data;
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100121 return spi_write_chunked(flash, buf, start, len,
Edward O'Callaghan653eb692021-05-20 20:27:59 +1000122 emu_data->spi_write_256_chunksize);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100123}
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
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100176#if EMULATE_SPI_CHIP
177static int emulate_spi_chip_response(unsigned int writecnt,
178 unsigned int readcnt,
179 const unsigned char *writearr,
180 unsigned char *readarr,
181 struct emu_data *data)
182{
183 unsigned int offs, i, toread;
184 static int unsigned aai_offs;
185 const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};
186 const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
187 const unsigned char mx25l6436_rems_response[2] = {0xc2, 0x16};
188 const unsigned char w25q128fv_rems_response[2] = {0xef, 0x17};
189
190 if (writecnt == 0) {
191 msg_perr("No command sent to the chip!\n");
192 return 1;
193 }
194 /* spi_blacklist has precedence over spi_ignorelist. */
195 for (i = 0; i < data->spi_blacklist_size; i++) {
196 if (writearr[0] == data->spi_blacklist[i]) {
197 msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
198 data->spi_blacklist[i]);
199 return SPI_INVALID_OPCODE;
200 }
201 }
202 for (i = 0; i < data->spi_ignorelist_size; i++) {
203 if (writearr[0] == data->spi_ignorelist[i]) {
204 msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
205 data->spi_ignorelist[i]);
206 /* Return success because the command does not fail,
207 * it is simply ignored.
208 */
209 return 0;
210 }
211 }
212
213 if (data->emu_max_aai_size && (data->emu_status & SPI_SR_AAI)) {
214 if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
215 writearr[0] != JEDEC_WRDI &&
216 writearr[0] != JEDEC_RDSR) {
217 msg_perr("Forbidden opcode (0x%02x) attempted during "
218 "AAI sequence!\n", writearr[0]);
219 return 0;
220 }
221 }
222
223 switch (writearr[0]) {
224 case JEDEC_RES:
225 if (writecnt < JEDEC_RES_OUTSIZE)
226 break;
227 /* offs calculation is only needed for SST chips which treat RES like REMS. */
228 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
229 offs += writecnt - JEDEC_REMS_OUTSIZE;
230 switch (data->emu_chip) {
231 case EMULATE_ST_M25P10_RES:
232 if (readcnt > 0)
233 memset(readarr, 0x10, readcnt);
234 break;
235 case EMULATE_SST_SST25VF040_REMS:
236 for (i = 0; i < readcnt; i++)
237 readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
238 break;
239 case EMULATE_SST_SST25VF032B:
240 for (i = 0; i < readcnt; i++)
241 readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
242 break;
243 case EMULATE_MACRONIX_MX25L6436:
244 if (readcnt > 0)
245 memset(readarr, 0x16, readcnt);
246 break;
247 case EMULATE_WINBOND_W25Q128FV:
248 if (readcnt > 0)
249 memset(readarr, 0x17, readcnt);
250 break;
251 default: /* ignore */
252 break;
253 }
254 break;
255 case JEDEC_REMS:
256 /* REMS response has wraparound and uses an address parameter. */
257 if (writecnt < JEDEC_REMS_OUTSIZE)
258 break;
259 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
260 offs += writecnt - JEDEC_REMS_OUTSIZE;
261 switch (data->emu_chip) {
262 case EMULATE_SST_SST25VF040_REMS:
263 for (i = 0; i < readcnt; i++)
264 readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
265 break;
266 case EMULATE_SST_SST25VF032B:
267 for (i = 0; i < readcnt; i++)
268 readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
269 break;
270 case EMULATE_MACRONIX_MX25L6436:
271 for (i = 0; i < readcnt; i++)
272 readarr[i] = mx25l6436_rems_response[(offs + i) % 2];
273 break;
274 case EMULATE_WINBOND_W25Q128FV:
275 for (i = 0; i < readcnt; i++)
276 readarr[i] = w25q128fv_rems_response[(offs + i) % 2];
277 break;
278 default: /* ignore */
279 break;
280 }
281 break;
282 case JEDEC_RDID:
283 switch (data->emu_chip) {
284 case EMULATE_SST_SST25VF032B:
285 if (readcnt > 0)
286 readarr[0] = 0xbf;
287 if (readcnt > 1)
288 readarr[1] = 0x25;
289 if (readcnt > 2)
290 readarr[2] = 0x4a;
291 break;
292 case EMULATE_MACRONIX_MX25L6436:
293 if (readcnt > 0)
294 readarr[0] = 0xc2;
295 if (readcnt > 1)
296 readarr[1] = 0x20;
297 if (readcnt > 2)
298 readarr[2] = 0x17;
299 break;
300 case EMULATE_WINBOND_W25Q128FV:
301 if (readcnt > 0)
302 readarr[0] = 0xef;
303 if (readcnt > 1)
304 readarr[1] = 0x40;
305 if (readcnt > 2)
306 readarr[2] = 0x18;
307 break;
308 case EMULATE_VARIABLE_SIZE:
309 if (readcnt > 0)
310 readarr[0] = (PROGMANUF_ID >> 8) & 0xff;
311 if (readcnt > 1)
312 readarr[1] = PROGMANUF_ID & 0xff;
313 if (readcnt > 2)
314 readarr[2] = (PROGDEV_ID >> 8) & 0xff;
315 if (readcnt > 3)
316 readarr[3] = PROGDEV_ID & 0xff;
317 break;
318 default: /* ignore */
319 break;
320 }
321 break;
322 case JEDEC_RDSR:
323 memset(readarr, data->emu_status, readcnt);
324 break;
325 /* FIXME: this should be chip-specific. */
326 case JEDEC_EWSR:
327 case JEDEC_WREN:
328 data->emu_status |= SPI_SR_WEL;
329 break;
330 case JEDEC_WRSR:
331 if (!(data->emu_status & SPI_SR_WEL)) {
332 msg_perr("WRSR attempted, but WEL is 0!\n");
333 break;
334 }
335 /* FIXME: add some reasonable simulation of the busy flag */
336 data->emu_status = writearr[1] & ~SPI_SR_WIP;
337 msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status);
338 break;
339 case JEDEC_READ:
340 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
341 /* Truncate to emu_chip_size. */
342 offs %= data->emu_chip_size;
343 if (readcnt > 0)
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000344 memcpy(readarr, data->flashchip_contents + offs, readcnt);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100345 break;
346 case JEDEC_READ_4BA:
347 offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
348 /* Truncate to emu_chip_size. */
349 offs %= data->emu_chip_size;
350 if (readcnt > 0)
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000351 memcpy(readarr, data->flashchip_contents + offs, readcnt);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100352 break;
353 case JEDEC_BYTE_PROGRAM:
354 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
355 /* Truncate to emu_chip_size. */
356 offs %= data->emu_chip_size;
357 if (writecnt < 5) {
358 msg_perr("BYTE PROGRAM size too short!\n");
359 return 1;
360 }
361 if (writecnt - 4 > data->emu_max_byteprogram_size) {
362 msg_perr("Max BYTE PROGRAM size exceeded!\n");
363 return 1;
364 }
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000365 memcpy(data->flashchip_contents + offs, writearr + 4, writecnt - 4);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100366 data->emu_modified = 1;
367 break;
368 case JEDEC_BYTE_PROGRAM_4BA:
369 offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
370 /* Truncate to emu_chip_size. */
371 offs %= data->emu_chip_size;
372 if (writecnt < 6) {
373 msg_perr("BYTE PROGRAM size too short!\n");
374 return 1;
375 }
376 if (writecnt - 5 > data->emu_max_byteprogram_size) {
377 msg_perr("Max BYTE PROGRAM size exceeded!\n");
378 return 1;
379 }
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000380 memcpy(data->flashchip_contents + offs, writearr + 5, writecnt - 5);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100381 data->emu_modified = 1;
382 break;
383 case JEDEC_AAI_WORD_PROGRAM:
384 if (!data->emu_max_aai_size)
385 break;
386 if (!(data->emu_status & SPI_SR_AAI)) {
387 if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
388 msg_perr("Initial AAI WORD PROGRAM size too "
389 "short!\n");
390 return 1;
391 }
392 if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
393 msg_perr("Initial AAI WORD PROGRAM size too "
394 "long!\n");
395 return 1;
396 }
397 data->emu_status |= SPI_SR_AAI;
398 aai_offs = writearr[1] << 16 | writearr[2] << 8 |
399 writearr[3];
400 /* Truncate to emu_chip_size. */
401 aai_offs %= data->emu_chip_size;
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000402 memcpy(data->flashchip_contents + aai_offs, writearr + 4, 2);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100403 aai_offs += 2;
404 } else {
405 if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
406 msg_perr("Continuation AAI WORD PROGRAM size "
407 "too short!\n");
408 return 1;
409 }
410 if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
411 msg_perr("Continuation AAI WORD PROGRAM size "
412 "too long!\n");
413 return 1;
414 }
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000415 memcpy(data->flashchip_contents + aai_offs, writearr + 1, 2);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100416 aai_offs += 2;
417 }
418 data->emu_modified = 1;
419 break;
420 case JEDEC_WRDI:
421 if (data->emu_max_aai_size)
422 data->emu_status &= ~SPI_SR_AAI;
423 break;
424 case JEDEC_SE:
425 if (!data->emu_jedec_se_size)
426 break;
427 if (writecnt != JEDEC_SE_OUTSIZE) {
428 msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
429 return 1;
430 }
431 if (readcnt != JEDEC_SE_INSIZE) {
432 msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
433 return 1;
434 }
435 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
436 if (offs & (data->emu_jedec_se_size - 1))
437 msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
438 offs &= ~(data->emu_jedec_se_size - 1);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000439 memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_se_size);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100440 data->emu_modified = 1;
441 break;
442 case JEDEC_BE_52:
443 if (!data->emu_jedec_be_52_size)
444 break;
445 if (writecnt != JEDEC_BE_52_OUTSIZE) {
446 msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
447 return 1;
448 }
449 if (readcnt != JEDEC_BE_52_INSIZE) {
450 msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
451 return 1;
452 }
453 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
454 if (offs & (data->emu_jedec_be_52_size - 1))
455 msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
456 offs &= ~(data->emu_jedec_be_52_size - 1);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000457 memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_be_52_size);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100458 data->emu_modified = 1;
459 break;
460 case JEDEC_BE_D8:
461 if (!data->emu_jedec_be_d8_size)
462 break;
463 if (writecnt != JEDEC_BE_D8_OUTSIZE) {
464 msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
465 return 1;
466 }
467 if (readcnt != JEDEC_BE_D8_INSIZE) {
468 msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
469 return 1;
470 }
471 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
472 if (offs & (data->emu_jedec_be_d8_size - 1))
473 msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
474 offs &= ~(data->emu_jedec_be_d8_size - 1);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000475 memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_be_d8_size);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100476 data->emu_modified = 1;
477 break;
478 case JEDEC_CE_60:
479 if (!data->emu_jedec_ce_60_size)
480 break;
481 if (writecnt != JEDEC_CE_60_OUTSIZE) {
482 msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
483 return 1;
484 }
485 if (readcnt != JEDEC_CE_60_INSIZE) {
486 msg_perr("CHIP ERASE 0x60 insize invalid!\n");
487 return 1;
488 }
489 /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
490 /* emu_jedec_ce_60_size is emu_chip_size. */
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000491 memset(data->flashchip_contents, 0xff, data->emu_jedec_ce_60_size);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100492 data->emu_modified = 1;
493 break;
494 case JEDEC_CE_C7:
495 if (!data->emu_jedec_ce_c7_size)
496 break;
497 if (writecnt != JEDEC_CE_C7_OUTSIZE) {
498 msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
499 return 1;
500 }
501 if (readcnt != JEDEC_CE_C7_INSIZE) {
502 msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
503 return 1;
504 }
505 /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
506 /* emu_jedec_ce_c7_size is emu_chip_size. */
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000507 memset(data->flashchip_contents, 0xff, data->emu_jedec_ce_c7_size);
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100508 data->emu_modified = 1;
509 break;
510 case JEDEC_SFDP:
511 if (data->emu_chip != EMULATE_MACRONIX_MX25L6436)
512 break;
513 if (writecnt < 4)
514 break;
515 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
516
517 /* SFDP expects one dummy byte after the address. */
518 if (writecnt == 4) {
519 /* The dummy byte was not written, make sure it is read instead.
520 * Shifting and shortening the read array does achieve this goal.
521 */
522 readarr++;
523 readcnt--;
524 } else {
525 /* The response is shifted if more than 5 bytes are written, because SFDP data is
526 * already shifted out by the chip while those superfluous bytes are written. */
527 offs += writecnt - 5;
528 }
529
530 /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
531 * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
532 * This is a reasonable implementation choice in hardware because it saves a few gates. */
533 if (offs >= sizeof(sfdp_table)) {
534 msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
535 "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
536 offs %= sizeof(sfdp_table);
537 }
538 toread = min(sizeof(sfdp_table) - offs, readcnt);
539 memcpy(readarr, sfdp_table + offs, toread);
540 if (toread < readcnt)
541 msg_pdbg("Crossing the SFDP table boundary in a single "
542 "continuous chunk produces undefined results "
543 "after that point.\n");
544 break;
545 default:
546 /* No special response. */
547 break;
548 }
549 if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
550 data->emu_status &= ~SPI_SR_WEL;
551 return 0;
552}
553#endif
554
555static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
556 unsigned int readcnt,
557 const unsigned char *writearr,
558 unsigned char *readarr)
559{
560 unsigned int i;
Edward O'Callaghan52c02752021-05-25 20:47:02 +1000561 struct emu_data *emu_data = flash->mst->spi.data;
Anastasia Klimchuk74697102021-02-15 14:57:56 +1100562 if (!emu_data) {
563 msg_perr("No data in flash context!\n");
564 return 1;
565 }
566
567 msg_pspew("%s:", __func__);
568
569 msg_pspew(" writing %u bytes:", writecnt);
570 for (i = 0; i < writecnt; i++)
571 msg_pspew(" 0x%02x", writearr[i]);
572
573 /* Response for unknown commands and missing chip is 0xff. */
574 memset(readarr, 0xff, readcnt);
575#if EMULATE_SPI_CHIP
576 switch (emu_data->emu_chip) {
577 case EMULATE_ST_M25P10_RES:
578 case EMULATE_SST_SST25VF040_REMS:
579 case EMULATE_SST_SST25VF032B:
580 case EMULATE_MACRONIX_MX25L6436:
581 case EMULATE_WINBOND_W25Q128FV:
582 case EMULATE_VARIABLE_SIZE:
583 if (emulate_spi_chip_response(writecnt, readcnt, writearr,
584 readarr, emu_data)) {
585 msg_pdbg("Invalid command sent to flash chip!\n");
586 return 1;
587 }
588 break;
589 default:
590 break;
591 }
592#endif
593 msg_pspew(" reading %u bytes:", readcnt);
594 for (i = 0; i < readcnt; i++)
595 msg_pspew(" 0x%02x", readarr[i]);
596 msg_pspew("\n");
597
598 programmer_delay((writecnt + readcnt) * emu_data->delay_us);
599 return 0;
600}
601
602
Michael Karcherb9dbe482011-05-11 17:07:07 +0000603
Nico Huber90739d12021-05-11 17:53:34 +0200604static const struct spi_master spi_master_dummyflasher = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100605 .features = SPI_MASTER_4BA,
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000606 .max_data_read = MAX_DATA_READ_UNLIMITED,
607 .max_data_write = MAX_DATA_UNSPECIFIED,
608 .command = dummy_spi_send_command,
609 .multicommand = default_spi_send_multicommand,
610 .read = default_spi_read,
611 .write_256 = dummy_spi_write_256,
Nico Huber7bca1262012-06-15 22:28:12 +0000612 .write_aai = default_spi_write_aai,
Michael Karcherb9dbe482011-05-11 17:07:07 +0000613};
David Hendricks8bb20212011-06-14 01:35:36 +0000614
Edward O'Callaghan93763e42021-05-20 20:21:13 +1000615static const struct par_master par_master_dummyflasher = {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000616 .chip_readb = dummy_chip_readb,
617 .chip_readw = dummy_chip_readw,
618 .chip_readl = dummy_chip_readl,
619 .chip_readn = dummy_chip_readn,
620 .chip_writeb = dummy_chip_writeb,
621 .chip_writew = dummy_chip_writew,
622 .chip_writel = dummy_chip_writel,
623 .chip_writen = dummy_chip_writen,
624};
625
David Hendricks8bb20212011-06-14 01:35:36 +0000626static int dummy_shutdown(void *data)
627{
628 msg_pspew("%s\n", __func__);
629#if EMULATE_CHIP
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000630 struct emu_data *emu_data = (struct emu_data *)data;
631 if (emu_data->emu_chip != EMULATE_NONE) {
632 if (emu_data->emu_persistent_image && emu_data->emu_modified) {
633 msg_pdbg("Writing %s\n", emu_data->emu_persistent_image);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000634 write_buf_to_file(emu_data->flashchip_contents,
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000635 emu_data->emu_chip_size,
636 emu_data->emu_persistent_image);
David Hendricks8bb20212011-06-14 01:35:36 +0000637 }
Angel Pons6b1f3b02021-05-25 12:46:43 +0200638 free(emu_data->emu_persistent_image);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000639 free(emu_data->flashchip_contents);
David Hendricks8bb20212011-06-14 01:35:36 +0000640 }
641#endif
Anastasia Klimchuk99100952021-04-21 07:55:21 +1000642 free(data);
David Hendricks8bb20212011-06-14 01:35:36 +0000643 return 0;
644}
645
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +0000646int dummy_init(void)
647{
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000648 char *bustext = NULL;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000649 char *tmp = NULL;
Nico Huber519be662018-12-23 20:03:35 +0100650 unsigned int i;
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000651#if EMULATE_SPI_CHIP
652 char *status = NULL;
Namyoon Woof7a08a82020-10-17 20:25:15 -0700653 int size = -1; /* size for VARIABLE_SIZE chip device */
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000654#endif
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000655#if EMULATE_CHIP
656 struct stat image_stat;
657#endif
Edward O'Callaghane3707bb2021-05-23 22:14:36 +1000658 char *endptr;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000659
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000660 struct emu_data *data = calloc(1, sizeof(struct emu_data));
661 if (!data) {
662 msg_perr("Out of memory!\n");
663 return 1;
664 }
665 data->emu_chip = EMULATE_NONE;
Edward O'Callaghancb9f3cd2020-09-17 13:32:00 +1000666 data->delay_us = 0;
Edward O'Callaghan653eb692021-05-20 20:27:59 +1000667 data->spi_write_256_chunksize = 256;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000668
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000669 msg_pspew("%s\n", __func__);
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000670
Carl-Daniel Hailfinger2b6dcb32010-07-08 10:13:37 +0000671 bustext = extract_programmer_param("bus");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000672 msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
673 if (!bustext)
674 bustext = strdup("parallel+lpc+fwh+spi");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000675 /* Convert the parameters to lowercase. */
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000676 tolower_string(bustext);
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000677
Edward O'Callaghan0282a832021-05-25 20:51:16 +1000678 enum chipbustype dummy_buses_supported = BUS_NONE;
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000679 if (strstr(bustext, "parallel")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000680 dummy_buses_supported |= BUS_PARALLEL;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000681 msg_pdbg("Enabling support for %s flash.\n", "parallel");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000682 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000683 if (strstr(bustext, "lpc")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000684 dummy_buses_supported |= BUS_LPC;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000685 msg_pdbg("Enabling support for %s flash.\n", "LPC");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000686 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000687 if (strstr(bustext, "fwh")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000688 dummy_buses_supported |= BUS_FWH;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000689 msg_pdbg("Enabling support for %s flash.\n", "FWH");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000690 }
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000691 if (strstr(bustext, "spi")) {
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000692 dummy_buses_supported |= BUS_SPI;
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000693 msg_pdbg("Enabling support for %s flash.\n", "SPI");
Carl-Daniel Hailfinger3504b532009-06-01 00:02:11 +0000694 }
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +0000695 if (dummy_buses_supported == BUS_NONE)
Carl-Daniel Hailfinger3ac101c2010-01-09 04:32:23 +0000696 msg_pdbg("Support for all flash bus types disabled.\n");
Carl-Daniel Hailfinger744132a2010-07-06 09:55:48 +0000697 free(bustext);
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000698
699 tmp = extract_programmer_param("spi_write_256_chunksize");
700 if (tmp) {
Edward O'Callaghane3707bb2021-05-23 22:14:36 +1000701 data->spi_write_256_chunksize = strtoul(tmp, &endptr, 0);
Edward O'Callaghane3707bb2021-05-23 22:14:36 +1000702 if (*endptr != '\0' || data->spi_write_256_chunksize < 1) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000703 msg_perr("invalid spi_write_256_chunksize\n");
Edward O'Callaghan51c1f392021-05-27 22:36:51 +1000704 free(tmp);
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000705 return 1;
706 }
707 }
Edward O'Callaghan51c1f392021-05-27 22:36:51 +1000708 free(tmp);
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000709
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000710 tmp = extract_programmer_param("spi_blacklist");
711 if (tmp) {
712 i = strlen(tmp);
713 if (!strncmp(tmp, "0x", 2)) {
714 i -= 2;
715 memmove(tmp, tmp + 2, i + 1);
716 }
717 if ((i > 512) || (i % 2)) {
718 msg_perr("Invalid SPI command blacklist length\n");
719 free(tmp);
720 return 1;
721 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000722 data->spi_blacklist_size = i / 2;
723 for (i = 0; i < data->spi_blacklist_size * 2; i++) {
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000724 if (!isxdigit((unsigned char)tmp[i])) {
725 msg_perr("Invalid char \"%c\" in SPI command "
726 "blacklist\n", tmp[i]);
727 free(tmp);
728 return 1;
729 }
730 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000731 for (i = 0; i < data->spi_blacklist_size; i++) {
Carl-Daniel Hailfinger5b554712012-02-16 01:43:06 +0000732 unsigned int tmp2;
733 /* SCNx8 is apparently not supported by MSVC (and thus
734 * MinGW), so work around it with an extra variable
735 */
736 sscanf(tmp + i * 2, "%2x", &tmp2);
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000737 data->spi_blacklist[i] = (uint8_t)tmp2;
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000738 }
739 msg_pdbg("SPI blacklist is ");
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000740 for (i = 0; i < data->spi_blacklist_size; i++)
741 msg_pdbg("%02x ", data->spi_blacklist[i]);
742 msg_pdbg(", size %u\n", data->spi_blacklist_size);
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000743 }
744 free(tmp);
745
746 tmp = extract_programmer_param("spi_ignorelist");
747 if (tmp) {
748 i = strlen(tmp);
749 if (!strncmp(tmp, "0x", 2)) {
750 i -= 2;
751 memmove(tmp, tmp + 2, i + 1);
752 }
753 if ((i > 512) || (i % 2)) {
754 msg_perr("Invalid SPI command ignorelist length\n");
755 free(tmp);
756 return 1;
757 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000758 data->spi_ignorelist_size = i / 2;
759 for (i = 0; i < data->spi_ignorelist_size * 2; i++) {
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000760 if (!isxdigit((unsigned char)tmp[i])) {
761 msg_perr("Invalid char \"%c\" in SPI command "
762 "ignorelist\n", tmp[i]);
763 free(tmp);
764 return 1;
765 }
766 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000767 for (i = 0; i < data->spi_ignorelist_size; i++) {
Carl-Daniel Hailfinger5b554712012-02-16 01:43:06 +0000768 unsigned int tmp2;
769 /* SCNx8 is apparently not supported by MSVC (and thus
770 * MinGW), so work around it with an extra variable
771 */
772 sscanf(tmp + i * 2, "%2x", &tmp2);
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000773 data->spi_ignorelist[i] = (uint8_t)tmp2;
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000774 }
775 msg_pdbg("SPI ignorelist is ");
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000776 for (i = 0; i < data->spi_ignorelist_size; i++)
777 msg_pdbg("%02x ", data->spi_ignorelist[i]);
778 msg_pdbg(", size %u\n", data->spi_ignorelist_size);
Carl-Daniel Hailfinger1b83be52012-02-08 23:28:54 +0000779 }
780 free(tmp);
781
Edward O'Callaghancb9f3cd2020-09-17 13:32:00 +1000782 /* frequency to emulate in Hz (default), KHz, or MHz */
783 tmp = extract_programmer_param("freq");
784 if (tmp) {
785 unsigned long int freq;
786 char *units = tmp;
787 char *end = tmp + strlen(tmp);
788
789 errno = 0;
790 freq = strtoul(tmp, &units, 0);
791 if (errno) {
792 msg_perr("Invalid frequency \"%s\", %s\n",
793 tmp, strerror(errno));
794 free(tmp);
795 return 1;
796 }
797
798 if ((units > tmp) && (units < end)) {
799 int units_valid = 0;
800
801 if (units < end - 3) {
802 ;
803 } else if (units == end - 2) {
804 if (!strcasecmp(units, "hz"))
805 units_valid = 1;
806 } else if (units == end - 3) {
807 if (!strcasecmp(units, "khz")) {
808 freq *= 1000;
809 units_valid = 1;
810 } else if (!strcasecmp(units, "mhz")) {
811 freq *= 1000000;
812 units_valid = 1;
813 }
814 }
815
816 if (!units_valid) {
817 msg_perr("Invalid units: %s\n", units);
818 free(tmp);
819 return 1;
820 }
821 }
822
823 /* Assume we only work with bytes and transfer at 1 bit/Hz */
824 data->delay_us = (1000000 * 8) / freq;
825 }
826 free(tmp);
827
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000828#if EMULATE_CHIP
Namyoon Woo31498222020-08-27 16:03:16 -0700829#if EMULATE_SPI_CHIP
830 tmp = extract_programmer_param("size");
831 if (tmp) {
Namyoon Woof7a08a82020-10-17 20:25:15 -0700832 size = strtol(tmp, NULL, 10);
Namyoon Woo31498222020-08-27 16:03:16 -0700833 if (size <= 0 || (size % 1024 != 0)) {
Angel Pons89a16e42021-05-25 13:05:09 +0200834 msg_perr("%s: Chip size is not a multiple of 1024: %s\n",
Namyoon Woo31498222020-08-27 16:03:16 -0700835 __func__, tmp);
836 free(tmp);
837 return 1;
838 }
839 free(tmp);
Namyoon Woo31498222020-08-27 16:03:16 -0700840 }
841#endif
842
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000843 tmp = extract_programmer_param("emulate");
844 if (!tmp) {
845 msg_pdbg("Not emulating any flash chip.\n");
846 /* Nothing else to do. */
David Hendricks8bb20212011-06-14 01:35:36 +0000847 goto dummy_init_out;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000848 }
849#if EMULATE_SPI_CHIP
850 if (!strcmp(tmp, "M25P10.RES")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000851 data->emu_chip = EMULATE_ST_M25P10_RES;
852 data->emu_chip_size = 128 * 1024;
853 data->emu_max_byteprogram_size = 128;
854 data->emu_max_aai_size = 0;
855 data->emu_jedec_se_size = 0;
856 data->emu_jedec_be_52_size = 0;
857 data->emu_jedec_be_d8_size = 32 * 1024;
858 data->emu_jedec_ce_60_size = 0;
859 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000860 msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
861 "write)\n");
862 }
863 if (!strcmp(tmp, "SST25VF040.REMS")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000864 data->emu_chip = EMULATE_SST_SST25VF040_REMS;
865 data->emu_chip_size = 512 * 1024;
866 data->emu_max_byteprogram_size = 1;
867 data->emu_max_aai_size = 0;
868 data->emu_jedec_se_size = 4 * 1024;
869 data->emu_jedec_be_52_size = 32 * 1024;
870 data->emu_jedec_be_d8_size = 0;
871 data->emu_jedec_ce_60_size = data->emu_chip_size;
872 data->emu_jedec_ce_c7_size = 0;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000873 msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
874 "byte write)\n");
875 }
876 if (!strcmp(tmp, "SST25VF032B")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000877 data->emu_chip = EMULATE_SST_SST25VF032B;
878 data->emu_chip_size = 4 * 1024 * 1024;
879 data->emu_max_byteprogram_size = 1;
880 data->emu_max_aai_size = 2;
881 data->emu_jedec_se_size = 4 * 1024;
882 data->emu_jedec_be_52_size = 32 * 1024;
883 data->emu_jedec_be_d8_size = 64 * 1024;
884 data->emu_jedec_ce_60_size = data->emu_chip_size;
885 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000886 msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
887 "write)\n");
888 }
Stefan Tauner0b9df972012-05-07 22:12:16 +0000889 if (!strcmp(tmp, "MX25L6436")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000890 data->emu_chip = EMULATE_MACRONIX_MX25L6436;
891 data->emu_chip_size = 8 * 1024 * 1024;
892 data->emu_max_byteprogram_size = 256;
893 data->emu_max_aai_size = 0;
894 data->emu_jedec_se_size = 4 * 1024;
895 data->emu_jedec_be_52_size = 32 * 1024;
896 data->emu_jedec_be_d8_size = 64 * 1024;
897 data->emu_jedec_ce_60_size = data->emu_chip_size;
898 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Stefan Tauner0b9df972012-05-07 22:12:16 +0000899 msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
900 "SFDP)\n");
901 }
Nico Huberf9632d82019-01-20 11:23:49 +0100902 if (!strcmp(tmp, "W25Q128FV")) {
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000903 data->emu_chip = EMULATE_WINBOND_W25Q128FV;
904 data->emu_chip_size = 16 * 1024 * 1024;
905 data->emu_max_byteprogram_size = 256;
906 data->emu_max_aai_size = 0;
907 data->emu_jedec_se_size = 4 * 1024;
908 data->emu_jedec_be_52_size = 32 * 1024;
909 data->emu_jedec_be_d8_size = 64 * 1024;
910 data->emu_jedec_ce_60_size = data->emu_chip_size;
911 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Nico Huberf9632d82019-01-20 11:23:49 +0100912 msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID)\n");
913 }
Namyoon Woo31498222020-08-27 16:03:16 -0700914
915 /* The name of variable-size virtual chip. A 4 MiB flash example:
916 * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
917 */
918 if (!strcmp(tmp, "VARIABLE_SIZE")) {
Namyoon Woof7a08a82020-10-17 20:25:15 -0700919 if (size == -1) {
920 msg_perr("%s: the size parameter is not given.\n", __func__);
921 free(tmp);
922 return 1;
923 }
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000924 data->emu_chip = EMULATE_VARIABLE_SIZE;
925 data->emu_chip_size = size;
926 data->emu_max_byteprogram_size = 256;
927 data->emu_max_aai_size = 0;
928 data->emu_jedec_se_size = 4 * 1024;
929 data->emu_jedec_be_52_size = 32 * 1024;
930 data->emu_jedec_be_d8_size = 64 * 1024;
931 data->emu_jedec_ce_60_size = data->emu_chip_size;
932 data->emu_jedec_ce_c7_size = data->emu_chip_size;
Namyoon Woo31498222020-08-27 16:03:16 -0700933 msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000934 data->emu_chip_size);
Namyoon Woo31498222020-08-27 16:03:16 -0700935 }
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000936#endif
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000937 if (data->emu_chip == EMULATE_NONE) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000938 msg_perr("Invalid chip specified for emulation: %s\n", tmp);
939 free(tmp);
940 return 1;
941 }
942 free(tmp);
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +1100943
944 /* Should emulated flash erase to zero (yes/no)? */
945 tmp = extract_programmer_param("erase_to_zero");
946 if (tmp) {
947 if (!strcmp(tmp, "yes")) {
948 msg_pdbg("Emulated chip will erase to 0x00\n");
949 data->erase_to_zero = 1;
950 } else if (!strcmp(tmp, "no")) {
951 msg_pdbg("Emulated chip will erase to 0xff\n");
952 } else {
953 msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
954 free(tmp);
955 return 1;
956 }
957 }
958 free(tmp);
959
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000960#ifdef EMULATE_SPI_CHIP
961 status = extract_programmer_param("spi_status");
962 if (status) {
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000963 errno = 0;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000964 data->emu_status = strtoul(status, &endptr, 0);
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000965 if (errno != 0 || status == endptr) {
Angel Ponsbe5af622021-05-25 13:03:24 +0200966 free(status);
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000967 msg_perr("Error: initial status register specified, "
968 "but the value could not be converted.\n");
969 return 1;
970 }
Angel Ponsbe5af622021-05-25 13:03:24 +0200971 free(status);
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000972 msg_pdbg("Initial status register is set to 0x%02x.\n",
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000973 data->emu_status);
Stefan Tauner5e695ab2012-05-06 17:03:40 +0000974 }
975#endif
976
Angel Pons2ef2efa2021-05-25 12:56:18 +0200977 data->flashchip_contents = malloc(data->emu_chip_size);
978 if (!data->flashchip_contents) {
979 msg_perr("Out of memory!\n");
980 return 1;
981 }
982
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +1100983 msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
984 data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +1000985 memset(data->flashchip_contents, data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000986
Stefan Taunerc2eec2c2014-05-03 21:33:01 +0000987 /* Will be freed by shutdown function if necessary. */
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000988 data->emu_persistent_image = extract_programmer_param("image");
989 if (!data->emu_persistent_image) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000990 /* Nothing else to do. */
David Hendricks8bb20212011-06-14 01:35:36 +0000991 goto dummy_init_out;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000992 }
Stefan Taunerc2eec2c2014-05-03 21:33:01 +0000993 /* We will silently (in default verbosity) ignore the file if it does not exist (yet) or the size does
994 * not match the emulated chip. */
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000995 if (!stat(data->emu_persistent_image, &image_stat)) {
Stefan Tauner23e10b82016-01-23 16:16:49 +0000996 msg_pdbg("Found persistent image %s, %jd B ",
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +1000997 data->emu_persistent_image, (intmax_t)image_stat.st_size);
998 if ((uintmax_t)image_stat.st_size == data->emu_chip_size) {
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +0000999 msg_pdbg("matches.\n");
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001000 msg_pdbg("Reading %s\n", data->emu_persistent_image);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +10001001 if (read_buf_from_file(data->flashchip_contents, data->emu_chip_size,
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001002 data->emu_persistent_image)) {
1003 msg_perr("Unable to read %s\n", data->emu_persistent_image);
Angel Pons6b1f3b02021-05-25 12:46:43 +02001004 free(data->emu_persistent_image);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +10001005 free(data->flashchip_contents);
Jacob Garberca598da2019-08-12 10:44:17 -06001006 return 1;
1007 }
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001008 } else {
1009 msg_pdbg("doesn't match.\n");
1010 }
1011 }
1012#endif
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +00001013
David Hendricks8bb20212011-06-14 01:35:36 +00001014dummy_init_out:
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001015 if (register_shutdown(dummy_shutdown, data)) {
Angel Pons6b1f3b02021-05-25 12:46:43 +02001016 free(data->emu_persistent_image);
Edward O'Callaghan245b7cd2021-05-20 20:34:02 +10001017 free(data->flashchip_contents);
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001018 free(data);
David Hendricks8bb20212011-06-14 01:35:36 +00001019 return 1;
Carl-Daniel Hailfingerf68aa8a2010-11-01 22:07:04 +00001020 }
Edward O'Callaghan6c9dfdc2021-05-17 20:01:27 +10001021 if (dummy_buses_supported & BUS_NONSPI)
Edward O'Callaghan93763e42021-05-20 20:21:13 +10001022 register_par_master(&par_master_dummyflasher,
Anastasia Klimchuk6a5db262021-05-21 09:40:58 +10001023 dummy_buses_supported & BUS_NONSPI,
Anastasia Klimchukc49aaee2021-05-21 09:45:53 +10001024 data);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +00001025 if (dummy_buses_supported & BUS_SPI)
Nico Huber90739d12021-05-11 17:53:34 +02001026 register_spi_master(&spi_master_dummyflasher, data);
Carl-Daniel Hailfingereaacd2d2011-11-09 23:40:00 +00001027
Carl-Daniel Hailfingerc3129202009-05-09 00:54:55 +00001028 return 0;
1029}
1030
Namyoon Woo31498222020-08-27 16:03:16 -07001031#if EMULATE_CHIP && EMULATE_SPI_CHIP
1032int probe_variable_size(struct flashctx *flash)
1033{
1034 unsigned int i;
Edward O'Callaghan0282a832021-05-25 20:51:16 +10001035 const struct emu_data *emu_data = flash->mst->spi.data;
Namyoon Woo31498222020-08-27 16:03:16 -07001036
1037 /* Skip the probing if we don't emulate this chip. */
Angel Ponsc8df4012020-10-17 15:20:27 +02001038 if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE)
Namyoon Woo31498222020-08-27 16:03:16 -07001039 return 0;
1040
1041 /*
1042 * This will break if one day flashctx becomes read-only.
1043 * Once that happens, we need to have special hacks in functions:
1044 *
1045 * erase_and_write_flash() in flashrom.c
1046 * read_flash_to_file()
1047 * handle_romentries()
1048 * ...
1049 *
1050 * Search "total_size * 1024" in code.
1051 */
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001052 flash->chip->total_size = emu_data->emu_chip_size / 1024;
Namyoon Woo31498222020-08-27 16:03:16 -07001053 msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
1054 flash->chip->total_size);
1055
Edward O'Callaghan3d300cb2020-11-23 22:35:20 +11001056 if (emu_data->erase_to_zero)
1057 flash->chip->feature_bits |= FEATURE_ERASED_ZERO;
1058
Namyoon Woo31498222020-08-27 16:03:16 -07001059 /* Update the first count of each of the block_erasers. */
1060 for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
1061 struct block_eraser *eraser = &flash->chip->block_erasers[i];
1062 if (!eraser->block_erase)
1063 break;
1064
Namyoon Woo79da18f2020-08-27 16:27:49 -07001065 eraser->eraseblocks[0].count = 1;
Lachlan Bishop3b8fe0f2020-09-10 14:57:05 +10001066 eraser->eraseblocks[0].size = emu_data->emu_chip_size;
Namyoon Woo31498222020-08-27 16:03:16 -07001067 msg_cdbg("%s: eraser.size=%d, .count=%d\n",
1068 __func__, eraser->eraseblocks[0].size,
1069 eraser->eraseblocks[0].count);
1070 }
1071
1072 return 1;
1073}
1074#endif