ndiscvt.c revision 201387
1227650Skevlo/* 2227650Skevlo * Copyright (c) 2003 3227650Skevlo * Bill Paul <wpaul@windriver.com>. All rights reserved. 4227650Skevlo * 5227650Skevlo * Redistribution and use in source and binary forms, with or without 6227650Skevlo * modification, are permitted provided that the following conditions 7227650Skevlo * are met: 8227650Skevlo * 1. Redistributions of source code must retain the above copyright 9227650Skevlo * notice, this list of conditions and the following disclaimer. 10227650Skevlo * 2. Redistributions in binary form must reproduce the above copyright 11227650Skevlo * notice, this list of conditions and the following disclaimer in the 12227650Skevlo * documentation and/or other materials provided with the distribution. 13227650Skevlo * 3. All advertising materials mentioning features or use of this software 14227650Skevlo * must display the following acknowledgement: 15227650Skevlo * This product includes software developed by Bill Paul. 16227650Skevlo * 4. Neither the name of the author nor the names of any co-contributors 17227650Skevlo * may be used to endorse or promote products derived from this software 18227650Skevlo * without specific prior written permission. 19227650Skevlo * 20227650Skevlo * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21227650Skevlo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22227650Skevlo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23227650Skevlo * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24227650Skevlo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25227650Skevlo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26227650Skevlo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27227650Skevlo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28227650Skevlo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29227650Skevlo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30227650Skevlo * THE POSSIBILITY OF SUCH DAMAGE. 31227650Skevlo */ 32227650Skevlo 33227650Skevlo#include <sys/cdefs.h> 34227650Skevlo__FBSDID("$FreeBSD: head/usr.sbin/ndiscvt/ndiscvt.c 201387 2010-01-02 11:05:34Z ed $"); 35227650Skevlo 36227650Skevlo#include <sys/types.h> 37227650Skevlo#include <sys/queue.h> 38227650Skevlo#include <sys/socket.h> 39227650Skevlo#include <net/if.h> 40227650Skevlo#include <stdlib.h> 41227650Skevlo#include <stddef.h> 42227650Skevlo#include <unistd.h> 43227650Skevlo#include <stdio.h> 44227650Skevlo#include <errno.h> 45227650Skevlo#include <string.h> 46227650Skevlo#include <libgen.h> 47227650Skevlo#include <err.h> 48227650Skevlo#include <ctype.h> 49227650Skevlo 50227650Skevlo#include <compat/ndis/pe_var.h> 51227650Skevlo 52227650Skevlo#include "inf.h" 53227650Skevlo 54227650Skevlostatic int insert_padding(void **, int *); 55227650Skevloextern const char *__progname; 56227650Skevlo 57227650Skevlo/* 58227650Skevlo * Sections within Windows PE files are defined using virtual 59227650Skevlo * and physical address offsets and virtual and physical sizes. 60227650Skevlo * The physical values define how the section data is stored in 61227650Skevlo * the executable file while the virtual values describe how the 62227650Skevlo * sections will look once loaded into memory. It happens that 63227650Skevlo * the linker in the Microsoft(r) DDK will tend to generate 64227650Skevlo * binaries where the virtual and physical values are identical, 65227650Skevlo * which means in most cases we can just transfer the file 66227650Skevlo * directly to memory without any fixups. This is not always 67227650Skevlo * the case though, so we have to be prepared to handle files 68227650Skevlo * where the in-memory section layout differs from the disk file 69227650Skevlo * section layout. 70227650Skevlo * 71227650Skevlo * There are two kinds of variations that can occur: the relative 72227650Skevlo * virtual address of the section might be different from the 73227650Skevlo * physical file offset, and the virtual section size might be 74227650Skevlo * different from the physical size (for example, the physical 75227650Skevlo * size of the .data section might be 1024 bytes, but the virtual 76227650Skevlo * size might be 1384 bytes, indicating that the data section should 77227650Skevlo * actually use up 1384 bytes in RAM and be padded with zeros). What we 78227650Skevlo * do is read the original file into memory and then make an in-memory 79227650Skevlo * copy with all of the sections relocated, re-sized and zero padded 80227650Skevlo * according to the virtual values specified in the section headers. 81227650Skevlo * We then emit the fixed up image file for use by the if_ndis driver. 82227650Skevlo * This way, we don't have to do the fixups inside the kernel. 83227650Skevlo */ 84227650Skevlo 85227650Skevlo#define ROUND_DOWN(n, align) (((uintptr_t)n) & ~((align) - 1l)) 86227650Skevlo#define ROUND_UP(n, align) ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \ 87227650Skevlo (align)) 88227650Skevlo 89227650Skevlo#define SET_HDRS(x) \ 90227650Skevlo dos_hdr = (image_dos_header *)x; \ 91227650Skevlo nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew); \ 92227650Skevlo sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); 93227650Skevlo 94227650Skevlostatic int 95227650Skevloinsert_padding(void **imgbase, int *imglen) 96227650Skevlo{ 97227650Skevlo image_section_header *sect_hdr; 98227650Skevlo image_dos_header *dos_hdr; 99227650Skevlo image_nt_header *nt_hdr; 100227650Skevlo image_optional_header opt_hdr; 101227650Skevlo int i = 0, sections, curlen = 0; 102227650Skevlo int offaccum = 0, oldraddr, oldrlen; 103227650Skevlo uint8_t *newimg, *tmp; 104227650Skevlo 105235713Skevlo newimg = malloc(*imglen); 106227650Skevlo 107235713Skevlo if (newimg == NULL) 108227650Skevlo return(ENOMEM); 109227650Skevlo 110235713Skevlo bcopy(*imgbase, newimg, *imglen); 111227650Skevlo curlen = *imglen; 112227650Skevlo 113227650Skevlo if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr)) 114227650Skevlo return(0); 115227650Skevlo 116227650Skevlo sections = pe_numsections((vm_offset_t)newimg); 117227650Skevlo 118227650Skevlo SET_HDRS(newimg); 119227650Skevlo 120227650Skevlo for (i = 0; i < sections; i++) { 121227650Skevlo oldraddr = sect_hdr->ish_rawdataaddr; 122227650Skevlo oldrlen = sect_hdr->ish_rawdatasize; 123227650Skevlo sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr; 124227650Skevlo offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr, 125227650Skevlo opt_hdr.ioh_filealign); 126227650Skevlo offaccum += 127227650Skevlo ROUND_UP(sect_hdr->ish_misc.ish_vsize, 128227650Skevlo opt_hdr.ioh_filealign) - 129227650Skevlo ROUND_UP(sect_hdr->ish_rawdatasize, 130227650Skevlo opt_hdr.ioh_filealign); 131227650Skevlo tmp = realloc(newimg, *imglen + offaccum); 132227650Skevlo if (tmp == NULL) { 133227650Skevlo free(newimg); 134227650Skevlo return(ENOMEM); 135227650Skevlo } 136227650Skevlo newimg = tmp; 137227650Skevlo SET_HDRS(newimg); 138227650Skevlo sect_hdr += i; 139227650Skevlo bzero(newimg + sect_hdr->ish_rawdataaddr, 140227650Skevlo ROUND_UP(sect_hdr->ish_misc.ish_vsize, 141227650Skevlo opt_hdr.ioh_filealign)); 142227650Skevlo bcopy((uint8_t *)(*imgbase) + oldraddr, 143227650Skevlo newimg + sect_hdr->ish_rawdataaddr, oldrlen); 144227650Skevlo sect_hdr++; 145227650Skevlo } 146227650Skevlo 147227650Skevlo free(*imgbase); 148227650Skevlo 149227650Skevlo *imgbase = newimg; 150227650Skevlo *imglen += offaccum; 151227650Skevlo 152227650Skevlo return(0); 153227650Skevlo} 154227650Skevlo 155227650Skevlostatic void 156227650Skevlousage(void) 157227650Skevlo{ 158227650Skevlo fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> " 159227650Skevlo "[-n devname] [-o outfile]\n", __progname); 160227650Skevlo fprintf(stderr, " %s -f <firmfile>\n", __progname); 161227650Skevlo 162227650Skevlo exit(1); 163227650Skevlo} 164227650Skevlo 165227650Skevlostatic void 166227650Skevlobincvt(char *sysfile, char *outfile, void *img, int fsize) 167227650Skevlo{ 168227650Skevlo char *ptr; 169227650Skevlo char tname[] = "/tmp/ndiscvt.XXXXXX"; 170227650Skevlo char sysbuf[1024]; 171227650Skevlo FILE *binfp; 172227650Skevlo 173227650Skevlo mkstemp(tname); 174227650Skevlo 175227650Skevlo binfp = fopen(tname, "a+"); 176227650Skevlo if (binfp == NULL) 177227650Skevlo err(1, "opening %s failed", tname); 178227650Skevlo 179227650Skevlo if (fwrite(img, fsize, 1, binfp) != 1) 180227650Skevlo err(1, "failed to output binary image"); 181227650Skevlo 182227650Skevlo fclose(binfp); 183227650Skevlo 184227650Skevlo outfile = strdup(basename(outfile)); 185227650Skevlo if (strchr(outfile, '.')) 186227650Skevlo *strchr(outfile, '.') = '\0'; 187227650Skevlo 188227650Skevlo snprintf(sysbuf, sizeof(sysbuf), 189227650Skevlo#ifdef __i386__ 190227650Skevlo "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", 191227650Skevlo#endif 192227650Skevlo#ifdef __amd64__ 193227650Skevlo "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n", 194227650Skevlo#endif 195227650Skevlo tname, outfile); 196227650Skevlo printf("%s", sysbuf); 197227650Skevlo system(sysbuf); 198227650Skevlo unlink(tname); 199227650Skevlo 200227650Skevlo ptr = tname; 201227650Skevlo while (*ptr) { 202227650Skevlo if (*ptr == '/' || *ptr == '.') 203227650Skevlo *ptr = '_'; 204227650Skevlo ptr++; 205227650Skevlo } 206227650Skevlo 207227650Skevlo snprintf(sysbuf, sizeof(sysbuf), 208227650Skevlo "objcopy --redefine-sym _binary_%s_start=ndis_%s_drv_data_start " 209227650Skevlo "--strip-symbol _binary_%s_size " 210227650Skevlo "--redefine-sym _binary_%s_end=ndis_%s_drv_data_end %s.o %s.o\n", 211227650Skevlo tname, sysfile, tname, tname, sysfile, outfile, outfile); 212227650Skevlo printf("%s", sysbuf); 213227650Skevlo system(sysbuf); 214227650Skevlo 215227650Skevlo return; 216227650Skevlo} 217227650Skevlo 218227650Skevlostatic void 219227650Skevlofirmcvt(char *firmfile) 220227650Skevlo{ 221227650Skevlo char *basefile, *outfile, *ptr; 222227650Skevlo char sysbuf[1024]; 223227650Skevlo 224227650Skevlo outfile = strdup(basename(firmfile)); 225227650Skevlo basefile = strdup(outfile); 226227650Skevlo 227227650Skevlo snprintf(sysbuf, sizeof(sysbuf), 228227650Skevlo#ifdef __i386__ 229227650Skevlo "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", 230227650Skevlo#endif 231227650Skevlo#ifdef __amd64__ 232227650Skevlo "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n", 233227650Skevlo#endif 234227650Skevlo firmfile, outfile); 235227650Skevlo printf("%s", sysbuf); 236227650Skevlo system(sysbuf); 237227650Skevlo 238227650Skevlo ptr = firmfile; 239227650Skevlo while (*ptr) { 240227650Skevlo if (*ptr == '/' || *ptr == '.') 241227650Skevlo *ptr = '_'; 242227650Skevlo ptr++; 243227650Skevlo } 244227650Skevlo ptr = basefile; 245227650Skevlo while (*ptr) { 246227650Skevlo if (*ptr == '/' || *ptr == '.') 247227650Skevlo *ptr = '_'; 248227650Skevlo else 249227650Skevlo *ptr = tolower(*ptr); 250227650Skevlo ptr++; 251227650Skevlo } 252227650Skevlo 253227650Skevlo snprintf(sysbuf, sizeof(sysbuf), 254227650Skevlo "objcopy --redefine-sym _binary_%s_start=%s_start " 255227650Skevlo "--strip-symbol _binary_%s_size " 256227650Skevlo "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n", 257227650Skevlo firmfile, basefile, firmfile, firmfile, 258227650Skevlo basefile, outfile, outfile); 259227650Skevlo ptr = sysbuf; 260227650Skevlo printf("%s", sysbuf); 261227650Skevlo system(sysbuf); 262227650Skevlo 263227650Skevlo snprintf(sysbuf, sizeof(sysbuf), 264227650Skevlo "ld -Bshareable -d -warn-common -o %s.ko %s.o\n", 265227650Skevlo outfile, outfile); 266227650Skevlo printf("%s", sysbuf); 267227650Skevlo system(sysbuf); 268227650Skevlo 269227650Skevlo free(basefile); 270227650Skevlo 271227650Skevlo exit(0); 272227650Skevlo} 273227650Skevlo 274227650Skevloint 275227650Skevlomain(int argc, char *argv[]) 276227650Skevlo{ 277227650Skevlo FILE *fp, *outfp; 278227650Skevlo int i, bin = 0; 279227650Skevlo void *img; 280227650Skevlo int n, fsize, cnt; 281227650Skevlo unsigned char *ptr; 282227650Skevlo char *inffile = NULL, *sysfile = NULL; 283227650Skevlo char *outfile = NULL, *firmfile = NULL; 284227650Skevlo char *dname = NULL; 285227650Skevlo int ch; 286227650Skevlo 287227650Skevlo while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) { 288227650Skevlo switch(ch) { 289227650Skevlo case 'f': 290227650Skevlo firmfile = optarg; 291227650Skevlo break; 292227650Skevlo case 'i': 293227650Skevlo inffile = optarg; 294227650Skevlo break; 295227650Skevlo case 's': 296227650Skevlo sysfile = optarg; 297227650Skevlo break; 298227650Skevlo case 'o': 299227650Skevlo outfile = optarg; 300227650Skevlo break; 301227650Skevlo case 'n': 302227650Skevlo dname = optarg; 303227650Skevlo break; 304227650Skevlo case 'O': 305227650Skevlo bin = 1; 306227650Skevlo break; 307227650Skevlo default: 308227650Skevlo usage(); 309227650Skevlo break; 310227650Skevlo } 311227650Skevlo } 312227650Skevlo 313227650Skevlo if (firmfile != NULL) 314227650Skevlo firmcvt(firmfile); 315227650Skevlo 316227650Skevlo if (sysfile == NULL) 317227650Skevlo usage(); 318227650Skevlo 319227650Skevlo /* Open the .SYS file and load it into memory */ 320227650Skevlo fp = fopen(sysfile, "r"); 321227650Skevlo if (fp == NULL) 322227650Skevlo err(1, "opening .SYS file '%s' failed", sysfile); 323227650Skevlo fseek (fp, 0L, SEEK_END); 324227650Skevlo fsize = ftell (fp); 325227650Skevlo rewind (fp); 326227650Skevlo img = calloc(fsize, 1); 327227650Skevlo n = fread (img, fsize, 1, fp); 328227650Skevlo 329227650Skevlo fclose(fp); 330227650Skevlo 331227650Skevlo if (insert_padding(&img, &fsize)) { 332227650Skevlo fprintf(stderr, "section relocation failed\n"); 333227650Skevlo exit(1); 334227650Skevlo } 335227650Skevlo 336227650Skevlo if (outfile == NULL || strcmp(outfile, "-") == 0) 337227650Skevlo outfp = stdout; 338227650Skevlo else { 339227650Skevlo outfp = fopen(outfile, "w"); 340227650Skevlo if (outfp == NULL) 341227650Skevlo err(1, "opening output file '%s' failed", outfile); 342227650Skevlo } 343227650Skevlo 344227650Skevlo fprintf(outfp, "\n/*\n"); 345227650Skevlo fprintf(outfp, " * Generated from %s and %s (%d bytes)\n", 346227650Skevlo inffile == NULL ? "<notused>" : inffile, sysfile, fsize); 347227650Skevlo fprintf(outfp, " */\n\n"); 348227650Skevlo 349227650Skevlo if (dname != NULL) { 350227650Skevlo if (strlen(dname) > IFNAMSIZ) 351227650Skevlo err(1, "selected device name '%s' is " 352227650Skevlo "too long (max chars: %d)", dname, IFNAMSIZ); 353227650Skevlo fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname); 354227650Skevlo fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname); 355227650Skevlo } 356227650Skevlo 357227650Skevlo if (inffile == NULL) { 358227650Skevlo fprintf (outfp, "#ifdef NDIS_REGVALS\n"); 359227650Skevlo fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n"); 360227650Skevlo fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n"); 361227650Skevlo fprintf (outfp, "#endif /* NDIS_REGVALS */\n"); 362227650Skevlo 363227650Skevlo fprintf (outfp, "};\n\n"); 364227650Skevlo } else { 365227650Skevlo fp = fopen(inffile, "r"); 366227650Skevlo if (fp == NULL) 367227650Skevlo err(1, "opening .INF file '%s' failed", inffile); 368227650Skevlo 369227650Skevlo 370227650Skevlo inf_parse(fp, outfp); 371227650Skevlo fclose(fp); 372227650Skevlo } 373227650Skevlo 374227650Skevlo fprintf(outfp, "\n#ifdef NDIS_IMAGE\n"); 375227650Skevlo 376227650Skevlo if (bin) { 377227650Skevlo sysfile = strdup(basename(sysfile)); 378227650Skevlo ptr = (unsigned char *)sysfile; 379227650Skevlo while (*ptr) { 380227650Skevlo if (*ptr == '.') 381227650Skevlo *ptr = '_'; 382227650Skevlo ptr++; 383227650Skevlo } 384227650Skevlo fprintf(outfp, 385227650Skevlo "\nextern unsigned char ndis_%s_drv_data_start[];\n", 386227650Skevlo sysfile); 387227650Skevlo fprintf(outfp, "static unsigned char *drv_data = " 388227650Skevlo "ndis_%s_drv_data_start;\n\n", sysfile); 389227650Skevlo bincvt(sysfile, outfile, img, fsize); 390227650Skevlo goto done; 391227650Skevlo } 392227650Skevlo 393227650Skevlo 394227650Skevlo fprintf(outfp, "\nextern unsigned char drv_data[];\n\n"); 395227650Skevlo 396227650Skevlo fprintf(outfp, "__asm__(\".data\");\n"); 397227650Skevlo fprintf(outfp, "__asm__(\".globl drv_data\");\n"); 398227650Skevlo fprintf(outfp, "__asm__(\".type drv_data, @object\");\n"); 399227650Skevlo fprintf(outfp, "__asm__(\".size drv_data, %d\");\n", fsize); 400227650Skevlo fprintf(outfp, "__asm__(\"drv_data:\");\n"); 401227650Skevlo 402227650Skevlo ptr = img; 403227650Skevlo cnt = 0; 404227650Skevlo while(cnt < fsize) { 405227650Skevlo fprintf (outfp, "__asm__(\".byte "); 406227650Skevlo for (i = 0; i < 10; i++) { 407227650Skevlo cnt++; 408227650Skevlo if (cnt == fsize) { 409227650Skevlo fprintf(outfp, "0x%.2X\");\n", ptr[i]); 410227650Skevlo goto done; 411227650Skevlo } else { 412227650Skevlo if (i == 9) 413227650Skevlo fprintf(outfp, "0x%.2X\");\n", ptr[i]); 414227650Skevlo else 415227650Skevlo fprintf(outfp, "0x%.2X, ", ptr[i]); 416227650Skevlo } 417227650Skevlo } 418227650Skevlo ptr += 10; 419227650Skevlo } 420227650Skevlo 421227650Skevlodone: 422227650Skevlo 423227650Skevlo fprintf(outfp, "#endif /* NDIS_IMAGE */\n"); 424227650Skevlo 425227650Skevlo if (fp != NULL) 426227650Skevlo fclose(fp); 427227650Skevlo fclose(outfp); 428227650Skevlo free(img); 429227650Skevlo exit(0); 430227650Skevlo} 431227650Skevlo