]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ndiscvt/ndiscvt.c
Merge libc++ trunk r321017 to contrib/libc++.
[FreeBSD/FreeBSD.git] / usr.sbin / ndiscvt / ndiscvt.c
1 /*
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2003
5  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/types.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <stdlib.h>
43 #include <stddef.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include <errno.h>
47 #include <string.h>
48 #include <libgen.h>
49 #include <err.h>
50 #include <ctype.h>
51
52 #include <compat/ndis/pe_var.h>
53
54 #include "inf.h"
55
56 static int insert_padding(void **, int *);
57 extern const char *__progname;
58
59 /*
60  * Sections within Windows PE files are defined using virtual
61  * and physical address offsets and virtual and physical sizes.
62  * The physical values define how the section data is stored in
63  * the executable file while the virtual values describe how the
64  * sections will look once loaded into memory. It happens that
65  * the linker in the Microsoft(r) DDK will tend to generate
66  * binaries where the virtual and physical values are identical,
67  * which means in most cases we can just transfer the file
68  * directly to memory without any fixups. This is not always
69  * the case though, so we have to be prepared to handle files
70  * where the in-memory section layout differs from the disk file
71  * section layout.
72  *
73  * There are two kinds of variations that can occur: the relative
74  * virtual address of the section might be different from the
75  * physical file offset, and the virtual section size might be
76  * different from the physical size (for example, the physical
77  * size of the .data section might be 1024 bytes, but the virtual
78  * size might be 1384 bytes, indicating that the data section should
79  * actually use up 1384 bytes in RAM and be padded with zeros). What we
80  * do is read the original file into memory and then make an in-memory
81  * copy with all of the sections relocated, re-sized and zero padded
82  * according to the virtual values specified in the section headers.
83  * We then emit the fixed up image file for use by the if_ndis driver.
84  * This way, we don't have to do the fixups inside the kernel.
85  */
86
87 #define ROUND_DOWN(n, align)    (((uintptr_t)n) & ~((align) - 1l))
88 #define ROUND_UP(n, align)      ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \
89                                 (align))
90
91 #define SET_HDRS(x)     \
92         dos_hdr = (image_dos_header *)x;                                \
93         nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew);          \
94         sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
95
96 static int
97 insert_padding(void **imgbase, int *imglen)
98 {
99         image_section_header    *sect_hdr;
100         image_dos_header        *dos_hdr;
101         image_nt_header         *nt_hdr;
102         image_optional_header   opt_hdr;
103         int                     i = 0, sections, curlen = 0;
104         int                     offaccum = 0, oldraddr, oldrlen;
105         uint8_t                 *newimg, *tmp;
106
107         newimg = malloc(*imglen);
108
109         if (newimg == NULL)
110                 return(ENOMEM);
111
112         bcopy(*imgbase, newimg, *imglen);
113         curlen = *imglen;
114
115         if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
116                 return(0);
117
118         sections = pe_numsections((vm_offset_t)newimg);
119
120         SET_HDRS(newimg);
121
122         for (i = 0; i < sections; i++) {
123                 oldraddr = sect_hdr->ish_rawdataaddr;
124                 oldrlen = sect_hdr->ish_rawdatasize;
125                 sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr;
126                 offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr,
127                     opt_hdr.ioh_filealign);
128                 offaccum +=
129                     ROUND_UP(sect_hdr->ish_misc.ish_vsize,
130                              opt_hdr.ioh_filealign) -
131                     ROUND_UP(sect_hdr->ish_rawdatasize,
132                              opt_hdr.ioh_filealign);
133                 tmp = realloc(newimg, *imglen + offaccum);
134                 if (tmp == NULL) {
135                         free(newimg);
136                         return(ENOMEM);
137                 }
138                 newimg = tmp;
139                 SET_HDRS(newimg);
140                 sect_hdr += i;
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
157 static void
158 usage(void)
159 {
160         fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> "
161             "[-n devname] [-o outfile]\n", __progname);
162         fprintf(stderr, "       %s -f <firmfile>\n", __progname);
163
164         exit(1);
165 }
166
167 static void
168 bincvt(char *sysfile, char *outfile, void *img, int fsize)
169 {
170         char                    *ptr;
171         char                    tname[] = "/tmp/ndiscvt.XXXXXX";
172         char                    sysbuf[1024];
173         FILE                    *binfp;
174
175         mkstemp(tname);
176
177         binfp = fopen(tname, "a+");
178         if (binfp == NULL)
179                 err(1, "opening %s failed", tname);
180
181         if (fwrite(img, fsize, 1, binfp) != 1)
182                 err(1, "failed to output binary image");
183
184         fclose(binfp);
185
186         outfile = strdup(basename(outfile));
187         if (strchr(outfile, '.'))
188                 *strchr(outfile, '.') = '\0';
189
190         snprintf(sysbuf, sizeof(sysbuf),
191 #ifdef __i386__
192             "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
193 #endif
194 #ifdef __amd64__
195             "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n",
196 #endif
197             tname, outfile);
198         printf("%s", sysbuf);
199         system(sysbuf);
200         unlink(tname);
201
202         ptr = tname;
203         while (*ptr) {
204                 if (*ptr == '/' || *ptr == '.')
205                         *ptr = '_';
206                 ptr++;
207         }
208
209         snprintf(sysbuf, sizeof(sysbuf),
210             "objcopy --redefine-sym _binary_%s_start=ndis_%s_drv_data_start "
211             "--strip-symbol _binary_%s_size "
212             "--redefine-sym _binary_%s_end=ndis_%s_drv_data_end %s.o %s.o\n",
213             tname, sysfile, tname, tname, sysfile, outfile, outfile);
214         printf("%s", sysbuf);
215         system(sysbuf);
216
217         return;
218 }
219    
220 static void
221 firmcvt(char *firmfile)
222 {
223         char                    *basefile, *outfile, *ptr;
224         char                    sysbuf[1024];
225
226         outfile = strdup(basename(firmfile));
227         basefile = strdup(outfile);
228
229         snprintf(sysbuf, sizeof(sysbuf),
230 #ifdef __i386__
231             "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
232 #endif
233 #ifdef __amd64__
234             "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n",
235 #endif
236             firmfile, outfile);
237         printf("%s", sysbuf);
238         system(sysbuf);
239
240         ptr = firmfile;
241         while (*ptr) {
242                 if (*ptr == '/' || *ptr == '.')
243                         *ptr = '_';
244                 ptr++;
245         }
246         ptr = basefile;
247         while (*ptr) {
248                 if (*ptr == '/' || *ptr == '.')
249                         *ptr = '_';
250                 else
251                         *ptr = tolower(*ptr);
252                 ptr++;
253         }
254
255         snprintf(sysbuf, sizeof(sysbuf),
256             "objcopy --redefine-sym _binary_%s_start=%s_start "
257             "--strip-symbol _binary_%s_size "
258             "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n",
259             firmfile, basefile, firmfile, firmfile,
260             basefile, outfile, outfile);
261         ptr = sysbuf;
262         printf("%s", sysbuf);
263         system(sysbuf);
264
265         snprintf(sysbuf, sizeof(sysbuf),
266             "ld -Bshareable -d -warn-common -o %s.ko %s.o\n",
267             outfile, outfile);
268         printf("%s", sysbuf);
269         system(sysbuf);
270
271         free(basefile);
272
273         exit(0);
274 }
275
276 int
277 main(int argc, char *argv[])
278 {
279         FILE                    *fp, *outfp;
280         int                     i, bin = 0;
281         void                    *img;
282         int                     n, fsize, cnt;
283         unsigned char           *ptr;
284         char                    *inffile = NULL, *sysfile = NULL;
285         char                    *outfile = NULL, *firmfile = NULL;
286         char                    *dname = NULL;
287         int                     ch;
288
289         while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) {
290                 switch(ch) {
291                 case 'f':
292                         firmfile = optarg;
293                         break;
294                 case 'i':
295                         inffile = optarg;
296                         break;
297                 case 's':
298                         sysfile = optarg;
299                         break;
300                 case 'o':
301                         outfile = optarg;
302                         break;
303                 case 'n':
304                         dname = optarg;
305                         break;
306                 case 'O':
307                         bin = 1;
308                         break;
309                 default:
310                         usage();
311                         break;
312                 }
313         }
314
315         if (firmfile != NULL)
316                 firmcvt(firmfile);
317
318         if (sysfile == NULL)
319                 usage();
320
321         /* Open the .SYS file and load it into memory */
322         fp = fopen(sysfile, "r");
323         if (fp == NULL)
324                 err(1, "opening .SYS file '%s' failed", sysfile);
325         fseek (fp, 0L, SEEK_END);
326         fsize = ftell (fp);
327         rewind (fp);
328         img = calloc(fsize, 1);
329         n = fread (img, fsize, 1, fp);
330         if (n == 0)
331                 err(1, "reading .SYS file '%s' failed", sysfile);
332
333         fclose(fp);
334
335         if (insert_padding(&img, &fsize)) {
336                 fprintf(stderr, "section relocation failed\n");
337                 exit(1);
338         }
339
340         if (outfile == NULL || strcmp(outfile, "-") == 0)
341                 outfp = stdout;
342         else {
343                 outfp = fopen(outfile, "w");
344                 if (outfp == NULL)
345                         err(1, "opening output file '%s' failed", outfile);
346         }
347
348         fprintf(outfp, "\n/*\n");
349         fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
350             inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
351         fprintf(outfp, " */\n\n");
352
353         if (dname != NULL) {
354                 if (strlen(dname) > IFNAMSIZ)
355                         err(1, "selected device name '%s' is "
356                             "too long (max chars: %d)", dname, IFNAMSIZ);
357                 fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
358                 fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
359         }
360
361         if (inffile == NULL) {
362                 fprintf (outfp, "#ifdef NDIS_REGVALS\n");
363                 fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
364                 fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
365                 fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
366
367                 fprintf (outfp, "};\n\n");
368         } else {
369                 fp = fopen(inffile, "r");
370                 if (fp == NULL)
371                         err(1, "opening .INF file '%s' failed", inffile);
372
373
374                 inf_parse(fp, outfp);
375                 fclose(fp);
376         }
377
378         fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
379
380         if (bin) {
381                 sysfile = strdup(basename(sysfile));
382                 ptr = (unsigned char *)sysfile;
383                 while (*ptr) {
384                         if (*ptr == '.')
385                                 *ptr = '_';
386                         ptr++;
387                 }
388                 fprintf(outfp,
389                     "\nextern unsigned char ndis_%s_drv_data_start[];\n",
390                     sysfile);
391                 fprintf(outfp, "static unsigned char *drv_data = "
392                     "ndis_%s_drv_data_start;\n\n", sysfile);
393                 bincvt(sysfile, outfile, img, fsize);
394                 goto done;
395         }
396
397
398         fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
399
400         fprintf(outfp, "__asm__(\".data\");\n");
401         fprintf(outfp, "__asm__(\".globl  drv_data\");\n");
402         fprintf(outfp, "__asm__(\".type   drv_data, @object\");\n");
403         fprintf(outfp, "__asm__(\".size   drv_data, %d\");\n", fsize);
404         fprintf(outfp, "__asm__(\"drv_data:\");\n");
405
406         ptr = img;
407         cnt = 0;
408         while(cnt < fsize) {
409                 fprintf (outfp, "__asm__(\".byte ");
410                 for (i = 0; i < 10; i++) {
411                         cnt++;
412                         if (cnt == fsize) {
413                                 fprintf(outfp, "0x%.2X\");\n", ptr[i]);
414                                 goto done;
415                         } else {
416                                 if (i == 9)
417                                         fprintf(outfp, "0x%.2X\");\n", ptr[i]);
418                                 else
419                                         fprintf(outfp, "0x%.2X, ", ptr[i]);
420                         }
421                 }
422                 ptr += 10;
423         }
424
425 done:
426
427         fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
428
429         if (fp != NULL)
430                 fclose(fp);
431         fclose(outfp);
432         free(img);
433         exit(0);
434 }