ndiscvt.c revision 267654
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: releng/9.3/usr.sbin/ndiscvt/ndiscvt.c 243210 2012-11-18 06:21:45Z eadler $"); 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 54static int insert_padding(void **, int *); 55extern 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 94static int 95insert_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 155static void 156usage(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 165static void 166bincvt(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 218static void 219firmcvt(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 274int 275main(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 423done: 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} 433