* @(#)sys.c 7.1 (Berkeley) 6/5/86
*/
-#include <sys/param.h>
-#include <ufs/ufs/dir.h>
-#include <sys/reboot.h>
-#include <architecture/byte_order.h>
-#include "ufs_byteorder.h"
#include "libsaio.h"
-#include "cache.h"
-#include "kernBootStruct.h"
-#include "stringConstants.h"
-#include <ufs/ffs/fs.h>
-#include "nbp.h"
-#include "memory.h"
-
-char * gFilename;
-
-extern int ram_debug_sarld; // in load.c
-
-#define DCACHE 1
-#define ICACHE 1
-#define SYS_MESSAGES 1
-#define CHECK_CAREFULLY 0
-#define COMPRESSION 1
-
-// #define DEBUG 1
-
-#ifdef DEBUG
-#define DPRINT(x) { printf x; }
-#define DSPRINT(x) { printf x; sleep(2); }
-#define RDPRINT(x) { if (ram_debug_sarld) printf x; }
-#define RDSPRINT(x) { if (ram_debug_sarld) printf x; sleep(2); }
-#else
-#define DPRINT(x)
-#define DSPRINT(x)
-#define RDPRINT(x)
-#define RDSPRINT(x)
-#endif
-
-char * devsw[] = {
- "sd",
- "hd",
- "fd",
- "en",
- NULL
+
+struct devsw {
+ const char * name;
+ unsigned char biosdev;
};
-//#############################################################################
-//#
-//# Disk filesystem functions.
-//#
-//#############################################################################
+static struct devsw devsw[] =
+{
+ { "sd", 0x80 }, /* DEV_SD */
+ { "hd", 0x80 }, /* DEV_HD */
+ { "fd", 0x00 }, /* DEV_FD */
+ { "en", 0xE0 }, /* DEV_EN */
+ { 0, 0 }
+};
-static ino_t dlook(char *s, struct iob *io);
-static char * xx(char *str, struct iob *file);
-static int ffs(register long mask);
+/*
+ * Max number of file descriptors.
+ */
+#define NFILES 6
-extern int label_secsize;
+static struct iob iob[NFILES];
-#define BIG_ENDIAN_INTEL_FS __LITTLE_ENDIAN__
+void * gFSLoadAddress = 0;
-#if ICACHE
-#define ICACHE_SIZE 256
-#define ICACHE_READAHEAD 8 // read behind and read ahead
-static cache_t * icache;
-#endif ICACHE
+static BVRef getBootVolumeRef( const char * path, const char ** outPath );
+static BVRef newBootVolumeRef( int biosdev, int partno );
-#if DCACHE
-#define DCACHE_SIZE 16 // 1k (DIRBLKSIZ) blocks
-static cache_t * dcache;
-#endif
+//==========================================================================
+// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
+// Load the specified file to the load buffer at LOAD_ADDR.
-#define DEV_BSIZE label_secsize
+long LoadFile(const char * fileSpec)
+{
+ const char * filePath;
+ long fileSize;
+ BVRef bvr;
-#if CHECK_CAREFULLY
-static int open_init;
-#endif
+ // Resolve the boot volume from the file spec.
-static struct fs * fs_block;
-static int fs_block_valid;
+ if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
+ return -1;
-#define SUPERBLOCK_ERROR "Bad superblock: error %d\n"
+ // Read file into load buffer. The data in the load buffer will be
+ // overwritten by the next LoadFile() call.
-/*==========================================================================
- *
- *
- */
-static struct iob * iob_from_fdesc(int fdesc)
-{
- register struct iob * file;
-
- if (fdesc < 0 || fdesc >= NFILES ||
- ((file = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
- return NULL;
- else
- return file;
-}
+ gFSLoadAddress = (void *) LOAD_ADDR;
+ fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
-/***************************************************************************
- *
- * Disk functions.
- *
- ***************************************************************************/
+ // Return the size of the file, or -1 if load failed.
-/*==========================================================================
- *
- *
- */
-static int
-openi(int n, struct iob * io)
-{
- struct dinode * dp;
- int cc, i, j, n_round;
-
-#if ICACHE
- struct dinode *ip;
-
- if (icache == 0) {
- icache = cacheInit(ICACHE_SIZE, sizeof(struct dinode));
- }
-#endif /* ICACHE */
-
- io->i_offset = 0;
- io->i_bn = fsbtodb(io->i_ffs, ino_to_fsba(io->i_ffs, n)) + io->i_boff;
- io->i_cc = io->i_ffs->fs_bsize;
- io->i_ma = io->i_buf;
-
-#if ICACHE
- if (cacheFind(icache, n, 0, (char **)&ip) == 1) {
- io->i_ino.i_din = *ip;
- cc = 0;
- } else {
-#endif ICACHE
- cc = devread(io);
- dp = (struct dinode *)io->i_buf;
- n_round = (n / INOPB(io->i_ffs)) * INOPB(io->i_ffs);
-#if ICACHE
- /* Read multiple inodes into cache */
- for (i = max(ino_to_fsbo(io->i_ffs, n) - ICACHE_READAHEAD, 0),
- j = min(i+2*ICACHE_READAHEAD, INOPB(io->i_ffs)); i < j; i++) {
- cacheFind(icache, n_round + i, 0, (char **)&ip);
-
-#if BIG_ENDIAN_INTEL_FS
-#warning Building with Big Endian changes
- byte_swap_dinode_in(&dp[i]);
-#endif /* BIG_ENDIAN_INTEL_FS */
-
- *ip = dp[i];
- if (i == ino_to_fsbo(io->i_ffs, n)) {
- io->i_ino.i_din = *ip;
- }
- }
- }
-#else ICACHE
-
-#if BIG_ENDIAN_INTEL_FS
- byte_swap_dinode_in(&dp[ino_to_fsbo(io->i_ffs, n)]);
-#endif /* BIG_ENDIAN_INTEL_FS */
-
- io->i_ino.i_din = dp[ino_to_fsbo(io->i_ffs, n)];
-#endif ICACHE
-
- io->i_ino.i_number = n;
- return (cc);
+ return fileSize;
}
-/*==========================================================================
- *
- *
- */
-static int
-readlink(struct iob * io, char * buf, int len)
+//==========================================================================
+// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
+// Fetch the next directory entry for the given directory.
+
+long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
+ long * flags, long * time)
{
- register struct inode * ip;
-
- ip = &io->i_ino;
-#if 1
- /* read contents */
- io->i_offset = 0;
- io->i_cc = 0;
- io->i_flgs |= F_FILE;
- if (read(io - iob, buf, len) < 0)
+ const char * dirPath;
+ BVRef bvr;
+
+ // Resolve the boot volume from the dir spec.
+
+ if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
return -1;
-#else
- if (ip->i_icflags & IC_FASTLINK) {
- if (ip->i_size > len)
- return -1;
- bcopy(ip->i_symlink, buf, ip->i_size);
- } else {
- /* read contents */
- io->i_offset = 0;
- io->i_cc = 0;
- io->i_flgs |= F_FILE;
- if (read(io - iob, buf, len) < 0)
- return -1;
- }
-#endif
- return 0;
+
+ // Return 0 on success, or -1 if there are no additional entries.
+
+ return bvr->fs_getdirentry( bvr,
+ /* dirPath */ (char *)dirPath,
+ /* dirIndex */ dirIndex,
+ /* dirEntry */ (char **)name, flags, time );
}
-/*==========================================================================
- *
- *
- */
-static int
-find(char * path, struct iob * file)
+//==========================================================================
+// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
+// Get attributes for the specified file.
+
+long GetFileInfo(const char * dirSpec, const char * name,
+ long * flags, long * time)
{
- char * q;
- char c;
- int n, parent;
- char * lbuf = malloc(MAXPATHLEN + 1);
- int ret;
-
-#if CHECK_CAREFULLY
- if (path==NULL || *path=='\0') {
- error("null path\n");
- ret = 0; goto out;
- }
-#endif CHECK_CAREFULLY
-
- DSPRINT(("in find: path=%s\n", path));
-
-root:
- n = ROOTINO;
- if (openi(n, file) < 0)
- {
- DPRINT(("openi failed\n"));
-
-#if SYS_MESSAGES
- error("bad root inode\n");
-#endif
-
- ret = 0; goto out;
- }
- DPRINT(("openi ok\n"));
-
- while (*path)
- {
- while (*path == '/')
- path++;
- q = path;
- while(*q != '/' && *q != '\0')
- q++;
- c = *q;
- *q = '\0';
- if (q == path) path = "." ; /* "/" means "/." */
-
- parent = n;
- if ((n = dlook(path, file)) != 0)
- {
- if (c == '\0')
- break;
- if (openi(n, file) < 0)
- {
- *q = c;
- ret = 0; goto out;
- }
- *q = c;
- path = q;
-
- /* Check for symlinks */
- if (file->i_ino.i_mode & IFLNK) {
- char *buf = malloc(MAXPATHLEN + 1);
- if (readlink(file, buf, MAXPATHLEN + 1) < 0)
- return -1;
- strcat(buf, q);
- strcpy(lbuf, buf);
- free(buf);
- path = lbuf;
- if (*path == '/')
- goto root;
- if (openi(parent, file) < 0) {
- ret = 0; goto out;
- }
- }
- continue;
- }
- else
- {
- *q = c;
- ret = 0; goto out;
- }
- }
- ret = n;
-out:
- free(lbuf);
- return (ret);
+ long index = 0;
+ const char * entryName;
+
+ while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
+ {
+ if (strcmp(entryName, name) == 0)
+ return 0; // success
+ }
+ return -1; // file not found
}
-/*==========================================================================
- *
- *
- */
-static daddr_t
-sbmap(struct iob * io, daddr_t bn)
+//==========================================================================
+// iob_from_fdesc()
+//
+// Return a pointer to an allocated 'iob' based on the file descriptor
+// provided. Returns NULL if the file descriptor given is invalid.
+
+static struct iob * iob_from_fdesc(int fdesc)
{
- register struct inode * ip;
- int i, j, sh;
- daddr_t nb, * bap;
-
- ip = &io->i_ino;
-
- if (bn < 0) {
-#if SYS_MESSAGES
- error("bn negative\n");
-#endif
- return ((daddr_t)0);
- }
-
- /*
- * blocks 0..NDADDR are direct blocks
- */
- if (bn < NDADDR)
- {
- nb = ip->i_db[bn];
- return (nb);
- }
-
- /*
- * addresses NIADDR have single and double indirect blocks.
- * the first step is to determine how many levels of indirection.
- */
- RDPRINT(("In NINADDR\n"));
-
- sh = 1;
- bn -= NDADDR;
- for (j = NIADDR; j > 0; j--) {
- sh *= NINDIR(io->i_ffs);
- if (bn < sh)
- break;
- bn -= sh;
- }
-
- if (j == 0) {
-#if SYS_MESSAGES
- error("bn ovf %d\n", bn);
-#endif
- return ((daddr_t)0);
- }
-
- /*
- * fetch the first indirect block address from the inode
- */
- nb = ip->i_ib[NIADDR - j];
- if (nb == 0) {
-#if SYS_MESSAGES
- error("bn void %d\n",bn);
-#endif
- return ((daddr_t)0);
- }
-
- /*
- * fetch through the indirect blocks
- */
- for (; j <= NIADDR; j++) {
- if (blknos[j] != nb) {
- io->i_bn = fsbtodb(io->i_ffs, nb) + io->i_boff;
- if (b[j] == (char *)0)
- b[j] = malloc(MAXBSIZE);
- io->i_ma = b[j];
- io->i_cc = io->i_ffs->fs_bsize;
-
- RDPRINT(("Indir block read\n"));
-
- if (devread(io) != io->i_ffs->fs_bsize) {
-#if SYS_MESSAGES
- error("bn %d: read error\n", io->i_bn);
-#endif
- return ((daddr_t)0);
- }
- blknos[j] = nb;
- }
- bap = (daddr_t *)b[j];
- sh /= NINDIR(io->i_ffs);
- i = (bn / sh) % NINDIR(io->i_ffs);
-#if BIG_ENDIAN_INTEL_FS
- nb = NXSwapBigLongToHost(bap[i]);
-#else /* BIG_ENDIAN_INTEL_FS */
- nb = bap[i];
-#endif /* BIG_ENDIAN_INTEL_FS */
- if (nb == 0) {
-#if SYS_MESSAGES
- error("bn void %d\n",bn);
-#endif
- return ((daddr_t)0);
- }
- }
-
- return (nb);
+ register struct iob * io;
+
+ if (fdesc < 0 || fdesc >= NFILES ||
+ ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
+ return NULL;
+ else
+ return io;
}
-/*==========================================================================
- *
- *
- */
-static struct dirstuff *
-disk_opendir(char * path)
+//==========================================================================
+// openmem()
+
+int openmem(char * buf, int len)
{
- register struct dirstuff * dirp;
- register int fd;
-
- dirp = (struct dirstuff *)malloc(sizeof(struct dirstuff));
- if (dirp == (struct dirstuff *)-1)
- return 0;
+ int fdesc;
+ struct iob * io;
- DPRINT(("Calling open in opendir\n"));
- fd = open(path,0);
- if (fd == -1) {
- DPRINT(("open failed \n"));
- free((void *)dirp);
- return 0;
- }
+ // Locate a free descriptor slot.
- DPRINT(("open ok fd is %d \n", fd));
- dirp->io = &iob[fd];
- dirp->loc = 0;
- iob[fd].dirbuf_blkno = -1;
+ for (fdesc = 0; fdesc < NFILES; fdesc++)
+ if (iob[fdesc].i_flgs == 0)
+ goto gotfile;
- return dirp;
-}
+ stop("Out of file descriptors");
-/*==========================================================================
- *
- *
- */
-static int
-disk_closedir(struct dirstuff * dirp)
-{
- close(dirp->io - iob);
- free((void *)dirp);
- return 0;
-}
+gotfile:
+ io = &iob[fdesc];
+ bzero(io, sizeof(*io));
-/*==========================================================================
- * get next entry in a directory.
- */
-static struct direct *
-disk_readdir(struct dirstuff * dirp)
-{
- struct direct * dp;
- register struct iob * io;
- daddr_t lbn, d;
- int off;
-#if DCACHE
- char * bp;
- int dirblkno;
-
- if (dcache == 0)
- dcache = cacheInit(DCACHE_SIZE, DIRBLKSIZ);
-#endif DCACHE
-
- io = dirp->io;
- for(;;)
- {
- if (dirp->loc >= io->i_ino.i_size)
- return (NULL);
- off = blkoff(io->i_ffs, dirp->loc);
- lbn = lblkno(io->i_ffs, dirp->loc);
-
-#if DCACHE
- dirblkno = dirp->loc / DIRBLKSIZ;
- if (cacheFind(dcache, io->i_ino.i_number, dirblkno, &bp)) {
- dp = (struct direct *)(bp + (dirp->loc % DIRBLKSIZ));
- } else
-#else DCACHE
- if (io->dirbuf_blkno != lbn)
-#endif DCACHE
- {
- if((d = sbmap(io, lbn)) == 0)
- return NULL;
- io->i_bn = fsbtodb(io->i_ffs, d) + io->i_boff;
- io->i_ma = io->i_buf;
- io->i_cc = blksize(io->i_ffs, &io->i_ino, lbn);
-
- if (devread(io) < 0)
- {
-#if SYS_MESSAGES
- error("bn %d: directory read error\n", io->i_bn);
-#endif
- return (NULL);
- }
-#if BIG_ENDIAN_INTEL_FS
- byte_swap_dir_block_in(io->i_buf, io->i_cc);
-#endif /* BIG_ENDIAN_INTEL_FS */
-
-#if DCACHE
- bcopy(io->i_buf + dirblkno * DIRBLKSIZ, bp, DIRBLKSIZ);
- dp = (struct direct *)(io->i_buf + off);
-#endif
- }
-#if !DCACHE
- dp = (struct direct *)(io->i_buf + off);
-#endif
- dirp->loc += dp->d_reclen;
-
- if (dp->d_ino != 0) return (dp);
- }
-}
+ // Mark the descriptor as taken. Set the F_MEM flag to indicate
+ // that the file buffer is provided by the caller.
-/*==========================================================================
- *
- *
- */
-static ino_t
-dlook(
- char * s,
- struct iob * io
-)
-{
- struct direct * dp;
- register struct inode * ip;
- struct dirstuff dirp;
- int len;
-
- if (s == NULL || *s == '\0')
- return (0);
- ip = &io->i_ino;
- if ((ip->i_mode & IFMT) != IFDIR) {
-#if SYS_MESSAGES
- error(". before %s not a dir\n", s);
-#endif
- return (0);
- }
- if (ip->i_size == 0) {
-#if SYS_MESSAGES
- error("%s: 0 length dir\n", s);
-#endif
- return (0);
- }
- len = strlen(s);
- dirp.loc = 0;
- dirp.io = io;
- io->dirbuf_blkno = -1;
-
- for (dp = disk_readdir(&dirp); dp != NULL; dp = disk_readdir(&dirp)) {
- DPRINT(("checking name %s\n", dp->d_name));
- if(dp->d_ino == 0)
- continue;
- if (dp->d_namlen == len && !strcmp(s, dp->d_name))
- return (dp->d_ino);
- }
- return (0);
-}
+ io->i_flgs = F_ALLOC | F_MEM;
+ io->i_buf = buf;
+ io->i_filesize = len;
-/*==========================================================================
- *
- *
- */
-static int
-getch(int fdesc)
-{
- register struct iob * io;
- struct fs * fs;
- char * p;
- int c, lbn, off, size, diff;
-
- if ((io = iob_from_fdesc(fdesc)) == 0) {
- return (-1);
- }
-
- RDPRINT(("In getch\n"));
-
- p = io->i_ma;
- if (io->i_cc <= 0) {
- if ((io->i_flgs & F_FILE) != 0) {
- diff = io->i_ino.i_size - io->i_offset;
- if (diff <= 0)
- return (-1);
- fs = io->i_ffs;
- lbn = lblkno(fs, io->i_offset);
-#if 1
- io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
-#else
- io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
-#endif
- off = blkoff(fs, io->i_offset);
- size = blksize(fs, &io->i_ino, lbn);
- } else {
- diff = 0;
-#ifndef SMALL
- io->i_bn = io->i_offset / DEV_BSIZE;
- off = 0;
- size = DEV_BSIZE;
-#endif SMALL
- }
-
- RDPRINT(("gc: bn=%x; off=%x\n",io->i_bn, io->i_offset));
-
- io->i_ma = io->i_buf;
- io->i_cc = size;
- if (devread(io) < 0) {
- return (-1);
- }
- if ((io->i_flgs & F_FILE) != 0) {
- if (io->i_offset - off + size >= io->i_ino.i_size)
- io->i_cc = diff + off;
- io->i_cc -= off;
- }
- p = &io->i_buf[off];
- }
- io->i_cc--;
- io->i_offset++;
- c = (unsigned)*p++;
- io->i_ma = p;
- return (c);
+ return fdesc;
}
-/*==========================================================================
- *
- */
-static int
-disk_read(int fdesc, char * buf, int count)
-{
- int i, size;
- register struct iob * file;
- struct fs * fs;
- int lbn, off;
-
- RDSPRINT(("IN READ\n"));
-
- if ((file = iob_from_fdesc(fdesc)) == 0) {
- return (-1);
- }
-#if CHECK_CAREFULLY
- if ((file->i_flgs&F_READ) == 0) {
- return (-1);
- }
-#endif
- if ((file->i_flgs & F_MEM) != 0) {
-
- RDSPRINT(("In read FMEM\n"));
-
- if (file->i_offset < file->i_boff) {
- if (count > (file->i_boff - file->i_offset))
- count = file->i_boff - file->i_offset;
- bcopy(file->i_buf + file->i_offset, buf, count);
- file->i_offset += count;
- } else {
- count = 0;
- }
- return count;
- }
-
-#ifndef SMALL
- if ((file->i_flgs & F_FILE) == 0) {
- file->i_cc = count;
- file->i_ma = buf;
- file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
-
- RDPRINT(("In read nsmall fbn=%x; offset=%x;", file->i_bn,
- file->i_offset));
- RDSPRINT(("boff=%x\n", file->i_boff));
-
- i = devread(file);
- file->i_offset += count;
- return (i);
- }
-#endif /* SMALL */
-
- if (file->i_offset+count > file->i_ino.i_size)
- count = file->i_ino.i_size - file->i_offset;
-
- RDSPRINT(("In read nsmall count=%x;", count));
-
- if ((i = count) <= 0)
- return (0);
-
- /*
- * While reading full blocks, do I/O into user buffer.
- * Anything else uses getc().
- */
- fs = file->i_ffs;
- while (i) {
- RDSPRINT(("In lread while\n"));
- off = blkoff(fs, file->i_offset);
- lbn = lblkno(fs, file->i_offset);
- size = blksize(fs, &file->i_ino, lbn);
- if (off == 0 && size <= i) {
- file->i_bn = fsbtodb(fs, sbmap(file, lbn)) +
- file->i_boff;
- file->i_cc = size;
- file->i_ma = buf;
-
- RDPRINT(("In read->devread\n"));
- RDPRINT(("In read fbn=%x; offset=%x;", file->i_bn,
- file->i_offset));
- RDSPRINT((" boff=%x\n", file->i_boff));
-
- if (devread(file) < 0) {
- return (-1);
- }
- file->i_offset += size;
- file->i_cc = 0;
- buf += size;
- i -= size;
- }
- else {
- RDSPRINT(("IN while nonread\n"));
- size -= off;
- if (size > i)
- size = i;
- i -= size;
- do {
- *buf++ = getch(fdesc);
- } while (--size);
- }
- }
-
- return (count);
-}
+//==========================================================================
+// open() - Open the file specified by 'path' for reading.
-/*==========================================================================
- * Disk (block device) functions.
- */
-static BOOL
-disk_open(char * name, struct iob * file, int how)
+int open(const char * path, int flags)
{
- int i;
-
- file->i_cc = SBSIZE;
-// file->i_bn = (SBLOCK / DEV_BSIZE) + file->i_boff;
- file->i_bn = (SBOFF/label_secsize) + file->i_boff;
- file->i_offset = 0;
-
- if (file->i_ffs == 0) {
- if (fs_block == 0) {
- DPRINT(("No super block; reading one \n"));
- fs_block = (struct fs *) malloc(SBSIZE);
- }
- if (fs_block_valid == 0) {
- file->i_ma = (char *)fs_block;
- if (devread(file) < 0) {
-#ifndef SMALL
- error(SUPERBLOCK_ERROR, 1);
-#endif
- return NO;
- }
-#if BIG_ENDIAN_INTEL_FS
- byte_swap_superblock(fs_block);
-#endif /* BIG_ENDIAN_INTEL_FS */
- DPRINT(("Read SB \n"));
- fs_block_valid = 1;
- }
- file->i_ffs = fs_block;
- file->i_buf = malloc(MAXBSIZE);
- }
-#if BIG_ENDIAN_INTEL_FS
- DPRINT(("IN BE_FS code \n"));
-
- if (file->i_ffs->fs_magic != FS_MAGIC) {
- DPRINT(("Bad magic in FS %d ; got %d\n", FS_MAGIC,
- file->i_ffs->fs_magic));
- error(SUPERBLOCK_ERROR, 2);
- return NO;
- }
- /*
- * The following is a gross hack to boot disks that have an actual
- * blocksize of 512 bytes but were written with a theoretical 1024
- * byte blocksize (fsbtodb == 0).
- *
- * We can make this assumption because we can only boot disks with
- * a 512 byte sector size.
- */
- DPRINT(("SB magic ok \n"));
- if (file->i_ffs->fs_fsize == 0) {
- error(SUPERBLOCK_ERROR,3);
- return NO;
- }
- file->i_ffs->fs_fsbtodb = ffs(file->i_ffs->fs_fsize / DEV_BSIZE) - 1;
-#endif /* BIG_ENDIAN_INTEL_FS */
-
- if ((i = find(name, file)) == 0) {
- DPRINT(("find() failed\n"));
- return NO;
- }
-
-#if CHECK_CAREFULLY
- if (how != 0) {
- error("Can't write files\n");
- return NO;
- }
-#endif CHECK_CAREFULLY
-
- DPRINT(("calling openi \n"));
- if (openi(i, file) < 0) {
- DPRINT(("openi failed \n"));
- return NO;
- }
-
- DPRINT(("openi ok \n"));
-
- file->i_offset = 0;
- file->i_cc = 0;
- file->i_flgs |= F_FILE | (how+1);
-
- return YES;
-}
+ int fdesc, i;
+ struct iob * io;
+ const char * filePath;
+ BVRef bvr;
-/*==========================================================================
- *
- *
- */
-static int
-ffs(register long mask)
-{
- register int cnt;
+ // Locate a free descriptor slot.
- if (mask == 0) return(0);
+ for (fdesc = 0; fdesc < NFILES; fdesc++)
+ if (iob[fdesc].i_flgs == 0)
+ goto gotfile;
- for (cnt = 1; !(mask & 1); cnt++)
- mask >>= 1;
- return(cnt);
-}
+ stop("Out of file descriptors");
-/*==========================================================================
- *
- *
- */
-static void
-disk_flushdev()
-{
- register int i;
-
- devflush();
+gotfile:
+ io = &iob[fdesc];
+ bzero(io, sizeof(*io));
+
+ // Mark the descriptor as taken.
+
+ io->i_flgs = F_ALLOC;
+
+ // Resolve the boot volume from the file spec.
+
+ if ((bvr = getBootVolumeRef(path, &filePath)) == NULL)
+ goto error;
+
+ // Find the next available memory block in the download buffer.
+
+ io->i_buf = (char *) LOAD_ADDR;
for (i = 0; i < NFILES; i++)
- if (iob[i].i_flgs & (F_READ | F_WRITE))
- error("flushdev: fd %d is open\n",i);
-
- fs_block_valid = 0;
-#if ICACHE
- cacheFlush(icache);
-#endif
-#if DCACHE
- cacheFlush(dcache);
-#endif
+ {
+ if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) continue;
+ io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
+ }
+
+ // Load entire file into memory. Unnecessary open() calls must
+ // be avoided.
+
+ gFSLoadAddress = io->i_buf;
+ io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
+ if (io->i_filesize < 0) goto error;
+
+ return fdesc;
+
+error:
+ close(fdesc);
+ return -1;
}
-/***************************************************************************
- *
- * Network functions.
- *
- ***************************************************************************/
+//==========================================================================
+// close() - Close a file descriptor.
-static int
-en_read(int fdesc, char * buf, int count)
+int close(int fdesc)
{
- struct iob * file;
+ struct iob * io;
- if ((file = iob_from_fdesc(fdesc)) == 0)
- return (-1);
-
- DSPRINT(("read[%d]: %x %x %d\n",
- fdesc, TFTP_ADDR + file->i_offset, (unsigned) buf, count));
+ if ((io = iob_from_fdesc(fdesc)) == NULL)
+ return (-1);
- bcopy((char *)(TFTP_ADDR + file->i_offset), buf, count);
- file->i_offset += count;
+ io->i_flgs = 0;
- return count;
+ return 0;
}
-
-static BOOL
-en_open(char * name, struct iob * file, int how)
+
+//==========================================================================
+// lseek() - Reposition the byte offset of the file descriptor from the
+// beginning of the file. Returns the relocated offset.
+
+int b_lseek(int fdesc, int offset, int ptr)
{
- unsigned long txferSize = TFTP_LEN;
-
- if (nbpTFTPReadFile(name, &txferSize, TFTP_ADDR) != nbpStatusSuccess)
- return NO;
+ struct iob * io;
- file->i_buf = NULL;
- file->i_offset = 0;
- file->i_ino.i_size = txferSize; // update the real size
+ if ((io = iob_from_fdesc(fdesc)) == NULL)
+ return (-1);
- return YES;
-}
+ io->i_offset = offset;
-static void
-en_devopen(char * name, struct iob * io)
-{
- io->i_error = 0;
+ return offset;
}
-/***************************************************************************
- *
- * Dispatch functions.
- *
- ***************************************************************************/
+//==========================================================================
+// tell() - Returns the byte offset of the file descriptor.
-/*==========================================================================
- *
- */
-static int
-gen_read(int fdesc, char * buf, int count)
+int tell(int fdesc)
{
- struct iob * file;
-
- if ((file = iob_from_fdesc(fdesc)) == 0)
- return (-1);
-
- return (file->i_ino.i_dev == DEV_EN) ?
- en_read(fdesc, buf, count) :
- disk_read(fdesc, buf, count);
-}
+ struct iob * io;
-/*==========================================================================
- *
- */
-static int
-gen_open(char * name, struct iob * file, int how)
-{
- return (file->i_ino.i_dev == DEV_EN) ?
- en_open(name, file, how) : disk_open(name, file, how);
+ if ((io = iob_from_fdesc(fdesc)) == NULL)
+ return 0;
+
+ return io->i_offset;
}
-/*==========================================================================
- *
- */
-static void
-gen_devopen(char * name, struct iob * io)
+//==========================================================================
+// read() - Read up to 'count' bytes of data from the file descriptor
+// into the buffer pointed to by buf.
+
+int read(int fdesc, char * buf, int count)
{
- return (io->i_ino.i_dev == DEV_EN) ?
- en_devopen(name, io) : devopen(name, io);
+ struct iob * io;
+
+ if ((io = iob_from_fdesc(fdesc)) == NULL)
+ return (-1);
+
+ if (io->i_offset + count > io->i_filesize)
+ count = io->i_filesize - io->i_offset;
+
+ if (count <= 0)
+ return 0; // end of file
+
+ bcopy(io->i_buf + io->i_offset, buf, count);
+
+ io->i_offset += count;
+
+ return count;
}
-/*==========================================================================
- *
- */
-static void
-gen_flushdev()
+//==========================================================================
+// file_size() - Returns the size of the file described by the file
+// descriptor.
+
+int file_size(int fdesc)
{
- return disk_flushdev();
+ struct iob * io;
+
+ if ((io = iob_from_fdesc(fdesc)) == 0)
+ return 0;
+
+ return io->i_filesize;
}
-/*==========================================================================
- *
- */
-static char *
-gen_usrDevices()
+//==========================================================================
+
+struct dirstuff * opendir(const char * path)
{
-#define NET_ARCH_DEVICES ""
+ struct dirstuff * dirp = 0;
+ const char * dirPath;
+ BVRef bvr;
+
+ if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
+ goto error;
+
+ dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
+ if (dirp == NULL)
+ goto error;
+
+ dirp->dir_path = newString(dirPath);
+ if (dirp->dir_path == NULL)
+ goto error;
+
+ dirp->dir_bvr = bvr;
+
+ return dirp;
- return (((currentdev() >> B_TYPESHIFT) & B_TYPEMASK) == DEV_EN) ?
- NET_ARCH_DEVICES : ARCH_DEVICES;
+error:
+ closedir(dirp);
+ return NULL;
}
-/***************************************************************************
- *
- * External functions.
- *
- ***************************************************************************/
+//==========================================================================
-/*==========================================================================
- *
- */
-struct dirstuff *
-opendir(char * path)
+int closedir(struct dirstuff * dirp)
{
- return disk_opendir(path);
+ if (dirp) {
+ if (dirp->dir_path) free(dirp->dir_path);
+ free(dirp);
+ }
+ return 0;
}
-/*==========================================================================
- *
- */
-int
-closedir(struct dirstuff * dirp)
+//==========================================================================
+
+int readdir(struct dirstuff * dirp, const char ** name, long * flags,
+ long * time)
{
- return disk_closedir(dirp);
+ return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
+ /* dirPath */ dirp->dir_path,
+ /* dirIndex */ &dirp->dir_index,
+ /* dirEntry */ (char **)name, flags, time );
}
-/*==========================================================================
- * get next entry in a directory.
- */
-struct direct *
-readdir(struct dirstuff * dirp)
+//==========================================================================
+
+int currentdev()
{
- return disk_readdir(dirp);
+ return kernBootStruct->kernDev;
}
-/*==========================================================================
- *
- */
-int
-b_lseek(int fdesc, unsigned int addr, int ptr)
+//==========================================================================
+
+int switchdev(int dev)
{
- register struct iob * io;
+ kernBootStruct->kernDev = dev;
+ return dev;
+}
- RDPRINT(("In lseek addr= %x\n", addr));
+//==========================================================================
-#if CHECK_CAREFULLY
- if (ptr != 0) {
- error("Seek not from beginning of file\n");
- return (-1);
- }
-#endif /* CHECK_CAREFULLY */
+const char * usrDevices()
+{
+ return (B_TYPE(currentdev()) == DEV_EN) ? "" : "/private/Drivers/i386";
+}
- if ((io = iob_from_fdesc(fdesc)) == 0) {
- return (-1);
- }
- io->i_offset = addr;
- io->i_bn = addr / DEV_BSIZE;
- io->i_cc = 0;
+//==========================================================================
- RDPRINT(("In end of lseek offset %x; bn %x\n", io->i_offset,io->i_bn));
+BVRef scanBootVolumes( int biosdev, int * count )
+{
+ BVRef bvr = 0;
- return (0);
+ switch ( BIOS_DEV_TYPE( biosdev ) )
+ {
+ case kBIOSDevTypeFloppy:
+ case kBIOSDevTypeHardDrive:
+ bvr = diskScanBootVolumes( biosdev, count );
+ break;
+ case kBIOSDevTypeNetwork:
+ bvr = nbpScanBootVolumes( biosdev, count );
+ break;
+ }
+ return bvr;
}
-/*==========================================================================
- *
- */
-int
-tell(int fdesc)
-{
- return iob[fdesc].i_offset;
-}
+//==========================================================================
-/*==========================================================================
- *
- */
-int
-read(int fdesc, char * buf, int count)
+void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen )
{
- return gen_read(fdesc, buf, count);
+ bvr->description( bvr, str, strMaxLen );
}
-/*==========================================================================
- *
- */
-int
-openmem(char * buf, int len)
-{
- register struct iob * file;
- int fdesc;
+//==========================================================================
- for (fdesc = 0; fdesc < NFILES; fdesc++)
- if (iob[fdesc].i_flgs == 0)
- goto gotfile;
- stop("Out of file descriptor slots");
+BVRef selectBootVolume( BVRef chain )
+{
+ BVRef bvr, bvr1 = 0, bvr2 = 0;
-gotfile:
- (file = &iob[fdesc])->i_flgs |= F_ALLOC;
- file->i_buf = buf;
- file->i_boff = len;
- file->i_offset = 0;
- file->i_flgs |= F_MEM;
- return fdesc;
-}
+ for ( bvr = chain; bvr; bvr = bvr->next )
+ {
+ if ( bvr->flags & kBVFlagNativeBoot ) bvr1 = bvr;
+ if ( bvr->flags & kBVFlagPrimary ) bvr2 = bvr;
+ }
-/*==========================================================================
- * Generic open call.
- */
-int
-open(char * str, int how)
-{
- register char * cp;
- register struct iob * file;
- int fdesc;
-
- DSPRINT(("In open %s\n", str));
-
-#if CHECK_CAREFULLY /* iob[] is in BSS, so it is guaranteed to be zero. */
- if (open_init == 0) {
- int i;
- for (i = 0; i < NFILES; i++)
- iob[i].i_flgs = 0;
- open_init = 1;
- }
-#endif
-
- for (fdesc = 0; fdesc < NFILES; fdesc++)
- if (iob[fdesc].i_flgs == 0)
- goto gotfile;
- stop("Out of file descriptor slots");
+ bvr = bvr1 ? bvr1 :
+ bvr2 ? bvr2 : chain;
-gotfile:
- (file = &iob[fdesc])->i_flgs |= F_ALLOC;
-
- if ((cp = xx(str, file)) == (char *) -1)
- {
- close(fdesc);
- return -1;
- }
-
- if (*cp == '\0') {
- file->i_flgs |= how+1;
- file->i_cc = 0;
- file->i_offset = 0;
- return (fdesc);
- }
-
- if (gen_open(cp, file, how) == NO) {
- close(fdesc);
- return -1;
- }
- return (fdesc);
+ return bvr;
}
-/*==========================================================================
- *
- */
+//==========================================================================
+
#define LP '('
#define RP ')'
+extern int gBIOSDev;
-static char * xx(char *str, struct iob *file)
+static BVRef getBootVolumeRef( const char * path, const char ** outPath )
{
- register char *cp = str, *xp;
- char ** dp;
- int old_dev = kernBootStruct->kernDev;
- int dev = (kernBootStruct->kernDev >> B_TYPESHIFT) & B_TYPEMASK;
- int unit = (kernBootStruct->kernDev >> B_UNITSHIFT) & B_UNITMASK;
- int part = (kernBootStruct->kernDev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
- int i;
- int no_dev;
- int biosOffset;
-
- biosOffset = unit; // set the device
-
- for (; *cp && *cp != LP; cp++) ;
- if (no_dev = !*cp) { // no left paren found
- cp = str;
- xp = devsw[dev];
- } else if (cp == str) { // paren but no device
- cp++;
- xp = devsw[dev];
- } else {
- xp = str;
- cp++;
- }
-
- for (dp = devsw; *dp; dp++)
- {
- if ((xp[0] == *dp[0]) && (xp[1] == *(dp[0] + 1)))
- goto gotdev;
- }
-
- error("Unknown device '%c%c'\n",xp[0],xp[1]);
- return ((char *)-1);
-
-gotdev:
- if (no_dev)
- goto none;
- i = 0;
- while (*cp >= '0' && *cp <= '9')
- {
- i = i * 10 + *cp++ - '0';
- unit = i; // get the specified unit number
- }
-
- biosOffset = unit; // set the device
-
- if (*cp == RP || no_dev)
- /* do nothing since ptol(")") returns 0 */ ;
- else if (*cp == ',')
- part = ptol(++cp); // get the specified partition number
- else if (cp[-1] == LP)
- part = ptol(cp);
- else {
-badoff:
- error("Missing offset specification\n");
- return ((char *)-1);
- }
-
- for ( ;!no_dev ;) { // skip after the right paren
- if (*cp == RP)
- break;
- if (*cp++)
- continue;
- goto badoff;
- }
-
-none:
- file->i_ino.i_dev = dev = dp - devsw;
- file->partition = part;
- file->biosdev = (BIOSDEV(dev)) + biosOffset;
-
- if (dev == DEV_SD) {
- file->biosdev += kernBootStruct->numIDEs;
- }
- else if (dev == DEV_EN) {
- file->biosdev = BIOS_DEV_EN;
+ const char * cp;
+ BVRef bvr;
+ int type = B_TYPE( kernBootStruct->kernDev );
+ int unit = B_UNIT( kernBootStruct->kernDev );
+ int part = B_PARTITION( kernBootStruct->kernDev );
+ int biosdev = gBIOSDev;
+ static BVRef lastBVR = 0;
+ static int lastKernDev;
+
+ // Search for left parenthesis in the path specification.
+
+ for (cp = path; *cp; cp++) {
+ if (*cp == LP || *cp == '/') break;
}
- else if (dev == DEV_HD && kernBootStruct->numIDEs == 0) {
- error("No IDE drives detected\n");
- return ((char *)-1);
- }
- kernBootStruct->kernDev = (dev << B_TYPESHIFT) |
- (unit << B_UNITSHIFT) |
- (part << B_PARTITIONSHIFT);
+ if (*cp != LP) // no left paren found
+ {
+ cp = path;
+ if ( lastBVR && lastKernDev == kernBootStruct->kernDev )
+ {
+ bvr = lastBVR;
+ goto quick_exit;
+ }
+ }
+ else if ((cp - path) == 2) // found "xx("
+ {
+ const struct devsw * dp;
+ const char * xp = path;
+ int i;
+
+ cp++;
+
+ // Check the 2 character device name pointed by 'xp'.
+
+ for (dp = devsw; dp->name; dp++)
+ {
+ if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
+ break; // found matching entry
+ }
+ if (dp->name == NULL)
+ {
+ error("Unknown device '%c%c'\n", xp[0], xp[1]);
+ return NULL;
+ }
+ type = dp - devsw; // kerndev type
+
+ // Extract the optional unit number from the specification.
+ // hd(unit) or hd(unit, part).
+
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ {
+ i = i * 10 + *cp++ - '0';
+ unit = i;
+ }
+
+ // Extract the optional partition number from the specification.
+
+ if (*cp == ',')
+ part = atoi(++cp);
+
+ // Skip past the right paren.
+
+ for ( ; *cp && *cp != RP; cp++) /* LOOP */;
+ if (*cp == RP) cp++;
+
+ biosdev = dp->biosdev;
+ }
+ else
+ {
+ // Bad device specifier, skip past the right paren.
- if (kernBootStruct->kernDev != old_dev)
- flushdev();
+ for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
+ if (*cp == RP) cp++;
+ }
- gen_devopen(str, file);
+ biosdev += (unit & kBIOSDevUnitMask);
- if (file->i_error)
- return (char *)-1;
- if (!no_dev && *cp) cp++;
+ if ((bvr = newBootVolumeRef(biosdev, part)) == NULL)
+ {
+ // error("newBootVolumeRef() error\n");
+ return NULL;
+ }
- gFilename = cp;
+ // Record the most recent device parameters in the
+ // KernBootStruct.
- return cp;
-}
+ kernBootStruct->kernDev = MAKEKERNDEV(type, unit, bvr->part_no);
-/*==========================================================================
- *
- */
-int
-close(int fdesc)
-{
- register struct iob * file;
- register int i;
-
- if ((file = iob_from_fdesc(fdesc)) == 0)
- return (-1);
-
- if ((file->i_flgs & F_MEM) == 0) {
-// free((char *)file->i_ffs);
- file->i_ffs = NULL;
- if (file->i_buf) {
- free(file->i_buf);
- file->i_buf = NULL;
- }
- for (i=0;i<NBUFS;i++)
- {
- if (b[i])
- { free(b[i]);
- b[i] = NULL;
- }
- blknos[i] = 0;
- }
- }
-
- file->i_flgs = 0;
- return (0);
-}
+ lastBVR = bvr;
+ lastKernDev = kernBootStruct->kernDev;
-/*==========================================================================
- *
- */
-int
-file_size(int fdesc)
-{
- register struct iob * io;
-
- if ((io = iob_from_fdesc(fdesc)) == 0)
- return (-1);
+quick_exit:
+ // Returns the file path following the device spec.
+ // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
- return io->i_ino.i_size;
-}
+ *outPath = cp;
-/*==========================================================================
- * ensure that all device caches are flushed,
- * because we are about to change the device media
- */
-void
-flushdev()
-{
- gen_flushdev();
+ return bvr;
}
-/*==========================================================================
- *
- */
-void
-stop(char * s)
-{
-#if CHECK_CAREFULLY
- register int i;
-
- for (i = 0; i < NFILES; i++)
- if (iob[i].i_flgs != 0)
- close(i);
-#endif CHECK_CAREFULLY
-
- /* textMode(); */ // can't call this function from here
- error("\n%s\n", s);
- sleep(4); // about to halt
- halt();
-}
+//==========================================================================
-/*==========================================================================
- *
- */
-int currentdev()
+static BVRef newBootVolumeRef( int biosdev, int partno )
{
- return kernBootStruct->kernDev;
-}
+ BVRef bvr, bvr1, bvrChain;
-/*==========================================================================
- *
- */
-int
-switchdev(int dev)
-{
- flushdev();
- kernBootStruct->kernDev = dev;
- return dev;
-}
+ // Fetch the volume list from the device.
-/*==========================================================================
- *
- */
-char *
-usrDevices()
-{
- return gen_usrDevices();
+ bvrChain = scanBootVolumes( biosdev, NULL );
+
+ // Look for a perfect match based on device and partition number.
+
+ for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
+ {
+ if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
+
+ bvr1 = bvr;
+ if ( bvr->part_no == partno ) break;
+ }
+
+ return bvr ? bvr : bvr1;
}