2 * SPDX-License-Identifier: BSD-4-Clause
5 * Bill Paul <wpaul@windriver.com>. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/types.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
52 #include <compat/ndis/pe_var.h>
56 static int insert_padding(void **, int *);
57 extern const char *__progname;
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
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.
87 #define ROUND_DOWN(n, align) (((uintptr_t)n) & ~((align) - 1l))
88 #define ROUND_UP(n, align) ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \
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);
97 insert_padding(void **imgbase, int *imglen)
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;
107 newimg = malloc(*imglen);
112 bcopy(*imgbase, newimg, *imglen);
115 if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
118 sections = pe_numsections((vm_offset_t)newimg);
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);
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);
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);
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);
168 bincvt(char *sysfile, char *outfile, void *img, int fsize)
171 char tname[] = "/tmp/ndiscvt.XXXXXX";
177 binfp = fopen(tname, "a+");
179 err(1, "opening %s failed", tname);
181 if (fwrite(img, fsize, 1, binfp) != 1)
182 err(1, "failed to output binary image");
186 outfile = strdup(basename(outfile));
187 if (strchr(outfile, '.'))
188 *strchr(outfile, '.') = '\0';
190 snprintf(sysbuf, sizeof(sysbuf),
192 "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
195 "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n",
198 printf("%s", sysbuf);
204 if (*ptr == '/' || *ptr == '.')
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);
222 firmcvt(char *firmfile)
224 char *basefile, *outfile, *ptr;
227 outfile = strdup(basename(firmfile));
228 basefile = strdup(outfile);
230 snprintf(sysbuf, sizeof(sysbuf),
232 "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
235 "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n",
238 printf("%s", sysbuf);
243 if (*ptr == '/' || *ptr == '.')
249 if (*ptr == '/' || *ptr == '.')
252 *ptr = tolower(*ptr);
256 snprintf(sysbuf, sizeof(sysbuf),
257 "objcopy --redefine-sym _binary_%s_start=%s_start "
258 "--strip-symbol _binary_%s_size "
259 "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n",
260 firmfile, basefile, firmfile, firmfile,
261 basefile, outfile, outfile);
263 printf("%s", sysbuf);
266 snprintf(sysbuf, sizeof(sysbuf),
267 "ld -Bshareable -d -warn-common -o %s.ko %s.o\n",
269 printf("%s", sysbuf);
278 main(int argc, char *argv[])
285 char *inffile = NULL, *sysfile = NULL;
286 char *outfile = NULL, *firmfile = NULL;
290 while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) {
316 if (firmfile != NULL)
322 /* Open the .SYS file and load it into memory */
323 fp = fopen(sysfile, "r");
325 err(1, "opening .SYS file '%s' failed", sysfile);
326 fseek (fp, 0L, SEEK_END);
329 img = calloc(fsize, 1);
330 n = fread (img, fsize, 1, fp);
332 err(1, "reading .SYS file '%s' failed", sysfile);
336 if (insert_padding(&img, &fsize)) {
337 fprintf(stderr, "section relocation failed\n");
341 if (outfile == NULL || strcmp(outfile, "-") == 0)
344 outfp = fopen(outfile, "w");
346 err(1, "opening output file '%s' failed", outfile);
349 fprintf(outfp, "\n/*\n");
350 fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
351 inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
352 fprintf(outfp, " */\n\n");
355 if (strlen(dname) > IFNAMSIZ)
356 err(1, "selected device name '%s' is "
357 "too long (max chars: %d)", dname, IFNAMSIZ);
358 fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
359 fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
362 if (inffile == NULL) {
363 fprintf (outfp, "#ifdef NDIS_REGVALS\n");
364 fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
365 fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
366 fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
368 fprintf (outfp, "};\n\n");
370 fp = fopen(inffile, "r");
372 err(1, "opening .INF file '%s' failed", inffile);
375 if (inf_parse(fp, outfp) != 0)
376 errx(1, "creating .INF file - no entries created, are you using the correct files?");
380 fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
383 sysfile = strdup(basename(sysfile));
384 ptr = (unsigned char *)sysfile;
391 "\nextern unsigned char ndis_%s_drv_data_start[];\n",
393 fprintf(outfp, "static unsigned char *drv_data = "
394 "ndis_%s_drv_data_start;\n\n", sysfile);
395 bincvt(sysfile, outfile, img, fsize);
400 fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
402 fprintf(outfp, "__asm__(\".data\");\n");
403 fprintf(outfp, "__asm__(\".globl drv_data\");\n");
404 fprintf(outfp, "__asm__(\".type drv_data, @object\");\n");
405 fprintf(outfp, "__asm__(\".size drv_data, %d\");\n", fsize);
406 fprintf(outfp, "__asm__(\"drv_data:\");\n");
411 fprintf (outfp, "__asm__(\".byte ");
412 for (i = 0; i < 10; i++) {
415 fprintf(outfp, "0x%.2X\");\n", ptr[i]);
419 fprintf(outfp, "0x%.2X\");\n", ptr[i]);
421 fprintf(outfp, "0x%.2X, ", ptr[i]);
429 fprintf(outfp, "#endif /* NDIS_IMAGE */\n");