#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; }