diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/mpc/qflash.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/cmd/mpc/qflash.b')
| -rw-r--r-- | appl/cmd/mpc/qflash.b | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/appl/cmd/mpc/qflash.b b/appl/cmd/mpc/qflash.b new file mode 100644 index 00000000..13c77ce8 --- /dev/null +++ b/appl/cmd/mpc/qflash.b @@ -0,0 +1,188 @@ +implement Writeflash; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "string.m"; + str: String; + +Writeflash: module +{ + init: fn(nil: ref Draw->Context, args: list of string); +}; + +Region: adt { + base: int; + limit: int; +}; + +# could come from file or #F/flash/flashctl +FLASHSEG: con 256*1024; +kernelregion := Region(FLASHSEG, FLASHSEG+2*FLASHSEG); +bootregion := Region(0, FLASHSEG); + +stderr: ref Sys->FD; +prog := "qflash"; +damaged := 0; + +usage() +{ + sys->fprint(stderr, "Usage: %s [-b] [-o offset] [-f flashdev] file\n", prog); + exit; +} + +err(s: string) +{ + sys->fprint(stderr, "%s: %s", prog, s); + if(!damaged) + sys->fprint(stderr, "; flash not modified\n"); + else + sys->fprint(stderr, "; flash might now be invalid\n"); + exit; +} + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil); + stderr = sys->fildes(2); + if(args != nil){ + prog = hd args; + args = tl args; + } + str = load String String->PATH; + if(str == nil) + err(sys->sprint("can't load %s: %r", String->PATH)); + region := kernelregion; + flash := "#F/flash/flash"; + offset := 0; + save := 0; + + for(; args != nil && (hd args)[0] == '-'; args = tl args) + case hd args { + "-b" => + region = bootregion; + offset = 16r100 - 8*4; # size of exec header + save = 1; + "-h" => + region.limit += FLASHSEG; + "-f" => + if(tl args == nil) + usage(); + flash = hd args; + args = tl args; + "-o" => + if(tl args == nil) + usage(); + args = tl args; + s := hd args; + v: int; + rs: string; + if(str->prefix("16r", s)) + (v, rs) = str->toint(s[3:], 16); + else if(str->prefix("0x", s)) + (v, rs) = str->toint(s[2:], 16); + else if(str->prefix("0", s)) + (v, rs) = str->toint(s[1:], 8); + else + (v, rs) = str->toint(s, 10); + if(v < 0 || len rs != 0) + err(sys->sprint("bad offset: %s", s)); + offset = v; + "-s" => + save = 1; + * => + usage(); + } + if(args == nil) + usage(); + fname := hd args; + fd := sys->open(fname, Sys->OREAD); + if(fd == nil) + err(sys->sprint("can't open %s: %r", fname)); + (r, dir) := sys->fstat(fd); + if(r < 0) + err(sys->sprint("can't stat %s: %r", fname)); + length := int dir.length; + avail := region.limit - (region.base+offset); + if(length > avail) + err(sys->sprint("%s contents %ud bytes, exceeds flash region %ud bytes", fname, length, avail)); + # check fname's contents... + where := region.base+offset; + saved: list of (int, array of byte); + if(save){ + saved = saveflash(flash, region.base, where) :: saved; + saved = saveflash(flash, where+length, region.limit) :: saved; + } + for(i := (region.base+offset)/FLASHSEG; i < region.limit/FLASHSEG; i++) + erase(flash, i); + out := sys->open(flash, Sys->OWRITE); + if(out == nil) + err(sys->sprint("can't open %s for writing: %r", flash)); + if(sys->seek(out, big where, 0) != big where) + err(sys->sprint("can't seek to #%6.6ux on flash: %r", where)); + if(length) + sys->print("writing %ud bytes to %s at #%6.6ux\n", length, flash, where); + buf := array[Sys->ATOMICIO] of byte; + total := 0; + while((n := sys->read(fd, buf, len buf)) > 0) { + if(total+n > avail) + err(sys->sprint("file %s too big for region of %ud bytes", fname, avail)); + r = sys->write(out, buf, n); + damaged = 1; + if(r != n){ + if(r < 0) + err(sys->sprint("error writing %s at byte %ud: %r", flash, total)); + else + err(sys->sprint("short write on %s at byte %ud", flash, total)); + } + total += n; + } + if(n < 0) + err(sys->sprint("error reading %s: %r", fname)); + sys->print("wrote %ud bytes from %s to flash %s (#%6.6ux-#%6.6ux)\n", total, fname, flash, region.base, region.base+total); + for(l := saved; l != nil; l = tl l){ + (addr, data) := hd l; + n = len data; + if(n == 0) + continue; + sys->print("restoring %ud bytes at #%6.6ux\n", n, addr); + if(sys->seek(out, big addr, 0) != big addr) + err(sys->sprint("can't seek to #%6.6ux on %s: %r", addr, flash)); + r = sys->write(out, data, n); + if(r < 0) + err(sys->sprint("error writing %s: %r", flash)); + else if(r != n) + err(sys->sprint("short write on %s at byte %ud/%ud", flash, r, n)); + else + sys->print("restored %ud bytes at #%6.6ux\n", n, addr); + } +} + +erase(flash: string, seg: int) +{ + ctl := sys->open(flash+"ctl", Sys->OWRITE); + if(ctl == nil) + err(sys->sprint("can't open %sctl: %r\n", flash)); + if(sys->fprint(ctl, "erase %ud", seg*FLASHSEG) < 0) + err(sys->sprint("can't erase flash %s segment %d: %r\n", flash, seg)); +} + +saveflash(flash: string, base: int, limit: int): (int, array of byte) +{ + fd := sys->open(flash, Sys->OREAD); + if(fd == nil) + err(sys->sprint("can't open %s for reading: %r", flash)); + nb := limit - base; + if(nb <= 0) + return (base, nil); + if(sys->seek(fd, big base, 0) != big base) + err(sys->sprint("can't seek to #%6.6ux to save flash contents: %r", base)); + saved := array[nb] of byte; + if(sys->read(fd, saved, len saved) != len saved) + err(sys->sprint("can't read flash #%6.6ux to #%6.6ux: %r", base, limit)); + sys->print("saved %ud bytes at #%6.6ux\n", len saved, base); + return (base, saved); +} |
