flashrom.c 14.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 6
 * Copyright (C) 2000 Silicon Integrated System Corporation
 * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
 * Copyright (C) 2005-2007 coresystems GmbH 
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
7
 *
8 9 10 11
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
12
 *
13 14 15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
17
 *
18 19 20
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
21 22 23 24 25
 */

#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
26 27
#include <sys/types.h>
#include <sys/stat.h>
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
28 29
#include <unistd.h>
#include <stdio.h>
Ronald G. Minnich's avatar
Ronald G. Minnich committed
30
#include <string.h>
Ronald G. Minnich's avatar
Ronald G. Minnich committed
31
#include <stdlib.h>
32
#include <getopt.h>
33 34 35 36 37 38 39 40
#include <pci/pci.h>
/* for iopl */
#if defined (__sun) && (defined(__i386) || defined(__amd64))
#include <strings.h>
#include <sys/sysi86.h>
#include <sys/psw.h>
#include <asm/sunddi.h>
#endif
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
41 42
#include "flash.h"

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

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

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

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

62
	return NULL;
63 64
}

65 66
struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
			      uint16_t card_vendor, uint16_t card_device)
67
{
68 69 70 71 72 73 74 75 76 77 78 79 80
	struct pci_dev *temp;
	struct pci_filter filter;

	pci_filter_init(NULL, &filter);
	filter.vendor = vendor;
	filter.device = device;

	for (temp = pacc->devices; temp; temp = temp->next)
		if (pci_filter_match(&filter, temp)) {
			if ((card_vendor == pci_read_word(temp, 0x2C)) &&
			    (card_device == pci_read_word(temp, 0x2E)))
				return temp;
		}
81

82
	return NULL;
83 84
}

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

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

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

	return 0;
}

102
struct flashchip *probe_flash(struct flashchip *flash)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
103
{
104
	volatile uint8_t *bios;
Stefan Reinauer's avatar
Stefan Reinauer committed
105
	unsigned long flash_baseaddr, size;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
106

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

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

#ifdef TS5300
		// FIXME: Wrong place for this decision
Stefan Reinauer's avatar
Stefan Reinauer committed
124
		// FIXME: This should be autodetected. It is trivial.
Stefan Reinauer's avatar
Stefan Reinauer committed
125 126 127 128 129 130
		flash_baseaddr = 0x9400000;
#else
		flash_baseaddr = (0xffffffff - size + 1);
#endif

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

136
		if (getpagesize() > size) {
137 138 139 140 141
			/*
			 * if a flash size of 0 is mapped, we map a single page
			 * so we can probe in that area whether we know the
			 * vendor at least.
			 */
142 143
			size = getpagesize();
		}
144

145
		bios = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
146
			    fd_mem, (off_t) flash_baseaddr);
147
		if (bios == MAP_FAILED) {
Stefan Reinauer's avatar
Stefan Reinauer committed
148
			perror("Can't mmap memory using " MEM_DEV);
149 150
			exit(1);
		}
151
		flash->virtual_memory = bios;
152 153

		if (flash->probe(flash) == 1) {
154
			printf("%s found at physical address 0x%lx.\n",
Stefan Reinauer's avatar
Stefan Reinauer committed
155
			       flash->name, flash_baseaddr);
156 157
			return flash;
		}
158
		munmap((void *)bios, size);
Stefan Reinauer's avatar
Stefan Reinauer committed
159

160
		flash++;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
161
	}
Uwe Hermann's avatar
Uwe Hermann committed
162

163
	return NULL;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
164 165
}

Stefan Reinauer's avatar
Stefan Reinauer committed
166
int verify_flash(struct flashchip *flash, uint8_t *buf)
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
167
{
Stefan Reinauer's avatar
Stefan Reinauer committed
168
	int idx;
169
	int total_size = flash->total_size * 1024;
170 171 172 173 174
	uint8_t *buf2 = (uint8_t *) calloc(total_size, sizeof(char));
	if (flash->read == NULL)
		memcpy(buf2, (const char *)flash->virtual_memory, total_size);
	else
		flash->read(flash, buf2);
175

176
	printf("Verifying flash... ");
177 178 179 180

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

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

185
		if (*(buf2 + idx) != *(buf + idx)) {
Stefan Reinauer's avatar
Stefan Reinauer committed
186 187 188
			if (verbose) {
				printf("0x%08x ", idx);
			}
189
			printf("FAILED!\n");
Stefan Reinauer's avatar
Stefan Reinauer committed
190
			return 1;
191
		}
192 193

		if (verbose && ((idx & 0xfff) == 0xfff))
194
			printf("\b\b\b\b\b\b\b\b\b\b");
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
195
	}
196
	if (verbose)
Stefan Reinauer's avatar
Stefan Reinauer committed
197
		printf("\b\b\b\b\b\b\b\b\b\b ");
198

199
	printf("VERIFIED.          \n");
Uwe Hermann's avatar
Uwe Hermann committed
200

Stefan Reinauer's avatar
Stefan Reinauer committed
201
	return 0;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
202 203
}

204 205 206 207 208 209 210
void print_supported_chips(void)
{
	int i;

	printf("Supported ROM chips:\n\n");

	for (i = 0; flashchips[i].name != NULL; i++)
211
		printf("%s %s\n", flashchips[i].vendor, flashchips[i].name);
212 213
}

Ronald G. Minnich's avatar
Ronald G. Minnich committed
214 215
void usage(const char *name)
{
216
	printf("usage: %s [-rwvEVfLhR] [-c chipname] [-s exclude_start]\n", name);
217
	printf("       [-e exclude_end] [-m [vendor:]part] [-l file.layout] [-i imagename] [file]\n");
218
	printf
219 220 221 222 223 224 225 226 227 228 229 230
	    ("   -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"
231 232
	     "   -L | --list-supported:            print supported devices\n"
	     "   -h | --help:                      print this help text\n"
233
	     "   -R | --version:                   print the version (release)\n"
234
	     "\n" " If no file is specified, then all that happens"
235
	     " is that flash info is dumped.\n\n");
236
	exit(1);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
237 238
}

239 240 241 242 243
void print_version(void)
{
	printf("flashrom r%s\n", FLASHROM_VERSION);
}

244
int main(int argc, char *argv[])
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
245
{
246
	uint8_t *buf;
247
	unsigned long size;
248
	FILE *image;
Claus Gindhart's avatar
Claus Gindhart committed
249 250
	/* Probe for up to three flash chips. */
	struct flashchip *flash, *flashes[3];
251
	int opt;
252
	int option_index = 0;
253
	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
Claus Gindhart's avatar
Claus Gindhart committed
254
	int ret = 0, i;
255 256 257
#ifdef __FreeBSD__
	int io_fd;
#endif
258

259 260 261 262 263 264 265 266 267 268 269 270 271
	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'},
272
		{"list-supported", 0, 0, 'L'},
273
		{"help", 0, 0, 'h'},
274
		{"version", 0, 0, 'R'},
275
		{0, 0, 0, 0}
276
	};
277

278
	char *filename = NULL;
279

280 281
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
282 283 284 285

	if (argc > 1) {
		/* Yes, print them. */
		int i;
286
		printf_debug("The arguments are:\n");
287
		for (i = 1; i < argc; ++i)
288
			printf_debug("%s\n", argv[i]);
289 290
	}

291
	setbuf(stdout, NULL);
292
	while ((opt = getopt_long(argc, argv, "rRwvVEfc:s:e:m:l:i:Lh",
293
				  long_options, &option_index)) != EOF) {
294 295 296 297 298 299 300 301 302 303 304 305 306
		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
307 308 309
		case 'V':
			verbose = 1;
			break;
310 311 312
		case 'E':
			erase_it = 1;
			break;
313 314
		case 's':
			tempstr = strdup(optarg);
315
			sscanf(tempstr, "%x", &exclude_start_position);
316 317
			break;
		case 'e':
318
			tempstr = strdup(optarg);
319
			sscanf(tempstr, "%x", &exclude_end_position);
320
			break;
321 322 323
		case 'm':
			tempstr = strdup(optarg);
			strtok(tempstr, ":");
324
			tempstr2 = strtok(NULL, ":");
325
			if (tempstr2) {
326 327
				lb_vendor = tempstr;
				lb_part = tempstr2;
328
			} else {
329 330
				lb_vendor = NULL;
				lb_part = tempstr;
331 332 333
			}
			break;
		case 'f':
334
			force = 1;
335 336
			break;
		case 'l':
337
			tempstr = strdup(optarg);
338 339
			if (read_romlayout(tempstr))
				exit(1);
340 341
			break;
		case 'i':
342
			tempstr = strdup(optarg);
343 344
			find_romentry(tempstr);
			break;
345 346 347 348 349 350
		case 'L':
			print_supported_chips();
			print_supported_chipsets();
			print_supported_boards();
			exit(0);
			break;
351 352 353 354
		case 'R':
			print_version();
			exit(0);
			break;
355
		case 'h':
356 357 358 359 360
		default:
			usage(argv[0]);
			break;
		}
	}
361

362 363 364 365
	if (read_it && write_it) {
		printf("-r and -w are mutually exclusive\n");
		usage(argv[0]);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
366

367 368
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
369

370
	/* First get full io access */
371
#if defined (__sun) && (defined(__i386) || defined(__amd64))
372
	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
373 374
#elif defined(__FreeBSD__)
	if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
375 376 377
#else
	if (iopl(3) != 0) {
#endif
378 379
		fprintf(stderr, "ERROR: iopl failed: \"%s\"\n",
			strerror(errno));
380 381 382
		exit(1);
	}

383
	/* Initialize PCI access for flash enables */
384 385 386 387 388
	pacc = pci_alloc();	/* Get the pci_access structure */
	/* Set all options you want -- here we stick with the defaults */
	pci_init(pacc);		/* Initialize the PCI library */
	pci_scan_bus(pacc);	/* We want to get the list of devices */

389 390
	/* Open the memory device UNCACHED. That's important for MMIO. */
	if ((fd_mem = open(MEM_DEV, O_RDWR|O_SYNC)) < 0) {
391 392
		perror("Error: Can not access memory using " MEM_DEV
		       ". You need to be root.");
Stefan Reinauer's avatar
Stefan Reinauer committed
393 394 395
		exit(1);
	}

396
	myusec_calibrate_delay();
397 398 399 400

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

403
	/* try to enable it. Failure IS an option, since not all motherboards
404
	 * really need this to be done, etc., etc.
405
	 */
406 407 408 409 410
	ret = chipset_flash_enable();
	if (ret == -2) {
		printf("WARNING: No chipset found. Flash detection "
		       "will most likely fail.\n");
	}
411

412
	board_flash_enable(lb_vendor, lb_part);
413

Claus Gindhart's avatar
Claus Gindhart committed
414 415 416 417 418 419 420 421 422 423 424 425 426 427
	for (i = 0; i < ARRAY_SIZE(flashes); i++) {
		flashes[i] = probe_flash(i ? flashes[i - 1] + 1 : flashchips);
		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]) {
428
		printf("No EEPROM/flash device found.\n");
429
		// FIXME: flash writes stay enabled!
430 431
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
432

Claus Gindhart's avatar
Claus Gindhart committed
433 434
	flash = flashes[0];

435
	printf("Flash part is %s (%d KB).\n", flash->name, flash->total_size);
436 437 438 439 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
	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");
		} else {
			printf("This flash part has status UNTESTED for operations:");
			if (!(flash->tested & TEST_OK_PROBE))
				printf(" PROBE");
			if (!(flash->tested & TEST_OK_READ))
				printf(" READ");
			if (!(flash->tested & TEST_OK_ERASE))
				printf(" ERASE");
			if (!(flash->tested & TEST_OK_WRITE))
				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");
	}
466

467 468 469 470 471 472
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

473
	if (!filename && !erase_it) {
474 475 476
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
477 478
	}

479 480
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
481

482 483
	if (erase_it) {
		printf("Erasing flash chip\n");
484 485 486 487
		if (!flash->erase) {
			fprintf(stderr, "Error: flashrom has no erase function for this flash chip.\n");
			return 1;
		}
488
		flash->erase(flash);
489
		exit(0);
490
	} else if (read_it) {
491
		if ((image = fopen(filename, "w")) == NULL) {
492 493 494 495
			perror(filename);
			exit(1);
		}
		printf("Reading Flash...");
Ollie Lho's avatar
Ollie Lho committed
496
		if (flash->read == NULL)
497
			memcpy(buf, (const char *)flash->virtual_memory, size);
498
		else
499
			flash->read(flash, buf);
500

501
		if (exclude_end_position - exclude_start_position > 0)
502 503
			memset(buf + exclude_start_position, 0,
			       exclude_end_position - exclude_start_position);
504

505 506 507 508
		fwrite(buf, sizeof(char), size, image);
		fclose(image);
		printf("done\n");
	} else {
509 510
		struct stat image_stat;

511
		if ((image = fopen(filename, "r")) == NULL) {
512 513 514
			perror(filename);
			exit(1);
		}
515 516 517 518
		if (fstat(fileno(image), &image_stat) != 0) {
			perror(filename);
			exit(1);
		}
519
		if (image_stat.st_size != flash->total_size * 1024) {
520
			fprintf(stderr, "Error: Image size doesnt match\n");
521 522 523
			exit(1);
		}

524
		fread(buf, sizeof(char), size, image);
525
		show_id(buf, size);
526 527
		fclose(image);
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
528

529 530 531 532 533 534
	/* 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
	 */
535

536
	// ////////////////////////////////////////////////////////////
537
	if (exclude_end_position - exclude_start_position > 0)
538
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
539 540
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
541
		       exclude_end_position - exclude_start_position);
542

543 544
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
545 546
		exclude_start_page++;
	}
547
	exclude_end_page = exclude_end_position / flash->page_size;
548 549 550 551
	// ////////////////////////////////////////////////////////////

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

554
	// ////////////////////////////////////////////////////////////
555

556 557 558 559 560
	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
561
		ret |= flash->write(flash, buf);
562
	}
563

564
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
565
		ret |= verify_flash(flash, buf);
566

567 568 569
#ifdef __FreeBSD__
	close(io_fd);
#endif
Stefan Reinauer's avatar
Stefan Reinauer committed
570
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
571
}