ndiscvt.c revision 142075
1123475Swpaul/* 2123475Swpaul * Copyright (c) 2003 3123475Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4123475Swpaul * 5123475Swpaul * Redistribution and use in source and binary forms, with or without 6123475Swpaul * modification, are permitted provided that the following conditions 7123475Swpaul * are met: 8123475Swpaul * 1. Redistributions of source code must retain the above copyright 9123475Swpaul * notice, this list of conditions and the following disclaimer. 10123475Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11123475Swpaul * notice, this list of conditions and the following disclaimer in the 12123475Swpaul * documentation and/or other materials provided with the distribution. 13123475Swpaul * 3. All advertising materials mentioning features or use of this software 14123475Swpaul * must display the following acknowledgement: 15123475Swpaul * This product includes software developed by Bill Paul. 16123475Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17123475Swpaul * may be used to endorse or promote products derived from this software 18123475Swpaul * without specific prior written permission. 19123475Swpaul * 20123475Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21123475Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22123475Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23123475Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24123475Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25123475Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26123475Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27123475Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28123475Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29123475Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30123475Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31123475Swpaul */ 32123475Swpaul 33123475Swpaul#include <sys/cdefs.h> 34123475Swpaul__FBSDID("$FreeBSD: head/usr.sbin/ndiscvt/ndiscvt.c 142075 2005-02-19 07:37:01Z wpaul $"); 35123475Swpaul 36123475Swpaul#include <sys/types.h> 37123475Swpaul#include <sys/queue.h> 38124060Swpaul#include <sys/socket.h> 39124060Swpaul#include <net/if.h> 40123475Swpaul#include <stdlib.h> 41123475Swpaul#include <unistd.h> 42123475Swpaul#include <stdio.h> 43123475Swpaul#include <errno.h> 44123475Swpaul#include <string.h> 45132973Swpaul#include <libgen.h> 46123475Swpaul#include <err.h> 47132973Swpaul#include <ctype.h> 48123475Swpaul 49123475Swpaul#include <compat/ndis/pe_var.h> 50123475Swpaul 51123475Swpaul#include "inf.h" 52123475Swpaul 53123475Swpaulstatic int insert_padding(void **, int *); 54123475Swpaulextern const char *__progname; 55123475Swpaul 56123475Swpaul/* 57133026Swpaul * Sections within Windows PE files are defined using virtual 58133026Swpaul * and physical address offsets and virtual and physical sizes. 59133026Swpaul * The physical values define how the section data is stored in 60133026Swpaul * the executable file while the virtual values describe how the 61133026Swpaul * sections will look once loaded into memory. It happens that 62133026Swpaul * the linker in the Microsoft(r) DDK will tend to generate 63133026Swpaul * binaries where the virtual and physical values are identical, 64133026Swpaul * which means in most cases we can just transfer the file 65133026Swpaul * directly to memory without any fixups. This is not always 66133026Swpaul * the case though, so we have to be prepared to handle files 67133026Swpaul * where the in-memory section layout differs from the disk file 68133026Swpaul * section layout. 69123475Swpaul * 70133026Swpaul * There are two kinds of variations that can occur: the relative 71133026Swpaul * virtual address of the section might be different from the 72133026Swpaul * physical file offset, and the virtual section size might be 73133026Swpaul * different from the physical size (for example, the physical 74133026Swpaul * size of the .data section might be 1024 bytes, but the virtual 75133026Swpaul * size might be 1384 bytes, indicating that the data section should 76133026Swpaul * actually use up 1384 bytes in RAM and be padded with zeros). What we 77133026Swpaul * do is read the original file into memory and then make an in-memory 78133026Swpaul * copy with all of the sections relocated, re-sized and zero padded 79133026Swpaul * according to the virtual values specified in the section headers. 80133026Swpaul * We then emit the fixed up image file for use by the if_ndis driver. 81133026Swpaul * This way, we don't have to do the fixups inside the kernel. 82123475Swpaul */ 83123475Swpaul 84133026Swpaul#define ROUND_DOWN(n, align) (((uintptr_t)n) & ~((align) - 1l)) 85133026Swpaul#define ROUND_UP(n, align) ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \ 86133026Swpaul (align)) 87123475Swpaul 88123475Swpaul#define SET_HDRS(x) \ 89123475Swpaul dos_hdr = (image_dos_header *)x; \ 90123475Swpaul nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew); \ 91123475Swpaul sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + \ 92123475Swpaul sizeof(image_nt_header)); 93123475Swpaul 94123475Swpaulstatic 95123475Swpaulint insert_padding(imgbase, imglen) 96123475Swpaul void **imgbase; 97123475Swpaul int *imglen; 98123475Swpaul{ 99123475Swpaul image_section_header *sect_hdr; 100123475Swpaul image_dos_header *dos_hdr; 101123475Swpaul image_nt_header *nt_hdr; 102123475Swpaul image_optional_header opt_hdr; 103123475Swpaul int i = 0, sections, curlen = 0; 104133026Swpaul int offaccum = 0, oldraddr, oldrlen; 105123475Swpaul uint8_t *newimg, *tmp; 106123475Swpaul 107123475Swpaul newimg = malloc(*imglen); 108123475Swpaul 109123475Swpaul if (newimg == NULL) 110123475Swpaul return(ENOMEM); 111123475Swpaul 112123475Swpaul bcopy(*imgbase, newimg, *imglen); 113123475Swpaul curlen = *imglen; 114123475Swpaul 115123475Swpaul if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr)) 116123475Swpaul return(0); 117123475Swpaul 118123475Swpaul sections = pe_numsections((vm_offset_t)newimg); 119123475Swpaul 120123475Swpaul SET_HDRS(newimg); 121123475Swpaul 122123475Swpaul for (i = 0; i < sections; i++) { 123123475Swpaul oldraddr = sect_hdr->ish_rawdataaddr; 124123475Swpaul oldrlen = sect_hdr->ish_rawdatasize; 125133026Swpaul sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr; 126133026Swpaul offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr, 127133026Swpaul opt_hdr.ioh_filealign); 128133026Swpaul offaccum += 129133026Swpaul ROUND_UP(sect_hdr->ish_misc.ish_vsize, 130133026Swpaul opt_hdr.ioh_filealign) - 131133026Swpaul ROUND_UP(sect_hdr->ish_rawdatasize, 132133026Swpaul opt_hdr.ioh_filealign); 133133026Swpaul tmp = realloc(newimg, *imglen + offaccum); 134133026Swpaul if (tmp == NULL) { 135133026Swpaul free(newimg); 136133026Swpaul return(ENOMEM); 137123475Swpaul } 138133026Swpaul newimg = tmp; 139133026Swpaul SET_HDRS(newimg); 140133026Swpaul sect_hdr += i; 141123475Swpaul bzero(newimg + sect_hdr->ish_rawdataaddr, 142123475Swpaul ROUND_UP(sect_hdr->ish_misc.ish_vsize, 143123475Swpaul opt_hdr.ioh_filealign)); 144123475Swpaul bcopy((uint8_t *)(*imgbase) + oldraddr, 145123475Swpaul newimg + sect_hdr->ish_rawdataaddr, oldrlen); 146123475Swpaul sect_hdr++; 147123475Swpaul } 148123475Swpaul 149123475Swpaul free(*imgbase); 150123475Swpaul 151123475Swpaul *imgbase = newimg; 152123475Swpaul *imglen += offaccum; 153123475Swpaul 154123475Swpaul return(0); 155123475Swpaul} 156123475Swpaul 157123475Swpaulstatic void 158123475Swpaulusage(void) 159123475Swpaul{ 160132973Swpaul fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> " 161124089Sgreen "[-n devname] [-o outfile]\n", __progname); 162132973Swpaul fprintf(stderr, " %s -f <firmfile>\n", __progname); 163132973Swpaul 164123475Swpaul exit(1); 165123475Swpaul} 166123475Swpaul 167132973Swpaulstatic void 168132973Swpaulbincvt(char *sysfile, char *outfile, void *img, int fsize) 169132973Swpaul{ 170132973Swpaul char *ptr; 171132973Swpaul char tname[] = "/tmp/ndiscvt.XXXXXX"; 172132973Swpaul char sysbuf[1024]; 173132973Swpaul FILE *binfp; 174132973Swpaul 175132973Swpaul mkstemp(tname); 176132973Swpaul 177132973Swpaul binfp = fopen(tname, "a+"); 178132973Swpaul if (binfp == NULL) 179132973Swpaul err(1, "opening %s failed", tname); 180132973Swpaul 181132973Swpaul if (fwrite(img, fsize, 1, binfp) != 1) 182132973Swpaul err(1, "failed to output binary image"); 183132973Swpaul 184132973Swpaul fclose(binfp); 185132973Swpaul 186132973Swpaul outfile = strdup(basename(outfile)); 187132973Swpaul if (strchr(outfile, '.')) 188132973Swpaul *strchr(outfile, '.') = '\0'; 189132973Swpaul 190132973Swpaul snprintf(sysbuf, sizeof(sysbuf), 191142075Swpaul#ifdef __i386__ 192132973Swpaul "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", 193142075Swpaul#endif 194142075Swpaul#ifdef __amd64__ 195142075Swpaul "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n", 196142075Swpaul#endif 197132973Swpaul tname, outfile); 198132973Swpaul printf("%s", sysbuf); 199132973Swpaul system(sysbuf); 200132973Swpaul unlink(tname); 201132973Swpaul 202132973Swpaul ptr = tname; 203132973Swpaul while (*ptr) { 204132973Swpaul if (*ptr == '/' || *ptr == '.') 205132973Swpaul *ptr = '_'; 206132973Swpaul ptr++; 207132973Swpaul } 208132973Swpaul 209132973Swpaul snprintf(sysbuf, sizeof(sysbuf), 210132973Swpaul "objcopy --redefine-sym _binary_%s_start=%s_drv_data_start " 211132973Swpaul "--strip-symbol _binary_%s_size " 212132973Swpaul "--redefine-sym _binary_%s_end=%s_drv_data_end %s.o %s.o\n", 213132973Swpaul tname, sysfile, tname, tname, sysfile, outfile, outfile); 214132973Swpaul printf("%s", sysbuf); 215132973Swpaul system(sysbuf); 216132973Swpaul 217132973Swpaul return; 218132973Swpaul} 219132973Swpaul 220132973Swpaulstatic void 221132973Swpaulfirmcvt(char *firmfile) 222132973Swpaul{ 223132973Swpaul char *basefile, *outfile, *ptr; 224132973Swpaul char sysbuf[1024]; 225132973Swpaul 226142075Swpaul outfile = strdup(basename(firmfile)); 227132973Swpaul basefile = strdup(outfile); 228132973Swpaul 229132973Swpaul snprintf(sysbuf, sizeof(sysbuf), 230142075Swpaul#ifdef __i386__ 231132973Swpaul "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", 232142075Swpaul#endif 233142075Swpaul#ifdef __amd64__ 234142075Swpaul "objcopy -I binary -O elf64-x86-64 -B i386 %s %s.o\n", 235142075Swpaul#endif 236132973Swpaul firmfile, outfile); 237132973Swpaul printf("%s", sysbuf); 238132973Swpaul system(sysbuf); 239132973Swpaul 240132973Swpaul ptr = firmfile; 241132973Swpaul while (*ptr) { 242132973Swpaul if (*ptr == '/' || *ptr == '.') 243132973Swpaul *ptr = '_'; 244132973Swpaul ptr++; 245132973Swpaul } 246132973Swpaul ptr = basefile; 247132973Swpaul while (*ptr) { 248132973Swpaul if (*ptr == '/' || *ptr == '.') 249132973Swpaul *ptr = '_'; 250132973Swpaul else 251132973Swpaul *ptr = tolower(*ptr); 252132973Swpaul ptr++; 253132973Swpaul } 254132973Swpaul 255132973Swpaul snprintf(sysbuf, sizeof(sysbuf), 256132973Swpaul "objcopy --redefine-sym _binary_%s_start=%s_start " 257132973Swpaul "--strip-symbol _binary_%s_size " 258132973Swpaul "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n", 259132973Swpaul firmfile, basefile, firmfile, firmfile, 260132973Swpaul basefile, outfile, outfile); 261132973Swpaul ptr = sysbuf; 262132973Swpaul printf("%s", sysbuf); 263132973Swpaul system(sysbuf); 264132973Swpaul 265132973Swpaul snprintf(sysbuf, sizeof(sysbuf), 266132973Swpaul "ld -Bshareable -d -warn-common -o %s.ko %s.o\n", 267132973Swpaul outfile, outfile); 268132973Swpaul printf("%s", sysbuf); 269132973Swpaul system(sysbuf); 270132973Swpaul 271132973Swpaul free(basefile); 272132973Swpaul 273132973Swpaul exit(0); 274132973Swpaul} 275132973Swpaul 276123475Swpaulint 277123475Swpaulmain(int argc, char *argv[]) 278123475Swpaul{ 279132973Swpaul FILE *fp, *outfp; 280132973Swpaul int i, bin = 0; 281132973Swpaul void *img; 282132973Swpaul int n, fsize, cnt; 283132973Swpaul unsigned char *ptr; 284132973Swpaul char *inffile = NULL, *sysfile = NULL; 285132973Swpaul char *outfile = NULL, *firmfile = NULL; 286132973Swpaul char *dname = NULL; 287132973Swpaul int ch; 288123475Swpaul 289132973Swpaul while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) { 290123475Swpaul switch(ch) { 291132973Swpaul case 'f': 292132973Swpaul firmfile = optarg; 293132973Swpaul break; 294123475Swpaul case 'i': 295123475Swpaul inffile = optarg; 296123475Swpaul break; 297123475Swpaul case 's': 298123475Swpaul sysfile = optarg; 299123475Swpaul break; 300123475Swpaul case 'o': 301123475Swpaul outfile = optarg; 302123475Swpaul break; 303124060Swpaul case 'n': 304124060Swpaul dname = optarg; 305124060Swpaul break; 306132973Swpaul case 'O': 307132973Swpaul bin = 1; 308132973Swpaul break; 309123475Swpaul default: 310123475Swpaul usage(); 311123475Swpaul break; 312123475Swpaul } 313123475Swpaul } 314123475Swpaul 315132973Swpaul if (firmfile != NULL) 316132973Swpaul firmcvt(firmfile); 317132973Swpaul 318123475Swpaul if (sysfile == NULL) 319123475Swpaul usage(); 320123475Swpaul 321123475Swpaul /* Open the .SYS file and load it into memory */ 322123475Swpaul fp = fopen(sysfile, "r"); 323123475Swpaul if (fp == NULL) 324123475Swpaul err(1, "opening .SYS file '%s' failed", sysfile); 325123475Swpaul fseek (fp, 0L, SEEK_END); 326123475Swpaul fsize = ftell (fp); 327123475Swpaul rewind (fp); 328123475Swpaul img = calloc(fsize, 1); 329123475Swpaul n = fread (img, fsize, 1, fp); 330123475Swpaul 331123475Swpaul fclose(fp); 332123475Swpaul 333123475Swpaul if (insert_padding(&img, &fsize)) { 334123475Swpaul fprintf(stderr, "section relocation failed\n"); 335123475Swpaul exit(1); 336123475Swpaul } 337123475Swpaul 338123475Swpaul if (outfile == NULL || strcmp(outfile, "-") == 0) 339123475Swpaul outfp = stdout; 340123475Swpaul else { 341123475Swpaul outfp = fopen(outfile, "w"); 342123475Swpaul if (outfp == NULL) 343123475Swpaul err(1, "opening output file '%s' failed", outfile); 344123475Swpaul } 345123475Swpaul 346123475Swpaul fprintf(outfp, "\n/*\n"); 347123475Swpaul fprintf(outfp, " * Generated from %s and %s (%d bytes)\n", 348124060Swpaul inffile == NULL ? "<notused>" : inffile, sysfile, fsize); 349123475Swpaul fprintf(outfp, " */\n\n"); 350123475Swpaul 351124060Swpaul if (dname != NULL) { 352124060Swpaul if (strlen(dname) > IFNAMSIZ) 353124060Swpaul err(1, "selected device name '%s' is " 354124060Swpaul "too long (max chars: %d)", dname, IFNAMSIZ); 355124060Swpaul fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname); 356124085Swpaul fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname); 357124060Swpaul } 358124060Swpaul 359124060Swpaul if (inffile == NULL) { 360126706Swpaul fprintf (outfp, "#ifdef NDIS_REGVALS\n"); 361123475Swpaul fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n"); 362124060Swpaul fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n"); 363126706Swpaul fprintf (outfp, "#endif /* NDIS_REGVALS */\n"); 364123475Swpaul 365123475Swpaul fprintf (outfp, "};\n\n"); 366123475Swpaul } else { 367123475Swpaul fp = fopen(inffile, "r"); 368123475Swpaul if (fp == NULL) 369123475Swpaul err(1, "opening .INF file '%s' failed", inffile); 370123475Swpaul 371123475Swpaul 372123475Swpaul inf_parse(fp, outfp); 373123475Swpaul fclose(fp); 374123475Swpaul } 375123475Swpaul 376126706Swpaul fprintf(outfp, "\n#ifdef NDIS_IMAGE\n"); 377132973Swpaul 378132973Swpaul if (bin) { 379132973Swpaul sysfile = strdup(basename(sysfile)); 380132973Swpaul ptr = sysfile; 381132973Swpaul while (*ptr) { 382132973Swpaul if (*ptr == '.') 383132973Swpaul *ptr = '_'; 384132973Swpaul ptr++; 385132973Swpaul } 386132973Swpaul fprintf(outfp, 387132973Swpaul "\nextern unsigned char %s_drv_data_start[];\n", 388132973Swpaul sysfile); 389132973Swpaul fprintf(outfp, "static unsigned char *drv_data = " 390132973Swpaul "%s_drv_data_start;\n\n", sysfile); 391132973Swpaul bincvt(sysfile, outfile, img, fsize); 392132973Swpaul goto done; 393132973Swpaul } 394132973Swpaul 395132973Swpaul 396126706Swpaul fprintf(outfp, "\nextern unsigned char drv_data[];\n\n"); 397123475Swpaul 398123653Swpaul fprintf(outfp, "__asm__(\".data\");\n"); 399141524Swpaul fprintf(outfp, "__asm__(\".globl drv_data\");\n"); 400123653Swpaul fprintf(outfp, "__asm__(\".type drv_data, @object\");\n"); 401123653Swpaul fprintf(outfp, "__asm__(\".size drv_data, %d\");\n", fsize); 402123653Swpaul fprintf(outfp, "__asm__(\"drv_data:\");\n"); 403123653Swpaul 404123475Swpaul ptr = img; 405123475Swpaul cnt = 0; 406123475Swpaul while(cnt < fsize) { 407123653Swpaul fprintf (outfp, "__asm__(\".byte "); 408123653Swpaul for (i = 0; i < 10; i++) { 409123475Swpaul cnt++; 410123475Swpaul if (cnt == fsize) { 411123653Swpaul fprintf(outfp, "0x%.2X\");\n", ptr[i]); 412123475Swpaul goto done; 413123653Swpaul } else { 414123653Swpaul if (i == 9) 415123653Swpaul fprintf(outfp, "0x%.2X\");\n", ptr[i]); 416123653Swpaul else 417123653Swpaul fprintf(outfp, "0x%.2X, ", ptr[i]); 418123653Swpaul } 419123475Swpaul } 420123653Swpaul ptr += 10; 421123475Swpaul } 422123475Swpaul 423123475Swpauldone: 424123475Swpaul 425126706Swpaul fprintf(outfp, "#endif /* NDIS_IMAGE */\n"); 426132973Swpaul 427123475Swpaul if (fp != NULL) 428123475Swpaul fclose(fp); 429123475Swpaul fclose(outfp); 430123475Swpaul free(img); 431123475Swpaul exit(0); 432123475Swpaul} 433