OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

[/] [eco32/] [tags/] [eco32-0.24/] [disk/] [tools/] [fs-NetBSD/] [mkboot/] [stage2/] [boot.c] - Rev 211

Compare with Previous | Blame | View Log

/*
 * boot.c -- the bootstrap (boot loader)
 */
 
 
#include "types.h"
#include "disklabel.h"
#include "fs.h"
#include "dinode.h"
#include "dir.h"
#include "stdarg.h"
#include "biolib.h"
 
 
/**************************************************************/
 
/* constants and data types */
 
 
#define LOADER_NAME	"loader"	/* name of loader in root dir */
#define LOADER_ADDR	0xC0300000	/* where to load the loader */
 
#define SSHIFT		9		/* ld of sector size */
#define SSIZE		(1 << SSHIFT)	/* disk sector size in bytes */
#define SMASK		(SSIZE - 1)	/* sector mask */
 
#define BSHIFT		13		/* ld of block size */
#define BSIZE		(1 << BSHIFT)	/* disk block size in bytes */
#define BMASK		(BSIZE - 1)	/* block mask */
 
 
typedef struct ufs1_dinode Dinode;
typedef struct direct Dirent;
typedef unsigned int daddr_t;
typedef unsigned int ino_t;
 
 
#define NIPB		(BSIZE / sizeof(Dinode))
 
#define NULL		0
 
 
/**************************************************************/
 
/* debugging */
 
 
Bool debugReadSectors = FALSE;
Bool debugReadDiskLabel = FALSE;
Bool debugReadSuperBlock = FALSE;
Bool debugGetInode = FALSE;
Bool debugSearchDir = FALSE;
Bool debugLoadLoader = FALSE;
 
 
/**************************************************************/
 
/* string support */
 
 
int strlen(char *str) {
  int i;
 
  i = 0;
  while (*str++ != '\0') {
    i++;
  }
  return i;
}
 
 
int strcmp(char *str1, char *str2) {
  while (*str1 == *str2) {
    if (*str1 == '\0') {
      return 0;
    }
    str1++;
    str2++;
  }
  return (* (unsigned char *) str1) - (* (unsigned char *) str2);
}
 
 
/**************************************************************/
 
/* scaled-down version of printf */
 
 
/*
 * Output a character on the console.
 * Replace LF by CR/LF.
 */
void putchar(char c) {
  if (c == '\n') {
    putchar('\r');
  }
  putc(c);
}
 
 
/*
 * Count the number of characters needed to represent
 * a given number in base 10.
 */
int countPrintn(long n) {
  long a;
  int res;
 
  res = 0;
  if (n < 0) {
    res++;
    n = -n;
  }
  a = n / 10;
  if (a != 0) {
    res += countPrintn(a);
  }
  return res + 1;
}
 
 
/*
 * Output a number in base 10.
 */
void printn(long n) {
  long a;
 
  if (n < 0) {
    putchar('-');
    n = -n;
  }
  a = n / 10;
  if (a != 0) {
    printn(a);
  }
  putchar(n % 10 + '0');
}
 
 
/*
 * Count the number of characters needed to represent
 * a given number in a given base.
 */
int countPrintu(unsigned long n, unsigned long b) {
  unsigned long a;
  int res;
 
  res = 0;
  a = n / b;
  if (a != 0) {
    res += countPrintu(a, b);
  }
  return res + 1;
}
 
 
/*
 * Output a number in a given base.
 */
void printu(unsigned long n, unsigned long b, Bool upperCase) {
  unsigned long a;
 
  a = n / b;
  if (a != 0) {
    printu(a, b, upperCase);
  }
  if (upperCase) {
    putchar("0123456789ABCDEF"[n % b]);
  } else {
    putchar("0123456789abcdef"[n % b]);
  }
}
 
 
/*
 * Output a number of filler characters.
 */
void fill(int numFillers, char filler) {
  while (numFillers-- > 0) {
    putchar(filler);
  }
}
 
 
/*
 * Formatted output with a variable argument list.
 */
void vprintf(char *fmt, va_list ap) {
  char c;
  int n;
  long ln;
  unsigned int u;
  unsigned long lu;
  char *s;
  Bool negFlag;
  char filler;
  int width, count;
 
  while (1) {
    while ((c = *fmt++) != '%') {
      if (c == '\0') {
        return;
      }
      putchar(c);
    }
    c = *fmt++;
    if (c == '-') {
      negFlag = TRUE;
      c = *fmt++;
    } else {
      negFlag = FALSE;
    }
    if (c == '0') {
      filler = '0';
      c = *fmt++;
    } else {
      filler = ' ';
    }
    width = 0;
    while (c >= '0' && c <= '9') {
      width *= 10;
      width += c - '0';
      c = *fmt++;
    }
    if (c == 'd') {
      n = va_arg(ap, int);
      count = countPrintn(n);
      if (width > 0 && !negFlag) {
        fill(width - count, filler);
      }
      printn(n);
      if (width > 0 && negFlag) {
        fill(width - count, filler);
      }
    } else
    if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
      u = va_arg(ap, int);
      count = countPrintu(u,
                c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
      if (width > 0 && !negFlag) {
        fill(width - count, filler);
      }
      printu(u,
             c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
             c == 'X');
      if (width > 0 && negFlag) {
        fill(width - count, filler);
      }
    } else
    if (c == 'l') {
      c = *fmt++;
      if (c == 'd') {
        ln = va_arg(ap, long);
        count = countPrintn(ln);
        if (width > 0 && !negFlag) {
          fill(width - count, filler);
        }
        printn(ln);
        if (width > 0 && negFlag) {
          fill(width - count, filler);
        }
      } else
      if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
        lu = va_arg(ap, long);
        count = countPrintu(lu,
                  c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
        if (width > 0 && !negFlag) {
          fill(width - count, filler);
        }
        printu(lu,
               c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
               c == 'X');
        if (width > 0 && negFlag) {
          fill(width - count, filler);
        }
      } else {
        putchar('l');
        putchar(c);
      }
    } else
    if (c == 's') {
      s = va_arg(ap, char *);
      count = strlen(s);
      if (width > 0 && !negFlag) {
        fill(width - count, filler);
      }
      while ((c = *s++) != '\0') {
        putchar(c);
      }
      if (width > 0 && negFlag) {
        fill(width - count, filler);
      }
    } else
    if (c == 'c') {
      c = va_arg(ap, char);
      putchar(c);
    } else {
      putchar(c);
    }
  }
}
 
 
/*
 * Formatted output.
 * This is a scaled-down version of the C library's
 * printf. Used to print diagnostic information on
 * the console (and optionally to a logfile).
 */
void printf(char *fmt, ...) {
  va_list ap;
 
  va_start(ap, fmt);
  vprintf(fmt, ap);
  va_end(ap);
}
 
 
/**************************************************************/
 
/* halt with error message */
 
 
void halt(char *msg) {
  printf(msg);
  printf(", machine halted.\n");
  while (1) ;
}
 
 
/**************************************************************/
 
/* disk I/O */
 
 
unsigned int bootDisk = 0;	/* gets loaded by previous stage */
				/* never changed */
unsigned int startSector = 0;	/* gets loaded by previous stage */
				/* initially holds start of slice */
				/* disklabel read --> start of partition */
unsigned int numSectors = 0;	/* gets loaded by previous stage */
				/* initially holds size of slice */
				/* disklabel read --> size of partition */
 
unsigned int spf;		/* superblock read --> sectors per fragment */
unsigned int spb;		/* superblock read --> sectors per block */
 
 
/*
 * read disk sectors
 *
 * NOTE: buffer must be word-aligned
 */
void readSectors(unsigned int start,
                 unsigned int count,
                 void *buffer) {
  unsigned int sector;
  int result;
 
  if (start + count > numSectors) {
    halt("Sector number exceeds slice or partition size");
  }
  sector = startSector + start;
  if (debugReadSectors) {
    printf("DEBUG: reading sector 0x%08X, %d sectors\n", sector, count);
  }
  result = rwscts(bootDisk, 'r', sector,
                  (unsigned int) buffer & 0x3FFFFFFF, count);
  if (result != 0) {
    halt("Load error");
  }
}
 
 
/**************************************************************/
 
/* disklabel handling */
 
 
unsigned int diskLabel[SSIZE / sizeof(unsigned int)];
DiskLabel *dlp = (DiskLabel *) &diskLabel[0];
 
unsigned int superStart;	/* partition-relative offset, in sectors */
unsigned int superSize;		/* size, in sectors */
 
 
void readDiskLabel(void) {
  readSectors(1, 1, dlp);
  if (dlp->d_magic != DSKMAGIC ||
      dlp->d_magic2 != DSKMAGIC) {
    halt("Disklabel corrupted");
  }
 
  startSector = dlp->d_parts[0].p_offset;
  numSectors = dlp->d_parts[0].p_size;
 
  superStart = dlp->d_bbsize;
  if ((superStart & SMASK) != 0) {
    halt("Superblock offset is not multiple of sector size");
  }
  superStart >>= SSHIFT;
 
  superSize = dlp->d_sbsize;
  if ((superSize & SMASK) != 0) {
    halt("Superblock size is not multiple of sector size");
  }
  if (superSize > BSIZE) {
    halt("Superblock too big");
  }
  superSize >>= SSHIFT;
 
  if (debugReadDiskLabel) {
    printf("DEBUG: super start = %d sectors, super size = %d sectors\n",
           superStart, superSize);
  }
}
 
 
/**************************************************************/
 
/* superblock handling */
 
 
unsigned int superBlock[BSIZE / sizeof(unsigned int)];
struct fs *sbp = (struct fs *) &superBlock[0];
 
 
void readSuperBlock(void) {
  readSectors(superStart, superSize, sbp);
  if (sbp->fs_magic != FS_UFS1_MAGIC) {
    halt("Wrong magic number in superblock");
  }
  spf = sbp->fs_fsize / SSIZE;
  spb = sbp->fs_bsize / SSIZE;
  if (sbp->fs_inopb != NIPB) {
    halt("Wrong number of inodes per block");
  }
  if (debugReadSuperBlock) {
    printf("DEBUG: %d sectors per fragment\n", spf);
    printf("DEBUG: %d sectors per block\n", spb);
    printf("DEBUG: %d inodes per block\n", NIPB);
  }
}
 
 
/**************************************************************/
 
 
unsigned int sibno = 0;
unsigned int sib[8192 / sizeof(unsigned int)];
unsigned int *sibp = (unsigned int *) &sib[0];
 
 
/*
 * read a block of a file
 *
 * NOTE: addr must be word-aligned
 */
void readFileBlock(Dinode *ip, int blkno, void *addr) {
  unsigned int diskFrag;
 
  if (blkno < NDADDR) {
    /* direct block */
    diskFrag = ip->di_db[blkno];
  } else
  if (blkno - NDADDR < sbp->fs_bsize / sizeof(int32_t)) {
    /* single indirect block */
    if (sibno != ip->di_ib[0]) {
      sibno = ip->di_ib[0];
      readSectors(sibno * spf, spb, sibp);
    }
    diskFrag = sibp[blkno - NDADDR];
  } else {
    /* double or triple indirect block */
    halt("Cannot do double or triple indirect blocks");
  }
  readSectors(diskFrag * spf, spb, addr);
}
 
 
/**************************************************************/
 
/* inode handling */
 
 
unsigned int inodeBlock[BSIZE / sizeof(unsigned int)];
Dinode *ibp = (Dinode *) &inodeBlock[0];
 
 
Dinode *getInode(unsigned int inode) {
  unsigned int fnum;
  unsigned int inum;
  Dinode *ip;
 
  fnum = ino_to_fsba(sbp, inode);
  inum = ino_to_fsbo(sbp, inode);
  if (debugGetInode) {
    printf("DEBUG: getting inode 0x%08X\n", inode);
    printf("DEBUG: this is in fragment %d, inode %d\n", fnum, inum);
  }
  readSectors(fnum * spf, spb, ibp);
  ip = ibp + inum;
  if (ip->di_size[0] != 0) {
    halt("File too big");
  }
  if (debugGetInode) {
    printf("DEBUG: mode of file = 0x%04X\n", ip->di_mode);
    printf("DEBUG: size of file = 0x%08X\n", ip->di_size[1]);
  }
  return ip;
}
 
 
/**************************************************************/
 
/* locate inode of loader in root dir */
 
 
unsigned int directoryBlock[BSIZE / sizeof(unsigned int)];
Dirent *dbp = (Dirent *) &directoryBlock[0];
 
 
Dinode *getLoader(char *loaderName) {
  Dinode *ip;
  unsigned int offset;
  Dirent *dp;
  unsigned int ino;
  unsigned int len;
 
  ip = getInode(ROOTINO);
  if ((ip->di_mode & IFMT) != IFDIR) {
    halt("No root directory");
  }
  offset = 0;
  while (1) {
    if (offset >= ip->di_size[1]) {
      /* not found */
      return NULL;
    }
    if ((offset & BMASK) == 0) {
      /* read the next directory block */
      readFileBlock(ip, offset >> BSHIFT, dbp);
      dp = dbp;
    }
    ino = dp->d_fileno;
    len = dp->d_reclen;
    if (debugSearchDir) {
      printf("DEBUG: ino = %4d, len = %4d, ", ino, len);
      printf("dirsiz = %4d, name = %s\n", DIRSIZ(0, dp, 0), dp->d_name);
    }
    if (ino != 0) {
      if (strcmp(loaderName, dp->d_name) == 0) {
        /* found */
        break;
      }
    }
    /* no match, try next entry */
    dp = (Dirent *) ((unsigned char *) dp + len);
    offset += len;
  }
  /* get corresponding inode */
  ip = getInode(ino);
  if ((ip->di_mode & IFMT) != IFREG) {
    printf("/%s ", loaderName);
    halt(" is not a regular file");
  }
  return ip;
}
 
 
/**************************************************************/
 
/* load the loader */
 
 
void loadLoader(Dinode *ip) {
  unsigned int numBlocks;
  unsigned int nextBlock;
  unsigned char *nextAddr;
 
  numBlocks = (ip->di_size[1] + (BSIZE - 1)) / BSIZE;
  nextBlock = 0;
  nextAddr = (unsigned char *) LOADER_ADDR;
  while (numBlocks--) {
    if (debugLoadLoader) {
      printf("DEBUG: loading block %d at 0x%08X\n", nextBlock, nextAddr);
    }
    readFileBlock(ip, nextBlock, nextAddr);
    nextBlock++;
    nextAddr += BSIZE;
  }
}
 
 
/**************************************************************/
 
/* main program */
 
 
unsigned int entryPoint;	/* where to continue from main() */
 
 
int main(void) {
  Dinode *ip;
  unsigned int saveBootDisk;
  unsigned int saveStartSector;
  unsigned int saveNumSectors;
 
  /* save environment, see below */
  saveBootDisk = bootDisk;
  saveStartSector = startSector;
  saveNumSectors = numSectors;
  printf("Bootstrap loader executing...\n");
  readDiskLabel();
  readSuperBlock();
  ip = getLoader(LOADER_NAME);
  if (ip == NULL) {
    printf("'/%s' ", LOADER_NAME);
    halt("not found");
  }
  printf("Loading '/%s'...\n", LOADER_NAME);
  loadLoader(ip);
  printf("Starting '/%s'...\n", LOADER_NAME);
  entryPoint = LOADER_ADDR;
  /* restore environment: the loader expects exactly
     the same entry conditions as the boot loader */
  bootDisk = saveBootDisk;
  startSector = saveStartSector;
  numSectors = saveNumSectors;
  return 0;
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.