flashrom.c 23.2 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 [-EVfLhR] [-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
	     "\nIf no file is specified, then all that happens"
502
	     " is that flash info is dumped.\n\n");
503
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
504 505
}

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

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

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

545
	char *filename = NULL;
546

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

550 551
	print_version();

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

560
	setbuf(stdout, NULL);
561
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:p:Lh",
562
				  long_options, &option_index)) != EOF) {
563 564 565 566 567 568 569 570 571 572 573 574 575
		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
576 577 578
		case 'V':
			verbose = 1;
			break;
579 580 581
		case 'E':
			erase_it = 1;
			break;
582 583
		case 's':
			tempstr = strdup(optarg);
584
			sscanf(tempstr, "%x", &exclude_start_position);
585 586
			break;
		case 'e':
587
			tempstr = strdup(optarg);
588
			sscanf(tempstr, "%x", &exclude_end_position);
589
			break;
590 591 592
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
593
			tempstr2 = strtok(NULL, ":");
594
			if (tempstr2) {
595 596
				lb_vendor = tempstr;
				lb_part = tempstr2;
597
			} else {
598 599
				lb_vendor = NULL;
				lb_part = tempstr;
600 601 602
			}
			break;
		case 'f':
603
			force = 1;
604 605
			break;
		case 'l':
606
			tempstr = strdup(optarg);
607 608
			if (read_romlayout(tempstr))
				exit(1);
609 610
			break;
		case 'i':
611
			tempstr = strdup(optarg);
612 613
			find_romentry(tempstr);
			break;
614
		case 'L':
Uwe Hermann's avatar
Uwe Hermann committed
615
			list_supported = 1;
616
			break;
617 618 619
		case 'p':
			if (strncmp(optarg, "internal", 8) == 0) {
				programmer = PROGRAMMER_INTERNAL;
620 621
			} else if (strncmp(optarg, "dummy", 5) == 0) {
				programmer = PROGRAMMER_DUMMY;
622 623
				if (optarg[5] == '=')
					dummytype = strdup(optarg + 6);
624 625
			} else if (strncmp(optarg, "nic3com", 7) == 0) {
				programmer = PROGRAMMER_NIC3COM;
626
				if (optarg[7] == '=')
627
					pcidev_bdf = strdup(optarg + 8);
628 629 630 631
			} else if (strncmp(optarg, "satasii", 7) == 0) {
				programmer = PROGRAMMER_SATASII;
				if (optarg[7] == '=')
					pcidev_bdf = strdup(optarg + 8);
632 633
			} else if (strncmp(optarg, "it87spi", 7) == 0) {
				programmer = PROGRAMMER_IT87SPI;
634 635 636 637 638
			} else {
				printf("Error: Unknown programmer.\n");
				exit(1);
			}
			break;
639
		case 'R':
640
			/* print_version() is always called during startup. */
641 642
			exit(0);
			break;
643
		case 'h':
644 645 646 647 648
		default:
			usage(argv[0]);
			break;
		}
	}
649

Uwe Hermann's avatar
Uwe Hermann committed
650 651 652 653 654 655 656
	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);
657
		print_supported_pcidevs(satas_sii);
Uwe Hermann's avatar
Uwe Hermann committed
658 659 660
		exit(0);
	}

661
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
662
		printf("Error: -r and -w are mutually exclusive.\n");
663 664
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
665

666 667
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
668

669
	ret = programmer_init();
670

671
	myusec_calibrate_delay();
672

Claus Gindhart's avatar
Claus Gindhart committed
673
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
674 675
		flashes[i] =
		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
Claus Gindhart's avatar
Claus Gindhart committed
676 677 678 679 680 681 682 683 684 685 686 687
		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]) {
688
		printf("No EEPROM/flash device found.\n");
Peter Stuge's avatar
Peter Stuge committed
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
		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);
			}
704
			return read_flash(flashes[0], filename, exclude_start_position, exclude_end_position);
Peter Stuge's avatar
Peter Stuge committed
705
		}
706
		// FIXME: flash writes stay enabled!
707 708
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
709

Claus Gindhart's avatar
Claus Gindhart committed
710 711
	flash = flashes[0];

712 713 714 715 716 717 718 719 720 721 722 723 724
	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");
725 726 727 728 729
		}
		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))) {
730
			printf("This flash part has status UNTESTED for operations:");
731
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
732
				printf(" PROBE");
733
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
734
				printf(" READ");
735
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
736
				printf(" ERASE");
737
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
738 739 740
				printf(" WRITE");
			printf("\n");
		}
741 742 743 744 745 746
		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");
747
	}
748

749 750 751 752 753 754
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

755
	if (!filename && !erase_it) {
756 757 758
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
759 760
	}

761 762
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
763

764
	if (erase_it) {
765
		if (erase_flash(flash))
766
			return 1;
767
	} else if (read_it) {
768
		if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
769
			return 1;
770
	} else {
771 772
		struct stat image_stat;

773
		if ((image = fopen(filename, "r")) == NULL) {
774 775 776
			perror(filename);
			exit(1);
		}
777 778 779 780
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
781
		if (image_stat.st_size != flash->total_size * 1024) {
Uwe Hermann's avatar
Uwe Hermann committed
782
			fprintf(stderr, "Error: Image size doesn't match\n");
783 784 785
			exit(1);
		}

786
		numbytes = fread(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
787
		show_id(buf, size, force);
788
		fclose(image);
789 790 791 792
		if (numbytes != size) {
			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
			return 1;
		}
793
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
794

795 796 797 798 799 800
	/* 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
	 */
801

802
	// ////////////////////////////////////////////////////////////
803
	if (exclude_end_position - exclude_start_position > 0)
804 805 806
		chip_readn(buf + exclude_start_position,
			   flash->virtual_memory + exclude_start_position,
			   exclude_end_position - exclude_start_position);
807

808 809
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
810 811
		exclude_start_page++;
	}
812
	exclude_end_page = exclude_end_position / flash->page_size;
813 814 815 816
	// ////////////////////////////////////////////////////////////

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

820
	// ////////////////////////////////////////////////////////////
821

822 823 824 825 826
	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
827
		ret |= flash->write(flash, buf);
828
	}
829

830
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
831
		ret |= verify_flash(flash, buf);
832

833 834
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
835
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
836
}