flashrom.c 18.7 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
	struct flashchip *flash;
86
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
87

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

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

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

106
		if (getpagesize() > size) {
107 108 109 110 111
			/*
			 * 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.
			 */
112 113
			size = getpagesize();
		}
114

115
		base = flashbase ? flashbase : (0xffffffff - size + 1);
116
		flash->virtual_memory = physmap("flash chip", base, size);
117

118 119 120
		if (force)
			break;

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

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

128
notfound:
129
		physunmap((void *)flash->virtual_memory, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
130
	}
Uwe Hermann's avatar
Uwe Hermann committed
131

132 133 134 135
	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
136
	       flash->vendor, flash->name, flash->total_size, base);
137
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
138 139
}

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

152
	printf("Verifying flash... ");
153 154 155 156

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

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

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

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

177
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
178

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

182 183 184 185 186 187 188 189 190 191 192
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... ");
193 194 195 196 197
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
		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;
	}
223 224
	flash->erase(flash);

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

232 233 234 235 236 237 238 239 240 241 242
	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
243
#ifndef MAX
244
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Uwe Hermann's avatar
Uwe Hermann committed
245
#endif
246 247
#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)

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

253 254 255 256 257 258
	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;
259

260 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
	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");
	}
300 301
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
302 303
void usage(const char *name)
{
304 305
	printf("usage: %s [-rwvEVfLhR] [-c chipname] [-s exclude_start]\n",
	       name);
306
	printf("       [-e exclude_end] [-m [vendor:]part] [-l file.layout] [-i imagename] [file]\n");
307 308 309 310
	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");
311
	printf
312 313 314 315 316 317 318 319 320 321 322 323
	    ("   -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"
324
	     "   -L | --list-supported:            print supported devices\n"
325
	     "   -p | --programmer <name>:         specify the programmer device\n"
326
	     "   -h | --help:                      print this help text\n"
327
	     "   -R | --version:                   print the version (release)\n"
328
	     "\n" " If no file is specified, then all that happens"
329
	     " is that flash info is dumped.\n\n");
330
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
331 332
}

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

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

351 352 353 354 355 356 357 358 359 360 361 362 363
	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'},
364
		{"list-supported", 0, 0, 'L'},
365
		{"programmer", 1, 0, 'p'},
366
		{"help", 0, 0, 'h'},
367
		{"version", 0, 0, 'R'},
368
		{0, 0, 0, 0}
369
	};
370

371
	char *filename = NULL;
372

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

376 377
	print_version();

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

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

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

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

475
	ret = programmer_init();
476

477
	myusec_calibrate_delay();
478

Claus Gindhart's avatar
Claus Gindhart committed
479
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
480 481
		flashes[i] =
		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
Claus Gindhart's avatar
Claus Gindhart committed
482 483 484 485 486 487 488 489 490 491 492 493
		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]) {
494
		printf("No EEPROM/flash device found.\n");
Peter Stuge's avatar
Peter Stuge committed
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
		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);
			}
510 511 512 513
			if (!filename) {
				printf("Error: No filename specified.\n");
				exit(1);
			}
Peter Stuge's avatar
Peter Stuge committed
514 515 516 517 518 519 520
			size = flashes[0]->total_size * 1024;
			buf = (uint8_t *) calloc(size, sizeof(char));

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
521
			printf("Force reading flash... ");
522 523 524 525 526
			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
527 528 529 530
				flashes[0]->read(flashes[0], buf);

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

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

Claus Gindhart's avatar
Claus Gindhart committed
544 545
	flash = flashes[0];

546 547 548 549 550 551 552 553 554 555 556 557 558
	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");
559 560 561 562 563
		}
		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))) {
564
			printf("This flash part has status UNTESTED for operations:");
565
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
566
				printf(" PROBE");
567
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
568
				printf(" READ");
569
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
570
				printf(" ERASE");
571
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
572 573 574 575 576 577 578 579
				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");
	}
580

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

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

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

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

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

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

627 628 629 630 631 632
	/* 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
	 */
633

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

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

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

655
	// ////////////////////////////////////////////////////////////
656

657 658 659 660 661
	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
662
		ret |= flash->write(flash, buf);
663
	}
664

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

668 669
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
670
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
671
}