flashrom.c 23.9 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>
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
Ronald G. Minnich committed
27
#include <string.h>
Ronald G. Minnich's avatar
Ronald G. Minnich committed
28
#include <stdlib.h>
29
#include <getopt.h>
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
30 31
#include "flash.h"

Ronald G. Minnich's avatar
Ronald G. Minnich committed
32
char *chip_to_probe = NULL;
Stefan Reinauer's avatar
Stefan Reinauer committed
33
int exclude_start_page, exclude_end_page;
Peter Stuge's avatar
Peter Stuge committed
34
int verbose = 0;
35 36 37 38
int programmer = PROGRAMMER_INTERNAL;

const struct programmer_entry programmer_table[] = {
	{
39 40
		.init			= internal_init,
		.shutdown		= internal_shutdown,
41 42
		.map_flash_region	= physmap,
		.unmap_flash_region	= physunmap,
43 44 45
		.chip_readb		= internal_chip_readb,
		.chip_readw		= internal_chip_readw,
		.chip_readl		= internal_chip_readl,
46
		.chip_readn		= internal_chip_readn,
47 48 49
		.chip_writeb		= internal_chip_writeb,
		.chip_writew		= internal_chip_writew,
		.chip_writel		= internal_chip_writel,
50
		.chip_writen		= fallback_chip_writen,
51
		.delay			= internal_delay,
52 53
	},

54
	{
55 56
		.init			= dummy_init,
		.shutdown		= dummy_shutdown,
57 58
		.map_flash_region	= dummy_map,
		.unmap_flash_region	= dummy_unmap,
59 60 61
		.chip_readb		= dummy_chip_readb,
		.chip_readw		= dummy_chip_readw,
		.chip_readl		= dummy_chip_readl,
62
		.chip_readn		= dummy_chip_readn,
63 64 65
		.chip_writeb		= dummy_chip_writeb,
		.chip_writew		= dummy_chip_writew,
		.chip_writel		= dummy_chip_writel,
66
		.chip_writen		= dummy_chip_writen,
67
		.delay			= internal_delay,
68 69
	},

70 71 72
	{
		.init			= nic3com_init,
		.shutdown		= nic3com_shutdown,
73 74
		.map_flash_region	= fallback_map,
		.unmap_flash_region	= fallback_unmap,
75
		.chip_readb		= nic3com_chip_readb,
76 77
		.chip_readw		= fallback_chip_readw,
		.chip_readl		= fallback_chip_readl,
78
		.chip_readn		= fallback_chip_readn,
79
		.chip_writeb		= nic3com_chip_writeb,
80 81
		.chip_writew		= fallback_chip_writew,
		.chip_writel		= fallback_chip_writel,
82
		.chip_writen		= fallback_chip_writen,
83
		.delay			= internal_delay,
84 85
	},

86 87 88
	{
		.init			= satasii_init,
		.shutdown		= satasii_shutdown,
89 90
		.map_flash_region	= fallback_map,
		.unmap_flash_region	= fallback_unmap,
91 92 93
		.chip_readb		= satasii_chip_readb,
		.chip_readw		= fallback_chip_readw,
		.chip_readl		= fallback_chip_readl,
94
		.chip_readn		= fallback_chip_readn,
95 96 97
		.chip_writeb		= satasii_chip_writeb,
		.chip_writew		= fallback_chip_writew,
		.chip_writel		= fallback_chip_writel,
98
		.chip_writen		= fallback_chip_writen,
99
		.delay			= internal_delay,
100 101
	},

102 103 104 105 106 107
	{
		.init			= it87spi_init,
		.shutdown		= dummy_shutdown,
		.map_flash_region	= dummy_map,
		.unmap_flash_region	= dummy_unmap,
		.chip_readb		= dummy_chip_readb,
108 109 110
		.chip_readw		= fallback_chip_readw,
		.chip_readl		= fallback_chip_readl,
		.chip_readn		= fallback_chip_readn,
111
		.chip_writeb		= dummy_chip_writeb,
112 113 114
		.chip_writew		= fallback_chip_writew,
		.chip_writel		= fallback_chip_writel,
		.chip_writen		= fallback_chip_writen,
115
		.delay			= internal_delay,
116 117
	},

118 119
	{},
};
120

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
int programmer_init(void)
{
	return programmer_table[programmer].init();
}

int programmer_shutdown(void)
{
	return programmer_table[programmer].shutdown();
}

void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
				  size_t len)
{
	return programmer_table[programmer].map_flash_region(descr,
							     phys_addr, len);
}

void programmer_unmap_flash_region(void *virt_addr, size_t len)
{
	programmer_table[programmer].unmap_flash_region(virt_addr, len);
}

void chip_writeb(uint8_t val, chipaddr addr)
{
	programmer_table[programmer].chip_writeb(val, addr);
}

void chip_writew(uint16_t val, chipaddr addr)
{
	programmer_table[programmer].chip_writew(val, addr);
}

void chip_writel(uint32_t val, chipaddr addr)
{
	programmer_table[programmer].chip_writel(val, addr);
}

158 159 160 161 162
void chip_writen(uint8_t *buf, chipaddr addr, size_t len)
{
	programmer_table[programmer].chip_writen(buf, addr, len);
}

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
uint8_t chip_readb(const chipaddr addr)
{
	return programmer_table[programmer].chip_readb(addr);
}

uint16_t chip_readw(const chipaddr addr)
{
	return programmer_table[programmer].chip_readw(addr);
}

uint32_t chip_readl(const chipaddr addr)
{
	return programmer_table[programmer].chip_readl(addr);
}

178 179 180 181 182 183
void chip_readn(uint8_t *buf, chipaddr addr, size_t len)
{
	programmer_table[programmer].chip_readn(buf, addr, len);
	return;
}

184 185 186 187 188
void programmer_delay(int usecs)
{
	programmer_table[programmer].delay(usecs);
}

189
void map_flash_registers(struct flashchip *flash)
190 191
{
	size_t size = flash->total_size * 1024;
192
	/* Flash registers live 4 MByte below the flash. */
193
	flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
194 195
}

196 197
int read_memmapped(struct flashchip *flash, uint8_t *buf)
{
198
	chip_readn(buf, flash->virtual_memory, flash->total_size * 1024);
199 200 201 202
		
	return 0;
}

203 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
char *strcat_realloc(char *dest, const char *src)
{
	dest = realloc(dest, strlen(dest) + strlen(src) + 1);
	if (!dest)
		return NULL;
	strcat(dest, src);
	return dest;
}

/* Return a string corresponding to the bustype parameter.
 * Memory is obtained with malloc() and can be freed with free().
 */
char *flashbuses_to_text(enum chipbustype bustype)
{
	char *ret = calloc(1, 1);
	if (bustype == CHIP_BUSTYPE_UNKNOWN) {
		ret = strcat_realloc(ret, "Unknown,");
	/* FIXME: Once all chipsets and flash chips have been updated, NONSPI
	 * will cease to exist and should be eliminated here as well.
	 */
	} else if (bustype == CHIP_BUSTYPE_NONSPI) {
		ret = strcat_realloc(ret, "Non-SPI,");
	} else {
		if (bustype & CHIP_BUSTYPE_PARALLEL)
			ret = strcat_realloc(ret, "Parallel,");
		if (bustype & CHIP_BUSTYPE_LPC)
			ret = strcat_realloc(ret, "LPC,");
		if (bustype & CHIP_BUSTYPE_FWH)
			ret = strcat_realloc(ret, "FWH,");
		if (bustype & CHIP_BUSTYPE_SPI)
			ret = strcat_realloc(ret, "SPI,");
		if (bustype == CHIP_BUSTYPE_NONE)
			ret = strcat_realloc(ret, "None,");
	}
	/* Kill last comma. */
	ret[strlen(ret) - 1] = '\0';
	ret = realloc(ret, strlen(ret) + 1);
	return ret;
}

243
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
244
{
245
	struct flashchip *flash;
246
	unsigned long base = 0, size;
247
	char *tmp;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
248

249
	for (flash = first_flash; flash && flash->name; flash++) {
250
		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
251
			continue;
252 253
		printf_debug("Probing for %s %s, %d KB: ",
			     flash->vendor, flash->name, flash->total_size);
Peter Stuge's avatar
Peter Stuge committed
254
		if (!flash->probe && !force) {
255 256 257
			printf_debug("failed! flashrom has no probe function for this flash chip.\n");
			continue;
		}
258 259 260 261 262 263 264 265 266
		if (!(buses_supported & flash->bustype)) {
			tmp = flashbuses_to_text(buses_supported);
			printf_debug("skipped. Host bus type %s ", tmp);
			free(tmp);
			tmp = flashbuses_to_text(flash->bustype);
			printf_debug("and chip bus type %s are incompatible.\n", tmp);
			free(tmp);
			continue;
		}
Stefan Reinauer's avatar
Stefan Reinauer committed
267

268
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
269

270
		base = flashbase ? flashbase : (0xffffffff - size + 1);
271
		flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
272

273 274 275
		if (force)
			break;

276 277 278
		if (flash->probe(flash) != 1)
			goto notfound;

279 280
		if (first_flash == flashchips
		    || flash->model_id != GENERIC_DEVICE_ID)
281
			break;
Stefan Reinauer's avatar
Stefan Reinauer committed
282

283
notfound:
284
		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
285
	}
Uwe Hermann's avatar
Uwe Hermann committed
286

287 288 289 290
	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
291
	       flash->vendor, flash->name, flash->total_size, base);
292
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
293 294
}

Stefan Reinauer's avatar
Stefan Reinauer committed
295
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
296
{
Stefan Reinauer's avatar
Stefan Reinauer committed
297
	int idx;
298
	int total_size = flash->total_size * 1024;
299
	uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
300 301 302 303 304
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
305
		flash->read(flash, buf2);
306

307
	printf("Verifying flash... ");
308 309 310 311

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

Stefan Reinauer's avatar
Stefan Reinauer committed
312
	for (idx = 0; idx < total_size; idx++) {
313
		if (verbose && ((idx & 0xfff) == 0xfff))
Stefan Reinauer's avatar
Stefan Reinauer committed
314 315
			printf("0x%08x", idx);

316
		if (*(buf2 + idx) != *(buf + idx)) {
317 318 319 320 321
			if (verbose)
				printf("0x%08x FAILED!", idx);
			else
				printf("FAILED at 0x%08x!", idx);
			printf("  Expected=0x%02x, Read=0x%02x\n",
322
			       *(buf + idx), *(buf2 + idx));
Stefan Reinauer's avatar
Stefan Reinauer committed
323
			return 1;
324
		}
325 326

		if (verbose && ((idx & 0xfff) == 0xfff))
327
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
328
	}
329
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
330
		printf("\b\b\b\b\b\b\b\b\b\b ");
331

332
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
333

Stefan Reinauer's avatar
Stefan Reinauer committed
334
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
335 336
}

337 338 339 340 341 342
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));
343 344 345 346 347

	if (!filename) {
		printf("Error: No filename specified.\n");
		return 1;
	}
348 349 350 351 352
	if ((image = fopen(filename, "w")) == NULL) {
		perror(filename);
		exit(1);
	}
	printf("Reading flash... ");
353 354 355 356 357
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
358 359 360 361 362 363 364 365
		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);
366
	free(buf);
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
	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;
	}
384 385
	flash->erase(flash);

386 387 388 389 390
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
391
		flash->read(flash, buf);
392

393 394 395 396 397 398 399 400 401 402 403
	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
404
#ifndef MAX
405
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Uwe Hermann's avatar
Uwe Hermann committed
406
#endif
407 408
#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)

409 410
void print_supported_chips(void)
{
411
	int okcol = 0, pos = 0, i;
412
	struct flashchip *f;
413

414 415 416 417 418 419
	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;
420

421 422
	printf("Supported flash chips:\n\n");
	POS_PRINT("Vendor:   Device:");
423 424 425 426 427 428 429
	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++) {
430 431 432 433 434 435 436 437 438 439
		/* Don't print "unknown XXXX SPI chip" entries. */
		if (!strncmp(f->name, "unknown", 7))
			continue;

		printf("%s", f->vendor);
		for (i = 0; i < 10 - strlen(f->vendor); i++)
			printf(" ");
		printf("%s", f->name);

		pos = 10 + strlen(f->name);
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
		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");
	}
470 471
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
472 473
void usage(const char *name)
{
474
	printf("usage: %s [-VfLhR] [-E|-r file|-w file|-v file] [-c chipname] [-s addr]\n"
475
	       "       [-e addr] [-m [vendor:]part] [-l file] [-i image] [-p programmer] [file]\n\n",
476
	       name);
477

478 479 480 481
	printf("Please note that the command line interface for flashrom will "
		"change before\nflashrom 1.0. Do not use flashrom in scripts "
		"or other automated tools without\nchecking that your flashrom"
		" version won't interpret options in a different way.\n\n");
482

483
	printf
484 485 486 487 488 489 490 491 492 493
	    ("   -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"
494
	     "   -l | --layout <file.layout>:      read ROM layout from file\n"
495
	     "   -i | --image <name>:              only flash image name from flash layout\n"
496
	     "   -L | --list-supported:            print supported devices\n"
497
	     "   -p | --programmer <name>:         specify the programmer device\n"
498
	     "                                     (internal, dummy, nic3com, satasii, it87spi)\n"
499
	     "   -h | --help:                      print this help text\n"
500
	     "   -R | --version:                   print the version (release)\n"
501 502
	     "\nYou can specify one of -E, -r, -w, -v or no operation.\n"
	     "If no operation is specified, then all that happens"
503
	     " is that flash info is dumped.\n\n");
504
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
505 506
}

507 508
void print_version(void)
{
Carl-Daniel Hailfinger's avatar
Carl-Daniel Hailfinger committed
509
	printf("flashrom v%s\n", FLASHROM_VERSION);
510 511
}

512
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
513
{
514
	uint8_t *buf;
515
	unsigned long size, numbytes;
516
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
517 518
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
519
	int opt;
520
	int option_index = 0;
Peter Stuge's avatar
Peter Stuge committed
521
	int force = 0;
522
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Uwe Hermann's avatar
Uwe Hermann committed
523
	int list_supported = 0;
524
	int operation_specified = 0;
Claus Gindhart's avatar
Claus Gindhart committed
525
	int ret = 0, i;
526

527 528 529 530 531 532 533 534 535 536 537 538 539
	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'},
540
		{"list-supported", 0, 0, 'L'},
541
		{"programmer", 1, 0, 'p'},
542
		{"help", 0, 0, 'h'},
543
		{"version", 0, 0, 'R'},
544
		{0, 0, 0, 0}
545
	};
546

547
	char *filename = NULL;
548

549 550
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
551

552 553
	print_version();

554 555 556
	if (argc > 1) {
		/* Yes, print them. */
		int i;
557
		printf_debug("The arguments are:\n");
558
		for (i = 1; i < argc; ++i)
559
			printf_debug("%s\n", argv[i]);
560 561
	}

562
	setbuf(stdout, NULL);
563
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:p:Lh",
564
				  long_options, &option_index)) != EOF) {
565 566
		switch (opt) {
		case 'r':
567 568 569 570 571
			if (++operation_specified > 1) {
				fprintf(stderr, "More than one operation "
					"specified. Aborting.\n");
				exit(1);
			}
572 573 574
			read_it = 1;
			break;
		case 'w':
575 576 577 578 579
			if (++operation_specified > 1) {
				fprintf(stderr, "More than one operation "
					"specified. Aborting.\n");
				exit(1);
			}
580 581 582
			write_it = 1;
			break;
		case 'v':
583 584 585 586 587
			if (++operation_specified > 1) {
				fprintf(stderr, "More than one operation "
					"specified. Aborting.\n");
				exit(1);
			}
588 589 590 591 592
			verify_it = 1;
			break;
		case 'c':
			chip_to_probe = strdup(optarg);
			break;
Ollie Lho's avatar
Ollie Lho committed
593 594 595
		case 'V':
			verbose = 1;
			break;
596
		case 'E':
597 598 599 600 601
			if (++operation_specified > 1) {
				fprintf(stderr, "More than one operation "
					"specified. Aborting.\n");
				exit(1);
			}
602 603
			erase_it = 1;
			break;
604 605
		case 's':
			tempstr = strdup(optarg);
606
			sscanf(tempstr, "%x", &exclude_start_position);
607 608
			break;
		case 'e':
609
			tempstr = strdup(optarg);
610
			sscanf(tempstr, "%x", &exclude_end_position);
611
			break;
612 613 614
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
615
			tempstr2 = strtok(NULL, ":");
616
			if (tempstr2) {
617 618
				lb_vendor = tempstr;
				lb_part = tempstr2;
619
			} else {
620 621
				lb_vendor = NULL;
				lb_part = tempstr;
622 623 624
			}
			break;
		case 'f':
625
			force = 1;
626 627
			break;
		case 'l':
628
			tempstr = strdup(optarg);
629 630
			if (read_romlayout(tempstr))
				exit(1);
631 632
			break;
		case 'i':
633
			tempstr = strdup(optarg);
634 635
			find_romentry(tempstr);
			break;
636
		case 'L':
Uwe Hermann's avatar
Uwe Hermann committed
637
			list_supported = 1;
638
			break;
639 640 641
		case 'p':
			if (strncmp(optarg, "internal", 8) == 0) {
				programmer = PROGRAMMER_INTERNAL;
642 643
			} else if (strncmp(optarg, "dummy", 5) == 0) {
				programmer = PROGRAMMER_DUMMY;
644 645
				if (optarg[5] == '=')
					dummytype = strdup(optarg + 6);
646 647
			} else if (strncmp(optarg, "nic3com", 7) == 0) {
				programmer = PROGRAMMER_NIC3COM;
648
				if (optarg[7] == '=')
649
					pcidev_bdf = strdup(optarg + 8);
650 651 652 653
			} else if (strncmp(optarg, "satasii", 7) == 0) {
				programmer = PROGRAMMER_SATASII;
				if (optarg[7] == '=')
					pcidev_bdf = strdup(optarg + 8);
654 655
			} else if (strncmp(optarg, "it87spi", 7) == 0) {
				programmer = PROGRAMMER_IT87SPI;
656 657 658 659 660
			} else {
				printf("Error: Unknown programmer.\n");
				exit(1);
			}
			break;
661
		case 'R':
662
			/* print_version() is always called during startup. */
663 664
			exit(0);
			break;
665
		case 'h':
666 667 668 669 670
		default:
			usage(argv[0]);
			break;
		}
	}
671

Uwe Hermann's avatar
Uwe Hermann committed
672 673 674 675 676 677 678
	if (list_supported) {
		print_supported_chips();
		print_supported_chipsets();
		print_supported_boards();
		printf("\nSupported PCI devices flashrom can use "
		       "as programmer:\n\n");
		print_supported_pcidevs(nics_3com);
679
		print_supported_pcidevs(satas_sii);
Uwe Hermann's avatar
Uwe Hermann committed
680 681 682
		exit(0);
	}

683
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
684
		printf("Error: -r and -w are mutually exclusive.\n");
685 686
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
687

688 689
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
690

691
	ret = programmer_init();
692

693
	myusec_calibrate_delay();
694

Claus Gindhart's avatar
Claus Gindhart committed
695
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
696 697
		flashes[i] =
		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
Claus Gindhart's avatar
Claus Gindhart committed
698 699 700 701 702 703 704 705 706 707 708 709
		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]) {
710
		printf("No EEPROM/flash device found.\n");
Peter Stuge's avatar
Peter Stuge committed
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
		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);
			}
726
			return read_flash(flashes[0], filename, exclude_start_position, exclude_end_position);
Peter Stuge's avatar
Peter Stuge committed
727
		}
728
		// FIXME: flash writes stay enabled!
729 730
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
731

Claus Gindhart's avatar
Claus Gindhart committed
732 733
	flash = flashes[0];

734 735 736 737 738 739 740 741 742 743 744 745 746
	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");
747 748 749 750 751
		}
		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))) {
752
			printf("This flash part has status UNTESTED for operations:");
753
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
754
				printf(" PROBE");
755
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
756
				printf(" READ");
757
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
758
				printf(" ERASE");
759
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
760 761 762
				printf(" WRITE");
			printf("\n");
		}
763 764 765 766 767 768
		printf("Please email a report to flashrom@coreboot.org if any "
		       "of the above operations\nwork correctly for you with "
		       "this flash part. Please include the flashrom\noutput "
		       "with the additional -V option for all operations you "
		       "tested (-V, -rV,\n-wV, -EV), and mention which "
		       "mainboard you tested. Thanks for your help!\n===\n");
769
	}
770

771 772 773 774 775 776
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

777
	if (!filename && !erase_it) {
778 779 780
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
781 782
	}

783 784
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
785

786
	if (erase_it) {
787
		if (erase_flash(flash))
788
			return 1;
789
	} else if (read_it) {
790
		if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
791
			return 1;
792
	} else {
793 794
		struct stat image_stat;

795
		if ((image = fopen(filename, "r")) == NULL) {
796 797 798
			perror(filename);
			exit(1);
		}
799 800 801 802
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
803
		if (image_stat.st_size != flash->total_size * 1024) {
Uwe Hermann's avatar
Uwe Hermann committed
804
			fprintf(stderr, "Error: Image size doesn't match\n");
805 806 807
			exit(1);
		}

808
		numbytes = fread(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
809
		show_id(buf, size, force);
810
		fclose(image);
811 812 813 814
		if (numbytes != size) {
			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
			return 1;
		}
815
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
816

817 818 819 820 821 822
	/* 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
	 */
823

824
	// ////////////////////////////////////////////////////////////
825
	if (exclude_end_position - exclude_start_position > 0)
826 827 828
		chip_readn(buf + exclude_start_position,
			   flash->virtual_memory + exclude_start_position,
			   exclude_end_position - exclude_start_position);
829

830 831
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
832 833
		exclude_start_page++;
	}
834
	exclude_end_page = exclude_end_position / flash->page_size;
835 836 837 838
	// ////////////////////////////////////////////////////////////

	// This should be moved into each flash part's code to do it 
	// cleanly. This does the job.
839
	/* FIXME: Adapt to the external flasher infrastructure. */
840
	handle_romentries(buf, (uint8_t *) flash->virtual_memory);
841

842
	// ////////////////////////////////////////////////////////////
843

844
	if (write_it) {
845
		printf("Writing flash chip... ");
846 847 848 849
		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
850
		ret |= flash->write(flash, buf);
851
		if (!ret) printf("COMPLETE.\n");
852
	}
853

854
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
855
		ret |= verify_flash(flash, buf);
856

857 858
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
859
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
860
}