kernel - Bring in dff23c692 from FreeBSD
[dragonfly.git] / usr.sbin / ndiscvt / ndiscvt.c
blob715b660c193118d1e5ff30bff0b5768977c097c7
1 /*
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
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.
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.
32 * $FreeBSD: src/usr.sbin/ndiscvt/ndiscvt.c,v 1.16 2011/02/18 20:54:12 dim Exp $
35 #include <sys/types.h>
36 #include <sys/queue.h>
37 #include <sys/socket.h>
38 #include <net/if.h>
39 #include <stdlib.h>
40 #include <stddef.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <errno.h>
44 #include <string.h>
45 #include <libgen.h>
46 #include <err.h>
47 #include <ctype.h>
49 #include <emulation/ndis/pe_var.h>
51 #include "inf.h"
53 static int insert_padding(void **, int *);
54 extern const char *__progname;
57 * Sections within Windows PE files are defined using virtual
58 * and physical address offsets and virtual and physical sizes.
59 * The physical values define how the section data is stored in
60 * the executable file while the virtual values describe how the
61 * sections will look once loaded into memory. It happens that
62 * the linker in the Microsoft(r) DDK will tend to generate
63 * binaries where the virtual and physical values are identical,
64 * which means in most cases we can just transfer the file
65 * directly to memory without any fixups. This is not always
66 * the case though, so we have to be prepared to handle files
67 * where the in-memory section layout differs from the disk file
68 * section layout.
70 * There are two kinds of variations that can occur: the relative
71 * virtual address of the section might be different from the
72 * physical file offset, and the virtual section size might be
73 * different from the physical size (for example, the physical
74 * size of the .data section might be 1024 bytes, but the virtual
75 * size might be 1384 bytes, indicating that the data section should
76 * actually use up 1384 bytes in RAM and be padded with zeros). What we
77 * do is read the original file into memory and then make an in-memory
78 * copy with all of the sections relocated, re-sized and zero padded
79 * according to the virtual values specified in the section headers.
80 * We then emit the fixed up image file for use by the if_ndis driver.
81 * This way, we don't have to do the fixups inside the kernel.
84 #define ROUND_DOWN(n, align) (((uintptr_t)n) & ~((align) - 1l))
85 #define ROUND_UP(n, align) ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \
86 (align))
88 #define SET_HDRS(x) \
89 dos_hdr = (image_dos_header *)x; \
90 nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew); \
91 sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
93 static int
94 insert_padding(void **imgbase, int *imglen)
96 image_section_header *sect_hdr;
97 image_dos_header *dos_hdr;
98 image_nt_header *nt_hdr;
99 image_optional_header opt_hdr;
100 int i = 0, sections;
101 int offaccum = 0, oldraddr, oldrlen;
102 uint8_t *newimg, *tmp;
104 newimg = malloc(*imglen);
106 if (newimg == NULL)
107 return(ENOMEM);
109 bcopy(*imgbase, newimg, *imglen);
111 if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
112 return(0);
114 sections = pe_numsections((vm_offset_t)newimg);
116 SET_HDRS(newimg);
118 for (i = 0; i < sections; i++) {
119 oldraddr = sect_hdr->ish_rawdataaddr;
120 oldrlen = sect_hdr->ish_rawdatasize;
121 sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr;
122 offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr,
123 opt_hdr.ioh_filealign);
124 offaccum +=
125 ROUND_UP(sect_hdr->ish_misc.ish_vsize,
126 opt_hdr.ioh_filealign) -
127 ROUND_UP(sect_hdr->ish_rawdatasize,
128 opt_hdr.ioh_filealign);
129 tmp = realloc(newimg, *imglen + offaccum);
130 if (tmp == NULL) {
131 free(newimg);
132 return(ENOMEM);
134 newimg = tmp;
135 SET_HDRS(newimg);
136 sect_hdr += i;
137 bzero(newimg + sect_hdr->ish_rawdataaddr,
138 ROUND_UP(sect_hdr->ish_misc.ish_vsize,
139 opt_hdr.ioh_filealign));
140 bcopy((uint8_t *)(*imgbase) + oldraddr,
141 newimg + sect_hdr->ish_rawdataaddr, oldrlen);
142 sect_hdr++;
145 free(*imgbase);
147 *imgbase = newimg;
148 *imglen += offaccum;
150 return(0);
153 static void
154 usage(void)
156 fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> "
157 "[-n devname] [-o outfile]\n", __progname);
158 fprintf(stderr, " %s -f <firmfile>\n", __progname);
160 exit(1);
163 static void
164 bincvt(char *sysfile, char *outfile, void *img, int fsize)
166 char *ptr;
167 char tname[] = "/tmp/ndiscvt.XXXXXX";
168 char sysbuf[1024];
169 FILE *binfp;
171 mkstemp(tname);
173 binfp = fopen(tname, "a+");
174 if (binfp == NULL)
175 err(1, "opening %s failed", tname);
177 if (fwrite(img, fsize, 1, binfp) != 1)
178 err(1, "failed to output binary image");
180 fclose(binfp);
182 outfile = strdup(basename(outfile));
183 if (strchr(outfile, '.'))
184 *strchr(outfile, '.') = '\0';
186 snprintf(sysbuf, sizeof(sysbuf),
187 #ifdef __i386__
188 "objcopy -I binary -O elf32-i386 -B i386 %s %s.o\n",
189 #endif
190 #ifdef __x86_64__
191 "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n",
192 #endif
193 tname, outfile);
194 printf("%s", sysbuf);
195 system(sysbuf);
196 unlink(tname);
198 ptr = tname;
199 while (*ptr) {
200 if (*ptr == '/' || *ptr == '.')
201 *ptr = '_';
202 ptr++;
205 snprintf(sysbuf, sizeof(sysbuf),
206 "objcopy --redefine-sym _binary_%s_start=ndis_%s_drv_data_start "
207 "--strip-symbol _binary_%s_size "
208 "--redefine-sym _binary_%s_end=ndis_%s_drv_data_end %s.o %s.o\n",
209 tname, sysfile, tname, tname, sysfile, outfile, outfile);
210 printf("%s", sysbuf);
211 system(sysbuf);
213 return;
216 static void
217 firmcvt(char *firmfile)
219 char *basefile, *outfile, *ptr;
220 char sysbuf[1024];
222 outfile = strdup(basename(firmfile));
223 basefile = strdup(outfile);
225 snprintf(sysbuf, sizeof(sysbuf),
226 #ifdef __i386__
227 "objcopy -I binary -O elf32-i386 -B i386 %s %s.o\n",
228 #endif
229 #ifdef __x86_64__
230 "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n",
231 #endif
232 firmfile, outfile);
233 printf("%s", sysbuf);
234 system(sysbuf);
236 ptr = firmfile;
237 while (*ptr) {
238 if (*ptr == '/' || *ptr == '.')
239 *ptr = '_';
240 ptr++;
242 ptr = basefile;
243 while (*ptr) {
244 if (*ptr == '/' || *ptr == '.')
245 *ptr = '_';
246 else
247 *ptr = tolower(*ptr);
248 ptr++;
251 snprintf(sysbuf, sizeof(sysbuf),
252 "objcopy --redefine-sym _binary_%s_start=%s_start "
253 "--strip-symbol _binary_%s_size "
254 "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n",
255 firmfile, basefile, firmfile, firmfile,
256 basefile, outfile, outfile);
257 ptr = sysbuf;
258 printf("%s", sysbuf);
259 system(sysbuf);
261 snprintf(sysbuf, sizeof(sysbuf),
262 "ld -Bshareable -d -warn-common -o %s.ko %s.o\n",
263 outfile, outfile);
264 printf("%s", sysbuf);
265 system(sysbuf);
267 free(basefile);
269 exit(0);
273 main(int argc, char *argv[])
275 FILE *fp, *outfp;
276 int i, bin = 0;
277 void *img;
278 int n, fsize, cnt;
279 unsigned char *ptr;
280 char *inffile = NULL, *sysfile = NULL;
281 char *outfile = NULL, *firmfile = NULL;
282 char *dname = NULL;
283 int ch;
285 while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) {
286 switch(ch) {
287 case 'f':
288 firmfile = optarg;
289 break;
290 case 'i':
291 inffile = optarg;
292 break;
293 case 's':
294 sysfile = optarg;
295 break;
296 case 'o':
297 outfile = optarg;
298 break;
299 case 'n':
300 dname = optarg;
301 break;
302 case 'O':
303 bin = 1;
304 break;
305 default:
306 usage();
307 break;
311 if (firmfile != NULL)
312 firmcvt(firmfile);
314 if (sysfile == NULL)
315 usage();
317 /* Open the .SYS file and load it into memory */
318 fp = fopen(sysfile, "r");
319 if (fp == NULL)
320 err(1, "opening .SYS file '%s' failed", sysfile);
321 fseek (fp, 0L, SEEK_END);
322 fsize = ftell (fp);
323 rewind (fp);
324 img = calloc(fsize, 1);
325 n = fread (img, fsize, 1, fp);
326 if (n == 0)
327 err(1, "reading .SYS file '%s' failed", sysfile);
329 fclose(fp);
331 if (insert_padding(&img, &fsize)) {
332 fprintf(stderr, "section relocation failed\n");
333 exit(1);
336 if (outfile == NULL || strcmp(outfile, "-") == 0)
337 outfp = stdout;
338 else {
339 outfp = fopen(outfile, "w");
340 if (outfp == NULL)
341 err(1, "opening output file '%s' failed", outfile);
344 fprintf(outfp, "\n/*\n");
345 fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
346 inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
347 fprintf(outfp, " */\n\n");
349 if (dname != NULL) {
350 if (strlen(dname) > IFNAMSIZ)
351 err(1, "selected device name '%s' is "
352 "too long (max chars: %d)", dname, IFNAMSIZ);
353 fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
354 fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
357 if (inffile == NULL) {
358 fprintf (outfp, "#ifdef NDIS_REGVALS\n");
359 fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
360 fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
361 fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
363 fprintf (outfp, "};\n\n");
364 } else {
365 fp = fopen(inffile, "r");
366 if (fp == NULL)
367 err(1, "opening .INF file '%s' failed", inffile);
370 inf_parse(fp, outfp);
371 fclose(fp);
374 fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
376 if (bin) {
377 sysfile = strdup(basename(sysfile));
378 ptr = (unsigned char *)sysfile;
379 while (*ptr) {
380 if (*ptr == '.')
381 *ptr = '_';
382 ptr++;
384 fprintf(outfp,
385 "\nextern unsigned char ndis_%s_drv_data_start[];\n",
386 sysfile);
387 fprintf(outfp, "static unsigned char *drv_data = "
388 "ndis_%s_drv_data_start;\n\n", sysfile);
389 bincvt(sysfile, outfile, img, fsize);
390 goto done;
394 fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
396 fprintf(outfp, "__asm__(\".data\");\n");
397 fprintf(outfp, "__asm__(\".globl drv_data\");\n");
398 fprintf(outfp, "__asm__(\".type drv_data, @object\");\n");
399 fprintf(outfp, "__asm__(\".size drv_data, %d\");\n", fsize);
400 fprintf(outfp, "__asm__(\"drv_data:\");\n");
402 ptr = img;
403 cnt = 0;
404 while(cnt < fsize) {
405 fprintf (outfp, "__asm__(\".byte ");
406 for (i = 0; i < 10; i++) {
407 cnt++;
408 if (cnt == fsize) {
409 fprintf(outfp, "0x%.2X\");\n", ptr[i]);
410 goto done;
411 } else {
412 if (i == 9)
413 fprintf(outfp, "0x%.2X\");\n", ptr[i]);
414 else
415 fprintf(outfp, "0x%.2X, ", ptr[i]);
418 ptr += 10;
421 done:
423 fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
425 if (fp != NULL)
426 fclose(fp);
427 fclose(outfp);
428 free(img);
429 exit(0);