#include #include #include #include #include #include #include "bootinfo.h" #include "paths.h" #include "symbols.h" static struct systemid sysid = { .magic = "SEGA SEGASATURN ", .maker = "SEGA TP T-000 ", .product = "T-000000G ", .version = "V0.001", .reldate = "20000101", .device = "CD-1/1 ", .regions = "JTUBKAEL ", .peripherals = "J ", .padding1 = " ", .title = "TEST TITLE ", .bootsize = 0xe00, .stack_master = 0, .stack_slave = 0, .load_addr = 0x06004000, .load_size = 0, }; static char ipbuf[0x7f00]; static char *ipfile, *outfile; static void serialize_region_code(char *out, const struct symbolname *region) { static const char defcode[32] = "\xa0\x0e\x00\x09" "For "; size_t namelen = region ? strlen(region->name) : 0; memcpy(out, defcode, sizeof defcode); if (namelen) memcpy(out+8, region->name, namelen); out[8+namelen] = '.'; } #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) { /* system id - 0x100 bytes */ WRITE (fp, &sysid, offsetof(struct systemid, bootsize)); WRITE32(fp, sysid.bootsize); WRITE32(fp, 0); /* reserved bytes */ WRITE32(fp, sysid.stack_master); WRITE32(fp, sysid.stack_slave); WRITE32(fp, sysid.load_addr); WRITE32(fp, sysid.load_size); WRITE32(fp, 0); /* reserved bytes */ WRITE32(fp, 0); /* reserved bytes */ /* initial program */ WRITE(fp, ipbuf, sysid.bootsize - 0x100); return ferror(fp) ? -1 : 0; } static FILE *open_installed_boot_file(const char *filename) { static const char *bootpath = DATA_PATH "/boot"; char *path = malloc(strlen(bootpath) + strlen(filename) + 2); if (!path) return NULL; sprintf(path, "%s/%s", bootpath, filename); return fopen(path, "rb"); } static FILE *open_boot_file(const char *filename) { FILE *fp = fopen(filename, "rb"); if (fp) return fp; if (!strchr(filename, '/')) return open_installed_boot_file(filename); return NULL; } static size_t readfile(FILE *fp, char *out, size_t maxsize, const char *errprefix) { size_t size = fread(out, 1, maxsize, fp); if (size == maxsize && fgetc(fp) != EOF) { fprintf(stderr, "%s: exceeds maximum size\n", errprefix); size = -1; } return size; } static size_t load_security_code(char *out) { const char *errprefix = "Error loading security code"; FILE *fp; if (!(fp = fopen(DATA_PATH "/securitycode.bin", "rb"))) { perror(errprefix); return -1; } size_t size = readfile(fp, out, 0xd00, errprefix); if (size != -1 && size != 0xd00) fprintf(stderr, "%s: wrong size\n", errprefix); fclose(fp); return size; } static size_t load_ip(char *out, size_t maxsize) { FILE *fp = ipfile ? open_boot_file(ipfile) : open_installed_boot_file("simple"); const char *errprefix = "Error loading initial program"; if (!fp) { perror(errprefix); return -1; } size_t size = readfile(fp, out, maxsize, errprefix); fclose(fp); return size; } static void print_symbols(int width, const struct symbolname *symbols) { for (; symbols->symbol; symbols++) { printf("\t%*s%c: %s\n", width+4, "", symbols->symbol, symbols->name); } } static void usage(const char *progname) { const int width = 20; printf("usage: %s -h\n", progname); printf(" %s -o[iprms]\n\n", progname); printf("\t%-*s%s\n", width, "-h", "Show this help text"); printf("\t%-*s%s\n", width, "-o output", "Output file"); printf("\t%-*s%s\n", width, "-i ip.bin", "Initial program code file"); printf("\t%-*s%s\n", width, "-p peripherals", "Supported peripherals (default: control pad):"); print_symbols(width, peripheraldefs); printf("\t%-*s%s\n", width, "-r regions", "Geographical regions (default: all):"); print_symbols(width, regiondefs); printf("\t%-*s%s\n", width, "-m master_stack", "Master stack address (default 0x06002000)"); printf("\t%-*s%s\n", width, "-s slave_stack", "Slave stack address (default 0x06001000)"); exit(0); } static int process_symbols(const char *progname, char *list, size_t size, const char *arg) { while (size-- && *arg) *list++ = *arg++; while (size--) *list++ = ' '; return *arg; } static int process_address(const char *progname, uint32_t *addr, const char *arg) { char *end; errno = 0; unsigned long val = strtoul(arg, &end, 16); if (end == arg || *end || errno || val > (uint32_t)-1) return 1; *addr = val; return 0; } #define FLAG_o (1U << 3) static int process_args(int argc, char **argv) { uint32_t seen = 0; int opt, fail = 0; extern char *optarg; extern int optind, optopt; static const char *optpat = "hi:o:p:r:m:s:"; while ((opt = getopt(argc, argv, optpat)) != -1) { uint32_t flag = opt == '?' ? 0 : 1U << strchr(optpat, opt) - optpat; if (seen & flag) { fprintf(stderr, "%s: Duplicate option -%c\n", argv[0], opt); fail = 1; continue; } seen |= flag; switch (opt) { case 'h': usage(argv[0]); case 'i': ipfile = optarg; break; case 'o': outfile = optarg; break; case 'm': if (process_address(argv[0], &sysid.stack_master, optarg)) { fprintf(stderr, "%s: Invalid master stack\n", argv[0]); fail = 1; } break; case 's': if (process_address(argv[0], &sysid.stack_slave, optarg)) { fprintf(stderr, "%s: Invalid slave stack\n", argv[0]); fail = 1; } break; case 'p': if (process_symbols(argv[0], sysid.peripherals, sizeof sysid.peripherals, optarg)) { fprintf(stderr, "%s: Too many peripherals specified (max 16)\n", argv[0]); fail = 1; } break; case 'r': if (process_symbols(argv[0], sysid.regions, sizeof sysid.regions, optarg)) { fprintf(stderr, "%s: Too many regions specified (max 10)\n", argv[0]); fail = 1; } break; default: fail = 1; } } if (!(seen & FLAG_o)) { fprintf(stderr, "%s: Missing required option -o\n", argv[0]); fail = 1; } if (argv[optind]) { fprintf(stderr, "%s: Unknown option '%s'\n", argv[0], argv[optind]); fail = 1; } if (fail) fprintf(stderr, "\nUse -h option for help on correct usage.\n"); return fail; } 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 < 8; i++) { serialize_region_code(ipout, find_symbol(regiondefs, sysid.regions[i])); ipout += 32; sysid.bootsize += 32; } ipsize = load_security_code(ipout); if (ipsize == -1) goto fail; ipout += ipsize; ipsize = load_ip(ipout, sizeof ipbuf - (ipout - ipbuf)); if (ipsize == -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; }