ndiscvt.c revision 132973
181084Sjake/* 281084Sjake * Copyright (c) 2003 381084Sjake * Bill Paul <wpaul@windriver.com>. All rights reserved. 481084Sjake * 581084Sjake * Redistribution and use in source and binary forms, with or without 681084Sjake * modification, are permitted provided that the following conditions 781084Sjake * are met: 881084Sjake * 1. Redistributions of source code must retain the above copyright 981084Sjake * notice, this list of conditions and the following disclaimer. 10147272Smarius * 2. Redistributions in binary form must reproduce the above copyright 11147272Smarius * notice, this list of conditions and the following disclaimer in the 12147272Smarius * documentation and/or other materials provided with the distribution. 13147272Smarius * 3. All advertising materials mentioning features or use of this software 14147272Smarius * must display the following acknowledgement: 15163890Smarius * This product includes software developed by Bill Paul. 16163890Smarius * 4. Neither the name of the author nor the names of any co-contributors 17163890Smarius * may be used to endorse or promote products derived from this software 18163890Smarius * without specific prior written permission. 19163890Smarius * 20146419Smarius * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21146419Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22146419Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23146419Smarius * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24146419Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25171167Sgnn * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26171167Sgnn * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27147272Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28147272Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29147272Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30147272Smarius * THE POSSIBILITY OF SUCH DAMAGE. 31147272Smarius */ 32147272Smarius 33147272Smarius#include <sys/cdefs.h> 34152862Sru__FBSDID("$FreeBSD: head/usr.sbin/ndiscvt/ndiscvt.c 132973 2004-08-01 20:04:31Z wpaul $"); 35130294Sscottl 36119382Sjake#include <sys/types.h> 37119382Sjake#include <sys/queue.h> 38170840Smarius#include <sys/socket.h> 39146483Smarius#include <net/if.h> 40147191Sjkoshy#include <stdlib.h> 41188654Sthompsa#include <unistd.h> 42166144Smarius#include <stdio.h> 43155151Smarius#include <errno.h> 44166144Smarius#include <string.h> 45186347Snwhitehorn#include <libgen.h> 46133589Smarius#include <err.h> 47152683Smarius#include <ctype.h> 48186347Snwhitehorn 4990623Stmm#include <compat/ndis/pe_var.h> 5086148Stmm 51105399Stmm#include "inf.h" 52116584Sjake 53152686Smariusstatic int insert_padding(void **, int *); 54151805Sjoergextern const char *__progname; 55152862Sru 56152862Sru/* 57119382Sjake * Sections in object code files can be sparse. That is, the 58186681Sed * section may occupy more space in memory that it does when 59119382Sjake * stored in a disk file. In Windows PE files, each section header 60119816Smarcel * has a 'virtual size' and 'raw data size' field. The latter 61122470Sjake * specifies the amount of section data actually stored in the 6293122Stmm * disk file, and the former describes how much space the section 63124516Sdes * should actually occupy in memory. If the vsize is larger than 64124481Sdes * the rsize, we need to allocate some extra storage and fill 65124481Sdes * it with zeros. (Think BSS.) 66124481Sdes * 67189170Sed * The typical method of loading an executable file involves 68111072Sjake * reading each segment into memory using the vaddr/vsize from 69100399Speter * each section header. We try to make a small optimization however 70202006Smarius * and only pad/move segments when it's absolutely necessary, i.e. 71182057Smarius * if the vsize is larger than the rsize. This conserves a little 72111072Sjake * bit of memory, at the cost of having to fixup some of the values 7386235Stmm * in the section headers. 74136944Syongari */ 75152862Sru 76128758Smarius#define ROUND_UP(x, y) \ 77129051Smarius (((x) + (y)) - ((x) % (y))) 78129051Smarius 79129051Smarius#define SET_HDRS(x) \ 8086235Stmm dos_hdr = (image_dos_header *)x; \ 81183423Smarius nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew); \ 82146392Smarius sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + \ 8390623Stmm sizeof(image_nt_header)); 84146392Smarius 85176197Smariusstatic 8681084Sjakeint insert_padding(imgbase, imglen) 8786235Stmm void **imgbase; 8886235Stmm int *imglen; 89112399Sjake{ 9081084Sjake image_section_header *sect_hdr; 9190623Stmm image_dos_header *dos_hdr; 9290623Stmm image_nt_header *nt_hdr; 9390623Stmm image_optional_header opt_hdr; 9490623Stmm int i = 0, sections, curlen = 0; 9590623Stmm int offaccum = 0, diff, oldraddr, oldrlen; 96105531Stmm uint8_t *newimg, *tmp; 9781084Sjake 98183202Smarius newimg = malloc(*imglen); 99183202Smarius 100152862Sru if (newimg == NULL) 101152862Sru return(ENOMEM); 102131951Smarcel 10384202Sjake bcopy(*imgbase, newimg, *imglen); 10490623Stmm curlen = *imglen; 105183202Smarius 106183202Smarius if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr)) 10781390Sjake return(0); 10886235Stmm 109182918Smarius sections = pe_numsections((vm_offset_t)newimg); 110111684Sru 11181084Sjake SET_HDRS(newimg); 112132956Smarkm 113183202Smarius for (i = 0; i < sections; i++) { 114183202Smarius /* 115101070Sjake * If we have accumulated any padding offset, 11689053Sjake * add it to the raw data address of this segment. 11786235Stmm */ 11886235Stmm oldraddr = sect_hdr->ish_rawdataaddr; 11981084Sjake oldrlen = sect_hdr->ish_rawdatasize; 120100844Sjake if (offaccum) 121152862Sru sect_hdr->ish_rawdataaddr += offaccum; 12282914Sjake if (sect_hdr->ish_misc.ish_vsize > 123119382Sjake sect_hdr->ish_rawdatasize) { 124182918Smarius diff = ROUND_UP(sect_hdr->ish_misc.ish_vsize - 125112399Sjake sect_hdr->ish_rawdatasize, 126174195Srwatson opt_hdr.ioh_filealign); 127183202Smarius offaccum += ROUND_UP(diff - 128183202Smarius (sect_hdr->ish_misc.ish_vsize - 12981084Sjake sect_hdr->ish_rawdatasize), 130101070Sjake opt_hdr.ioh_filealign); 13181390Sjake sect_hdr->ish_rawdatasize = 13296998Sjake ROUND_UP(sect_hdr->ish_rawdatasize, 13381084Sjake opt_hdr.ioh_filealign); 13481084Sjake tmp = realloc(newimg, *imglen + offaccum); 135127297Salc if (tmp == NULL) { 136166060Smarius free(newimg); 13781084Sjake return(ENOMEM); 138 } 139 newimg = tmp; 140 SET_HDRS(newimg); 141 sect_hdr += i; 142 } 143 bzero(newimg + sect_hdr->ish_rawdataaddr, 144 ROUND_UP(sect_hdr->ish_misc.ish_vsize, 145 opt_hdr.ioh_filealign)); 146 bcopy((uint8_t *)(*imgbase) + oldraddr, 147 newimg + sect_hdr->ish_rawdataaddr, oldrlen); 148 sect_hdr++; 149 } 150 151 free(*imgbase); 152 153 *imgbase = newimg; 154 *imglen += offaccum; 155 156 return(0); 157} 158 159static void 160usage(void) 161{ 162 fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> " 163 "[-n devname] [-o outfile]\n", __progname); 164 fprintf(stderr, " %s -f <firmfile>\n", __progname); 165 166 exit(1); 167} 168 169static void 170bincvt(char *sysfile, char *outfile, void *img, int fsize) 171{ 172 char *ptr; 173 char tname[] = "/tmp/ndiscvt.XXXXXX"; 174 char sysbuf[1024]; 175 FILE *binfp; 176 177 mkstemp(tname); 178 179 binfp = fopen(tname, "a+"); 180 if (binfp == NULL) 181 err(1, "opening %s failed", tname); 182 183 if (fwrite(img, fsize, 1, binfp) != 1) 184 err(1, "failed to output binary image"); 185 186 fclose(binfp); 187 188 outfile = strdup(basename(outfile)); 189 if (strchr(outfile, '.')) 190 *strchr(outfile, '.') = '\0'; 191 192 snprintf(sysbuf, sizeof(sysbuf), 193 "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", 194 tname, outfile); 195 printf("%s", sysbuf); 196 system(sysbuf); 197 unlink(tname); 198 199 ptr = tname; 200 while (*ptr) { 201 if (*ptr == '/' || *ptr == '.') 202 *ptr = '_'; 203 ptr++; 204 } 205 206 snprintf(sysbuf, sizeof(sysbuf), 207 "objcopy --redefine-sym _binary_%s_start=%s_drv_data_start " 208 "--strip-symbol _binary_%s_size " 209 "--redefine-sym _binary_%s_end=%s_drv_data_end %s.o %s.o\n", 210 tname, sysfile, tname, tname, sysfile, outfile, outfile); 211 printf("%s", sysbuf); 212 system(sysbuf); 213 214 return; 215} 216 217static void 218firmcvt(char *firmfile) 219{ 220 char *basefile, *outfile, *ptr; 221 char sysbuf[1024]; 222 223 outfile = basename(firmfile); 224 basefile = strdup(outfile); 225 226 snprintf(sysbuf, sizeof(sysbuf), 227 "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", 228 firmfile, outfile); 229 printf("%s", sysbuf); 230 system(sysbuf); 231 232 ptr = firmfile; 233 while (*ptr) { 234 if (*ptr == '/' || *ptr == '.') 235 *ptr = '_'; 236 ptr++; 237 } 238 ptr = basefile; 239 while (*ptr) { 240 if (*ptr == '/' || *ptr == '.') 241 *ptr = '_'; 242 else 243 *ptr = tolower(*ptr); 244 ptr++; 245 } 246 247 snprintf(sysbuf, sizeof(sysbuf), 248 "objcopy --redefine-sym _binary_%s_start=%s_start " 249 "--strip-symbol _binary_%s_size " 250 "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n", 251 firmfile, basefile, firmfile, firmfile, 252 basefile, outfile, outfile); 253 ptr = sysbuf; 254 printf("%s", sysbuf); 255 system(sysbuf); 256 257 snprintf(sysbuf, sizeof(sysbuf), 258 "ld -Bshareable -d -warn-common -o %s.ko %s.o\n", 259 outfile, outfile); 260 printf("%s", sysbuf); 261 system(sysbuf); 262 263 free(basefile); 264 265 exit(0); 266} 267 268int 269main(int argc, char *argv[]) 270{ 271 FILE *fp, *outfp; 272 int i, bin = 0; 273 void *img; 274 int n, fsize, cnt; 275 unsigned char *ptr; 276 char *inffile = NULL, *sysfile = NULL; 277 char *outfile = NULL, *firmfile = NULL; 278 char *dname = NULL; 279 int ch; 280 281 while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) { 282 switch(ch) { 283 case 'f': 284 firmfile = optarg; 285 break; 286 case 'i': 287 inffile = optarg; 288 break; 289 case 's': 290 sysfile = optarg; 291 break; 292 case 'o': 293 outfile = optarg; 294 break; 295 case 'n': 296 dname = optarg; 297 break; 298 case 'O': 299 bin = 1; 300 break; 301 default: 302 usage(); 303 break; 304 } 305 } 306 307 if (firmfile != NULL) 308 firmcvt(firmfile); 309 310 if (sysfile == NULL) 311 usage(); 312 313 /* Open the .SYS file and load it into memory */ 314 fp = fopen(sysfile, "r"); 315 if (fp == NULL) 316 err(1, "opening .SYS file '%s' failed", sysfile); 317 fseek (fp, 0L, SEEK_END); 318 fsize = ftell (fp); 319 rewind (fp); 320 img = calloc(fsize, 1); 321 n = fread (img, fsize, 1, fp); 322 323 fclose(fp); 324 325 if (insert_padding(&img, &fsize)) { 326 fprintf(stderr, "section relocation failed\n"); 327 exit(1); 328 } 329 330 if (outfile == NULL || strcmp(outfile, "-") == 0) 331 outfp = stdout; 332 else { 333 outfp = fopen(outfile, "w"); 334 if (outfp == NULL) 335 err(1, "opening output file '%s' failed", outfile); 336 } 337 338 fprintf(outfp, "\n/*\n"); 339 fprintf(outfp, " * Generated from %s and %s (%d bytes)\n", 340 inffile == NULL ? "<notused>" : inffile, sysfile, fsize); 341 fprintf(outfp, " */\n\n"); 342 343 if (dname != NULL) { 344 if (strlen(dname) > IFNAMSIZ) 345 err(1, "selected device name '%s' is " 346 "too long (max chars: %d)", dname, IFNAMSIZ); 347 fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname); 348 fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname); 349 } 350 351 if (inffile == NULL) { 352 fprintf (outfp, "#ifdef NDIS_REGVALS\n"); 353 fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n"); 354 fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n"); 355 fprintf (outfp, "#endif /* NDIS_REGVALS */\n"); 356 357 fprintf (outfp, "};\n\n"); 358 } else { 359 fp = fopen(inffile, "r"); 360 if (fp == NULL) 361 err(1, "opening .INF file '%s' failed", inffile); 362 363 364 inf_parse(fp, outfp); 365 fclose(fp); 366 } 367 368 fprintf(outfp, "\n#ifdef NDIS_IMAGE\n"); 369 370 if (bin) { 371 sysfile = strdup(basename(sysfile)); 372 ptr = sysfile; 373 while (*ptr) { 374 if (*ptr == '.') 375 *ptr = '_'; 376 ptr++; 377 } 378 fprintf(outfp, 379 "\nextern unsigned char %s_drv_data_start[];\n", 380 sysfile); 381 fprintf(outfp, "static unsigned char *drv_data = " 382 "%s_drv_data_start;\n\n", sysfile); 383 bincvt(sysfile, outfile, img, fsize); 384 goto done; 385 } 386 387 388 fprintf(outfp, "\nextern unsigned char drv_data[];\n\n"); 389 390 fprintf(outfp, "__asm__(\".data\");\n"); 391 fprintf(outfp, "__asm__(\".type drv_data, @object\");\n"); 392 fprintf(outfp, "__asm__(\".size drv_data, %d\");\n", fsize); 393 fprintf(outfp, "__asm__(\"drv_data:\");\n"); 394 395 ptr = img; 396 cnt = 0; 397 while(cnt < fsize) { 398 fprintf (outfp, "__asm__(\".byte "); 399 for (i = 0; i < 10; i++) { 400 cnt++; 401 if (cnt == fsize) { 402 fprintf(outfp, "0x%.2X\");\n", ptr[i]); 403 goto done; 404 } else { 405 if (i == 9) 406 fprintf(outfp, "0x%.2X\");\n", ptr[i]); 407 else 408 fprintf(outfp, "0x%.2X, ", ptr[i]); 409 } 410 } 411 ptr += 10; 412 } 413 414done: 415 416 fprintf(outfp, "#endif /* NDIS_IMAGE */\n"); 417 418 if (fp != NULL) 419 fclose(fp); 420 fclose(outfp); 421 free(img); 422 exit(0); 423} 424