ndiscvt.c revision 132973
181084Sjake/*
281084Sjake * Copyright (c) 2003
381084Sjake *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
481084Sjake *
581084Sjake * Redistribution and use in source and binary forms, with or without
681084Sjake * modification, are permitted provided that the following conditions
781084Sjake * are met:
881084Sjake * 1. Redistributions of source code must retain the above copyright
981084Sjake *    notice, this list of conditions and the following disclaimer.
10147272Smarius * 2. Redistributions in binary form must reproduce the above copyright
11147272Smarius *    notice, this list of conditions and the following disclaimer in the
12147272Smarius *    documentation and/or other materials provided with the distribution.
13147272Smarius * 3. All advertising materials mentioning features or use of this software
14147272Smarius *    must display the following acknowledgement:
15163890Smarius *	This product includes software developed by Bill Paul.
16163890Smarius * 4. Neither the name of the author nor the names of any co-contributors
17163890Smarius *    may be used to endorse or promote products derived from this software
18163890Smarius *    without specific prior written permission.
19163890Smarius *
20146419Smarius * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21146419Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22146419Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23146419Smarius * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24146419Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25171167Sgnn * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26171167Sgnn * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27147272Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28147272Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29147272Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30147272Smarius * THE POSSIBILITY OF SUCH DAMAGE.
31147272Smarius */
32147272Smarius
33147272Smarius#include <sys/cdefs.h>
34152862Sru__FBSDID("$FreeBSD: head/usr.sbin/ndiscvt/ndiscvt.c 132973 2004-08-01 20:04:31Z wpaul $");
35130294Sscottl
36119382Sjake#include <sys/types.h>
37119382Sjake#include <sys/queue.h>
38170840Smarius#include <sys/socket.h>
39146483Smarius#include <net/if.h>
40147191Sjkoshy#include <stdlib.h>
41188654Sthompsa#include <unistd.h>
42166144Smarius#include <stdio.h>
43155151Smarius#include <errno.h>
44166144Smarius#include <string.h>
45186347Snwhitehorn#include <libgen.h>
46133589Smarius#include <err.h>
47152683Smarius#include <ctype.h>
48186347Snwhitehorn
4990623Stmm#include <compat/ndis/pe_var.h>
5086148Stmm
51105399Stmm#include "inf.h"
52116584Sjake
53152686Smariusstatic int insert_padding(void **, int *);
54151805Sjoergextern const char *__progname;
55152862Sru
56152862Sru/*
57119382Sjake * Sections in object code files can be sparse. That is, the
58186681Sed * section may occupy more space in memory that it does when
59119382Sjake * stored in a disk file. In Windows PE files, each section header
60119816Smarcel * has a 'virtual size' and 'raw data size' field. The latter
61122470Sjake * specifies the amount of section data actually stored in the
6293122Stmm * disk file, and the former describes how much space the section
63124516Sdes * should actually occupy in memory. If the vsize is larger than
64124481Sdes * the rsize, we need to allocate some extra storage and fill
65124481Sdes * it with zeros. (Think BSS.)
66124481Sdes *
67189170Sed * The typical method of loading an executable file involves
68111072Sjake * reading each segment into memory using the vaddr/vsize from
69100399Speter * each section header. We try to make a small optimization however
70202006Smarius * and only pad/move segments when it's absolutely necessary, i.e.
71182057Smarius * if the vsize is larger than the rsize. This conserves a little
72111072Sjake * bit of memory, at the cost of having to fixup some of the values
7386235Stmm * in the section headers.
74136944Syongari */
75152862Sru
76128758Smarius#define ROUND_UP(x, y)	\
77129051Smarius	(((x) + (y)) - ((x) % (y)))
78129051Smarius
79129051Smarius#define SET_HDRS(x)	\
8086235Stmm	dos_hdr = (image_dos_header *)x;				\
81183423Smarius	nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew);		\
82146392Smarius	sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +	\
8390623Stmm	    sizeof(image_nt_header));
84146392Smarius
85176197Smariusstatic
8681084Sjakeint insert_padding(imgbase, imglen)
8786235Stmm	void			**imgbase;
8886235Stmm	int			*imglen;
89112399Sjake{
9081084Sjake        image_section_header	*sect_hdr;
9190623Stmm        image_dos_header	*dos_hdr;
9290623Stmm        image_nt_header		*nt_hdr;
9390623Stmm	image_optional_header	opt_hdr;
9490623Stmm        int			i = 0, sections, curlen = 0;
9590623Stmm	int			offaccum = 0, diff, oldraddr, oldrlen;
96105531Stmm	uint8_t			*newimg, *tmp;
9781084Sjake
98183202Smarius	newimg = malloc(*imglen);
99183202Smarius
100152862Sru	if (newimg == NULL)
101152862Sru		return(ENOMEM);
102131951Smarcel
10384202Sjake	bcopy(*imgbase, newimg, *imglen);
10490623Stmm	curlen = *imglen;
105183202Smarius
106183202Smarius	if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
10781390Sjake		return(0);
10886235Stmm
109182918Smarius        sections = pe_numsections((vm_offset_t)newimg);
110111684Sru
11181084Sjake	SET_HDRS(newimg);
112132956Smarkm
113183202Smarius	for (i = 0; i < sections; i++) {
114183202Smarius		/*
115101070Sjake		 * If we have accumulated any padding offset,
11689053Sjake		 * add it to the raw data address of this segment.
11786235Stmm		 */
11886235Stmm		oldraddr = sect_hdr->ish_rawdataaddr;
11981084Sjake		oldrlen = sect_hdr->ish_rawdatasize;
120100844Sjake		if (offaccum)
121152862Sru			sect_hdr->ish_rawdataaddr += offaccum;
12282914Sjake		if (sect_hdr->ish_misc.ish_vsize >
123119382Sjake		    sect_hdr->ish_rawdatasize) {
124182918Smarius			diff = ROUND_UP(sect_hdr->ish_misc.ish_vsize -
125112399Sjake			    sect_hdr->ish_rawdatasize,
126174195Srwatson			    opt_hdr.ioh_filealign);
127183202Smarius			offaccum += ROUND_UP(diff -
128183202Smarius			    (sect_hdr->ish_misc.ish_vsize -
12981084Sjake			    sect_hdr->ish_rawdatasize),
130101070Sjake			    opt_hdr.ioh_filealign);
13181390Sjake			sect_hdr->ish_rawdatasize =
13296998Sjake			    ROUND_UP(sect_hdr->ish_rawdatasize,
13381084Sjake			    opt_hdr.ioh_filealign);
13481084Sjake			tmp = realloc(newimg, *imglen + offaccum);
135127297Salc			if (tmp == NULL) {
136166060Smarius				free(newimg);
13781084Sjake				return(ENOMEM);
138			}
139			newimg = tmp;
140			SET_HDRS(newimg);
141			sect_hdr += i;
142		}
143		bzero(newimg + sect_hdr->ish_rawdataaddr,
144		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
145		    opt_hdr.ioh_filealign));
146		bcopy((uint8_t *)(*imgbase) + oldraddr,
147		    newimg + sect_hdr->ish_rawdataaddr, oldrlen);
148		sect_hdr++;
149	}
150
151	free(*imgbase);
152
153	*imgbase = newimg;
154	*imglen += offaccum;
155
156	return(0);
157}
158
159static void
160usage(void)
161{
162	fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> "
163	    "[-n devname] [-o outfile]\n", __progname);
164	fprintf(stderr, "       %s -f <firmfile>\n", __progname);
165
166	exit(1);
167}
168
169static void
170bincvt(char *sysfile, char *outfile, void *img, int fsize)
171{
172	char			*ptr;
173	char			tname[] = "/tmp/ndiscvt.XXXXXX";
174	char			sysbuf[1024];
175	FILE			*binfp;
176
177	mkstemp(tname);
178
179	binfp = fopen(tname, "a+");
180	if (binfp == NULL)
181		err(1, "opening %s failed", tname);
182
183	if (fwrite(img, fsize, 1, binfp) != 1)
184		err(1, "failed to output binary image");
185
186	fclose(binfp);
187
188	outfile = strdup(basename(outfile));
189	if (strchr(outfile, '.'))
190		*strchr(outfile, '.') = '\0';
191
192	snprintf(sysbuf, sizeof(sysbuf),
193	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
194	    tname, outfile);
195	printf("%s", sysbuf);
196	system(sysbuf);
197	unlink(tname);
198
199	ptr = tname;
200	while (*ptr) {
201		if (*ptr == '/' || *ptr == '.')
202			*ptr = '_';
203		ptr++;
204	}
205
206	snprintf(sysbuf, sizeof(sysbuf),
207	    "objcopy --redefine-sym _binary_%s_start=%s_drv_data_start "
208	    "--strip-symbol _binary_%s_size "
209	    "--redefine-sym _binary_%s_end=%s_drv_data_end %s.o %s.o\n",
210	    tname, sysfile, tname, tname, sysfile, outfile, outfile);
211	printf("%s", sysbuf);
212	system(sysbuf);
213
214	return;
215}
216
217static void
218firmcvt(char *firmfile)
219{
220	char			*basefile, *outfile, *ptr;
221	char			sysbuf[1024];
222
223	outfile = basename(firmfile);
224	basefile = strdup(outfile);
225
226	snprintf(sysbuf, sizeof(sysbuf),
227	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
228	    firmfile, outfile);
229	printf("%s", sysbuf);
230	system(sysbuf);
231
232	ptr = firmfile;
233	while (*ptr) {
234		if (*ptr == '/' || *ptr == '.')
235			*ptr = '_';
236		ptr++;
237	}
238	ptr = basefile;
239	while (*ptr) {
240		if (*ptr == '/' || *ptr == '.')
241			*ptr = '_';
242		else
243			*ptr = tolower(*ptr);
244		ptr++;
245	}
246
247	snprintf(sysbuf, sizeof(sysbuf),
248	    "objcopy --redefine-sym _binary_%s_start=%s_start "
249	    "--strip-symbol _binary_%s_size "
250	    "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n",
251	    firmfile, basefile, firmfile, firmfile,
252	    basefile, outfile, outfile);
253	ptr = sysbuf;
254	printf("%s", sysbuf);
255	system(sysbuf);
256
257	snprintf(sysbuf, sizeof(sysbuf),
258	    "ld -Bshareable -d -warn-common -o %s.ko %s.o\n",
259	    outfile, outfile);
260	printf("%s", sysbuf);
261	system(sysbuf);
262
263	free(basefile);
264
265	exit(0);
266}
267
268int
269main(int argc, char *argv[])
270{
271	FILE			*fp, *outfp;
272	int			i, bin = 0;
273	void			*img;
274	int			n, fsize, cnt;
275	unsigned char		*ptr;
276	char			*inffile = NULL, *sysfile = NULL;
277	char			*outfile = NULL, *firmfile = NULL;
278	char			*dname = NULL;
279	int			ch;
280
281	while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) {
282		switch(ch) {
283		case 'f':
284			firmfile = optarg;
285			break;
286		case 'i':
287			inffile = optarg;
288			break;
289		case 's':
290			sysfile = optarg;
291			break;
292		case 'o':
293			outfile = optarg;
294			break;
295		case 'n':
296			dname = optarg;
297			break;
298		case 'O':
299			bin = 1;
300			break;
301		default:
302			usage();
303			break;
304		}
305	}
306
307	if (firmfile != NULL)
308		firmcvt(firmfile);
309
310	if (sysfile == NULL)
311		usage();
312
313	/* Open the .SYS file and load it into memory */
314	fp = fopen(sysfile, "r");
315	if (fp == NULL)
316		err(1, "opening .SYS file '%s' failed", sysfile);
317	fseek (fp, 0L, SEEK_END);
318	fsize = ftell (fp);
319	rewind (fp);
320	img = calloc(fsize, 1);
321	n = fread (img, fsize, 1, fp);
322
323	fclose(fp);
324
325	if (insert_padding(&img, &fsize)) {
326		fprintf(stderr, "section relocation failed\n");
327		exit(1);
328	}
329
330	if (outfile == NULL || strcmp(outfile, "-") == 0)
331		outfp = stdout;
332	else {
333		outfp = fopen(outfile, "w");
334		if (outfp == NULL)
335			err(1, "opening output file '%s' failed", outfile);
336	}
337
338	fprintf(outfp, "\n/*\n");
339	fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
340	    inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
341	fprintf(outfp, " */\n\n");
342
343	if (dname != NULL) {
344		if (strlen(dname) > IFNAMSIZ)
345			err(1, "selected device name '%s' is "
346			    "too long (max chars: %d)", dname, IFNAMSIZ);
347		fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
348		fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
349	}
350
351	if (inffile == NULL) {
352		fprintf (outfp, "#ifdef NDIS_REGVALS\n");
353		fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
354        	fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
355		fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
356
357		fprintf (outfp, "};\n\n");
358	} else {
359		fp = fopen(inffile, "r");
360		if (fp == NULL)
361			err(1, "opening .INF file '%s' failed", inffile);
362
363
364		inf_parse(fp, outfp);
365		fclose(fp);
366	}
367
368	fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
369
370	if (bin) {
371		sysfile = strdup(basename(sysfile));
372		ptr = sysfile;
373		while (*ptr) {
374			if (*ptr == '.')
375				*ptr = '_';
376			ptr++;
377		}
378		fprintf(outfp,
379		    "\nextern unsigned char %s_drv_data_start[];\n",
380		    sysfile);
381		fprintf(outfp, "static unsigned char *drv_data = "
382		    "%s_drv_data_start;\n\n", sysfile);
383		bincvt(sysfile, outfile, img, fsize);
384		goto done;
385	}
386
387
388	fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
389
390	fprintf(outfp, "__asm__(\".data\");\n");
391	fprintf(outfp, "__asm__(\".type   drv_data, @object\");\n");
392	fprintf(outfp, "__asm__(\".size   drv_data, %d\");\n", fsize);
393	fprintf(outfp, "__asm__(\"drv_data:\");\n");
394
395	ptr = img;
396	cnt = 0;
397	while(cnt < fsize) {
398		fprintf (outfp, "__asm__(\".byte ");
399		for (i = 0; i < 10; i++) {
400			cnt++;
401			if (cnt == fsize) {
402				fprintf(outfp, "0x%.2X\");\n", ptr[i]);
403				goto done;
404			} else {
405				if (i == 9)
406					fprintf(outfp, "0x%.2X\");\n", ptr[i]);
407				else
408					fprintf(outfp, "0x%.2X, ", ptr[i]);
409			}
410		}
411		ptr += 10;
412	}
413
414done:
415
416	fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
417
418	if (fp != NULL)
419		fclose(fp);
420	fclose(outfp);
421	free(img);
422	exit(0);
423}
424