diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/BuildImage.c | 420 | ||||
-rw-r--r-- | util/default.ld | 247 | ||||
-rw-r--r-- | util/gdbinit | 31 | ||||
-rw-r--r-- | util/listblob.c | 240 | ||||
-rw-r--r-- | util/mkblob.c | 321 |
5 files changed, 0 insertions, 1259 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; -} diff --git a/util/default.ld b/util/default.ld deleted file mode 100644 index 0c600e4..0000000 --- a/util/default.ld +++ /dev/null @@ -1,247 +0,0 @@ -GNU ld (GNU Binutils for Ubuntu) 2.30 - Supported emulations: - elf_x86_64 - elf32_x86_64 - elf_i386 - elf_iamcu - i386linux - elf_l1om - elf_k1om - i386pep - i386pe -using internal linker script: -================================================== -/* Script for -z combreloc: combine and sort reloc sections */ -/* Copyright (C) 2014-2018 Free Software Foundation, Inc. - Copying and distribution of this script, with or without modification, - are permitted in any medium without royalty provided the copyright - notice and this notice are preserved. */ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", - "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) -SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; - .interp : { *(.interp) } - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) - *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) - *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) - *(.rela.ifunc) - } - .rela.plt : - { - *(.rela.plt) - PROVIDE_HIDDEN (__rela_iplt_start = .); - *(.rela.iplt) - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .init : - { - KEEP (*(SORT_NONE(.init))) - } - .plt : { *(.plt) *(.iplt) } -.plt.got : { *(.plt.got) } -.plt.sec : { *(.plt.sec) } - .text : - { - *(.text.unlikely .text.*_unlikely .text.unlikely.*) - *(.text.exit .text.exit.*) - *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } - .fini : - { - KEEP (*(SORT_NONE(.fini))) - } - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table - .gcc_except_table.*) } - .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } - /* These sections are generated by the Sun/Oracle C++ compiler. */ - .exception_ranges : ONLY_IF_RO { *(.exception_ranges - .exception_ranges*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } - .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } - .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) - KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) - PROVIDE_HIDDEN (__init_array_end = .); - } - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) - KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) - PROVIDE_HIDDEN (__fini_array_end = .); - } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*crtbegin?.o(.ctors)) - /* We don't want to include the .ctor section from - the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } - .dynamic : { *(.dynamic) } - .got : { *(.got) *(.igot) } - . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); - .got.plt : { *(.got.plt) *(.igot.plt) } - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; PROVIDE (edata = .); - . = .; - __bss_start = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 64 / 8 : 1); - } - .lbss : - { - *(.dynlbss) - *(.lbss .lbss.* .gnu.linkonce.lb.*) - *(LARGE_COMMON) - } - . = ALIGN(64 / 8); - . = SEGMENT_START("ldata-segment", .); - .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : - { - *(.lrodata .lrodata.* .gnu.linkonce.lr.*) - } - .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : - { - *(.ldata .ldata.* .gnu.linkonce.l.*) - . = ALIGN(. != 0 ? 64 / 8 : 1); - } - . = ALIGN(64 / 8); - _end = .; PROVIDE (end = .); - . = DATA_SEGMENT_END (.); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* DWARF 3 */ - .debug_pubtypes 0 : { *(.debug_pubtypes) } - .debug_ranges 0 : { *(.debug_ranges) } - /* DWARF Extension. */ - .debug_macro 0 : { *(.debug_macro) } - .debug_addr 0 : { *(.debug_addr) } - .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } -} - - -================================================== diff --git a/util/gdbinit b/util/gdbinit deleted file mode 100644 index ca2c885..0000000 --- a/util/gdbinit +++ /dev/null @@ -1,31 +0,0 @@ -# adapted from the xv6 .gdbinit.tmpl file -set $lastcs = -1 - -define hook-stop - # There doesn't seem to be a good way to detect if we're in 16- or - # 32-bit mode, but we always run with CS == 8 in 32-bit mode. - if $cs == 8 || $cs == 27 - if $lastcs != 8 && $lastcs != 27 - set architecture i386 - end - x/i $pc - else - if $lastcs == -1 || $lastcs == 8 || $lastcs == 27 - set architecture i8086 - end - # Translate the segment:offset into a physical address - printf "[%4x:%4x] ", $cs, $eip - x/i $cs*16+$eip - end - set $lastcs = $cs -end - -echo + target remote localhost:1337\n -target remote localhost:1337 - -# If this fails, it's probably because your GDB doesn't support ELF. -# Look at the tools page at -# http://pdos.csail.mit.edu/6.828/2009/tools.html -# for instructions on building GDB with ELF support. -echo + symbol-file build/kernel/kernel\n -symbol-file build/kernel/kernel diff --git a/util/listblob.c b/util/listblob.c deleted file mode 100644 index e6266a3..0000000 --- a/util/listblob.c +++ /dev/null @@ -1,240 +0,0 @@ -/** -** @file listblob.c -** -** @author Warren R. Carithers -** -** Examine a binary blob of ELF files. -*/ -#define _DEFAULT_SOURCE -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include <unistd.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <elf.h> -#include <ctype.h> - -/* -** Blob file organization -** -** The file begins with a four-byte magic number and a four-byte integer -** indicating the number of ELF files contained in the blob. This is -** followed by an array of 32-byte file entries, and then the contents -** of the ELF files in the order they appear in the program file table. -** -** Bytes Contents -** ----- ---------------------------- -** 0 - 3 File magic number ("BLB\0") -** 4 - 7 Number of ELF files in blob ("n") -** 8 - n*32+8 Program file table -** n*32+9 - ? ELF file contents -** -** Each program file table entry contains the following information: -** -** name File name (up to 19 characters long) -** offset Byte offset to the ELF header for this file -** size Size of this ELF file, in bytes -** flags Flags related to this file -*/ - -// blob header: 8 bytes -typedef struct header_s { - char magic[4]; - uint32_t num; -} header_t; - -// The program table entry is 32 bytes long. To accomplish this, the -// name field is 20 bytes long, which allows file names of 19 characters -// (followed by a trailing NUL byte). -// -// If that field is made longer, it should be incremented in multiples -// of four to avoid the insertion of padding bytes. -#define NAMELEN 20 - -// program descriptor: 32 bytes -typedef struct prog_s { - char name[NAMELEN]; // truncated name (19 chars plus NUL) - uint32_t offset; // offset from the beginning of the blob - uint32_t size; // size of this ELF module - uint32_t flags; // miscellaneous flags -} prog_t; - -// modules must be written as multiples of eight bytes -#define FL_ROUNDUP 0x00000001 - -// mask for mod 8 checking -#define FSIZE_MASK 0x00000007 - -// program list entry -typedef struct node_s { - prog_t *data; - struct node_s *next; -} node_t; - -node_t *progs, *last_prog; // list pointers -uint32_t n_progs; // number of files being copied -uint32_t offset; // current file area offset -bool defs = false; // print CPP #defines? -bool enums = false; // print C enums? - -// header string for the userids.h file -const char header[] = - "/**\n" - "** @file userids.h\n" - "**\n" - "** @author Warren R. Carithers\n" - "**\n" - "** @brief IDs for user-level programs\n" - "**\n" - "** NOTE: this file is automatically generated when the user.img file\n" - "** is created. Do not edit this manually!\n" - "*/\n" - "\n" - "#ifndef USERIDS_H_\n" - "#define USERIDS_H_\n" - "\n" - "#ifndef ASM_SRC\n" - "/*\n" - "** These IDs are used to identify the various user programs.\n" - "** Each call to exec() will provide one of these as the first\n" - "** argument.\n" - "**\n" - "** This list should be updated if/when the collection of\n" - "** user processes changes.\n" - "*/\n" - "enum users_e {"; - -// trailer string for the userids.h file -const char trailer[] = "\n\t// sentinel\n\t, N_USERS\n" - "};\n" - "#endif /* !ASM_SRC */\n" - "\n" - "#endif"; - -/** -** Name: process -** -** Process a program list entry -** -** @param num Program list index -** @param prog Pointer to the program list entry -*/ -void process(uint32_t num, prog_t *prog) -{ - if (defs || enums) { - char *slash = strrchr(prog->name, '/'); - if (slash == NULL) { - slash = prog->name; - } else { - ++slash; - } - - slash[0] = toupper(slash[0]); - - if (defs) { - // just printing #define statements - printf("#define %-15s %2d\n", prog->name, num); - - } else { - // printing a new userids.h file - if (num == 0) { - // first one, so print the file header - puts(header); - putchar('\t'); - } else { - // second or later entry; limit to 8 per line - fputs(((num & 0x7) == 0) ? ",\n\t" : ", ", stdout); - } - printf("%s", prog->name); - } - - } else { - // just printing information - printf("Entry %2d: ", num); - printf("%-s,", prog->name); - printf(" offset 0x%x, size 0x%x, flags %08x\n", prog->offset, - prog->size, prog->flags); - } -} - -void usage(char *name) -{ - fprintf(stderr, "usage: %s [-d | -e] blob_name\n", name); -} - -int main(int argc, char *argv[]) -{ - if (argc < 2 || argc > 3) { - usage(argv[0]); - exit(1); - } - - int nameix = 1; - - // could use getopt() for this, but this is easy enough - if (argc == 3) { - if (strcmp(argv[1], "-d") == 0) { - defs = true; - } else if (strcmp(argv[1], "-e") == 0) { - enums = true; - } else { - usage(argv[0]); - exit(1); - } - nameix = 2; - } - - char *name = argv[nameix]; - - int fd = open(name, O_RDONLY); - if (fd < 0) { - perror(name); - exit(1); - } - - header_t hdr; - - int n = read(fd, &hdr, sizeof(header_t)); - if (n != sizeof(header_t)) { - fprintf(stderr, "%s: header read returned only %d bytes\n", name, n); - close(fd); - exit(1); - } - - if (strcmp(hdr.magic, "BLB") != 0) { - fprintf(stderr, "%s: bad magic number\n", name); - close(fd); - exit(1); - } - - if (hdr.num < 1) { - fprintf(stderr, "%s: no programs in blob?\n", name); - close(fd); - exit(1); - } - - prog_t progs[hdr.num]; - - n = read(fd, progs, hdr.num * sizeof(prog_t)); - if (n != (int)(hdr.num * sizeof(prog_t))) { - fprintf(stderr, "%s: prog table only %d bytes, expected %lu\n", name, n, - hdr.num * sizeof(prog_t)); - close(fd); - exit(1); - } - - for (uint32_t i = 0; i < hdr.num; ++i) { - process(i, &progs[i]); - } - - if (enums) { - // print the file trailer - puts(trailer); - } - - close(fd); - return 0; -} diff --git a/util/mkblob.c b/util/mkblob.c deleted file mode 100644 index ea6a946..0000000 --- a/util/mkblob.c +++ /dev/null @@ -1,321 +0,0 @@ -/** -** @file mkblob.c -** -** @author Warren R. Carithers -** -** Create a binary blob from a collection of ELF files. -*/ -#define _DEFAULT_SOURCE - -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <elf.h> - -/* -** Blob file organization -** -** The file begins with a four-byte magic number and a four-byte integer -** indicating the number of ELF files contained in the blob. This is -** followed by an array of 32-byte file table entries, and then the contents -** of the ELF files in the order they appear in the program file table. -** -** Bytes Contents -** ----- ---------------------------- -** 0 - 3 File magic number ("BLB\0") -** 4 - 7 Number of ELF files in blob ("n") -** 8 - n*32+8 Program file table -** n*32+9 - ? ELF file contents -** -** Each program file table entry contains the following information: -** -** name File name (up to 19 characters long) -** offset Byte offset to the ELF header for this file -** size Size of this ELF file, in bytes -** flags Flags related to this file -*/ - -// blob header -typedef struct header_s { - char magic[4]; - uint32_t num; -} header_t; - -// length of the file name field -#define NAMELEN 20 - -// program descriptor -typedef struct prog_s { - char name[NAMELEN]; // truncated name (15 chars) - uint32_t offset; // offset from the beginning of the blob - uint32_t size; // size of this ELF module - uint32_t flags; // miscellaneous flags -} prog_t; - -// modules must be written as multiples of eight bytes -#define FL_ROUNDUP 0x00000001 - -// mask for mod 8 checking -#define FSIZE_MASK 0x00000007 - -// program list entry -typedef struct node_s { - prog_t *data; - char *fullname; - struct node_s *next; -} node_t; - -node_t *progs, *last_prog; // list pointers -uint32_t n_progs; // number of files being copied -uint32_t offset; // current file area offset - -/** -** Name: process -** -** Do the initial processing for an ELF file -** -** @param name The name of the file -*/ -void process(const char *name) -{ - struct stat info; - - // check the name length - if (strlen(name) >= NAMELEN) { - fprintf(stderr, "%s: name exceeds length limit (%d)\n", name, - NAMELEN - 1); - return; - } - - // does it exist? - if (stat(name, &info) < 0) { - perror(name); - return; - } - - // is it a regular file? - if (!S_ISREG(info.st_mode)) { - fprintf(stderr, "%s: not a regular file\n", name); - return; - } - - // open it and check the file header - int fd = open(name, O_RDONLY); - if (fd < 0) { - perror(name); - return; - } - - // read and check the ELF header - Elf32_Ehdr hdr; - int n = read(fd, &hdr, sizeof(Elf32_Ehdr)); - close(fd); - - if (n != sizeof(Elf32_Ehdr)) { - fprintf(stderr, "%s: header read was short - only %d\n", name, n); - return; - } - - if (hdr.e_ident[EI_MAG0] != ELFMAG0 || hdr.e_ident[EI_MAG1] != ELFMAG1 || - hdr.e_ident[EI_MAG2] != ELFMAG2 || hdr.e_ident[EI_MAG3] != ELFMAG3) { - fprintf(stderr, "%s: bad ELF magic number\n", name); - return; - } - - // ok, it's a valid ELF file - create the prog list entry - prog_t *new = calloc(1, sizeof(prog_t)); - if (new == NULL) { - fprintf(stderr, "%s: calloc prog returned NULL\n", name); - return; - } - - node_t *node = calloc(1, sizeof(node_t)); - if (node == NULL) { - free(new); - fprintf(stderr, "%s: calloc node returned NULL\n", name); - return; - } - - node->data = new; - node->fullname = strdup(name); - - // copy in the name - - // only want the last component - const char *slash = strrchr(name, '/'); - if (slash == NULL) { - // only the file name - slash = name; - } else { - // skip the slash - ++slash; - } - - strncpy(new->name, slash, sizeof(new->name) - 1); - new->offset = offset; - new->size = info.st_size; - - // bump our counters - ++n_progs; - offset += info.st_size; - - // make sure it's a multiple of eight bytes long - if ((info.st_size & FSIZE_MASK) != 0) { - // nope, so we must round it up when we write it out - new->flags |= FL_ROUNDUP; - // increases the offset to the next file - offset += 8 - (info.st_size & FSIZE_MASK); - } - - // add to the list - if (progs == NULL) { - // first entry - progs = node; - } else { - // add to the end - if (last_prog == NULL) { - fprintf(stderr, "%s: progs ! NULL, last_prog is NULL\n", name); - free(new); - free(node->fullname); - free(node); - return; - } - last_prog->next = node; - } - last_prog = node; -} - -/** -** Name: copy -** -** Copy the contents of a program list entry into the blob -** -** @param ofd The output FILE* to be written -** @param prog Pointer to the program list entry for the file -*/ -void copy(FILE *ofd, node_t *node) -{ - prog_t *prog = node->data; - - // open it so we can copy it - int fd = open(node->fullname, O_RDONLY); - if (fd < 0) { - perror(node->fullname); - return; - } - - uint8_t buf[512]; - - // copy it block-by-block - do { - int n = read(fd, buf, 512); - // no bytes --> we're done - if (n < 1) { - break; - } - // copy it, and verify the copy count - int k = fwrite(buf, 1, n, ofd); - if (k != n) { - fprintf(stderr, "%s: write of %d returned %d\n", prog->name, n, k); - } - } while (1); - - printf("%s: copied %d", prog->name, prog->size); - - // do we need to round up? - if ((prog->flags & FL_ROUNDUP) != 0) { - // we'll fill with NUL bytes - uint64_t filler = 0; - - // how many filler bytes do we need? - int nbytes = 8 - (prog->size & FSIZE_MASK); - - // do it, and check the transfer count to be sure - int n = fwrite(&filler, 1, nbytes, ofd); - if (n != nbytes) { - fprintf(stderr, "%s: fill write of %d returned %d\n", prog->name, - nbytes, n); - } - - // report that we added some filler bytes - printf("(+%d)", n); - } - puts(" bytes"); - - // all done! - close(fd); -} - -int main(int argc, char *argv[]) -{ - // construct program list - for (int i = 1; i < argc; ++i) { - process(argv[i]); - } - - if (n_progs < 1) { - fputs("Nothing to do... exiting.", stderr); - exit(0); - } - - // create the output file - FILE *ofd; - ofd = fopen("user.img", "wb"); - if (ofd == NULL) { - perror("user.img"); - exit(1); - } - - printf("Processing %d ELF files\n", n_progs); - - // we need to adjust the offset values so they are relative to the - // start of the blob, not relative to the start of the file area. - // do this by adding the sum of the file header and program entries - // to each offset field. - - uint32_t hlen = sizeof(header_t) + n_progs * sizeof(prog_t); - node_t *curr = progs; - while (curr != NULL) { - curr->data->offset += hlen; - curr = curr->next; - } - - // write out the blob header - header_t hdr = { "BLB", n_progs }; - if (fwrite(&hdr, sizeof(header_t), 1, ofd) != 1) { - perror("blob header"); - fclose(ofd); - exit(1); - } - - // next, the program entries - curr = progs; - while (curr != NULL) { - if (fwrite(curr->data, sizeof(prog_t), 1, ofd) != 1) { - perror("blob prog entry write"); - fclose(ofd); - exit(1); - } - curr = curr->next; - } - - // finally, copy the files - curr = progs; - while (curr != NULL) { - prog_t *prog = curr->data; - copy(ofd, curr); - node_t *tmp = curr; - curr = curr->next; - free(tmp->data); - free(tmp->fullname); - free(tmp); - } - - fclose(ofd); - - return 0; -} |