flashrom.c 18.8 KB
Newer Older
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
1
/*
2
 * This file is part of the flashrom project.
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
3
 *
4 5
 * Copyright (C) 2000 Silicon Integrated System Corporation
 * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
Stefan Reinauer's avatar
Stefan Reinauer committed
6
 * Copyright (C) 2005-2008 coresystems GmbH 
7
 * Copyright (C) 2008,2009 Carl-Daniel Hailfinger
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
8
 *
9 10 11 12
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
13
 *
14 15 16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
18
 *
19 20 21
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
22 23 24
 */

#include <fcntl.h>
25 26
#include <sys/types.h>
#include <sys/stat.h>
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
27 28
#include <unistd.h>
#include <stdio.h>
Ronald G. Minnich's avatar
Ronald G. Minnich committed
29
#include <string.h>
Ronald G. Minnich's avatar
Ronald G. Minnich committed
30
#include <stdlib.h>
31
#include <getopt.h>
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
32 33
#include "flash.h"

Ronald G. Minnich's avatar
Ronald G. Minnich committed
34
char *chip_to_probe = NULL;
Stefan Reinauer's avatar
Stefan Reinauer committed
35
int exclude_start_page, exclude_end_page;
Peter Stuge's avatar
Peter Stuge committed
36
int verbose = 0;
37 38 39 40 41 42 43 44 45 46 47 48 49 50
int programmer = PROGRAMMER_INTERNAL;

const struct programmer_entry programmer_table[] = {
	{
		.init		= internal_init,
		.shutdown	= internal_shutdown,
		.chip_readb	= internal_chip_readb,
		.chip_readw	= internal_chip_readw,
		.chip_readl	= internal_chip_readl,
		.chip_writeb	= internal_chip_writeb,
		.chip_writew	= internal_chip_writew,
		.chip_writel	= internal_chip_writel,
	},

51 52 53 54 55 56 57 58 59 60 61
	{
		.init		= dummy_init,
		.shutdown	= dummy_shutdown,
		.chip_readb	= dummy_chip_readb,
		.chip_readw	= dummy_chip_readw,
		.chip_readl	= dummy_chip_readl,
		.chip_writeb	= dummy_chip_writeb,
		.chip_writew	= dummy_chip_writew,
		.chip_writel	= dummy_chip_writel,
	},

62 63
	{},
};
64

65
void map_flash_registers(struct flashchip *flash)
66 67
{
	size_t size = flash->total_size * 1024;
68
	flash->virtual_registers = physmap("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
69 70
}

71 72 73 74 75 76 77 78 79 80 81 82
int read_memmapped(struct flashchip *flash, uint8_t *buf)
{
	int i;

	/* We could do a memcpy as optimization if the flash is onboard */
	//memcpy(buf, (const char *)flash->virtual_memory, flash->total_size * 1024);
	for (i = 0; i < flash->total_size * 1024; i++)
		buf[i] = chip_readb(flash->virtual_memory + i);
		
	return 0;
}

83
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
84
{
85
	volatile uint8_t *bios;
86
	struct flashchip *flash;
87
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
88

89
	for (flash = first_flash; flash && flash->name; flash++) {
90
		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
91
			continue;
92 93
		printf_debug("Probing for %s %s, %d KB: ",
			     flash->vendor, flash->name, flash->total_size);
Peter Stuge's avatar
Peter Stuge committed
94
		if (!flash->probe && !force) {
95 96 97
			printf_debug("failed! flashrom has no probe function for this flash chip.\n");
			continue;
		}
Stefan Reinauer's avatar
Stefan Reinauer committed
98

99
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
100 101

		/* If getpagesize() > size -> 
Stefan Reinauer's avatar
Stefan Reinauer committed
102
		 * "Can't mmap memory using /dev/mem: Invalid argument"
Stefan Reinauer's avatar
Stefan Reinauer committed
103
		 * This should never happen as we don't support any flash chips
Stefan Reinauer's avatar
Stefan Reinauer committed
104
		 * smaller than 4k or 8k (yet).
Stefan Reinauer's avatar
Stefan Reinauer committed
105 106
		 */

107
		if (getpagesize() > size) {
108 109 110 111 112
			/*
			 * if a flash size of 0 is mapped, we map a single page
			 * so we can probe in that area whether we know the
			 * vendor at least.
			 */
113 114
			size = getpagesize();
		}
115

116
		base = flashbase && flashchips == first_flash ? flashbase : (0xffffffff - size + 1);
117
		flash->virtual_memory = bios = physmap("flash chip", base, size);
118

119 120 121
		if (force)
			break;

122 123 124
		if (flash->probe(flash) != 1)
			goto notfound;

125 126
		if (first_flash == flashchips
		    || flash->model_id != GENERIC_DEVICE_ID)
127
			break;
Stefan Reinauer's avatar
Stefan Reinauer committed
128

129
notfound:
130
		physunmap((void *)bios, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
131
	}
Uwe Hermann's avatar
Uwe Hermann committed
132

133 134 135 136
	if (!flash || !flash->name)
		return NULL;

	printf("Found chip \"%s %s\" (%d KB) at physical address 0x%lx.\n",
Peter Stuge's avatar
Peter Stuge committed
137 138
	       flash->vendor, flash->name, flash->total_size, base);
	flashbase = base;
139
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
140 141
}

Stefan Reinauer's avatar
Stefan Reinauer committed
142
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
143
{
Stefan Reinauer's avatar
Stefan Reinauer committed
144
	int idx;
145
	int total_size = flash->total_size * 1024;
146
	uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
147 148 149 150 151
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
152
		flash->read(flash, buf2);
153

154
	printf("Verifying flash... ");
155 156 157 158

	if (verbose)
		printf("address: 0x00000000\b\b\b\b\b\b\b\b\b\b");

Stefan Reinauer's avatar
Stefan Reinauer committed
159
	for (idx = 0; idx < total_size; idx++) {
160
		if (verbose && ((idx & 0xfff) == 0xfff))
Stefan Reinauer's avatar
Stefan Reinauer committed
161 162
			printf("0x%08x", idx);

163
		if (*(buf2 + idx) != *(buf + idx)) {
164 165 166 167 168
			if (verbose)
				printf("0x%08x FAILED!", idx);
			else
				printf("FAILED at 0x%08x!", idx);
			printf("  Expected=0x%02x, Read=0x%02x\n",
169
			       *(buf + idx), *(buf2 + idx));
Stefan Reinauer's avatar
Stefan Reinauer committed
170
			return 1;
171
		}
172 173

		if (verbose && ((idx & 0xfff) == 0xfff))
174
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
175
	}
176
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
177
		printf("\b\b\b\b\b\b\b\b\b\b ");
178

179
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
180

Stefan Reinauer's avatar
Stefan Reinauer committed
181
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
182 183
}

184 185 186 187 188 189 190 191 192 193 194
int read_flash(struct flashchip *flash, char *filename, unsigned int exclude_start_position, unsigned int exclude_end_position)
{
	unsigned long numbytes;
	FILE *image;
	unsigned long size = flash->total_size * 1024;
	unsigned char *buf = calloc(size, sizeof(char));
	if ((image = fopen(filename, "w")) == NULL) {
		perror(filename);
		exit(1);
	}
	printf("Reading flash... ");
195 196 197 198 199
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
		flash->read(flash, buf);

	if (exclude_end_position - exclude_start_position > 0)
		memset(buf + exclude_start_position, 0,
		       exclude_end_position - exclude_start_position);

	numbytes = fwrite(buf, 1, size, image);
	fclose(image);
	printf("%s.\n", numbytes == size ? "done" : "FAILED");
	if (numbytes != size)
		return 1;
	return 0;
}

int erase_flash(struct flashchip *flash)
{
	uint32_t erasedbytes;
	unsigned long size = flash->total_size * 1024;
	unsigned char *buf = calloc(size, sizeof(char));
	printf("Erasing flash chip... ");
	if (NULL == flash->erase) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
		return 1;
	}
225 226
	flash->erase(flash);

227 228 229 230 231
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
232
		flash->read(flash, buf);
233

234 235 236 237 238 239 240 241 242 243 244
	for (erasedbytes = 0; erasedbytes < size; erasedbytes++)
		if (0xff != buf[erasedbytes]) {
			printf("FAILED!\n");
			fprintf(stderr, "ERROR at 0x%08x: Expected=0xff, Read=0x%02x\n",
				erasedbytes, buf[erasedbytes]);
			return 1;
		}
	printf("SUCCESS.\n");
	return 0;
}

Uwe Hermann's avatar
Uwe Hermann committed
245
#ifndef MAX
246
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Uwe Hermann's avatar
Uwe Hermann committed
247
#endif
248 249
#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)

250 251
void print_supported_chips(void)
{
252 253
	int okcol = 0, pos = 0;
	struct flashchip *f;
254

255 256 257 258 259 260
	for (f = flashchips; f->name != NULL; f++) {
		if (GENERIC_DEVICE_ID == f->model_id)
			continue;
		okcol = MAX(okcol, strlen(f->vendor) + 1 + strlen(f->name));
	}
	okcol = (okcol + 7) & ~7;
261

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
	POS_PRINT("Supported flash chips:");
	while (pos < okcol) {
		printf("\t");
		pos += 8 - (pos % 8);
	}
	printf("Tested OK operations:\tKnown BAD operations:\n\n");

	for (f = flashchips; f->name != NULL; f++) {
		printf("%s %s", f->vendor, f->name);
		pos = strlen(f->vendor) + 1 + strlen(f->name);
		while (pos < okcol) {
			printf("\t");
			pos += 8 - (pos % 8);
		}
		if ((f->tested & TEST_OK_MASK)) {
			if ((f->tested & TEST_OK_PROBE))
				POS_PRINT("PROBE ");
			if ((f->tested & TEST_OK_READ))
				POS_PRINT("READ ");
			if ((f->tested & TEST_OK_ERASE))
				POS_PRINT("ERASE ");
			if ((f->tested & TEST_OK_WRITE))
				POS_PRINT("WRITE");
		}
		while (pos < okcol + 24) {
			printf("\t");
			pos += 8 - (pos % 8);
		}
		if ((f->tested & TEST_BAD_MASK)) {
			if ((f->tested & TEST_BAD_PROBE))
				printf("PROBE ");
			if ((f->tested & TEST_BAD_READ))
				printf("READ ");
			if ((f->tested & TEST_BAD_ERASE))
				printf("ERASE ");
			if ((f->tested & TEST_BAD_WRITE))
				printf("WRITE");
		}
		printf("\n");
	}
302 303
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
304 305
void usage(const char *name)
{
306 307
	printf("usage: %s [-rwvEVfLhR] [-c chipname] [-s exclude_start]\n",
	       name);
308
	printf("       [-e exclude_end] [-m [vendor:]part] [-l file.layout] [-i imagename] [file]\n");
309 310 311 312
	printf("Please  note that the command line interface for flashrom will "
		"change before flashrom 1.0. Do not use flashrom in scripts or "
		"other automated tools without checking that your flashrom "
		"version won't interpret them in a totally different way.\n\n");
313
	printf
314 315 316 317 318 319 320 321 322 323 324 325
	    ("   -r | --read:                      read flash and save into file\n"
	     "   -w | --write:                     write file into flash\n"
	     "   -v | --verify:                    verify flash against file\n"
	     "   -E | --erase:                     erase flash device\n"
	     "   -V | --verbose:                   more verbose output\n"
	     "   -c | --chip <chipname>:           probe only for specified flash chip\n"
	     "   -s | --estart <addr>:             exclude start position\n"
	     "   -e | --eend <addr>:               exclude end postion\n"
	     "   -m | --mainboard <[vendor:]part>: override mainboard settings\n"
	     "   -f | --force:                     force write without checking image\n"
	     "   -l | --layout <file.layout>:      read rom layout from file\n"
	     "   -i | --image <name>:              only flash image name from flash layout\n"
326
	     "   -L | --list-supported:            print supported devices\n"
327
	     "   -p | --programmer <name>:         specify the programmer device\n"
328
	     "   -h | --help:                      print this help text\n"
329
	     "   -R | --version:                   print the version (release)\n"
330
	     "\n" " If no file is specified, then all that happens"
331
	     " is that flash info is dumped.\n\n");
332
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
333 334
}

335 336
void print_version(void)
{
Carl-Daniel Hailfinger's avatar
Carl-Daniel Hailfinger committed
337
	printf("flashrom v%s\n", FLASHROM_VERSION);
338 339
}

340
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
341
{
342
	uint8_t *buf;
343
	unsigned long size, numbytes;
344
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
345 346
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
347
	int opt;
348
	int option_index = 0;
Peter Stuge's avatar
Peter Stuge committed
349
	int force = 0;
350
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Claus Gindhart's avatar
Claus Gindhart committed
351
	int ret = 0, i;
352

353 354 355 356 357 358 359 360 361 362 363 364 365
	static struct option long_options[] = {
		{"read", 0, 0, 'r'},
		{"write", 0, 0, 'w'},
		{"erase", 0, 0, 'E'},
		{"verify", 0, 0, 'v'},
		{"chip", 1, 0, 'c'},
		{"estart", 1, 0, 's'},
		{"eend", 1, 0, 'e'},
		{"mainboard", 1, 0, 'm'},
		{"verbose", 0, 0, 'V'},
		{"force", 0, 0, 'f'},
		{"layout", 1, 0, 'l'},
		{"image", 1, 0, 'i'},
366
		{"list-supported", 0, 0, 'L'},
367
		{"programmer", 1, 0, 'p'},
368
		{"help", 0, 0, 'h'},
369
		{"version", 0, 0, 'R'},
370
		{0, 0, 0, 0}
371
	};
372

373
	char *filename = NULL;
374

375 376
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
377

378 379
	print_version();

380 381 382
	if (argc > 1) {
		/* Yes, print them. */
		int i;
383
		printf_debug("The arguments are:\n");
384
		for (i = 1; i < argc; ++i)
385
			printf_debug("%s\n", argv[i]);
386 387
	}

388
	setbuf(stdout, NULL);
389
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:p:Lh",
390
				  long_options, &option_index)) != EOF) {
391 392 393 394 395 396 397 398 399 400 401 402 403
		switch (opt) {
		case 'r':
			read_it = 1;
			break;
		case 'w':
			write_it = 1;
			break;
		case 'v':
			verify_it = 1;
			break;
		case 'c':
			chip_to_probe = strdup(optarg);
			break;
Ollie Lho's avatar
Ollie Lho committed
404 405 406
		case 'V':
			verbose = 1;
			break;
407 408 409
		case 'E':
			erase_it = 1;
			break;
410 411
		case 's':
			tempstr = strdup(optarg);
412
			sscanf(tempstr, "%x", &exclude_start_position);
413 414
			break;
		case 'e':
415
			tempstr = strdup(optarg);
416
			sscanf(tempstr, "%x", &exclude_end_position);
417
			break;
418 419 420
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
421
			tempstr2 = strtok(NULL, ":");
422
			if (tempstr2) {
423 424
				lb_vendor = tempstr;
				lb_part = tempstr2;
425
			} else {
426 427
				lb_vendor = NULL;
				lb_part = tempstr;
428 429 430
			}
			break;
		case 'f':
431
			force = 1;
432 433
			break;
		case 'l':
434
			tempstr = strdup(optarg);
435 436
			if (read_romlayout(tempstr))
				exit(1);
437 438
			break;
		case 'i':
439
			tempstr = strdup(optarg);
440 441
			find_romentry(tempstr);
			break;
442 443 444 445 446 447
		case 'L':
			print_supported_chips();
			print_supported_chipsets();
			print_supported_boards();
			exit(0);
			break;
448 449 450
		case 'p':
			if (strncmp(optarg, "internal", 8) == 0) {
				programmer = PROGRAMMER_INTERNAL;
451 452
			} else if (strncmp(optarg, "dummy", 5) == 0) {
				programmer = PROGRAMMER_DUMMY;
453 454 455 456 457
			} else {
				printf("Error: Unknown programmer.\n");
				exit(1);
			}
			break;
458
		case 'R':
459
			/* print_version() is always called during startup. */
460 461
			exit(0);
			break;
462
		case 'h':
463 464 465 466 467
		default:
			usage(argv[0]);
			break;
		}
	}
468

469
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
470
		printf("Error: -r and -w are mutually exclusive.\n");
471 472
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
473

474 475
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
476

477
	ret = programmer_init();
478

479
	myusec_calibrate_delay();
480

Claus Gindhart's avatar
Claus Gindhart committed
481
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
482 483
		flashes[i] =
		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
Claus Gindhart's avatar
Claus Gindhart committed
484 485 486 487 488 489 490 491 492 493 494 495
		if (!flashes[i])
			for (i++; i < ARRAY_SIZE(flashes); i++)
				flashes[i] = NULL;
	}

	if (flashes[1]) {
		printf("Multiple flash chips were detected:");
		for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++)
			printf(" %s", flashes[i]->name);
		printf("\nPlease specify which chip to use with the -c <chipname> option.\n");
		exit(1);
	} else if (!flashes[0]) {
496
		printf("No EEPROM/flash device found.\n");
Peter Stuge's avatar
Peter Stuge committed
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
		if (!force || !chip_to_probe) {
			printf("If you know which flash chip you have, and if this version of flashrom\n");
			printf("supports a similar flash chip, you can try to force read your chip. Run:\n");
			printf("flashrom -f -r -c similar_supported_flash_chip filename\n");
			printf("\n");
			printf("Note: flashrom can never write when the flash chip isn't found automatically.\n");
		}
		if (force && read_it && chip_to_probe) {
			printf("Force read (-f -r -c) requested, forcing chip probe success:\n");
			flashes[0] = probe_flash(flashchips, 1);
			if (!flashes[0]) {
				printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe);
				printf("Run flashrom -L to view the hardware supported in this flashrom version.\n");
				exit(1);
			}
512 513 514 515
			if (!filename) {
				printf("Error: No filename specified.\n");
				exit(1);
			}
Peter Stuge's avatar
Peter Stuge committed
516 517 518 519 520 521 522
			size = flashes[0]->total_size * 1024;
			buf = (uint8_t *) calloc(size, sizeof(char));

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
523
			printf("Force reading flash... ");
524 525 526 527 528
			if (!flashes[0]->read) {
				printf("FAILED!\n");
				fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
				return 1;
			} else
Peter Stuge's avatar
Peter Stuge committed
529 530 531 532
				flashes[0]->read(flashes[0], buf);

			if (exclude_end_position - exclude_start_position > 0)
				memset(buf + exclude_start_position, 0,
533 534
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
535

536
			numbytes = fwrite(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
537
			fclose(image);
538
			printf("%s.\n", numbytes == size ? "done" : "FAILED");
Peter Stuge's avatar
Peter Stuge committed
539
			free(buf);
540
			return numbytes != size;
Peter Stuge's avatar
Peter Stuge committed
541
		}
542
		// FIXME: flash writes stay enabled!
543 544
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
545

Claus Gindhart's avatar
Claus Gindhart committed
546 547
	flash = flashes[0];

548 549 550 551 552 553 554 555 556 557 558 559 560
	if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) {
		printf("===\n");
		if (flash->tested & TEST_BAD_MASK) {
			printf("This flash part has status NOT WORKING for operations:");
			if (flash->tested & TEST_BAD_PROBE)
				printf(" PROBE");
			if (flash->tested & TEST_BAD_READ)
				printf(" READ");
			if (flash->tested & TEST_BAD_ERASE)
				printf(" ERASE");
			if (flash->tested & TEST_BAD_WRITE)
				printf(" WRITE");
			printf("\n");
561 562 563 564 565
		}
		if ((!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE)) ||
		    (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ)) ||
		    (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE)) ||
		    (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))) {
566
			printf("This flash part has status UNTESTED for operations:");
567
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
568
				printf(" PROBE");
569
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
570
				printf(" READ");
571
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
572
				printf(" ERASE");
573
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
574 575 576 577 578 579 580 581
				printf(" WRITE");
			printf("\n");
		}
		printf("Please email a report to flashrom@coreboot.org if any of the above operations\n");
		printf("work correctly for you with this flash part. Please include the full output\n");
		printf("from the program, including chipset found. Thank you for your help!\n");
		printf("===\n");
	}
582

583 584 585 586 587 588
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

589
	if (!filename && !erase_it) {
590 591 592
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
593 594
	}

595 596
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
597

598
	if (erase_it) {
599
		if (erase_flash(flash))
600
			return 1;
601
	} else if (read_it) {
602
		if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
603
			return 1;
604
	} else {
605 606
		struct stat image_stat;

607
		if ((image = fopen(filename, "r")) == NULL) {
608 609 610
			perror(filename);
			exit(1);
		}
611 612 613 614
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
615
		if (image_stat.st_size != flash->total_size * 1024) {
Uwe Hermann's avatar
Uwe Hermann committed
616
			fprintf(stderr, "Error: Image size doesn't match\n");
617 618 619
			exit(1);
		}

620
		numbytes = fread(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
621
		show_id(buf, size, force);
622
		fclose(image);
623 624 625 626
		if (numbytes != size) {
			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
			return 1;
		}
627
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
628

629 630 631 632 633 634
	/* exclude range stuff. Nice idea, but at the moment it is only
	 * supported in hardware by the pm49fl004 chips. 
	 * Instead of implementing this for all chips I suggest advancing
	 * it to the rom layout feature below and drop exclude range
	 * completely once all flash chips can do rom layouts. stepan
	 */
635

636
	// ////////////////////////////////////////////////////////////
637 638 639
	/* FIXME: This memcpy will not work for SPI nor external flashers.
	 * Convert to chip_readb.
	 */
640
	if (exclude_end_position - exclude_start_position > 0)
641
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
642 643
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
644
		       exclude_end_position - exclude_start_position);
645

646 647
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
648 649
		exclude_start_page++;
	}
650
	exclude_end_page = exclude_end_position / flash->page_size;
651 652 653 654
	// ////////////////////////////////////////////////////////////

	// This should be moved into each flash part's code to do it 
	// cleanly. This does the job.
655
	handle_romentries(buf, (uint8_t *) flash->virtual_memory);
656

657
	// ////////////////////////////////////////////////////////////
658

659 660 661 662 663
	if (write_it) {
		if (!flash->write) {
			fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n");
			return 1;
		}
Stefan Reinauer's avatar
Stefan Reinauer committed
664
		ret |= flash->write(flash, buf);
665
	}
666

667
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
668
		ret |= verify_flash(flash, buf);
669

670 671
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
672
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
673
}