From f39b2b31fc8a604d7a3972cd15473bc8cab28684 Mon Sep 17 00:00:00 2001 From: Bobby Bingham Date: Sat, 12 Sep 2015 14:11:23 -0500 Subject: tool to create saturn boot sector --- Makefile | 29 ++++++++ src/bootinfo.h | 23 ++++++ src/satmkboot.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/symbols.c | 25 +++++++ src/symbols.h | 13 ++++ tools/bin2c | 35 +++++++++ 6 files changed, 343 insertions(+) create mode 100644 Makefile create mode 100644 src/bootinfo.h create mode 100644 src/satmkboot.c create mode 100644 src/symbols.c create mode 100644 src/symbols.h create mode 100755 tools/bin2c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..af28deb --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +CFLAGS = -Os -pipe -std=c99 -D_POSIX_C_SOURCE=200809L +LDFLAGS = + +SRCS = $(sort $(wildcard src/*.c)) +DATA = $(sort $(wildcard src/*.bin)) +OBJS = $(SRCS:.c=.o) $(DATA:.bin=.o) +BINS = bin/satmkboot + +.PHONY: all clean + +all: $(BINS) + +clean: + rm -f $(BINS) + rm -f $(OBJS) + +bin/satmkboot: \ + src/satmkboot.o \ + src/securitycode.o \ + src/symbols.o + +%.c: %.bin + tools/bin2c $< > $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +%: + $(CC) $(LDFLAGS) $^ -o $@ diff --git a/src/bootinfo.h b/src/bootinfo.h new file mode 100644 index 0000000..976f8e1 --- /dev/null +++ b/src/bootinfo.h @@ -0,0 +1,23 @@ +#ifndef SATTOOLS_BOOT_BOOTINFO_H +#define SATTOOLS_BOOT_BOOTINFO_H + +#include + +struct systemid { + char title [112]; + char maker [ 16]; + char product [ 10]; + char version [ 6]; + char reldate [ 8]; + char device [ 8]; + char regions [ 10]; + char peripherals[ 16]; + + uint32_t bootsize; + uint32_t stack_master; + uint32_t stack_slave; + uint32_t load_addr; + uint32_t load_size; +}; + +#endif diff --git a/src/satmkboot.c b/src/satmkboot.c new file mode 100644 index 0000000..6bd9823 --- /dev/null +++ b/src/satmkboot.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include + +#include "bootinfo.h" +#include "symbols.h" + +static struct systemid sysid = { + .title = "TEST TITLE ", + .maker = "SEGA TP T-000 ", + .product = "T-000000G ", + .version = "V0.001", + .reldate = "20000101", + .device = "CD-1/1 ", + .regions = "JTUBKAEL ", + .peripherals = "J ", + .bootsize = 0xe00, + .stack_master = 0, + .stack_slave = 0, + .load_addr = 0x06004000, + .load_size = 0, +}; + +static char ipbuf[0x7200]; +static char *ipfile, *outfile; + +static char *serialize_region_code(char *out, const struct symbolname *region) +{ + size_t namelen = strlen(region->name); + char *tmp = out; + char *end = out+32; + + memcpy(tmp, "\xa0\x0e\x00\x09For ", 8); tmp += 8; + memcpy(tmp, region->name, namelen); tmp += namelen; + *tmp++ = '.'; + memset(tmp, ' ', end - tmp); + return end; +} + +#define WRITE(f,p,s) fwrite(p,s,1,f) +#define WRITE32(f,v) fwrite((char[]){(v)>>24,(v)>>16,(v)>>8,(v)},4,1,f) + +static int write_output(FILE *fp) +{ + static const unsigned char zeros[16]; + extern const unsigned char securitycode[]; + extern const size_t securitycode_size; + + /* system id - 0x100 bytes */ + WRITE (fp, "SEGA SEGASATURN ", 16); + WRITE (fp, sysid.maker, 16); + WRITE (fp, sysid.product, 10); + WRITE (fp, sysid.version, 6); + WRITE (fp, sysid.reldate, 8); + WRITE (fp, sysid.device, 8); + WRITE (fp, sysid.regions, 10); + WRITE (fp, " ", 6); + WRITE (fp, sysid.peripherals, 16); + WRITE (fp, sysid.title, 112); + WRITE (fp, zeros, 16); /* reserved bytes */ + WRITE32(fp, sysid.bootsize); + WRITE (fp, zeros, 4); /* reserved bytes */ + WRITE32(fp, sysid.stack_master); + WRITE32(fp, sysid.stack_slave); + WRITE32(fp, sysid.load_addr); + WRITE32(fp, sysid.load_size); + WRITE (fp, zeros, 8); /* reserved bytes */ + + /* security code */ + WRITE(fp, securitycode, securitycode_size); + + /* initial program */ + WRITE(fp, ipbuf, sysid.bootsize - 0xe00); + return ferror(fp) ? -1 : 0; +} + +static size_t load_ip(char *filename, char *out, size_t maxsize) +{ + FILE *fp; + size_t size; + const char *errprefix = "Error loading initial program"; + + if (!(fp = fopen(filename, "rb"))) { + goto fail_perror; + } + if ((size = fread(out, 1, maxsize, fp)) < maxsize) { + /* read fewer than requested amount. determine if we hit error or eof */ + if (ferror(fp)) { + goto fail_perror; + } + } else { + /* successfully read the requested amount. verify we reached eof */ + if (fgetc(fp) != EOF) { + fprintf(stderr, "%s: exceeds maximum size\n", errprefix); + goto fail; + } + } + + fclose(fp); + return size; + +fail_perror: + perror(errprefix); +fail: + if (fp) fclose(fp); + return -1; +} + +static void usage(const char *progname) +{ + const int width = 20; + + fprintf(stderr, "usage: %s -h\n", progname); + fprintf(stderr, " %s -io\n\n", progname); + fprintf(stderr, "\t%-*s%s\n", width, "-h", "Show this help text"); + fprintf(stderr, "\t%-*s%s\n", width, "-i ip.bin", "Initial program code file"); + fprintf(stderr, "\t%-*s%s\n", width, "-o output", "Output file"); +} + +static int process_args(int argc, char **argv) +{ + int fail = 0, help = 0; + int opt; + + extern char *optarg; + extern int optind, optopt; + + while ((opt = getopt(argc, argv, ":hi:o:")) != -1) { + switch (opt) { + case 'h': + help = 1; + break; + + case 'i': + if (ipfile) { + fprintf(stderr, "Duplicate -i parameter\n"); + fail = 1; + } + ipfile = optarg; + break; + + case 'o': + if (outfile) { + fprintf(stderr, "Duplicate -o parameter\n"); + fail = 1; + } + outfile = optarg; + break; + + case ':': + fprintf(stderr, "Option '%c' missing required parameter\n", optopt); + fail = 1; + break; + + default: + fprintf(stderr, "Unknown option '%c'\n", opt); + fail = 1; + } + } + + if (help) { + usage(argv[0]); + } else { + if (argv[optind]) { + fprintf(stderr, "Unknown extra arguments\n"); + fail = 1; + } + if (!ipfile || !outfile) { + fprintf(stderr, "Missing required option\n"); + fail = 1; + } + + if (fail) { + fprintf(stderr, "Use -h option for help on correct usage.\n"); + } + } + + return fail | help; +} + +int main(int argc, char **argv) +{ + FILE *outfp = NULL; + char *ipout = ipbuf; + size_t ipsize; + + if (process_args(argc, argv)) { + return 1; + } + + for (int i = 0; i < 10 && sysid.regions[i] != ' '; i++) { + const struct symbolname *region = find_symbol(regiondefs, sysid.regions[i]); + if (region) ipout = serialize_region_code(ipout, region); + } + + if ((ipsize = load_ip(ipfile, ipout, sizeof ipbuf - (ipout - ipbuf))) == -1) { + goto fail; + } + sysid.bootsize += ipsize; + + if (!(outfp = fopen(outfile, "wb"))) { + perror("Error opening output file"); + goto fail; + } + + if (write_output(outfp)) { + perror("Error writing output"); + goto fail; + } + + fclose(outfp); + return 0; + +fail: + if (outfp) fclose(outfp); + return 1; +} diff --git a/src/symbols.c b/src/symbols.c new file mode 100644 index 0000000..4bb73bb --- /dev/null +++ b/src/symbols.c @@ -0,0 +1,25 @@ +#include + +#include "symbols.h" + +const struct symbolname regiondefs[] = { + { .symbol = 'A', .name = "ASIA PAL area" }, + { .symbol = 'B', .name = "BRAZIL" }, + { .symbol = 'E', .name = "EUROPE" }, + { .symbol = 'J', .name = "JAPAN" }, + { .symbol = 'K', .name = "KOREA" }, + { .symbol = 'L', .name = "LATIN AMERICA" }, + { .symbol = 'T', .name = "TAIWAN and PHILIPINES" }, + { .symbol = 'U', .name = "USA and CANADA" }, + { 0 } +}; + +const struct symbolname *find_symbol(const struct symbolname *symbols, char symbol) +{ + for (; symbols->symbol; symbols++) { + if (symbols->symbol == symbol) { + return symbols; + } + } + return NULL; +} diff --git a/src/symbols.h b/src/symbols.h new file mode 100644 index 0000000..78888ba --- /dev/null +++ b/src/symbols.h @@ -0,0 +1,13 @@ +#ifndef SATTOOLS_BOOT_SYMBOLS_H +#define SATTOOLS_BOOT_SYMBOLS_H + +struct symbolname { + char symbol; + const char *name; +}; + +extern const struct symbolname regiondefs[]; + +const struct symbolname *find_symbol(const struct symbolname *symbols, char symbol); + +#endif diff --git a/tools/bin2c b/tools/bin2c new file mode 100755 index 0000000..25bb6f7 --- /dev/null +++ b/tools/bin2c @@ -0,0 +1,35 @@ +#! /bin/sh + +readbyte() +{ + read dummy hex << EOF + $(dd bs=1 count=1 2> /dev/null | od -t xC) +EOF + printf "%s\n" $hex +} + +if [ $# -ne 1 ] ; then + echo "usage: $0 in.bin > out.c" + exit +fi + +varname=$(basename $1 .bin | tr -d "\n" | tr -c a-zA-Z _) +length=0 + +exec < $1 +printf "#include \n" +printf "const unsigned char %s[] = {" $varname + +byte=$(readbyte) +until [ -z $byte ] ; do + [ $(($length % 12)) -eq 0 ] && printf "\n\t" + printf "0x%s," $byte + let length+=1 + + byte=$(readbyte) +done + +[ $length -ne 0 ] && printf "\n" +printf "};\n" + +printf "const size_t %s_size = %s;\n" $varname $length -- cgit v1.2.3