/* Copyright (C) 2000 by Anders Larsen and Baumer Ident GmbH Slightly adapted for the winterm.gaast.project by Wilmer van der Gaast This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include int verbose = 0; u_int8_t signature[7] = "B000FF\n"; u_int32_t start = 0x90000; u_int32_t test = 0x17db90; int usage(char *const argv0) { fprintf(stderr, "Puts a kernel and (optionally) initrd together in one nk.bin file.\n" "\n" "Read the documentation before using this tool!\n" "\n" "Usage: %s -k []\n" "\n" "Options:\n" "-k \tKernel file (MUST be in bzImage format)\n" "-i \tInitial ramdisk file (default: none)\n" "-m \tMemory size (dec) in KB (default: see boot.S)\n" "-r \tOffset of RAM-disk (default: calculated from memsize)\n" "-o \tOutput file (default: nk.bin)\n" "-v\t\tVerbose mode\n" "-h\t\tThis information\n", argv0); return EXIT_FAILURE; } int copy(char const *name, u_int32_t offset, u_int32_t addr, FILE * fpo) { int ch; u_int32_t cksum = 0; u_int32_t size = 0; FILE *fpi; if (!(fpi = fopen(name, "r"))) { perror("Can't open input file"); return EXIT_FAILURE; } fseek(fpo, 3 * sizeof(u_int32_t), SEEK_CUR); if (offset) fseek(fpi, offset, SEEK_SET); while ((ch = getc(fpi)) != EOF) { size++; cksum += ch; putc(ch, fpo); } fseek(fpo, -(long) (size + 3 * sizeof(u_int32_t)), SEEK_CUR); fwrite(&addr, sizeof(addr), 1, fpo); fwrite(&size, sizeof(size), 1, fpo); fwrite(&cksum, sizeof(cksum), 1, fpo); fseek(fpo, size, SEEK_CUR); if (verbose) printf("%16s @ %08x, %7d bytes (checksum %08x)\n", name, addr, size, cksum); fclose(fpi); return size; } int main(int argc, char *const *argv) { int ch; u_int16_t offset; u_int32_t memsize = 0; u_int32_t rootaddr = 0; u_int32_t rootsize = 0; u_int32_t linuxoff; u_int32_t ul; char version[41]; FILE *fpi; FILE *fpo; char const *cp; struct stat statbuf; char *kernel = NULL; char *initrd = NULL; char *output = "nk.bin"; while ((ch = getopt(argc, argv, "k:i:o:m:r:vh")) != EOF) switch (ch) { case 'k': kernel = strdup(optarg); break; case 'i': initrd = strdup(optarg); if (stat(initrd, &statbuf)) { perror("Can't stat initrd"); return EXIT_FAILURE; } rootsize = statbuf.st_size; break; case 'o': output = strdup(optarg); break; case 'm': /* Subtracting 1024 here because the kernel asks for *extended* memory size. */ memsize = strtol(optarg, 0, 10) - 1024; break; case 'r': rootaddr = strtol(optarg, 0, 16); break; case 'v': verbose++; break; default: return usage(argv[0]); } if (kernel == NULL ) return usage(argv[0]); // extract information from kernel if (!(fpi = fopen(kernel, "r"))) { perror("Can't open kernel"); return EXIT_FAILURE; } fseek(fpi, 0x1f1, SEEK_SET); fread(&linuxoff, sizeof(linuxoff), 1, fpi); fseek(fpi, 0x20e, SEEK_SET); fread(&offset, sizeof(offset), 1, fpi); fseek(fpi, offset + 0x200, SEEK_SET); // SETUPSEG - INITSEG fread(version, sizeof(version), 1, fpi); version[sizeof(version) - 1] = 0; fclose(fpi); linuxoff = ((linuxoff & 0xff) + 1) * 512; // update information in "boot" if (!(fpi = fopen("boot", "r+"))) { perror("Can't open boot"); return EXIT_FAILURE; } // copy kernel version string if ((cp = strtok(version, " ")) != NULL) { fseek(fpi, 0x22e, SEEK_SET); // 0x20e + Minix header fread(&offset, sizeof(offset), 1, fpi); fseek(fpi, offset + 0x26, SEEK_SET); // Minix header + "Linux " fwrite(cp, strlen(cp) + 1, 1, fpi); } // get/set memory size fseek(fpi, 0x200, SEEK_SET); // 0x1e0 + Minix header if (memsize == 0) fread(&memsize, sizeof(memsize), 1, fpi); else fwrite(&memsize, sizeof(memsize), 1, fpi); if (memsize != 0) memsize = (memsize + 1024) * 1024; if (initrd) { // write initrd info if (rootaddr == 0) { if (memsize != 0) rootaddr = (memsize - rootsize) & 0xfffe0000; else rootaddr = 0x300000; /* Let's hope the kernel is <2MB! :-) */ } fseek(fpi, 0x238, SEEK_SET); fwrite(&rootaddr, sizeof(rootaddr), 1, fpi); fwrite(&rootsize, sizeof(rootsize), 1, fpi); fclose(fpi); } // write NK.bin header if (!(fpo = fopen(output, "w+"))) { perror("Can't open output file"); return EXIT_FAILURE; } fwrite(signature, sizeof(signature), 1, fpo); fwrite(&start, sizeof(start), 1, fpo); fwrite(&test, sizeof(test), 1, fpo); copy("boot", 32, 0x90000, fpo); copy(kernel, linuxoff, 0x100000, fpo); if (initrd) copy(initrd, 0, rootaddr, fpo); // write NK.bin trailer ul = 0; fwrite(&ul, sizeof(ul), 1, fpo); // this is the real entry point, start seems to be bogus, or something else? ul = 0x91000; fwrite(&ul, sizeof(ul), 1, fpo); ul = 0; fwrite(&ul, sizeof(ul), 1, fpo); fclose(fpo); return EXIT_SUCCESS; }