📄 devflash.c
字号:
FlashRegion *r; Flash *flash; flash = findflash(addr); if (flash == nil) error(Ebadarg); 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(Flash *flash, 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(Flash *flash, 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+1)*r->size; } return (ulong)-1;}static longflashctlwrite(FPart *fp, char *p, long n){ Cmdbuf *cmd; ulong off; Flash *flash; if(fp == nil) panic("flashctlwrite"); flash = fp->flash; cmd = parsecmd(p, n); wlock(flash); if(waserror()){ wunlock(flash); nexterror(); } if(strcmp(cmd->f[0], "erase") == 0){ switch(cmd->nf){ case 2: /* erase a single block in the partition */ off = atoi(cmd->f[1]); off += fp->start; if(off >= fp->end) error("region not in partition"); if(off != blockstart(flash, off)) error("erase must be a block boundary"); bootprotect(off); (*flash->alg->erase)(flash, off); break; case 1: /* erase the whole partition */ bootprotect(fp->start); for(off = fp->start; off < fp->end; off = blockend(flash, off)) (*flash->alg->erase)(flash, off); break; default: error(Ebadarg); } } else if(strcmp(cmd->f[0], "add") == 0){ if(cmd->nf != 4) error(Ebadarg); addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0)); } else if(strcmp(cmd->f[0], "remove") == 0){ rempart(fp); } else if(strcmp(cmd->f[0], "protectboot") == 0){ if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0) flash->bootprotect = 1; else flash->bootprotect = 0; } else error(Ebadarg); poperror(); wunlock(flash); free(cmd); return n;}static longflashdatawrite(FPart *fp, uchar *p, long n, long off){ uchar *end; int m; int on; long ooff; uchar *buf; Flash *flash; if(fp == nil) panic("flashdatawrite"); flash = fp->flash; buf = nil; wlock(flash); if(waserror()){ wunlock(flash); if(buf != nil) free(buf); nexterror(); } if(fp->name == nil) error("partition vanished"); if(!iseve()) error(Eperm); /* can't cross partition boundaries */ off += fp->start; if(off >= fp->end || off+n > fp->end || n <= 0) error(Ebadarg); /* make sure we're not writing the boot sector */ bootprotect(off); on = n; /* * get the data into kernel memory to avoid faults during writing. * if write is not on a quad boundary or not a multiple of 4 bytes, * extend with data already in flash. */ buf = smalloc(n+8); m = off & 3; if(m){ *(ulong*)buf = flash->p[off>>Wshift]; n += m; off -= m; } if(n & 3){ n -= n & 3; *(ulong*)(&buf[n]) = flash->p[(off+n)>>Wshift]; n += 4; } memmove(&buf[m], p, on); /* (*flash->alg->write) can't cross blocks */ ooff = off; p = buf; for(end = p + n; p < end; p += m){ m = blockend(flash, off) - off; if(m > end - p) m = end - p; if(m > Maxwchunk) m = Maxwchunk; (*flash->alg->write)(flash, p, m, off); off += m; } /* make sure write succeeded */ if(memcmp(buf, &flash->p[ooff>>Wshift], n) != 0) error("written bytes don't match"); wunlock(flash); free(buf); poperror(); return on;}static long flashwrite(Chan* c, void* a, long n, vlong off){ int t; if(c->qid.type == QTDIR) error(Eperm); if(!iseve()) error(Eperm); t = FTYPE(c->qid.path); switch(t){ default: panic("flashwrite"); case Qfctl: n = flashctlwrite(FPART(c->qid.path), a, n); break; case Qfdata: n = flashdatawrite(FPART(c->qid.path), a, n, off); break; } return n;}Dev flashdevtab = { 'F', "flash", devreset, flashinit, devshutdown, flashattach, flashwalk, flashstat, flashopen, devcreate, flashclose, flashread, devbread, flashwrite, devbwrite, devremove, devwstat,};enum{ /* status register */ ISEs_lockerr= 1<<1, ISEs_powererr= 1<<3, ISEs_progerr= 1<<4, ISEs_eraseerr= 1<<5, ISEs_ready= 1<<7, ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr), /* extended status register */ ISExs_bufavail= 1<<7,};/* intel/sharp extended command set */static voidise_reset(Flash* flash){ flash->p[reg(0xaa)] = mirror(0xff); /* reset */}static voidise_id(Flash* flash){ ise_reset(flash); flash->p[reg(0xaaa)] = mirror(0x90); /* uncover vendor info */ flash->manid = fromendian(flash->p[reg(0x0)]); flash->devid = fromendian(flash->p[reg(0x1)]); ise_reset(flash);}static voidise_clearerror(Flash* flash){ flash->p[reg(0x200)] = mirror(0x50);}static voidise_error(int bank, ulong status){ char err[64]; if(status & (ISEs_lockerr)){ sprint(err, "flash%d: block locked %lux", bank, status); error(err); } if(status & (ISEs_powererr)){ sprint(err, "flash%d: low prog voltage %lux", bank, status); error(err); } if(status & (ISEs_progerr|ISEs_eraseerr)){ sprint(err, "flash%d: i/o error %lux", bank, status); error(err); }}static voidise_erase(Flash *flash, ulong addr){ ulong start; ulong x; addr >>= Wshift; flashprogpower(1); flash->p[addr] = mirror(0x20); flash->p[addr] = mirror(0xd0); start = m->ticks; do { x = fromendian(flash->p[addr]); if((x & mirror(ISEs_ready)) == mirror(ISEs_ready)) break; } while(TK2MS(m->ticks-start) < 1500); flashprogpower(0); ise_clearerror(flash); ise_error(0, x); ise_error(1, x>>16); ise_reset(flash);}/* * the flash spec claimes writing goes faster if we use * the write buffer. We fill the write buffer and then * issue the write request. After the write request, * subsequent reads will yield the status register. * * returns the status, even on timeouts. * * NOTE: I tried starting back to back buffered writes * without reading the status in between, as the * flowchart in the intel data sheet suggests. * However, it always responded with an illegal * command sequence, so I must be missing something. * If someone learns better, please email me, though * I doubt it will be much faster. - presotto@bell-labs.com */static longise_wbwrite(Flash *flash, Fword *p, int n, ulong off, ulong baddr, ulong *status){ Fword x; ulong start; int i; int s; /* put flash into write buffer mode */ start = m->ticks; for(;;) { s = splhi(); /* request write buffer mode */ flash->p[baddr] = mirror(0xe8); /* look at extended status reg for status */ if((flash->p[baddr] & mirror(1<<7)) == mirror(1<<7)) break; splx(s); /* didn't work, keep trying for 2 secs */ if(TK2MS(m->ticks-start) > 2000){ /* set up to read status */ flash->p[baddr] = mirror(0x70); *status = fromendian(flash->p[baddr]); pprint("write buffered cmd timed out\n"); return -1; } } /* fill write buffer */ flash->p[baddr] = mirror(n-1); for(i = 0; i < n; i++) flash->p[off+i] = *p++; /* program from buffer */ flash->p[baddr] = mirror(0xd0); splx(s); /* wait till the programming is done */ start = m->ticks; for(;;) { x = flash->p[baddr]; /* read status register */ *status = fromendian(x); if((x & mirror(ISEs_ready)) == mirror(ISEs_ready)) break; if(TK2MS(m->ticks-start) > 2000){ pprint("read status timed out\n"); return -1; } } if(x & mirror(ISEs_err)) return -1; return n;}static voidise_write(Flash *flash, void *a, long n, ulong off){ Fword *p, *end; int i, wbsize; ulong x, baddr; /* everything in terms of Fwords */ wbsize = flash->wbsize >> Wshift; baddr = blockstart(flash, off) >> Wshift; off >>= Wshift; n >>= Wshift; p = a; /* first see if write will succeed */ for(i = 0; i < n; i++) if((p[i] & flash->p[off+i]) != p[i]) error("flash needs erase"); if(waserror()){ ise_reset(flash); flashprogpower(0); nexterror(); } flashprogpower(1); /* * use the first write to reach * a write buffer boundary. the intel maunal * says writes starting at wb boundaries * maximize speed. */ i = wbsize - (off & (wbsize-1)); for(end = p + n; p < end;){ if(i > end - p) i = end - p; if(ise_wbwrite(flash, p, i, off, baddr, &x) < 0) break; off += i; p += i; i = wbsize; } ise_clearerror(flash); ise_error(0, x); ise_error(1, x>>16); ise_reset(flash); flashprogpower(0); poperror();}/* amd/fujitsu standard command set * I don't have an amd chipset to work with * so I'm loathe to write this yet. If someone * else does, please send it to me and I'll * incorporate it -- presotto@bell-labs.com */static voidafs_reset(Flash *flash){ flash->p[reg(0xaa)] = mirror(0xf0); /* reset */}static voidafs_id(Flash *flash){ afs_reset(flash); flash->p[reg(0xaa)] = mirror(0xf0); /* reset */ flash->p[reg(0xaaa)] = mirror(0xaa); /* query vendor block */ flash->p[reg(0x554)] = mirror(0x55); flash->p[reg(0xaaa)] = mirror(0x90); flash->manid = fromendian(flash->p[reg(0x00)]); afs_reset(flash); flash->p[reg(0xaaa)] = mirror(0xaa); /* query vendor block */ flash->p[reg(0x554)] = mirror(0x55); flash->p[reg(0xaaa)] = mirror(0x90); flash->devid = fromendian(flash->p[reg(0x02)]); afs_reset(flash);}static voidafs_erase(Flash*, ulong){ error("amd/fujistsu erase not implemented");}static voidafs_write(Flash*, void*, long, ulong){ error("amd/fujistsu write not implemented");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -