source: trunk/dummyflasher.c @ 1534

Revision 1534, 23.3 KB checked in by stefanct, 10 days ago (diff)

dummyflasher.c: add support for SFDP by adding a new emulator chip: MX25L6436

The chip features a complete 1.0 SFDP JEDEC flash parameter table and also a
vendor-specific extension table (defining voltages, lock bits etc).
NB: the MX25L6436 uses the same RDID as the MX25L6405.

Signed-off-by: Stefan Tauner <stefan.tauner@…>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>

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 const 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};
131
132static const struct par_programmer par_programmer_dummy = {
133                .chip_readb             = dummy_chip_readb,
134                .chip_readw             = dummy_chip_readw,
135                .chip_readl             = dummy_chip_readl,
136                .chip_readn             = dummy_chip_readn,
137                .chip_writeb            = dummy_chip_writeb,
138                .chip_writew            = dummy_chip_writew,
139                .chip_writel            = dummy_chip_writel,
140                .chip_writen            = dummy_chip_writen,
141};
142
143enum chipbustype dummy_buses_supported = BUS_NONE;
144
145static int dummy_shutdown(void *data)
146{
147        msg_pspew("%s\n", __func__);
148#if EMULATE_CHIP
149        if (emu_chip != EMULATE_NONE) {
150                if (emu_persistent_image) {
151                        msg_pdbg("Writing %s\n", emu_persistent_image);
152                        write_buf_to_file(flashchip_contents, emu_chip_size,
153                                          emu_persistent_image);
154                }
155                free(flashchip_contents);
156        }
157#endif
158        return 0;
159}
160
161int dummy_init(void)
162{
163        char *bustext = NULL;
164        char *tmp = NULL;
165        int i;
166#if EMULATE_SPI_CHIP
167        char *status = NULL;
168#endif
169#if EMULATE_CHIP
170        struct stat image_stat;
171#endif
172
173        msg_pspew("%s\n", __func__);
174
175        bustext = extract_programmer_param("bus");
176        msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
177        if (!bustext)
178                bustext = strdup("parallel+lpc+fwh+spi");
179        /* Convert the parameters to lowercase. */
180        tolower_string(bustext);
181
182        dummy_buses_supported = BUS_NONE;
183        if (strstr(bustext, "parallel")) {
184                dummy_buses_supported |= BUS_PARALLEL;
185                msg_pdbg("Enabling support for %s flash.\n", "parallel");
186        }
187        if (strstr(bustext, "lpc")) {
188                dummy_buses_supported |= BUS_LPC;
189                msg_pdbg("Enabling support for %s flash.\n", "LPC");
190        }
191        if (strstr(bustext, "fwh")) {
192                dummy_buses_supported |= BUS_FWH;
193                msg_pdbg("Enabling support for %s flash.\n", "FWH");
194        }
195        if (strstr(bustext, "spi")) {
196                dummy_buses_supported |= BUS_SPI;
197                msg_pdbg("Enabling support for %s flash.\n", "SPI");
198        }
199        if (dummy_buses_supported == BUS_NONE)
200                msg_pdbg("Support for all flash bus types disabled.\n");
201        free(bustext);
202
203        tmp = extract_programmer_param("spi_write_256_chunksize");
204        if (tmp) {
205                spi_write_256_chunksize = atoi(tmp);
206                free(tmp);
207                if (spi_write_256_chunksize < 1) {
208                        msg_perr("invalid spi_write_256_chunksize\n");
209                        return 1;
210                }
211        }
212
213        tmp = extract_programmer_param("spi_blacklist");
214        if (tmp) {
215                i = strlen(tmp);
216                if (!strncmp(tmp, "0x", 2)) {
217                        i -= 2;
218                        memmove(tmp, tmp + 2, i + 1);
219                }
220                if ((i > 512) || (i % 2)) {
221                        msg_perr("Invalid SPI command blacklist length\n");
222                        free(tmp);
223                        return 1;
224                }
225                spi_blacklist_size = i / 2;
226                for (i = 0; i < spi_blacklist_size * 2; i++) {
227                        if (!isxdigit((unsigned char)tmp[i])) {
228                                msg_perr("Invalid char \"%c\" in SPI command "
229                                         "blacklist\n", tmp[i]);
230                                free(tmp);
231                                return 1;
232                        }
233                }
234                for (i = 0; i < spi_blacklist_size; i++) {
235                        unsigned int tmp2;
236                        /* SCNx8 is apparently not supported by MSVC (and thus
237                         * MinGW), so work around it with an extra variable
238                         */
239                        sscanf(tmp + i * 2, "%2x", &tmp2);
240                        spi_blacklist[i] = (uint8_t)tmp2;
241                }
242                msg_pdbg("SPI blacklist is ");
243                for (i = 0; i < spi_blacklist_size; i++)
244                        msg_pdbg("%02x ", spi_blacklist[i]);
245                msg_pdbg(", size %i\n", spi_blacklist_size);
246        }
247        free(tmp);
248
249        tmp = extract_programmer_param("spi_ignorelist");
250        if (tmp) {
251                i = strlen(tmp);
252                if (!strncmp(tmp, "0x", 2)) {
253                        i -= 2;
254                        memmove(tmp, tmp + 2, i + 1);
255                }
256                if ((i > 512) || (i % 2)) {
257                        msg_perr("Invalid SPI command ignorelist length\n");
258                        free(tmp);
259                        return 1;
260                }
261                spi_ignorelist_size = i / 2;
262                for (i = 0; i < spi_ignorelist_size * 2; i++) {
263                        if (!isxdigit((unsigned char)tmp[i])) {
264                                msg_perr("Invalid char \"%c\" in SPI command "
265                                         "ignorelist\n", tmp[i]);
266                                free(tmp);
267                                return 1;
268                        }
269                }
270                for (i = 0; i < spi_ignorelist_size; i++) {
271                        unsigned int tmp2;
272                        /* SCNx8 is apparently not supported by MSVC (and thus
273                         * MinGW), so work around it with an extra variable
274                         */
275                        sscanf(tmp + i * 2, "%2x", &tmp2);
276                        spi_ignorelist[i] = (uint8_t)tmp2;
277                }
278                msg_pdbg("SPI ignorelist is ");
279                for (i = 0; i < spi_ignorelist_size; i++)
280                        msg_pdbg("%02x ", spi_ignorelist[i]);
281                msg_pdbg(", size %i\n", spi_ignorelist_size);
282        }
283        free(tmp);
284
285#if EMULATE_CHIP
286        tmp = extract_programmer_param("emulate");
287        if (!tmp) {
288                msg_pdbg("Not emulating any flash chip.\n");
289                /* Nothing else to do. */
290                goto dummy_init_out;
291        }
292#if EMULATE_SPI_CHIP
293        if (!strcmp(tmp, "M25P10.RES")) {
294                emu_chip = EMULATE_ST_M25P10_RES;
295                emu_chip_size = 128 * 1024;
296                emu_max_byteprogram_size = 128;
297                emu_max_aai_size = 0;
298                emu_jedec_se_size = 0;
299                emu_jedec_be_52_size = 0;
300                emu_jedec_be_d8_size = 32 * 1024;
301                emu_jedec_ce_60_size = 0;
302                emu_jedec_ce_c7_size = emu_chip_size;
303                msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
304                         "write)\n");
305        }
306        if (!strcmp(tmp, "SST25VF040.REMS")) {
307                emu_chip = EMULATE_SST_SST25VF040_REMS;
308                emu_chip_size = 512 * 1024;
309                emu_max_byteprogram_size = 1;
310                emu_max_aai_size = 0;
311                emu_jedec_se_size = 4 * 1024;
312                emu_jedec_be_52_size = 32 * 1024;
313                emu_jedec_be_d8_size = 0;
314                emu_jedec_ce_60_size = emu_chip_size;
315                emu_jedec_ce_c7_size = 0;
316                msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
317                         "byte write)\n");
318        }
319        if (!strcmp(tmp, "SST25VF032B")) {
320                emu_chip = EMULATE_SST_SST25VF032B;
321                emu_chip_size = 4 * 1024 * 1024;
322                emu_max_byteprogram_size = 1;
323                emu_max_aai_size = 2;
324                emu_jedec_se_size = 4 * 1024;
325                emu_jedec_be_52_size = 32 * 1024;
326                emu_jedec_be_d8_size = 64 * 1024;
327                emu_jedec_ce_60_size = emu_chip_size;
328                emu_jedec_ce_c7_size = emu_chip_size;
329                msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
330                         "write)\n");
331        }
332        if (!strcmp(tmp, "MX25L6436")) {
333                emu_chip = EMULATE_MACRONIX_MX25L6436;
334                emu_chip_size = 8 * 1024 * 1024;
335                emu_max_byteprogram_size = 256;
336                emu_max_aai_size = 0;
337                emu_jedec_se_size = 4 * 1024;
338                emu_jedec_be_52_size = 32 * 1024;
339                emu_jedec_be_d8_size = 64 * 1024;
340                emu_jedec_ce_60_size = emu_chip_size;
341                emu_jedec_ce_c7_size = emu_chip_size;
342                msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
343                         "SFDP)\n");
344        }
345#endif
346        if (emu_chip == EMULATE_NONE) {
347                msg_perr("Invalid chip specified for emulation: %s\n", tmp);
348                free(tmp);
349                return 1;
350        }
351        free(tmp);
352        flashchip_contents = malloc(emu_chip_size);
353        if (!flashchip_contents) {
354                msg_perr("Out of memory!\n");
355                return 1;
356        }
357
358#ifdef EMULATE_SPI_CHIP
359        status = extract_programmer_param("spi_status");
360        if (status) {
361                char *endptr;
362                errno = 0;
363                emu_status = strtoul(status, &endptr, 0);
364                free(status);
365                if (errno != 0 || status == endptr) {
366                        msg_perr("Error: initial status register specified, "
367                                 "but the value could not be converted.\n");
368                        return 1;
369                }
370                msg_pdbg("Initial status register is set to 0x%02x.\n",
371                         emu_status);
372        }
373#endif
374
375        msg_pdbg("Filling fake flash chip with 0xff, size %i\n", emu_chip_size);
376        memset(flashchip_contents, 0xff, emu_chip_size);
377
378        emu_persistent_image = extract_programmer_param("image");
379        if (!emu_persistent_image) {
380                /* Nothing else to do. */
381                goto dummy_init_out;
382        }
383        if (!stat(emu_persistent_image, &image_stat)) {
384                msg_pdbg("Found persistent image %s, size %li ",
385                         emu_persistent_image, (long)image_stat.st_size);
386                if (image_stat.st_size == emu_chip_size) {
387                        msg_pdbg("matches.\n");
388                        msg_pdbg("Reading %s\n", emu_persistent_image);
389                        read_buf_from_file(flashchip_contents, emu_chip_size,
390                                           emu_persistent_image);
391                } else {
392                        msg_pdbg("doesn't match.\n");
393                }
394        }
395#endif
396
397dummy_init_out:
398        if (register_shutdown(dummy_shutdown, NULL)) {
399                free(flashchip_contents);
400                return 1;
401        }
402        if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
403                register_par_programmer(&par_programmer_dummy,
404                                        dummy_buses_supported &
405                                                (BUS_PARALLEL | BUS_LPC |
406                                                 BUS_FWH));
407        if (dummy_buses_supported & BUS_SPI)
408                register_spi_programmer(&spi_programmer_dummyflasher);
409
410        return 0;
411}
412
413void *dummy_map(const char *descr, unsigned long phys_addr, size_t len)
414{
415        msg_pspew("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n",
416                  __func__, descr, (unsigned long)len, phys_addr);
417        return (void *)phys_addr;
418}
419
420void dummy_unmap(void *virt_addr, size_t len)
421{
422        msg_pspew("%s: Unmapping 0x%lx bytes at %p\n",
423                  __func__, (unsigned long)len, virt_addr);
424}
425
426static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val,
427                              chipaddr addr)
428{
429        msg_pspew("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val);
430}
431
432static void dummy_chip_writew(const struct flashctx *flash, uint16_t val,
433                              chipaddr addr)
434{
435        msg_pspew("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val);
436}
437
438static void dummy_chip_writel(const struct flashctx *flash, uint32_t val,
439                              chipaddr addr)
440{
441        msg_pspew("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val);
442}
443
444static void dummy_chip_writen(const struct flashctx *flash, uint8_t *buf,
445                              chipaddr addr, size_t len)
446{
447        size_t i;
448        msg_pspew("%s: addr=0x%lx, len=0x%08lx, writing data (hex):",
449                  __func__, addr, (unsigned long)len);
450        for (i = 0; i < len; i++) {
451                if ((i % 16) == 0)
452                        msg_pspew("\n");
453                msg_pspew("%02x ", buf[i]);
454        }
455}
456
457static uint8_t dummy_chip_readb(const struct flashctx *flash,
458                                const chipaddr addr)
459{
460        msg_pspew("%s:  addr=0x%lx, returning 0xff\n", __func__, addr);
461        return 0xff;
462}
463
464static uint16_t dummy_chip_readw(const struct flashctx *flash,
465                                 const chipaddr addr)
466{
467        msg_pspew("%s:  addr=0x%lx, returning 0xffff\n", __func__, addr);
468        return 0xffff;
469}
470
471static uint32_t dummy_chip_readl(const struct flashctx *flash,
472                                 const chipaddr addr)
473{
474        msg_pspew("%s:  addr=0x%lx, returning 0xffffffff\n", __func__, addr);
475        return 0xffffffff;
476}
477
478static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf,
479                             const chipaddr addr, size_t len)
480{
481        msg_pspew("%s:  addr=0x%lx, len=0x%lx, returning array of 0xff\n",
482                  __func__, addr, (unsigned long)len);
483        memset(buf, 0xff, len);
484        return;
485}
486
487#if EMULATE_SPI_CHIP
488static int emulate_spi_chip_response(unsigned int writecnt,
489                                     unsigned int readcnt,
490                                     const unsigned char *writearr,
491                                     unsigned char *readarr)
492{
493        unsigned int offs, i, toread;
494        static int unsigned aai_offs;
495
496        if (writecnt == 0) {
497                msg_perr("No command sent to the chip!\n");
498                return 1;
499        }
500        /* spi_blacklist has precedence over spi_ignorelist. */
501        for (i = 0; i < spi_blacklist_size; i++) {
502                if (writearr[0] == spi_blacklist[i]) {
503                        msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
504                                 spi_blacklist[i]);
505                        return SPI_INVALID_OPCODE;
506                }
507        }
508        for (i = 0; i < spi_ignorelist_size; i++) {
509                if (writearr[0] == spi_ignorelist[i]) {
510                        msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
511                                 spi_ignorelist[i]);
512                        /* Return success because the command does not fail,
513                         * it is simply ignored.
514                         */
515                        return 0;
516                }
517        }
518
519        if (emu_max_aai_size && (emu_status & SPI_SR_AAI)) {
520                if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
521                    writearr[0] != JEDEC_WRDI &&
522                    writearr[0] != JEDEC_RDSR) {
523                        msg_perr("Forbidden opcode (0x%02x) attempted during "
524                                 "AAI sequence!\n", writearr[0]);
525                        return 0;
526                }
527        }
528
529        switch (writearr[0]) {
530        case JEDEC_RES:
531                if (emu_chip != EMULATE_ST_M25P10_RES)
532                        break;
533                /* Respond with ST_M25P10_RES. */
534                if (readcnt > 0)
535                        readarr[0] = 0x10;
536                break;
537        case JEDEC_REMS:
538                if (emu_chip != EMULATE_SST_SST25VF040_REMS)
539                        break;
540                /* Respond with SST_SST25VF040_REMS. */
541                if (readcnt > 0)
542                        readarr[0] = 0xbf;
543                if (readcnt > 1)
544                        readarr[1] = 0x44;
545                break;
546        case JEDEC_RDID:
547                switch (emu_chip) {
548                case EMULATE_SST_SST25VF032B:
549                        if (readcnt > 0)
550                                readarr[0] = 0xbf;
551                        if (readcnt > 1)
552                                readarr[1] = 0x25;
553                        if (readcnt > 2)
554                                readarr[2] = 0x4a;
555                        break;
556                case EMULATE_MACRONIX_MX25L6436:
557                        if (readcnt > 0)
558                                readarr[0] = 0xc2;
559                        if (readcnt > 1)
560                                readarr[1] = 0x20;
561                        if (readcnt > 2)
562                                readarr[2] = 0x17;
563                        break;
564                default: /* ignore */
565                        break;
566                }
567                break;
568        case JEDEC_RDSR:
569                memset(readarr, emu_status, readcnt);
570                break;
571        /* FIXME: this should be chip-specific. */
572        case JEDEC_EWSR:
573        case JEDEC_WREN:
574                emu_status |= SPI_SR_WEL;
575                break;
576        case JEDEC_WRSR:
577                if (!(emu_status & SPI_SR_WEL)) {
578                        msg_perr("WRSR attempted, but WEL is 0!\n");
579                        break;
580                }
581                /* FIXME: add some reasonable simulation of the busy flag */
582                emu_status = writearr[1] & ~SPI_SR_WIP;
583                msg_pdbg2("WRSR wrote 0x%02x.\n", emu_status);
584                break;
585        case JEDEC_READ:
586                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
587                /* Truncate to emu_chip_size. */
588                offs %= emu_chip_size;
589                if (readcnt > 0)
590                        memcpy(readarr, flashchip_contents + offs, readcnt);
591                break;
592        case JEDEC_BYTE_PROGRAM:
593                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
594                /* Truncate to emu_chip_size. */
595                offs %= emu_chip_size;
596                if (writecnt < 5) {
597                        msg_perr("BYTE PROGRAM size too short!\n");
598                        return 1;
599                }
600                if (writecnt - 4 > emu_max_byteprogram_size) {
601                        msg_perr("Max BYTE PROGRAM size exceeded!\n");
602                        return 1;
603                }
604                memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
605                break;
606        case JEDEC_AAI_WORD_PROGRAM:
607                if (!emu_max_aai_size)
608                        break;
609                if (!(emu_status & SPI_SR_AAI)) {
610                        if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
611                                msg_perr("Initial AAI WORD PROGRAM size too "
612                                         "short!\n");
613                                return 1;
614                        }
615                        if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
616                                msg_perr("Initial AAI WORD PROGRAM size too "
617                                         "long!\n");
618                                return 1;
619                        }
620                        emu_status |= SPI_SR_AAI;
621                        aai_offs = writearr[1] << 16 | writearr[2] << 8 |
622                                   writearr[3];
623                        /* Truncate to emu_chip_size. */
624                        aai_offs %= emu_chip_size;
625                        memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
626                        aai_offs += 2;
627                } else {
628                        if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
629                                msg_perr("Continuation AAI WORD PROGRAM size "
630                                         "too short!\n");
631                                return 1;
632                        }
633                        if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
634                                msg_perr("Continuation AAI WORD PROGRAM size "
635                                         "too long!\n");
636                                return 1;
637                        }
638                        memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
639                        aai_offs += 2;
640                }
641                break;
642        case JEDEC_WRDI:
643                if (emu_max_aai_size)
644                        emu_status &= ~SPI_SR_AAI;
645                break;
646        case JEDEC_SE:
647                if (!emu_jedec_se_size)
648                        break;
649                if (writecnt != JEDEC_SE_OUTSIZE) {
650                        msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
651                        return 1;
652                }
653                if (readcnt != JEDEC_SE_INSIZE) {
654                        msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
655                        return 1;
656                }
657                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
658                if (offs & (emu_jedec_se_size - 1))
659                        msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
660                offs &= ~(emu_jedec_se_size - 1);
661                memset(flashchip_contents + offs, 0xff, emu_jedec_se_size);
662                break;
663        case JEDEC_BE_52:
664                if (!emu_jedec_be_52_size)
665                        break;
666                if (writecnt != JEDEC_BE_52_OUTSIZE) {
667                        msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
668                        return 1;
669                }
670                if (readcnt != JEDEC_BE_52_INSIZE) {
671                        msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
672                        return 1;
673                }
674                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
675                if (offs & (emu_jedec_be_52_size - 1))
676                        msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
677                offs &= ~(emu_jedec_be_52_size - 1);
678                memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size);
679                break;
680        case JEDEC_BE_D8:
681                if (!emu_jedec_be_d8_size)
682                        break;
683                if (writecnt != JEDEC_BE_D8_OUTSIZE) {
684                        msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
685                        return 1;
686                }
687                if (readcnt != JEDEC_BE_D8_INSIZE) {
688                        msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
689                        return 1;
690                }
691                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
692                if (offs & (emu_jedec_be_d8_size - 1))
693                        msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
694                offs &= ~(emu_jedec_be_d8_size - 1);
695                memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size);
696                break;
697        case JEDEC_CE_60:
698                if (!emu_jedec_ce_60_size)
699                        break;
700                if (writecnt != JEDEC_CE_60_OUTSIZE) {
701                        msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
702                        return 1;
703                }
704                if (readcnt != JEDEC_CE_60_INSIZE) {
705                        msg_perr("CHIP ERASE 0x60 insize invalid!\n");
706                        return 1;
707                }
708                /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
709                /* emu_jedec_ce_60_size is emu_chip_size. */
710                memset(flashchip_contents, 0xff, emu_jedec_ce_60_size);
711                break;
712        case JEDEC_CE_C7:
713                if (!emu_jedec_ce_c7_size)
714                        break;
715                if (writecnt != JEDEC_CE_C7_OUTSIZE) {
716                        msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
717                        return 1;
718                }
719                if (readcnt != JEDEC_CE_C7_INSIZE) {
720                        msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
721                        return 1;
722                }
723                /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
724                /* emu_jedec_ce_c7_size is emu_chip_size. */
725                memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size);
726                break;
727        case JEDEC_SFDP:
728                if (emu_chip != EMULATE_MACRONIX_MX25L6436)
729                        break;
730                if (writecnt < 4)
731                        break;
732                offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
733
734                /* SFDP expects one dummy byte after the address. */
735                if (writecnt == 4) {
736                        /* The dummy byte was not written, make sure it is read instead.
737                         * Shifting and shortening the read array does achieve this goal.
738                         */
739                        readarr++;
740                        readcnt--;
741                } else {
742                        /* The response is shifted if more than 5 bytes are written, because SFDP data is
743                         * already shifted out by the chip while those superfluous bytes are written. */
744                        offs += writecnt - 5;
745                }
746
747                /* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
748                 * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
749                 * This is a reasonable implementation choice in hardware because it saves a few gates. */
750                if (offs >= sizeof(sfdp_table)) {
751                        msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
752                                 "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
753                        offs %= sizeof(sfdp_table);
754                }
755                toread = min(sizeof(sfdp_table) - offs, readcnt);
756                memcpy(readarr, sfdp_table + offs, toread);
757                if (toread < readcnt)
758                        msg_pdbg("Crossing the SFDP table boundary in a single "
759                                 "continuous chunk produces undefined results "
760                                 "after that point.\n");
761                break;
762        default:
763                /* No special response. */
764                break;
765        }
766        if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
767                emu_status &= ~SPI_SR_WEL;
768        return 0;
769}
770#endif
771
772static int dummy_spi_send_command(struct flashctx *flash, unsigned int writecnt,
773                                  unsigned int readcnt,
774                                  const unsigned char *writearr,
775                                  unsigned char *readarr)
776{
777        int i;
778
779        msg_pspew("%s:", __func__);
780
781        msg_pspew(" writing %u bytes:", writecnt);
782        for (i = 0; i < writecnt; i++)
783                msg_pspew(" 0x%02x", writearr[i]);
784
785        /* Response for unknown commands and missing chip is 0xff. */
786        memset(readarr, 0xff, readcnt);
787#if EMULATE_SPI_CHIP
788        switch (emu_chip) {
789        case EMULATE_ST_M25P10_RES:
790        case EMULATE_SST_SST25VF040_REMS:
791        case EMULATE_SST_SST25VF032B:
792        case EMULATE_MACRONIX_MX25L6436:
793                if (emulate_spi_chip_response(writecnt, readcnt, writearr,
794                                              readarr)) {
795                        msg_pdbg("Invalid command sent to flash chip!\n");
796                        return 1;
797                }
798                break;
799        default:
800                break;
801        }
802#endif
803        msg_pspew(" reading %u bytes:", readcnt);
804        for (i = 0; i < readcnt; i++)
805                msg_pspew(" 0x%02x", readarr[i]);
806        msg_pspew("\n");
807        return 0;
808}
809
810static int dummy_spi_write_256(struct flashctx *flash, uint8_t *buf,
811                               unsigned int start, unsigned int len)
812{
813        return spi_write_chunked(flash, buf, start, len,
814                                 spi_write_256_chunksize);
815}
Note: See TracBrowser for help on using the repository browser.