flashrom.c 18.6 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
void map_flash_registers(struct flashchip *flash)
70 71
{
	size_t size = flash->total_size * 1024;
72
	/* Flash registers live 4 MByte below the flash. */
73
	flash->virtual_registers = programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
74 75
}

76 77 78 79 80 81 82 83 84 85 86 87
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;
}

88
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
89
{
90
	struct flashchip *flash;
91
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
92

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

103
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
104

105
		base = flashbase ? flashbase : (0xffffffff - size + 1);
106
		flash->virtual_memory = programmer_map_flash_region("flash chip", base, size);
107

108 109 110
		if (force)
			break;

111 112 113
		if (flash->probe(flash) != 1)
			goto notfound;

114 115
		if (first_flash == flashchips
		    || flash->model_id != GENERIC_DEVICE_ID)
116
			break;
Stefan Reinauer's avatar
Stefan Reinauer committed
117

118
notfound:
119 120
		/* 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
121
	}
Uwe Hermann's avatar
Uwe Hermann committed
122

123 124 125 126
	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
127
	       flash->vendor, flash->name, flash->total_size, base);
128
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
129 130
}

Stefan Reinauer's avatar
Stefan Reinauer committed
131
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
132
{
Stefan Reinauer's avatar
Stefan Reinauer committed
133
	int idx;
134
	int total_size = flash->total_size * 1024;
135
	uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
136 137 138 139 140
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
141
		flash->read(flash, buf2);
142

143
	printf("Verifying flash... ");
144 145 146 147

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

Stefan Reinauer's avatar
Stefan Reinauer committed
148
	for (idx = 0; idx < total_size; idx++) {
149
		if (verbose && ((idx & 0xfff) == 0xfff))
Stefan Reinauer's avatar
Stefan Reinauer committed
150 151
			printf("0x%08x", idx);

152
		if (*(buf2 + idx) != *(buf + idx)) {
153 154 155 156 157
			if (verbose)
				printf("0x%08x FAILED!", idx);
			else
				printf("FAILED at 0x%08x!", idx);
			printf("  Expected=0x%02x, Read=0x%02x\n",
158
			       *(buf + idx), *(buf2 + idx));
Stefan Reinauer's avatar
Stefan Reinauer committed
159
			return 1;
160
		}
161 162

		if (verbose && ((idx & 0xfff) == 0xfff))
163
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
164
	}
165
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
166
		printf("\b\b\b\b\b\b\b\b\b\b ");
167

168
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
169

Stefan Reinauer's avatar
Stefan Reinauer committed
170
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
171 172
}

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

216 217 218 219 220
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
221
		flash->read(flash, buf);
222

223 224 225 226 227 228 229 230 231 232 233
	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
234
#ifndef MAX
235
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Uwe Hermann's avatar
Uwe Hermann committed
236
#endif
237 238
#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)

239 240
void print_supported_chips(void)
{
241 242
	int okcol = 0, pos = 0;
	struct flashchip *f;
243

244 245 246 247 248 249
	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;
250

251 252 253 254 255 256 257 258 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
	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");
	}
291 292
}

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

324 325
void print_version(void)
{
Carl-Daniel Hailfinger's avatar
Carl-Daniel Hailfinger committed
326
	printf("flashrom v%s\n", FLASHROM_VERSION);
327 328
}

329
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
330
{
331
	uint8_t *buf;
332
	unsigned long size, numbytes;
333
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
334 335
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
336
	int opt;
337
	int option_index = 0;
Peter Stuge's avatar
Peter Stuge committed
338
	int force = 0;
339
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Claus Gindhart's avatar
Claus Gindhart committed
340
	int ret = 0, i;
341

342 343 344 345 346 347 348 349 350 351 352 353 354
	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'},
355
		{"list-supported", 0, 0, 'L'},
356
		{"programmer", 1, 0, 'p'},
357
		{"help", 0, 0, 'h'},
358
		{"version", 0, 0, 'R'},
359
		{0, 0, 0, 0}
360
	};
361

362
	char *filename = NULL;
363

364 365
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
366

367 368
	print_version();

369 370 371
	if (argc > 1) {
		/* Yes, print them. */
		int i;
372
		printf_debug("The arguments are:\n");
373
		for (i = 1; i < argc; ++i)
374
			printf_debug("%s\n", argv[i]);
375 376
	}

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

458
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
459
		printf("Error: -r and -w are mutually exclusive.\n");
460 461
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
462

463 464
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
465

466
	ret = programmer_init();
467

468
	myusec_calibrate_delay();
469

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

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
512
			printf("Force reading flash... ");
513 514 515 516 517
			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
518 519 520 521
				flashes[0]->read(flashes[0], buf);

			if (exclude_end_position - exclude_start_position > 0)
				memset(buf + exclude_start_position, 0,
522 523
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
524

525
			numbytes = fwrite(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
526
			fclose(image);
527
			printf("%s.\n", numbytes == size ? "done" : "FAILED");
Peter Stuge's avatar
Peter Stuge committed
528
			free(buf);
529
			return numbytes != size;
Peter Stuge's avatar
Peter Stuge committed
530
		}
531
		// FIXME: flash writes stay enabled!
532 533
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
534

Claus Gindhart's avatar
Claus Gindhart committed
535 536
	flash = flashes[0];

537 538 539 540 541 542 543 544 545 546 547 548 549
	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");
550 551 552 553 554
		}
		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))) {
555
			printf("This flash part has status UNTESTED for operations:");
556
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
557
				printf(" PROBE");
558
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
559
				printf(" READ");
560
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
561
				printf(" ERASE");
562
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
563 564 565 566 567 568 569 570
				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");
	}
571

572 573 574 575 576 577
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

578
	if (!filename && !erase_it) {
579 580 581
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
582 583
	}

584 585
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
586

587
	if (erase_it) {
588
		if (erase_flash(flash))
589
			return 1;
590
	} else if (read_it) {
591
		if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
592
			return 1;
593
	} else {
594 595
		struct stat image_stat;

596
		if ((image = fopen(filename, "r")) == NULL) {
597 598 599
			perror(filename);
			exit(1);
		}
600 601 602 603
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
604
		if (image_stat.st_size != flash->total_size * 1024) {
Uwe Hermann's avatar
Uwe Hermann committed
605
			fprintf(stderr, "Error: Image size doesn't match\n");
606 607 608
			exit(1);
		}

609
		numbytes = fread(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
610
		show_id(buf, size, force);
611
		fclose(image);
612 613 614 615
		if (numbytes != size) {
			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
			return 1;
		}
616
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
617

618 619 620 621 622 623
	/* 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
	 */
624

625
	// ////////////////////////////////////////////////////////////
626 627 628
	/* FIXME: This memcpy will not work for SPI nor external flashers.
	 * Convert to chip_readb.
	 */
629
	if (exclude_end_position - exclude_start_position > 0)
630
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
631 632
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
633
		       exclude_end_position - exclude_start_position);
634

635 636
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
637 638
		exclude_start_page++;
	}
639
	exclude_end_page = exclude_end_position / flash->page_size;
640 641 642 643
	// ////////////////////////////////////////////////////////////

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

646
	// ////////////////////////////////////////////////////////////
647

648 649 650 651 652
	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
653
		ret |= flash->write(flash, buf);
654
	}
655

656
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
657
		ret |= verify_flash(flash, buf);
658

659 660
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
661
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
662
}