flashrom.c 19 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 25
 */

#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
26 27
#include <sys/types.h>
#include <sys/stat.h>
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
28 29
#include <unistd.h>
#include <stdio.h>
Ronald G. Minnich's avatar
Ronald G. Minnich committed
30
#include <string.h>
Ronald G. Minnich's avatar
Ronald G. Minnich committed
31
#include <stdlib.h>
32
#include <getopt.h>
33 34 35 36 37 38 39 40
#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
41 42
#include "flash.h"

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

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

54 55 56
	pci_filter_init(NULL, &filter);
	filter.vendor = vendor;
	filter.device = device;
57

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

62
	return NULL;
63 64
}

65 66
struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
			      uint16_t card_vendor, uint16_t card_device)
67
{
68 69 70 71 72 73 74 75 76
	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)) {
77 78 79 80
			if ((card_vendor ==
			     pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
			    && (card_device ==
				pci_read_word(temp, PCI_SUBSYSTEM_ID)))
81 82
				return temp;
		}
83

84
	return NULL;
85 86
}

87 88 89 90 91 92
int map_flash_registers(struct flashchip *flash)
{
	volatile uint8_t *registers;
	size_t size = flash->total_size * 1024;

	registers = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
Uwe Hermann's avatar
Uwe Hermann committed
93
			 fd_mem, (off_t) (0xFFFFFFFF - 0x400000 - size + 1));
94 95 96 97 98 99 100 101 102 103

	if (registers == MAP_FAILED) {
		perror("Can't mmap registers using " MEM_DEV);
		exit(1);
	}
	flash->virtual_registers = registers;

	return 0;
}

104
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
105
{
106
	volatile uint8_t *bios;
107
	struct flashchip *flash;
108
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
109

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

120
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
121 122

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

128
		if (getpagesize() > size) {
129 130 131 132 133
			/*
			 * 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.
			 */
134 135
			size = getpagesize();
		}
136

Peter Stuge's avatar
Peter Stuge committed
137
		base = flashbase ? flashbase : (0xffffffff - size + 1);
138
		bios = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
Peter Stuge's avatar
Peter Stuge committed
139
			    fd_mem, (off_t) base);
140
		if (bios == MAP_FAILED) {
Stefan Reinauer's avatar
Stefan Reinauer committed
141
			perror("Can't mmap memory using " MEM_DEV);
142 143
			exit(1);
		}
144
		flash->virtual_memory = bios;
145

146 147 148
		if (force)
			break;

149 150 151
		if (flash->probe(flash) != 1)
			goto notfound;

152 153
		if (first_flash == flashchips
		    || flash->model_id != GENERIC_DEVICE_ID)
154
			break;
Stefan Reinauer's avatar
Stefan Reinauer committed
155

156
notfound:
157
		munmap((void *)bios, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
158
	}
Uwe Hermann's avatar
Uwe Hermann committed
159

160 161 162 163
	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
164 165
	       flash->vendor, flash->name, flash->total_size, base);
	flashbase = base;
166
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
167 168
}

Stefan Reinauer's avatar
Stefan Reinauer committed
169
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
170
{
Stefan Reinauer's avatar
Stefan Reinauer committed
171
	int idx;
172
	int total_size = flash->total_size * 1024;
173 174 175 176 177
	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);
178

179
	printf("Verifying flash... ");
180 181 182 183

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

Stefan Reinauer's avatar
Stefan Reinauer committed
184
	for (idx = 0; idx < total_size; idx++) {
185
		if (verbose && ((idx & 0xfff) == 0xfff))
Stefan Reinauer's avatar
Stefan Reinauer committed
186 187
			printf("0x%08x", idx);

188
		if (*(buf2 + idx) != *(buf + idx)) {
189 190 191 192 193
			if (verbose)
				printf("0x%08x FAILED!", idx);
			else
				printf("FAILED at 0x%08x!", idx);
			printf("  Expected=0x%02x, Read=0x%02x\n",
194
			       *(buf + idx), *(buf2 + idx));
Stefan Reinauer's avatar
Stefan Reinauer committed
195
			return 1;
196
		}
197 198

		if (verbose && ((idx & 0xfff) == 0xfff))
199
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
200
	}
201
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
202
		printf("\b\b\b\b\b\b\b\b\b\b ");
203

204
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
205

Stefan Reinauer's avatar
Stefan Reinauer committed
206
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
207 208
}

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

212 213
void print_supported_chips(void)
{
214 215
	int okcol = 0, pos = 0;
	struct flashchip *f;
216

217 218 219 220 221 222
	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;
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	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");
	}
264 265
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
266 267
void usage(const char *name)
{
268 269
	printf("usage: %s [-rwvEVfLhR] [-c chipname] [-s exclude_start]\n",
	       name);
270
	printf("       [-e exclude_end] [-m [vendor:]part] [-l file.layout] [-i imagename] [file]\n");
271
	printf
272 273 274 275 276 277 278 279 280 281 282 283
	    ("   -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"
284 285
	     "   -L | --list-supported:            print supported devices\n"
	     "   -h | --help:                      print this help text\n"
286
	     "   -R | --version:                   print the version (release)\n"
287
	     "\n" " If no file is specified, then all that happens"
288
	     " is that flash info is dumped.\n\n");
289
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
290 291
}

292 293 294 295 296
void print_version(void)
{
	printf("flashrom r%s\n", FLASHROM_VERSION);
}

297
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
298
{
299
	uint8_t *buf;
300
	unsigned long size, numbytes;
301
	uint32_t erasedbytes;
302
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
303 304
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
305
	int opt;
306
	int option_index = 0;
Peter Stuge's avatar
Peter Stuge committed
307
	int force = 0;
308
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Claus Gindhart's avatar
Claus Gindhart committed
309
	int ret = 0, i;
310 311 312
#ifdef __FreeBSD__
	int io_fd;
#endif
313

314 315 316 317 318 319 320 321 322 323 324 325 326
	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'},
327
		{"list-supported", 0, 0, 'L'},
328
		{"help", 0, 0, 'h'},
329
		{"version", 0, 0, 'R'},
330
		{0, 0, 0, 0}
331
	};
332

333
	char *filename = NULL;
334

335 336
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
337 338 339 340

	if (argc > 1) {
		/* Yes, print them. */
		int i;
341
		printf_debug("The arguments are:\n");
342
		for (i = 1; i < argc; ++i)
343
			printf_debug("%s\n", argv[i]);
344 345
	}

346
	setbuf(stdout, NULL);
347
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:Lh",
348
				  long_options, &option_index)) != EOF) {
349 350 351 352 353 354 355 356 357 358 359 360 361
		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
362 363 364
		case 'V':
			verbose = 1;
			break;
365 366 367
		case 'E':
			erase_it = 1;
			break;
368 369
		case 's':
			tempstr = strdup(optarg);
370
			sscanf(tempstr, "%x", &exclude_start_position);
371 372
			break;
		case 'e':
373
			tempstr = strdup(optarg);
374
			sscanf(tempstr, "%x", &exclude_end_position);
375
			break;
376 377 378
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
379
			tempstr2 = strtok(NULL, ":");
380
			if (tempstr2) {
381 382
				lb_vendor = tempstr;
				lb_part = tempstr2;
383
			} else {
384 385
				lb_vendor = NULL;
				lb_part = tempstr;
386 387 388
			}
			break;
		case 'f':
389
			force = 1;
390 391
			break;
		case 'l':
392
			tempstr = strdup(optarg);
393 394
			if (read_romlayout(tempstr))
				exit(1);
395 396
			break;
		case 'i':
397
			tempstr = strdup(optarg);
398 399
			find_romentry(tempstr);
			break;
400 401 402 403 404 405
		case 'L':
			print_supported_chips();
			print_supported_chipsets();
			print_supported_boards();
			exit(0);
			break;
406 407 408 409
		case 'R':
			print_version();
			exit(0);
			break;
410
		case 'h':
411 412 413 414 415
		default:
			usage(argv[0]);
			break;
		}
	}
416

417
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
418
		printf("Error: -r and -w are mutually exclusive.\n");
419 420
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
421

422 423
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
424

425
	/* First get full io access */
426
#if defined (__sun) && (defined(__i386) || defined(__amd64))
427
	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
428 429
#elif defined(__FreeBSD__)
	if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
430 431 432
#else
	if (iopl(3) != 0) {
#endif
433
		fprintf(stderr, "ERROR: Could not get IO privileges (%s).\nYou need to be root.\n", strerror(errno));
434 435 436
		exit(1);
	}

437
	/* Initialize PCI access for flash enables */
438 439 440 441 442
	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 */

443
	/* Open the memory device UNCACHED. That's important for MMIO. */
444
	if ((fd_mem = open(MEM_DEV, O_RDWR | O_SYNC)) < 0) {
445 446
		perror("Error: Can not access memory using " MEM_DEV
		       ". You need to be root.");
Stefan Reinauer's avatar
Stefan Reinauer committed
447 448 449
		exit(1);
	}

450
	myusec_calibrate_delay();
451 452 453 454

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

457
	/* try to enable it. Failure IS an option, since not all motherboards
458
	 * really need this to be done, etc., etc.
459
	 */
460 461 462 463 464
	ret = chipset_flash_enable();
	if (ret == -2) {
		printf("WARNING: No chipset found. Flash detection "
		       "will most likely fail.\n");
	}
465

466
	board_flash_enable(lb_vendor, lb_part);
467

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

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
510
			printf("Force reading flash... ");
Peter Stuge's avatar
Peter Stuge committed
511 512 513 514 515 516 517
			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,
518 519
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
520

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

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

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

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

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

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

583
	if (erase_it) {
584
		printf("Erasing flash chip... ");
585 586 587
		if (NULL == flash->erase) {
			printf("FAILED!\n");
			fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
588 589
			return 1;
		}
590
		flash->erase(flash);
591 592 593 594 595 596 597 598 599 600 601 602 603
		if (NULL == flash->read)
			memcpy(buf, (const char *)flash->virtual_memory, size);
		else
			flash->read(flash, buf);
		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;
604
	} else if (read_it) {
605
		if ((image = fopen(filename, "w")) == NULL) {
606 607 608
			perror(filename);
			exit(1);
		}
609
		printf("Reading flash... ");
Ollie Lho's avatar
Ollie Lho committed
610
		if (flash->read == NULL)
611
			memcpy(buf, (const char *)flash->virtual_memory, size);
612
		else
613
			flash->read(flash, buf);
614

615
		if (exclude_end_position - exclude_start_position > 0)
616 617
			memset(buf + exclude_start_position, 0,
			       exclude_end_position - exclude_start_position);
618

619
		numbytes = fwrite(buf, 1, size, image);
620
		fclose(image);
621 622 623
		printf("%s.\n", numbytes == size ? "done" : "FAILED");
		if (numbytes != size)
			return 1;
624
	} else {
625 626
		struct stat image_stat;

627
		if ((image = fopen(filename, "r")) == NULL) {
628 629 630
			perror(filename);
			exit(1);
		}
631 632 633 634
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
635
		if (image_stat.st_size != flash->total_size * 1024) {
Uwe Hermann's avatar
Uwe Hermann committed
636
			fprintf(stderr, "Error: Image size doesn't match\n");
637 638 639
			exit(1);
		}

640
		numbytes = fread(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
641
		show_id(buf, size, force);
642
		fclose(image);
643 644 645 646
		if (numbytes != size) {
			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
			return 1;
		}
647
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
648

649 650 651 652 653 654
	/* 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
	 */
655

656
	// ////////////////////////////////////////////////////////////
657
	if (exclude_end_position - exclude_start_position > 0)
658
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
659 660
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
661
		       exclude_end_position - exclude_start_position);
662

663 664
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
665 666
		exclude_start_page++;
	}
667
	exclude_end_page = exclude_end_position / flash->page_size;
668 669 670 671
	// ////////////////////////////////////////////////////////////

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

674
	// ////////////////////////////////////////////////////////////
675

676 677 678 679 680
	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
681
		ret |= flash->write(flash, buf);
682
	}
683

684
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
685
		ret |= verify_flash(flash, buf);
686

687 688 689
#ifdef __FreeBSD__
	close(io_fd);
#endif
Stefan Reinauer's avatar
Stefan Reinauer committed
690
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
691
}