flashrom.c 19.1 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
int programmer = PROGRAMMER_INTERNAL;

const struct programmer_entry programmer_table[] = {
	{
41 42
		.init			= internal_init,
		.shutdown		= internal_shutdown,
43 44
		.map_flash_region	= physmap,
		.unmap_flash_region	= physunmap,
45 46 47 48 49 50
		.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
		.init			= dummy_init,
		.shutdown		= dummy_shutdown,
56 57
		.map_flash_region	= dummy_map,
		.unmap_flash_region	= dummy_unmap,
58 59 60 61 62 63
		.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,
64 65
	},

66 67 68 69 70 71 72 73 74 75 76 77 78
	{
		.init			= nic3com_init,
		.shutdown		= nic3com_shutdown,
		.map_flash_region	= nic3com_map,
		.unmap_flash_region	= nic3com_unmap,
		.chip_readb		= nic3com_chip_readb,
		.chip_readw		= nic3com_chip_readw,
		.chip_readl		= nic3com_chip_readl,
		.chip_writeb		= nic3com_chip_writeb,
		.chip_writew		= nic3com_chip_writew,
		.chip_writel		= nic3com_chip_writel,
	},

79 80
	{},
};
81

82
void map_flash_registers(struct flashchip *flash)
83 84
{
	size_t size = flash->total_size * 1024;
85
	/* Flash registers live 4 MByte below the flash. */
86
	flash->virtual_registers = programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
87 88
}

89 90 91 92 93 94 95 96 97 98 99 100
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;
}

101
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
102
{
103
	struct flashchip *flash;
104
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
105

106
	for (flash = first_flash; flash && flash->name; flash++) {
107
		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
108
			continue;
109 110
		printf_debug("Probing for %s %s, %d KB: ",
			     flash->vendor, flash->name, flash->total_size);
Peter Stuge's avatar
Peter Stuge committed
111
		if (!flash->probe && !force) {
112 113 114
			printf_debug("failed! flashrom has no probe function for this flash chip.\n");
			continue;
		}
Stefan Reinauer's avatar
Stefan Reinauer committed
115

116
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
117

118
		base = flashbase ? flashbase : (0xffffffff - size + 1);
119
		flash->virtual_memory = programmer_map_flash_region("flash chip", base, size);
120

121 122 123
		if (force)
			break;

124 125 126
		if (flash->probe(flash) != 1)
			goto notfound;

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

131
notfound:
132 133
		/* The intermediate cast to unsigned long works around a gcc warning bug. */
		programmer_unmap_flash_region((void *)(unsigned long)flash->virtual_memory, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
134
	}
Uwe Hermann's avatar
Uwe Hermann committed
135

136 137 138 139
	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
140
	       flash->vendor, flash->name, flash->total_size, base);
141
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
142 143
}

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

156
	printf("Verifying flash... ");
157 158 159 160

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

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

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

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

181
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
182

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

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

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

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

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

257 258 259 260 261 262
	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;
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 302 303
	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");
	}
304 305
}

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

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

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

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

375
	char *filename = NULL;
376

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

380 381
	print_version();

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

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

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

478 479
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
480

481
	ret = programmer_init();
482

483
	myusec_calibrate_delay();
484

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

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
527
			printf("Force reading flash... ");
528 529 530 531 532
			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
533 534 535 536
				flashes[0]->read(flashes[0], buf);

			if (exclude_end_position - exclude_start_position > 0)
				memset(buf + exclude_start_position, 0,
537 538
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
539

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

Claus Gindhart's avatar
Claus Gindhart committed
550 551
	flash = flashes[0];

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

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

593
	if (!filename && !erase_it) {
594 595 596
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
597 598
	}

599 600
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
601

602
	if (erase_it) {
603
		if (erase_flash(flash))
604
			return 1;
605
	} else if (read_it) {
606
		if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
607
			return 1;
608
	} else {
609 610
		struct stat image_stat;

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

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

633 634 635 636 637 638
	/* 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
	 */
639

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

650 651
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
652 653
		exclude_start_page++;
	}
654
	exclude_end_page = exclude_end_position / flash->page_size;
655 656 657 658
	// ////////////////////////////////////////////////////////////

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

661
	// ////////////////////////////////////////////////////////////
662

663 664 665 666 667
	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
668
		ret |= flash->write(flash, buf);
669
	}
670

671
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
672
		ret |= verify_flash(flash, buf);
673

674 675
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
676
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
677
}