flashrom.c 18.3 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 51 52
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,
	},

	{},
};
53

54
void map_flash_registers(struct flashchip *flash)
55 56
{
	size_t size = flash->total_size * 1024;
57
	flash->virtual_registers = physmap("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
58 59
}

60 61 62 63 64 65 66 67 68 69 70 71
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;
}

72
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
73
{
74
	volatile uint8_t *bios;
75
	struct flashchip *flash;
76
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
77

78
	for (flash = first_flash; flash && flash->name; flash++) {
79
		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
80
			continue;
81 82
		printf_debug("Probing for %s %s, %d KB: ",
			     flash->vendor, flash->name, flash->total_size);
Peter Stuge's avatar
Peter Stuge committed
83
		if (!flash->probe && !force) {
84 85 86
			printf_debug("failed! flashrom has no probe function for this flash chip.\n");
			continue;
		}
Stefan Reinauer's avatar
Stefan Reinauer committed
87

88
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
89 90

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

96
		if (getpagesize() > size) {
97 98 99 100 101
			/*
			 * 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.
			 */
102 103
			size = getpagesize();
		}
104

105
		base = flashbase && flashchips == first_flash ? flashbase : (0xffffffff - size + 1);
106
		flash->virtual_memory = bios = physmap("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
		physunmap((void *)bios, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
120
	}
Uwe Hermann's avatar
Uwe Hermann committed
121

122 123 124 125
	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
126 127
	       flash->vendor, flash->name, flash->total_size, base);
	flashbase = 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 316
	     "   -L | --list-supported:            print supported devices\n"
	     "   -h | --help:                      print this help text\n"
317
	     "   -R | --version:                   print the version (release)\n"
318
	     "\n" " If no file is specified, then all that happens"
319
	     " is that flash info is dumped.\n\n");
320
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
321 322
}

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

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

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

361
	char *filename = NULL;
362

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

366 367
	print_version();

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

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

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

460 461
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
462

463
	ret = programmer_init();
464

465
	myusec_calibrate_delay();
466

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

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

			if (exclude_end_position - exclude_start_position > 0)
				memset(buf + exclude_start_position, 0,
519 520
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
521

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

Claus Gindhart's avatar
Claus Gindhart committed
532 533
	flash = flashes[0];

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

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

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

581 582
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
583

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

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

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

615 616 617 618 619 620
	/* 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
	 */
621

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

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

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

643
	// ////////////////////////////////////////////////////////////
644

645 646 647 648 649
	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
650
		ret |= flash->write(flash, buf);
651
	}
652

653
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
654
		ret |= verify_flash(flash, buf);
655

656 657
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
658
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
659
}