ndiscvt.c revision 201387
1227650Skevlo/*
2227650Skevlo * Copyright (c) 2003
3227650Skevlo *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4227650Skevlo *
5227650Skevlo * Redistribution and use in source and binary forms, with or without
6227650Skevlo * modification, are permitted provided that the following conditions
7227650Skevlo * are met:
8227650Skevlo * 1. Redistributions of source code must retain the above copyright
9227650Skevlo *    notice, this list of conditions and the following disclaimer.
10227650Skevlo * 2. Redistributions in binary form must reproduce the above copyright
11227650Skevlo *    notice, this list of conditions and the following disclaimer in the
12227650Skevlo *    documentation and/or other materials provided with the distribution.
13227650Skevlo * 3. All advertising materials mentioning features or use of this software
14227650Skevlo *    must display the following acknowledgement:
15227650Skevlo *	This product includes software developed by Bill Paul.
16227650Skevlo * 4. Neither the name of the author nor the names of any co-contributors
17227650Skevlo *    may be used to endorse or promote products derived from this software
18227650Skevlo *    without specific prior written permission.
19227650Skevlo *
20227650Skevlo * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21227650Skevlo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22227650Skevlo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23227650Skevlo * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24227650Skevlo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25227650Skevlo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26227650Skevlo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27227650Skevlo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28227650Skevlo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29227650Skevlo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30227650Skevlo * THE POSSIBILITY OF SUCH DAMAGE.
31227650Skevlo */
32227650Skevlo
33227650Skevlo#include <sys/cdefs.h>
34227650Skevlo__FBSDID("$FreeBSD: head/usr.sbin/ndiscvt/ndiscvt.c 201387 2010-01-02 11:05:34Z ed $");
35227650Skevlo
36227650Skevlo#include <sys/types.h>
37227650Skevlo#include <sys/queue.h>
38227650Skevlo#include <sys/socket.h>
39227650Skevlo#include <net/if.h>
40227650Skevlo#include <stdlib.h>
41227650Skevlo#include <stddef.h>
42227650Skevlo#include <unistd.h>
43227650Skevlo#include <stdio.h>
44227650Skevlo#include <errno.h>
45227650Skevlo#include <string.h>
46227650Skevlo#include <libgen.h>
47227650Skevlo#include <err.h>
48227650Skevlo#include <ctype.h>
49227650Skevlo
50227650Skevlo#include <compat/ndis/pe_var.h>
51227650Skevlo
52227650Skevlo#include "inf.h"
53227650Skevlo
54227650Skevlostatic int insert_padding(void **, int *);
55227650Skevloextern const char *__progname;
56227650Skevlo
57227650Skevlo/*
58227650Skevlo * Sections within Windows PE files are defined using virtual
59227650Skevlo * and physical address offsets and virtual and physical sizes.
60227650Skevlo * The physical values define how the section data is stored in
61227650Skevlo * the executable file while the virtual values describe how the
62227650Skevlo * sections will look once loaded into memory. It happens that
63227650Skevlo * the linker in the Microsoft(r) DDK will tend to generate
64227650Skevlo * binaries where the virtual and physical values are identical,
65227650Skevlo * which means in most cases we can just transfer the file
66227650Skevlo * directly to memory without any fixups. This is not always
67227650Skevlo * the case though, so we have to be prepared to handle files
68227650Skevlo * where the in-memory section layout differs from the disk file
69227650Skevlo * section layout.
70227650Skevlo *
71227650Skevlo * There are two kinds of variations that can occur: the relative
72227650Skevlo * virtual address of the section might be different from the
73227650Skevlo * physical file offset, and the virtual section size might be
74227650Skevlo * different from the physical size (for example, the physical
75227650Skevlo * size of the .data section might be 1024 bytes, but the virtual
76227650Skevlo * size might be 1384 bytes, indicating that the data section should
77227650Skevlo * actually use up 1384 bytes in RAM and be padded with zeros). What we
78227650Skevlo * do is read the original file into memory and then make an in-memory
79227650Skevlo * copy with all of the sections relocated, re-sized and zero padded
80227650Skevlo * according to the virtual values specified in the section headers.
81227650Skevlo * We then emit the fixed up image file for use by the if_ndis driver.
82227650Skevlo * This way, we don't have to do the fixups inside the kernel.
83227650Skevlo */
84227650Skevlo
85227650Skevlo#define ROUND_DOWN(n, align)    (((uintptr_t)n) & ~((align) - 1l))
86227650Skevlo#define ROUND_UP(n, align)      ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \
87227650Skevlo                                (align))
88227650Skevlo
89227650Skevlo#define SET_HDRS(x)	\
90227650Skevlo	dos_hdr = (image_dos_header *)x;				\
91227650Skevlo	nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew);		\
92227650Skevlo	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
93227650Skevlo
94227650Skevlostatic int
95227650Skevloinsert_padding(void **imgbase, int *imglen)
96227650Skevlo{
97227650Skevlo        image_section_header	*sect_hdr;
98227650Skevlo        image_dos_header	*dos_hdr;
99227650Skevlo        image_nt_header		*nt_hdr;
100227650Skevlo	image_optional_header	opt_hdr;
101227650Skevlo        int			i = 0, sections, curlen = 0;
102227650Skevlo	int			offaccum = 0, oldraddr, oldrlen;
103227650Skevlo	uint8_t			*newimg, *tmp;
104227650Skevlo
105235713Skevlo	newimg = malloc(*imglen);
106227650Skevlo
107235713Skevlo	if (newimg == NULL)
108227650Skevlo		return(ENOMEM);
109227650Skevlo
110235713Skevlo	bcopy(*imgbase, newimg, *imglen);
111227650Skevlo	curlen = *imglen;
112227650Skevlo
113227650Skevlo	if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
114227650Skevlo		return(0);
115227650Skevlo
116227650Skevlo        sections = pe_numsections((vm_offset_t)newimg);
117227650Skevlo
118227650Skevlo	SET_HDRS(newimg);
119227650Skevlo
120227650Skevlo	for (i = 0; i < sections; i++) {
121227650Skevlo		oldraddr = sect_hdr->ish_rawdataaddr;
122227650Skevlo		oldrlen = sect_hdr->ish_rawdatasize;
123227650Skevlo		sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr;
124227650Skevlo		offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr,
125227650Skevlo		    opt_hdr.ioh_filealign);
126227650Skevlo		offaccum +=
127227650Skevlo		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
128227650Skevlo			     opt_hdr.ioh_filealign) -
129227650Skevlo		    ROUND_UP(sect_hdr->ish_rawdatasize,
130227650Skevlo			     opt_hdr.ioh_filealign);
131227650Skevlo		tmp = realloc(newimg, *imglen + offaccum);
132227650Skevlo		if (tmp == NULL) {
133227650Skevlo			free(newimg);
134227650Skevlo			return(ENOMEM);
135227650Skevlo		}
136227650Skevlo		newimg = tmp;
137227650Skevlo		SET_HDRS(newimg);
138227650Skevlo		sect_hdr += i;
139227650Skevlo		bzero(newimg + sect_hdr->ish_rawdataaddr,
140227650Skevlo		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
141227650Skevlo		    opt_hdr.ioh_filealign));
142227650Skevlo		bcopy((uint8_t *)(*imgbase) + oldraddr,
143227650Skevlo		    newimg + sect_hdr->ish_rawdataaddr, oldrlen);
144227650Skevlo		sect_hdr++;
145227650Skevlo	}
146227650Skevlo
147227650Skevlo	free(*imgbase);
148227650Skevlo
149227650Skevlo	*imgbase = newimg;
150227650Skevlo	*imglen += offaccum;
151227650Skevlo
152227650Skevlo	return(0);
153227650Skevlo}
154227650Skevlo
155227650Skevlostatic void
156227650Skevlousage(void)
157227650Skevlo{
158227650Skevlo	fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> "
159227650Skevlo	    "[-n devname] [-o outfile]\n", __progname);
160227650Skevlo	fprintf(stderr, "       %s -f <firmfile>\n", __progname);
161227650Skevlo
162227650Skevlo	exit(1);
163227650Skevlo}
164227650Skevlo
165227650Skevlostatic void
166227650Skevlobincvt(char *sysfile, char *outfile, void *img, int fsize)
167227650Skevlo{
168227650Skevlo	char			*ptr;
169227650Skevlo	char			tname[] = "/tmp/ndiscvt.XXXXXX";
170227650Skevlo	char			sysbuf[1024];
171227650Skevlo	FILE			*binfp;
172227650Skevlo
173227650Skevlo	mkstemp(tname);
174227650Skevlo
175227650Skevlo	binfp = fopen(tname, "a+");
176227650Skevlo	if (binfp == NULL)
177227650Skevlo		err(1, "opening %s failed", tname);
178227650Skevlo
179227650Skevlo	if (fwrite(img, fsize, 1, binfp) != 1)
180227650Skevlo		err(1, "failed to output binary image");
181227650Skevlo
182227650Skevlo	fclose(binfp);
183227650Skevlo
184227650Skevlo	outfile = strdup(basename(outfile));
185227650Skevlo	if (strchr(outfile, '.'))
186227650Skevlo		*strchr(outfile, '.') = '\0';
187227650Skevlo
188227650Skevlo	snprintf(sysbuf, sizeof(sysbuf),
189227650Skevlo#ifdef __i386__
190227650Skevlo	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
191227650Skevlo#endif
192227650Skevlo#ifdef __amd64__
193227650Skevlo	    "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n",
194227650Skevlo#endif
195227650Skevlo	    tname, outfile);
196227650Skevlo	printf("%s", sysbuf);
197227650Skevlo	system(sysbuf);
198227650Skevlo	unlink(tname);
199227650Skevlo
200227650Skevlo	ptr = tname;
201227650Skevlo	while (*ptr) {
202227650Skevlo		if (*ptr == '/' || *ptr == '.')
203227650Skevlo			*ptr = '_';
204227650Skevlo		ptr++;
205227650Skevlo	}
206227650Skevlo
207227650Skevlo	snprintf(sysbuf, sizeof(sysbuf),
208227650Skevlo	    "objcopy --redefine-sym _binary_%s_start=ndis_%s_drv_data_start "
209227650Skevlo	    "--strip-symbol _binary_%s_size "
210227650Skevlo	    "--redefine-sym _binary_%s_end=ndis_%s_drv_data_end %s.o %s.o\n",
211227650Skevlo	    tname, sysfile, tname, tname, sysfile, outfile, outfile);
212227650Skevlo	printf("%s", sysbuf);
213227650Skevlo	system(sysbuf);
214227650Skevlo
215227650Skevlo	return;
216227650Skevlo}
217227650Skevlo
218227650Skevlostatic void
219227650Skevlofirmcvt(char *firmfile)
220227650Skevlo{
221227650Skevlo	char			*basefile, *outfile, *ptr;
222227650Skevlo	char			sysbuf[1024];
223227650Skevlo
224227650Skevlo	outfile = strdup(basename(firmfile));
225227650Skevlo	basefile = strdup(outfile);
226227650Skevlo
227227650Skevlo	snprintf(sysbuf, sizeof(sysbuf),
228227650Skevlo#ifdef __i386__
229227650Skevlo	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
230227650Skevlo#endif
231227650Skevlo#ifdef __amd64__
232227650Skevlo	    "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n",
233227650Skevlo#endif
234227650Skevlo	    firmfile, outfile);
235227650Skevlo	printf("%s", sysbuf);
236227650Skevlo	system(sysbuf);
237227650Skevlo
238227650Skevlo	ptr = firmfile;
239227650Skevlo	while (*ptr) {
240227650Skevlo		if (*ptr == '/' || *ptr == '.')
241227650Skevlo			*ptr = '_';
242227650Skevlo		ptr++;
243227650Skevlo	}
244227650Skevlo	ptr = basefile;
245227650Skevlo	while (*ptr) {
246227650Skevlo		if (*ptr == '/' || *ptr == '.')
247227650Skevlo			*ptr = '_';
248227650Skevlo		else
249227650Skevlo			*ptr = tolower(*ptr);
250227650Skevlo		ptr++;
251227650Skevlo	}
252227650Skevlo
253227650Skevlo	snprintf(sysbuf, sizeof(sysbuf),
254227650Skevlo	    "objcopy --redefine-sym _binary_%s_start=%s_start "
255227650Skevlo	    "--strip-symbol _binary_%s_size "
256227650Skevlo	    "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n",
257227650Skevlo	    firmfile, basefile, firmfile, firmfile,
258227650Skevlo	    basefile, outfile, outfile);
259227650Skevlo	ptr = sysbuf;
260227650Skevlo	printf("%s", sysbuf);
261227650Skevlo	system(sysbuf);
262227650Skevlo
263227650Skevlo	snprintf(sysbuf, sizeof(sysbuf),
264227650Skevlo	    "ld -Bshareable -d -warn-common -o %s.ko %s.o\n",
265227650Skevlo	    outfile, outfile);
266227650Skevlo	printf("%s", sysbuf);
267227650Skevlo	system(sysbuf);
268227650Skevlo
269227650Skevlo	free(basefile);
270227650Skevlo
271227650Skevlo	exit(0);
272227650Skevlo}
273227650Skevlo
274227650Skevloint
275227650Skevlomain(int argc, char *argv[])
276227650Skevlo{
277227650Skevlo	FILE			*fp, *outfp;
278227650Skevlo	int			i, bin = 0;
279227650Skevlo	void			*img;
280227650Skevlo	int			n, fsize, cnt;
281227650Skevlo	unsigned char		*ptr;
282227650Skevlo	char			*inffile = NULL, *sysfile = NULL;
283227650Skevlo	char			*outfile = NULL, *firmfile = NULL;
284227650Skevlo	char			*dname = NULL;
285227650Skevlo	int			ch;
286227650Skevlo
287227650Skevlo	while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) {
288227650Skevlo		switch(ch) {
289227650Skevlo		case 'f':
290227650Skevlo			firmfile = optarg;
291227650Skevlo			break;
292227650Skevlo		case 'i':
293227650Skevlo			inffile = optarg;
294227650Skevlo			break;
295227650Skevlo		case 's':
296227650Skevlo			sysfile = optarg;
297227650Skevlo			break;
298227650Skevlo		case 'o':
299227650Skevlo			outfile = optarg;
300227650Skevlo			break;
301227650Skevlo		case 'n':
302227650Skevlo			dname = optarg;
303227650Skevlo			break;
304227650Skevlo		case 'O':
305227650Skevlo			bin = 1;
306227650Skevlo			break;
307227650Skevlo		default:
308227650Skevlo			usage();
309227650Skevlo			break;
310227650Skevlo		}
311227650Skevlo	}
312227650Skevlo
313227650Skevlo	if (firmfile != NULL)
314227650Skevlo		firmcvt(firmfile);
315227650Skevlo
316227650Skevlo	if (sysfile == NULL)
317227650Skevlo		usage();
318227650Skevlo
319227650Skevlo	/* Open the .SYS file and load it into memory */
320227650Skevlo	fp = fopen(sysfile, "r");
321227650Skevlo	if (fp == NULL)
322227650Skevlo		err(1, "opening .SYS file '%s' failed", sysfile);
323227650Skevlo	fseek (fp, 0L, SEEK_END);
324227650Skevlo	fsize = ftell (fp);
325227650Skevlo	rewind (fp);
326227650Skevlo	img = calloc(fsize, 1);
327227650Skevlo	n = fread (img, fsize, 1, fp);
328227650Skevlo
329227650Skevlo	fclose(fp);
330227650Skevlo
331227650Skevlo	if (insert_padding(&img, &fsize)) {
332227650Skevlo		fprintf(stderr, "section relocation failed\n");
333227650Skevlo		exit(1);
334227650Skevlo	}
335227650Skevlo
336227650Skevlo	if (outfile == NULL || strcmp(outfile, "-") == 0)
337227650Skevlo		outfp = stdout;
338227650Skevlo	else {
339227650Skevlo		outfp = fopen(outfile, "w");
340227650Skevlo		if (outfp == NULL)
341227650Skevlo			err(1, "opening output file '%s' failed", outfile);
342227650Skevlo	}
343227650Skevlo
344227650Skevlo	fprintf(outfp, "\n/*\n");
345227650Skevlo	fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
346227650Skevlo	    inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
347227650Skevlo	fprintf(outfp, " */\n\n");
348227650Skevlo
349227650Skevlo	if (dname != NULL) {
350227650Skevlo		if (strlen(dname) > IFNAMSIZ)
351227650Skevlo			err(1, "selected device name '%s' is "
352227650Skevlo			    "too long (max chars: %d)", dname, IFNAMSIZ);
353227650Skevlo		fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
354227650Skevlo		fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
355227650Skevlo	}
356227650Skevlo
357227650Skevlo	if (inffile == NULL) {
358227650Skevlo		fprintf (outfp, "#ifdef NDIS_REGVALS\n");
359227650Skevlo		fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
360227650Skevlo        	fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
361227650Skevlo		fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
362227650Skevlo
363227650Skevlo		fprintf (outfp, "};\n\n");
364227650Skevlo	} else {
365227650Skevlo		fp = fopen(inffile, "r");
366227650Skevlo		if (fp == NULL)
367227650Skevlo			err(1, "opening .INF file '%s' failed", inffile);
368227650Skevlo
369227650Skevlo
370227650Skevlo		inf_parse(fp, outfp);
371227650Skevlo		fclose(fp);
372227650Skevlo	}
373227650Skevlo
374227650Skevlo	fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
375227650Skevlo
376227650Skevlo	if (bin) {
377227650Skevlo		sysfile = strdup(basename(sysfile));
378227650Skevlo		ptr = (unsigned char *)sysfile;
379227650Skevlo		while (*ptr) {
380227650Skevlo			if (*ptr == '.')
381227650Skevlo				*ptr = '_';
382227650Skevlo			ptr++;
383227650Skevlo		}
384227650Skevlo		fprintf(outfp,
385227650Skevlo		    "\nextern unsigned char ndis_%s_drv_data_start[];\n",
386227650Skevlo		    sysfile);
387227650Skevlo		fprintf(outfp, "static unsigned char *drv_data = "
388227650Skevlo		    "ndis_%s_drv_data_start;\n\n", sysfile);
389227650Skevlo		bincvt(sysfile, outfile, img, fsize);
390227650Skevlo		goto done;
391227650Skevlo	}
392227650Skevlo
393227650Skevlo
394227650Skevlo	fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
395227650Skevlo
396227650Skevlo	fprintf(outfp, "__asm__(\".data\");\n");
397227650Skevlo	fprintf(outfp, "__asm__(\".globl  drv_data\");\n");
398227650Skevlo	fprintf(outfp, "__asm__(\".type   drv_data, @object\");\n");
399227650Skevlo	fprintf(outfp, "__asm__(\".size   drv_data, %d\");\n", fsize);
400227650Skevlo	fprintf(outfp, "__asm__(\"drv_data:\");\n");
401227650Skevlo
402227650Skevlo	ptr = img;
403227650Skevlo	cnt = 0;
404227650Skevlo	while(cnt < fsize) {
405227650Skevlo		fprintf (outfp, "__asm__(\".byte ");
406227650Skevlo		for (i = 0; i < 10; i++) {
407227650Skevlo			cnt++;
408227650Skevlo			if (cnt == fsize) {
409227650Skevlo				fprintf(outfp, "0x%.2X\");\n", ptr[i]);
410227650Skevlo				goto done;
411227650Skevlo			} else {
412227650Skevlo				if (i == 9)
413227650Skevlo					fprintf(outfp, "0x%.2X\");\n", ptr[i]);
414227650Skevlo				else
415227650Skevlo					fprintf(outfp, "0x%.2X, ", ptr[i]);
416227650Skevlo			}
417227650Skevlo		}
418227650Skevlo		ptr += 10;
419227650Skevlo	}
420227650Skevlo
421227650Skevlodone:
422227650Skevlo
423227650Skevlo	fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
424227650Skevlo
425227650Skevlo	if (fp != NULL)
426227650Skevlo		fclose(fp);
427227650Skevlo	fclose(outfp);
428227650Skevlo	free(img);
429227650Skevlo	exit(0);
430227650Skevlo}
431227650Skevlo