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