xref: /inferno-os/utils/ms2/ms2.c (revision 5d0c4cf3fc288434c41cba52dd998ab1d7375a7b)
1 #include <lib9.h>
2 #include <bio.h>
3 #include <mach.h>
4 
5 void	record(uchar*, int);
6 void	usage(void);
7 void	dosegment(long, int);
8 void trailer(ulong);
9 void header(void);
10 
11 enum
12 {
13 	Recordsize = 32
14 };
15 
16 int	dsegonly;
17 int	supressend;
18 int	binary;
19 ulong	addr;
20 ulong 	psize = 4096;
21 ulong	startaddr = 0x030000;
22 Biobuf 	bout;
23 Biobuf	bio;
24 
25 void
26 main(int argc, char **argv)
27 {
28 	Dir *dir;
29 	Fhdr f;
30 	int fd;
31 
32 	ARGBEGIN{
33 	case 'd':
34 		dsegonly++;
35 		break;
36 	case 's':
37 		supressend++;
38 		break;
39 	case 'a':
40 	case 'T':
41 		addr = strtoul(ARGF(), 0, 0);
42 		break;
43 	case 'p':
44 	case 'R':
45 		psize = strtoul(ARGF(), 0, 0);
46 		break;
47 	case 'b':
48 		binary++;
49 		break;
50 	case 'S':
51 		startaddr = strtoul(ARGF(), 0, 0);
52 		break;
53 	default:
54 		usage();
55 	}ARGEND
56 
57 	if(argc != 1)
58 		usage();
59 
60 	Binit(&bout, 1, OWRITE);
61 
62 	fd = open(argv[0], OREAD);
63 	if(fd < 0) {
64 		fprint(2, "ms2: open %s: %r\n", argv[0]);
65 		exits("open");
66 	}
67 
68 	if(binary) {
69 		if((dir = dirfstat(fd)) == nil) {
70 			fprint(2, "ms2: stat failed %r");
71 			exits("dirfstat");
72 		}
73 		Binit(&bio, fd, OREAD);
74 		header();
75 		dosegment(0, dir->length);
76 		if(supressend == 0)
77 			trailer(startaddr);
78 		Bterm(&bout);
79 		Bterm(&bio);
80 		free(dir);
81 		exits(0);
82 	}
83 
84 	if(crackhdr(fd, &f) == 0){
85 		fprint(2, "ms2: bad magic: %r\n");
86 		exits("magic");
87 	}
88 	seek(fd, 0, 0);
89 
90 	Binit(&bio, fd, OREAD);
91 
92 	header();
93 	if(dsegonly)
94 		dosegment(f.datoff, f.datsz);
95 	else {
96 		dosegment(f.txtoff, f.txtsz);
97 		addr = (addr+(psize-1))&~(psize-1);
98 		dosegment(f.datoff, f.datsz);
99 	}
100 
101 	if(supressend == 0)
102 		trailer(startaddr);
103 
104 	Bterm(&bout);
105 	Bterm(&bio);
106 	exits(0);
107 }
108 
109 void
110 dosegment(long foff, int len)
111 {
112 	int l, n;
113 	uchar buf[2*Recordsize];
114 
115 	Bseek(&bio, foff, 0);
116 	for(;;) {
117 		l = len;
118 		if(l > Recordsize)
119 			l = Recordsize;
120 		n = Bread(&bio, buf, l);
121 		if(n == 0)
122 			break;
123 		if(n < 0) {
124 			fprint(2, "ms2: read error: %r\n");
125 			exits("read");
126 		}
127 		record(buf, l);
128 		len -= l;
129 	}
130 }
131 
132 void
133 record(uchar *s, int l)
134 {
135 	int i;
136 	ulong cksum;
137 
138 	if(addr & (0xFF<<24)){
139 		Bprint(&bout, "S3%.2X%.8lX", l+5, addr);
140 		cksum = l+5;
141 		cksum += (addr>>24)&0xff;
142 	}else{
143 		Bprint(&bout, "S2%.2X%.6lX", l+4, addr);
144 		cksum = l+4;
145 	}
146 	cksum += addr&0xff;
147 	cksum += (addr>>8)&0xff;
148 	cksum += (addr>>16)&0xff;
149 
150 	for(i = 0; i < l; i++) {
151 		cksum += *s;
152 		Bprint(&bout, "%.2X", *s++);
153 	}
154 	Bprint(&bout, "%.2lX\n", (~cksum)&0xff);
155 	addr += l;
156 }
157 
158 void
159 header(void)
160 {
161 	Bprint(&bout, "S0030000FC\n");
162 }
163 
164 void
165 trailer(ulong a)
166 {
167 	ulong cksum;
168 
169 	cksum = 0;
170 	if(a & (0xFF<<24)){
171 		Bprint(&bout, "S7%.8lX", a);
172 		cksum += (a>>24)&0xff;
173 	}else
174 		Bprint(&bout, "S9%.6lX", a);
175 	cksum += a&0xff;
176 	cksum += (a>>8)&0xff;
177 	cksum += (a>>16)&0xff;
178 	Bprint(&bout, "%.2lX\n", (~cksum)&0xff);
179 }
180 
181 void
182 usage(void)
183 {
184 	fprint(2, "usage: ms2 [-dsb] [-T address] [-R pagesize] [-S startaddress] ?.out\n");
185 	exits("usage");
186 }
187