/* * NAME * upload.c - 17-Apr-97 16:40:52 * * AUTHOR * Jon Rocatis - jon@funcom.com * * DESCRIPTION * Yaroze Upload tool. Reads batch files and executes them. * Not all commands are supported at the moment! * */ #include #include #include #include #include #include #include #include #include "upload_protos.h" #include "serial_protos.h" #include "tools_protos.h" #include "parse_protos.h" #include "myecoff.h" #include "upload.h" /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Endian change for 32 bit integers #define ENDIAN_CHG32(a) ( ((a >> 24) & 0xff) | ((a >> 8) & 0xff00) | ((a << 8) & 0x00ff0000) | ((a << 24) & 0xff000000) ) // Endian change for 16 bit integers #define ENDIAN_CHG16(a) ( ((a >> 8) & 0xff) | ((a << 8) & 0xff00) ) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// VERSTRING; // Amiga program version string LONG jumpAddr; // The start address of the executable BOOL dontSendData; int baudRate; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * NAME * SendGo * * FUNCTION * Sends the "go" command to the PlayStation. First sets the EPC register. * * INFO * When uploading COFF file: * REG_EPC must be set to a_entry * REG_GP must be set to a_gp * REG_SP must be set to 0x801fff00 * */ void SendGo( void ) { UBYTE dynacmd[100]; LONG cmdlen; printf( "Here we go!\n" ); printf( "Jump address: $%08x\n\n", jumpAddr ); cmdlen = sprintf( dynacmd, "sr epc %08x\015", jumpAddr); SerialSend( dynacmd, cmdlen ); Wait( SIGBREAKF_CTRL_D ); cmdlen = sprintf( dynacmd, "go\015", jumpAddr); SerialSend( dynacmd, cmdlen ); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * NAME * DataSend * * FUNCTION * Uploads a binary file to the PlayStation. * * INPUT * fh - file ptr to already opened binary file (ready to read) * loadAddr - the load address of the file * size - the size in bytes of the file * */ void DataSend( const BPTR fh, const ULONG loadAddr, const ULONG size ) { struct UploadHeader ulh; // Header that request file uploading on PSX struct Packet *packet; // Ptr to packet that is send to PSX ULONG sigs; // Signal mask received from Wait() LONG rest, // #bytes still left to be send from file rlen; // #bytes still left to be send from buffer static UBYTE cmd1[] = {'b','w','r',0x0d}; // "Binary Write" command static UBYTE cmd2[] = {0x0d}; packet = AllocMem( sizeof(struct Packet), 0 ); if ( packet == NULL ) return; printf( "Starting upload.. " ); fflush( stdout ); SerialSend( cmd1, sizeof(cmd1) ); // Tell PSX we want to upload.. (The PSX will answer with: "bwr" 0x0a 0x0d "binary" 0x0d) // w4bin = TRUE; // printf( "Waiting for 'bwr binary' (with auto) \n" ); sigs = Wait( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_D ); w4bin = FALSE; if ( sigs & SIGBREAKF_CTRL_C ) goto stop; if ( sigs & SIGBREAKF_CTRL_D ) { // Got 'bwr binary' automatically Delay( 5 ); } // packet->id = STATE_DATA; ulh.id = STATE_UPLOAD; ulh.address = loadAddr; ulh.length = size; SerialSend( &ulh.id, 9 ); // Tell PSX load address and size of file to upload (PSX doesn't answer this one it seems!) Delay( 20 ); // Now lets send the data in 2K chunks.. for ( rest = size; rest > 0; ) { UBYTE chksum; LONG cidx; if ( rest >= BLOCKSIZE ) rlen = BLOCKSIZE; else { rlen = rest; memset( &packet->data, 0, sizeof(packet->data) ); } Read( fh, &packet->data, rlen ); printf( "\r (%6d / %6d) %d%%.. ", (size - rest), size, 100 - (rest*100 / size)); fflush( stdout ); rest -= rlen; // printf( "rlen = %d, rest = %d\n", rlen, rest ); for ( chksum = cidx = 0; cidx < BLOCKSIZE; cidx++ ) chksum += packet->data[cidx]; packet->chksum = chksum; // printf( "Chksum = %02x\n", chksum ); // Wait( SIGBREAKF_CTRL_F ); Delay(7); // 7 seems to be the lowest! retry: w4y = TRUE; SerialSend( packet, sizeof(struct Packet) ); // printf("Waiting for 'Y' (CF)\n"); sigs = Wait( SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F ); if ( sigs & SIGBREAKF_CTRL_E ) { // printf( "Got Y!\n"); } else { if ( sigs & SIGBREAKF_CTRL_F ) goto retry; else goto stop; } // Delay(7); // 7 seems to be the lowest! } printf( "\rUploaded %d bytes \n", size ); fflush( stdout ); // The whole file has been transferred! Now wait for the PSX to be ready again for more. SerialSend( cmd2, 1 ); // printf( "Waiting for '>>'\n" ); sigs = Wait( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_D ); if ( sigs & SIGBREAKF_CTRL_C ) goto stop; if ( sigs & SIGBREAKF_CTRL_D ) { // printf( "Got >>\n" ); } // printf( "\n\n" ); stop: FreeMem( packet, sizeof(struct Packet) ); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * NAME * WaitForPSX * * FUNCTION * Waits for the PSX to send '>>' * */ void WaitForPSX( void ) { static UBYTE cmd2[] = {0x0d}; printf( "All data transfered! (F). " ); fflush( stdout ); SerialSend( cmd2, 1 ); Wait( SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_F ); printf( "Got >>..\n\n" ); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * NAME * UploadExe * * FUNCTION * Uploads a PlayStation executable. Searches the COFF file and extracts * info on the 4 needed sections (text, rdata, data, sdata) * * INPUT * fname - ptr to filename * * RESULT * An uploaded file or error message if anything went wrong * */ #define FAIL(a) { puts(a); goto error; } void UploadExe( char *fname ) { LONG idx, totSize, numSects; struct Section *sections = NULL; struct ecoff_file_hdr header; struct ecoff_aout_hdr aheader; BPTR fh; printf( "Program load!\n" ); fh = Open( fname, MODE_OLDFILE ); if (!fh) FAIL( "Couldn't open file!\n" ); printf( "Reading %s..\n", fname ); Read( fh, &header, sizeof(header) ); if ( header.f_magic != ECOFF_MIPS_MAGIC_LITTLE_SWAP ) FAIL( "Not a Yaroze EXE file!\n" ); numSects = ENDIAN_CHG16( header.f_nscns ); sections = AllocVec( sizeof(struct Section) * numSects, 0 ); if ( sections == NULL ) FAIL( "Out of memory!\n" ); // Read( fh, &aheader, sizeof(aheader) ); jumpAddr = ENDIAN_CHG32( aheader.a_entry ); printf( "Jump address: $%08x\n\n", jumpAddr ); // Read( fh, sections, sizeof(struct Section) * numSects ); for ( totSize = idx = 0; idx < 4 /*numSects*/; idx++ ) { sections[idx].loadAddr = ENDIAN_CHG32( sections[idx].loadAddr ); sections[idx].size = ENDIAN_CHG32( sections[idx].size ); sections[idx].fpos = ENDIAN_CHG32( sections[idx].fpos ); DisplaySectionInfo( §ions[idx] ); totSize += sections[idx].size; } printf( "Total size of sections: %d bytes (%dK)\n\n", totSize, ((totSize-1) / 1024) + 1 ); /////// for ( idx = 0; idx < 4; idx++ ) // Send 4 sections { Seek( fh, sections[idx].fpos, OFFSET_BEGINNING ); DataSend( fh, sections[idx].loadAddr, sections[idx].size ); } WaitForPSX(); /////// error: if (sections) FreeVec(sections); if (fh) Close(fh); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void main( int argc, char **argv ) { char *fname; FILE *fp; static char test[4] = {0x1,0x2,0x3,0x4}; if ( (argc < 2) || (argc > 3) ) { printf( "Usage: %s [nd]\n", argv[0] ); exit(1); } fname = argv[1]; if (!(fp = fopen( fname, "r" ))) { printf( "*** Couldn't open %s!\n", fname ); exit(1); } if ( argc == 3 ) dontSendData = TRUE; else dontSendData = FALSE; baudRate = GetBaudRate(); if (baudRate == -1) { printf( "*** Illegal baudrate!\n" ); exit(1); } if ( SerialInit() ) { if ( InitTask() ) { LONG sigs; printf( "\nParsing '%s'. Baud rate: %d\n\n", fname, baudRate ); ParseBatchFile( fp ); printf( "Parsing complete. Press CTRL-F to quit\n" ); Signal( task, SIGBREAKF_CTRL_E ); do { sigs = Wait( SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_D ); if (sigs & SIGBREAKF_CTRL_E) { PrintLine(); } /* if (sigs & SIGBREAKF_CTRL_D) { printf(">> sending\n"); SerialSend( test, 4 ); } */ } while (!(sigs & SIGBREAKF_CTRL_F)); FreeTask(); } else printf( "*** Couldn't Initialize Task!\n" ); SerialClose(); } else printf( "*** Couldn't Initialize Serial Device!\n" ); fclose( fp ); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////