1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5
6 void record(uchar*, long);
7 void usage(void);
8 void segment(vlong, vlong);
9
10 enum
11 {
12 Recordsize = 32,
13 };
14
15 int dsegonly;
16 int supressend;
17 int binary;
18 int halfswap;
19 int srec = 2;
20 uvlong addr;
21 uvlong psize = 4096;
22 Biobuf stdout;
23 Fhdr exech;
24 Biobuf *bio;
25
26 void
main(int argc,char ** argv)27 main(int argc, char **argv)
28 {
29 Dir *dir;
30 uvlong totsz;
31
32 ARGBEGIN{
33 case 'd':
34 dsegonly++;
35 break;
36 case 's':
37 supressend++;
38 break;
39 case 'a':
40 addr = strtoull(ARGF(), 0, 0);
41 break;
42 case 'p':
43 psize = strtoul(ARGF(), 0, 0);
44 break;
45 case 'b':
46 binary++;
47 break;
48 case 'h':
49 halfswap++;
50 break;
51 case '1':
52 srec = 1;
53 break;
54 case '2':
55 srec = 2;
56 break;
57 case '3':
58 srec = 3;
59 break;
60 default:
61 usage();
62 }ARGEND
63
64 if(argc != 1)
65 usage();
66
67 Binit(&stdout, 1, OWRITE);
68
69 bio = Bopen(argv[0], OREAD);
70 if(bio == 0) {
71 fprint(2, "ms2: open %s: %r\n", argv[0]);
72 exits("open");
73 }
74
75 if(binary) {
76 if((dir = dirfstat(Bfildes(bio))) == nil) {
77 fprint(2, "ms2: stat failed %r");
78 exits("dirfstat");
79 }
80 segment(0, dir->length);
81 Bprint(&stdout, "S9030000FC\n");
82 Bterm(&stdout);
83 Bterm(bio);
84 free(dir);
85 exits(0);
86 }
87
88 if(!crackhdr(Bfildes(bio), &exech)) {
89 fprint(2, "ms2: can't decode file header\n");
90 return;
91 }
92
93 totsz = exech.txtsz + exech.datsz + exech.bsssz;
94 fprint(2, "%s: %lud+%lud+%lud=%llud\n",
95 exech.name, exech.txtsz, exech.datsz, exech.bsssz, totsz);
96
97 if(dsegonly)
98 segment(exech.datoff, exech.datsz);
99 else {
100 segment(exech.txtoff, exech.txtsz);
101 addr = (addr+(psize-1))&~(psize-1);
102 segment(exech.datoff, exech.datsz);
103 }
104
105 if(supressend == 0) {
106 switch(srec) {
107 case 1:
108 case 2:
109 Bprint(&stdout, "S9030000FC\n");
110 break;
111 case 3:
112 Bprint(&stdout, "S705000000FA\n");
113 break;
114 }
115 }
116
117 Bterm(&stdout);
118 Bterm(bio);
119 exits(0);
120 }
121
122 void
segment(vlong foff,vlong len)123 segment(vlong foff, vlong len)
124 {
125 int i;
126 long l, n;
127 uchar t, buf[2*Recordsize];
128
129 Bseek(bio, foff, 0);
130 for(;;) {
131 l = len;
132 if(l > Recordsize)
133 l = Recordsize;
134 n = Bread(bio, buf, l);
135 if(n == 0)
136 break;
137 if(n < 0) {
138 fprint(2, "ms2: read error: %r\n");
139 exits("read");
140 }
141 if(halfswap) {
142 if(n & 1) {
143 fprint(2, "ms2: data must be even length\n");
144 exits("even");
145 }
146 for(i = 0; i < n; i += 2) {
147 t = buf[i];
148 buf[i] = buf[i+1];
149 buf[i+1] = t;
150 }
151 }
152 record(buf, l);
153 len -= l;
154 }
155 }
156
157 void
record(uchar * s,long l)158 record(uchar *s, long l)
159 {
160 int i;
161 ulong cksum = 0;
162
163 switch(srec) {
164 case 1:
165 cksum = l+3;
166 Bprint(&stdout, "S1%.2lX%.4lluX", l+3, addr);
167 cksum += addr&0xff;
168 cksum += (addr>>8)&0xff;
169 break;
170 case 2:
171 cksum = l+4;
172 Bprint(&stdout, "S2%.2lX%.6lluX", l+4, addr);
173 cksum += addr&0xff;
174 cksum += (addr>>8)&0xff;
175 cksum += (addr>>16)&0xff;
176 break;
177 case 3:
178 cksum = l+5;
179 Bprint(&stdout, "S3%.2lX%.8lluX", l+5, addr);
180 cksum += addr&0xff;
181 cksum += (addr>>8)&0xff;
182 cksum += (addr>>16)&0xff;
183 cksum += (addr>>24)&0xff;
184 break;
185 }
186
187 for(i = 0; i < l; i++) {
188 cksum += *s;
189 Bprint(&stdout, "%.2X", *s++);
190 }
191 Bprint(&stdout, "%.2luX\n", (~cksum)&0xff);
192 addr += l;
193 }
194
195 void
usage(void)196 usage(void)
197 {
198 fprint(2, "usage: ms2 [-dsbh] [-a address] [-p pagesize] ?.out\n");
199 exits("usage");
200 }
201