diff options
Diffstat (limited to 'appl/cmd/mpc')
| -rw-r--r-- | appl/cmd/mpc/mkfile | 14 | ||||
| -rw-r--r-- | appl/cmd/mpc/qconfig.b | 193 | ||||
| -rw-r--r-- | appl/cmd/mpc/qflash.b | 188 |
3 files changed, 395 insertions, 0 deletions
diff --git a/appl/cmd/mpc/mkfile b/appl/cmd/mpc/mkfile new file mode 100644 index 00000000..17d7ab37 --- /dev/null +++ b/appl/cmd/mpc/mkfile @@ -0,0 +1,14 @@ +<../../../mkconfig + +TARG=\ + qconfig.dis\ + qflash.dis\ + +SYSMODULES=\ + sys.m\ + draw.m\ + string.m\ + +DISBIN=$ROOT/dis/mpc + +<$ROOT/mkfiles/mkdis diff --git a/appl/cmd/mpc/qconfig.b b/appl/cmd/mpc/qconfig.b new file mode 100644 index 00000000..dbff19b7 --- /dev/null +++ b/appl/cmd/mpc/qconfig.b @@ -0,0 +1,193 @@ +implement Configflash; + +# +# this isn't a proper config program: it's currently just +# enough to set important parameters such as ethernet address. +# an extension is in the works. +# --chf + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "string.m"; + str: String; + +Configflash: module +{ + init: fn(nil: ref Draw->Context, args: list of string); +}; + +Region: adt { + base: int; + limit: int; +}; + +# +# structure of allocation descriptor +# +Fcheck: con 0; +Fbase: con 4; +Flen: con 8; +Ftag: con 11; +Fsig: con 12; +Fasize: con 3*4+3+1; + +Tdead: con byte 0; +Tboot: con byte 16r01; +Tconf: con byte 16r02; +Tnone: con byte 16rFF; + +flashsig := array[] of {byte 16rF1, byte 16rA5, byte 16r5A, byte 16r1F}; +noval := array[] of {0 to 3 =>byte 16rFF}; # + +Ctag, Cscreen, Cconsole, Cbaud, Cether, Cea, Cend: con iota; +config := array[] of { + Ctag => "#plan9.ini\n", # current flag for qboot, don't change + Cscreen => "vgasize=640x480x8\n", + Cconsole => "console=0 lcd\n", + Cbaud => "baud=9600\n", + Cether => "ether0=type=SCC port=2 ", # note missing \n + Cea => "ea=08003e400080\n", + Cend => "\0" # qboot currently requires it but shouldn't +}; + +Param: adt { + name: string; + index: int; +}; + +params := array[] of { + Param("vgasize", Cscreen), + Param("console", Cconsole), + Param("ea", Cea), + Param("baud", Cbaud) +}; + +# could come from file or #F/flash/flashctl +FLASHSEG: con 256*1024; +bootregion := Region(0, FLASHSEG); + +stderr: ref Sys->FD; +prog := "qconfig"; +damaged := 0; +debug := 0; + +usage() +{ + sys->fprint(stderr, "Usage: %s [-D] [-f flash] [-param value ...]\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)); + flash := "#F/flash/flash"; + offset := 0; + region := bootregion; + + for(; args != nil && (hd args)[0] == '-'; args = tl args) + case a := hd args { + "-f" => + (flash, args) = argf(tl args); + "-D" => + debug = 1; + * => + p := lookparam(params, a[1:]); + if(p.index < 0) + err(sys->sprint("unknown config parameter: %s", a)); + v: string; + (v, args) = argf(tl args); + config[p.index] = a[1:]+"="+v+"\n"; # would be nice to check it + } + if(len args > 0) + usage(); + out := sys->open(flash, Sys->ORDWR); + if(out == nil) + err(sys->sprint("can't open %s for read/write: %r", flash)); + # TO DO: hunt for free space and add new entry + plonk(out, FLASHSEG-Fasize, mkdesc(0, 128*1024, Tboot)); + c := flatten(config); + if(debug) + sys->print("%s", c); + bconf := array of byte c; + plonk(out, FLASHSEG-Fasize*2, mkdesc(128*1024, len bconf, Tconf)); + plonk(out, 128*1024, bconf); +} + +argf(args: list of string): (string, list of string) +{ + if(args == nil) + usage(); + return (hd args, args); +} + +lookparam(options: array of Param, s: string): Param +{ + for(i := 0; i < len options; i++) + if(options[i].name == s) + return options[i]; + return Param(nil, -1); +} + +flatten(a: array of string): string +{ + s := ""; + for(i := 0; i < len a; i++) + s += a[i]; + return s; +} + +plonk(out: ref Sys->FD, where: int, val: array of byte) +{ + if(debug){ + sys->print("write #%ux [%d]:", where, len val); + for(i:=0; i<len val; i++) + sys->print(" %.2ux", int val[i]); + sys->print("\n"); + } + sys->seek(out, big where, 0); + if(sys->write(out, val, len val) != len val) + err(sys->sprint("bad flash write: %r")); +} + +cvt(v: int): array of byte +{ + a := array[4] of byte; + a[0] = byte (v>>24); + a[1] = byte (v>>16); + a[2] = byte (v>>8); + a[3] = byte (v & 16rff); + return a; +} + +mkdesc(base: int, length: int, tag: byte): array of byte +{ + a := array[Fasize] of byte; + a[Fcheck:] = noval; + a[Fbase:] = cvt(base); + a[Flen:] = cvt(length)[1:]; # it's three bytes + a[Ftag] = tag; + a[Fsig:] = flashsig; + return a; +} 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); +} |
