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 56static int insert_padding(void **, int *); 57extern 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 96static int 97insert_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 157static void 158usage(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 167static void 168bincvt(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 free(outfile); 217 218 return; 219} 220 221static void 222firmcvt(char *firmfile) 223{ 224 char *basefile, *outfile, *ptr; 225 char sysbuf[1024]; 226 227 outfile = strdup(basename(firmfile)); 228 basefile = strdup(outfile); 229 230 snprintf(sysbuf, sizeof(sysbuf), 231#ifdef __i386__ 232 "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", 233#endif 234#ifdef __amd64__ 235 "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n", 236#endif 237 firmfile, outfile); 238 printf("%s", sysbuf); 239 system(sysbuf); 240 241 ptr = firmfile; 242 while (*ptr) { 243 if (*ptr == '/' || *ptr == '.') 244 *ptr = '_'; 245 ptr++; 246 } 247 ptr = basefile; 248 while (*ptr) { 249 if (*ptr == '/' || *ptr == '.') 250 *ptr = '_'; 251 else 252 *ptr = tolower(*ptr); 253 ptr++; 254 } 255 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); 262 ptr = sysbuf; 263 printf("%s", sysbuf); 264 system(sysbuf); 265 266 snprintf(sysbuf, sizeof(sysbuf), 267 "ld -Bshareable -d -warn-common -o %s.ko %s.o\n", 268 outfile, outfile); 269 printf("%s", sysbuf); 270 system(sysbuf); 271 272 free(basefile); 273 274 exit(0); 275} 276 277int 278main(int argc, char *argv[]) 279{ 280 FILE *fp, *outfp; 281 int i, bin = 0; 282 void *img; 283 int n, fsize, cnt; 284 unsigned char *ptr; 285 char *inffile = NULL, *sysfile = NULL; 286 char *outfile = NULL, *firmfile = NULL; 287 char *dname = NULL; 288 int ch; 289 290 while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) { 291 switch(ch) { 292 case 'f': 293 firmfile = optarg; 294 break; 295 case 'i': 296 inffile = optarg; 297 break; 298 case 's': 299 sysfile = optarg; 300 break; 301 case 'o': 302 outfile = optarg; 303 break; 304 case 'n': 305 dname = optarg; 306 break; 307 case 'O': 308 bin = 1; 309 break; 310 default: 311 usage(); 312 break; 313 } 314 } 315 316 if (firmfile != NULL) 317 firmcvt(firmfile); 318 319 if (sysfile == NULL) 320 usage(); 321 322 /* Open the .SYS file and load it into memory */ 323 fp = fopen(sysfile, "r"); 324 if (fp == NULL) 325 err(1, "opening .SYS file '%s' failed", sysfile); 326 fseek (fp, 0L, SEEK_END); 327 fsize = ftell (fp); 328 rewind (fp); 329 img = calloc(fsize, 1); 330 n = fread (img, fsize, 1, fp); 331 if (n == 0) 332 err(1, "reading .SYS file '%s' failed", sysfile); 333 334 fclose(fp); 335 336 if (insert_padding(&img, &fsize)) { 337 fprintf(stderr, "section relocation failed\n"); 338 exit(1); 339 } 340 341 if (outfile == NULL || strcmp(outfile, "-") == 0) 342 outfp = stdout; 343 else { 344 outfp = fopen(outfile, "w"); 345 if (outfp == NULL) 346 err(1, "opening output file '%s' failed", outfile); 347 } 348 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"); 353 354 if (dname != NULL) { 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); 360 } 361 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"); 367 368 fprintf (outfp, "};\n\n"); 369 } else { 370 fp = fopen(inffile, "r"); 371 if (fp == NULL) 372 err(1, "opening .INF file '%s' failed", inffile); 373 374 375 if (inf_parse(fp, outfp) != 0) 376 errx(1, "creating .INF file - no entries created, are you using the correct files?"); 377 fclose(fp); 378 } 379 380 fprintf(outfp, "\n#ifdef NDIS_IMAGE\n"); 381 382 if (bin) { 383 sysfile = strdup(basename(sysfile)); 384 ptr = (unsigned char *)sysfile; 385 while (*ptr) { 386 if (*ptr == '.') 387 *ptr = '_'; 388 ptr++; 389 } 390 fprintf(outfp, 391 "\nextern unsigned char ndis_%s_drv_data_start[];\n", 392 sysfile); 393 fprintf(outfp, "static unsigned char *drv_data = " 394 "ndis_%s_drv_data_start;\n\n", sysfile); 395 bincvt(sysfile, outfile, img, fsize); 396 goto done; 397 } 398 399 400 fprintf(outfp, "\nextern unsigned char drv_data[];\n\n"); 401 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"); 407 408 ptr = img; 409 cnt = 0; 410 while(cnt < fsize) { 411 fprintf (outfp, "__asm__(\".byte "); 412 for (i = 0; i < 10; i++) { 413 cnt++; 414 if (cnt == fsize) { 415 fprintf(outfp, "0x%.2X\");\n", ptr[i]); 416 goto done; 417 } else { 418 if (i == 9) 419 fprintf(outfp, "0x%.2X\");\n", ptr[i]); 420 else 421 fprintf(outfp, "0x%.2X, ", ptr[i]); 422 } 423 } 424 ptr += 10; 425 } 426 427done: 428 429 fprintf(outfp, "#endif /* NDIS_IMAGE */\n"); 430 431 if (fp != NULL) 432 fclose(fp); 433 fclose(outfp); 434 free(img); 435 exit(0); 436} 437