diff options
author | Bobby Bingham <koorogi@koorogi.info> | 2015-09-12 14:11:23 -0500 |
---|---|---|
committer | Bobby Bingham <koorogi@koorogi.info> | 2015-09-15 22:43:32 -0500 |
commit | f39b2b31fc8a604d7a3972cd15473bc8cab28684 (patch) | |
tree | 0480b2ca50965fb5c3c4863ff275850e4196a994 /src |
tool to create saturn boot sector
Diffstat (limited to 'src')
-rw-r--r-- | src/bootinfo.h | 23 | ||||
-rw-r--r-- | src/satmkboot.c | 218 | ||||
-rw-r--r-- | src/symbols.c | 25 | ||||
-rw-r--r-- | src/symbols.h | 13 |
4 files changed, 279 insertions, 0 deletions
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 |