david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[3c90xutil] Update bromutil.c and cromutil.c.

bromutil.c has been updated with a command to "fix" 3c905B NICs
so that EEPROMs larger than 8K may be used.

cromutil.c has been replaced with an updated version that has been
included in etherboot-5.4 for some time now.

See README for usage.

Signed-off-by: Marty Connor <mdc@etherboot.org>
This commit is contained in:
Thomas Miletich 2009-12-05 00:00:44 +01:00 committed by Marty Connor
parent dacc64724f
commit 90bffed805
5 changed files with 585 additions and 191 deletions

View File

@ -1,4 +1,4 @@
FILES = cromutil bromutil
FILES = cromutil ocromutil bromutil
INCLUDEDIR = /usr/include
CFLAGS = -O2 -fomit-frame-pointer -Wall -I$(INCLUDEDIR)

View File

@ -8,6 +8,55 @@ with AT49BV512 Flash memory, and created cromutil and bromutil to
differentiate the versions. cromutil is for 3C905C and bromutil is
for 3C905B.
8.28.2005 I am adding a new version from Jorge L. deLyra that will
replace cromutil.c. I will rename cromutil.c to ocromutil.c
From: delyra@fma.if.usp.br
Subject: Improved version of cromutil.c.
Date: June 22, 2004 12:19:00 AM EDT
To: mdc@thinguin.org
Dear Marty,
Below you will find a new version of the cronutil.c program. Since
the changes were quite large I am sending the program rather than a patch.
I added support for 3C905CX cards with a page-mode super-flash EEPROM, and
included several informative messages, a programming progress report and a
detailed help message. I did all the tests I could with it and it seems to
work correctly for the 3C905CX with either type of EEPROM chip.
A question: is there a similar program for Intel eepro100 cards or for the
Intel or 3COM Gbit cards?
Cheers,
----------------------------------------------------------------
Jorge L. deLyra, Associate Professor of Physics
The University of Sao Paulo, IFUSP-DFMA
For more information: finger delyra@latt.if.usp.br
----------------------------------------------------------------
12/4/2009 The new cromutil version from Jorge L. deLyra can be found in
cromutil.c, whereas the old version can be found in ocromutil.c.
bromutil.c now supports enabling a bootrom workaround that was previously
implemented in the old 3c90x driver. Some 3c90xB cards refuse to load gPXE
after the ROM is burned. The gPXE banner is likely to appear, but gPXE will
crash soon after.
If this is the case try the following commands. It is assumed that you replace
0x6600 with the I/O address of your card which can be acquired with:
(look for a line like 'I/O ports at e400')
$ lspci -v
$ make
$ ./bromutil 0x6600 bootrom
This command will write into the settings EEPROM of the network card. In case
the network card shows any unexpected behavior it is possible to restore the
EEPROM settings with a 3COm provided tool called '3c90xcfg.exe'(google it for
mirrors).
-- Thomas Miletich
Be careful. You can easily erase your Flash memory using these
utilities. Make *sure* to back them up first using the "read"
command. You must "erase" before using "prog" to program the chip with

View File

@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#ifdef __FreeBSD__
@ -30,140 +31,224 @@
#endif
int main(int argc, char **argv)
/*
* write_eeprom() and enum definitions are copied from vortex-diag.c,
* Copyright 1997-2004 by Donald Becker.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
* Contact the author for use under other terms.
*/
enum vortex_cmd {
TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
UpStall = 6<<11, UpUnstall = (6<<11)+1,
DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
SetTxThreshold = 18<<11, SetTxStart = 19<<11,
StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,
};
enum Window0 {
Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
Wn0EepromData = 12, /* Window 0: EEPROM results register. */
IntrStatus=0x0E, /* Valid in all windows. */
};
enum Win0_EEPROM_cmds {
EEPROM_Read = 2, EEPROM_WRITE = 1, EEPROM_ERASE = 3,
EEPROM_EWENB = 0xC, /* Enable erasing/writing for 10 msec. */
EEPROM_EWDIS = 0x0, /* Disable EWENB before 10 msec timeout. */
};
#define debug 1
static void write_eeprom(long ioaddr, int addrlen, int index, int value)
{
unsigned int i, j, n;
unsigned int ioaddr;
unsigned long recvrstat;
unsigned char buf[128];
unsigned char b;
int timer;
if (argc != 3) {
printf("Usage: romid ioaddr [erase|protect|unprotect|id|read >file|prog <file]\n");
exit(-1);
}
#ifdef __FreeBSD__
/* get permissions for in/out{blw} */
open("/dev/io",O_RDONLY,0);
#else
setuid(0); /* if we're setuid, do it really */
if (iopl(3)) {
perror("iopl()");
exit(1);
}
#endif
sscanf(argv[1],"%x",&ioaddr);
/* Set the register window to 3 for the 3c905b */
OUTW(0x803, ioaddr+0xe);
recvrstat = inl(ioaddr); /* save the receiver status */
/* set the receiver type to MII so the full bios rom address space
can be accessed */
OUTL((recvrstat & 0xf00fffff)|0x00600000, ioaddr);
/* Set the register window to 0 for the 3c905b */
OUTW(0x800, ioaddr+0xe);
if (strcmp(argv[2], "erase") == 0) {
/* do the funky chicken to erase the rom contents */
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0x80, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0x10, ioaddr+0x8);
printf("Bios ROM at %04x has been erased\n", ioaddr);
} else if (strcmp(argv[2], "protect") == 0) {
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0xa0, ioaddr+0x8);
printf("Software Data Protection for Bios ROM at %04x has been enabled\n",
ioaddr);
} else if (strcmp(argv[2], "unprotect") == 0) {
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0x80, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0x20, ioaddr+0x8);
printf("Software Data Protection for Bios ROM at %04x has been disabled\n",
ioaddr);
} else if (strcmp(argv[2], "id") == 0) {
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0x90, ioaddr+0x8);
/* 10ms delay needed */
printf("Manufacturer ID - ");
/* manuf. id */
OUTL(0x0000, ioaddr+0x4);
printf("%02x\n", inb(ioaddr+0x8));
/* device id */
OUTL(0x0001, ioaddr+0x4);
printf("Device ID - %02x\n", inb(ioaddr+0x8));
/* undo the funky chicken */
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0xf0, ioaddr+0x8);
} else if (strcmp(argv[2], "read") == 0) {
for (i = 0; i < 65536; i++) {
OUTL(i, ioaddr+0x4);
b = inb(ioaddr+0x8);
write(1, &b, 1);
}
} else if (strcmp(argv[2], "prog") == 0) {
/* program the rom in 128 bute chunks */
for (i = 0, n = 0; i < 65536; i += n) {
n = read(0, buf, 128);
if (n == 0)
break;
if (n < 0) {
perror("File Error");
exit(-3);
/* Verify that the EEPROM is idle. */
for (timer = 1620; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
if (--timer < 0)
goto error_return;
/* Enable writing: EEPROM_EWENB | 110000.... */
OUTW(3 << (addrlen-2), ioaddr + Wn0EepromCmd);
for (timer = 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) {
if (--timer < 0)
goto error_return;
}
/* disable SDP temporarily for programming a sector */
OUTL(0x5555, ioaddr+0x4);
OUTB(0xaa, ioaddr+0x8);
OUTL(0x2aaa, ioaddr+0x4);
OUTB(0x55, ioaddr+0x8);
OUTL(0x5555, ioaddr+0x4);
OUTB(0xa0, ioaddr+0x8);
for (j = 0; j < n; j++) {
OUTL(i+j, ioaddr+0x4);
OUTB(buf[j], ioaddr+0x8);
if (debug)
fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400 - timer);
OUTW((EEPROM_ERASE << addrlen) + index, ioaddr + Wn0EepromCmd);
for (timer = 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
if (--timer < 0) {
fprintf(stderr, "EEPROM failed to erase index %d!\n", index);
return;
}
if (debug)
fprintf(stderr, "EEPROM erased index %d after %d ticks!\n",
index, 16000-timer);
OUTW(3 << (addrlen-2), ioaddr + Wn0EepromCmd);
for (timer = 400; inw(ioaddr + Wn0EepromCmd) & 0x8000;) {
if (--timer < 0)
goto error_return;
}
/* wait for the programming of this sector to coomplete */
while (inb(ioaddr+0x8) != buf[j-1])
;
}
}
/* Set the register window to 3 for the 3c905b */
OUTW(0x803, ioaddr+0xe);
/* restore the receiver status */
OUTL(recvrstat, ioaddr);
return 0;
if (debug)
fprintf(stderr, "EEPROM write enable took %d ticks!\n", 400-timer);
OUTW(value, ioaddr + Wn0EepromData);
OUTW((EEPROM_WRITE << addrlen) + index, ioaddr + Wn0EepromCmd);
for (timer = 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
if (--timer < 0)
goto error_return;
if (debug)
fprintf(stderr, "EEPROM wrote index %d with 0x%4.4x after %d ticks!\n",
index, value, 16000-timer);
return;
error_return:
fprintf(stderr, "Failed to write EEPROM location %d with 0x%4.4x!\n",
index, value);
}
#endif /* __i386__ */
int main(int argc, char **argv)
{
unsigned int i, j, n;
unsigned int ioaddr;
unsigned long recvrstat;
unsigned char buf[128];
unsigned char b;
if (argc != 3) {
printf
("Usage: romid ioaddr [erase|protect|unprotect|id|bootrom|read >file|prog <file]\n");
exit(-1);
}
#ifdef __FreeBSD__
/* get permissions for in/out{blw} */
open("/dev/io", O_RDONLY, 0);
#else
setuid(0); /* if we're setuid, do it really */
if (iopl(3)) {
perror("iopl()");
exit(1);
}
#endif
sscanf(argv[1], "%x", &ioaddr);
/* Set the register window to 3 for the 3c905b */
OUTW(0x803, ioaddr + 0xe);
recvrstat = inl(ioaddr); /* save the receiver status */
/* set the receiver type to MII so the full bios rom address space
can be accessed */
OUTL((recvrstat & 0xf00fffff) | 0x00600000, ioaddr);
/* Set the register window to 0 for the 3c905b */
OUTW(0x800, ioaddr + 0xe);
if (strcmp(argv[2], "erase") == 0) {
/* do the funky chicken to erase the rom contents */
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0x80, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0x10, ioaddr + 0x8);
printf("Bios ROM at %04x has been erased\n", ioaddr);
} else if (strcmp(argv[2], "protect") == 0) {
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xa0, ioaddr + 0x8);
printf
("Software Data Protection for Bios ROM at %04x has been enabled\n",
ioaddr);
} else if (strcmp(argv[2], "unprotect") == 0) {
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0x80, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0x20, ioaddr + 0x8);
printf
("Software Data Protection for Bios ROM at %04x has been disabled\n",
ioaddr);
} else if (strcmp(argv[2], "id") == 0) {
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0x90, ioaddr + 0x8);
/* 10ms delay needed */
printf("Manufacturer ID - ");
/* manuf. id */
OUTL(0x0000, ioaddr + 0x4);
printf("%02x\n", inb(ioaddr + 0x8));
/* device id */
OUTL(0x0001, ioaddr + 0x4);
printf("Device ID - %02x\n", inb(ioaddr + 0x8));
/* undo the funky chicken */
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xf0, ioaddr + 0x8);
} else if(strcmp(argv[2], "bootrom") == 0) {
printf("bootrom fix\n");
write_eeprom(ioaddr, 6, 19, 0x160);
} else if (strcmp(argv[2], "read") == 0) {
for (i = 0; i < 65536; i++) {
OUTL(i, ioaddr + 0x4);
b = inb(ioaddr + 0x8);
write(1, &b, 1);
}
} else if (strcmp(argv[2], "prog") == 0) {
/* program the rom in 128 bute chunks */
for (i = 0, n = 0; i < 65536; i += n) {
n = read(0, buf, 128);
if (n == 0)
break;
if (n < 0) {
perror("File Error");
exit(-3);
}
/* disable SDP temporarily for programming a sector */
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xaa, ioaddr + 0x8);
OUTL(0x2aaa, ioaddr + 0x4);
OUTB(0x55, ioaddr + 0x8);
OUTL(0x5555, ioaddr + 0x4);
OUTB(0xa0, ioaddr + 0x8);
for (j = 0; j < n; j++) {
OUTL(i + j, ioaddr + 0x4);
OUTB(buf[j], ioaddr + 0x8);
}
/* wait for the programming of this sector to coomplete */
while (inb(ioaddr + 0x8) != buf[j - 1]);
}
}
/* Set the register window to 3 for the 3c905b */
OUTW(0x803, ioaddr + 0xe);
/* restore the receiver status */
OUTL(recvrstat, ioaddr);
return 0;
}
#endif /* __i386__ */

View File

@ -1,101 +1,257 @@
/*
* 3c905cutil.c - perform various control ops on the 3C905C bios rom
* which we assume to be an AT49BV512
/*
* JLdL 21Jun04.
*
* cromutil.c
*
* Perform various control operations on the flash EEPROM of
* _ the 3COM models 3C905C or 3C905CX network cards, in order
* _ to write a boot program such as Etherboot into it.
*
* This program is meant for the Linux operating system only,
* _ and only for the i386 architecture.
*
* The flash EEPROM usually used in these cards is the AT49BV512
* _ chip, which has 512 Kbit (64 KByte). Another possible chip,
* _ which is equivalent to this one, is the SST39VF512.
*
* Added alternative read128 and prog128 commands for cards with
* _ the SST29EE020 fast page-write (super-)flash EEPROM, which
* _ has 2 Mbit (256 KByte), and which has to be programmed in
* _ a 128-byte page mode. NOTE: it seems that the card can
* _ address only the first half of the memory in this chip,
* _ so only 128 Kbytes are actually available for use.
*
* Added a few informative messages and a detailed help message.
*
*/
#ifndef __i386__
# error "This program can't compile or run on non-intel computers"
# error "This program can't compile or run on non-Intel computers"
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#include <string.h>
int main(int argc, char **argv)
{
unsigned int ioaddr, i, n;
/* Counters. */
unsigned int i, j, n;
/* For ROM chips larger than 64 KB, a long integer
_ is needed for the global byte counter. */
unsigned long k;
/* The I/O address of the card. */
unsigned int ioaddr;
/* Storage for a byte. */
unsigned char b;
/* Storage for a page. */
unsigned char buf[128];
setuid(0); /* if we're setuid, do it really */
/* Initialize a few things to avoid compiler warnings. */
i=0; j=0; n=0; k=0;
/* Verify the command-line parameters; write
_ out an usage message if needed. */
if (argc != 3) {
printf("Usage: romid ioaddr [erase|id|read >file|prog <file]\n");
/* Exactly 2 command line parameters are needed. */
printf("Usage: ./cromutil ioaddr command [(>|<) file]\n");
printf(" (try './cromutil 0x0000 help' for details)\n");
exit(-1);
}
/* Set the UID to root if possible. */
setuid(0);
/* Get port-access permissions for in{blw}/out{blw}. */
if (iopl(3)) {
perror("iopl()");
exit(1);
}
/* Pass the I/O address of the card to a variable. */
sscanf(argv[1],"%x",&ioaddr);
/* Set the register window to 0 for the 3C905C */
/* Set the register window to 0. */
outw(0x800, ioaddr+0xe);
if (strcmp(argv[2], "erase") == 0) {
/* do the funky chicken to erase the rom contents */
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0x80, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0x10, ioaddr+0x8);
sleep (1);
printf("Bios ROM at %04x has been erased\n", ioaddr);
} else if (strcmp(argv[2], "id") == 0) {
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0x90, ioaddr+0x8);
/* 10ms delay needed */
printf("Manufacturer ID - ");
/* manuf. id */
/*
* Execute the requested command.
*
* "id": get and write out the ID numbers.
*/
if (strcmp(argv[2], "id") == 0) {
/* Software ID entry command sequence. */
outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4); outb(0x90, ioaddr+0x8);
/* A 10 ms delay is needed. */
usleep(10000);
/* Get the manufacturer id. */
outl(0x0000, ioaddr+0x4);
printf("%02x\n", inb(ioaddr+0x8));
/* device id */
printf("Manufacturer ID - %02x\n", inb(ioaddr+0x8));
/* Get the device id. */
outl(0x0001, ioaddr+0x4);
printf("Device ID - %02x\n", inb(ioaddr+0x8));
/* undo the funky chicken */
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0xf0, ioaddr+0x8);
} else if (strcmp(argv[2], "read") == 0) {
for (i = 0; i < 65536; i++) {
outl(i, ioaddr+0x4);
/* Software ID exit command sequence. */
outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4); outb(0xf0, ioaddr+0x8);
}
/*
* "read": read data from the 512 Kbit ROM.
*/
else if (strcmp(argv[2], "read") == 0) {
/* Loop over the whole ROM. */
for (k = 0; k < 65536; k++) {
outl(k, ioaddr+0x4);
b = inb(ioaddr+0x8);
write(1, &b, 1);
}
} else if (strcmp(argv[2], "prog") == 0) {
for (i = 0; i < 65536; i++) {
n = read(0, &b, 1);
/* Write out an informative message. */
perror("Read 65536 bytes from ROM");
}
/*
* "read128": this alternative is for the 2 Mbit ROM.
*/
else if (strcmp(argv[2], "read128") == 0) {
/* Loop over the accessible part of the ROM. */
for (k = 0; k < 131072; k++) {
outl(k, ioaddr+0x4);
b = inb(ioaddr+0x8);
write(1, &b, 1);
}
/* Write out an informative message. */
perror("Read 131072 bytes from ROM");
}
/*
* "erase": erase the ROM contents.
*/
else if (strcmp(argv[2], "erase") == 0) {
/* Software chip-erase command sequence. */
outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4); outb(0x80, ioaddr+0x8);
outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4); outb(0x10, ioaddr+0x8);
/* Wait a bit. */
sleep(1);
/* Write out an informative message. */
printf("Bios ROM at %04x has been erased: Success\n", ioaddr);
}
/*
* "prog": program the 512 Kbit ROM.
*/
else if (strcmp(argv[2], "prog") == 0) {
/* Loop over the bytes in pages, to
_ allow for a progress report. */
for (j = 0; j < 512; j++) {
for (i = 0; i < 128; i++) {
/* If this program is to run on a diskless node,
_ must read in the byte _before_ changing the
_ mode of the chip, or NFS may block. */
n = read(0, &b, 1);
/* At EOF exit the inner loop. */
if (n == 0)
break;
if (n < 0) {
perror("Input File Error");
exit(-3);
}
/* Disable SDP temporarily for programming a byte. */
outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4); outb(0xA0, ioaddr+0x8);
/* Calculate the address of the byte. */
k=i+128*j;
/* Program this byte. */
outl(k, ioaddr+0x4); outb(b, ioaddr+0x8);
/* Wait for the programming of this byte to complete. */
while (inb(ioaddr+0x8) != b)
;
}
/* At EOF exit the outer loop. */
if (n == 0)
break;
/* Write out a progress report. */
printf("."); fflush(NULL);
}
/* Write out an informative message. */
printf("\nWrote %ld bytes to ROM: Success\n", k);
}
/*
* "prog128": this alternative is for the 2 Mbit ROM.
*/
else if (strcmp(argv[2], "prog128") == 0) {
/* Loop over the accessible pages; the card can
_ access only the first half of the chip. */
for (j = 0; j < 1024; j++) {
/* If this program is to run on a diskless node,
_ must read in the page _before_ changing the
_ mode of the chip, or NFS may block. */
n = read(0, buf, 128);
/* At EOF exit the loop. */
if (n == 0)
break;
if (n < 0) {
perror("File Error");
perror("Input File Error");
exit(-3);
}
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0xA0, ioaddr+0x8);
outl(i, ioaddr+0x4);
outb(b, ioaddr+0x8);
while (inb(ioaddr+0x8) != b)
/* Disable SDP temporarily for programming a page. */
outl(0x5555, ioaddr+0x4); outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4); outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4); outb(0xA0, ioaddr+0x8);
/* Loop over the bytes in a page. */
for (i = 0; i < n; i++) {
/* Calculate the address of the byte. */
k=i+128*j;
/* Program this byte. */
outl(k, ioaddr+0x4); outb(buf[i], ioaddr+0x8);
}
/* Wait for the programming of this page to complete. */
while (inb(ioaddr+0x8) != buf[i-1])
;
/* Write out a progress report. */
printf("."); fflush(NULL);
}
/* Write out an informative message. */
printf("\nWrote %d pages to ROM: Success\n", j);
}
/*
* "help": write out a detailed help message.
*/
else if (strcmp(argv[2], "help") == 0) {
printf("This utility can be used to write data, usually boot loaders\n");
printf(" such as Etherboot, to the flash EEPROM of the 3COM models\n");
printf(" 3C905C and 3C905CX network cards. You use it like this:\n");
printf(" ./cromutil ioaddr command [(>|<) file]\n");
printf("Here ioaddr is the hexadecimal I/O address of the card, such\n");
printf(" as 0xA123, in some cases you need input/output redirection\n");
printf(" from/to a file, and the command can be one of these:\n");
printf(" id get the ID numbers of the card;\n");
printf(" read > file read the contents of the ROM into a file;\n");
printf(" read128 > file read the contents of the ROM into a file;\n");
printf(" erase erase the whole ROM to the 1 state;\n");
printf(" prog < file write the contents of a file into the ROM;\n");
printf(" prog128 < file write the contents of a file into the ROM.\n");
printf("You can get the I/O address of the card using the commands\n");
printf(" 'lspci -v', 'cat /proc/pci', or 'dmesg | grep -i 3C905C'.\n");
printf("The read and prog commands are to be used if the card has a\n");
printf(" traditional 512 Kb (64 KB) flash EEPROM chip, such as:\n");
printf(" | AT49BV512 | SST39VF512 |\n");
printf("The read128 and prog128 versions are for cards with a 2 Mb\n");
printf(" (128 KB usable) page-write flash EEPROM chip, such as:\n");
printf(" | SST29EE020 |\n");
}
/*
* Write out the usage message if an unknown command is used.
*/
else {
printf("Usage: ./cromutil ioaddr command [(>|<) file]\n");
printf("(try './cromutil 0x0000 help' for details)\n");
exit(-1);
}
return 0;
}

View File

@ -0,0 +1,104 @@
/*
* 3c905cutil.c - perform various control ops on the 3C905C bios rom
* which we assume to be an AT49BV512
*
*/
#ifndef __i386__
# error "This program can't compile or run on non-intel computers"
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#include <string.h>
int main(int argc, char **argv)
{
unsigned int ioaddr, i, n;
unsigned char b;
setuid(0); /* if we're setuid, do it really */
if (argc != 3) {
printf("Usage: romid ioaddr [erase|id|read >file|prog <file]\n");
exit(-1);
}
if (iopl(3)) {
perror("iopl()");
exit(1);
}
sscanf(argv[1],"%x",&ioaddr);
/* Set the register window to 0 for the 3C905C */
outw(0x800, ioaddr+0xe);
if (strcmp(argv[2], "erase") == 0) {
/* do the funky chicken to erase the rom contents */
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0x80, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0x10, ioaddr+0x8);
sleep (1);
printf("Bios ROM at %04x has been erased\n", ioaddr);
} else if (strcmp(argv[2], "id") == 0) {
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0x90, ioaddr+0x8);
/* 10ms delay needed */
printf("Manufacturer ID - ");
/* manuf. id */
outl(0x0000, ioaddr+0x4);
printf("%02x\n", inb(ioaddr+0x8));
/* device id */
outl(0x0001, ioaddr+0x4);
printf("Device ID - %02x\n", inb(ioaddr+0x8));
/* undo the funky chicken */
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0xf0, ioaddr+0x8);
} else if (strcmp(argv[2], "read") == 0) {
for (i = 0; i < 65536; i++) {
outl(i, ioaddr+0x4);
b = inb(ioaddr+0x8);
write(1, &b, 1);
}
} else if (strcmp(argv[2], "prog") == 0) {
for (i = 0; i < 65536; i++) {
n = read(0, &b, 1);
if (n == 0)
break;
if (n < 0) {
perror("File Error");
exit(-3);
}
outl(0x5555, ioaddr+0x4);
outb(0xaa, ioaddr+0x8);
outl(0x2aaa, ioaddr+0x4);
outb(0x55, ioaddr+0x8);
outl(0x5555, ioaddr+0x4);
outb(0xA0, ioaddr+0x8);
outl(i, ioaddr+0x4);
outb(b, ioaddr+0x8);
while (inb(ioaddr+0x8) != b)
;
}
}
return 0;
}
#endif /* __i386__ */