ndiscvt.c revision 126706
1/*
2 * Copyright (c) 2003
3 *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/usr.sbin/ndiscvt/ndiscvt.c 126706 2004-03-07 02:49:06Z wpaul $");
35
36#include <sys/types.h>
37#include <sys/queue.h>
38#include <sys/socket.h>
39#include <net/if.h>
40#include <stdlib.h>
41#include <unistd.h>
42#include <stdio.h>
43#include <errno.h>
44#include <string.h>
45#include <err.h>
46
47#include <compat/ndis/pe_var.h>
48
49#include "inf.h"
50
51static int insert_padding(void **, int *);
52extern const char *__progname;
53
54/*
55 * Sections in object code files can be sparse. That is, the
56 * section may occupy more space in memory that it does when
57 * stored in a disk file. In Windows PE files, each section header
58 * has a 'virtual size' and 'raw data size' field. The latter
59 * specifies the amount of section data actually stored in the
60 * disk file, and the former describes how much space the section
61 * should actually occupy in memory. If the vsize is larger than
62 * the rsize, we need to allocate some extra storage and fill
63 * it with zeros. (Think BSS.)
64 *
65 * The typical method of loading an executable file involves
66 * reading each segment into memory using the vaddr/vsize from
67 * each section header. We try to make a small optimization however
68 * and only pad/move segments when it's absolutely necessary, i.e.
69 * if the vsize is larger than the rsize. This conserves a little
70 * bit of memory, at the cost of having to fixup some of the values
71 * in the section headers.
72 */
73
74#define ROUND_UP(x, y)	\
75	(((x) + (y)) - ((x) % (y)))
76
77#define SET_HDRS(x)	\
78	dos_hdr = (image_dos_header *)x;				\
79	nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew);		\
80	sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +	\
81	    sizeof(image_nt_header));
82
83static
84int insert_padding(imgbase, imglen)
85	void			**imgbase;
86	int			*imglen;
87{
88        image_section_header	*sect_hdr;
89        image_dos_header	*dos_hdr;
90        image_nt_header		*nt_hdr;
91	image_optional_header	opt_hdr;
92        int			i = 0, sections, curlen = 0;
93	int			offaccum = 0, diff, oldraddr, oldrlen;
94	uint8_t			*newimg, *tmp;
95
96	newimg = malloc(*imglen);
97
98	if (newimg == NULL)
99		return(ENOMEM);
100
101	bcopy(*imgbase, newimg, *imglen);
102	curlen = *imglen;
103
104	if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
105		return(0);
106
107        sections = pe_numsections((vm_offset_t)newimg);
108
109	SET_HDRS(newimg);
110
111	for (i = 0; i < sections; i++) {
112		/*
113		 * If we have accumulated any padding offset,
114		 * add it to the raw data address of this segment.
115		 */
116		oldraddr = sect_hdr->ish_rawdataaddr;
117		oldrlen = sect_hdr->ish_rawdatasize;
118		if (offaccum)
119			sect_hdr->ish_rawdataaddr += offaccum;
120		if (sect_hdr->ish_misc.ish_vsize >
121		    sect_hdr->ish_rawdatasize) {
122			diff = ROUND_UP(sect_hdr->ish_misc.ish_vsize -
123			    sect_hdr->ish_rawdatasize,
124			    opt_hdr.ioh_filealign);
125			offaccum += ROUND_UP(diff -
126			    (sect_hdr->ish_misc.ish_vsize -
127			    sect_hdr->ish_rawdatasize),
128			    opt_hdr.ioh_filealign);
129			sect_hdr->ish_rawdatasize =
130			    ROUND_UP(sect_hdr->ish_rawdatasize,
131			    opt_hdr.ioh_filealign);
132			tmp = realloc(newimg, *imglen + offaccum);
133			if (tmp == NULL) {
134				free(newimg);
135				return(ENOMEM);
136			}
137			newimg = tmp;
138			SET_HDRS(newimg);
139			sect_hdr += i;
140		}
141		bzero(newimg + sect_hdr->ish_rawdataaddr,
142		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
143		    opt_hdr.ioh_filealign));
144		bcopy((uint8_t *)(*imgbase) + oldraddr,
145		    newimg + sect_hdr->ish_rawdataaddr, oldrlen);
146		sect_hdr++;
147	}
148
149	free(*imgbase);
150
151	*imgbase = newimg;
152	*imglen += offaccum;
153
154	return(0);
155}
156
157static void
158usage(void)
159{
160	fprintf(stderr, "Usage: %s [-i <inffile>] -s <sysfile> "
161	    "[-n devname] [-o outfile]\n", __progname);
162	exit(1);
163}
164
165int
166main(int argc, char *argv[])
167{
168	FILE		*fp, *outfp;
169	void		*img;
170	int		n, fsize, cnt;
171	unsigned char	*ptr;
172	int		i;
173	char		*inffile = NULL, *sysfile = NULL, *outfile = NULL;
174	char		*dname = NULL;
175	int		ch;
176
177	while((ch = getopt(argc, argv, "i:s:o:n:")) != -1) {
178		switch(ch) {
179		case 'i':
180			inffile = optarg;
181			break;
182		case 's':
183			sysfile = optarg;
184			break;
185		case 'o':
186			outfile = optarg;
187			break;
188		case 'n':
189			dname = optarg;
190			break;
191		default:
192			usage();
193			break;
194		}
195	}
196
197	if (sysfile == NULL)
198		usage();
199
200	/* Open the .SYS file and load it into memory */
201	fp = fopen(sysfile, "r");
202	if (fp == NULL)
203		err(1, "opening .SYS file '%s' failed", sysfile);
204	fseek (fp, 0L, SEEK_END);
205	fsize = ftell (fp);
206	rewind (fp);
207	img = calloc(fsize, 1);
208	n = fread (img, fsize, 1, fp);
209
210	fclose(fp);
211
212	if (insert_padding(&img, &fsize)) {
213		fprintf(stderr, "section relocation failed\n");
214		exit(1);
215	}
216
217	if (outfile == NULL || strcmp(outfile, "-") == 0)
218		outfp = stdout;
219	else {
220		outfp = fopen(outfile, "w");
221		if (outfp == NULL)
222			err(1, "opening output file '%s' failed", outfile);
223	}
224
225	fprintf(outfp, "\n/*\n");
226	fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
227	    inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
228	fprintf(outfp, " */\n\n");
229
230	if (dname != NULL) {
231		if (strlen(dname) > IFNAMSIZ)
232			err(1, "selected device name '%s' is "
233			    "too long (max chars: %d)", dname, IFNAMSIZ);
234		fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
235		fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
236	}
237
238	if (inffile == NULL) {
239		fprintf (outfp, "#ifdef NDIS_REGVALS\n");
240		fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
241        	fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
242		fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
243
244		fprintf (outfp, "};\n\n");
245	} else {
246		fp = fopen(inffile, "r");
247		if (fp == NULL)
248			err(1, "opening .INF file '%s' failed", inffile);
249
250
251		inf_parse(fp, outfp);
252		fclose(fp);
253	}
254
255	fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
256	fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
257
258	fprintf(outfp, "__asm__(\".data\");\n");
259	fprintf(outfp, "__asm__(\".type   drv_data, @object\");\n");
260	fprintf(outfp, "__asm__(\".size   drv_data, %d\");\n", fsize);
261	fprintf(outfp, "__asm__(\"drv_data:\");\n");
262
263	ptr = img;
264	cnt = 0;
265	while(cnt < fsize) {
266		fprintf (outfp, "__asm__(\".byte ");
267		for (i = 0; i < 10; i++) {
268			cnt++;
269			if (cnt == fsize) {
270				fprintf(outfp, "0x%.2X\");\n", ptr[i]);
271				goto done;
272			} else {
273				if (i == 9)
274					fprintf(outfp, "0x%.2X\");\n", ptr[i]);
275				else
276					fprintf(outfp, "0x%.2X, ", ptr[i]);
277			}
278		}
279		ptr += 10;
280	}
281
282done:
283
284	fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
285	if (fp != NULL)
286		fclose(fp);
287	fclose(outfp);
288	free(img);
289	exit(0);
290}
291