diff options
Diffstat (limited to 'util/BuildImage.c')
-rw-r--r-- | util/BuildImage.c | 420 |
1 files changed, 0 insertions, 420 deletions
diff --git a/util/BuildImage.c b/util/BuildImage.c deleted file mode 100644 index f43f0b0..0000000 --- a/util/BuildImage.c +++ /dev/null @@ -1,420 +0,0 @@ -/** -** SCCS ID: @(#)BuildImage.c 2.2 1/16/25 -** -** @file BuildImage.c -** -** @author K. Reek -** @author Jon Coles -** @author Warren R. Carithers -** @author Garrett C. Smith -** -** Modify the bootstrap image to include the information -** on the programs to be loaded, and produce the file -** that contains the concatenation of these programs. -** -*/ - -#define _POSIX_C_SOURCE 200809L - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> - -#define TRUE 1 -#define FALSE 0 - -#define DRIVE_FLOPPY 0x00 -#define DRIVE_USB 0x80 - -#define SECT_SIZE 512 - -char *progname; /* invocation name of this program */ -char *bootstrap_filename; /* path of file holding bootstrap program */ -char *output_filename; /* path of disk image file */ -FILE *out; /* output stream for disk image file */ -short drive = DRIVE_USB; /* boot drive */ - -/* -** Array into which program information will be stored, starting at the -** end and moving back toward the front. The array is the same size as -** a sector, which is guaranteed to be larger than the maximum possible -** space available for this stuff in the bootstrap image. Thus, the -** bootstrap image itself (and the amount of space available on the -** device) are the only limiting factors on how many program sections -** can be loaded. -*/ - -#define N_INFO (SECT_SIZE / sizeof(short)) - -short info[N_INFO]; -int n_info = N_INFO; - -/** -** quit with an appropriate message -** -** @param msg NULL, or a message to be printed to stderr -** @param call_perror non-zero if perror() should be used; else, -** fprintf() will be used -** -** does not return -*/ -void quit(char *msg, int call_perror) -{ - if (msg != NULL) { - // preserve the error code in case we need it - int err_num = errno; - fprintf(stderr, "%s: ", progname); - errno = err_num; - if (call_perror) { - perror(msg); - } else { - fprintf(stderr, "%s\n", msg); - } - } - if (output_filename != NULL) { - unlink(output_filename); - } - exit(EXIT_FAILURE); - // NOTREACHED -} - -const char usage_error_msg[] = - "\nUsage: %s [ -d drive ] -b bootfile -o outfile { progfile loadpt } ...\n\n" - "\t'drive' is either 'floppy' or 'usb' (default 'usb')\n\n" - "\tThere must be at least one program file and load point.\n\n" - "\tLoad points may be specified either as 32-bit quantities in hex,\n" - "\tdecimal or octal (e.g. 0x10c00, 68608, 0206000 are all equivalent),\n" - "\tor as an explicit segment:offset pair whose digits are always\n" - "\tinterpreted as hexadecimal values (e.g. 10c0:0000, 1000:0c00 are\n" - "\tboth equivalent to the previous examples).\n\n"; - -/** -** print a usage message and then call quit() -** -** does not return -*/ -void usage_error(void) -{ - fprintf(stderr, usage_error_msg, progname); - quit(NULL, FALSE); - // NOTREACHED -} - -/** -** copy the contents of a binary file into the output file, padding the -** last sector with NUL bytes -** -** @param in open FILE to be read -** @return the number of sectors copied from the file -*/ -int copy_file(FILE *in) -{ - int n_sectors = 0; - char buf[SECT_SIZE]; - int n_bytes; - int i; - - /* - ** Copy the file to the output, being careful that the - ** last sector is padded with null bytes out to the - ** sector size. - */ - n_sectors = 0; - while ((n_bytes = fread(buf, 1, sizeof(buf), in)) > 0) { - // pad this sector out to block size - if (n_bytes < sizeof(buf)) { - int i; - - for (i = n_bytes; i < sizeof(buf); i += 1) { - buf[i] = '\0'; - } - } - if (fwrite(buf, 1, sizeof(buf), out) != sizeof(buf)) { - quit("Write failed or was wrong size", FALSE); - } - n_sectors += 1; - } - return n_sectors; -} - -/** -** process a file whose contents should be at a specific' -** address in memory when the program is loaded -** -** @param name path to the file to be copied -** @param addr string containing the load address -*/ -void process_file(char *name, char *addr) -{ - long address; - short segment, offset; - int n_bytes; - - /* - ** Open the input file. - */ - FILE *in = fopen(name, "rb"); - if (in == NULL) { - quit(name, TRUE); - } - - /* - ** Copy the file to the output, being careful that the - ** last block is padded with null bytes. - */ - int n_sectors = copy_file(in); - fclose(in); - - /* - ** Decode the address they gave us. We'll accept two forms: - ** "nnnn:nnnn" for a segment:offset value (assumed to be hex), - ** "nnnnnnn" for a decimal, hex, or octal value - */ - int valid_address = FALSE; - char *cp = strchr(addr, ':'); - if (cp != NULL) { - // must be in nnnn:nnnn form exactly - if (strlen(addr) == 9 && cp == addr + 4) { - char *ep1, *ep2; - int a1, a2; - - segment = strtol(addr, &ep1, 16); - offset = strtol(addr + 5, &ep2, 16); - address = (segment << 4) + offset; - valid_address = *ep1 == '\0' && *ep2 == '\0'; - } else { - fprintf(stderr, "Bad address format - '%s'\n", addr); - quit(NULL, FALSE); - } - } else { - // just a number, possibly hex or octal - char *ep; - - address = strtol(addr, &ep, 0); - segment = (short)(address >> 4); - offset = (short)(address & 0xf); - valid_address = *ep == '\0' && address <= 0x0009ffff; - } - - if (!valid_address) { - fprintf(stderr, "%s: Invalid address: %s\n", progname, addr); - quit(NULL, FALSE); - } - - /* - ** Make sure the program will fit! - */ - if (address + n_sectors * SECT_SIZE > 0x0009ffff) { - fprintf(stderr, "Program %s too large to start at 0x%08x\n", name, - (unsigned int)address); - quit(NULL, FALSE); - } - - if (n_info < 3) { - quit("Too many programs!", FALSE); - } - - /* - ** Looks good: report and store the information. - */ - fprintf(stderr, " %s: %d sectors, loaded at 0x%x\n", name, n_sectors, - (unsigned int)address); - - info[--n_info] = n_sectors; - info[--n_info] = segment; - info[--n_info] = offset; -} - -/* -** Global variables set by getopt() -*/ - -extern int optind, optopt; -extern char *optarg; - -/** -** process the command-line arguments -** -** @param ac the count of entries in av -** @param av the argument vector -*/ -void process_args(int ac, char **av) -{ - int c; - - while ((c = getopt(ac, av, ":d:o:b:")) != EOF) { - switch (c) { - case ':': /* missing arg value */ - fprintf(stderr, "missing operand after -%c\n", optopt); - /* FALL THROUGH */ - - case '?': /* error */ - usage_error(); - /* NOTREACHED */ - - case 'b': /* -b bootstrap_file */ - bootstrap_filename = optarg; - break; - - case 'd': /* -d drive */ - switch (*optarg) { - case 'f': - drive = DRIVE_FLOPPY; - break; - case 'u': - drive = DRIVE_USB; - break; - default: - usage_error(); - } - break; - - case 'o': /* -o output_file */ - output_filename = optarg; - break; - - default: - usage_error(); - } - } - - if (!bootstrap_filename) { - fprintf(stderr, "%s: no bootstrap file specified\n", progname); - exit(2); - } - - if (!output_filename) { - fprintf(stderr, "%s: no disk image file specified\n", progname); - exit(2); - } - - /* - ** Must have at least two remaining arguments (file to load, - ** address at which it should be loaded), and must have an - ** even number of remaining arguments. - */ - int remain = ac - optind; - if (remain < 2 || (remain & 1) != 0) { - usage_error(); - } -} - -/** -** build a bootable image file from one or more binary files -** -** usage: -** BuildImage [ -d drive ] -b bootfile -o outfile { binfile1 loadpt1 } ... ] -** -** @param ac command-line argument count -** @param av command-line argument vector -** @return EXIT_SUCCESS or EXIT_FAILURE -*/ -int main(int ac, char **av) -{ - FILE *bootimage; - int bootimage_size; - int n_bytes, n_words; - short existing_data[N_INFO]; - int i; - - /* - ** Save the program name for error messages - */ - progname = strrchr(av[0], '/'); - if (progname != NULL) { - progname++; - } else { - progname = av[0]; - } - - /* - ** Process arguments - */ - process_args(ac, av); - - /* - ** Open the output file - */ - - out = fopen(output_filename, "wb+"); - if (out == NULL) { - quit(output_filename, TRUE); - } - - /* - ** Open the bootstrap file and copy it to the output image. - */ - bootimage = fopen(bootstrap_filename, "rb"); - if (bootimage == NULL) { - quit(bootstrap_filename, TRUE); - } - - /* - ** Remember the size of the bootstrap for later, as we - ** need to patch some things into it - */ - int n_sectors = copy_file(bootimage); - fclose(bootimage); - - bootimage_size = n_sectors * SECT_SIZE; - fprintf(stderr, " %s: %d sectors\n", bootstrap_filename, n_sectors); - - /* - ** Process the programs one by one - */ - ac -= optind; - av += optind; - while (ac >= 2) { - process_file(av[0], av[1]); - ac -= 2; - av += 2; - } - - /* - ** Check for oddball leftover argument - */ - if (ac > 0) { - usage_error(); - } - - /* - ** Seek to where the array of module data must begin and read - ** what's already there. - */ - n_words = (N_INFO - n_info); - n_bytes = n_words * sizeof(info[0]); - fseek(out, bootimage_size - n_bytes, SEEK_SET); - if (fread(existing_data, sizeof(info[0]), n_words, out) != n_words) { - quit("Read from boot image failed or was too short", FALSE); - } - - /* - ** If that space is non-zero, we have a problem - */ - for (i = 0; i < n_words; i += 1) { - if (existing_data[i] != 0) { - quit("Too many programs to load!", FALSE); - } - } - - /* - ** We know that we're only overwriting zeros at the end of - ** the bootstrap image, so it is ok to go ahead and do it. - */ - fseek(out, bootimage_size - n_bytes, SEEK_SET); - if (fwrite(info + n_info, sizeof(info[0]), n_words, out) != n_words) { - quit("Write to boot image failed or was too short", FALSE); - } - - /* - ** Write the drive index to the image. - */ - fseek(out, 508, SEEK_SET); - fwrite((void *)&drive, sizeof(drive), 1, out); - - fclose(out); - - return EXIT_SUCCESS; -} |