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

275
	char *filename = NULL;
276

277 278
	unsigned int exclude_start_position = 0, exclude_end_position = 0;	// [x,y)
	char *tempstr = NULL, *tempstr2 = NULL;
279 280 281 282

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

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

359 360 361 362
	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
363

364 365
	if (optind < argc)
		filename = argv[optind++];
Ronald G. Minnich's avatar
Ronald G. Minnich committed
366

367
	/* First get full io access */
368
#if defined (__sun) && (defined(__i386) || defined(__amd64))
369
	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
370 371 372
#else
	if (iopl(3) != 0) {
#endif
373 374
		fprintf(stderr, "ERROR: iopl failed: \"%s\"\n",
			strerror(errno));
375 376 377
		exit(1);
	}

378
	/* Initialize PCI access for flash enables */
379 380 381 382 383
	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 */

Stefan Reinauer's avatar
Stefan Reinauer committed
384 385
	/* Open the memory device. A lot of functions need it */
	if ((fd_mem = open(MEM_DEV, O_RDWR)) < 0) {
386 387
		perror("Error: Can not access memory using " MEM_DEV
		       ". You need to be root.");
Stefan Reinauer's avatar
Stefan Reinauer committed
388 389 390
		exit(1);
	}

391
	myusec_calibrate_delay();
392 393 394 395

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

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

407
	board_flash_enable(lb_vendor, lb_part);
408

Claus Gindhart's avatar
Claus Gindhart committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422
	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]) {
423
		printf("No EEPROM/flash device found.\n");
424
		// FIXME: flash writes stay enabled!
425 426
		exit(1);
	}
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
427

Claus Gindhart's avatar
Claus Gindhart committed
428 429
	flash = flashes[0];

430
	printf("Flash part is %s (%d KB).\n", flash->name, flash->total_size);
431 432 433 434 435 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
	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");
	}
461

462 463 464 465 466 467
	if (!(read_it | write_it | verify_it | erase_it)) {
		printf("No operations were specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
	}

468
	if (!filename && !erase_it) {
469 470 471
		printf("Error: No filename specified.\n");
		// FIXME: flash writes stay enabled!
		exit(1);
472 473
	}

474 475
	size = flash->total_size * 1024;
	buf = (uint8_t *) calloc(size, sizeof(char));
476

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

496
		if (exclude_end_position - exclude_start_position > 0)
497 498
			memset(buf + exclude_start_position, 0,
			       exclude_end_position - exclude_start_position);
499

500 501 502 503
		fwrite(buf, sizeof(char), size, image);
		fclose(image);
		printf("done\n");
	} else {
504 505
		struct stat image_stat;

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

519
		fread(buf, sizeof(char), size, image);
520
		show_id(buf, size);
521 522
		fclose(image);
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
523

524 525 526 527 528 529
	/* 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
	 */
530

531
	// ////////////////////////////////////////////////////////////
532
	if (exclude_end_position - exclude_start_position > 0)
533
		memcpy(buf + exclude_start_position,
Uwe Hermann's avatar
Uwe Hermann committed
534 535
		       (const char *)flash->virtual_memory +
		       exclude_start_position,
536
		       exclude_end_position - exclude_start_position);
537

538 539
	exclude_start_page = exclude_start_position / flash->page_size;
	if ((exclude_start_position % flash->page_size) != 0) {
540 541
		exclude_start_page++;
	}
542
	exclude_end_page = exclude_end_position / flash->page_size;
543 544 545 546
	// ////////////////////////////////////////////////////////////

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

549
	// ////////////////////////////////////////////////////////////
550

551 552 553 554 555
	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
556
		ret |= flash->write(flash, buf);
557
	}
558

559
	if (verify_it)
Stefan Reinauer's avatar
Stefan Reinauer committed
560
		ret |= verify_flash(flash, buf);
561

Stefan Reinauer's avatar
Stefan Reinauer committed
562
	return ret;
Ronald G. Minnich's avatar
Dammit  
Ronald G. Minnich committed
563
}