scripts

misc scripts and tools
git clone git://git.2f30.org/scripts
Log | Files | Refs

commit f5f03a72cf4a1df4c1e2916f2823b45cdf7e99fd
parent 11a41ffbdba04d88382988ca5937f9d1b1c7d2d2
Author: lostd <lostd@2f30.org>
Date:   Mon,  2 Sep 2013 14:10:49 +0300

dreamcast selfboot burning guide and tools

Diffstat:
Aselfboot/1strdchk.c | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aselfboot/IP.TMPL | 0
Aselfboot/Makefile | 8++++++++
Aselfboot/README | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aselfboot/ip.txt | 11+++++++++++
Aselfboot/makeip.c | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aselfboot/scramble.c | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 682 insertions(+), 0 deletions(-)

diff --git a/selfboot/1strdchk.c b/selfboot/1strdchk.c @@ -0,0 +1,159 @@ +/*********************************************************************************** + * 1st_read.bin File Checker - Visual Basic to C conversion + * + * LyingWake <LyingWake@gmail.com> + * http://www.consolevision.com/members/fackue/ + * + * This is a port of 1st_read.bin File Checker 1.5's source code + * from Visual Basic 6.0 to Microsoft Visual C++. + * + * Thanks to all those that helped; JustBurn, Quzar, GPFerror and + * and anyond else I forgot. + ***********************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <stdlib.h> + +#ifdef _WIN32 + #include <io.h> +#else + #include <unistd.h> + #define _O_BINARY 0 + #define _O_RDONLY O_RDONLY +#endif + +#define Unscrambled 0 +#define Scrambled 1 + +#ifndef _WIN32 + long _filelength(int fd) { + long pos; + lseek(fd, 0, SEEK_SET); + pos = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + return pos; + } +#endif + +char *memoryspace; /* A pointer that will be stored the file */ + +//////////////////////////////////////////////////////////////////////////////////// + +/* //////////////////////////////////////////////////////////////////// */ +/* // // */ +/* // Function: IdentifyBin // */ +/* // Description: Reads file, checks if any given string is inside, // */ +/* // if so, it's unscrambled, else it is scrambled. // */ +/* // // */ +/* // Returns: integer (rIdentifyBin) // */ +/* // // */ +/* //////////////////////////////////////////////////////////////////// */ + +int IdentifyBin(char *filename) { + int pFile; + int rIdentifyBin; + int bytesreaded; + int i; + + char abc1[] = "abcdefghijklmnopqrstuvwxyz1234567890"; + char abc2[] = "abcdefghijklmnopqrstuvwxyz0123456789"; + char abc3[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + char abc4[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + char abc5[] = "1234567890abcdefghijklmnopqrstuvwxyz"; + char abc6[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + char abc7[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + char abc8[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + char temp[] = "#...'...*...-.../...2...4...7...9...;...=...?...A...C...E...G...I...J...L...N...O...Q...R...T...U...W...X...Z..."; + char temp2[] = "0123456789abcdef....(null)..0123456789ABCDEF"; + char punch[] = "PORTDEV INFOENBLSTATRADRTOUTDRQCFUNCEND"; + char tetris[] = "abcdefghijklEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()"; + char netbsd[] = "$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + char bortmnt[] = "0123456789ABCDEF....Inf.NaN.0123456789abcdef....(null)..."; + char dreamsnes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789-"; + + rIdentifyBin = Scrambled; + + pFile = open(filename, _O_BINARY | _O_RDONLY); + if (pFile == -1) { + return -1; + } + + /* Get the number of bytes in the file */ + bytesreaded = _filelength(pFile); + + /* Allocate memory to store the file plus the NULL-termination char */ + memoryspace = (char *)malloc(bytesreaded + 1); + + /* Ok, now we read the file */ + bytesreaded = read(pFile, memoryspace, bytesreaded); + + /* This is the little cheat ;) */ + for (i = 0; i < bytesreaded; i++) { + if (memoryspace[i] == 0x00) { + memoryspace[i] = '.'; + } + } + + /* We can't forget the NULL-termination char or program will crash! */ + memoryspace[bytesreaded] = '\0'; + close(pFile); + + if (strstr(memoryspace, abc1) || + strstr(memoryspace, abc2) || + strstr(memoryspace, abc3) || + strstr(memoryspace, abc4) || + strstr(memoryspace, abc5) || + strstr(memoryspace, abc6) || + strstr(memoryspace, abc7) || + strstr(memoryspace, abc8) || + strstr(memoryspace, temp) || + strstr(memoryspace, temp2) || + strstr(memoryspace, bortmnt) || + strstr(memoryspace, dreamsnes) || + strstr(memoryspace, tetris) || + strstr(memoryspace, punch) || + strstr(memoryspace, netbsd)) { + rIdentifyBin = Unscrambled; + } + + /* We dont need the memory anymore */ + free(memoryspace); + + return rIdentifyBin; +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char *argv[]) { + int i; + int retval = 0; + + /* The program was opened without a filename argument */ + if(argc < 2) { + fprintf(stderr, "1st_read.bin File Checker\nhttp://www.consolevision.com/members/fackue/\n\n"); + fprintf(stderr, "Usage: %s filename\n", argv[0]); + return 1; + } + + /* The program was opened with a filename argument */ + for(i = 1; i < argc; i++) { + switch(IdentifyBin(argv[i])) { + case 0: + printf("%s is unscrambled\n", argv[i]); + break; + case 1: + printf("%s is scrambled\n", argv[i]); + break; + default: + fprintf(stderr, "%s not found\n", argv[i]); + retval = 1; + break; + } + } + + return retval; +} diff --git a/selfboot/IP.TMPL b/selfboot/IP.TMPL Binary files differ. diff --git a/selfboot/Makefile b/selfboot/Makefile @@ -0,0 +1,8 @@ +# dreamcast selfboot tools + +BINS = makeip scramble 1strdchk + +all: $(BINS) + +clean: + rm -f $(BINS) diff --git a/selfboot/README b/selfboot/README @@ -0,0 +1,54 @@ +Self-boot disc burning guide for the Dreamcast +============================================== + +Original information and software from: + + http://mc.pp.se/dc/sw.html + http://mc.pp.se/dc/cdr.html + http://dchelp.dcemulation.org/downloads/ + http://chui.dcemu.co.uk/snes4all.html + +First get the compiled binary of the game/program. Here we will use the +latest SNES4ALL release. Test if the file is scrambled with the +`1strdchk' program. + + $ ./1strdchk snes4all.bin + snes4all.bin is unscrambled + +If it is not you need to `scramble' it. It can have any given name but +keep it simple. + + $ ./scramble snes4all.bin 1ST_READ.BIN + +Generate the IP.BIN boot sector using the `makeip' program and its text +configuration file. The ip.txt contains the boot filename 1ST_READ.BIN. +Change it if you are using another filename. + + $ ./makeip ip.txt IP.BIN + +Create a dummy audio track and burn it to an empty disc. + + $ dd if=/dev/zero bs=2352 count=300 of=audio.raw + $ cdrecord -multi -audio speed=1 audio.raw + +Query the information for the session you just burned on disc. + + $ cdrecord -msinfo + 0,11702 + +Use the above information to create the image for the second session. +Create this file as follows: + + $ mkisofs -C 0,11702 -V SNES4ALL -l -o tmp.iso 1ST_READ.BIN roms/ + $ (cat IP.BIN; dd if=tmp.iso bs=2048 skip=16) > data.raw +or + $ mkisofs -C 0,11702 -V SNES4ALL -l -G IP.BIN -o data.raw \ + 1ST_READ.BIN roms/ + +Read your `cdrecord' manpage to see which of the -xa, -xa{1,2} option is +the correct CD-ROM XA mode 2 form 1 with data size multiple of 2056 +bytes. For example, `wodim' has this as -xa but `cdrtools' as -xa1. + + $ cdrecord -multi -xa1 speed=1 data.raw + +Put the disc in your Dreamcast and enjoy! diff --git a/selfboot/ip.txt b/selfboot/ip.txt @@ -0,0 +1,11 @@ +Hardware ID : SEGA SEGAKATANA +Maker ID : SEGA ENTERPRISES +Device Info : 0000 CD-ROM1/1 +Area Symbols : JUE +Peripherals : E000F10 +Product No : T0000 +Version : V1.000 +Release Date : 20000627 +Boot Filename : 1ST_READ.BIN +SW Maker Name : YOUR NAME HERE +Game Title : TITLE OF THE SOFTWARE diff --git a/selfboot/makeip.c b/selfboot/makeip.c @@ -0,0 +1,191 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#define NUM_FIELDS 11 + +struct field; + +int check_areasym(char *, struct field *); + +struct field { + char *name; + int pos; + int len; + int (*extra_check)(char *, struct field *); +} fields[NUM_FIELDS] = { + { "Hardware ID", 0x0, 0x10, NULL }, + { "Maker ID", 0x10, 0x10, NULL }, + { "Device Info", 0x20, 0x10, NULL }, + { "Area Symbols", 0x30, 0x8, check_areasym }, + { "Peripherals", 0x38, 0x8, NULL }, + { "Product No", 0x40, 0xa, NULL }, + { "Version", 0x4a, 0x6, NULL }, + { "Release Date", 0x50, 0x10, NULL }, + { "Boot Filename", 0x60, 0x10, NULL }, + { "SW Maker Name", 0x70, 0x10, NULL }, + { "Game Title", 0x80, 0x80, NULL }, +}; + +int filled_in[NUM_FIELDS]; + +int check_areasym(char *ptr, struct field *f) +{ + int i, a = 0; + for(i=0; i<f->len; i++) + switch(ptr[i]) { + case 'J': + a |= (1<<0); + break; + case 'U': + a |= (1<<1); + break; + case 'E': + a |= (1<<2); + break; + case ' ': + break; + default: + fprintf(stderr, "Unknown area symbol '%c'.\n", ptr[i]); + return 0; + } + for(i=0; i<f->len; i++) + if((a & (1<<i)) == 0) + ptr[i] = ' '; + else + ptr[i] = "JUE"[i]; + return 1; +} + +void trim(char *str) +{ + int l = strlen(str); + while(l>0 && (str[l-1] == '\r' || str[l-1] == '\n' || + str[l-1] == ' ' || str[l-1] == '\t')) + str[--l]='\0'; +} + +int parse_input(FILE *fh, char *ip) +{ + static char buf[80]; + int i; + memset(filled_in, 0, sizeof(filled_in)); + while(fgets(buf, sizeof(buf), fh)) { + char *p; + trim(buf); + if(*buf) + if((p = strchr(buf, ':'))) { + *p++ = '\0'; + trim(buf); + for(i=0; i<NUM_FIELDS; i++) + if(!strcmp(buf, fields[i].name)) + break; + if(i>=NUM_FIELDS) { + fprintf(stderr, "Unknown field \"%s\".\n", buf); + return 0; + } + memset(ip+fields[i].pos, ' ', fields[i].len); + while(*p == ' ' || *p == '\t') + p++; + if(strlen(p)>fields[i].len) { + fprintf(stderr, "Data for field \"%s\" is too long.\n", fields[i]); + return 0; + } + memcpy(ip+fields[i].pos, p, strlen(p)); + if(fields[i].extra_check!=NULL && + !(*fields[i].extra_check)(ip+fields[i].pos, &fields[i])) + return 0; + filled_in[i] = 1; + } else { + fprintf(stderr, "Missing : on line.\n"); + return 0; + } + } + + for(i=0; i<NUM_FIELDS; i++) + if(!filled_in[i]) { + fprintf(stderr, "Missing value for \"%s\".\n", fields[i]); + return 0; + } + + return 1; +} + +int calcCRC(const unsigned char *buf, int size) +{ + int i, c, n = 0xffff; + for (i = 0; i < size; i++) + { + n ^= (buf[i]<<8); + for (c = 0; c < 8; c++) + if (n & 0x8000) + n = (n << 1) ^ 4129; + else + n = (n << 1); + } + return n & 0xffff; +} + +void update_crc(char *ip) +{ + int n = calcCRC((unsigned char *)(ip+0x40), 16); + char buf[5]; + sprintf(buf, "%04X", n); + if(memcmp(buf, ip+0x20, 4)) { + printf("Setting CRC to %s (was %.4s)\n", buf, ip+0x20); + memcpy(ip+0x20, buf, 4); + } +} + +void makeip(char *ip_tmpl, char *in, char *out) +{ + static char ip[0x8000]; + FILE *fh = fopen(ip_tmpl, "rb"); + if(fh == NULL) { + fprintf(stderr, "Can't open \"%s\".\n", ip_tmpl); + exit(1); + } + if(fread(ip, 1, 0x8000, fh) != 0x8000) { + fprintf(stderr, "Read error.\n"); + exit(1); + } + fclose(fh); + fh = fopen(in, "r"); + if(fh == NULL) { + fprintf(stderr, "Can't open \"%s\".\n", in); + exit(1); + } + if(!parse_input(fh, ip)) + exit(1); + fclose(fh); + update_crc(ip); + fh = fopen(out, "wb"); + if(fh == NULL) { + fprintf(stderr, "Can't open \"%s\".\n", out); + exit(1); + } + if(fwrite(ip, 1, 0x8000, fh) != 0x8000) { + fprintf(stderr, "Write error.\n"); + exit(1); + } + fclose(fh); +} + +int main(int argc, char *argv[]) +{ + char *ip_tmpl; + + if(argc != 3) { + fprintf(stderr, "Usage: %s ip.txt IP.BIN\n", argv[0]); + exit(1); + } + + ip_tmpl = getenv("IP_TEMPLATE_FILE"); + if(ip_tmpl == NULL) + ip_tmpl = "IP.TMPL"; + + makeip(ip_tmpl, argv[1], argv[2]); + + return 0; +} diff --git a/selfboot/scramble.c b/selfboot/scramble.c @@ -0,0 +1,259 @@ +#include <stdio.h> +#include <stdlib.h> + +#define MAXCHUNK (2048*1024) + +static unsigned int seed; + +void my_srand(unsigned int n) +{ + seed = n & 0xffff; +} + +unsigned int my_rand() +{ + seed = (seed * 2109 + 9273) & 0x7fff; + return (seed + 0xc000) & 0xffff; +} + +void load(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + if(fread(ptr, 1, sz, fh) != sz) + { + fprintf(stderr, "Read error!\n"); + exit(1); + } +} + +void load_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + static int idx[MAXCHUNK/32]; + int i; + + /* Convert chunk size to number of slices */ + sz /= 32; + + /* Initialize index table with unity, + so that each slice gets loaded exactly once */ + for(i = 0; i < sz; i++) + idx[i] = i; + + for(i = sz-1; i >= 0; --i) + { + /* Select a replacement index */ + int x = (my_rand() * i) >> 16; + + /* Swap */ + int tmp = idx[i]; + idx[i] = idx[x]; + idx[x] = tmp; + + /* Load resulting slice */ + load(fh, ptr+32*idx[i], 32); + } +} + +void load_file(FILE *fh, unsigned char *ptr, unsigned long filesz) +{ + unsigned long chunksz; + + my_srand(filesz); + + /* Descramble 2 meg blocks for as long as possible, then + gradually reduce the window down to 32 bytes (1 slice) */ + for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) + while(filesz >= chunksz) + { + load_chunk(fh, ptr, chunksz); + filesz -= chunksz; + ptr += chunksz; + } + + /* Load final incomplete slice */ + if(filesz) + load(fh, ptr, filesz); +} + +void read_file(char *filename, unsigned char **ptr, unsigned long *sz) +{ + FILE *fh = fopen(filename, "rb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", filename); + exit(1); + } + if(fseek(fh, 0, SEEK_END)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + *sz = ftell(fh); + *ptr = malloc(*sz); + if( *ptr == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + if(fseek(fh, 0, SEEK_SET)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + load_file(fh, *ptr, *sz); + fclose(fh); +} + +void save(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + if(fwrite(ptr, 1, sz, fh) != sz) + { + fprintf(stderr, "Write error!\n"); + exit(1); + } +} + +void save_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + static int idx[MAXCHUNK/32]; + int i; + + /* Convert chunk size to number of slices */ + sz /= 32; + + /* Initialize index table with unity, + so that each slice gets saved exactly once */ + for(i = 0; i < sz; i++) + idx[i] = i; + + for(i = sz-1; i >= 0; --i) + { + /* Select a replacement index */ + int x = (my_rand() * i) >> 16; + + /* Swap */ + int tmp = idx[i]; + idx[i] = idx[x]; + idx[x] = tmp; + + /* Save resulting slice */ + save(fh, ptr+32*idx[i], 32); + } +} + +void save_file(FILE *fh, unsigned char *ptr, unsigned long filesz) +{ + unsigned long chunksz; + + my_srand(filesz); + + /* Descramble 2 meg blocks for as long as possible, then + gradually reduce the window down to 32 bytes (1 slice) */ + for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) + while(filesz >= chunksz) + { + save_chunk(fh, ptr, chunksz); + filesz -= chunksz; + ptr += chunksz; + } + + /* Save final incomplete slice */ + if(filesz) + save(fh, ptr, filesz); +} + +void write_file(char *filename, unsigned char *ptr, unsigned long sz) +{ + FILE *fh = fopen(filename, "wb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", filename); + exit(1); + } + save_file(fh, ptr, sz); + fclose(fh); +} + +void descramble(char *src, char *dst) +{ + unsigned char *ptr = NULL; + unsigned long sz = 0; + FILE *fh; + + read_file(src, &ptr, &sz); + + fh = fopen(dst, "wb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", dst); + exit(1); + } + if( fwrite(ptr, 1, sz, fh) != sz ) + { + fprintf(stderr, "Write error.\n"); + exit(1); + } + fclose(fh); + free(ptr); +} + +void scramble(char *src, char *dst) +{ + unsigned char *ptr = NULL; + unsigned long sz = 0; + FILE *fh; + + fh = fopen(src, "rb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", src); + exit(1); + } + if(fseek(fh, 0, SEEK_END)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + sz = ftell(fh); + ptr = malloc(sz); + if( ptr == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + if(fseek(fh, 0, SEEK_SET)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + if( fread(ptr, 1, sz, fh) != sz ) + { + fprintf(stderr, "Read error.\n"); + exit(1); + } + fclose(fh); + + write_file(dst, ptr, sz); + + free(ptr); +} + +int main(int argc, char *argv[]) +{ + int opt = 0; + + if(argc > 1 && !strcmp(argv[1], "-d")) + opt ++; + + if(argc != 3+opt) + { + fprintf(stderr, "Usage: %s [-d] from to\n", argv[0]); + exit(1); + } + + if(opt) + descramble(argv[2], argv[3]); + else + scramble(argv[1], argv[2]); + + return 0; +}