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

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

const struct programmer_entry programmer_table[] = {
	{
41 42
		.init			= internal_init,
		.shutdown		= internal_shutdown,
43 44
		.map_flash_region	= physmap,
		.unmap_flash_region	= physunmap,
45 46 47 48 49 50
		.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,
51 52
	},

53
	{
54 55
		.init			= dummy_init,
		.shutdown		= dummy_shutdown,
56 57
		.map_flash_region	= dummy_map,
		.unmap_flash_region	= dummy_unmap,
58 59 60 61 62 63
		.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,
64 65
	},

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

79 80
	{},
};
81

82
void map_flash_registers(struct flashchip *flash)
83 84
{
	size_t size = flash->total_size * 1024;
85
	/* Flash registers live 4 MByte below the flash. */
86
	flash->virtual_registers = programmer_map_flash_region("flash chip registers", (0xFFFFFFFF - 0x400000 - size + 1), size);
87 88
}

89 90 91 92 93 94 95 96 97 98 99 100
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;
}

101
struct flashchip *probe_flash(struct flashchip *first_flash, int force)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
102
{
103
	struct flashchip *flash;
104
	unsigned long base = 0, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
105

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

116
		size = flash->total_size * 1024;
Stefan Reinauer's avatar
Stefan Reinauer committed
117

118
		base = flashbase ? flashbase : (0xffffffff - size + 1);
119
		flash->virtual_memory = programmer_map_flash_region("flash chip", base, size);
120

121 122 123
		if (force)
			break;

124 125 126
		if (flash->probe(flash) != 1)
			goto notfound;

127 128
		if (first_flash == flashchips
		    || flash->model_id != GENERIC_DEVICE_ID)
129
			break;
Stefan Reinauer's avatar
Stefan Reinauer committed
130

131
notfound:
132 133
		/* The intermediate cast to unsigned long works around a gcc warning bug. */
		programmer_unmap_flash_region((void *)(unsigned long)flash->virtual_memory, size);
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
134
	}
Uwe Hermann's avatar
Uwe Hermann committed
135

136 137 138 139
	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
140
	       flash->vendor, flash->name, flash->total_size, base);
141
	return flash;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
142 143
}

Stefan Reinauer's avatar
Stefan Reinauer committed
144
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
145
{
Stefan Reinauer's avatar
Stefan Reinauer committed
146
	int idx;
147
	int total_size = flash->total_size * 1024;
148
	uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
149 150 151 152 153
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
154
		flash->read(flash, buf2);
155

156
	printf("Verifying flash... ");
157 158 159 160

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

Stefan Reinauer's avatar
Stefan Reinauer committed
161
	for (idx = 0; idx < total_size; idx++) {
162
		if (verbose && ((idx & 0xfff) == 0xfff))
Stefan Reinauer's avatar
Stefan Reinauer committed
163 164
			printf("0x%08x", idx);

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

		if (verbose && ((idx & 0xfff) == 0xfff))
176
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
177
	}
178
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
179
		printf("\b\b\b\b\b\b\b\b\b\b ");
180

181
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
182

Stefan Reinauer's avatar
Stefan Reinauer committed
183
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
184 185
}

186 187 188 189 190 191 192 193 194 195 196
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... ");
197 198 199 200 201
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
		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;
	}
227 228
	flash->erase(flash);

229 230 231 232 233
	if (!flash->read) {
		printf("FAILED!\n");
		fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n");
		return 1;
	} else
234
		flash->read(flash, buf);
235

236 237 238 239 240 241 242 243 244 245 246
	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
247
#ifndef MAX
248
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Uwe Hermann's avatar
Uwe Hermann committed
249
#endif
250 251
#define POS_PRINT(x) do { pos += strlen(x); printf(x); } while (0)

252 253
void print_supported_chips(void)
{
254 255
	int okcol = 0, pos = 0;
	struct flashchip *f;
256

257 258 259 260 261 262
	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;
263

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 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	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");
	}
304 305
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
306 307
void usage(const char *name)
{
308 309
	printf("usage: %s [-rwvEVfLhR] [-c chipname] [-s exclude_start]\n",
	       name);
310
	printf("       [-e exclude_end] [-m [vendor:]part] [-l file.layout] [-i imagename] [file]\n");
311 312 313 314
	printf("Please  note that the command line interface for flashrom will "
		"change before flashrom 1.0. Do not use flashrom in scripts or "
		"other automated tools without checking that your flashrom "
		"version won't interpret them in a totally different way.\n\n");
315
	printf
316 317 318 319 320 321 322 323 324 325 326 327
	    ("   -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"
328
	     "   -L | --list-supported:            print supported devices\n"
329
	     "   -p | --programmer <name>:         specify the programmer device\n"
330
	     "   -h | --help:                      print this help text\n"
331
	     "   -R | --version:                   print the version (release)\n"
332
	     "\n" " If no file is specified, then all that happens"
333
	     " is that flash info is dumped.\n\n");
334
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
335 336
}

337 338
void print_version(void)
{
Carl-Daniel Hailfinger's avatar
Carl-Daniel Hailfinger committed
339
	printf("flashrom v%s\n", FLASHROM_VERSION);
340 341
}

342
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
343
{
344
	uint8_t *buf;
345
	unsigned long size, numbytes;
346
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
347 348
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
349
	int opt;
350
	int option_index = 0;
Peter Stuge's avatar
Peter Stuge committed
351
	int force = 0;
352
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Claus Gindhart's avatar
Claus Gindhart committed
353
	int ret = 0, i;
354

355 356 357 358 359 360 361 362 363 364 365 366 367
	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'},
368
		{"list-supported", 0, 0, 'L'},
369
		{"programmer", 1, 0, 'p'},
370
		{"help", 0, 0, 'h'},
371
		{"version", 0, 0, 'R'},
372
		{0, 0, 0, 0}
373
	};
374

375
	char *filename = NULL;
376

377 378
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
379

380 381
	print_version();

382 383 384
	if (argc > 1) {
		/* Yes, print them. */
		int i;
385
		printf_debug("The arguments are:\n");
386
		for (i = 1; i < argc; ++i)
387
			printf_debug("%s\n", argv[i]);
388 389
	}

390
	setbuf(stdout, NULL);
391
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:p:Lh",
392
				  long_options, &option_index)) != EOF) {
393 394 395 396 397 398 399 400 401 402 403 404 405
		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
406 407 408
		case 'V':
			verbose = 1;
			break;
409 410 411
		case 'E':
			erase_it = 1;
			break;
412 413
		case 's':
			tempstr = strdup(optarg);
414
			sscanf(tempstr, "%x", &exclude_start_position);
415 416
			break;
		case 'e':
417
			tempstr = strdup(optarg);
418
			sscanf(tempstr, "%x", &exclude_end_position);
419
			break;
420 421 422
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
423
			tempstr2 = strtok(NULL, ":");
424
			if (tempstr2) {
425 426
				lb_vendor = tempstr;
				lb_part = tempstr2;
427
			} else {
428 429
				lb_vendor = NULL;
				lb_part = tempstr;
430 431 432
			}
			break;
		case 'f':
433
			force = 1;
434 435
			break;
		case 'l':
436
			tempstr = strdup(optarg);
437 438
			if (read_romlayout(tempstr))
				exit(1);
439 440
			break;
		case 'i':
441
			tempstr = strdup(optarg);
442 443
			find_romentry(tempstr);
			break;
444 445 446 447
		case 'L':
			print_supported_chips();
			print_supported_chipsets();
			print_supported_boards();
448 449 450
			printf("\nSupported PCI devices flashrom can use "
			       "as programmer:\n\n");
			print_supported_pcidevs(nics_3com);
451 452
			exit(0);
			break;
453 454 455
		case 'p':
			if (strncmp(optarg, "internal", 8) == 0) {
				programmer = PROGRAMMER_INTERNAL;
456 457
			} else if (strncmp(optarg, "dummy", 5) == 0) {
				programmer = PROGRAMMER_DUMMY;
458 459
			} else if (strncmp(optarg, "nic3com", 7) == 0) {
				programmer = PROGRAMMER_NIC3COM;
460
				if (optarg[7] == '=')
461
					pcidev_bdf = strdup(optarg + 8);
462 463 464 465 466
			} else {
				printf("Error: Unknown programmer.\n");
				exit(1);
			}
			break;
467
		case 'R':
468
			/* print_version() is always called during startup. */
469 470
			exit(0);
			break;
471
		case 'h':
472 473 474 475 476
		default:
			usage(argv[0]);
			break;
		}
	}
477

478
	if (read_it && write_it) {
Uwe Hermann's avatar
Uwe Hermann committed
479
		printf("Error: -r and -w are mutually exclusive.\n");
480 481
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
482

483 484
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
485

486
	ret = programmer_init();
487

488
	myusec_calibrate_delay();
489

Claus Gindhart's avatar
Claus Gindhart committed
490
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
491 492
		flashes[i] =
		    probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0);
Claus Gindhart's avatar
Claus Gindhart committed
493 494 495 496 497 498 499 500 501 502 503 504
		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]) {
505
		printf("No EEPROM/flash device found.\n");
Peter Stuge's avatar
Peter Stuge committed
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
		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);
			}
521 522 523 524
			if (!filename) {
				printf("Error: No filename specified.\n");
				exit(1);
			}
Peter Stuge's avatar
Peter Stuge committed
525 526 527 528 529 530 531
			size = flashes[0]->total_size * 1024;
			buf = (uint8_t *) calloc(size, sizeof(char));

			if ((image = fopen(filename, "w")) == NULL) {
				perror(filename);
				exit(1);
			}
532
			printf("Force reading flash... ");
533 534 535 536 537
			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
538 539 540 541
				flashes[0]->read(flashes[0], buf);

			if (exclude_end_position - exclude_start_position > 0)
				memset(buf + exclude_start_position, 0,
542 543
				       exclude_end_position -
				       exclude_start_position);
Peter Stuge's avatar
Peter Stuge committed
544

545
			numbytes = fwrite(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
546
			fclose(image);
547
			printf("%s.\n", numbytes == size ? "done" : "FAILED");
Peter Stuge's avatar
Peter Stuge committed
548
			free(buf);
549
			return numbytes != size;
Peter Stuge's avatar
Peter Stuge committed
550
		}
551
		// FIXME: flash writes stay enabled!
552 553
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
554

Claus Gindhart's avatar
Claus Gindhart committed
555 556
	flash = flashes[0];

557 558 559 560 561 562 563 564 565 566 567 568 569
	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");
570 571 572 573 574
		}
		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))) {
575
			printf("This flash part has status UNTESTED for operations:");
576
			if (!(flash->tested & TEST_BAD_PROBE) && !(flash->tested & TEST_OK_PROBE))
577
				printf(" PROBE");
578
			if (!(flash->tested & TEST_BAD_READ) && !(flash->tested & TEST_OK_READ))
579
				printf(" READ");
580
			if (!(flash->tested & TEST_BAD_ERASE) && !(flash->tested & TEST_OK_ERASE))
581
				printf(" ERASE");
582
			if (!(flash->tested & TEST_BAD_WRITE) && !(flash->tested & TEST_OK_WRITE))
583 584 585 586 587 588 589 590
				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");
	}
591

592 593 594 595 596 597
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

598
	if (!filename && !erase_it) {
599 600 601
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
602 603
	}

604 605
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
606

607
	if (erase_it) {
608
		if (erase_flash(flash))
609
			return 1;
610
	} else if (read_it) {
611
		if (read_flash(flash, filename, exclude_start_position, exclude_end_position))
612
			return 1;
613
	} else {
614 615
		struct stat image_stat;

616
		if ((image = fopen(filename, "r")) == NULL) {
617 618 619
			perror(filename);
			exit(1);
		}
620 621 622 623
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
624
		if (image_stat.st_size != flash->total_size * 1024) {
Uwe Hermann's avatar
Uwe Hermann committed
625
			fprintf(stderr, "Error: Image size doesn't match\n");
626 627 628
			exit(1);
		}

629
		numbytes = fread(buf, 1, size, image);
Peter Stuge's avatar
Peter Stuge committed
630
		show_id(buf, size, force);
631
		fclose(image);
632 633 634 635
		if (numbytes != size) {
			fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size);
			return 1;
		}
636
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
637

638 639 640 641 642 643
	/* 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
	 */
644

645
	// ////////////////////////////////////////////////////////////
646 647 648
	/* FIXME: This memcpy will not work for SPI nor external flashers.
	 * Convert to chip_readb.
	 */
649
	if (exclude_end_position - exclude_start_position > 0)
650
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
651 652
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
653
		       exclude_end_position - exclude_start_position);
654

655 656
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
657 658
		exclude_start_page++;
	}
659
	exclude_end_page = exclude_end_position / flash->page_size;
660 661 662 663
	// ////////////////////////////////////////////////////////////

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

666
	// ////////////////////////////////////////////////////////////
667

668 669 670 671 672
	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
673
		ret |= flash->write(flash, buf);
674
	}
675

676
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
677
		ret |= verify_flash(flash, buf);
678

679 680
	programmer_shutdown();

Stefan Reinauer's avatar
Stefan Reinauer committed
681
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
682
}