flashrom.c 18.4 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 
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
7
 *
8 9 10 11
 * 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
12
 *
13 14 15 16
 * 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
17
 *
18 19 20
 * 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
21 22 23 24
 */

#include <errno.h>
#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>
32 33 34 35 36 37 38 39
#include <pci/pci.h>
/* for iopl */
#if defined (__sun) && (defined(__i386) || defined(__amd64))
#include <strings.h>
#include <sys/sysi86.h>
#include <sys/psw.h>
#include <asm/sunddi.h>
#endif
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
40 41
#include "flash.h"

Ronald G. Minnich's avatar
Ronald G. Minnich committed
42
char *chip_to_probe = NULL;
43
struct pci_access *pacc;	/* For board and chipset_enable */
Stefan Reinauer's avatar
Stefan Reinauer committed
44
int exclude_start_page, exclude_end_page;
Peter Stuge's avatar
Peter Stuge committed
45
int verbose = 0;
Stefan Reinauer's avatar
Stefan Reinauer committed
46

47
struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
48
{
49 50
	struct pci_dev *temp;
	struct pci_filter filter;
51

52 53 54
	pci_filter_init(NULL, &filter);
	filter.vendor = vendor;
	filter.device = device;
55

56 57 58
	for (temp = pacc->devices; temp; temp = temp->next)
		if (pci_filter_match(&filter, temp))
			return temp;
59

60
	return NULL;
61 62
}

63 64
struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
			      uint16_t card_vendor, uint16_t card_device)
65
{
66 67 68 69 70 71 72 73 74
	struct pci_dev *temp;
	struct pci_filter filter;

	pci_filter_init(NULL, &filter);
	filter.vendor = vendor;
	filter.device = device;

	for (temp = pacc->devices; temp; temp = temp->next)
		if (pci_filter_match(&filter, temp)) {
75 76 77 78
			if ((card_vendor ==
			     pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
			    && (card_device ==
				pci_read_word(temp, PCI_SUBSYSTEM_ID)))
79 80
				return temp;
		}
81

82
	return NULL;
83 84
}

85
void map_flash_registers(struct flashchip *flash)
86 87
{
	size_t size = flash->total_size * 1024;
88
	flash->virtual_registers = physmap("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
89 90
}

91
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
92
{
93
	volatile uint8_t *bios;
94
	struct flashchip *flash;
95
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
96

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

107
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
108 109

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

115
		if (getpagesize() > size) {
116 117 118 119 120
			/*
			 * 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.
			 */
121 122
			size = getpagesize();
		}
123

Peter Stuge's avatar
Peter Stuge committed
124
		base = flashbase ? flashbase : (0xffffffff - size + 1);
125
		flash->virtual_memory = bios = physmap("flash chip", base, size);
126

127 128 129
		if (force)
			break;

130 131 132
		if (flash->probe(flash) != 1)
			goto notfound;

133 134
		if (first_flash == flashchips
		    || flash->model_id != GENERIC_DEVICE_ID)
135
			break;
Stefan Reinauer's avatar
Stefan Reinauer committed
136

137
notfound:
138
		physunmap((void *)bios, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
139
	}
Uwe Hermann's avatar
Uwe Hermann committed
140

141 142 143 144
	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
145 146
	       flash->vendor, flash->name, flash->total_size, base);
	flashbase = base;
147
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
148 149
}

Stefan Reinauer's avatar
Stefan Reinauer committed
150
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
151
{
Stefan Reinauer's avatar
Stefan Reinauer committed
152
	int idx;
153
	int total_size = flash->total_size * 1024;
154 155 156 157 158
	uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
	if (flash->read == NULL)
		memcpy(buf2, (const char *)flash->virtual_memory, total_size);
	else
		flash->read(flash, buf2);
159

160
	printf("Verifying flash... ");
161 162 163 164

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

Stefan Reinauer's avatar
Stefan Reinauer committed
165
	for (idx = 0; idx < total_size; idx++) {
166
		if (verbose && ((idx & 0xfff) == 0xfff))
Stefan Reinauer's avatar
Stefan Reinauer committed
167 168
			printf("0x%08x", idx);

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

		if (verbose && ((idx & 0xfff) == 0xfff))
180
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
181
	}
182
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
183
		printf("\b\b\b\b\b\b\b\b\b\b ");
184

185
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
186

Stefan Reinauer's avatar
Stefan Reinauer committed
187
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
188 189
}

190 191 192
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)

193 194
void print_supported_chips(void)
{
195 196
	int okcol = 0, pos = 0;
	struct flashchip *f;
197

198 199 200 201 202 203
	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;
204

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
	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");
	}
245 246
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
247 248
void usage(const char *name)
{
249 250
	printf("usage: %s [-rwvEVfLhR] [-c chipname] [-s exclude_start]\n",
	       name);
251
	printf("       [-e exclude_end] [-m [vendor:]part] [-l file.layout] [-i imagename] [file]\n");
252
	printf
253 254 255 256 257 258 259 260 261 262 263 264
	    ("   -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"
265 266
	     "   -L | --list-supported:            print supported devices\n"
	     "   -h | --help:                      print this help text\n"
267
	     "   -R | --version:                   print the version (release)\n"
268
	     "\n" " If no file is specified, then all that happens"
269
	     " is that flash info is dumped.\n\n");
270
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
271 272
}

273 274 275 276 277
void print_version(void)
{
	printf("flashrom r%s\n", FLASHROM_VERSION);
}

278
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
279
{
280
	uint8_t *buf;
281
	unsigned long size, numbytes;
282
	uint32_t erasedbytes;
283
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
284 285
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
286
	int opt;
287
	int option_index = 0;
Peter Stuge's avatar
Peter Stuge committed
288
	int force = 0;
289
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Claus Gindhart's avatar
Claus Gindhart committed
290
	int ret = 0, i;
291 292 293
#ifdef __FreeBSD__
	int io_fd;
#endif
294

295 296 297 298 299 300 301 302 303 304 305 306 307
	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'},
308
		{"list-supported", 0, 0, 'L'},
309
		{"help", 0, 0, 'h'},
310
		{"version", 0, 0, 'R'},
311
		{0, 0, 0, 0}
312
	};
313

314
	char *filename = NULL;
315

316 317
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
318 319 320 321

	if (argc > 1) {
		/* Yes, print them. */
		int i;
322
		printf_debug("The arguments are:\n");
323
		for (i = 1; i < argc; ++i)
324
			printf_debug("%s\n", argv[i]);
325 326
	}

327
	setbuf(stdout, NULL);
328
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:Lh",
329
				  long_options, &option_index)) != EOF) {
330 331 332 333 334 335 336 337 338 339 340 341 342
		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
343 344 345
		case 'V':
			verbose = 1;
			break;
346 347 348
		case 'E':
			erase_it = 1;
			break;
349 350
		case 's':
			tempstr = strdup(optarg);
351
			sscanf(tempstr, "%x", &exclude_start_position);
352 353
			break;
		case 'e':
354
			tempstr = strdup(optarg);
355
			sscanf(tempstr, "%x", &exclude_end_position);
356
			break;
357 358 359
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
360
			tempstr2 = strtok(NULL, ":");
361
			if (tempstr2) {
362 363
				lb_vendor = tempstr;
				lb_part = tempstr2;
364
			} else {
365 366
				lb_vendor = NULL;
				lb_part = tempstr;
367 368 369
			}
			break;
		case 'f':
370
			force = 1;
371 372
			break;
		case 'l':
373
			tempstr = strdup(optarg);
374 375
			if (read_romlayout(tempstr))
				exit(1);
376 377
			break;
		case 'i':
378
			tempstr = strdup(optarg);
379 380
			find_romentry(tempstr);
			break;
381 382 383 384 385 386
		case 'L':
			print_supported_chips();
			print_supported_chipsets();
			print_supported_boards();
			exit(0);
			break;
387 388 389 390
		case 'R':
			print_version();
			exit(0);
			break;
391
		case 'h':
392 393 394 395 396
		default:
			usage(argv[0]);
			break;
		}
	}
397

398
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
399
		printf("Error: -r and -w are mutually exclusive.\n");
400 401
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
402

403 404
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
405

406
	/* First get full io access */
407
#if defined (__sun) && (defined(__i386) || defined(__amd64))
408
	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
409 410
#elif defined(__FreeBSD__)
	if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
411 412 413
#else
	if (iopl(3) != 0) {
#endif
414
		fprintf(stderr, "ERROR: Could not get IO privileges (%s).\nYou need to be root.\n", strerror(errno));
415 416 417
		exit(1);
	}

418
	/* Initialize PCI access for flash enables */
419 420 421 422 423
	pacc = pci_alloc();	/* Get the pci_access structure */
	/* Set all options you want -- here we stick with the defaults */
	pci_init(pacc);		/* Initialize the PCI library */
	pci_scan_bus(pacc);	/* We want to get the list of devices */

424
	myusec_calibrate_delay();
425 426 427 428

	/* We look at the lbtable first to see if we need a
	 * mainboard specific flash enable sequence.
	 */
Stefan Reinauer's avatar
Stefan Reinauer committed
429
	coreboot_init();
Ronald G. Minnich's avatar
Ronald G. Minnich committed
430

431
	/* try to enable it. Failure IS an option, since not all motherboards
432
	 * really need this to be done, etc., etc.
433
	 */
434 435 436 437 438
	ret = chipset_flash_enable();
	if (ret == -2) {
		printf("WARNING: No chipset found. Flash detection "
		       "will most likely fail.\n");
	}
439

440
	board_flash_enable(lb_vendor, lb_part);
441

Claus Gindhart's avatar
Claus Gindhart committed
442
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
443 444
		flashes[i] =
		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
Claus Gindhart's avatar
Claus Gindhart committed
445 446 447 448 449 450 451 452 453 454 455 456
		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]) {
457
		printf("No EEPROM/flash device found.\n");
Peter Stuge's avatar
Peter Stuge committed
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
		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);
			}
473 474 475 476
			if (!filename) {
				printf("Error: No filename specified.\n");
				exit(1);
			}
Peter Stuge's avatar
Peter Stuge committed
477 478 479 480 481 482 483
			size = flashes[0]->total_size * 1024;
			buf = (uint8_t *) calloc(size, sizeof(char));

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
484
			printf("Force reading flash... ");
Peter Stuge's avatar
Peter Stuge committed
485 486 487 488 489 490 491
			if (!flashes[0]->read)
				memcpy(buf, (const char *)flashes[0]->virtual_memory, size);
			else
				flashes[0]->read(flashes[0], buf);

			if (exclude_end_position - exclude_start_position > 0)
				memset(buf + exclude_start_position, 0,
492 493
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
494

495
			numbytes = fwrite(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
496
			fclose(image);
497
			printf("%s.\n", numbytes == size ? "done" : "FAILED");
Peter Stuge's avatar
Peter Stuge committed
498
			free(buf);
499
			return numbytes != size;
Peter Stuge's avatar
Peter Stuge committed
500
		}
501
		// FIXME: flash writes stay enabled!
502 503
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
504

Claus Gindhart's avatar
Claus Gindhart committed
505 506
	flash = flashes[0];

507 508 509 510 511 512 513 514 515 516 517 518 519
	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");
520 521 522 523 524
		}
		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))) {
525
			printf("This flash part has status UNTESTED for operations:");
526
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
527
				printf(" PROBE");
528
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
529
				printf(" READ");
530
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
531
				printf(" ERASE");
532
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
533 534 535 536 537 538 539 540
				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");
	}
541

542 543 544 545 546 547
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

548
	if (!filename && !erase_it) {
549 550 551
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
552 553
	}

554 555
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
556

557
	if (erase_it) {
558
		printf("Erasing flash chip... ");
559 560 561
		if (NULL == flash->erase) {
			printf("FAILED!\n");
			fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
562 563
			return 1;
		}
564
		flash->erase(flash);
565 566 567 568
		if (NULL == flash->read)
			memcpy(buf, (const char *)flash->virtual_memory, size);
		else
			flash->read(flash, buf);
569
		for (erasedbytes = 0; erasedbytes < size; erasedbytes++)
570 571 572 573 574 575 576 577
			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;
578
	} else if (read_it) {
579
		if ((image = fopen(filename, "w")) == NULL) {
580 581 582
			perror(filename);
			exit(1);
		}
583
		printf("Reading flash... ");
Ollie Lho's avatar
Ollie Lho committed
584
		if (flash->read == NULL)
585
			memcpy(buf, (const char *)flash->virtual_memory, size);
586
		else
587
			flash->read(flash, buf);
588

589
		if (exclude_end_position - exclude_start_position > 0)
590 591
			memset(buf + exclude_start_position, 0,
			       exclude_end_position - exclude_start_position);
592

593
		numbytes = fwrite(buf, 1, size, image);
594
		fclose(image);
595 596 597
		printf("%s.\n", numbytes == size ? "done" : "FAILED");
		if (numbytes != size)
			return 1;
598
	} else {
599 600
		struct stat image_stat;

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

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

623 624 625 626 627 628
	/* 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
	 */
629

630
	// ////////////////////////////////////////////////////////////
631
	if (exclude_end_position - exclude_start_position > 0)
632
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
633 634
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
635
		       exclude_end_position - exclude_start_position);
636

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

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

648
	// ////////////////////////////////////////////////////////////
649

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

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

661 662 663
#ifdef __FreeBSD__
	close(io_fd);
#endif
Stefan Reinauer's avatar
Stefan Reinauer committed
664
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
665
}