flashrom.c 21 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 46 47 48
		.chip_readb		= internal_chip_readb,
		.chip_readw		= internal_chip_readw,
		.chip_readl		= internal_chip_readl,
		.chip_writeb		= internal_chip_writeb,
		.chip_writew		= internal_chip_writew,
		.chip_writel		= internal_chip_writel,
49 50
	},

51
	{
52 53
		.init			= dummy_init,
		.shutdown		= dummy_shutdown,
54 55
		.map_flash_region	= dummy_map,
		.unmap_flash_region	= dummy_unmap,
56 57 58 59 60 61
		.chip_readb		= dummy_chip_readb,
		.chip_readw		= dummy_chip_readw,
		.chip_readl		= dummy_chip_readl,
		.chip_writeb		= dummy_chip_writeb,
		.chip_writew		= dummy_chip_writew,
		.chip_writel		= dummy_chip_writel,
62 63
	},

64 65 66
	{
		.init			= nic3com_init,
		.shutdown		= nic3com_shutdown,
67 68
		.map_flash_region	= fallback_map,
		.unmap_flash_region	= fallback_unmap,
69
		.chip_readb		= nic3com_chip_readb,
70 71
		.chip_readw		= fallback_chip_readw,
		.chip_readl		= fallback_chip_readl,
72
		.chip_writeb		= nic3com_chip_writeb,
73 74
		.chip_writew		= fallback_chip_writew,
		.chip_writel		= fallback_chip_writel,
75 76
	},

77 78 79
	{
		.init			= satasii_init,
		.shutdown		= satasii_shutdown,
80 81
		.map_flash_region	= fallback_map,
		.unmap_flash_region	= fallback_unmap,
82 83 84 85 86 87 88 89
		.chip_readb		= satasii_chip_readb,
		.chip_readw		= fallback_chip_readw,
		.chip_readl		= fallback_chip_readl,
		.chip_writeb		= satasii_chip_writeb,
		.chip_writew		= fallback_chip_writew,
		.chip_writel		= fallback_chip_writel,
	},

90 91
	{},
};
92

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 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
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);
}

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);
}

145
void map_flash_registers(struct flashchip *flash)
146 147
{
	size_t size = flash->total_size * 1024;
148
	/* Flash registers live 4 MByte below the flash. */
149
	flash->virtual_registers = (chipaddr)programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
150 151
}

152 153 154 155 156 157 158 159 160 161 162 163
int read_memmapped(struct flashchip *flash, uint8_t *buf)
{
	int i;

	/* We could do a memcpy as optimization if the flash is onboard */
	//memcpy(buf, (const char *)flash->virtual_memory, flash->total_size * 1024);
	for (i = 0; i < flash->total_size * 1024; i++)
		buf[i] = chip_readb(flash->virtual_memory + i);
		
	return 0;
}

164
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
165
{
166
	struct flashchip *flash;
167
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
168

169
	for (flash = first_flash; flash && flash->name; flash++) {
170
		if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0)
171
			continue;
172 173
		printf_debug("Probing for %s %s, %d KB: ",
			     flash->vendor, flash->name, flash->total_size);
Peter Stuge's avatar
Peter Stuge committed
174
		if (!flash->probe && !force) {
175 176 177
			printf_debug("failed! flashrom has no probe function for this flash chip.\n");
			continue;
		}
Stefan Reinauer's avatar
Stefan Reinauer committed
178

179
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
180

181
		base = flashbase ? flashbase : (0xffffffff - size + 1);
182
		flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size);
183

184 185 186
		if (force)
			break;

187 188 189
		if (flash->probe(flash) != 1)
			goto notfound;

190 191
		if (first_flash == flashchips
		    || flash->model_id != GENERIC_DEVICE_ID)
192
			break;
Stefan Reinauer's avatar
Stefan Reinauer committed
193

194
notfound:
195
		programmer_unmap_flash_region((void *)flash->virtual_memory, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
196
	}
Uwe Hermann's avatar
Uwe Hermann committed
197

198 199 200 201
	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
202
	       flash->vendor, flash->name, flash->total_size, base);
203
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
204 205
}

Stefan Reinauer's avatar
Stefan Reinauer committed
206
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
207
{
Stefan Reinauer's avatar
Stefan Reinauer committed
208
	int idx;
209
	int total_size = flash->total_size * 1024;
210
	uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
211 212 213 214 215
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
216
		flash->read(flash, buf2);
217

218
	printf("Verifying flash... ");
219 220 221 222

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

Stefan Reinauer's avatar
Stefan Reinauer committed
223
	for (idx = 0; idx < total_size; idx++) {
224
		if (verbose && ((idx & 0xfff) == 0xfff))
Stefan Reinauer's avatar
Stefan Reinauer committed
225 226
			printf("0x%08x", idx);

227
		if (*(buf2 + idx) != *(buf + idx)) {
228 229 230 231 232
			if (verbose)
				printf("0x%08x FAILED!", idx);
			else
				printf("FAILED at 0x%08x!", idx);
			printf("  Expected=0x%02x, Read=0x%02x\n",
233
			       *(buf + idx), *(buf2 + idx));
Stefan Reinauer's avatar
Stefan Reinauer committed
234
			return 1;
235
		}
236 237

		if (verbose && ((idx & 0xfff) == 0xfff))
238
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
239
	}
240
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
241
		printf("\b\b\b\b\b\b\b\b\b\b ");
242

243
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
244

Stefan Reinauer's avatar
Stefan Reinauer committed
245
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
246 247
}

248 249 250 251 252 253 254 255 256 257 258
int read_flash(struct flashchip *flash, char *filename, unsigned int exclude_start_position, unsigned int exclude_end_position)
{
	unsigned long numbytes;
	FILE *image;
	unsigned long size = flash->total_size * 1024;
	unsigned char *buf = calloc(size, sizeof(char));
	if ((image = fopen(filename, "w")) == NULL) {
		perror(filename);
		exit(1);
	}
	printf("Reading flash... ");
259 260 261 262 263
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
		flash->read(flash, buf);

	if (exclude_end_position - exclude_start_position > 0)
		memset(buf + exclude_start_position, 0,
		       exclude_end_position - exclude_start_position);

	numbytes = fwrite(buf, 1, size, image);
	fclose(image);
	printf("%s.\n", numbytes == size ? "done" : "FAILED");
	if (numbytes != size)
		return 1;
	return 0;
}

int erase_flash(struct flashchip *flash)
{
	uint32_t erasedbytes;
	unsigned long size = flash->total_size * 1024;
	unsigned char *buf = calloc(size, sizeof(char));
	printf("Erasing flash chip... ");
	if (NULL == flash->erase) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n");
		return 1;
	}
289 290
	flash->erase(flash);

291 292 293 294 295
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
296
		flash->read(flash, buf);
297

298 299 300 301 302 303 304 305 306 307 308
	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
309
#ifndef MAX
310
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Uwe Hermann's avatar
Uwe Hermann committed
311
#endif
312 313
#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)

314 315
void print_supported_chips(void)
{
316 317
	int okcol = 0, pos = 0;
	struct flashchip *f;
318

319 320 321 322 323 324
	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;
325

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	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");
	}
366 367
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
368 369
void usage(const char *name)
{
370 371
	printf("usage: %s [-EVfLhR] [-r file] [-w file] [-v file] [-c chipname] [-s addr]\n"
	       "       [-e addr] [-m [vendor:]part] [-l file] [-i image] [-p programmer] [file]",
372
	       name);
373 374 375 376

	printf("\n\nPlease note that the command line interface for flashrom will "
		"change before flashrom 1.0.\nDo not use flashrom in scripts or "
		"other automated tools without checking that your flashrom\n"
377
		"version won't interpret them in a totally different way.\n\n");
378

379
	printf
380 381 382 383 384 385 386 387 388 389 390 391
	    ("   -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"
392
	     "   -L | --list-supported:            print supported devices\n"
393
	     "   -p | --programmer <name>:         specify the programmer device\n"
394
	     "                                     (internal, dummy, nic3com, satasii)\n"
395
	     "   -h | --help:                      print this help text\n"
396
	     "   -R | --version:                   print the version (release)\n"
397
	     "\nIf no file is specified, then all that happens"
398
	     " is that flash info is dumped.\n\n");
399
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
400 401
}

402 403
void print_version(void)
{
Carl-Daniel Hailfinger's avatar
Carl-Daniel Hailfinger committed
404
	printf("flashrom v%s\n", FLASHROM_VERSION);
405 406
}

407
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
408
{
409
	uint8_t *buf;
410
	unsigned long size, numbytes;
411
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
412 413
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
414
	int opt;
415
	int option_index = 0;
Peter Stuge's avatar
Peter Stuge committed
416
	int force = 0;
417
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Uwe Hermann's avatar
Uwe Hermann committed
418
	int list_supported = 0;
Claus Gindhart's avatar
Claus Gindhart committed
419
	int ret = 0, i;
420

421 422 423 424 425 426 427 428 429 430 431 432 433
	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'},
434
		{"list-supported", 0, 0, 'L'},
435
		{"programmer", 1, 0, 'p'},
436
		{"help", 0, 0, 'h'},
437
		{"version", 0, 0, 'R'},
438
		{0, 0, 0, 0}
439
	};
440

441
	char *filename = NULL;
442

443 444
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
445

446 447
	print_version();

448 449 450
	if (argc > 1) {
		/* Yes, print them. */
		int i;
451
		printf_debug("The arguments are:\n");
452
		for (i = 1; i < argc; ++i)
453
			printf_debug("%s\n", argv[i]);
454 455
	}

456
	setbuf(stdout, NULL);
457
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:p:Lh",
458
				  long_options, &option_index)) != EOF) {
459 460 461 462 463 464 465 466 467 468 469 470 471
		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
472 473 474
		case 'V':
			verbose = 1;
			break;
475 476 477
		case 'E':
			erase_it = 1;
			break;
478 479
		case 's':
			tempstr = strdup(optarg);
480
			sscanf(tempstr, "%x", &exclude_start_position);
481 482
			break;
		case 'e':
483
			tempstr = strdup(optarg);
484
			sscanf(tempstr, "%x", &exclude_end_position);
485
			break;
486 487 488
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
489
			tempstr2 = strtok(NULL, ":");
490
			if (tempstr2) {
491 492
				lb_vendor = tempstr;
				lb_part = tempstr2;
493
			} else {
494 495
				lb_vendor = NULL;
				lb_part = tempstr;
496 497 498
			}
			break;
		case 'f':
499
			force = 1;
500 501
			break;
		case 'l':
502
			tempstr = strdup(optarg);
503 504
			if (read_romlayout(tempstr))
				exit(1);
505 506
			break;
		case 'i':
507
			tempstr = strdup(optarg);
508 509
			find_romentry(tempstr);
			break;
510
		case 'L':
Uwe Hermann's avatar
Uwe Hermann committed
511
			list_supported = 1;
512
			break;
513 514 515
		case 'p':
			if (strncmp(optarg, "internal", 8) == 0) {
				programmer = PROGRAMMER_INTERNAL;
516 517
			} else if (strncmp(optarg, "dummy", 5) == 0) {
				programmer = PROGRAMMER_DUMMY;
518 519
			} else if (strncmp(optarg, "nic3com", 7) == 0) {
				programmer = PROGRAMMER_NIC3COM;
520
				if (optarg[7] == '=')
521
					pcidev_bdf = strdup(optarg + 8);
522 523 524 525
			} else if (strncmp(optarg, "satasii", 7) == 0) {
				programmer = PROGRAMMER_SATASII;
				if (optarg[7] == '=')
					pcidev_bdf = strdup(optarg + 8);
526 527 528 529 530
			} else {
				printf("Error: Unknown programmer.\n");
				exit(1);
			}
			break;
531
		case 'R':
532
			/* print_version() is always called during startup. */
533 534
			exit(0);
			break;
535
		case 'h':
536 537 538 539 540
		default:
			usage(argv[0]);
			break;
		}
	}
541

Uwe Hermann's avatar
Uwe Hermann committed
542 543 544 545 546 547 548
	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);
549
		print_supported_pcidevs(satas_sii);
Uwe Hermann's avatar
Uwe Hermann committed
550 551 552
		exit(0);
	}

553
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
554
		printf("Error: -r and -w are mutually exclusive.\n");
555 556
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
557

558 559
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
560

561
	ret = programmer_init();
562

563
	myusec_calibrate_delay();
564

Claus Gindhart's avatar
Claus Gindhart committed
565
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
566 567
		flashes[i] =
		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
Claus Gindhart's avatar
Claus Gindhart committed
568 569 570 571 572 573 574 575 576 577 578 579
		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]) {
580
		printf("No EEPROM/flash device found.\n");
Peter Stuge's avatar
Peter Stuge committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
		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);
			}
596 597 598 599
			if (!filename) {
				printf("Error: No filename specified.\n");
				exit(1);
			}
Peter Stuge's avatar
Peter Stuge committed
600 601 602 603 604 605 606
			size = flashes[0]->total_size * 1024;
			buf = (uint8_t *) calloc(size, sizeof(char));

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
607
			printf("Force reading flash... ");
608 609 610 611 612
			if (!flashes[0]->read) {
				printf("FAILED!\n");
				fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
				return 1;
			} else
Peter Stuge's avatar
Peter Stuge committed
613 614 615 616
				flashes[0]->read(flashes[0], buf);

			if (exclude_end_position - exclude_start_position > 0)
				memset(buf + exclude_start_position, 0,
617 618
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
619

620
			numbytes = fwrite(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
621
			fclose(image);
622
			printf("%s.\n", numbytes == size ? "done" : "FAILED");
Peter Stuge's avatar
Peter Stuge committed
623
			free(buf);
624
			return numbytes != size;
Peter Stuge's avatar
Peter Stuge committed
625
		}
626
		// FIXME: flash writes stay enabled!
627 628
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
629

Claus Gindhart's avatar
Claus Gindhart committed
630 631
	flash = flashes[0];

632 633 634 635 636 637 638 639 640 641 642 643 644
	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");
645 646 647 648 649
		}
		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))) {
650
			printf("This flash part has status UNTESTED for operations:");
651
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
652
				printf(" PROBE");
653
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
654
				printf(" READ");
655
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
656
				printf(" ERASE");
657
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
658 659 660 661 662 663 664 665
				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");
	}
666

667 668 669 670 671 672
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

673
	if (!filename && !erase_it) {
674 675 676
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
677 678
	}

679 680
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
681

682
	if (erase_it) {
683
		if (erase_flash(flash))
684
			return 1;
685
	} else if (read_it) {
686
		if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
687
			return 1;
688
	} else {
689 690
		struct stat image_stat;

691
		if ((image = fopen(filename, "r")) == NULL) {
692 693 694
			perror(filename);
			exit(1);
		}
695 696 697 698
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
699
		if (image_stat.st_size != flash->total_size * 1024) {
Uwe Hermann's avatar
Uwe Hermann committed
700
			fprintf(stderr, "Error: Image size doesn't match\n");
701 702 703
			exit(1);
		}

704
		numbytes = fread(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
705
		show_id(buf, size, force);
706
		fclose(image);
707 708 709 710
		if (numbytes != size) {
			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
			return 1;
		}
711
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
712

713 714 715 716 717 718
	/* 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
	 */
719

720
	// ////////////////////////////////////////////////////////////
721 722 723
	/* FIXME: This memcpy will not work for SPI nor external flashers.
	 * Convert to chip_readb.
	 */
724
	if (exclude_end_position - exclude_start_position > 0)
725
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
726 727
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
728
		       exclude_end_position - exclude_start_position);
729

730 731
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
732 733
		exclude_start_page++;
	}
734
	exclude_end_page = exclude_end_position / flash->page_size;
735 736 737 738
	// ////////////////////////////////////////////////////////////

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

741
	// ////////////////////////////////////////////////////////////
742

743 744 745 746 747
	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
748
		ret |= flash->write(flash, buf);
749
	}
750

751
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
752
		ret |= verify_flash(flash, buf);
753

754 755
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
756
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
757
}