summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile29
-rw-r--r--src/bootinfo.h23
-rw-r--r--src/satmkboot.c218
-rw-r--r--src/symbols.c25
-rw-r--r--src/symbols.h13
-rwxr-xr-xtools/bin2c35
6 files changed, 343 insertions, 0 deletions
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 <stdint.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#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 <stddef.h>
+
+#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 <stddef.h>\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