Commit the ndiscvt(8) utility too. (Missed it in the last import.)

This commit is contained in:
Bill Paul 2003-12-11 22:38:14 +00:00
parent c854fc1092
commit d934c8b0de
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=123475
7 changed files with 1138 additions and 0 deletions

23
usr.sbin/ndiscvt/Makefile Normal file
View File

@ -0,0 +1,23 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../sys/dev/ndis
PROG= ndiscvt
SRCS= ndiscvt.c
SRCS+= subr_pe.c
SRCS+= inf.c inf-token.l inf-parse.y y.tab.h
MAN8= ndiscvt.8
WARNS= 4
DPADD= ${LIBL}
LDADD= -ll
YFLAGS+=-v
CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../sys
CLEANFILES= y.output
.include <bsd.prog.mk>

View File

@ -0,0 +1,83 @@
%{
/*
* $Id: inf-parse.y,v 1.3 2003/11/30 21:58:16 winter Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <stdio.h>
#include <sys/types.h>
#include <sys/queue.h>
#include "inf.h"
extern int yyparse (void);
extern int yylex (void);
extern void yyerror(const char *);
%}
%token EQUALS COMMA EOL
%token <str> SECTION
%token <str> STRING
%token <str> WORD
%union {
char *str;
}
%%
inf_file
: inf_list
|
;
inf_list
: inf
| inf_list inf
;
inf
: SECTION EOL
{ section_add($1); }
| WORD EQUALS assign EOL
{ assign_add($1); }
| WORD COMMA regkey EOL
{ regkey_add($1); }
| WORD EOL
{ define_add($1); }
| EOL
;
assign
: WORD
{ push_word($1); }
| STRING
{ push_word($1); }
| WORD COMMA assign
{ push_word($1); }
| STRING COMMA assign
{ push_word($1); }
| COMMA assign
{ push_word(NULL); }
| COMMA
{ push_word(NULL); }
|
;
regkey
: WORD
{ push_word($1); }
| STRING
{ push_word($1); }
| WORD COMMA regkey
{ push_word($1); }
| STRING COMMA regkey
{ push_word($1); }
| COMMA regkey
{ push_word(NULL); }
| COMMA
{ push_word(NULL); }
;
%%

View File

@ -0,0 +1,91 @@
%{
/*
* $Id: inf-token.l,v 1.2 2003/11/30 20:41:06 winter Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <regex.h>
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"
int lineno = 1;
#define YY_NO_UNPUT
int yylex(void);
void yyerror(const char *);
static void
update_lineno(const char *cp)
{
while (*cp)
if (*cp++ == '\n')
lineno++;
}
%}
%%
[ \t]+ ;
\n { lineno++; return EOL; }
\r ;
;.*$ ;
= { return EQUALS; }
, { return COMMA; }
\"(\\\"|[^"])*\" {
int len = strlen(yytext) - 2;
int blen = len + 1;
char *walker;
int i;
update_lineno(yytext);
yylval.str = (char *)malloc(blen);
if (yylval.str == NULL)
goto out;
walker = yylval.str;
for (i = 1; i <= len; i++) {
if (yytext[i] == '\\') {
switch (yytext[i + 1]) {
case '\n':
i += 2;
while(isspace(yytext[i]))
i++;
break;
case '\"':
i++;
break;
case '(':
i++;
break;
default:
break;
}
}
*walker++ = yytext[i];
}
*walker++ = '\0';
out:;
return STRING;
}
\[[a-zA-Z0-9%&\{\}\-\.\/_\\\*\ ]+\] {
int len = strlen(yytext);
yytext[len-1] = '\0';
yylval.str = strdup(yytext+1);
return SECTION;
}
[a-zA-Z0-9%&\{\}\-\.\/_\\\*]+ {
yylval.str = strdup(yytext);
return WORD;
}
%%
void
yyerror(const char *s)
{
errx(1, "line %d: %s%s %s.", lineno, yytext, yytext?":":"", s);
}

484
usr.sbin/ndiscvt/inf.c Normal file
View File

@ -0,0 +1,484 @@
/*
* $Id: inf.c,v 1.3 2003/11/30 21:58:16 winter Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/queue.h>
#include "inf.h"
extern FILE *yyin;
int yyparse (void);
const char *words[W_MAX]; /* More than we'll need. */
int idx;
static struct section_head sh;
static struct reg_head rh;
static struct assign_head ah;
static char *sstrdup (const char *);
static struct assign
*find_assign (const char *, const char *);
static struct section
*find_section (const char *);
static void dump_deviceids (void);
static void dump_pci_id (const char *);
static void dump_regvals (void);
static void dump_paramreg (const struct section *, const struct reg *);
static FILE *ofp;
int
inf_parse (FILE *fp, FILE *outfp)
{
TAILQ_INIT(&sh);
TAILQ_INIT(&rh);
TAILQ_INIT(&ah);
ofp = outfp;
yyin = fp;
yyparse();
dump_deviceids();
dump_regvals();
return (0);
}
void
section_add (const char *s)
{
struct section *sec;
sec = malloc(sizeof(struct section));
bzero(sec, sizeof(struct section));
sec->name = s;
TAILQ_INSERT_TAIL(&sh, sec, link);
return;
}
static struct assign *
find_assign (const char *s, const char *k)
{
struct assign *assign;
char newkey[256];
/* Deal with string section lookups. */
if (k != NULL && k[0] == '%') {
bzero(newkey, sizeof(newkey));
strncpy(newkey, k + 1, strlen(k) - 2);
k = newkey;
}
TAILQ_FOREACH(assign, &ah, link) {
if (strcasecmp(assign->section->name, s) == 0) {
if (k == NULL)
return(assign);
else
if (strcasecmp(assign->key, k) == 0)
return(assign);
}
}
return(NULL);
}
static const char *
stringcvt(const char *s)
{
struct assign *manf;
manf = find_assign("strings", s);
if (manf == NULL)
return(s);
return(manf->vals[0]);
}
struct section *
find_section (const char *s)
{
struct section *section;
TAILQ_FOREACH(section, &sh, link) {
if (strcasecmp(section->name, s) == 0)
return(section);
}
return(NULL);
}
static void
dump_pci_id(const char *s)
{
char *p;
char vidstr[7], didstr[7];
p = strcasestr(s, "VEN_");
if (p == NULL)
return;
p += 4;
strcpy(vidstr, "0x");
strncat(vidstr, p, 4);
p = strcasestr(s, "DEV_");
if (p == NULL)
return;
p += 4;
strcpy(didstr, "0x");
strncat(didstr, p, 4);
if (p == NULL)
return;
fprintf(ofp, "\t\\\n\t{ %s, %s,", vidstr, didstr);
return;
}
static void
dump_deviceids()
{
struct assign *manf, *dev;
struct section *sec;
struct assign *assign;
/* Find manufacturer name */
manf = find_assign("Manufacturer", NULL);
/* Find manufacturer section */
sec = find_section(manf->vals[0]);
/* Emit start of device table */
fprintf (ofp, "#define NDIS_DEV_TABLE");
/*
* Now run through all the device names listed
* in the manufacturer section and dump out the
* device descriptions and vendor/device IDs.
*/
TAILQ_FOREACH(assign, &ah, link) {
if (assign->section == sec) {
dev = find_assign("strings", assign->key);
/* Emit device IDs. */
if (strcasestr(assign->vals[1], "PCI") != NULL)
dump_pci_id(assign->vals[1]);
#ifdef notdef
else if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
dump_pcmcia_id(assign->vals[1]);
#endif
/* Emit device description */
fprintf (ofp, "\t\\\n\t\"%s\"", dev->vals[0]);
}
}
/* Emit end of table */
fprintf(ofp, " },\n\n");
}
static void
dump_addreg(const char *s)
{
struct section *sec;
struct reg *reg;
/* Find the addreg section */
sec = find_section(s);
/* Dump all the keys defined in it. */
TAILQ_FOREACH(reg, &rh, link) {
/*
* Keys with an empty subkey are very easy to parse,
* so just deal with them here. If a parameter key
* of the same name also exists, prefer that one and
* skip this one.
*/
if (reg->section == sec) {
if (reg->subkey == NULL) {
fprintf(ofp, "\n\t{ \"%s\",", reg->key);
fprintf(ofp,"\n\t\"%s \",", reg->key);
fprintf(ofp, "\n\t{ \"%s\" } },",
reg->value == NULL ? "" :
reg->value);
} else if (strcasestr(reg->subkey,
"Ndi\\params") != NULL &&
strcasecmp(reg->key, "ParamDesc") == 0)
dump_paramreg(sec, reg);
}
}
return;
}
static void
dump_enumreg(const struct section *s, const struct reg *r)
{
struct reg *reg;
char enumkey[256];
sprintf(enumkey, "%s\\enum", r->subkey);
TAILQ_FOREACH(reg, &rh, link) {
if (reg->section != s)
continue;
if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
continue;
fprintf(ofp, " [%s=%s]", reg->key, stringcvt(reg->value));
}
return;
}
static void
dump_editreg(const struct section *s, const struct reg *r)
{
struct reg *reg;
TAILQ_FOREACH(reg, &rh, link) {
if (reg->section != s)
continue;
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
continue;
if (strcasecmp(reg->key, "LimitText") == 0)
fprintf(ofp, " [maxchars=%s]", reg->value);
if (strcasecmp(reg->key, "Optional") == 0 &&
strcmp(reg->value, "1") == 0)
fprintf(ofp, " [optional]");
}
return;
}
/* Use this for int too */
static void
dump_dwordreg(const struct section *s, const struct reg *r)
{
struct reg *reg;
TAILQ_FOREACH(reg, &rh, link) {
if (reg->section != s)
continue;
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
continue;
if (strcasecmp(reg->key, "min") == 0)
fprintf(ofp, " [min=%s]", reg->value);
if (strcasecmp(reg->key, "max") == 0)
fprintf(ofp, " [max=%s]", reg->value);
}
return;
}
static void
dump_defaultinfo(const struct section *s, const struct reg *r)
{
struct reg *reg;
TAILQ_FOREACH(reg, &rh, link) {
if (reg->section != s)
continue;
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
continue;
if (strcasecmp(reg->key, "Default"))
continue;
fprintf(ofp, "\n\t{ \"%s\" } },", reg->value == NULL ? "" :
reg->value);
break;
}
return;
}
static void
dump_paramdesc(const struct section *s, const struct reg *r)
{
struct reg *reg;
TAILQ_FOREACH(reg, &rh, link) {
if (reg->section != s)
continue;
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
continue;
if (strcasecmp(reg->key, "ParamDesc"))
continue;
fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
break;
}
return;
}
static void
dump_typeinfo(const struct section *s, const struct reg *r)
{
struct reg *reg;
TAILQ_FOREACH(reg, &rh, link) {
if (reg->section != s)
continue;
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
continue;
if (strcasecmp(reg->key, "type"))
continue;
if (strcasecmp(reg->value, "dword") == 0 ||
strcasecmp(reg->value, "int") == 0)
dump_dwordreg(s, r);
if (strcasecmp(reg->value, "enum") == 0)
dump_enumreg(s, r);
if (strcasecmp(reg->value, "edit") == 0)
dump_editreg(s, r);
}
return;
}
static void
dump_paramreg(const struct section *s, const struct reg *r)
{
const char *keyname;
keyname = r->subkey + strlen("Ndi\\params\\");
fprintf(ofp, "\n\t{ \"%s\",", keyname);
dump_paramdesc(s, r);
dump_typeinfo(s, r);
fprintf(ofp, "\",");
dump_defaultinfo(s, r);
return;
}
static void
dump_regvals(void)
{
struct assign *manf, *dev, *dev_dup;
struct section *sec;
struct assign *assign;
struct assign_head tmp_ah;
char sname[256];
int i;
TAILQ_INIT(&tmp_ah);
/* Find manufacturer name */
manf = find_assign("Manufacturer", NULL);
/* Find manufacturer section */
sec = find_section(manf->vals[0]);
/* Emit start of block */
fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
TAILQ_FOREACH(assign, &ah, link) {
/* Avoid repeating the same section. */
i = 0;
TAILQ_FOREACH(dev_dup, &tmp_ah, link)
if (strcmp(dev_dup->vals[0], assign->vals[0]) == 0) {
i++;
break;
}
if (i)
continue;
dev_dup = malloc(sizeof(struct assign));
bcopy((char *)assign, (char *)dev_dup,
sizeof(struct assign));
TAILQ_INSERT_TAIL(&tmp_ah, dev_dup, link);
if (assign->section == sec) {
/* Ignore Windows 95-era data. */
sprintf(sname, "%s.NT", assign->vals[0]);
/* Find all the AddReg sections. */
dev = find_assign(sname, "AddReg");
for (i = 0; i < W_MAX; i++) {
if (dev->vals[i] != NULL)
dump_addreg(dev->vals[i]);
}
}
}
fprintf(ofp, "\n\t{ NULL, NULL, { 0 } }\n};\n\n");
return;
}
void
assign_add (const char *a)
{
struct assign *assign;
int i;
assign = malloc(sizeof(struct assign));
bzero(assign, sizeof(struct assign));
assign->section = TAILQ_LAST(&sh, section_head);
assign->key = sstrdup(a);
for (i = 0; i < idx; i++)
assign->vals[(idx - 1) - i] = sstrdup(words[i]);
TAILQ_INSERT_TAIL(&ah, assign, link);
clear_words();
return;
}
void
define_add (const char *d __unused)
{
#ifdef notdef
fprintf(stderr, "define \"%s\"\n", d);
#endif
return;
}
static char *
sstrdup(const char *str)
{
if (str != NULL && strlen(str))
return (strdup(str));
return (NULL);
}
static int
satoi (const char *nptr)
{
if (nptr != NULL && strlen(nptr))
return (atoi(nptr));
return (0);
}
void
regkey_add (const char *r)
{
struct reg *reg;
reg = malloc(sizeof(struct reg));
bzero(reg, sizeof(struct reg));
reg->section = TAILQ_LAST(&sh, section_head);
reg->root = sstrdup(r);
reg->subkey = sstrdup(words[3]);
reg->key = sstrdup(words[2]);
reg->flags = satoi(words[1]);
reg->value = sstrdup(words[0]);
TAILQ_INSERT_TAIL(&rh, reg, link);
free(__DECONST(char *, r));
clear_words();
return;
}
void
push_word (const char *w)
{
if (w && strlen(w))
words[idx++] = w;
else
words[idx++] = NULL;
return;
}
void
clear_words (void)
{
int i;
for (i = 0; i < idx; i++) {
if (words[i]) {
free(__DECONST(char *, words[i]));
}
}
idx = 0;
bzero(words, sizeof(words));
return;
}

61
usr.sbin/ndiscvt/inf.h Normal file
View File

@ -0,0 +1,61 @@
/*
* $Id: inf.h,v 1.3 2003/11/30 21:58:16 winter Exp $
*
* $FreeBSD$
*/
#define W_MAX 16
struct section {
const char * name;
TAILQ_ENTRY(section) link;
};
TAILQ_HEAD(section_head, section);
struct assign {
struct section *section;
const char * key;
const char * vals[W_MAX];
TAILQ_ENTRY(assign) link;
};
TAILQ_HEAD(assign_head, assign);
struct reg {
struct section *section;
const char * root;
const char * subkey;
const char * key;
u_int flags;
const char * value;
TAILQ_ENTRY(reg) link;
};
TAILQ_HEAD(reg_head, reg);
#define FLG_ADDREG_TYPE_SZ 0x00000000
#define FLG_ADDREG_BINVALUETYPE 0x00000001
#define FLG_ADDREG_NOCLOBBER 0x00000002
#define FLG_ADDREG_DELVAL 0x00000004
#define FLG_ADDREG_APPEND 0x00000008
#define FLG_ADDREG_KEYONLY 0x00000010
#define FLG_ADDREG_OVERWRITEONLY 0x00000020
#define FLG_ADDREG_64BITKEY 0x00001000
#define FLG_ADDREG_KEYONLY_COMMON 0x00002000
#define FLG_ADDREG_32BITKEY 0x00004000
#define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
#define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
#define FLG_ADDREG_TYPE_DWORD 0x00010001
#define FLG_ADDREG_TYPE_NONE 0x00020001
extern void section_add (const char *);
extern void assign_add (const char *);
extern void define_add (const char *);
extern void regkey_add (const char *);
extern void push_word (const char *);
extern void clear_words (void);
extern int inf_parse (FILE *, FILE *);

132
usr.sbin/ndiscvt/ndiscvt.8 Normal file
View File

@ -0,0 +1,132 @@
.\" Copyright (c) 2003
.\" Bill Paul <wpaul@windriver.com> All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by Bill Paul.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
.\" THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd December 10, 2003
.Dt NDISCVT 8
.Os
.Sh NAME
.Nm ndiscvt
.Nd Convert Windows(r) NDIS drivers for use with FreeBSD
.Sh SYNOPSIS
.Nm
.Op Fl i Ar <inffile>
.Fl s Ar <sysfile>
.Op Fl o Ar <outfile>
.Sh DESCRIPTION
The
.Nm
utility transforms a Windows(r) NDIS driver into a data file which
is used to build an
.Xr ndis 4
compatibility driver module. Windows(r) drivers consist of two main
parts: a .SYS file, which contains the actual driver executable code,
and a .INF file, which provides the Windows(r) installer with device
identifier information and a list of driver-specific registry keys.
The
.Nm
utility can convert these files into a header file that is compiled
intoe
.Pa if_ndis.c
to create an object code module that can be linked into
the
.Fx
kernel.
.Pp
The .INF file is typically required since only it contains device
identification data such as PCI vendor and device IDs or PCMCIA
indentifier strings. The .INF file may be optionally omitted however,
in which case the
.Nm
utility will only perform the conversion of the .SYS file. This is
useful for debugging purposes only.
.Pp
.Sh OPTIONS
The options are as follows:
.Bl -tag -width indent
.It Op Fl i Ar <inffile>
Open and parse the specified .INF file when performing conversion.
The
.Nm
utility will parse this file and emit a device identification
structure and registry key configuration structures which will be
used by the
.Xr ndis 4
driver and
.Xr ndisapi 9
kernel subsystem.
If this is omitted,
.Nm
will emit a dummy configuration structure only.
.It Fl s Ar <sysfile>
Open and parse the specified .SYS file. This file must contain
a Windows(r) driver image. The
.Nm
utility will perform some manipulation of the sections within the
executable file to make runtime linking within the kernel a little
easier and then convert the image into a data array.
.It Op Fl o Ar <outfile>
Specify the output file in which to place the resulting data. This
can be any file pathname. If
.Ar <outfile>
is a single dash, the data will be written to the standard output.
The
.Pa if_ndis.c
module expects to find the driver data in a file called
.Pa ndis_driver_data.h ,
so it is recommended that this name be used.
.El
.Sh SEE ALSO
.Xr ndis 4 ,
.Xr ndisapi 9
.Sh BUGS
Some Windows(r) drivers support multiple devices which each may
require sets of registry keys. The .INF file format allows all of
these devices to be supported in a single file. The
.Nm
utility will emit keys for all of the devices that it are specified
in a given file, even if this results in some duplicated entries.
.Sh HISTORY
The
.Nm
utility first appeared in
.Fx 5.3.
.Sh AUTHORS
The
.Nm
utility was written by
.An Bill Paul Aq wpaul@windriver.com .
The
.Xr lex 1
and
.Xr yacc 1
INF file parser was written by
.An Mathew Dodd Aq mdodd@freebsd.org .

264
usr.sbin/ndiscvt/ndiscvt.c Normal file
View File

@ -0,0 +1,264 @@
/*
* Copyright (c) 2003
* Bill Paul <wpaul@windriver.com>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/queue.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <err.h>
#include <compat/ndis/pe_var.h>
#include "inf.h"
static int insert_padding(void **, int *);
extern const char *__progname;
/*
* Sections in object code files can be sparse. That is, the
* section may occupy more space in memory that it does when
* stored in a disk file. In Windows PE files, each section header
* has a 'virtual size' and 'raw data size' field. The latter
* specifies the amount of section data actually stored in the
* disk file, and the former describes how much space the section
* should actually occupy in memory. If the vsize is larger than
* the rsize, we need to allocate some extra storage and fill
* it with zeros. (Think BSS.)
*
* The typical method of loading an executable file involves
* reading each segment into memory using the vaddr/vsize from
* each section header. We try to make a small optimization however
* and only pad/move segments when it's absolutely necessary, i.e.
* if the vsize is larger than the rsize. This conserves a little
* bit of memory, at the cost of having to fixup some of the values
* in the section headers.
*/
#define ROUND_UP(x, y) \
(((x) + (y)) - ((x) % (y)))
#define SET_HDRS(x) \
dos_hdr = (image_dos_header *)x; \
nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew); \
sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + \
sizeof(image_nt_header));
static
int insert_padding(imgbase, imglen)
void **imgbase;
int *imglen;
{
image_section_header *sect_hdr;
image_dos_header *dos_hdr;
image_nt_header *nt_hdr;
image_optional_header opt_hdr;
int i = 0, sections, curlen = 0;
int offaccum = 0, diff, oldraddr, oldrlen;
uint8_t *newimg, *tmp;
newimg = malloc(*imglen);
if (newimg == NULL)
return(ENOMEM);
bcopy(*imgbase, newimg, *imglen);
curlen = *imglen;
if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
return(0);
sections = pe_numsections((vm_offset_t)newimg);
SET_HDRS(newimg);
for (i = 0; i < sections; i++) {
/*
* If we have accumulated any padding offset,
* add it to the raw data address of this segment.
*/
oldraddr = sect_hdr->ish_rawdataaddr;
oldrlen = sect_hdr->ish_rawdatasize;
if (offaccum)
sect_hdr->ish_rawdataaddr += offaccum;
if (sect_hdr->ish_misc.ish_vsize >
sect_hdr->ish_rawdatasize) {
diff = ROUND_UP(sect_hdr->ish_misc.ish_vsize -
sect_hdr->ish_rawdatasize,
opt_hdr.ioh_filealign);
offaccum += ROUND_UP(diff -
(sect_hdr->ish_misc.ish_vsize -
sect_hdr->ish_rawdatasize),
opt_hdr.ioh_filealign);
sect_hdr->ish_rawdatasize =
ROUND_UP(sect_hdr->ish_rawdatasize,
opt_hdr.ioh_filealign);
tmp = realloc(newimg, *imglen + offaccum);
if (tmp == NULL) {
free(newimg);
return(ENOMEM);
}
newimg = tmp;
SET_HDRS(newimg);
sect_hdr += i;
}
bzero(newimg + sect_hdr->ish_rawdataaddr,
ROUND_UP(sect_hdr->ish_misc.ish_vsize,
opt_hdr.ioh_filealign));
bcopy((uint8_t *)(*imgbase) + oldraddr,
newimg + sect_hdr->ish_rawdataaddr, oldrlen);
sect_hdr++;
}
free(*imgbase);
*imgbase = newimg;
*imglen += offaccum;
return(0);
}
static void
usage(void)
{
fprintf(stderr, "Usage: %s [-i <inffile>] -s <sysfile> "
"[-o outfile]\n", __progname);
exit(1);
}
int
main(int argc, char *argv[])
{
FILE *fp, *outfp;
void *img;
int n, fsize, cnt;
unsigned char *ptr;
int i;
char *inffile = NULL, *sysfile = NULL, *outfile = NULL;
int ch;
while((ch = getopt(argc, argv, "i:s:o")) != -1) {
switch(ch) {
case 'i':
inffile = optarg;
break;
case 's':
sysfile = optarg;
break;
case 'o':
outfile = optarg;
break;
default:
usage();
break;
}
}
if (sysfile == NULL)
usage();
/* Open the .SYS file and load it into memory */
fp = fopen(sysfile, "r");
if (fp == NULL)
err(1, "opening .SYS file '%s' failed", sysfile);
fseek (fp, 0L, SEEK_END);
fsize = ftell (fp);
rewind (fp);
img = calloc(fsize, 1);
n = fread (img, fsize, 1, fp);
fclose(fp);
if (insert_padding(&img, &fsize)) {
fprintf(stderr, "section relocation failed\n");
exit(1);
}
if (outfile == NULL || strcmp(outfile, "-") == 0)
outfp = stdout;
else {
outfp = fopen(outfile, "w");
if (outfp == NULL)
err(1, "opening output file '%s' failed", outfile);
}
fprintf(outfp, "\n/*\n");
fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
inffile, sysfile, fsize);
fprintf(outfp, " */\n\n");
if (fp == NULL) {
fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
fprintf (outfp, "\t{ NULL, NULL, ndis_parm_int, { 0 } }\n");
fprintf (outfp, "};\n\n");
} else {
fp = fopen(inffile, "r");
if (fp == NULL)
err(1, "opening .INF file '%s' failed", inffile);
inf_parse(fp, outfp);
fclose(fp);
}
fprintf(outfp, "\n\nunsigned char drv_data[] = { \n");
ptr = img;
cnt = 0;
while(cnt < fsize) {
for (i = 0; i < 12; i++) {
cnt++;
if (cnt == fsize) {
fprintf(outfp, "0x%.2X\n", ptr[i]);
goto done;
} else
fprintf(outfp, "0x%.2X, ", ptr[i]);
}
fprintf(outfp, "\n");
ptr += 12;
}
done:
fprintf(outfp, "};\n");
if (fp != NULL)
fclose(fp);
fclose(outfp);
free(img);
exit(0);
}