summaryrefslogtreecommitdiff
path: root/package/aboot/src/srmbootfat/srmbootfat.c
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2017-12-31 18:47:16 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2017-12-31 18:47:25 +0100
commit3a96085b999220c4da0c5ef7d1f7ba26b9ddfb98 (patch)
tree77f1445aae2e6be5135594e95986b3278bbc061c /package/aboot/src/srmbootfat/srmbootfat.c
parentcc28479164b8dc8afd4310716da32f16022f5974 (diff)
dec-multia: make netboot possible, add aboot bootloader
Diffstat (limited to 'package/aboot/src/srmbootfat/srmbootfat.c')
-rw-r--r--package/aboot/src/srmbootfat/srmbootfat.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/package/aboot/src/srmbootfat/srmbootfat.c b/package/aboot/src/srmbootfat/srmbootfat.c
new file mode 100644
index 000000000..71380ded5
--- /dev/null
+++ b/package/aboot/src/srmbootfat/srmbootfat.c
@@ -0,0 +1,246 @@
+/*
+ * SRMbootFAT - SRM boot block composer for FAT filesystems.
+ * Copyright (C) 1998 Nikita Schmidt <cetus@snowball.ucd.ie>
+ * msdos.h is Copyright (C) 1995 Alain Knaff.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "msdos.h"
+
+/* This should test for little-endianness, but why bother,
+ the whole thing is Alpha-specific anyway. */
+#ifdef __alpha__ /* Little endian */
+#define WORD(x) (*(u_int16_t *)(x))
+#define DWORD(x) (*(u_int32_t *)(x))
+#else /* Big endian; in fact, generic stuff */
+#define WORD _WORD
+#define DWORD _DWORD
+#endif
+
+union full_bootsector {
+ struct bootsector dos;
+ struct {
+ unsigned char textlabel[64];
+ unsigned char disklabel[276];
+ unsigned char unused[140];
+ u_int64_t count, start, flags;
+ u_int64_t checksum;
+ } srm;
+ struct {
+ u_int64_t contents[63];
+ u_int64_t checksum;
+ } check;
+};
+
+#ifdef __alpha__ /* Should be test for little endian */
+unsigned int get_fat_entry (unsigned char *fat, int fatbits, unsigned entry)
+{
+ unsigned i, a, b;
+
+ /* No check for fat boundaries... */
+ switch (fatbits) {
+ case 12:
+ i = ((entry *= 3) & 7) << 2; /* Number of bits to shift */
+ a = ((u_int32_t *)fat)[entry >>= 3];
+ b = ((u_int32_t *)fat)[entry + 1]; /* May be outside FAT */
+ return ((a >> i) | (b << (32 - i))) & 0xFFF;
+ case 16:
+ return ((u_int16_t *)fat)[entry];
+ }
+ fprintf (stderr, "Unknown FAT type - FAT-%d\n", fatbits);
+ exit (3);
+}
+#else
+// Portable Version from Falk Hueffner <falk.hueffner@student.uni-tuebingen.de>
+unsigned int get_fat_entry (unsigned char *fat, int fatbits, unsigned entry)
+{
+ unsigned i, a, b;
+
+ /* No check for fat boundaries... */
+ switch (fatbits) {
+ case 12:
+ i = ((entry *= 3) & 7) << 2; /* Number of bits to shift */
+ entry >>= 3;
+ a = DWORD(fat + 4 * entry);
+ b = DWORD(fat + 4 * entry + 4);
+ return ((a >> i) | (b << (32 - i))) & 0xFFF;
+ case 16:
+ return WORD(fat + 2 * entry);
+ }
+ fprintf (stderr, "Unknown FAT type - FAT-%d\n", fatbits);
+ exit (3);
+}
+#endif
+
+int main (int argc, char *argv[])
+{
+ int f;
+ int i;
+ char *p;
+ union full_bootsector boot;
+ unsigned secsize; /* Bytes per sector, hopefully 512 */
+ unsigned clusize; /* Cluster size in sectors */
+ unsigned fatstart; /* Number of reserved (boot) sectors */
+ unsigned nfat; /* Number of FAT tables, hopefully 2 */
+ unsigned dirents; /* Number of directory slots */
+ unsigned psect; /* Total sectors on disk */
+ unsigned media; /* Media descriptor=first byte of FAT */
+ unsigned fatsize; /* Sectors in FAT */
+ unsigned fatbits; /* FAT type (bits per entry) */
+ unsigned char *fat;
+ struct directory *rootdir;
+ unsigned start; /* Starting cluster of the boot file */
+ unsigned size; /* Boot file size */
+ unsigned fat_end;
+ unsigned j;
+ u_int64_t checksum;
+ char dosname[12];
+
+ if (argc != 3)
+ return printf ("Usage: srmbootfat <filesystem image file> <boot file>\n"), 1;
+
+ if ((f = open (argv[1], O_RDWR)) < 0)
+ return perror (argv[1]), 2;
+
+ if (read (f, &boot, sizeof boot) != sizeof boot)
+ return fprintf (stderr, "Can't read boot sector from %s\n", argv[1]), 2;
+
+ secsize = _WORD (boot.dos.secsiz);
+ clusize = boot.dos.clsiz;
+ fatstart = WORD (boot.dos.nrsvsect);
+ nfat = boot.dos.nfat;
+ dirents = _WORD (boot.dos.dirents);
+ psect = _WORD (boot.dos.psect);
+ media = boot.dos.descr;
+ fatsize = WORD (boot.dos.fatlen);
+
+ if ((media & ~7) == 0xf8) {
+ i = media & 3;
+ clusize = old_dos[i].cluster_size;
+ fatstart = 1;
+ fatsize = old_dos[i].fat_len;
+ dirents = old_dos[i].dir_len * (512 / MDIR_SIZE);
+ nfat = 2;
+ fatbits = 12;
+ } else if (strncmp (boot.dos.ext.old.fat_type, "FAT12", 5) == 0)
+ fatbits = 12;
+ else if (strncmp (boot.dos.ext.old.fat_type, "FAT16", 5) == 0)
+ fatbits = 16;
+ else return fprintf (stderr, "%s: unrecognisable FAT type\n", argv[1]),
+ 3;
+#ifdef DEBUG
+ printf ("%s: filesystem type is FAT-%d\n", argv[1], fatbits);
+#endif
+
+ if (secsize != 512)
+ return fprintf (stderr, "%s: sector size is %d; "
+ "unfortunately, this is not supported\n",
+ argv[1], secsize),
+ 3;
+ if (nfat != 1 && nfat != 2)
+ fprintf (stderr,
+ "%s: warning: weird number of FAT tables (%d)\n",
+ argv[1], nfat);
+
+ fat = malloc (i = fatsize * secsize);
+ rootdir = malloc (dirents * MDIR_SIZE);
+ if (!fat || !rootdir)
+ return fprintf (stderr, "Not enough memory\n"), 2;
+ if (lseek (f, fatstart * secsize, SEEK_SET) == -1
+ || read (f, fat, i) != i
+ || lseek (f, (nfat - 1) * i, SEEK_CUR) == -1
+ || read (f, rootdir, dirents * MDIR_SIZE) != dirents * MDIR_SIZE)
+ return perror (argv[1]), 2;
+
+ memset (dosname, ' ', sizeof dosname);
+ i = 0;
+ for (p = argv[2]; *p; p++)
+ if (*p == '.')
+ i = 8;
+ else if (i < sizeof dosname)
+ dosname[i++] = toupper (*p);
+
+ for (i = 0; i < dirents; i++)
+ if (memcmp (rootdir[i].name, dosname, 11) == 0
+ && (rootdir[i].attr & (8 | 16)) == 0)
+ break;
+ if (i == dirents)
+ return fprintf (stderr,
+ "Can't find %s in the root directory in %s\n",
+ argv[2], argv[1]), 4;
+
+ start = WORD (rootdir[i].start);
+ size = DWORD (rootdir[i].size);
+
+ if (start * fatbits > fatsize * secsize * 8)
+ return fprintf (stderr,
+ "%s: first cluster (%u) is beyond the end of FAT",
+ argv[2], start), 3;
+
+ /* Fill in the bootstrap information */
+ size = (size + secsize - 1) / secsize; /* Size is now in sectors */
+ boot.srm.start = (start - 2) * clusize + fatstart + nfat * fatsize
+ + dirents / (512 / MDIR_SIZE);
+ boot.srm.count = size;
+ boot.srm.flags = 0;
+
+ /* Check that the image is contiguous */
+ i = 1;
+ fat_end = (1 << fatbits) - 9; /* 0xFF7, 0xFFF7 or whatever */
+ while ((j = get_fat_entry (fat, fatbits, start)) < fat_end) {
+ if (j != start + 1)
+ return fprintf (stderr,
+ "Unfortunately, %s is not contiguous\n",
+ argv[2]), 4;
+ start = j;
+ i++;
+ }
+ if ((size + clusize - 1) / clusize != i)
+ return fprintf (stderr, "Inconsistency: file size contradicts "
+ "with the number of clusters allocated\n"), 3;
+
+ /* Put the checksum and write the boot sector. */
+ checksum = 0;
+ for (i = 0; i < 63; i++)
+ checksum += boot.check.contents[i];
+ boot.check.checksum = checksum;
+
+ printf ("Writing SRM boot block: starting sector %u, block count %u\n",
+ (unsigned)boot.srm.start, (unsigned)boot.srm.count);
+
+ if (lseek (f, 0, SEEK_SET) == -1
+ || write (f, &boot, sizeof boot) != sizeof boot)
+ return perror (argv[2]), 2;
+
+ close (f);
+ return 0;
+}
+
+struct OldDos_t old_dos[]={
+ { 40, 9, 1, 4, 1, 2, 0xfc },
+ { 40, 9, 2, 7, 2, 2, 0xfd },
+ { 40, 8, 1, 4, 1, 1, 0xfe },
+ { 40, 8, 2, 7, 2, 1, 0xff },
+ { 80, 9, 2, 7, 2, 3, 0xf9 },
+ { 80, 15, 2,14, 1, 7, 0xf9 },
+ { 80, 18, 2,14, 1, 9, 0xf0 },
+ { 80, 36, 2,15, 2, 9, 0xf0 },
+ { 1, 8, 1, 1, 1, 1, 0xf0 }
+};