1implement Writeflash; 2 3include "sys.m"; 4 sys: Sys; 5 6include "draw.m"; 7 8include "string.m"; 9 str: String; 10 11Writeflash: module 12{ 13 init: fn(nil: ref Draw->Context, args: list of string); 14}; 15 16Region: adt { 17 base: int; 18 limit: int; 19}; 20 21# could come from file or #F/flash/flashctl 22FLASHSEG: con 256*1024; 23kernelregion := Region(FLASHSEG, FLASHSEG+2*FLASHSEG); 24bootregion := Region(0, FLASHSEG); 25 26stderr: ref Sys->FD; 27prog := "qflash"; 28damaged := 0; 29 30usage() 31{ 32 sys->fprint(stderr, "Usage: %s [-b] [-o offset] [-f flashdev] file\n", prog); 33 exit; 34} 35 36err(s: string) 37{ 38 sys->fprint(stderr, "%s: %s", prog, s); 39 if(!damaged) 40 sys->fprint(stderr, "; flash not modified\n"); 41 else 42 sys->fprint(stderr, "; flash might now be invalid\n"); 43 exit; 44} 45 46init(nil: ref Draw->Context, args: list of string) 47{ 48 sys = load Sys Sys->PATH; 49 sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil); 50 stderr = sys->fildes(2); 51 if(args != nil){ 52 prog = hd args; 53 args = tl args; 54 } 55 str = load String String->PATH; 56 if(str == nil) 57 err(sys->sprint("can't load %s: %r", String->PATH)); 58 region := kernelregion; 59 flash := "#F/flash/flash"; 60 offset := 0; 61 save := 0; 62 63 for(; args != nil && (hd args)[0] == '-'; args = tl args) 64 case hd args { 65 "-b" => 66 region = bootregion; 67 offset = 16r100 - 8*4; # size of exec header 68 save = 1; 69 "-h" => 70 region.limit += FLASHSEG; 71 "-f" => 72 if(tl args == nil) 73 usage(); 74 flash = hd args; 75 args = tl args; 76 "-o" => 77 if(tl args == nil) 78 usage(); 79 args = tl args; 80 s := hd args; 81 v: int; 82 rs: string; 83 if(str->prefix("16r", s)) 84 (v, rs) = str->toint(s[3:], 16); 85 else if(str->prefix("0x", s)) 86 (v, rs) = str->toint(s[2:], 16); 87 else if(str->prefix("0", s)) 88 (v, rs) = str->toint(s[1:], 8); 89 else 90 (v, rs) = str->toint(s, 10); 91 if(v < 0 || len rs != 0) 92 err(sys->sprint("bad offset: %s", s)); 93 offset = v; 94 "-s" => 95 save = 1; 96 * => 97 usage(); 98 } 99 if(args == nil) 100 usage(); 101 fname := hd args; 102 fd := sys->open(fname, Sys->OREAD); 103 if(fd == nil) 104 err(sys->sprint("can't open %s: %r", fname)); 105 (r, dir) := sys->fstat(fd); 106 if(r < 0) 107 err(sys->sprint("can't stat %s: %r", fname)); 108 length := int dir.length; 109 avail := region.limit - (region.base+offset); 110 if(length > avail) 111 err(sys->sprint("%s contents %ud bytes, exceeds flash region %ud bytes", fname, length, avail)); 112 # check fname's contents... 113 where := region.base+offset; 114 saved: list of (int, array of byte); 115 if(save){ 116 saved = saveflash(flash, region.base, where) :: saved; 117 saved = saveflash(flash, where+length, region.limit) :: saved; 118 } 119 for(i := (region.base+offset)/FLASHSEG; i < region.limit/FLASHSEG; i++) 120 erase(flash, i); 121 out := sys->open(flash, Sys->OWRITE); 122 if(out == nil) 123 err(sys->sprint("can't open %s for writing: %r", flash)); 124 if(sys->seek(out, big where, 0) != big where) 125 err(sys->sprint("can't seek to #%6.6ux on flash: %r", where)); 126 if(length) 127 sys->print("writing %ud bytes to %s at #%6.6ux\n", length, flash, where); 128 buf := array[Sys->ATOMICIO] of byte; 129 total := 0; 130 while((n := sys->read(fd, buf, len buf)) > 0) { 131 if(total+n > avail) 132 err(sys->sprint("file %s too big for region of %ud bytes", fname, avail)); 133 r = sys->write(out, buf, n); 134 damaged = 1; 135 if(r != n){ 136 if(r < 0) 137 err(sys->sprint("error writing %s at byte %ud: %r", flash, total)); 138 else 139 err(sys->sprint("short write on %s at byte %ud", flash, total)); 140 } 141 total += n; 142 } 143 if(n < 0) 144 err(sys->sprint("error reading %s: %r", fname)); 145 sys->print("wrote %ud bytes from %s to flash %s (#%6.6ux-#%6.6ux)\n", total, fname, flash, region.base, region.base+total); 146 for(l := saved; l != nil; l = tl l){ 147 (addr, data) := hd l; 148 n = len data; 149 if(n == 0) 150 continue; 151 sys->print("restoring %ud bytes at #%6.6ux\n", n, addr); 152 if(sys->seek(out, big addr, 0) != big addr) 153 err(sys->sprint("can't seek to #%6.6ux on %s: %r", addr, flash)); 154 r = sys->write(out, data, n); 155 if(r < 0) 156 err(sys->sprint("error writing %s: %r", flash)); 157 else if(r != n) 158 err(sys->sprint("short write on %s at byte %ud/%ud", flash, r, n)); 159 else 160 sys->print("restored %ud bytes at #%6.6ux\n", n, addr); 161 } 162} 163 164erase(flash: string, seg: int) 165{ 166 ctl := sys->open(flash+"ctl", Sys->OWRITE); 167 if(ctl == nil) 168 err(sys->sprint("can't open %sctl: %r\n", flash)); 169 if(sys->fprint(ctl, "erase %ud", seg*FLASHSEG) < 0) 170 err(sys->sprint("can't erase flash %s segment %d: %r\n", flash, seg)); 171} 172 173saveflash(flash: string, base: int, limit: int): (int, array of byte) 174{ 175 fd := sys->open(flash, Sys->OREAD); 176 if(fd == nil) 177 err(sys->sprint("can't open %s for reading: %r", flash)); 178 nb := limit - base; 179 if(nb <= 0) 180 return (base, nil); 181 if(sys->seek(fd, big base, 0) != big base) 182 err(sys->sprint("can't seek to #%6.6ux to save flash contents: %r", base)); 183 saved := array[nb] of byte; 184 if(sys->read(fd, saved, len saved) != len saved) 185 err(sys->sprint("can't read flash #%6.6ux to #%6.6ux: %r", base, limit)); 186 sys->print("saved %ud bytes at #%6.6ux\n", len saved, base); 187 return (base, saved); 188} 189