Logo Search packages:      
Sourcecode: palo version File versions  Download package

byteio.c

/* 
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) Hewlett-Packard (Paul Bame) paul_bame@hp.com
 */
#include "bootloader.h"

/* A bunch of little routines to make reading the boot device easier.
 *    Caller can seekread into unaligned buffers
 *      Caller can seekread arbitrary amounts of data
 *      Caller can sort-of pretend they have a random-access device,
 *              as long as they only "seek" forwards.
 *      Caller need not keep track of where they are as much as before.
 *      Caller doesn't need to handle error returns -- there aren't any
 *              because a good error recovery isn't designed in, nor
 *              does bootdev_sread() check/recover in some cases I think.
 *
 *                                      -Paul Bame
 */

/* this struct should be considered private except to b2b.c */
struct bs
{
    short fd;     /* fd of underlying device */

    /* block size of underlying device */
    int blocksize;
    /* alignment for reads from device */
    int align;

    /* data in 'bd_readbuf' was seekread from boot device offset 'bd_bufoffset' */
    int devoffset;

    /* offset of next byte to be seekread from device */
    int devnextptr;

    /* pointer to the properly-aligned 'blocksize' buffer */
    char *readbuf;
};

static struct bs *blockio = 0;

static int
delivercache(struct bs *b, char **buf, unsigned *devaddr, unsigned endaddr)
{
    unsigned block = *devaddr & ~(b->blocksize - 1);
    int offset = *devaddr - block;
    int n = 0;

    if (block == b->devoffset)            /* anything useful in the cache? */
    {
      n = b->blocksize - offset;    /* we could deliver this many bytes */
      if (n > endaddr - *devaddr)   /* user might want fewer bytes */
          n = endaddr - *devaddr;

      /* copy into user's buffer */
      memcpy(*buf, b->readbuf + offset, n);
      if (Debug) printf("delivercache: %d bytes from devaddr 0x%x to 0x%p\r\n",
            n, *devaddr, *buf);

      *devaddr += n;
      *buf += n;
    }

    return n;
}

static int
cacheblock(struct bs *b, unsigned devaddr)
{
    int n;
    unsigned block = devaddr & ~(b->blocksize - 1);

    if ((n = seekread(b->fd, b->readbuf, b->blocksize, block)) != b->blocksize)
    {
      printf("byteio_read: seekread() returned %d expected %d\n",
          n, b->blocksize);
          
      return 0;
    }
    b->devoffset = block;
    if (Debug) printf("cacheblock: cached block at devaddr 0x%x\r\n", devaddr);
    return 1;
}

static int byteio_read(int fd, char *buf, unsigned count, unsigned devaddr)
{
    struct bs *b = &blockio[fd];
    unsigned endaddr = devaddr + count;
    unsigned remember = devaddr;

    if (Debug) printf("byteio_read(fd:%d, buf:%p, count:%u, devaddr:0x%x)\r\n",
      fd, buf, count, devaddr);

    while (devaddr < endaddr)
    {
      int n, bigread;
      char *alignedbuf;

      if (Debug) printf("b_r: buf:0x%p devaddr 0x%x %s endaddr 0x%x\r\n",
            buf, devaddr, 
            (devaddr & (b->blocksize - 1)) == 0 ? "aligned" : "unaligned",
            endaddr);

      if (delivercache(b, &buf, &devaddr, endaddr) > 0)
          continue;

      /* if not block aligned, use the cache */
      if ((devaddr & (b->blocksize - 1)) != 0)
      {
          if (!cacheblock(b, devaddr))
            return -1;
          continue;
      }

      /* devaddr is aligned.  If < 2 blocks remain, just use the cache */
      if (endaddr - devaddr < b->blocksize * 2)
      {
          if (!cacheblock(b, devaddr))
            return -1;
          continue;
      }

      /* devaddr is aligned and there are >= 2 blocks remaining */
      bigread = endaddr - devaddr;

      /* user's buf is probably not aligned */
      alignedbuf = (char *)(((unsigned int) buf + (b->align - 1)) &
                  ~(b->align - 1));

      /* alignment loss */
      bigread -= alignedbuf - buf;

      /* must be a multiple of blocksize */
      bigread &= ~(b->blocksize - 1);

      if (Debug) printf("reading %u bytes from dev %x to ubuf %p\r\n",
                        bigread, devaddr, alignedbuf);
      /* read the blocks into user's buf */
      if ((n = seekread(b->fd, alignedbuf, bigread, devaddr))
                != bigread)
      {
          printf("byteio_read: seekread() returned %d expected %d\n",
            n, bigread);
            
          return -1;
      }

      if (buf != alignedbuf)
      {
          /* move user's data to the right place in their buffer */
          if (Debug) printf("moving %u bytes from %p to %p\r\n", n, alignedbuf, buf);
          memcpy(buf, alignedbuf, n);
      }
      devaddr += n;
      buf += n;
    }

    return devaddr - remember;
}

static void byteio_describe(int fd, int *bufalign,
                        int *blocksize)
{
    if (bufalign != 0)
      *bufalign = 1;

    if (blocksize != 0)
      *blocksize = 1;
}

/* returns true if OK */
int byteio_open(int otherfd)
{
    int fd = fileio_open(byteio_describe, byteio_read);

    if (blockio == 0)
    {
      int sz = sizeof blockio[0] * MAX_FD;
      blockio = (struct bs *)malloc(sz);
    }

    if (fd >= 0)
    {
      struct bs *b = &blockio[fd];

      memset(b, 0, sizeof *b);
      b->fd = otherfd;
      describe(otherfd, &b->align, &b->blocksize);

      b->readbuf = malloc_aligned(b->blocksize, b->align);

      if (!cacheblock(b, 0))
          die("initial read failed");
    }

    return fd;
}

/* $Id: byteio.c,v 1.1 2000/02/29 17:41:28 bame Exp $ */

Generated by  Doxygen 1.6.0   Back to index