xref: /inferno-os/appl/cmd/mpc/qflash.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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