/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
/*
2005-10-16 gentoox@shallax.com * Updated and tested NetBSD/ FreeBSD patches.
Thanks to Ed and Rink.
2005-08-11 gentoox@shallax.com + Added eXOBeX's JEDEC compliance tests
to ensure that an invalid manufacturer ID
is correctly ignored.
2005-07-29 gentoox@shallax.com + Added Rink's BSD support patch.
2005-07-25 gentoox@shallax.com + Reworked the help logic to accept
-h/ --help. Help is now displayed
regardless of whether a chip was
recognised.
2005-02-09 gentoox@shallax.com + Added a load of flash types.
2003-01-27 andy@warmcat.com + Cosmetic edits, using character bars for
progress.
+ Support for 28xxx flash.
2003-01-06 andy@warmcat.com + Created.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if defined(linux)
#include <sys/io.h>
#elif defined(__NetBSD__)
#include <machine/sysarch.h>
#endif
#include <ctype.h>
#include <signal.h>
#include "boot.h"
#include "BootFlash.h"
#define RAINCOAT_VERSION "0.11"
bool FlashingCallback(void * pvoidObjectFlash, ENUM_EVENTS ee, DWORD dwPos, DWORD dwExtent);
OBJECT_FLASH objectflash;
KNOWN_FLASH_TYPE aknownflashtype[1024] = { // Max of 1023 flash types (+1 terminator).
#include "flashtypes.h"
};
void Progress(int nPercent) {
int n=0;
printf(" %3d%% .:(", nPercent);
while(n++<((40 * nPercent)/100)) printf("*");
while(n++<40) printf(".");
printf("):.\r");
}
void ClearProgress(void) {
int n=0;
while(n++<54) printf(" ");
printf("\r");
}
bool FlashingCallback(void * pvoidof, ENUM_EVENTS ee, DWORD dwPos, DWORD dwExtent)
{
// OBJECT_FLASH * pof=(OBJECT_FLASH *)pvoidof;
switch(ee) {
case EE_ERASE_START:
printf(" Erasing...\n");
break;
case EE_ERASE_UPDATE:
Progress((dwPos*100)/dwExtent);
break;
case EE_ERASE_END:
ClearProgress();
printf(" Done \n");
break;
case EE_ERASE_ERROR:
printf(" ERASE ERROR AT +0x%lX...read 0x%02lX\n", dwPos, dwExtent&0xff);
break;
case EE_PROGRAM_START:
printf(" Programming...\n");
break;
case EE_PROGRAM_UPDATE:
Progress((dwPos*100)/dwExtent);
break;
case EE_PROGRAM_END:
ClearProgress();
printf(" Done \n");
break;
case EE_PROGRAM_ERROR:
printf(" PROGRAM ERROR AT +0x%lX...wrote 0x%02lX read 0x%02lX\n", dwPos, (dwExtent>>8), dwExtent&0xff);
break;
case EE_VERIFY_START:
printf(" Verifying...\n");
break;
case EE_VERIFY_UPDATE:
Progress((dwPos*100)/dwExtent);
break;
case EE_VERIFY_END:
ClearProgress();
printf(" Done \n");
break;
case EE_VERIFY_ERROR:
printf(" VERIFY ERROR AT +0x%lX...wrote 0x%02lX read 0x%02lX\n", dwPos, (dwExtent>>8), dwExtent&0xff);
break;
}
return true;
}
// Check that the manufacturer ID is valid (if not then we probably have some
// bad soldering on our hands or a write-protected modchip).
void checkID() {
if((((objectflash.m_bManufacturerId & 1) +
((objectflash.m_bManufacturerId >> 1) & 1) +
((objectflash.m_bManufacturerId >> 2) & 1) +
((objectflash.m_bManufacturerId >> 3) & 1) +
((objectflash.m_bManufacturerId >> 4) & 1) +
((objectflash.m_bManufacturerId >> 5) & 1) +
((objectflash.m_bManufacturerId >> 6) & 1) +
((objectflash.m_bManufacturerId >> 7) & 1)) & 1)==0) {
// valid JEDEC manufacturer IDs are always odd-parity
printf("\n!! Invalid manufacturer ID: 0x%02X\n",
objectflash.m_bManufacturerId);
printf("Check all your soldering points and check that write-enable "
"switch is enabled.\n");
exit(1);
}
}
int main(int argc, char * argv[])
{
bool fProgram=false;
bool fReadback=false;
bool fVerbose=false;
char szFilepathProgram[256]="";
char szFilepathReadback[256]="";
int fileMem;
#if defined(__FreeBSD__)
int fileIO;
#endif
char szConfigFile[1024];
//For some reason (anyone?) we OCCASIONALLY get a SIGTRAP, which
//kills us, if we don't ignore it (or handle it).
signal(SIGTRAP, SIG_IGN);
strcpy(szConfigFile,"/usr/local/etc/raincoat.conf");
// construct the flash object
objectflash.m_bManufacturerId=0;
objectflash.m_bDeviceId=0;
objectflash.m_dwLengthInBytes=0;
objectflash.m_dwStartOffset=0;
objectflash.m_dwLengthUsedArea=0;
objectflash.m_pcallbackFlash=FlashingCallback;
objectflash.m_fDetectedUsing28xxxConventions=false;
strcpy(&objectflash.m_szFlashDescription[0], "Unknown");
int nCountSeen=0;
int flashIterator=0;
int pathSet=0;
while((aknownflashtype[nCountSeen].m_bManufacturerId != 0) && (aknownflashtype[nCountSeen].m_bDeviceId != 0)) {
nCountSeen++;
}
printf("raincoat Flasher "RAINCOAT_VERSION" ("__DATE__")\n");
// map the BIOS region 0xff000000 - 0xffffffff so that we can touch it
fileMem = open("/dev/mem", O_RDWR);
if(fileMem < 0)
{
printf ("Cannot open /dev/mem - are you root?\n");
return 1;
}
objectflash.m_pbMemoryMappedStartAddress = (BYTE *)mmap(0, 0x1000000, PROT_READ | PROT_WRITE, MAP_SHARED, fileMem , 0xff000000);
if(objectflash.m_pbMemoryMappedStartAddress==NULL) { printf("Unable to map register memory\n"); return 1; }
#if defined(linux)
if (iopl (3))
#elif defined(__NetBSD__)
if (i386_iopl (3))
#elif defined(__FreeBSD__)
fileIO = open ("/dev/io", O_RDWR);
if (fileIO < 0)
#else
#error "No I/O privileges possible?"
#endif
{
printf ("Cannot acquire I/O privileges\n");
return 1;
}
// parse arguments
{
int n=1;
while(n<argc) {
if(strcmp(argv[n], "-p")==0) { // program
n++;
if(n>=argc) {
printf("Missing argument after -p\n");
return 1;
}
strncpy(szFilepathProgram, &argv[n][0], sizeof(szFilepathProgram)-1);
fProgram=true;
}
if(strcmp(argv[n], "-r")==0) { // readback
n++;
if(n>=argc) {
printf("Missing argument after -r\n");
return 1;
}
strncpy(szFilepathReadback, &argv[n][0], sizeof(szFilepathReadback)-1);
fReadback=true;
}
if(strcmp(argv[n], "-a")==0) { // start offset
n++;
if(n>=argc) {
printf("Missing argument after -a\n");
return 1;
}
if(strlen(argv[n])>8) {
printf("-a argument too long\n");
return 1;
}
sscanf(argv[n], "%lx", (DWORD *)&objectflash.m_dwStartOffset);
}
if(strcmp(argv[n], "-v")==0) { // verbose
fVerbose=true;
}
if(strcmp(argv[n], "-c")==0) { // config file
n++;
strcpy(szConfigFile,argv[n]);
pathSet = 1;
}
if((strcmp(argv[n], "-h")==0) ||
(strcmp(argv[n], "--help")==0)) { // help
printf(
"Created by: Andy Green (andy@warmcat.com)\n"
"Maintained by: Thomas Pedley (gentoox@shallax.com)\n"
"Website: http://www.xbox-linux.org\n\n"
"%s [-p filetoprog] [-r filetodumpto] [-a hexoffset] [-v] [-h] [-c]\n"
" -p filetoprog Program flash with given file\n"
" -r filetodumpto Read whole flash back into file\n"
" -a hexoffset Optional start offset in flash, default 0\n"
" -v Verbose informational messages\n"
" -h This screen\n"
" -c configfile Use a userdefined config File\n\n"
"Example: %s -p cromwell.bin\n\n"
"Please note, -p will reprogram your BIOS flash\n"
" Please do not use if you don't understand what that\n"
" means, there is no simple undo for this if you\n"
" programmed the wrong thing.\n"
" -r is always safe to use, as is running with no args\n", argv[0], argv[0]
);
return 0;
}
n++;
}
}
// bring in the conf file
{
int fileRead;
struct stat statFile;
int nFlashesFromFile = 0;
printf("Trying to read \"%s\"... ",szConfigFile);
fileRead = open(szConfigFile, O_RDONLY);
if((fileRead<=0) && (pathSet == 0)) {
printf("Not found.\nTrying to read \"./raincoat.conf\"... ");
fileRead = open("./raincoat.conf", O_RDONLY);
}
if(fileRead>0) {
fstat(fileRead, &statFile);
if(fVerbose) printf("\n");
{
KNOWN_FLASH_TYPE pkft;
BYTE * pbFile = (BYTE *)malloc(statFile.st_size+1);
char * sz=(char *)pbFile;
int found = 0;
int nCountMaximumFlashTypes=(sizeof(aknownflashtype)/sizeof(KNOWN_FLASH_TYPE))-1-nCountSeen;
if(pbFile==NULL) { printf("unable to allocate %u bytes of memory\n", (unsigned int)statFile.st_size); return 1; }
if(read(fileRead, &pbFile[0], statFile.st_size)<statFile.st_size) {
printf("Failed to read full file\n");
return 1;
}
pbFile[statFile.st_size]='\0';
close(fileRead);
while((*sz) && (nCountMaximumFlashTypes)) {
if((strncmp(sz, "flash", 5)==0) || (strncmp(sz, "Flash", 5)==0) ) { // candidate
sz+=5;
while((*sz) && (isspace((int) *sz))) sz++;
if(*sz=='=') {
while((*sz) && (*sz!='x')) sz++;
if(*sz) {
int n;
char *szHex;
sz++;
szHex=sz;
n=9;
while((n--)&&(*sz!=',')) sz++;
if(n>=0) {
sscanf(szHex, "%x", &n);
pkft.m_bManufacturerId=(BYTE)(n>>8);
pkft.m_bDeviceId=(BYTE)n;
while((*sz) && (*sz!='\"')) sz++;
n=sizeof(pkft.m_szFlashDescription)-1;
if(*sz) {
int nPos=0;
sz++;
while((n--) && (*sz) && (*sz!='\"')) {
pkft.m_szFlashDescription[nPos++]=*sz++;
}
pkft.m_szFlashDescription[nPos++]='\0';
if(*sz) {
while((*sz) && (*sz!='x')) sz++;
if(*sz) {
sz++;
szHex=sz;
n=9;
while((n--)&&(!isspace((int) *sz)) ) sz++;
if(n>=0) {
sscanf(szHex, "%lx", &pkft.m_dwLengthInBytes);
if(fVerbose) {
printf(" 0x%02X, 0x%02X, '%s', %08lX",
pkft.m_bManufacturerId,
pkft.m_bDeviceId,
pkft.m_szFlashDescription,
pkft.m_dwLengthInBytes
);
}
flashIterator=0;
while(flashIterator < nCountSeen) {
// If this is true then the flash is already known about...
if(pkft.m_bManufacturerId == aknownflashtype[flashIterator].m_bManufacturerId) {
if(pkft.m_bDeviceId == aknownflashtype[flashIterator].m_bDeviceId) {
if(fVerbose) {
printf(" - already known.");
}
// Flag it as such.
found = 1;
}
}
flashIterator++;
}
if(fVerbose) {
printf("\n");
}
// If we didn't already know about this flash...
if(found == 0) {
// Add the flash.
if((--nCountMaximumFlashTypes)==0) { //
// Warn when the last possible flash is going to be added.
printf(" (note, raincoat only supports %d flash types, rest ignored)\n", (sizeof(aknownflashtype)/sizeof(KNOWN_FLASH_TYPE))-1);
}
/*
printf("DEBUG: Added to pos %i\n", nCountSeen);
printf("DEBUG: prev2 0x%02X, 0x%02X, '%s', %08lX\n",
aknownflashtype[nCountSeen-2].m_bManufacturerId,
aknownflashtype[nCountSeen-2].m_bDeviceId,
aknownflashtype[nCountSeen-2].m_szFlashDescription,
aknownflashtype[nCountSeen-2].m_dwLengthInBytes
);
printf("DEBUG: prev1 0x%02X, 0x%02X, '%s', %08lX\n",
aknownflashtype[nCountSeen-1].m_bManufacturerId,
aknownflashtype[nCountSeen-1].m_bDeviceId,
aknownflashtype[nCountSeen-1].m_szFlashDescription,
aknownflashtype[nCountSeen-1].m_dwLengthInBytes
);
printf("DEBUG: WAS 0x%02X, 0x%02X, '%s', %08lX\n",
aknownflashtype[nCountSeen].m_bManufacturerId,
aknownflashtype[nCountSeen].m_bDeviceId,
aknownflashtype[nCountSeen].m_szFlashDescription,
aknownflashtype[nCountSeen].m_dwLengthInBytes
);
*/
aknownflashtype[nCountSeen] = pkft;
/*
printf("DEBUG: NOW 0x%02X, 0x%02X, '%s', %08lX\n\n",
aknownflashtype[nCountSeen].m_bManufacturerId,
aknownflashtype[nCountSeen].m_bDeviceId,
aknownflashtype[nCountSeen].m_szFlashDescription,
aknownflashtype[nCountSeen].m_dwLengthInBytes
);
*/
nCountSeen++;
nFlashesFromFile++;
}
found = 0;
flashIterator=0;
}
}
}
}
}
}
}
}
while((*sz) && (*sz!='\n') && (*sz!='\r')) sz++;
while((*sz) && ((*sz=='\n') || (*sz=='\r'))) sz++;
}
free(pbFile);
printf("%d flash types added from file.\n", nFlashesFromFile);
// terminating entry is all zeros
//printf("DEBUG: terminator = %i\n", nCountSeen);
KNOWN_FLASH_TYPE *final = &aknownflashtype[nCountSeen];
memset(final, 0, sizeof(KNOWN_FLASH_TYPE));
}
close(fileRead);
} else {
printf("Not found, using built-in list.\n");
}
}
printf("Total known flashes: %i\n", nCountSeen);
if(fVerbose) {
flashIterator = 0;
printf("\nFinal list of known flash types:\n");
while(flashIterator < nCountSeen) {
printf(" 0x%02X, 0x%02X, '%s', %08lX\n",
aknownflashtype[flashIterator].m_bManufacturerId,
aknownflashtype[flashIterator].m_bDeviceId,
aknownflashtype[flashIterator].m_szFlashDescription,
aknownflashtype[flashIterator].m_dwLengthInBytes
);
flashIterator++;
}
}
if(argc==1) {
printf("Use %s --help for more details\n", argv[0]);
}
// check device type, and exit if we don't recognize it
{
if(BootFlashGetDescriptor(&objectflash, &aknownflashtype[0])) {
checkID();
printf("\nDETECTED: %s\n", objectflash.m_szFlashDescription);
} else {
checkID();
if(!fReadback) {
printf("\nUNKNOWN DEVICE %s\n", objectflash.m_szFlashDescription);
printf("Try adding the device ID to %s\n", szConfigFile);
return(1);
}
}
if(objectflash.m_dwStartOffset >= objectflash.m_dwLengthInBytes) {
printf("-a start offset 0x%lX is too large for ROM size 0x%lX\n", objectflash.m_dwStartOffset, objectflash.m_dwLengthInBytes);
}
}
// perform the selected actions according to commandline switches
if(fProgram) { // perform programming action
struct stat statFile;
int fileRead;
printf("Programming with %s...", szFilepathProgram);
if(!objectflash.m_fIsBelievedCapableOfWriteAndErase) {
printf("\nFlash is locked, unable to write\n");
return 1;
}
fileRead = open(szFilepathProgram, O_RDONLY);
if(fileRead<=0) {
printf("unable to open file\n");
return 1;
}
fstat(fileRead, &statFile);
{
BYTE * pbFile = (BYTE *)malloc(statFile.st_size);
if(pbFile==NULL) { printf("unable to allocate %u bytes of memory\n", (unsigned int)statFile.st_size); return 1; }
if(read(fileRead, &pbFile[0], statFile.st_size)<statFile.st_size) {
printf("Failed to read full file\n");
return 1;
}
printf("Read %u bytes from file\n",(unsigned int)statFile.st_size);
close(fileRead);
objectflash.m_dwLengthUsedArea=(DWORD)statFile.st_size;
if(statFile.st_size > (objectflash.m_dwLengthInBytes - objectflash.m_dwStartOffset)) {
printf("File is too large for available space\n");
return 1;
}
if(BootFlashEraseMinimalRegion(&objectflash)) {
if(!BootFlashProgram(&objectflash, pbFile)) {
printf(" Programming Error: %s\n", objectflash.m_szAdditionalErrorInfo);
}
} else {
printf(" Error: %s\n Could your chip be write-protected?\n", objectflash.m_szAdditionalErrorInfo);
if(objectflash.m_bManufacturerId==0xbf) {
printf(
" Matrix/Xodus users need their switches both off\n"
" With a flashing orange LED. Note that you need\n"
" to cycle power to change switch mode\n"
);
}
}
free(pbFile);
}
}
if(fReadback) { // perform readback
int fileDump;
printf("Reading back to %s...\n", szFilepathReadback);
fileDump = open(szFilepathReadback, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
if(objectflash.m_dwLengthInBytes == 0) objectflash.m_dwLengthInBytes = 0x100000;
write(fileDump, (BYTE *)objectflash.m_pbMemoryMappedStartAddress, objectflash.m_dwLengthInBytes);
close(fileDump);
}
// finished with mapping
munmap((void *)objectflash.m_pbMemoryMappedStartAddress, 0x1000000);
close(fileMem);
#if defined(__FreeBSD__)
close(fileIO);
#endif
printf("Completed\n");
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1