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