9os

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit a40b81b1c64504004d67f265b9284c7ca9f5f099
parent 19176444e19f44995419389945871864a8f3ed43
Author: Roberto Vargas <roberto.vargas@arm.com>
Date:   Thu, 16 May 2019 10:05:22 +0100

[dev] Add devblk.c

This driver is intended for block based devices (for example
sd cards) and it implements a very simplified version of a buffer
cache. The blocks actually written when the buffer is taken for
other block or when fsync() or sync() are called.

Change-Id: I3cbab2eb348cd2401e951adaa876ba581a5fcc86

Diffstat:
Adrivers/blk.h | 13+++++++++++++
Adrivers/devblk.c | 300+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtarget/hosted/rcode | 1+
3 files changed, 314 insertions(+), 0 deletions(-)

diff --git a/drivers/blk.h b/drivers/blk.h @@ -0,0 +1,13 @@ +typedef struct blk Blk; +typedef struct blkphy Blkphy; + +struct blk { + mutex_t m; + Blkphy *phy; +}; + +struct blkphy { + void (*init)(Blk *dev, Attr *attr); + int (*bread)(Blk *dev, long blkno, void *buf); + int (*bwrite)(Blk *dev, long blkno, void *buf); +}; diff --git a/drivers/devblk.c b/drivers/devblk.c @@ -0,0 +1,300 @@ +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <rcode/rcode.h> +#include <rcode/io.h> + +#include "dev.h" +#include "blk.h" + +#define NR_BUFFERS 1 +#define NR_BLKS 2 +#define BLKSIZ 512 + +typedef struct buffer Buffer; + +enum Odevqid { + Qblockfs, + Qraw, + Qctl, +}; + +enum bstatus { + BBUSY = 1 << 0, + BDIRTY = 1 << 1, + BVALID = 1 << 2, + BERROR = 1 << 3, +}; + +struct buffer { + int devno; + long block; + int flags; + void *ptr; + mutex_t mutex; +}; + +static char buffers[NR_BUFFERS][BLKSIZ]; +static Buffer bcache[NR_BUFFERS]; + +static const Dirtab dirtab[] = { + {"raw", Qraw, 0, O_READ | O_WRITE}, + {"ctl", Qctl, 0, O_READ | O_WRITE} +}; + +static Blk *blks[NR_BLKS]; +static int nblks; + +static int +blkwalk(Chan *c, const char *name) +{ + return devwalk(c, name, dirtab, NELEM(dirtab), devgen); +} + +static int +blkstat(Chan *c, char *file, unsigned char *buf, int n) +{ + return devstat(c, file, buf, n, dirtab, NELEM(dirtab), devgen); +} + +static Buffer * +getblk(int devno, long blkno) +{ + Buffer *bp = &bcache[blkno % NR_BUFFERS]; + Blk *dev; + +repeat: + lock(&bp->mutex); + if (bp->flags & BBUSY) { + unlock(&bp->mutex); + /* TODO: sleep(); */ + goto repeat; + } + + if ((bp->flags & BVALID) == 0 || + bp->devno != devno || bp->block != blkno) { + if (bp->flags & BDIRTY) { + dev = blks[bp->devno]; + if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) { + errno = EIO; + bp->flags |= BERROR; + goto return_buffer; + } + } + + bp->devno = devno; + bp->block = blkno; + bp->flags = 0; + dev = blks[devno]; + + switch (dev->phy->bread(dev, blkno, bp->ptr)) { + case -1: + bp->flags |= BERROR; + break; + case 1: + bp->flags |= BVALID; + break; + } + } + +return_buffer: + bp->flags |= BBUSY; + unlock(&bp->mutex); + return bp; +} + +static int +brelse(Buffer *bp) +{ + int r = 0; + Blk *dev; + + if ((bp->flags & BBUSY) == 0) + panic("brelse"); + + lock(&bp->mutex); + if ((bp->flags & BDIRTY) != 0) { + dev = blks[bp->devno]; + if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) { + errno = EIO; + bp->flags |= BERROR; + r = -1; + } + } + bp->flags &= ~(BBUSY|BDIRTY); + unlock(&bp->mutex); + + return r; +} + +static int +rawread(Chan *c, void *buf, int nbytes) +{ + int n, cnt; + Buffer *bp; + long off, blk; + char *ptr = buf; + + for (cnt = 0; cnt < nbytes; cnt += n) { + blk = c->offset / BLKSIZ; + off = c->offset % BLKSIZ; + + bp = getblk(c->dev, blk); + switch (bp->flags & (BVALID | BERROR)) { + case BVALID|BERROR: + case BERROR: + cnt = -1; + case 0: + brelse(bp); + return cnt; + case BVALID: + n = BLKSIZ - off; + if (n > nbytes) + n = nbytes; + memcpy(ptr, bp->ptr + off, n); + ptr += n; + c->offset += n; + bp->flags |= BDIRTY; + brelse(bp); + break; + } + } + + return cnt; +} + +static int +blkread(Chan *c, void *buf, int n) +{ + switch (c->qid & ~CHDIR) { + case Qblockfs: + return dirread(c, buf, n, dirtab, NELEM(dirtab), devgen); + case Qraw: + return rawread(c, buf, n); + case Qctl: + /* TODO */ + default: + panic("blkread"); + } +} + +static int +rawwrite(Chan *c, void *buf, int nbytes) +{ + int n, cnt; + Buffer *bp; + long off, blk; + char *ptr = buf; + + for (cnt = 0; cnt < nbytes; cnt += n) { + blk = c->offset / BLKSIZ; + off = c->offset % BLKSIZ; + + bp = getblk(c->dev, blk); + switch (bp->flags & (BVALID | BERROR)) { + case 0: + errno = EFBIG; + case BVALID|BERROR: + case BERROR: + brelse(bp); + return -1; + case BVALID: + n = BLKSIZ - off; + if (n > nbytes) + n = nbytes; + memcpy(bp->ptr + off, ptr, n); + ptr += n; + c->offset += n; + bp->flags |= BDIRTY; + brelse(bp); + break; + } + } + return cnt; +} + +static int +blkwrite(Chan *c, void *buf, int n) +{ + switch (c->qid & ~CHDIR) { + case Qraw: + return rawwrite(c, buf, n); + case Qctl: + /* TODO */ + default: + panic("blkwrite"); + } +} + +static int +blksync(Chan *c, int what) +{ + Blk *dev; + Buffer *bp; + int r = 0; + + for (bp = bcache; bp < &bcache[NR_BUFFERS]; ++bp) { + lock(&bp->mutex); + + if ((bp->flags & BDIRTY) != 0 && + (what == SYNCALL || bp->devno == c->dev)) { + dev = blks[bp->devno]; + if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) { + r = -1; + errno = EIO; + bp->flags |= BERROR; + } else { + bp->flags &= BDIRTY; + } + } + + unlock(&bp->mutex); + } + + return r; +} + +void +blklink(Blkphy *phy, Attr *attr) +{ + size_t siz; + Blk *dev; + static int first = 1; + + if (nblks == NR_BLKS) + panic("blklink"); + + if (first) { + int i; + Buffer *bp; + + for (i = 0; i < NR_BUFFERS; i++) { + bp = &bcache[i]; + bp->ptr = buffers[i]; + bp->flags = 0; + } + first = 0; + } + + siz = sizeof(Blk); + dev = memset(alloc(siz), 0, siz); + dev->phy = phy; + blks[nblks++] = dev; + + (*phy->init)(dev, attr); +} + +const Dev blkdevtab = { + .id = 'b', + .stat = blkstat, + .clone = devclone, + .attach = devattach, + .walk = blkwalk, + .read = blkread, + .write = blkwrite, + .mount = deverrmount, + .seek = devseek, + .sync = blksync, +}; diff --git a/target/hosted/rcode b/target/hosted/rcode @@ -4,6 +4,7 @@ dev dummyuart base=0x1c0c0000,clk=24000000,cfg=b115200 l8 #t0 dummyuart base=0x1c0c0100,clk=24000000 #t1 cons + blk ar blob bios 0x100,0x400