ndiscvt.c revision 178213
1123475Swpaul/*
2123475Swpaul * Copyright (c) 2003
3123475Swpaul *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4123475Swpaul *
5123475Swpaul * Redistribution and use in source and binary forms, with or without
6123475Swpaul * modification, are permitted provided that the following conditions
7123475Swpaul * are met:
8123475Swpaul * 1. Redistributions of source code must retain the above copyright
9123475Swpaul *    notice, this list of conditions and the following disclaimer.
10123475Swpaul * 2. Redistributions in binary form must reproduce the above copyright
11123475Swpaul *    notice, this list of conditions and the following disclaimer in the
12123475Swpaul *    documentation and/or other materials provided with the distribution.
13123475Swpaul * 3. All advertising materials mentioning features or use of this software
14123475Swpaul *    must display the following acknowledgement:
15123475Swpaul *	This product includes software developed by Bill Paul.
16123475Swpaul * 4. Neither the name of the author nor the names of any co-contributors
17123475Swpaul *    may be used to endorse or promote products derived from this software
18123475Swpaul *    without specific prior written permission.
19123475Swpaul *
20123475Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21123475Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22123475Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23123475Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24123475Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25123475Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26123475Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27123475Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28123475Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29123475Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30123475Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
31123475Swpaul */
32123475Swpaul
33123475Swpaul#include <sys/cdefs.h>
34123475Swpaul__FBSDID("$FreeBSD: head/usr.sbin/ndiscvt/ndiscvt.c 178213 2008-04-15 04:17:13Z thompsa $");
35123475Swpaul
36123475Swpaul#include <sys/types.h>
37123475Swpaul#include <sys/queue.h>
38124060Swpaul#include <sys/socket.h>
39124060Swpaul#include <net/if.h>
40123475Swpaul#include <stdlib.h>
41151703Swpaul#include <stddef.h>
42123475Swpaul#include <unistd.h>
43123475Swpaul#include <stdio.h>
44123475Swpaul#include <errno.h>
45123475Swpaul#include <string.h>
46132973Swpaul#include <libgen.h>
47123475Swpaul#include <err.h>
48132973Swpaul#include <ctype.h>
49123475Swpaul
50123475Swpaul#include <compat/ndis/pe_var.h>
51123475Swpaul
52123475Swpaul#include "inf.h"
53123475Swpaul
54123475Swpaulstatic int insert_padding(void **, int *);
55123475Swpaulextern const char *__progname;
56123475Swpaul
57123475Swpaul/*
58133026Swpaul * Sections within Windows PE files are defined using virtual
59133026Swpaul * and physical address offsets and virtual and physical sizes.
60133026Swpaul * The physical values define how the section data is stored in
61133026Swpaul * the executable file while the virtual values describe how the
62133026Swpaul * sections will look once loaded into memory. It happens that
63133026Swpaul * the linker in the Microsoft(r) DDK will tend to generate
64133026Swpaul * binaries where the virtual and physical values are identical,
65133026Swpaul * which means in most cases we can just transfer the file
66133026Swpaul * directly to memory without any fixups. This is not always
67133026Swpaul * the case though, so we have to be prepared to handle files
68133026Swpaul * where the in-memory section layout differs from the disk file
69133026Swpaul * section layout.
70123475Swpaul *
71133026Swpaul * There are two kinds of variations that can occur: the relative
72133026Swpaul * virtual address of the section might be different from the
73133026Swpaul * physical file offset, and the virtual section size might be
74133026Swpaul * different from the physical size (for example, the physical
75133026Swpaul * size of the .data section might be 1024 bytes, but the virtual
76133026Swpaul * size might be 1384 bytes, indicating that the data section should
77133026Swpaul * actually use up 1384 bytes in RAM and be padded with zeros). What we
78133026Swpaul * do is read the original file into memory and then make an in-memory
79133026Swpaul * copy with all of the sections relocated, re-sized and zero padded
80133026Swpaul * according to the virtual values specified in the section headers.
81133026Swpaul * We then emit the fixed up image file for use by the if_ndis driver.
82133026Swpaul * This way, we don't have to do the fixups inside the kernel.
83123475Swpaul */
84123475Swpaul
85133026Swpaul#define ROUND_DOWN(n, align)    (((uintptr_t)n) & ~((align) - 1l))
86133026Swpaul#define ROUND_UP(n, align)      ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \
87133026Swpaul                                (align))
88123475Swpaul
89123475Swpaul#define SET_HDRS(x)	\
90123475Swpaul	dos_hdr = (image_dos_header *)x;				\
91123475Swpaul	nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew);		\
92151703Swpaul	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
93123475Swpaul
94123475Swpaulstatic
95123475Swpaulint insert_padding(imgbase, imglen)
96123475Swpaul	void			**imgbase;
97123475Swpaul	int			*imglen;
98123475Swpaul{
99123475Swpaul        image_section_header	*sect_hdr;
100123475Swpaul        image_dos_header	*dos_hdr;
101123475Swpaul        image_nt_header		*nt_hdr;
102123475Swpaul	image_optional_header	opt_hdr;
103123475Swpaul        int			i = 0, sections, curlen = 0;
104133026Swpaul	int			offaccum = 0, oldraddr, oldrlen;
105123475Swpaul	uint8_t			*newimg, *tmp;
106123475Swpaul
107123475Swpaul	newimg = malloc(*imglen);
108123475Swpaul
109123475Swpaul	if (newimg == NULL)
110123475Swpaul		return(ENOMEM);
111123475Swpaul
112123475Swpaul	bcopy(*imgbase, newimg, *imglen);
113123475Swpaul	curlen = *imglen;
114123475Swpaul
115123475Swpaul	if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
116123475Swpaul		return(0);
117123475Swpaul
118123475Swpaul        sections = pe_numsections((vm_offset_t)newimg);
119123475Swpaul
120123475Swpaul	SET_HDRS(newimg);
121123475Swpaul
122123475Swpaul	for (i = 0; i < sections; i++) {
123123475Swpaul		oldraddr = sect_hdr->ish_rawdataaddr;
124123475Swpaul		oldrlen = sect_hdr->ish_rawdatasize;
125133026Swpaul		sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr;
126133026Swpaul		offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr,
127133026Swpaul		    opt_hdr.ioh_filealign);
128133026Swpaul		offaccum +=
129133026Swpaul		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
130133026Swpaul			     opt_hdr.ioh_filealign) -
131133026Swpaul		    ROUND_UP(sect_hdr->ish_rawdatasize,
132133026Swpaul			     opt_hdr.ioh_filealign);
133133026Swpaul		tmp = realloc(newimg, *imglen + offaccum);
134133026Swpaul		if (tmp == NULL) {
135133026Swpaul			free(newimg);
136133026Swpaul			return(ENOMEM);
137123475Swpaul		}
138133026Swpaul		newimg = tmp;
139133026Swpaul		SET_HDRS(newimg);
140133026Swpaul		sect_hdr += i;
141123475Swpaul		bzero(newimg + sect_hdr->ish_rawdataaddr,
142123475Swpaul		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
143123475Swpaul		    opt_hdr.ioh_filealign));
144123475Swpaul		bcopy((uint8_t *)(*imgbase) + oldraddr,
145123475Swpaul		    newimg + sect_hdr->ish_rawdataaddr, oldrlen);
146123475Swpaul		sect_hdr++;
147123475Swpaul	}
148123475Swpaul
149123475Swpaul	free(*imgbase);
150123475Swpaul
151123475Swpaul	*imgbase = newimg;
152123475Swpaul	*imglen += offaccum;
153123475Swpaul
154123475Swpaul	return(0);
155123475Swpaul}
156123475Swpaul
157123475Swpaulstatic void
158123475Swpaulusage(void)
159123475Swpaul{
160132973Swpaul	fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> "
161124089Sgreen	    "[-n devname] [-o outfile]\n", __progname);
162132973Swpaul	fprintf(stderr, "       %s -f <firmfile>\n", __progname);
163132973Swpaul
164123475Swpaul	exit(1);
165123475Swpaul}
166123475Swpaul
167132973Swpaulstatic void
168132973Swpaulbincvt(char *sysfile, char *outfile, void *img, int fsize)
169132973Swpaul{
170132973Swpaul	char			*ptr;
171132973Swpaul	char			tname[] = "/tmp/ndiscvt.XXXXXX";
172132973Swpaul	char			sysbuf[1024];
173132973Swpaul	FILE			*binfp;
174132973Swpaul
175132973Swpaul	mkstemp(tname);
176132973Swpaul
177132973Swpaul	binfp = fopen(tname, "a+");
178132973Swpaul	if (binfp == NULL)
179132973Swpaul		err(1, "opening %s failed", tname);
180132973Swpaul
181132973Swpaul	if (fwrite(img, fsize, 1, binfp) != 1)
182132973Swpaul		err(1, "failed to output binary image");
183132973Swpaul
184132973Swpaul	fclose(binfp);
185132973Swpaul
186132973Swpaul	outfile = strdup(basename(outfile));
187132973Swpaul	if (strchr(outfile, '.'))
188132973Swpaul		*strchr(outfile, '.') = '\0';
189132973Swpaul
190132973Swpaul	snprintf(sysbuf, sizeof(sysbuf),
191142075Swpaul#ifdef __i386__
192132973Swpaul	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
193142075Swpaul#endif
194142075Swpaul#ifdef __amd64__
195142075Swpaul	    "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n",
196142075Swpaul#endif
197132973Swpaul	    tname, outfile);
198132973Swpaul	printf("%s", sysbuf);
199132973Swpaul	system(sysbuf);
200132973Swpaul	unlink(tname);
201132973Swpaul
202132973Swpaul	ptr = tname;
203132973Swpaul	while (*ptr) {
204132973Swpaul		if (*ptr == '/' || *ptr == '.')
205132973Swpaul			*ptr = '_';
206132973Swpaul		ptr++;
207132973Swpaul	}
208132973Swpaul
209132973Swpaul	snprintf(sysbuf, sizeof(sysbuf),
210178213Sthompsa	    "objcopy --redefine-sym _binary_%s_start=ndis_%s_drv_data_start "
211132973Swpaul	    "--strip-symbol _binary_%s_size "
212178213Sthompsa	    "--redefine-sym _binary_%s_end=ndis_%s_drv_data_end %s.o %s.o\n",
213132973Swpaul	    tname, sysfile, tname, tname, sysfile, outfile, outfile);
214132973Swpaul	printf("%s", sysbuf);
215132973Swpaul	system(sysbuf);
216132973Swpaul
217132973Swpaul	return;
218132973Swpaul}
219132973Swpaul
220132973Swpaulstatic void
221132973Swpaulfirmcvt(char *firmfile)
222132973Swpaul{
223132973Swpaul	char			*basefile, *outfile, *ptr;
224132973Swpaul	char			sysbuf[1024];
225132973Swpaul
226142075Swpaul	outfile = strdup(basename(firmfile));
227132973Swpaul	basefile = strdup(outfile);
228132973Swpaul
229132973Swpaul	snprintf(sysbuf, sizeof(sysbuf),
230142075Swpaul#ifdef __i386__
231132973Swpaul	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
232142075Swpaul#endif
233142075Swpaul#ifdef __amd64__
234142075Swpaul	    "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n",
235142075Swpaul#endif
236132973Swpaul	    firmfile, outfile);
237132973Swpaul	printf("%s", sysbuf);
238132973Swpaul	system(sysbuf);
239132973Swpaul
240132973Swpaul	ptr = firmfile;
241132973Swpaul	while (*ptr) {
242132973Swpaul		if (*ptr == '/' || *ptr == '.')
243132973Swpaul			*ptr = '_';
244132973Swpaul		ptr++;
245132973Swpaul	}
246132973Swpaul	ptr = basefile;
247132973Swpaul	while (*ptr) {
248132973Swpaul		if (*ptr == '/' || *ptr == '.')
249132973Swpaul			*ptr = '_';
250132973Swpaul		else
251132973Swpaul			*ptr = tolower(*ptr);
252132973Swpaul		ptr++;
253132973Swpaul	}
254132973Swpaul
255132973Swpaul	snprintf(sysbuf, sizeof(sysbuf),
256132973Swpaul	    "objcopy --redefine-sym _binary_%s_start=%s_start "
257132973Swpaul	    "--strip-symbol _binary_%s_size "
258132973Swpaul	    "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n",
259132973Swpaul	    firmfile, basefile, firmfile, firmfile,
260132973Swpaul	    basefile, outfile, outfile);
261132973Swpaul	ptr = sysbuf;
262132973Swpaul	printf("%s", sysbuf);
263132973Swpaul	system(sysbuf);
264132973Swpaul
265132973Swpaul	snprintf(sysbuf, sizeof(sysbuf),
266132973Swpaul	    "ld -Bshareable -d -warn-common -o %s.ko %s.o\n",
267132973Swpaul	    outfile, outfile);
268132973Swpaul	printf("%s", sysbuf);
269132973Swpaul	system(sysbuf);
270132973Swpaul
271132973Swpaul	free(basefile);
272132973Swpaul
273132973Swpaul	exit(0);
274132973Swpaul}
275132973Swpaul
276123475Swpaulint
277123475Swpaulmain(int argc, char *argv[])
278123475Swpaul{
279132973Swpaul	FILE			*fp, *outfp;
280132973Swpaul	int			i, bin = 0;
281132973Swpaul	void			*img;
282132973Swpaul	int			n, fsize, cnt;
283132973Swpaul	unsigned char		*ptr;
284132973Swpaul	char			*inffile = NULL, *sysfile = NULL;
285132973Swpaul	char			*outfile = NULL, *firmfile = NULL;
286132973Swpaul	char			*dname = NULL;
287132973Swpaul	int			ch;
288123475Swpaul
289132973Swpaul	while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) {
290123475Swpaul		switch(ch) {
291132973Swpaul		case 'f':
292132973Swpaul			firmfile = optarg;
293132973Swpaul			break;
294123475Swpaul		case 'i':
295123475Swpaul			inffile = optarg;
296123475Swpaul			break;
297123475Swpaul		case 's':
298123475Swpaul			sysfile = optarg;
299123475Swpaul			break;
300123475Swpaul		case 'o':
301123475Swpaul			outfile = optarg;
302123475Swpaul			break;
303124060Swpaul		case 'n':
304124060Swpaul			dname = optarg;
305124060Swpaul			break;
306132973Swpaul		case 'O':
307132973Swpaul			bin = 1;
308132973Swpaul			break;
309123475Swpaul		default:
310123475Swpaul			usage();
311123475Swpaul			break;
312123475Swpaul		}
313123475Swpaul	}
314123475Swpaul
315132973Swpaul	if (firmfile != NULL)
316132973Swpaul		firmcvt(firmfile);
317132973Swpaul
318123475Swpaul	if (sysfile == NULL)
319123475Swpaul		usage();
320123475Swpaul
321123475Swpaul	/* Open the .SYS file and load it into memory */
322123475Swpaul	fp = fopen(sysfile, "r");
323123475Swpaul	if (fp == NULL)
324123475Swpaul		err(1, "opening .SYS file '%s' failed", sysfile);
325123475Swpaul	fseek (fp, 0L, SEEK_END);
326123475Swpaul	fsize = ftell (fp);
327123475Swpaul	rewind (fp);
328123475Swpaul	img = calloc(fsize, 1);
329123475Swpaul	n = fread (img, fsize, 1, fp);
330123475Swpaul
331123475Swpaul	fclose(fp);
332123475Swpaul
333123475Swpaul	if (insert_padding(&img, &fsize)) {
334123475Swpaul		fprintf(stderr, "section relocation failed\n");
335123475Swpaul		exit(1);
336123475Swpaul	}
337123475Swpaul
338123475Swpaul	if (outfile == NULL || strcmp(outfile, "-") == 0)
339123475Swpaul		outfp = stdout;
340123475Swpaul	else {
341123475Swpaul		outfp = fopen(outfile, "w");
342123475Swpaul		if (outfp == NULL)
343123475Swpaul			err(1, "opening output file '%s' failed", outfile);
344123475Swpaul	}
345123475Swpaul
346123475Swpaul	fprintf(outfp, "\n/*\n");
347123475Swpaul	fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
348124060Swpaul	    inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
349123475Swpaul	fprintf(outfp, " */\n\n");
350123475Swpaul
351124060Swpaul	if (dname != NULL) {
352124060Swpaul		if (strlen(dname) > IFNAMSIZ)
353124060Swpaul			err(1, "selected device name '%s' is "
354124060Swpaul			    "too long (max chars: %d)", dname, IFNAMSIZ);
355124060Swpaul		fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
356124085Swpaul		fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
357124060Swpaul	}
358124060Swpaul
359124060Swpaul	if (inffile == NULL) {
360126706Swpaul		fprintf (outfp, "#ifdef NDIS_REGVALS\n");
361123475Swpaul		fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
362124060Swpaul        	fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
363126706Swpaul		fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
364123475Swpaul
365123475Swpaul		fprintf (outfp, "};\n\n");
366123475Swpaul	} else {
367123475Swpaul		fp = fopen(inffile, "r");
368123475Swpaul		if (fp == NULL)
369123475Swpaul			err(1, "opening .INF file '%s' failed", inffile);
370123475Swpaul
371123475Swpaul
372123475Swpaul		inf_parse(fp, outfp);
373123475Swpaul		fclose(fp);
374123475Swpaul	}
375123475Swpaul
376126706Swpaul	fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
377132973Swpaul
378132973Swpaul	if (bin) {
379132973Swpaul		sysfile = strdup(basename(sysfile));
380162491Skan		ptr = (unsigned char *)sysfile;
381132973Swpaul		while (*ptr) {
382132973Swpaul			if (*ptr == '.')
383132973Swpaul				*ptr = '_';
384132973Swpaul			ptr++;
385132973Swpaul		}
386132973Swpaul		fprintf(outfp,
387178213Sthompsa		    "\nextern unsigned char ndis_%s_drv_data_start[];\n",
388132973Swpaul		    sysfile);
389132973Swpaul		fprintf(outfp, "static unsigned char *drv_data = "
390178213Sthompsa		    "ndis_%s_drv_data_start;\n\n", sysfile);
391132973Swpaul		bincvt(sysfile, outfile, img, fsize);
392132973Swpaul		goto done;
393132973Swpaul	}
394132973Swpaul
395132973Swpaul
396126706Swpaul	fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
397123475Swpaul
398123653Swpaul	fprintf(outfp, "__asm__(\".data\");\n");
399141524Swpaul	fprintf(outfp, "__asm__(\".globl  drv_data\");\n");
400123653Swpaul	fprintf(outfp, "__asm__(\".type   drv_data, @object\");\n");
401123653Swpaul	fprintf(outfp, "__asm__(\".size   drv_data, %d\");\n", fsize);
402123653Swpaul	fprintf(outfp, "__asm__(\"drv_data:\");\n");
403123653Swpaul
404123475Swpaul	ptr = img;
405123475Swpaul	cnt = 0;
406123475Swpaul	while(cnt < fsize) {
407123653Swpaul		fprintf (outfp, "__asm__(\".byte ");
408123653Swpaul		for (i = 0; i < 10; i++) {
409123475Swpaul			cnt++;
410123475Swpaul			if (cnt == fsize) {
411123653Swpaul				fprintf(outfp, "0x%.2X\");\n", ptr[i]);
412123475Swpaul				goto done;
413123653Swpaul			} else {
414123653Swpaul				if (i == 9)
415123653Swpaul					fprintf(outfp, "0x%.2X\");\n", ptr[i]);
416123653Swpaul				else
417123653Swpaul					fprintf(outfp, "0x%.2X, ", ptr[i]);
418123653Swpaul			}
419123475Swpaul		}
420123653Swpaul		ptr += 10;
421123475Swpaul	}
422123475Swpaul
423123475Swpauldone:
424123475Swpaul
425126706Swpaul	fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
426132973Swpaul
427123475Swpaul	if (fp != NULL)
428123475Swpaul		fclose(fp);
429123475Swpaul	fclose(outfp);
430123475Swpaul	free(img);
431123475Swpaul	exit(0);
432123475Swpaul}
433