source: trunk/dummyflasher.c

Last change on this file was 1646, checked in by stefanct, 5 months ago

Fix duplicate 'const' declaration specifiers.

Thanks to Idwer and clang for noticing these problems.

Signed-off-by: Stefan Tauner <stefan.tauner@…>
Signed-off-by: Idwer Vollering <vidwer@…>
Acked-by: Stefan Tauner <stefan.tauner@…>

File size: 24.6 KB
Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
5 *
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
8 * the Free Software Foundation; version 2 of the License.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18 */
19
20#include <string.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <ctype.h>
24#include <errno.h>
25#include "flash.h"
26#include "chipdrivers.h"
27#include "programmer.h"
28
29/* Remove the #define below if you don't want SPI flash chip emulation. */
30#define EMULATE_SPI_CHIP 1
31
32#if EMULATE_SPI_CHIP
33#define EMULATE_CHIP 1
34#include "spi.h"
35#endif
36
37#if EMULATE_CHIP
38#include <sys/types.h>
39#include <sys/stat.h>
40#endif
41
42#if EMULATE_CHIP
43static uint8_t *flashchip_contents = NULL;
44enum emu_chip {
45        EMULATE_NONE,
46        EMULATE_ST_M25P10_RES,
47        EMULATE_SST_SST25VF040_REMS,
48        EMULATE_SST_SST25VF032B,
49        EMULATE_MACRONIX_MX25L6436,
50};
51static enum emu_chip emu_chip = EMULATE_NONE;
52static char *emu_persistent_image = NULL;
53static unsigned int emu_chip_size = 0;
54#if EMULATE_SPI_CHIP
55static unsigned int emu_max_byteprogram_size = 0;
56static unsigned int emu_max_aai_size = 0;
57static unsigned int emu_jedec_se_size = 0;
58static unsigned int emu_jedec_be_52_size = 0;
59static unsigned int emu_jedec_be_d8_size = 0;
60static unsigned int emu_jedec_ce_60_size = 0;
61static unsigned int emu_jedec_ce_c7_size = 0;
62unsigned char spi_blacklist[256];
63unsigned char spi_ignorelist[256];
64int spi_blacklist_size = 0;
65int spi_ignorelist_size = 0;
66static uint8_t emu_status = 0;
67
68/* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
69static const uint8_t sfdp_table[] = {
70        0x53, 0x46, 0x44, 0x50, // @0x00: SFDP signature
71        0x00, 0x01, 0x01, 0xFF, // @0x04: revision 1.0, 2 headers
72        0x00, 0x00, 0x01, 0x09, // @0x08: JEDEC SFDP header rev. 1.0, 9 DW long
73        0x1C, 0x00, 0x00, 0xFF, // @0x0C: PTP0 = 0x1C (instead of 0x30)
74        0xC2, 0x00, 0x01, 0x04, // @0x10: Macronix header rev. 1.0, 4 DW long
75        0x48, 0x00, 0x00, 0xFF, // @0x14: PTP1 = 0x48 (instead of 0x60)
76        0xFF, 0xFF, 0xFF, 0xFF, // @0x18: hole.
77        0xE5, 0x20, 0xC9, 0xFF, // @0x1C: SFDP parameter table start
78        0xFF, 0xFF, 0xFF, 0x03, // @0x20
79        0x00, 0xFF, 0x08, 0x6B, // @0x24
80        0x08, 0x3B, 0x00, 0xFF, // @0x28
81        0xEE, 0xFF, 0xFF, 0xFF, // @0x2C
82        0xFF, 0xFF, 0x00, 0x00, // @0x30
83        0xFF, 0xFF, 0x00, 0xFF, // @0x34
84        0x0C, 0x20, 0x0F, 0x52, // @0x38
85        0x10, 0xD8, 0x00, 0xFF, // @0x3C: SFDP parameter table end
86        0xFF, 0xFF, 0xFF, 0xFF, // @0x40: hole.
87        0xFF, 0xFF, 0xFF, 0xFF, // @0x44: hole.
88        0x00, 0x36, 0x00, 0x27, // @0x48: Macronix parameter table start
89        0xF4, 0x4F, 0xFF, 0xFF, // @0x4C
90        0xD9, 0xC8, 0xFF, 0xFF, // @0x50
91        0xFF, 0xFF, 0xFF, 0xFF, // @0x54: Macronix parameter table end
92};
93
94#endif
95#endif
96
97static unsigned int spi_write_256_chunksize = 256;
98
99static int dummy_spi_send_command(struct flashctx *flash, unsigned int writecnt,
100                                  unsigned int readcnt,
101                                  const unsigned char *writearr,
102                                  unsigned char *readarr);
103static int dummy_spi_write_256(struct flashctx *flash, uint8_t *buf,
104                               unsigned int start, unsigned int len);
105static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val,
106                              chipaddr addr);
107static void dummy_chip_writew(const struct flashctx *flash, uint16_t val,
108                              chipaddr addr);
109static void dummy_chip_writel(const struct flashctx *flash, uint32_t val,
110                              chipaddr addr);
111static void dummy_chip_writen(const struct flashctx *flash, uint8_t *buf,
112                              chipaddr addr, size_t len);
113static uint8_t dummy_chip_readb(const struct flashctx *flash,
114                                const chipaddr addr);
115static uint16_t dummy_chip_readw(const struct flashctx *flash,
116                                 const chipaddr addr);
117static uint32_t dummy_chip_readl(const struct flashctx *flash,
118                                 const chipaddr addr);
119static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf,
120                             const chipaddr addr, size_t len);
121
122static const struct spi_programmer spi_programmer_dummyflasher = {
123        .type           = SPI_CONTROLLER_DUMMY,
124        .max_data_read  = MAX_DATA_READ_UNLIMITED,
125        .max_data_write = MAX_DATA_UNSPECIFIED,
126        .command        = dummy_spi_send_command,
127        .multicommand   = default_spi_send_multicommand,
128        .read           = default_spi_read,
129        .write_256      = dummy_spi_write_256,
130        .write_aai      = default_spi_write_aai,
131};
132
133static const struct par_programmer par_programmer_dummy = {
134                .chip_readb             = dummy_chip_readb,
135                .chip_readw             = dummy_chip_readw,
136                .chip_readl             = dummy_chip_readl,
137                .chip_readn             = dummy_chip_readn,
138                .chip_writeb            = dummy_chip_writeb,
139                .chip_writew            = dummy_chip_writew,
140                .chip_writel            = dummy_chip_writel,
141                .chip_writen            = dummy_chip_writen,
142};
143
144enum chipbustype dummy_buses_supported = BUS_NONE;
145
146static int dummy_shutdown(void *data)
147{
148        msg_pspew("%s\n", __func__);
149#if EMULATE_CHIP
150        if (emu_chip != EMULATE_NONE) {
151                if (emu_persistent_image) {
152                        msg_pdbg("Writing %s\n", emu_persistent_image);
153                        write_buf_to_file(flashchip_contents, emu_chip_size, emu_persistent_image);
154                        free(emu_persistent_image);
155                        emu_persistent_image = NULL;
156                }
157                free(flashchip_contents);
158        }
159#endif
160        return 0;
161}
162
163int dummy_init(void)
164{
165        char *bustext = NULL;
166        char *tmp = NULL;
167        int i;
168#if EMULATE_SPI_CHIP
169        char *status = NULL;
170#endif
171#if EMULATE_CHIP
172        struct stat image_stat;
173#endif
174
175        msg_pspew("%s\n", __func__);
176
177        bustext = extract_programmer_param("bus");
178        msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
179        if (!bustext)
180                bustext = strdup("parallel+lpc+fwh+spi");
181        /* Convert the parameters to lowercase. */
182        tolower_string(bustext);
183
184        dummy_buses_supported = BUS_NONE;
185        if (strstr(bustext, "parallel")) {
186                dummy_buses_supported |= BUS_PARALLEL;
187                msg_pdbg("Enabling support for %s flash.\n", "parallel");
188        }
189        if (strstr(bustext, "lpc")) {
190                dummy_buses_supported |= BUS_LPC;
191                msg_pdbg("Enabling support for %s flash.\n", "LPC");
192        }
193        if (strstr(bustext, "fwh")) {
194                dummy_buses_supported |= BUS_FWH;
195                msg_pdbg("Enabling support for %s flash.\n", "FWH");
196        }
197        if (strstr(bustext, "spi")) {
198                dummy_buses_supported |= BUS_SPI;
199                msg_pdbg("Enabling support for %s flash.\n", "SPI");
200        }
201        if (dummy_buses_supported == BUS_NONE)
202                msg_pdbg("Support for all flash bus types disabled.\n");
203        free(bustext);
204
205        tmp = extract_programmer_param("spi_write_256_chunksize");
206        if (tmp) {
207                spi_write_256_chunksize = atoi(tmp);
208                free(tmp);
209                if (spi_write_256_chunksize < 1) {
210                        msg_perr("invalid spi_write_256_chunksize\n");
211                        return 1;
212                }
213        }
214
215        tmp = extract_programmer_param("spi_blacklist");
216        if (tmp) {
217                i = strlen(tmp);
218                if (!strncmp(tmp, "0x", 2)) {
219                        i -= 2;
220                        memmove(tmp, tmp + 2, i + 1);
221                }
222                if ((i > 512) || (i % 2)) {
223                        msg_perr("Invalid SPI command blacklist length\n");
224                        free(tmp);
225                        return 1;
226                }
227                spi_blacklist_size = i / 2;
228                for (i = 0; i < spi_blacklist_size * 2; i++) {
229                        if (!isxdigit((unsigned char)tmp[i])) {
230                                msg_perr("Invalid char \"%c\" in SPI command "
231                                         "blacklist\n", tmp[i]);
232                                free(tmp);
233                                return 1;
234                        }
235                }
236                for (i = 0; i < spi_blacklist_size; i++) {
237                        unsigned int tmp2;
238                        /* SCNx8 is apparently not supported by MSVC (and thus
239                         * MinGW), so work around it with an extra variable
240                         */
241                        sscanf(tmp + i * 2, "%2x", &tmp2);
242                        spi_blacklist[i] = (uint8_t)tmp2;
243                }
244                msg_pdbg("SPI blacklist is ");
245                for (i = 0; i < spi_blacklist_size; i++)
246                        msg_pdbg("%02x ", spi_blacklist[i]);
247                msg_pdbg(", size %i\n", spi_blacklist_size);
248        }
249        free(tmp);
250
251        tmp = extract_programmer_param("spi_ignorelist");
252        if (tmp) {
253                i = strlen(tmp);
254                if (!strncmp(tmp, "0x", 2)) {
255                        i -= 2;
256                        memmove(tmp, tmp + 2, i + 1);
257                }
258                if ((i > 512) || (i % 2)) {
259                        msg_perr("Invalid SPI command ignorelist length\n");
260                        free(tmp);
261                        return 1;
262                }
263                spi_ignorelist_size = i / 2;
264                for (i = 0; i < spi_ignorelist_size * 2; i++) {
265                        if (!isxdigit((unsigned char)tmp[i])) {
266                                msg_perr("Invalid char \"%c\" in SPI command "
267                                         "ignorelist\n", tmp[i]);
268                                free(tmp);
269                                return 1;
270                        }
271                }
272                for (i = 0; i < spi_ignorelist_size; i++) {
273                        unsigned int tmp2;
274                        /* SCNx8 is apparently not supported by MSVC (and thus
275                         * MinGW), so work around it with an extra variable
276                         */
277                        sscanf(tmp + i * 2, "%2x", &tmp2);
278                        spi_ignorelist[i] = (uint8_t)tmp2;
279                }
280                msg_pdbg("SPI ignorelist is ");
281                for (i = 0; i < spi_ignorelist_size; i++)
282                        msg_pdbg("%02x ", spi_ignorelist[i]);
283                msg_pdbg(", size %i\n", spi_ignorelist_size);
284        }
285        free(tmp);
286
287#if EMULATE_CHIP
288        tmp = extract_programmer_param("emulate");
289        if (!tmp) {
290                msg_pdbg("Not emulating any flash chip.\n");
291                /* Nothing else to do. */
292                goto dummy_init_out;
293        }
294#if EMULATE_SPI_CHIP
295        if (!strcmp(tmp, "M25P10.RES")) {
296                emu_chip = EMULATE_ST_M25P10_RES;
297                emu_chip_size = 128 * 1024;
298                emu_max_byteprogram_size = 128;
299                emu_max_aai_size = 0;
300                emu_jedec_se_size = 0;
301                emu_jedec_be_52_size = 0;
302                emu_jedec_be_d8_size = 32 * 1024;
303                emu_jedec_ce_60_size = 0;
304                emu_jedec_ce_c7_size = emu_chip_size;
305                msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
306                         "write)\n");
307        }
308        if (!strcmp(tmp, "SST25VF040.REMS")) {
309                emu_chip = EMULATE_SST_SST25VF040_REMS;
310                emu_chip_size = 512 * 1024;
311                emu_max_byteprogram_size = 1;
312                emu_max_aai_size = 0;
313                emu_jedec_se_size = 4 * 1024;
314                emu_jedec_be_52_size = 32 * 1024;
315                emu_jedec_be_d8_size = 0;
316                emu_jedec_ce_60_size = emu_chip_size;
317                emu_jedec_ce_c7_size = 0;
318                msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
319                         "byte write)\n");
320        }
321        if (!strcmp(tmp, "SST25VF032B")) {
322                emu_chip = EMULATE_SST_SST25VF032B;
323                emu_chip_size = 4 * 1024 * 1024;
324                emu_max_byteprogram_size = 1;
325                emu_max_aai_size = 2;
326                emu_jedec_se_size = 4 * 1024;
327                emu_jedec_be_52_size = 32 * 1024;
328                emu_jedec_be_d8_size = 64 * 1024;
329                emu_jedec_ce_60_size = emu_chip_size;
330                emu_jedec_ce_c7_size = emu_chip_size;
331                msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
332                         "write)\n");
333        }
334        if (!strcmp(tmp, "MX25L6436")) {
335                emu_chip = EMULATE_MACRONIX_MX25L6436;
336                emu_chip_size = 8 * 1024 * 1024;
337                emu_max_byteprogram_size = 256;
338                emu_max_aai_size = 0;
339                emu_jedec_se_size = 4 * 1024;
340                emu_jedec_be_52_size = 32 * 1024;
341                emu_jedec_be_d8_size = 64 * 1024;
342                emu_jedec_ce_60_size = emu_chip_size;
343                emu_jedec_ce_c7_size = emu_chip_size;
344                msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
345                         "SFDP)\n");
346        }
347#endif
348        if (emu_chip == EMULATE_NONE) {
349                msg_perr("Invalid chip specified for emulation: %s\n", tmp);
350                free(tmp);
351                return 1;
352        }
353        free(tmp);
354        flashchip_contents = malloc(emu_chip_size);
355        if (!flashchip_contents) {
356                msg_perr("Out of memory!\n");
357                return 1;
358        }
359
360#ifdef EMULATE_SPI_CHIP
361        status = extract_programmer_param("spi_status");
362        if (status) {
363                char *endptr;
364                errno = 0;
365                emu_status = strtoul(status, &endptr, 0);
366                free(status);
367                if (errno != 0 || status == endptr) {
368                        msg_perr("Error: initial status register specified, "
369                                 "but the value could not be converted.\n");
370                        return 1;
371                }
372                msg_pdbg("Initial status register is set to 0x%02x.\n",
373                         emu_status);
374        }
375#endif
376
377        msg_pdbg("Filling fake flash chip with 0xff, size %i\n", emu_chip_size);
378        memset(flashchip_contents, 0xff, emu_chip_size);
379
380        emu_persistent_image = extract_programmer_param("image");
381        if (!emu_persistent_image) {
382                /* Nothing else to do. */
383                goto dummy_init_out;
384        }
385        if (!stat(emu_persistent_image, &image_stat)) {
386                msg_pdbg("Found persistent image %s, size %li ",
387                         emu_persistent_image, (long)image_stat.st_size);
388                if (image_stat.st_size == emu_chip_size) {
389                        msg_pdbg("matches.\n");
390                        msg_pdbg("Reading %s\n", emu_persistent_image);
391                        read_buf_from_file(flashchip_contents, emu_chip_size,
392                                           emu_persistent_image);
393                } else {
394                        msg_pdbg("doesn't match.\n");
395                }
396        }
397#endif
398
399dummy_init_out:
400        if (register_shutdown(dummy_shutdown, NULL)) {
401                free(flashchip_contents);
402                return 1;
403        }
404        if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
405                register_par_programmer(&par_programmer_dummy,
406                                        dummy_buses_supported &
407                                                (BUS_PARALLEL | BUS_LPC |
408                                                 BUS_FWH));
409        if (dummy_buses_supported & BUS_SPI)
410                register_spi_programmer(&spi_programmer_dummyflasher);
411
412        return 0;
413}
414
415void *dummy_map(const char *descr, unsigned long phys_addr, size_t len)
416{
417        msg_pspew("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n",
418                  __func__, descr, (unsigned long)len, phys_addr);
419        return (void *)phys_addr;
420}
421
422void dummy_unmap(void *virt_addr, size_t len)
423{
424        msg_pspew("%s: Unmapping 0x%lx bytes at %p\n",
425                  __func__, (unsigned long)len, virt_addr);
426}
427
428static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val,
429                              chipaddr addr)
430{
431        msg_pspew("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val);
432}
433
434static void dummy_chip_writew(const struct flashctx *flash, uint16_t val,
435                              chipaddr addr)
436{
437        msg_pspew("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val);
438}
439
440static void dummy_chip_writel(const struct flashctx *flash, uint32_t val,
441                              chipaddr addr)
442{
443        msg_pspew("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val);
444}
445
446static void dummy_chip_writen(const struct flashctx *flash, uint8_t *buf,
447                              chipaddr addr, size_t len)
448{
449        size_t i;
450        msg_pspew("%s: addr=0x%lx, len=0x%08lx, writing data (hex):",
451                  __func__, addr, (unsigned long)len);
452        for (i = 0; i < len; i++) {
453                if ((i % 16) == 0)
454                        msg_pspew("\n");
455                msg_pspew("%02x ", buf[i]);
456        }
457}
458
459static uint8_t dummy_chip_readb(const struct flashctx *flash,
460                                const chipaddr addr)
461{
462        msg_pspew("%s:  addr=0x%lx, returning 0xff\n", __func__, addr);
463        return 0xff;
464}
465
466static uint16_t dummy_chip_readw(const struct flashctx *flash,
467                                 const chipaddr addr)
468{
469        msg_pspew("%s:  addr=0x%lx, returning 0xffff\n", __func__, addr);
470        return 0xffff;
471}
472
473static uint32_t dummy_chip_readl(const struct flashctx *flash,
474                                 const chipaddr addr)
475{
476        msg_pspew("%s:  addr=0x%lx, returning 0xffffffff\n", __func__, addr);
477        return 0xffffffff;
478}
479
480static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf,
481                             const chipaddr addr, size_t len)
482{
483        msg_pspew("%s:  addr=0x%lx, len=0x%lx, returning array of 0xff\n",
484                  __func__, addr, (unsigned long)len);
485        memset(buf, 0xff, len);
486        return;
487}
488
489#if EMULATE_SPI_CHIP
490static int emulate_spi_chip_response(unsigned int writecnt,
491                                     unsigned int readcnt,
492                                     const unsigned char *writearr,
493                                     unsigned char *readarr)
494{
495        unsigned int offs, i, toread;
496        static int unsigned aai_offs;
497        const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};
498        const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
499        const unsigned char mx25l6436_rems_response[2] = {0xc2, 0x16};
500
501        if (writecnt == 0) {
502                msg_perr("No command sent to the chip!\n");
503                return 1;
504        }
505        /* spi_blacklist has precedence over spi_ignorelist. */
506        for (i = 0; i < spi_blacklist_size; i++) {
507                if (writearr[0] == spi_blacklist[i]) {
508                        msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
509                                 spi_blacklist[i]);
510                        return SPI_INVALID_OPCODE;
511                }
512        }
513        for (i = 0; i < spi_ignorelist_size; i++) {
514                if (writearr[0] == spi_ignorelist[i]) {
515                        msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
516                                 spi_ignorelist[i]);
517                        /* Return success because the command does not fail,
518                         * it is simply ignored.
519                         */
520                        return 0;
521                }
522        }
523
524        if (emu_max_aai_size && (emu_status & SPI_SR_AAI)) {
525                if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
526                    writearr[0] != JEDEC_WRDI &&
527                    writearr[0] != JEDEC_RDSR) {
528                        msg_perr("Forbidden opcode (0x%02x) attempted during "
529                                 "AAI sequence!\n", writearr[0]);
530                        return 0;
531                }
532        }
533
534        switch (writearr[0]) {
535        case JEDEC_RES:
536                if (writecnt < JEDEC_RES_OUTSIZE)
537                        break;
538                /* offs calculation is only needed for SST chips which treat RES like REMS. */
539                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
540                offs += writecnt - JEDEC_REMS_OUTSIZE;
541                switch (emu_chip) {
542                case EMULATE_ST_M25P10_RES:
543                        if (readcnt > 0)
544                                memset(readarr, 0x10, readcnt);
545                        break;
546                case EMULATE_SST_SST25VF040_REMS:
547                        for (i = 0; i < readcnt; i++)
548                                readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
549                        break;
550                case EMULATE_SST_SST25VF032B:
551                        for (i = 0; i < readcnt; i++)
552                                readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
553                        break;
554                case EMULATE_MACRONIX_MX25L6436:
555                        if (readcnt > 0)
556                                memset(readarr, 0x16, readcnt);
557                        break;
558                default: /* ignore */
559                        break;
560                }
561                break;
562        case JEDEC_REMS:
563                /* REMS response has wraparound and uses an address parameter. */
564                if (writecnt < JEDEC_REMS_OUTSIZE)
565                        break;
566                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
567                offs += writecnt - JEDEC_REMS_OUTSIZE;
568                switch (emu_chip) {
569                case EMULATE_SST_SST25VF040_REMS:
570                        for (i = 0; i < readcnt; i++)
571                                readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
572                        break;
573                case EMULATE_SST_SST25VF032B:
574                        for (i = 0; i < readcnt; i++)
575                                readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
576                        break;
577                case EMULATE_MACRONIX_MX25L6436:
578                        for (i = 0; i < readcnt; i++)
579                                readarr[i] = mx25l6436_rems_response[(offs + i) % 2];
580                        break;
581                default: /* ignore */
582                        break;
583                }
584                break;
585        case JEDEC_RDID:
586                switch (emu_chip) {
587                case EMULATE_SST_SST25VF032B:
588                        if (readcnt > 0)
589                                readarr[0] = 0xbf;
590                        if (readcnt > 1)
591                                readarr[1] = 0x25;
592                        if (readcnt > 2)
593                                readarr[2] = 0x4a;
594                        break;
595                case EMULATE_MACRONIX_MX25L6436:
596                        if (readcnt > 0)
597                                readarr[0] = 0xc2;
598                        if (readcnt > 1)
599                                readarr[1] = 0x20;
600                        if (readcnt > 2)
601                                readarr[2] = 0x17;
602                        break;
603                default: /* ignore */
604                        break;
605                }
606                break;
607        case JEDEC_RDSR:
608                memset(readarr, emu_status, readcnt);
609                break;
610        /* FIXME: this should be chip-specific. */
611        case JEDEC_EWSR:
612        case JEDEC_WREN:
613                emu_status |= SPI_SR_WEL;
614                break;
615        case JEDEC_WRSR:
616                if (!(emu_status & SPI_SR_WEL)) {
617                        msg_perr("WRSR attempted, but WEL is 0!\n");
618                        break;
619                }
620                /* FIXME: add some reasonable simulation of the busy flag */
621                emu_status = writearr[1] & ~SPI_SR_WIP;
622                msg_pdbg2("WRSR wrote 0x%02x.\n", emu_status);
623                break;
624        case JEDEC_READ:
625                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
626                /* Truncate to emu_chip_size. */
627                offs %= emu_chip_size;
628                if (readcnt > 0)
629                        memcpy(readarr, flashchip_contents + offs, readcnt);
630                break;
631        case JEDEC_BYTE_PROGRAM:
632                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
633                /* Truncate to emu_chip_size. */
634                offs %= emu_chip_size;
635                if (writecnt < 5) {
636                        msg_perr("BYTE PROGRAM size too short!\n");
637                        return 1;
638                }
639                if (writecnt - 4 > emu_max_byteprogram_size) {
640                        msg_perr("Max BYTE PROGRAM size exceeded!\n");
641                        return 1;
642                }
643                memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
644                break;
645        case JEDEC_AAI_WORD_PROGRAM:
646                if (!emu_max_aai_size)
647                        break;
648                if (!(emu_status & SPI_SR_AAI)) {
649                        if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
650                                msg_perr("Initial AAI WORD PROGRAM size too "
651                                         "short!\n");
652                                return 1;
653                        }
654                        if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
655                                msg_perr("Initial AAI WORD PROGRAM size too "
656                                         "long!\n");
657                                return 1;
658                        }
659                        emu_status |= SPI_SR_AAI;
660                        aai_offs = writearr[1] << 16 | writearr[2] << 8 |
661                                   writearr[3];
662                        /* Truncate to emu_chip_size. */
663                        aai_offs %= emu_chip_size;
664                        memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
665                        aai_offs += 2;
666                } else {
667                        if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
668                                msg_perr("Continuation AAI WORD PROGRAM size "
669                                         "too short!\n");
670                                return 1;
671                        }
672                        if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
673                                msg_perr("Continuation AAI WORD PROGRAM size "
674                                         "too long!\n");
675                                return 1;
676                        }
677                        memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
678                        aai_offs += 2;
679                }
680                break;
681        case JEDEC_WRDI:
682                if (emu_max_aai_size)
683                        emu_status &= ~SPI_SR_AAI;
684                break;
685        case JEDEC_SE:
686                if (!emu_jedec_se_size)
687                        break;
688                if (writecnt != JEDEC_SE_OUTSIZE) {
689                        msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
690                        return 1;
691                }
692                if (readcnt != JEDEC_SE_INSIZE) {
693                        msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
694                        return 1;
695                }
696                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
697                if (offs & (emu_jedec_se_size - 1))
698                        msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
699                offs &= ~(emu_jedec_se_size - 1);
700                memset(flashchip_contents + offs, 0xff, emu_jedec_se_size);
701                break;
702        case JEDEC_BE_52:
703                if (!emu_jedec_be_52_size)
704                        break;
705                if (writecnt != JEDEC_BE_52_OUTSIZE) {
706                        msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
707                        return 1;
708                }
709                if (readcnt != JEDEC_BE_52_INSIZE) {
710                        msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
711                        return 1;
712                }
713                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
714                if (offs & (emu_jedec_be_52_size - 1))
715                        msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
716                offs &= ~(emu_jedec_be_52_size - 1);
717                memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size);
718                break;
719        case JEDEC_BE_D8:
720                if (!emu_jedec_be_d8_size)
721                        break;
722                if (writecnt != JEDEC_BE_D8_OUTSIZE) {
723                        msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
724                        return 1;
725                }
726                if (readcnt != JEDEC_BE_D8_INSIZE) {
727                        msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
728                        return 1;
729                }
730                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
731                if (offs & (emu_jedec_be_d8_size - 1))
732                        msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
733                offs &= ~(emu_jedec_be_d8_size - 1);
734                memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size);
735                break;
736        case JEDEC_CE_60:
737                if (!emu_jedec_ce_60_size)
738                        break;
739                if (writecnt != JEDEC_CE_60_OUTSIZE) {
740                        msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
741                        return 1;
742                }
743                if (readcnt != JEDEC_CE_60_INSIZE) {
744                        msg_perr("CHIP ERASE 0x60 insize invalid!\n");
745                        return 1;
746                }
747                /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
748                /* emu_jedec_ce_60_size is emu_chip_size. */
749                memset(flashchip_contents, 0xff, emu_jedec_ce_60_size);
750                break;
751        case JEDEC_CE_C7:
752                if (!emu_jedec_ce_c7_size)
753                        break;
754                if (writecnt != JEDEC_CE_C7_OUTSIZE) {
755                        msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
756                        return 1;
757                }
758                if (readcnt != JEDEC_CE_C7_INSIZE) {
759                        msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
760                        return 1;
761                }
762                /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
763                /* emu_jedec_ce_c7_size is emu_chip_size. */
764                memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size);
765                break;
766        case JEDEC_SFDP:
767                if (emu_chip != EMULATE_MACRONIX_MX25L6436)
768                        break;
769                if (writecnt < 4)
770                        break;
771                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
772
773                /* SFDP expects one dummy byte after the address. */
774                if (writecnt == 4) {
775                        /* The dummy byte was not written, make sure it is read instead.
776                         * Shifting and shortening the read array does achieve this goal.
777                         */
778                        readarr++;
779                        readcnt--;
780                } else {
781                        /* The response is shifted if more than 5 bytes are written, because SFDP data is
782                         * already shifted out by the chip while those superfluous bytes are written. */
783                        offs += writecnt - 5;
784                }
785
786                /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
787                 * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
788                 * This is a reasonable implementation choice in hardware because it saves a few gates. */
789                if (offs >= sizeof(sfdp_table)) {
790                        msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
791                                 "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
792                        offs %= sizeof(sfdp_table);
793                }
794                toread = min(sizeof(sfdp_table) - offs, readcnt);
795                memcpy(readarr, sfdp_table + offs, toread);
796                if (toread < readcnt)
797                        msg_pdbg("Crossing the SFDP table boundary in a single "
798                                 "continuous chunk produces undefined results "
799                                 "after that point.\n");
800                break;
801        default:
802                /* No special response. */
803                break;
804        }
805        if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
806                emu_status &= ~SPI_SR_WEL;
807        return 0;
808}
809#endif
810
811static int dummy_spi_send_command(struct flashctx *flash, unsigned int writecnt,
812                                  unsigned int readcnt,
813                                  const unsigned char *writearr,
814                                  unsigned char *readarr)
815{
816        int i;
817
818        msg_pspew("%s:", __func__);
819
820        msg_pspew(" writing %u bytes:", writecnt);
821        for (i = 0; i < writecnt; i++)
822                msg_pspew(" 0x%02x", writearr[i]);
823
824        /* Response for unknown commands and missing chip is 0xff. */
825        memset(readarr, 0xff, readcnt);
826#if EMULATE_SPI_CHIP
827        switch (emu_chip) {
828        case EMULATE_ST_M25P10_RES:
829        case EMULATE_SST_SST25VF040_REMS:
830        case EMULATE_SST_SST25VF032B:
831        case EMULATE_MACRONIX_MX25L6436:
832                if (emulate_spi_chip_response(writecnt, readcnt, writearr,
833                                              readarr)) {
834                        msg_pdbg("Invalid command sent to flash chip!\n");
835                        return 1;
836                }
837                break;
838        default:
839                break;
840        }
841#endif
842        msg_pspew(" reading %u bytes:", readcnt);
843        for (i = 0; i < readcnt; i++)
844                msg_pspew(" 0x%02x", readarr[i]);
845        msg_pspew("\n");
846        return 0;
847}
848
849static int dummy_spi_write_256(struct flashctx *flash, uint8_t *buf,
850                               unsigned int start, unsigned int len)
851{
852        return spi_write_chunked(flash, buf, start, len,
853                                 spi_write_256_chunksize);
854}
Note: See TracBrowser for help on using the repository browser.