📄 devflash.c
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"/* * on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit * accesses, one to the low half of the chip and the other to the high * half. Therefore for all command accesses, ushort indices in the * manuals turn into ulong indices in our code. Also, by copying all * 16 bit commands to both halves of a 32 bit command, we erase 2 * sectors for each request erase request. */#define mirror(x) (((x)<<16)|(x))/* this defines a contiguous set of erase blocks of one size */typedef struct FlashRegion FlashRegion;struct FlashRegion{ ulong addr; /* start of region */ ulong end; /* end of region + 1 */ ulong n; /* number of blocks */ ulong size; /* size of each block */};/* this defines a particular access algorithm */typedef struct FlashAlg FlashAlg;struct FlashAlg{ int id; char *name; void (*identify)(void); /* identify device */ void (*erase)(ulong); /* erase a region */ void (*write)(void*, long, ulong); /* write a region */};static void ise_id(void);static void ise_erase(ulong);static void ise_write(void*, long, ulong);static void afs_id(void);static void afs_erase(ulong);static void afs_write(void*, long, ulong);static ulong blockstart(ulong);static ulong blockend(ulong);FlashAlg falg[] ={ { 1, "Intel/Sharp Extended", ise_id, ise_erase, ise_write }, { 2, "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write },};struct{ RWlock; ulong *p; ushort algid; /* access algorithm */ FlashAlg *alg; ushort manid; /* manufacturer id */ ushort devid; /* device id */ ulong size; /* size in bytes */ int wbsize; /* size of write buffer */ ulong nr; /* number of regions */ uchar bootprotect; FlashRegion r[32];} flash;enum{ Maxwchunk= 1024, /* maximum chunk written by one call to falg->write */};/* * common flash interface */static ucharcfigetc(int off){ uchar rv; flash.p[0x55] = mirror(0x98); rv = flash.p[off]; flash.p[0x55] = mirror(0xFF); return rv;}static ushortcfigets(int off){ return (cfigetc(off+1)<<8)|cfigetc(off);}static ulongcfigetl(int off){ return (cfigetc(off+3)<<24)|(cfigetc(off+2)<<16)| (cfigetc(off+1)<<8)|cfigetc(off);}static voidcfiquery(void){ uchar q, r, y; ulong x, addr; q = cfigetc(0x10); r = cfigetc(0x11); y = cfigetc(0x12); if(q != 'Q' || r != 'R' || y != 'Y'){ print("cfi query failed: %ux %ux %ux\n", q, r, y); return; } flash.algid = cfigetc(0x13); flash.size = 1<<(cfigetc(0x27)+1); flash.wbsize = 1<<(cfigetc(0x2a)+1); flash.nr = cfigetc(0x2c); if(flash.nr > nelem(flash.r)){ print("cfi reports > %d regions\n", nelem(flash.r)); flash.nr = nelem(flash.r); } addr = 0; for(q = 0; q < flash.nr; q++){ x = cfigetl(q+0x2d); flash.r[q].size = 2*256*(x>>16); flash.r[q].n = (x&0xffff)+1; flash.r[q].addr = addr; addr += flash.r[q].size*flash.r[q].n; flash.r[q].end = addr; }}/* * flash device interface */enum{ Qtopdir, Q2nddir, Qfctl, Qfdata, Maxpart= 8,};typedef struct FPart FPart;struct FPart{ char *name; char *ctlname; ulong start; ulong end;};static FPart part[Maxpart];#define FQID(p,q) ((p)<<8|(q))#define FTYPE(q) ((q) & 0xff)#define FPART(q) (&part[(q) >>8])static intgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp){ Qid q; FPart *fp; q.vers = 0; /* top level directory contains the name of the network */ if(c->qid.path == Qtopdir){ switch(i){ case DEVDOTDOT: q.path = Qtopdir; q.type = QTDIR; devdir(c, q, "#F", 0, eve, DMDIR|0555, dp); break; case 0: q.path = Q2nddir; q.type = QTDIR; devdir(c, q, "flash", 0, eve, DMDIR|0555, dp); break; default: return -1; } return 1; } /* second level contains all partitions and their control files */ switch(i) { case DEVDOTDOT: q.path = Qtopdir; q.type = QTDIR; devdir(c, q, "#F", 0, eve, DMDIR|0555, dp); break; default: if(i >= 2*Maxpart) return -1; fp = &part[i>>1]; if(fp->name == nil) return 0; if(i & 1){ q.path = FQID(i>>1, Qfdata); q.type = QTFILE; devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp); } else { q.path = FQID(i>>1, Qfctl); q.type = QTFILE; devdir(c, q, fp->ctlname, 0, eve, 0660, dp); } break; } return 1;}static FPart*findpart(char *name){ int i; for(i = 0; i < Maxpart; i++) if(part[i].name != nil && strcmp(name, part[i].name) == 0) break; if(i >= Maxpart) return nil; return &part[i];}static voidaddpart(FPart *fp, char *name, ulong start, ulong end){ int i; char ctlname[64]; if(fp == nil){ if(start >= flash.size || end > flash.size) error(Ebadarg); } else { start += fp->start; end += fp->start; if(start >= fp->end || end > fp->end) error(Ebadarg); } if(blockstart(start) != start) error("must start on erase boundary"); if(blockstart(end) != end && end != flash.size) error("must end on erase boundary"); fp = findpart(name); if(fp != nil) error(Eexist); for(i = 0; i < Maxpart; i++) if(part[i].name == nil) break; if(i == Maxpart) error("no more partitions"); fp = &part[i]; kstrdup(&fp->name, name); snprint(ctlname, sizeof ctlname, "%sctl", name); kstrdup(&fp->ctlname, ctlname); fp->start = start; fp->end = end;}static voidrempart(FPart *fp){ char *p, *cp; p = fp->name; fp->name = nil; cp = fp->ctlname; fp->ctlname = nil; free(p); free(cp);}voidflashinit(void){ int i; flash.p = (ulong*)FLASHZERO; cfiquery(); for(i = 0; i < nelem(falg); i++) if(flash.algid == falg[i].id){ flash.alg = &falg[i]; (*flash.alg->identify)(); break; } flash.bootprotect = 1; addpart(nil, "flash", 0, flash.size);}static Chan*flashattach(char* spec){ return devattach('F', spec);}static Walkqid*flashwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, nil, 0, gen);}static int flashstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, nil, 0, gen);}static Chan*flashopen(Chan* c, int omode){ omode = openmode(omode); if(strcmp(up->user, eve)!=0) error(Eperm); return devopen(c, omode, nil, 0, gen);}static void flashclose(Chan*){}static longflashctlread(FPart *fp, void* a, long n, vlong off){ char *buf, *p, *e; int i; ulong addr, end; buf = smalloc(1024); e = buf + 1024; p = seprint(buf, e, "0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n", fp->end-fp->start, flash.wbsize, flash.manid, flash.devid); addr = fp->start; for(i = 0; i < flash.nr && addr < fp->end; i++) if(flash.r[i].addr <= addr && flash.r[i].end > addr){ if(fp->end <= flash.r[i].end) end = fp->end; else end = flash.r[i].end; p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr, (end-addr)/flash.r[i].size, flash.r[i].size); addr = end; } n = readstr(off, a, n, buf); free(buf); return n;}static longflashdataread(FPart *fp, void* a, long n, vlong off){ rlock(&flash); if(waserror()){ runlock(&flash); nexterror(); } if(fp->name == nil) error("partition vanished"); if(!iseve()) error(Eperm); off += fp->start; if(off >= fp->end) n = 0; if(off+n >= fp->end) n = fp->end - off; if(n > 0) memmove(a, ((uchar*)FLASHZERO)+off, n); runlock(&flash); poperror(); return n;}static long flashread(Chan* c, void* a, long n, vlong off){ int t; if(c->qid.type == QTDIR) return devdirread(c, a, n, nil, 0, gen); t = FTYPE(c->qid.path); switch(t){ default: error(Eperm); case Qfctl: n = flashctlread(FPART(c->qid.path), a, n, off); break; case Qfdata: n = flashdataread(FPART(c->qid.path), a, n, off); break; } return n;}static voidbootprotect(ulong addr){ FlashRegion *r; if(flash.bootprotect == 0) return; if(flash.nr == 0) error("writing over boot loader disallowed"); r = flash.r; if(addr >= r->addr && addr < r->addr + r->size) error("writing over boot loader disallowed");}static ulongblockstart(ulong addr){ FlashRegion *r, *e; ulong x; r = flash.r; for(e = &flash.r[flash.nr]; r < e; r++) if(addr >= r->addr && addr < r->end){ x = addr - r->addr; x /= r->size; return r->addr + x*r->size; } return (ulong)-1;}static ulongblockend(ulong addr){ FlashRegion *r, *e;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -