Release 0.0.2 wine-0.0.2
authorAlexandre Julliard <julliard@winehq.org>
Tue, 29 Jun 1993 16:33:12 +0000 (16:33 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 29 Jun 1993 16:33:12 +0000 (16:33 +0000)
WHAT'S NEW with version 0.0.2:

    - Again thanks to Eric Youngdale for some very useful comments.
    - The Windows startup code created by Micrsoft C 7.0 now runs
      to completion.
    - Added a new patch to the kernel to increase the usable size of
      the ldt to the full 32 entries currently allowed.
    - Imported name relocations are now supported.
    - Source code for my infamous test program is now included.
    - A handful of basic Windows functions are now emulated.  See
      "kernel.spec" for examples of how to use the build program.

WHAT'S NEW with version 0.0.1:

    - Eric Youngdale contributed countless improvements in memory
      efficiency, bug fixes, and relocation.
    - The build program has been completed.  It now lets you specify
      how the main DLL entry point should interface to your emulation
      library routines.  A brief description of how to build these
      specifications is included in the file "build-spec.txt".
    - The code to dispatch builtin DLL calls is complete, but untested.

32 files changed:
COPYRIGHT [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
build [new file with mode: 0755]
build-spec.txt [new file with mode: 0644]
build.c [new file with mode: 0644]
dlls.h [new file with mode: 0644]
dump.c [new file with mode: 0644]
gdi.spec [new file with mode: 0644]
heap.c [new file with mode: 0644]
if1632.S [new file with mode: 0644]
kernel.c [new file with mode: 0644]
kernel.spec [new file with mode: 0644]
ldt.c [new file with mode: 0644]
ldt.tar [new file with mode: 0644]
ldtlib.c [new file with mode: 0644]
neexe.h [new file with mode: 0644]
prototypes.h [new file with mode: 0644]
relay.c [new file with mode: 0644]
segmem.h [new file with mode: 0644]
selector.c [new file with mode: 0644]
test.exe [new file with mode: 0755]
unixlib.spec [new file with mode: 0644]
user.c [new file with mode: 0644]
user.spec [new file with mode: 0644]
wine [new file with mode: 0755]
wine.c [new file with mode: 0644]
winetest/main.c [new file with mode: 0755]
winetest/makefile [new file with mode: 0755]
winetest/winetest.def [new file with mode: 0755]
winetest/winetest.h [new file with mode: 0755]
winetest/winetest.rc [new file with mode: 0755]

diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..45db164
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,3 @@
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..54dff6d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+CFLAGS=-g
+
+######################################################################
+# FILES:
+#
+#      Be very careful if you change the order of the files listed
+# here.  if1632.o must linked first to guarrantee that it sits at a low
+# enough address.  I intend to change this requirement someday, but
+# for now live with it.
+#
+DLL_LENGTH=256
+
+BUILDOBJS=dll_kernel.o dll_user.o dll_gdi.o dll_unixlib.o \
+         dll_kernel_tab.o dll_user_tab.o dll_gdi_tab.o dll_unixlib_tab.o
+
+MUST_BE_LINKED_FIRST=if1632.o $(BUILDOBJS)
+
+OBJS=$(MUST_BE_LINKED_FIRST) \
+       dump.o heap.o ldt.o kernel.o relay.o selector.o user.o wine.o
+
+TARGET=wine
+LIBS=-lldt
+
+all: $(TARGET) libldt.a
+
+clean:
+       rm -f *.o *~ *.s dll_*
+
+$(TARGET): $(OBJS)
+       $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
+
+build: build.c
+       cc -g -o build build.c
+
+libldt.a: ldtlib.c
+       $(CC) -O6 -c ldtlib.c
+       ar rcs libldt.a ldtlib.o
+
+dll_kernel.S dll_kernel_tab.c: build kernel.spec
+       build kernel.spec
+
+dll_user.S dll_user_tab.c: build user.spec
+       build user.spec
+
+dll_gdi.S dll_gdi_tab.c: build gdi.spec
+       build gdi.spec
+
+dll_unixlib.S dll_unixlib_tab.c: build unixlib.spec
+       build unixlib.spec
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..09eb3de
--- /dev/null
+++ b/README
@@ -0,0 +1,73 @@
+Copyright  Robert J. Amstadt, 1993.  All code is provided without
+warranty.  It is my intent to cover this code with the Gnu Public
+License.
+
+So here goes release 0.0.2 of the Windows loader.  It will do some 
+relocations and then run the program.  The program test.exe is a 
+Windows executable.  Try the command "wine test.exe".
+
+WHAT'S NEW with version 0.0.2:
+
+    - Again thanks to Eric Youngdale for some very useful comments.
+    - The Windows startup code created by Micrsoft C 7.0 now runs 
+      to completion.
+    - Added a new patch to the kernel to increase the usable size of
+      the ldt to the full 32 entries currently allowed.
+    - Imported name relocations are now supported.
+    - Source code for my infamous test program is now included.
+    - A handful of basic Windows functions are now emulated.  See
+      "kernel.spec" for examples of how to use the build program.
+
+WHAT'S NEW with version 0.0.1:
+
+    - Eric Youngdale contributed countless improvements in memory
+      efficiency, bug fixes, and relocation.
+    - The build program has been completed.  It now lets you specify
+      how the main DLL entry point should interface to your emulation
+      library routines.  A brief description of how to build these
+      specifications is included in the file "build-spec.txt".
+    - The code to dispatch builtin DLL calls is complete, but untested.
+
+TODO:
+
+    - Segment fixup code completion.
+    - Make changes to the kernel to allow more than 32 LDT entries.
+    - Trap and handle DOS and DPMI calls.
+    - Windows emulation library (connect to Peter MacDonald's library).
+    - Set registers correctly when starting Windows program.
+    - Allowing loading of 16-bit DLLs for use with program.
+    - global memory allocation
+    - complete and improve local heap allocation
+
+INSTALLATION:
+
+    Uncompress and untar this archive into the directory of your
+choice.  The file "ldt.tar" contains a necessary kernel patch against
+Linux 0.99.10.  If you installed the "ldt.tar" from the first release
+of this package, then you MUST to replace it.  In the directory 
+/usr/src/linux (or whereever you keep your kernel sources), untar 
+this file it contains three files:
+
+       kernel/ldt.c
+               - This is source for a new system call.
+       
+       include/linux/ldt.h
+               - This contains structures defining the system call
+                 interface.
+
+       ldt.patch
+               - This is a patch that must be applied to the kernel.
+                 It updates two header files, and the kernel Makefile.
+
+BUILD:
+
+    The documentation for the build program is in the file build-spec.txt
+
+FINALE:
+
+Good luck,
+
+       If you successfully add anything, please send me a copy.
+
+Bob Amstadt
+bob@amscons.com
diff --git a/build b/build
new file mode 100755 (executable)
index 0000000..d47f542
Binary files /dev/null and b/build differ
diff --git a/build-spec.txt b/build-spec.txt
new file mode 100644 (file)
index 0000000..61937bf
--- /dev/null
@@ -0,0 +1,81 @@
+name   NAME
+id     ID_NUMBER
+length NUMBER_OF_ORDINALS
+
+ORDINAL VARTYPE EXPORTNAME (DATA [DATA [DATA [...]]])
+
+ORDINAL FUNCTYPE EXPORTNAME([ARGTYPE [ARGTYPE [...]]])
+                HANDLERNAME([ARGNUM [ARGNUM [...]]])
+
+ORDINAL equate EXPORTNAME DATA
+--------------------
+General:
+
+    "name", "id" and "length" fields are mandatory.  Specific ordinal 
+declarations are optional, but the default handler will print an
+error message.
+
+Variable ordinals:
+
+    This type defines data storage at the ordinal specified.  You may
+store items as bytes, 16-bit words, or 32-bit words.
+    "ORDINAL" is replaced by the ordinal number corresponding to the
+variable.  "VARTYPE" should be "byte", "word" or "long" for 8, 16, or
+32 bits respectively.  "EXPORTNAME" will be the name available for
+dynamic linking.  "DATA" can be a decimal number or a hex number preceeded
+by "0x".  The following example defines the variable "VariableA" at
+ordinal 2 and containing 4 bytes:
+
+       2 byte VariableA -1 0xff 0 0
+
+Function ordinals:
+
+    This type defines a function entry point.  The prototype defined
+by "EXPORTNAME ([ARGTYPE [ARGTYPE [...]]])" specifies the name available
+for dynamic linking and the format of the 16-bit stack.  By specifying
+"FUNCTYPE", the loader can automatically determine which order the
+parameters were pushed by the calling routine.  The prototype
+specified by "HANDLERNAME([ARGNUM [ARGNUM [...]]])"  specifies to
+the loader how to call the 32-bit library routine which will handle this
+call.  Note that specifying "ARGNUM" as 1 means the leftmost argument
+given to the function call, and not the first argument on the stack.
+For "pascal" functions, "ARGNUM" equal to 1 specifies the last
+argument on the stack.  If you do not specify any arguments to the
+handler function, then address of the 16-bit argument stack is
+passed to the handler function.
+    "ORDINAL" is replaced by the ordinal number corresponding to the
+function.  "FUNCTYPE" should be "c" or "pascal" ("pascal" may be
+shortened to "p").  "EXPORTNAME" will be the name available for
+dynamic linking.  "ARGTYPE" should be "byte", "word", "long", "ptr",
+"s_byte" (signed byte), "s_word" (signed word) or "s_long"
+(signed long).  "HANDLERNAME" is the name of the actual function
+that will process the request in 32-bit mode.  "ARGNUM" is the
+original argument number.  The first argument is numbered "1".
+
+    This first example defines an entry point for the CreateWindow()
+call (the ordinal 100 is just an example):
+
+       100 pascal CreateWindow(ptr ptr long s_word s_word s_word s_word
+                               word word word ptr)
+                  WIN_CreateWindow(1 2 3 4 5 6 7 8 9 10 11)
+
+   This second example defines an entry point for the GetFocus()
+call (the ordinal 100 is just an example):
+
+       100 pascal GetFocus() WIN_GetFocus()
+
+Equate ordinals:
+
+    This type defines an ordinal as an absolute value.
+"ORDINAL" is replaced by the ordinal number corresponding to the
+variable.  "EXPORTNAME" will be the name available for dynamic linking.  
+"DATA" can be a decimal number or a hex number preceeded by "0x".
+
+Return ordinals:
+
+    This type defines a function entry point whose handler should do
+nothing but return a value.
+    "ORDINAL" is replaced by the ordinal number corresponding to the
+variable.  ARGLENGTH is the number of bytes that need to be removed
+from the stack before returning to the caller.  RETVALUE is the
+return value which will be passed back to the caller.
diff --git a/build.c b/build.c
new file mode 100644 (file)
index 0000000..f7dd03d
--- /dev/null
+++ b/build.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define VARTYPE_BYTE   0
+#define VARTYPE_SIGNEDWORD     0
+#define VARTYPE_WORD   1
+#define VARTYPE_LONG   2
+#define VARTYPE_FARPTR 3
+
+#define FUNCTYPE_PASCAL        16
+#define FUNCTYPE_C     17
+#define FUNCTYPE_REG   19
+
+#define EQUATETYPE_ABS 18
+
+#define MAX_ORDINALS   1024
+
+typedef struct ordinal_definition_s
+{
+    int valid;
+    int type;
+    char export_name[80];
+    void *additional_data;
+} ORDDEF;
+
+typedef struct ordinal_variable_definition_s
+{
+    int n_values;
+    int *values;
+} ORDVARDEF;
+
+typedef struct ordinal_function_definition_s
+{
+    int n_args_16;
+    int arg_types_16[16];
+    int arg_16_offsets[16];
+    int arg_16_size;
+    char internal_name[80];
+    int n_args_32;
+    int arg_indices_32[16];
+} ORDFUNCDEF;
+
+ORDDEF OrdinalDefinitions[MAX_ORDINALS];
+
+char LowerDLLName[80];
+char UpperDLLName[80];
+int Limit;
+int DLLId;
+FILE *SpecFp;
+
+char *ParseBuffer = NULL;
+char *ParseNext;
+char ParseSaveChar;
+int Line;
+
+int IsNumberString(char *s)
+{
+    while (*s != '\0')
+       if (!isdigit(*s++))
+           return 0;
+
+    return 1;
+}
+
+char *strlower(char *s)
+{
+    char *p;
+    
+    for(p = s; *p != '\0'; p++)
+       *p = tolower(*p);
+
+    return s;
+}
+
+char *strupper(char *s)
+{
+    char *p;
+    
+    for(p = s; *p != '\0'; p++)
+       *p = toupper(*p);
+
+    return s;
+}
+
+int stricmp(char *s1, char *s2)
+{
+    if (strlen(s1) != strlen(s2))
+       return -1;
+    
+    while (*s1 != '\0')
+       if (*s1++ != *s2++)
+           return -1;
+    
+    return 0;
+}
+
+char *
+GetTokenInLine(void)
+{
+    char *p;
+    char *token;
+
+    if (ParseNext != ParseBuffer)
+    {
+       if (ParseSaveChar == '\0')
+           return NULL;
+       *ParseNext = ParseSaveChar;
+    }
+    
+    /*
+     * Remove initial white space.
+     */
+    for (p = ParseNext; isspace(*p); p++)
+       ;
+    
+    if (*p == '\0')
+       return NULL;
+    
+    /*
+     * Find end of token.
+     */
+    token = p++;
+    if (*token != '(' && *token != ')')
+       while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
+           p++;
+    
+    ParseSaveChar = *p;
+    ParseNext = p;
+    *p = '\0';
+
+    return token;
+}
+
+char *
+GetToken(void)
+{
+    char *token;
+
+    if (ParseBuffer == NULL)
+    {
+       ParseBuffer = malloc(512);
+       ParseNext = ParseBuffer;
+       Line++;
+       if (fgets(ParseBuffer, 511, SpecFp) == NULL)
+           return NULL;
+    }
+
+    while ((token = GetTokenInLine()) == NULL)
+    {
+       ParseNext = ParseBuffer;
+       Line++;
+       if (fgets(ParseBuffer, 511, SpecFp) == NULL)
+           return NULL;
+    }
+
+    return token;
+}
+
+int
+ParseVariable(int ordinal, int type)
+{
+    ORDDEF *odp;
+    ORDVARDEF *vdp;
+    char export_name[80];
+    char *token;
+    char *endptr;
+    int *value_array;
+    int n_values;
+    int value_array_size;
+    
+    strcpy(export_name, GetToken());
+
+    token = GetToken();
+    if (*token != '(')
+    {
+       fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
+       exit(1);
+    }
+
+    n_values = 0;
+    value_array_size = 25;
+    value_array = malloc(sizeof(*value_array) * value_array_size);
+    
+    while ((token = GetToken()) != NULL)
+    {
+       if (*token == ')')
+           break;
+
+       value_array[n_values++] = strtol(token, &endptr, 0);
+       if (n_values == value_array_size)
+       {
+           value_array_size += 25;
+           value_array = realloc(value_array, 
+                                 sizeof(*value_array) * value_array_size);
+       }
+       
+       if (endptr == NULL || *endptr != '\0')
+       {
+           fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
+                   token);
+           exit(1);
+       }
+    }
+    
+    if (token == NULL)
+    {
+       fprintf(stderr, "%d: End of file in variable declaration\n", Line);
+       exit(1);
+    }
+
+    if (ordinal >= MAX_ORDINALS)
+    {
+       fprintf(stderr, "%d: Ordinal number too large\n", Line);
+       exit(1);
+    }
+    
+    odp = &OrdinalDefinitions[ordinal];
+    odp->valid = 1;
+    odp->type = type;
+    strcpy(odp->export_name, export_name);
+    
+    vdp = malloc(sizeof(*vdp));
+    odp->additional_data = vdp;
+    
+    vdp->n_values = n_values;
+    vdp->values = realloc(value_array, sizeof(*value_array) * n_values);
+
+    return 0;
+}
+
+int
+ParseExportFunction(int ordinal, int type)
+{
+    char *token;
+    ORDDEF *odp;
+    ORDFUNCDEF *fdp;
+    int arg_types[16];
+    int i;
+    int arg_num;
+    int current_offset;
+    int arg_size;
+       
+    
+    if (ordinal >= MAX_ORDINALS)
+    {
+       fprintf(stderr, "%d: Ordinal number too large\n", Line);
+       exit(1);
+    }
+    
+    odp = &OrdinalDefinitions[ordinal];
+    strcpy(odp->export_name, GetToken());
+    odp->valid = 1;
+    odp->type = type;
+    fdp = malloc(sizeof(*fdp));
+    odp->additional_data = fdp;
+
+    token = GetToken();
+    if (*token != '(')
+    {
+       fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
+       exit(1);
+    }
+
+    fdp->arg_16_size = 0;
+    for (i = 0; i < 16; i++)
+    {
+       token = GetToken();
+       if (*token == ')')
+           break;
+
+       if (stricmp(token, "byte") == 0 || stricmp(token, "word") == 0)
+       {
+           fdp->arg_types_16[i] = VARTYPE_WORD;
+           fdp->arg_16_size += 2;
+           fdp->arg_16_offsets[i] = 2;
+       }
+       else if (stricmp(token, "s_byte") == 0 || 
+                stricmp(token, "s_word") == 0)
+       {
+           fdp->arg_types_16[i] = VARTYPE_SIGNEDWORD;
+           fdp->arg_16_size += 2;
+           fdp->arg_16_offsets[i] = 2;
+       }
+       else if (stricmp(token, "long") == 0 || stricmp(token, "s_long") == 0)
+       {
+           fdp->arg_types_16[i] = VARTYPE_LONG;
+           fdp->arg_16_size += 4;
+           fdp->arg_16_offsets[i] = 4;
+       }
+       else if (stricmp(token, "ptr") == 0)
+       {
+           fdp->arg_types_16[i] = VARTYPE_FARPTR;
+           fdp->arg_16_size += 4;
+           fdp->arg_16_offsets[i] = 4;
+       }
+       else
+       {
+           fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
+           exit(1);
+       }
+    }
+    fdp->n_args_16 = i;
+
+    if (type == FUNCTYPE_PASCAL || type == FUNCTYPE_REG)
+    {
+       current_offset = 0;
+       for (i--; i >= 0; i--)
+       {
+           arg_size = fdp->arg_16_offsets[i];
+           fdp->arg_16_offsets[i] = current_offset;
+           current_offset += arg_size;
+       }
+    }
+    else
+    {
+       current_offset = 0;
+       for (i = 0; i < fdp->n_args_16; i++)
+       {
+           arg_size = fdp->arg_16_offsets[i];
+           fdp->arg_16_offsets[i] = current_offset;
+           current_offset += arg_size;
+       }
+    }
+
+    strcpy(fdp->internal_name, GetToken());
+    token = GetToken();
+    if (*token != '(')
+    {
+       fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
+       exit(1);
+    }
+    for (i = 0; i < 16; i++)
+    {
+       token = GetToken();
+       if (*token == ')')
+           break;
+
+       fdp->arg_indices_32[i] = atoi(token);
+       if (fdp->arg_indices_32[i] < 1 || 
+           fdp->arg_indices_32[i] > fdp->n_args_16)
+       {
+           fprintf(stderr, "%d: Bad argument index %d\n", Line,
+                   fdp->arg_indices_32[i]);
+           exit(1);
+       }
+    }
+    fdp->n_args_32 = i;
+
+    return 0;
+}
+
+int
+ParseEquate(int ordinal)
+{
+    ORDDEF *odp;
+    char *token;
+    char *endptr;
+    int value;
+    
+    if (ordinal >= MAX_ORDINALS)
+    {
+       fprintf(stderr, "%d: Ordinal number too large\n", Line);
+       exit(1);
+    }
+    
+    odp = &OrdinalDefinitions[ordinal];
+    strcpy(odp->export_name, GetToken());
+
+    token = GetToken();
+    value = strtol(token, &endptr, 0);
+    if (endptr == NULL || *endptr != '\0')
+    {
+       fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
+               token);
+       exit(1);
+    }
+
+    odp->valid = 1;
+    odp->type = EQUATETYPE_ABS;
+    odp->additional_data = (void *) value;
+
+    return 0;
+}
+
+int
+ParseOrdinal(int ordinal)
+{
+    char *token;
+    
+    token = GetToken();
+    if (token == NULL)
+    {
+       fprintf(stderr, "%d: Expected type after ordinal\n", Line);
+       exit(1);
+    }
+
+    if (stricmp(token, "byte") == 0)
+       return ParseVariable(ordinal, VARTYPE_BYTE);
+    else if (stricmp(token, "word") == 0)
+       return ParseVariable(ordinal, VARTYPE_WORD);
+    else if (stricmp(token, "long") == 0)
+       return ParseVariable(ordinal, VARTYPE_LONG);
+    else if (stricmp(token, "c") == 0)
+       return ParseExportFunction(ordinal, FUNCTYPE_C);
+    else if (stricmp(token, "p") == 0)
+       return ParseExportFunction(ordinal, FUNCTYPE_PASCAL);
+    else if (stricmp(token, "pascal") == 0)
+       return ParseExportFunction(ordinal, FUNCTYPE_PASCAL);
+    else if (stricmp(token, "register") == 0)
+       return ParseExportFunction(ordinal, FUNCTYPE_REG);
+    else if (stricmp(token, "equate") == 0)
+       return ParseEquate(ordinal);
+    else
+    {
+       fprintf(stderr, 
+               "%d: Expected type after ordinal, found '%s' instead\n",
+               Line, token);
+       exit(1);
+    }
+}
+
+int
+ParseTopLevel(void)
+{
+    char *token;
+    
+    while ((token = GetToken()) != NULL)
+    {
+       if (stricmp(token, "name") == 0)
+       {
+           strcpy(LowerDLLName, GetToken());
+           strlower(LowerDLLName);
+
+           strcpy(UpperDLLName, LowerDLLName);
+           strupper(UpperDLLName);
+       }
+       else if (stricmp(token, "id") == 0)
+       {
+           token = GetToken();
+           if (!IsNumberString(token))
+           {
+               fprintf(stderr, "%d: Expected number after id\n", Line);
+               exit(1);
+           }
+           
+           DLLId = atoi(token);
+       }
+       else if (stricmp(token, "length") == 0)
+       {
+           token = GetToken();
+           if (!IsNumberString(token))
+           {
+               fprintf(stderr, "%d: Expected number after length\n", Line);
+               exit(1);
+           }
+
+           Limit = atoi(token);
+       }
+       else if (IsNumberString(token))
+       {
+           int ordinal;
+           int rv;
+           
+           ordinal = atoi(token);
+           if ((rv = ParseOrdinal(ordinal)) < 0)
+               return rv;
+       }
+       else
+       {
+           fprintf(stderr, 
+                   "%d: Expected name, id, length or ordinal\n", Line);
+           exit(1);
+       }
+    }
+
+    return 0;
+}
+
+void
+OutputVariableCode(FILE *fp, char *storage, ORDDEF *odp)
+{
+    ORDVARDEF *vdp;
+    int i;
+
+    fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
+
+    vdp = odp->additional_data;
+    for (i = 0; i < vdp->n_values; i++)
+    {
+       if ((i & 7) == 0)
+           fprintf(fp, "\t%s\t", storage);
+           
+       fprintf(fp, "%d", vdp->values[i]);
+       
+       if ((i & 7) == 7 || i == vdp->n_values - 1)
+           fprintf(fp, "\n");
+       else
+           fprintf(fp, ", ");
+    }
+    fprintf(fp, "\n");
+}
+
+main(int argc, char **argv)
+{
+    ORDDEF *odp;
+    ORDFUNCDEF *fdp;
+    FILE *fp;
+    char filename[80];
+    char buffer[80];
+    char *p;
+    int i;
+    
+    if (argc < 2)
+    {
+       fprintf(stderr, "usage: build SPECNAME\n");
+       exit(1);
+    }
+
+    SpecFp = fopen(argv[1], "r");
+    if (SpecFp == NULL)
+    {
+       fprintf(stderr, "Could not open specification file, '%s'\n", argv[1]);
+       exit(1);
+    }
+
+    ParseTopLevel();
+
+    sprintf(filename, "dll_%s.S", LowerDLLName);
+    fp = fopen(filename, "w");
+
+    fprintf(fp, "\t.globl _%s_Dispatch\n", UpperDLLName);
+    fprintf(fp, "_%s_Dispatch:\n", UpperDLLName);
+    fprintf(fp, "\torl\t$0x%08x,%%eax\n", DLLId << 16);
+    fprintf(fp, "\tjmp\t_CallTo32\n\n");
+
+    odp = OrdinalDefinitions;
+    for (i = 0; i <= Limit; i++, odp++)
+    {
+       fprintf(fp, "\t.globl _%s_Ordinal_%d\n", UpperDLLName, i);
+
+       if (!odp->valid)
+       {
+           fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
+           fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
+           fprintf(fp, "\tpushw\t$0\n");
+           fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
+       }
+       else
+       {
+           fdp = odp->additional_data;
+           
+           switch (odp->type)
+           {
+             case EQUATETYPE_ABS:
+               fprintf(fp, "_%s_Ordinal_%d = %d\n\n", 
+                       UpperDLLName, i, (int) odp->additional_data);
+               break;
+
+             case VARTYPE_BYTE:
+               OutputVariableCode(fp, ".byte", odp);
+               break;
+
+             case VARTYPE_WORD:
+               OutputVariableCode(fp, ".word", odp);
+               break;
+
+             case VARTYPE_LONG:
+               OutputVariableCode(fp, ".long", odp);
+               break;
+
+             case FUNCTYPE_REG:
+               fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
+               fprintf(fp, "\tpushw\t%%ax\n");
+               fprintf(fp, "\tpushw\t%%cx\n");
+               fprintf(fp, "\tpushw\t%%dx\n");
+               fprintf(fp, "\tpushw\t%%bx\n");
+               fprintf(fp, "\tpushw\t%%sp\n");
+               fprintf(fp, "\tpushw\t%%bp\n");
+               fprintf(fp, "\tpushw\t%%si\n");
+               fprintf(fp, "\tpushw\t%%di\n");
+               fprintf(fp, "\tpushw\t%%ds\n");
+               fprintf(fp, "\tpushw\t%%es\n");
+               fprintf(fp, "\tmovl\t%%ebp,%%eax\n");
+               fprintf(fp, "\tmovw\t%%esp,%%ebp\n");
+               fprintf(fp, "\tpushl\t20(%%ebp)\n");
+               fprintf(fp, "\tmovl\t%%eax,%%ebp\n");
+               fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
+               fprintf(fp, "\tpushw\t$24\n");
+               fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
+               break;
+
+             case FUNCTYPE_PASCAL:
+               fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
+               fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
+               fprintf(fp, "\tpushw\t$%d\n", fdp->arg_16_size);
+               fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
+               break;
+               
+             case FUNCTYPE_C:
+             default:
+               fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
+               fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
+               fprintf(fp, "\tpushw\t$0\n");
+               fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
+               break;
+           }
+       }
+    }
+
+    fclose(fp);
+
+    sprintf(filename, "dll_%s_tab.c", LowerDLLName);
+    fp = fopen(filename, "w");
+
+    fprintf(fp, "#include <stdio.h>\n");
+    fprintf(fp, "#include <stdlib.h>\n");
+    fprintf(fp, "#include \042dlls.h\042\n\n");
+
+    for (i = 0; i <= Limit; i++)
+    {
+       fprintf(fp, "extern void %s_Ordinal_%d();\n", UpperDLLName, i);
+    }
+    
+    odp = OrdinalDefinitions;
+    for (i = 0; i <= Limit; i++, odp++)
+    {
+       if (odp->valid && 
+           (odp->type == FUNCTYPE_PASCAL || odp->type == FUNCTYPE_C ||
+            odp->type == FUNCTYPE_REG))
+       {
+           fdp = odp->additional_data;
+           fprintf(fp, "extern int %s();\n", fdp->internal_name);
+       }
+    }
+    
+    fprintf(fp, "\nstruct dll_table_entry_s %s_table[%d] =\n", 
+           UpperDLLName, Limit + 1);
+    fprintf(fp, "{\n");
+    odp = OrdinalDefinitions;
+    for (i = 0; i <= Limit; i++, odp++)
+    {
+       fdp = odp->additional_data;
+
+       if (!odp->valid)
+           odp->type = -1;
+       
+       switch (odp->type)
+       {
+         case FUNCTYPE_PASCAL:
+         case FUNCTYPE_REG:
+           fprintf(fp, "    { 0x23, %s_Ordinal_%d, ", UpperDLLName, i);
+           fprintf(fp, "\042%s\042, ", odp->export_name);
+           fprintf(fp, "%s, DLL_HANDLERTYPE_PASCAL, ", fdp->internal_name);
+           fprintf(fp, "%d, ", fdp->n_args_32);
+           if (fdp->n_args_32 > 0)
+           {
+               int argnum;
+               
+               fprintf(fp, "\n      {\n");
+               for (argnum = 0; argnum < fdp->n_args_32; argnum++)
+               {
+                   fprintf(fp, "        { %d, %d },\n",
+                           fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1],
+                           fdp->arg_types_16[argnum]);
+               }
+               fprintf(fp, "      }\n    ");
+           }
+           fprintf(fp, "}, \n");
+           break;
+               
+         case FUNCTYPE_C:
+           fprintf(fp, "    { 0x23, %s_Ordinal_%d, ", UpperDLLName, i);
+           fprintf(fp, "\042%s\042, ", odp->export_name);
+           fprintf(fp, "%s, DLL_HANDLERTYPE_C, ", fdp->internal_name);
+           fprintf(fp, "%d, ", fdp->n_args_32);
+           if (fdp->n_args_32 > 0)
+           {
+               int argnum;
+               
+               fprintf(fp, "\n      {\n");
+               for (argnum = 0; argnum < fdp->n_args_32; argnum++)
+               {
+                   fprintf(fp, "        { %d, %d },\n",
+                           fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1],
+                           fdp->arg_types_16[argnum]);
+               }
+               fprintf(fp, "      }\n    ");
+           }
+           fprintf(fp, "}, \n");
+           break;
+           
+         default:
+           fprintf(fp, "    { 0x23, %s_Ordinal_%d, \042\042, NULL },\n", 
+                   UpperDLLName, i);
+           break;
+       }
+    }
+    fprintf(fp, "};\n");
+
+    fclose(fp);
+}
+
diff --git a/dlls.h b/dlls.h
new file mode 100644 (file)
index 0000000..a43a9e0
--- /dev/null
+++ b/dlls.h
@@ -0,0 +1,56 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+
+#ifndef DLLS_H
+#define DLLS_H
+
+typedef struct dll_arg_relocation_s
+{
+    unsigned short dst_arg;    /* Offset to argument on stack          */
+    unsigned char src_type;    /* Argument type                        */
+} DLL_ARG;
+
+#define DLL_ARGTYPE_SIGNEDWORD 0
+#define DLL_ARGTYPE_WORD       1
+#define DLL_ARGTYPE_LONG       2
+#define DLL_ARGTYPE_FARPTR     3
+#define DLL_MAX_ARGS           16
+
+#define DLL_HANDLERTYPE_PASCAL 16
+#define DLL_HANDLERTYPE_C      17
+
+struct dll_table_entry_s
+{
+    /*
+     * Relocation data
+     */
+    unsigned int selector;     /* Selector to access this entry point    */
+    void *address;             /* Offset in segment of entry point       */
+
+    /*
+     * 16->32 bit interface data
+     */
+    char *export_name;
+    void *handler;             /* Address of function to process request */
+    int handler_type;          /* C or PASCAL calling convention         */
+    int n_args;                        /* Number of arguments passed to function */
+    DLL_ARG args[DLL_MAX_ARGS]; /* Argument conversion data              */
+};
+
+struct dll_name_table_entry_s
+{
+    char *dll_name;
+    struct dll_table_entry_s *dll_table;
+    int dll_table_length;
+    int dll_number;
+};
+
+extern struct dll_table_entry_s KERNEL_table[];
+extern struct dll_table_entry_s USER_table[];
+extern struct dll_table_entry_s GDI_table[];
+extern struct dll_table_entry_s UNIXLIB_table[];
+
+#endif /* DLLS_H */
diff --git a/dump.c b/dump.c
new file mode 100644 (file)
index 0000000..72edc7a
--- /dev/null
+++ b/dump.c
@@ -0,0 +1,92 @@
+/* $Id$
+ */
+
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#include <errno.h>
+#include "neexe.h"
+#include "segmem.h"
+#include "prototypes.h"
+
+/**********************************************************************
+ *                                     PrintFileHeader
+ */
+void
+PrintFileHeader(struct ne_header_s *ne_header)
+{
+    printf("ne_header: %c%c\n",
+          ne_header->header_type[0], 
+          ne_header->header_type[1]);
+    printf("linker version: %d.%d\n", ne_header->linker_version,
+          ne_header->linker_revision);
+    printf("format flags: %04.4x\n", ne_header->format_flags);
+    printf("automatic data segment: %04.4x\n", ne_header->auto_data_seg);
+    printf("CS:IP  %04.4x:%04.4x\n", ne_header->cs, ne_header->ip);
+    printf("SS:SP  %04.4x:%04.4x\n", ne_header->ss, ne_header->sp);
+    printf("additional flags: %02.2x\n", ne_header->additional_flags);
+    printf("operating system: %02.2x\n", ne_header->operating_system);
+    printf("fast load offset: %04.4x\n", ne_header->fastload_offset);
+    printf("fast load length: %04.4x\n", ne_header->fastload_length);
+}
+\f
+/**********************************************************************
+ *                                     PrintSegmentTable
+ */
+void
+PrintSegmentTable(struct ne_segment_table_entry_s *seg_table, int nentries)
+{
+    int i;
+
+    for (i = 0; i < nentries; i++)
+    {
+       printf("  %2d: OFFSET %04.4x, LENGTH %04.4x, ",
+              i + 1, seg_table[i].seg_data_offset, 
+              seg_table[i].seg_data_length);
+       printf("FLAGS %04.4x, MIN ALLOC %04.4x\n",
+              seg_table[i].seg_flags, seg_table[i].min_alloc);
+    }
+}
+\f
+/**********************************************************************
+ *                                     PrintRelocationTable
+ */
+void 
+PrintRelocationTable(char *exe_ptr, 
+                    struct ne_segment_table_entry_s *seg_entry_p,
+                    int segment)
+{
+    struct relocation_entry_s *rep;
+    int i;
+    int offset;
+    u_short n_entries, *sp;
+
+    printf("RELOCATION TABLE %d:\n", segment + 1);
+    
+    if (seg_entry_p->seg_data_offset == 0)
+       return;
+
+    offset = seg_entry_p->seg_data_length;
+    if (offset == 0)
+       offset = 0x10000;
+
+    sp = (u_short *) (exe_ptr + seg_entry_p->seg_data_offset * 512 + offset);
+    n_entries = *sp;
+
+    rep = (struct relocation_entry_s *) (sp + 1);
+    for (i = 0; i < n_entries; i++, rep++)
+    {
+       printf("  ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,",
+              rep->address_type, rep->relocation_type, rep->offset);
+       printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
+    }
+}
diff --git a/gdi.spec b/gdi.spec
new file mode 100644 (file)
index 0000000..9f87b18
--- /dev/null
+++ b/gdi.spec
@@ -0,0 +1,3 @@
+name   gdi
+id     3
+length 256
diff --git a/heap.c b/heap.c
new file mode 100644 (file)
index 0000000..156e9c8
--- /dev/null
+++ b/heap.c
@@ -0,0 +1,93 @@
+static char RCSId[] = "$Id$";
+static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "prototypes.h"
+
+typedef struct heap_mem_desc_s
+{
+    struct heap_mem_desc_s *prev, *next;
+    int   length;
+} MDESC;
+
+MDESC *FreeList;
+
+/**********************************************************************
+ *                                     HEAP_LocalInit
+ */
+void
+HEAP_LocalInit(void *start, int length)
+{
+    FreeList = (MDESC *) start;
+    FreeList->prev = NULL;
+    FreeList->next = NULL;
+    FreeList->length = length - sizeof(MDESC);
+}
+
+/**********************************************************************
+ *                                     HEAP_LocalAlloc
+ */
+void *
+HEAP_LocalAlloc(int flags, int bytes)
+{
+    MDESC *m, *m_new;
+    
+#ifdef HEAP_DEBUG
+    fprintf(stderr, "LocalAlloc: flags %x, bytes %d, ", flags, bytes);
+#endif
+
+    /*
+     * Find free block big enough.
+     */
+    for (m = FreeList; m != NULL; m = m->next)
+    {
+       if (m->length == bytes && m->length < bytes + 4 * sizeof(MDESC))
+       {
+           break;
+       }
+       else if (m->length > bytes)
+       {
+           m_new = m + (bytes / sizeof(MDESC)) + 2;
+           if (m->prev == NULL)
+               FreeList = m_new;
+           else
+               m->prev->next = m_new;
+           
+           if (m->next != NULL)
+               m->next->prev = m_new;
+           
+           m_new->next = m->next;
+           m_new->prev = m->prev;
+           m_new->length = m->length - ((int) m_new - (int) m);
+           m->length -= (m_new->length + sizeof(MDESC));
+
+#ifdef HEAP_DEBUG
+           fprintf(stderr, "Returning %x\n", (int) (m + 1));
+#endif
+           return (void *) (m + 1);
+       }
+    }
+
+    if (m != NULL)
+    {
+       if (m->prev == NULL)
+           FreeList = m->next;
+       else
+           m->prev->next = m->next;
+       
+       if (m->next != NULL)
+           m->next->prev = m->prev;
+       
+#ifdef HEAP_DEBUG
+       fprintf(stderr, "Returning %x\n", (int) (m + 1));
+#endif
+       return (void *) (m + 1);
+    }
+
+#ifdef HEAP_DEBUG
+    fprintf(stderr, "Returning 0\n");
+#endif
+    return 0;
+}
+
diff --git a/if1632.S b/if1632.S
new file mode 100644 (file)
index 0000000..7d2bbed
--- /dev/null
+++ b/if1632.S
@@ -0,0 +1,294 @@
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+       .data
+jump_target:
+return_value:
+       .long   0
+
+/**********************************************************************
+ *     Places to keep info about the current 32-bit stack frame.
+ */
+saved_esp:
+       .long   0
+saved_ebp:
+       .long   0
+saved_ss:
+       .word   0
+
+/**********************************************************************
+ *     Places to keep info about the current 16-bit stack frame.
+ */
+saved_16esp:
+       .long   0
+saved_16ebp:
+       .long   0
+saved_16ss:
+       .word   0
+
+nbytes:
+       .word   0
+selector:
+       .word   0
+offset:
+       .word   0
+
+       .text
+
+/**********************************************************************
+ *     int CallTo16(unsigned long csip, unsigned long sssp,
+ *                  unsigned short ds)
+ *
+ *     Stack:          0       ebp
+ *                     4       eip
+ *                     8       target ip
+ *                     10      target cs
+ *                     12      target sp
+ *                     14      target ss
+ *                     16      target ds
+ */
+       .align  4
+       .globl _CallTo16
+_CallTo16:
+       pushl   %ebp
+       movl    %esp,%ebp
+
+       /*
+        * Save our registers
+        */
+       pushal
+       pushl   saved_esp
+       pushl   saved_ebp
+       pushw   saved_ss
+
+       /*
+        * Get target address.
+        */
+       movl    8(%ebp),%eax
+       movl    %eax,jump_target
+       lea     jump_target,%edx
+
+       /*
+        * Put stack registers where we can get them after stack switch.
+        */
+       movw    %ss,saved_ss
+       movl    %esp,saved_esp
+       movl    %ebp,saved_ebp
+
+       /*
+        * Load ds, es, sp, ss & bp
+        */
+       movl    $0,%eax
+       movw    _PSPSelector,%ax
+       movw    %ax,%es
+       movw    16(%ebp),%ax
+       movw    %ax,%ds
+       xorl    %eax,%eax
+       movw    12(%ebp),%ax
+       movl    %eax,%esp
+       movw    14(%ebp),%ax
+       movw    %ax,%ss
+       movl    %eax,%ebp
+
+       /*
+        * Call entry point
+        */
+       .byte   0x66
+       lcall   %fs:(%edx)
+
+       /*
+        * Restore old stack and segment registers.
+        *
+        * Two choices here:
+        *      1. Trust that fs or gs hasn't changed.
+        *      2. Rely on knowledge of Linux use of segments.
+        *
+        * I'll opt for choice 2 because who knows what programs we
+        * going to run.  Linux should be fairly stable in terms of
+        * GDT usage.
+        */
+       pushl   %eax
+       movw    $0x2b,%ax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%fs
+       movw    %ax,%gs
+       popl    %eax
+       movw    saved_ss,%ss
+       movl    saved_esp,%esp
+       movl    saved_ebp,%ebp
+
+       /*
+        * Restore registers, but do not destroy return value.
+        */
+       popw    saved_ss
+       popl    saved_ebp
+       popl    saved_esp
+       movl    %eax,return_value
+       popal
+       movl    return_value,%eax
+       .align  2,0x90
+       leave
+       ret
+
+/**********************************************************************
+ *     CallTo32()
+ *
+ *     This function is called as a relay point to the built function
+ *     handler.  KERNEL, USER and GDI calls are dealt with by this
+ *     handler.  Calls to these DLLs will be mapped to a call handler
+ *     which will set EAX to a number indicating which DLL and which
+ *     function within that DLL.
+ *
+ *     This function will pass to the function handler two arguments.
+ *     The first argument will be the contents of EAX, the second
+ *     argument will be a segment:offset pair that points to the
+ *     16-bit stack.
+ */
+       .align  4
+       .globl _CallTo32
+_CallTo32:
+       pushl   %ebp
+       movl    %esp,%ebp
+
+       /*
+        * Save registers.  286 mode does not have fs or gs.
+        */
+       pushw   %ds
+       pushw   %es
+
+       /*
+        * Restore segment registers.
+        */
+       pushl   %eax
+       movw    $0x2b,%ax
+       movw    %ax,%ds
+       movw    %ax,%es
+       popl    %eax
+
+       /*
+        * Save old stack save variables, save stack registers, reload
+        * stack registers.
+        */
+       pushl   saved_16esp
+       pushl   saved_16ebp
+       pushw   saved_16ss
+
+       movw    %ss,saved_16ss
+       movl    %esp,saved_16esp
+       movl    %ebp,saved_16ebp
+
+       movw    saved_ss,%ss
+       movl    saved_esp,%esp
+       movl    saved_ebp,%ebp
+
+       /*
+        * Call entry point
+        */
+       pushw   saved_16ss
+       pushw   saved_16esp
+       pushl   %eax
+       call    _DLLRelay
+
+       /*
+        * Restore registers, but do not destroy return value.
+        */
+       movw    saved_16ss,%ss
+       movl    saved_16esp,%esp
+       movl    saved_16ebp,%ebp
+
+       popw    saved_16ss
+       popl    saved_16ebp
+       popl    saved_16esp
+
+       popw    %es
+       popw    %ds
+
+       .align  2,0x90
+       leave
+       /*
+        * Now we need to ditch the parameter bytes that were left on the
+        * stack. We do this by effectively popping the number of bytes,
+        * and the return address, removing the parameters and then putting
+        * the return address back on the stack.
+        * Normally this field is filled in by the relevant function in
+        * the emulation library, since it should know how many bytes to
+        * expect.
+        */
+       popw    %gs:nbytes
+       cmpw    $0,%gs:nbytes
+       je      noargs
+       popw    %gs:offset
+       popw    %gs:selector
+       addw    %gs:nbytes,%esp
+       pushw   %gs:selector
+       pushw   %gs:offset
+noargs:
+
+       /*
+        * Last, but not least we need to move the high word from eax to dx
+        */
+       pushl   %eax
+       popw    %dx
+       popw    %dx
+
+       .byte   0x66
+       lret
+
+/**********************************************************************
+ *     KERNEL_InitTask()
+ *
+ *     This interface functions is special because it returns all
+ *     of its values in registers.  Thus we can't just fall back through
+ *     the C functions that called us.  Instead we simply abandon
+ *     the 32-bit stack, set up the registers and return.
+ */
+       .globl _KERNEL_InitTask
+_KERNEL_InitTask:
+       /*
+        * Restore stack
+        */
+       movw    saved_16ss,%ss
+       movl    saved_16esp,%esp
+       movl    saved_16ebp,%ebp
+
+       popw    saved_16ss
+       popl    saved_16ebp
+       popl    saved_16esp
+
+       popw    %es
+       popw    %ds
+
+       .align  2,0x90
+       leave
+       /*
+        * Now we need to ditch the parameter bytes that were left on the
+        * stack. We do this by effectively popping the number of bytes,
+        * and the return address, removing the parameters and then putting
+        * the return address back on the stack.
+        * Normally this field is filled in by the relevant function in
+        * the emulation library, since it should know how many bytes to
+        * expect.
+        */
+       popw    %gs:nbytes
+       cmpw    $0,%gs:nbytes
+       je      noargs_2
+       popw    %gs:offset
+       popw    %gs:selector
+       addw    %gs:nbytes,%esp
+       pushw   %gs:selector
+       pushw   %gs:offset
+noargs_2:
+
+       /*
+        * Last, we need to load the return values.
+        */
+       movw    $1,%ax
+       movw    %gs:_WIN_StackSize,%cx
+       movw    $1,%dx
+       movw    0x80,%bx
+       movl    $0,%esi
+       movl    $1,%edi
+
+       .byte   0x66
+       lret
diff --git a/kernel.c b/kernel.c
new file mode 100644 (file)
index 0000000..4c57006
--- /dev/null
+++ b/kernel.c
@@ -0,0 +1,106 @@
+static char RCSId[] = "$Id$";
+static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "prototypes.h"
+
+extern unsigned short *Stack16Frame;
+
+/**********************************************************************
+ *                                     KERNEL_GetVersion
+ *
+ * Return the version of Windows that we emulate.
+ */
+int
+KERNEL_GetVersion(void)
+{
+    return 0x0301;
+}
+
+/**********************************************************************
+ *                                     KERNEL_LockSegment
+ */
+int
+KERNEL_LockSegment(int segment)
+{
+    if (segment == -1)
+       segment = *(Stack16Frame + 6);
+
+#ifdef RELAY_DEBUG
+    fprintf(stderr, "LockSegment: segment %x\n", segment);
+#endif
+
+    return segment;
+}
+
+/**********************************************************************
+ *                                     KERNEL_UnlockSegment
+ */
+int
+KERNEL_UnlockSegment(int segment)
+{
+    if (segment == -1)
+       segment = *(Stack16Frame + 6);
+
+#ifdef RELAY_DEBUG
+    fprintf(stderr, "UnlockSegment: segment %x\n", segment);
+#endif
+
+    return segment;
+}
+
+/**********************************************************************
+ *                                     KERNEL_WaitEvent
+ */
+int
+KERNEL_WaitEvent(int task)
+{
+#ifdef RELAY_DEBUG
+    fprintf(stderr, "WaitEvent: task %d\n", task);
+#endif
+    return 0;
+}
+/**********************************************************************
+ *                                     KERNEL_GetModuleFileName
+ */
+int
+KERNEL_GetModuleFileName(int module, char *filename, int bytes)
+{
+#ifdef RELAY_DEBUG
+    fprintf(stderr, "GetModuleFileName: module %d, filename %x, bytes %d\n", 
+           module, filename, bytes);
+#endif
+    
+    strcpy(filename, "TEST.EXE");
+    
+    return strlen(filename);
+}
+
+/**********************************************************************
+ *                                     KERNEL_DOS3Call
+ */
+int
+KERNEL_DOS3Call(int ax, int cx, int dx, int bx, int sp, int bp,
+               int si, int di, int ds, int es)
+{
+    switch ((ax >> 8) & 0xff)
+    {
+      case 0x30:
+       return 0x0303;
+       
+      case 0x25:
+      case 0x35:
+       return 0;
+
+      default:
+       fprintf(stderr, "DOS: AX %04x, BX %04x, CX %04x, DX %04x\n",
+               ax, bx, cx, dx);
+       fprintf(stderr, "     SP %04x, BP %04x, SI %04x, DI %04x\n",
+               sp, bp, si, di);
+       fprintf(stderr, "     DS %04x, ES %04x\n",
+               ds, es);
+    }
+    
+    return 0;
+}
diff --git a/kernel.spec b/kernel.spec
new file mode 100644 (file)
index 0000000..58a0f0a
--- /dev/null
@@ -0,0 +1,16 @@
+name   kernel
+id     1
+length 256
+
+3   pascal GetVersion() KERNEL_GetVersion()
+5   pascal LocalAlloc(word word) HEAP_LocalAlloc(1 2)
+23  pascal LockSegment(s_word) KERNEL_LockSegment(1)
+24  pascal UnlockSegment(s_word) KERNEL_UnlockSegment(1)
+30  pascal WaitEvent(word) KERNEL_WaitEvent(1)
+49  pascal GetModuleFileName(word ptr s_word) KERNEL_GetModuleFileName(1 2 3)
+91  pascal InitTask() KERNEL_InitTask()
+102 register DOS3Call(word word word word word
+                     word word word word word) 
+            KERNEL_DOS3Call(1 2 3 4 5 6 7 8 9 10)
+131 pascal GetDOSEnvironment() GetDOSEnvironment()
+178 equate __WINFLAGS 0x413
diff --git a/ldt.c b/ldt.c
new file mode 100644 (file)
index 0000000..facad91
--- /dev/null
+++ b/ldt.c
@@ -0,0 +1,74 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#include "prototypes.h"
+
+/**********************************************************************
+ *                                     print_ldt
+ */
+void
+print_ldt()
+{
+    char buffer[0x10000];
+    struct modify_ldt_ldt_s ldt_info;
+    unsigned long *lp;
+    unsigned long base_addr, limit;
+    int type, dpl, i;
+    
+    if (get_ldt(buffer) < 0)
+       exit(1);
+    
+    lp = (unsigned long *) buffer;
+    for (i = 0; i < 32; i++, lp++)
+    {
+       /* First 32 bits of descriptor */
+       base_addr = (*lp >> 16) & 0x0000FFFF;
+       limit = *lp & 0x0000FFFF;
+       lp++;
+       
+       /* First 32 bits of descriptor */
+       base_addr |= (*lp & 0xFF000000) | ((*lp << 16) & 0x00FF0000);
+       limit |= (*lp & 0x000F0000);
+       type = (*lp >> 9) & 7;
+       dpl = (*lp >> 13) & 3;
+
+       if (*lp & 1000)
+       {
+           printf("Entry %2d: Base %08.8x, Limit %05.5x, DPL %d, Type %d\n",
+                  i, base_addr, limit, dpl, type);
+           printf("          ");
+           if (*lp & 0x100)
+               printf("Accessed, ");
+           if (*lp & 8000)
+               printf("Present, ");
+           if (*lp & 0x100000)
+               printf("User, ");
+           if (*lp & 0x200000)
+               printf("X, ");
+           if (*lp & 0x400000)
+               printf("32, ");
+           else
+               printf("16, ");
+           if (*lp & 0x800000)
+               printf("page limit, ");
+           else
+               printf("byte limit, ");
+           printf("\n");
+           printf("          %08.8x %08.8x\n", *(lp), *(lp-1));
+       }
+       else
+       {
+           printf("Entry %2d: Base %08.8x, Limit %05.5x, DPL %d, Type %d\n",
+                  i, base_addr, limit, dpl, type);
+           printf("          SYSTEM: %08.8x %08.8x\n", *lp, *(lp-1));
+       }
+    }
+}
diff --git a/ldt.tar b/ldt.tar
new file mode 100644 (file)
index 0000000..a4c8dde
Binary files /dev/null and b/ldt.tar differ
diff --git a/ldtlib.c b/ldtlib.c
new file mode 100644 (file)
index 0000000..137130d
--- /dev/null
+++ b/ldtlib.c
@@ -0,0 +1,37 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+
+_syscall2(int, modify_ldt, int, func, void *, ptr)
+
+int
+get_ldt(void *buffer)
+{
+    return modify_ldt(0, buffer);
+}
+
+int
+set_ldt_entry(int entry, unsigned long base, unsigned int limit,
+             int seg_32bit_flag, int contents, int read_only_flag,
+             int limit_in_pages_flag)
+{
+    struct modify_ldt_ldt_s ldt_info;
+
+    ldt_info.entry_number   = entry;
+    ldt_info.base_addr      = base;
+    ldt_info.limit          = limit;
+    ldt_info.seg_32bit      = seg_32bit_flag;
+    ldt_info.contents       = contents;
+    ldt_info.read_exec_only = read_only_flag;
+    ldt_info.limit_in_pages = limit_in_pages_flag;
+
+    return modify_ldt(1, &ldt_info);
+}
diff --git a/neexe.h b/neexe.h
new file mode 100644 (file)
index 0000000..d92b4a6
--- /dev/null
+++ b/neexe.h
@@ -0,0 +1,158 @@
+/* $Id: neexe.h,v 1.1 1993/06/09 03:28:10 root Exp root $
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#ifndef NEEXE_H
+#define NEEXE_H
+
+/*
+ * Old MZ header for DOS programs.  Actually just a couple of fields
+ * from it, so that we can find the start of the NE header.
+ */
+struct mz_header_s
+{
+    u_char dont_care1[0x18];   /* MZ Header stuff                      */
+    u_char must_be_0x40;       /* 0x40 for non-MZ program              */
+    u_char dont_care2[0x23];   /* More MZ header stuff                 */
+    u_short ne_offset;         /* Offset to extended header            */
+};
+
+/*
+ * This is the Windows executable (NE) header.
+ */
+struct ne_header_s
+{
+    char    header_type[2];    /* Must contain 'N' 'E'                 */
+    u_char  linker_version;    /* Linker version number                */
+    u_char  linker_revision;   /* Linker revision number               */
+    u_short entry_tab_offset;  /* Offset to entry table relative to NE */
+    u_short entry_tab_length;  /* Length of etnry table in bytes       */
+    u_long  reserved1;         /* Reserved by Microsoft                */
+    u_short format_flags;      /* Flags that segments in this file     */
+    u_short auto_data_seg;     /* Automatic data segment number        */
+    u_short local_heap_length; /* Initial size of local heap           */
+    u_short stack_length;      /* Initial size of stack                */
+    u_short ip;                        /* Initial IP                           */
+    u_short cs;                        /* Initial CS                           */
+    u_short sp;                        /* Initial SP                           */
+    u_short ss;                        /* Initial SS                           */
+    u_short n_segment_tab;     /* # of entries in segment table        */
+    u_short n_mod_ref_tab;     /* # of entries in module reference tab.*/
+    u_short nrname_tab_length;         /* Length of nonresident-name table     */
+    u_short segment_tab_offset;        /* Offset to segment table              */
+    u_short resource_tab_offset;/* Offset to resource table            */
+    u_short rname_tab_offset;  /* Offset to resident-name table        */
+    u_short moduleref_tab_offset;/* Offset to module reference table   */
+    u_short iname_tab_offset;  /* Offset to imported name table        */
+    u_long  nrname_tab_offset; /* Offset to nonresident-name table     */
+    u_short n_mov_entry_points;        /* # of movable entry points            */
+    u_short align_shift_count; /* Logical sector alignment shift count */
+    u_short n_resource_seg;    /* # of resource segments               */
+    u_char  operating_system;  /* Flags indicating target OS           */
+    u_char  additional_flags;  /* Additional information flags         */
+    u_short fastload_offset;   /* Offset to fast load area             */
+    u_short fastload_length;   /* Length of fast load area             */
+    u_short reserved2;         /* Reserved by Microsoft                */
+    u_short expect_version;    /* Expected Windows version number      */
+};
+
+/*
+ * NE Header FORMAT FLAGS
+ */
+#define NE_FFLAGS_SINGLEDATA   0x0001
+#define NE_FFLAGS_MULTIPLEDATA 0x0002
+#define NE_FFLAGS_SELFLOAD     0x0800
+#define NE_FFLAGS_LINKERROR    0x2000
+#define NE_FFLAGS_LIBMODULE    0x8000
+
+/*
+ * NE Header OPERATING SYSTEM
+ */
+#define NE_OSFLAGS_UNKNOWN     0x01
+#define NE_OSFLAGS_WINDOWS     0x04
+
+/*
+ * NE Header ADDITIONAL FLAGS
+ */
+#define NE_AFLAGS_WIN2_PROTMODE        0x02
+#define NE_AFLAGS_WIN2_PROFONTS        0x04
+#define NE_AFLAGS_FASTLOAD     0x08
+
+/*
+ * Segment table entry
+ */
+struct ne_segment_table_entry_s
+{
+    u_short seg_data_offset;   /* Sector offset of segment data        */
+    u_short seg_data_length;   /* Length of segment data               */
+    u_short seg_flags;         /* Flags associated with this segment   */
+    u_short min_alloc;         /* Minimum allocation size for this     */
+};
+
+/*
+ * Segment Flags
+ */
+#define NE_SEGFLAGS_DATA       0x0001
+#define NE_SEGFLAGS_ALLOCATED  0x0002
+#define NE_SEGFLAGS_LOADED     0x0004
+#define NE_SEGFLAGS_MOVEABLE   0x0010
+#define NE_SEGFLAGS_SHAREABLE  0x0020
+#define NE_SEGFLAGS_PRELOAD    0x0040
+#define NE_SEGFLAGS_EXECUTEONLY        0x0080
+#define NE_SEGFLAGS_READONLY   0x0080
+#define NE_SEGFLAGS_RELOC_DATA 0x0100
+#define NE_SEGFLAGS_DISCARDABLE        0x1000
+
+/*
+ * Relocation table entry
+ */
+struct relocation_entry_s
+{
+    u_char  address_type;      /* Relocation address type              */
+    u_char  relocation_type;   /* Relocation type                      */
+    u_short offset;            /* Offset in segment to fixup           */
+    u_short target1;           /* Target specification                 */
+    u_short target2;           /* Target specification                 */
+};
+
+/*
+ * Relocation address types
+ */
+#define NE_RADDR_LOWBYTE       0
+#define NE_RADDR_SELECTOR      2
+#define NE_RADDR_POINTER32     3
+#define NE_RADDR_OFFSET16      5
+#define NE_RADDR_POINTER48     11
+#define NE_RADDR_OFFSET32      13
+
+/*
+ * Relocation types
+ */
+#define NE_RELTYPE_INTERNAL    0
+#define NE_RELTYPE_ORDINAL     1
+#define NE_RELTYPE_NAME                2
+#define NE_RELTYPE_OSFIXUP     3
+
+/*
+ * DOS PSP
+ */
+struct dos_psp_s
+{
+    unsigned short pspInt20;
+    unsigned short pspNextParagraph;
+    unsigned char  pspReserved1;
+    unsigned char  pspDispatcher[5];
+    unsigned long  pspTerminateVector;
+    unsigned long  pspControlCVector;
+    unsigned long  pspCritErrorVector;
+    unsigned short pspReserved2[11];
+    unsigned short pspEnvironment;
+    unsigned short pspReserved3[23];
+    unsigned char  pspFCB_1[16];
+    unsigned char  pspFCB_2[16];
+    unsigned char  pspCommandTailCount;
+    unsigned char  pspCommandTail[128];
+};
+
+#endif /* NEEXE_H */
diff --git a/prototypes.h b/prototypes.h
new file mode 100644 (file)
index 0000000..0b6b8ed
--- /dev/null
@@ -0,0 +1,32 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#ifndef PROTOTYPES_H
+#define PROTOTYPES_H
+
+#include <sys/types.h>
+#include "neexe.h"
+#include "segmem.h"
+
+extern struct segment_descriptor_s *
+    CreateSelectors(int fd, struct ne_segment_table_entry_s *seg_table,
+                   struct ne_header_s *ne_header);
+
+extern void PrintFileHeader(struct ne_header_s *ne_header);
+extern void PrintSegmentTable(struct ne_segment_table_entry_s *seg_table, 
+                             int nentries);
+extern void PrintRelocationTable(char *exe_ptr, 
+                                struct ne_segment_table_entry_s *seg_entry_p,
+                                int segment);
+extern int FixupSegment(int fd, struct mz_header_s * mz_header,
+                       struct ne_header_s *ne_header,
+                       struct ne_segment_table_entry_s *seg_table, 
+                       struct segment_descriptor_s *selecetor_table,
+                       int segment_num);
+extern struct  dll_table_entry_s *FindDLLTable(char *dll_name);
+
+extern char WIN_CommandLine[];
+
+#endif /* PROTOTYPES_H */
diff --git a/relay.c b/relay.c
new file mode 100644 (file)
index 0000000..067d0ab
--- /dev/null
+++ b/relay.c
@@ -0,0 +1,201 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#include <linux/segment.h>
+#include <errno.h>
+#include "neexe.h"
+#include "segmem.h"
+#include "prototypes.h"
+#include "dlls.h"
+
+struct dll_name_table_entry_s dll_builtin_table[4] =
+{
+    { "KERNEL",  KERNEL_table,         256, 1 },
+    { "USER",    USER_table,   256, 2 },
+    { "GDI",     GDI_table,    256, 3 },
+    { "UNIXLIB", UNIXLIB_table, 256, 4 },
+};
+
+unsigned short *Stack16Frame;
+
+/**********************************************************************
+ *                                     DLLRelay
+ *
+ * We get a stack frame pointer to data that looks like this:
+ *
+ *   Hex Offset Contents
+ *   ---------- -------
+ *     +00     previous saved_16ss
+ *     +02     previous saved_16ebp
+ *     +06     previous saved_16esp
+ *     +0A     16-bit es
+ *     +0C     16-bit ds
+ *     +0E     16-bit ebp
+ *     +12     length of 16-bit arguments
+ *     +14     16-bit ip
+ *     +16     16-bit cs
+ *     +18     arguments
+ */
+int
+DLLRelay(unsigned int func_num, unsigned int seg_off)
+{
+    struct dll_table_entry_s *dll_p;
+    unsigned int segment;
+    unsigned int offset;
+    unsigned int dll_id;
+    unsigned int ordinal;
+    int arg_table[DLL_MAX_ARGS];
+    void *arg_ptr;
+    int (*func_ptr)();
+    int i;
+    
+    /*
+     * Determine address of arguments.
+     */
+    Stack16Frame = (unsigned short *) seg_off;
+    arg_ptr = (void *) (seg_off + 0x18);
+
+    /*
+     * Extract the DLL number and ordinal number.
+     */
+    dll_id  = ((func_num >> 16) & 0xffff) - 1;
+    ordinal = func_num & 0xffff;
+    dll_p   = &dll_builtin_table[dll_id].dll_table[ordinal];
+
+#ifdef RELAY_DEBUG
+    {
+       unsigned int *ret_addr;
+       unsigned short *stack_p;
+       
+       ret_addr = (unsigned int *) ((char *) seg_off + 0x14);
+       printf("RELAY: Calling %s.%d, 16-bit stack at %04x:%04x, ",
+              dll_builtin_table[dll_id].dll_name, ordinal,
+              seg_off >> 16, seg_off & 0xffff);
+       printf("return to %08x\n", *ret_addr);
+
+#ifdef STACK_DEBUG
+       stack_p = (unsigned short *) seg_off;
+       for (i = 0; i < 24; i++, stack_p++)
+       {
+            printf("%04x ", *stack_p);
+           if ((i & 7) == 7)
+               printf("\n");
+       }
+       printf("\n");
+#endif /* STACK_DEBUG */
+    }
+#endif /* RELAY_DEBUG */
+
+    /*
+     * Make sure we have a handler defined for this call.
+     */
+    if (dll_p->handler == NULL)
+    {
+       char buffer[100];
+       
+       sprintf(buffer, "No handler for routine %s.%d", 
+               dll_builtin_table[dll_id].dll_name, ordinal);
+       myerror(buffer);
+    }
+    func_ptr = dll_p->handler;
+
+    /*
+     * OK, special case.  If the handler is define as taking no arguments
+     * then pass the address of the arguments on the 16-bit stack to the
+     * handler.  It will just ignore the pointer if it really takes no
+     * arguments.  This allows us to write slightly faster library routines
+     * if we choose.
+     */
+    if (dll_p->n_args == 0)
+       return (*func_ptr)(arg_ptr);
+
+    /*
+     * Getting this far means we need to convert the 16-bit argument stack.
+     */
+    for (i = 0; i < dll_p->n_args; i++)
+    {
+       short *sp;
+       int *ip;
+       
+       offset = dll_p->args[i].dst_arg;
+
+       switch (dll_p->args[i].src_type)
+       {
+         case DLL_ARGTYPE_SIGNEDWORD:
+           sp = (short *) ((char *) arg_ptr + offset);
+           arg_table[i] = *sp;
+           break;
+           
+         case DLL_ARGTYPE_WORD:
+           sp = (short *) ((char *) arg_ptr + offset);
+           arg_table[i] = (int) *sp & 0xffff;
+           break;
+           
+         case DLL_ARGTYPE_LONG:
+         case DLL_ARGTYPE_FARPTR:
+           ip = (int *) ((char *) arg_ptr + offset);
+           arg_table[i] = *ip;
+           break;
+       }
+    }
+
+    /*
+     * Call the handler
+     */
+    return (*func_ptr)(arg_table[0], arg_table[1], arg_table[2], 
+                      arg_table[3], arg_table[4], arg_table[5], 
+                      arg_table[6], arg_table[7], arg_table[8], 
+                      arg_table[9], arg_table[10], arg_table[11],
+                      arg_table[12], arg_table[13], arg_table[14], 
+                      arg_table[15]);
+}
+
+/**********************************************************************
+ *                                     FindDLLTable
+ */
+struct  dll_table_entry_s *
+FindDLLTable(char *dll_name)
+{
+    int i;
+
+    for (i = 0; i < 4; i++)
+       if (strcmp(dll_builtin_table[i].dll_name, dll_name) == 0)
+           return dll_builtin_table[i].dll_table;
+    
+    return NULL;
+}
+
+/**********************************************************************
+ *                                     FindOrdinalFromName
+ */
+int
+FindOrdinalFromName(struct dll_table_entry_s *dll_table, char *func_name)
+{
+    int i, limit;
+
+    for (i = 0; i < 4; i++)
+       if (dll_table == dll_builtin_table[i].dll_table)
+           break;
+    
+    if (i == 4)
+       return 0;
+
+    limit = dll_builtin_table[i].dll_table_length;
+    for (i = 0; i < limit; i++)
+       if (strcasecmp(dll_table[i].export_name, func_name) == 0)
+           return i;
+    
+    return 0;
+}
diff --git a/segmem.h b/segmem.h
new file mode 100644 (file)
index 0000000..39a0225
--- /dev/null
+++ b/segmem.h
@@ -0,0 +1,26 @@
+/* $Id$
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+#ifndef SEGMEM_H
+#define SEGMEM_H
+
+/*
+ * Structure to hold info about each selector we create.
+ */
+
+struct segment_descriptor_s
+{
+    void          *base_addr;  /* Pointer to segment in flat memory    */
+    unsigned int   length;     /* Length of segment                    */
+    unsigned int   flags;      /* Segment flags (see neexe.h and below)*/
+    unsigned short selector;   /* Selector used to access this segment */
+};
+
+/*
+ * Additional flags
+ */
+#define NE_SEGFLAGS_MALLOCED   0x00010000 /* Memory allocated with malloc() */
+
+#endif /* SEGMEM_H */
diff --git a/selector.c b/selector.c
new file mode 100644 (file)
index 0000000..449e9ba
--- /dev/null
@@ -0,0 +1,264 @@
+/* $Id: exedump.c,v 1.1 1993/06/09 03:28:10 root Exp root $
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/ldt.h>
+#include <errno.h>
+#include "neexe.h"
+#include "segmem.h"
+#include "prototypes.h"
+
+struct segment_descriptor_s *SelectorTable;
+int SelectorTableLength;
+int EnvironmentSelectorIdx;
+int PSPSelectorIdx;
+unsigned short PSPSelector;
+
+extern void KERNEL_Ordinal_102();
+extern void UNIXLIB_Ordinal_0();
+
+\f
+/**********************************************************************
+ *                                     GetDOSEnvironment
+ */
+void *
+GetDOSEnvironment()
+{
+    return SelectorTable[EnvironmentSelectorIdx].base_addr;
+}
+\f
+/**********************************************************************
+ *                                     CreateEnvironment
+ */
+void
+CreateEnvironment(int sel_idx, struct segment_descriptor_s *s, FILE *zfile)
+{
+    char *p;
+
+    EnvironmentSelectorIdx = sel_idx;
+
+    /*
+     * Create memory to hold environment.
+     */
+    s->flags = NE_SEGFLAGS_DATA;
+    s->selector = (sel_idx << 3) | 0x0007;
+    s->length = PAGE_SIZE;
+    s->base_addr = (void *) mmap((char *) (s->selector << 16),
+                                PAGE_SIZE,
+                                PROT_EXEC | PROT_READ | PROT_WRITE,
+                                MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
+
+    /*
+     * Fill environment with meaningless babble.
+     */
+    p = (char *) s->base_addr;
+    strcpy(p, "PATH=C:\\WINDOWS");
+    p += strlen(p) + 1;
+    *p++ = '\0';
+    *p++ = 11;
+    *p++ = 0;
+    strcpy(p, "C:\\TEST.EXE");
+
+    /*
+     * Create entry in LDT for this segment.
+     */
+    if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr, s->length, 0, 
+                     MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0)
+    {
+       myerror("Could not create LDT entry for environment");
+    }
+}
+\f
+/**********************************************************************
+ *                                     CreatePSP
+ */
+void
+CreatePSP(int sel_idx, struct segment_descriptor_s *s, FILE *zfile)
+{
+    struct dos_psp_s *psp;
+    unsigned short *usp;
+    
+    PSPSelectorIdx = sel_idx;
+
+    /*
+     * Create memory to hold PSP.
+     */
+    s->flags = NE_SEGFLAGS_DATA;
+    s->selector = (sel_idx << 3) | 0x0007;
+    s->length = PAGE_SIZE;
+    s->base_addr = (void *) mmap((char *) (s->selector << 16),
+                                PAGE_SIZE,
+                                PROT_EXEC | PROT_READ | PROT_WRITE,
+                                MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
+
+    /*
+     * Fill PSP
+     */
+    PSPSelector = s->selector;
+    psp = (struct dos_psp_s *) s->base_addr;
+    psp->pspInt20 = 0x20cd;
+    psp->pspDispatcher[0] = 0x9a;
+    usp = (unsigned short *) &psp->pspDispatcher[1];
+    *usp       = (unsigned short) KERNEL_Ordinal_102;
+    *(usp + 1) = 0x23;
+    psp->pspTerminateVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff);
+    psp->pspControlCVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff);
+    psp->pspCritErrorVector = 0x00230000 | ((int) UNIXLIB_Ordinal_0 & 0xffff);
+    psp->pspEnvironment = SelectorTable[EnvironmentSelectorIdx].selector;
+    psp->pspCommandTailCount = 1;
+    strcpy(psp->pspCommandTail, "\r");
+    
+
+    /*
+     * Create entry in LDT for this segment.
+     */
+    if (set_ldt_entry(sel_idx, (unsigned long) s->base_addr, s->length, 0, 
+                     MODIFY_LDT_CONTENTS_DATA, 0, 0) < 0)
+    {
+       myerror("Could not create LDT entry for PSP");
+    }
+}
+\f
+/**********************************************************************
+ *                                     CreateSelectors
+ */
+struct segment_descriptor_s *
+CreateSelectors(int fd, struct ne_segment_table_entry_s *seg_table,
+               struct ne_header_s *ne_header)
+{
+    struct segment_descriptor_s *selectors, *s;
+    int contents, read_only;
+    int i;
+    int status;
+    FILE * zfile;
+    int old_length;
+
+    /*
+     * Allocate memory for the table to keep track of all selectors.
+     */
+    SelectorTableLength = ne_header->n_segment_tab + 2;
+    selectors = malloc(SelectorTableLength * sizeof(*selectors));
+    if (selectors == NULL)
+       return NULL;
+    SelectorTable = selectors;
+
+    /*
+     * Step through the segment table in the exe header.
+     */
+    s = selectors;
+    zfile = fopen("/dev/zero","r");
+    for (i = 0; i < ne_header->n_segment_tab; i++, s++)
+    {
+       /*
+        * Store the flags in our table.
+        */
+       s->flags = seg_table[i].seg_flags;
+       s->selector = (i << 3) | 0x0007;
+
+       /*
+        * Is there an image for this segment in the file?
+        */
+       if (seg_table[i].seg_data_offset == 0)
+       {
+           /*
+            * No image in exe file, let's allocate some memory for it.
+            */
+           s->length = seg_table[i].min_alloc;
+       }
+       else
+       {
+           /*
+            * Image in file, let's just point to the image in memory.
+            */
+           s->length    = seg_table[i].seg_data_length;
+       }
+
+       if (s->length == 0)
+           s->length = 0x10000;
+       old_length = s->length;
+
+       /*
+        * If this is the automatic data segment, its size must be adjusted.
+        * First we need to check for local heap.  Second we nee to see if
+        * this is also the stack segment.
+        */
+       if (i + 1 == ne_header->auto_data_seg)
+       {
+           s->length += ne_header->local_heap_length;
+
+           if (i + 1 == ne_header->ss)
+           {
+               s->length += ne_header->stack_length;
+               ne_header->sp = s->length;
+           }
+       }
+
+       /*
+        * Is this a DATA or CODE segment?
+        */
+       read_only = 0;
+       if (s->flags & NE_SEGFLAGS_DATA)
+       {
+           contents = MODIFY_LDT_CONTENTS_DATA;
+           if (s->flags & NE_SEGFLAGS_READONLY)
+               read_only = 1;
+       }
+       else
+       {
+           contents = MODIFY_LDT_CONTENTS_CODE;
+           if (s->flags & NE_SEGFLAGS_EXECUTEONLY)
+               read_only = 1;
+       }
+       s->base_addr =
+         (void *) mmap((char *) (s->selector << 16),
+                       (s->length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1),
+                       PROT_EXEC | PROT_READ | PROT_WRITE,
+                       MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0);
+       if (seg_table[i].seg_data_offset != 0)
+       {
+           /*
+            * Image in file.
+            */
+           status = lseek(fd, seg_table[i].seg_data_offset * 512, SEEK_SET);
+           if(read(fd, s->base_addr, old_length) != old_length)
+             myerror("Unable to read segment from file");
+       }
+       /*
+        * Create entry in LDT for this segment.
+        */
+       if (set_ldt_entry(i, (unsigned long) s->base_addr, s->length, 0, 
+                         contents, read_only, 0) < 0)
+       {
+           free(selectors);
+           return NULL;
+       }
+       /*
+        * If this is the automatic data segment, then we must initialize
+        * the local heap.
+        */
+       if (i + 1 == ne_header->auto_data_seg)
+       {
+           HEAP_LocalInit(s->base_addr + old_length, 
+                          ne_header->local_heap_length);
+       }
+    }
+
+    CreateEnvironment(i++, s++, zfile);
+    CreatePSP(i++, s++, zfile);
+
+    fclose(zfile);
+
+    return selectors;
+}
diff --git a/test.exe b/test.exe
new file mode 100755 (executable)
index 0000000..3a75f7c
Binary files /dev/null and b/test.exe differ
diff --git a/unixlib.spec b/unixlib.spec
new file mode 100644 (file)
index 0000000..7b5b9dd
--- /dev/null
@@ -0,0 +1,5 @@
+name   unixlib
+id     4
+length 256
+
+1   c _DebugPrintString(ptr) DebugPrintString(1)
\ No newline at end of file
diff --git a/user.c b/user.c
new file mode 100644 (file)
index 0000000..7b3ceed
--- /dev/null
+++ b/user.c
@@ -0,0 +1,17 @@
+static char RCSId[] = "$Id$";
+static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "prototypes.h"
+
+/**********************************************************************
+ *                                     USER_InitApp
+ *
+ * Load necessary resources?
+ */
+int
+USER_InitApp(int hInstance)
+{
+    return 1;
+}
diff --git a/user.spec b/user.spec
new file mode 100644 (file)
index 0000000..152ef18
--- /dev/null
+++ b/user.spec
@@ -0,0 +1,5 @@
+name   user
+id     2
+length 256
+
+5   pascal InitApp(word) USER_InitApp(1)
\ No newline at end of file
diff --git a/wine b/wine
new file mode 100755 (executable)
index 0000000..57d7234
Binary files /dev/null and b/wine differ
diff --git a/wine.c b/wine.c
new file mode 100644 (file)
index 0000000..85d3844
--- /dev/null
+++ b/wine.c
@@ -0,0 +1,348 @@
+/* $Id: exedump.c,v 1.1 1993/06/09 03:28:10 root Exp root $
+ */
+/*
+ * Copyright  Robert J. Amstadt, 1993
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+#include <linux/segment.h>
+#include <errno.h>
+#include "neexe.h"
+#include "segmem.h"
+#include "prototypes.h"
+#include "dlls.h"
+
+extern int CallTo16(unsigned long csip, unsigned long sssp, unsigned short ds);
+extern void CallTo32();
+
+unsigned short WIN_StackSize;
+
+char **Argv;
+int Argc;
+
+/**********************************************************************
+ *                                     DebugPrintString
+ */
+int
+DebugPrintString(char *str)
+{
+    fprintf(stderr, "%s", str);
+    return 0;
+}
+
+/**********************************************************************
+ *                                     myerror
+ */
+void
+myerror(const char *s)
+{
+    char buffer[200];
+    
+    sprintf(buffer, "%s", Argv[0]);
+    if (s == NULL)
+       perror(buffer);
+    else
+       fprintf(stderr, "%s: %s\n", buffer, s);
+
+    exit(1);
+}
+\f
+/**********************************************************************
+ *                                     main
+ */
+main(int argc, char **argv)
+{
+    struct stat finfo;
+    struct mz_header_s *mz_header;
+    struct ne_header_s *ne_header;
+    struct ne_segment_table_entry_s *seg_table;
+    unsigned int status;
+    unsigned int read_size;
+    struct segment_descriptor_s *selector_table;
+    int fd;
+    int segment;
+    int cs_reg, ds_reg, ss_reg, ip_reg, sp_reg;
+    int rv;
+
+    Argc = argc;
+    Argv = argv;
+    
+    if (argc < 2)
+    {
+       fprintf(stderr, "usage: %s FILENAME\n", argv[0]);
+       exit(1);
+    }
+    
+    /*
+     * Open file for reading.
+     */
+    fd = open(argv[1], O_RDONLY);
+    if (fd < 0)
+    {
+       myerror(NULL);
+    }
+
+    /*
+     * Allocate memory to hold entire executable.
+     */
+    if (fstat(fd, &finfo) < 0)
+       myerror(NULL);
+    
+    /*
+     * Establish header pointers.
+     */
+    mz_header = (struct mz_header_s *) malloc(sizeof(struct mz_header_s));;
+    status = lseek(fd, 0, SEEK_SET);
+    if (read(fd, mz_header, sizeof(struct mz_header_s)) !=
+       sizeof(struct mz_header_s))
+    {
+       myerror("Unable to read MZ header from file");
+    }
+    if (mz_header->must_be_0x40 != 0x40)
+       myerror("This is not a Windows program");
+    
+    ne_header = (struct ne_header_s *) malloc(sizeof(struct ne_header_s));
+    status = lseek(fd, mz_header->ne_offset, SEEK_SET);
+    if (read(fd, ne_header, sizeof(struct ne_header_s)) 
+       != sizeof(struct ne_header_s))
+    {
+       myerror("Unable to read NE header from file");
+    }
+    if (ne_header->header_type[0] != 'N' || ne_header->header_type[1] != 'E')
+       myerror("This is not a Windows program");
+
+    WIN_StackSize = ne_header->stack_length;
+    
+
+    /*
+     * Create segment selectors.
+     */
+    status = lseek(fd, mz_header->ne_offset + ne_header->segment_tab_offset,
+                  SEEK_SET);
+    read_size  = ne_header->n_segment_tab *
+                sizeof(struct ne_segment_table_entry_s);
+    seg_table = (struct ne_segment_table_entry_s *) malloc(read_size);
+    if (read(fd, seg_table, read_size) != read_size)
+       myerror("Unable to read segment table header from file");
+    selector_table = CreateSelectors(fd, seg_table, ne_header);
+    
+    /*
+     * Fixup references.
+     */
+    for (segment = 0; segment < ne_header->n_segment_tab; segment++)
+    {
+       if (FixupSegment(fd, mz_header, ne_header, seg_table,
+                        selector_table, segment) < 0)
+       {
+           myerror("fixup failed.");
+       }
+    }
+
+    close(fd);
+    /*
+     * Fixup stack and jump to start.
+     */
+    ds_reg = selector_table[ne_header->auto_data_seg-1].selector;
+    cs_reg = selector_table[ne_header->cs-1].selector;
+    ip_reg = ne_header->ip;
+    ss_reg = selector_table[ne_header->ss-1].selector;
+    sp_reg = ne_header->sp;
+
+    rv = CallTo16(cs_reg << 16 | ip_reg, ss_reg << 16 | sp_reg, ds_reg);
+    printf ("rv = %x\n", rv);
+}
+
+\f
+/**********************************************************************
+ *                                     GetImportedName
+ */
+char *
+GetImportedName(int fd, struct mz_header_s *mz_header, 
+               struct ne_header_s *ne_header, int name_offset, char *buffer)
+{
+    char *p;
+    int length;
+    int status;
+    int i;
+    
+    status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
+                  name_offset, SEEK_SET);
+    length = 0;
+    read(fd, &length, 1);  /* Get the length byte */
+    read(fd, buffer, length);
+    buffer[length] = 0;
+    return buffer;
+}
+
+/**********************************************************************
+ *                                     GetModuleName
+ */
+char *
+GetModuleName(int fd, struct mz_header_s *mz_header, 
+             struct ne_header_s *ne_header, int index, char *buffer)
+{
+    char *p;
+    int length;
+    int name_offset, status;
+    int i;
+    
+    status = lseek(fd, mz_header->ne_offset + ne_header->moduleref_tab_offset +
+                  2*(index - 1), SEEK_SET);
+    name_offset = 0;
+    read(fd, &name_offset, 2);
+    status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
+                  name_offset, SEEK_SET);
+    length = 0;
+    read(fd, &length, 1);  /* Get the length byte */
+    read(fd, buffer, length);
+    buffer[length] = 0;
+    return buffer;
+}
+
+\f
+/**********************************************************************
+ *                                     FixupSegment
+ */
+int
+FixupSegment(int fd, struct mz_header_s * mz_header,
+            struct ne_header_s *ne_header,
+            struct ne_segment_table_entry_s *seg_table, 
+            struct segment_descriptor_s *selector_table,
+            int segment_num)
+{
+    struct relocation_entry_s *rep, *rep1;
+    struct ne_segment_table_entry_s *seg;
+    struct segment_descriptor_s *sel;
+    struct dll_table_entry_s *dll_table;
+    unsigned short *sp;
+    unsigned int selector, address;
+    unsigned int next_addr;
+    int ordinal;
+    int status;
+    char dll_name[257];
+    char func_name[257];
+    int i, n_entries;
+
+    seg = &seg_table[segment_num];
+    sel = &selector_table[segment_num];
+
+    if (seg->seg_data_offset == 0)
+       return 0;
+
+    /*
+     * Go through the relocation table on entry at a time.
+     */
+    i = seg->seg_data_length;
+    if (i == 0)
+       i = 0x10000;
+
+    status = lseek(fd, seg->seg_data_offset * 512 + i, SEEK_SET);
+    n_entries = 0;
+    read(fd, &n_entries, sizeof(short int));
+    rep = (struct relocation_entry_s *)
+         malloc(n_entries * sizeof(struct relocation_entry_s));
+
+    if (read(fd,rep, n_entries * sizeof(struct relocation_entry_s)) !=
+        n_entries * sizeof(struct relocation_entry_s))
+    {
+       myerror("Unable to read relocation information");
+    }
+    
+    rep1 = rep;
+
+    for (i = 0; i < n_entries; i++, rep++)
+    {
+       /*
+        * Get the target address corresponding to this entry.
+        */
+       switch (rep->relocation_type)
+       {
+         case NE_RELTYPE_ORDINAL:
+           if (GetModuleName(fd, mz_header, ne_header, rep->target1,
+                             dll_name) == NULL)
+           {
+               return -1;
+           }
+           
+           dll_table = FindDLLTable(dll_name);
+           ordinal = rep->target2;
+           selector = dll_table[ordinal].selector;
+           address  = (unsigned int) dll_table[ordinal].address;
+#ifdef DEBUG_FIXUP
+           printf("%d: %s.%d: %04.4x:%04.4x\n", i + 1, dll_name, ordinal,
+                  selector, address);
+#endif
+           break;
+           
+         case NE_RELTYPE_NAME:
+           if (GetModuleName(fd, mz_header, ne_header, rep->target1, dll_name)
+               == NULL)
+           {
+               return -1;
+           }
+           dll_table = FindDLLTable(dll_name);
+
+           if (GetImportedName(fd, mz_header, ne_header, 
+                               rep->target2, func_name) == NULL)
+           {
+               return -1;
+           }
+           ordinal = FindOrdinalFromName(dll_table, func_name);
+           selector = dll_table[ordinal].selector;
+           address  = (unsigned int) dll_table[ordinal].address;
+#ifdef DEBUG_FIXUP
+           printf("%d: %s %s.%d: %04.4x:%04.4x\n", i + 1, func_name,
+                  dll_name, ordinal, selector, address);
+#endif
+           break;
+           
+         case NE_RELTYPE_INTERNAL:
+         default:
+           free(rep1);
+           return -1;
+       }
+
+       /*
+        * Stuff the right size result in.
+        */
+       sp = (unsigned short *) ((char *) sel->base_addr + rep->offset);
+       switch (rep->address_type)
+       {
+         case NE_RADDR_OFFSET16:
+           do {
+               next_addr = *sp;
+               *sp = (unsigned short) address;
+               sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
+           } 
+           while (next_addr != 0xffff);
+
+           break;
+           
+         case NE_RADDR_POINTER32:
+           do {
+               next_addr = *sp;
+               *sp     = (unsigned short) address;
+               *(sp+1) = (unsigned short) selector;
+               sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
+           } 
+           while (next_addr != 0xffff);
+
+           break;
+           
+         default:
+           free(rep1);
+           return -1;
+       }
+    }
+
+    free(rep1);
+    return 0;
+}
diff --git a/winetest/main.c b/winetest/main.c
new file mode 100755 (executable)
index 0000000..de7d738
--- /dev/null
@@ -0,0 +1,101 @@
+/*     MAIN.C\r
+ *\r
+ *     PURPOSE: \r
+ *\r
+ *     FUNCTIONS:\r
+ *          WinMain() - Initializes app, calls all other functions.\r
+ */\r
+\r
+#include <windows.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+/*\r
+ *     Globals\r
+ */\r
+char   szAppName[] = "WineTest";\r
+\r
+extern long FAR PASCAL WineTestWndProc(HWND hwnd, unsigned message,\r
+                                       WORD wParam, LONG lParam);\r
+/* extern void FAR __cdecl DebugPrintString(const char FAR *str); */\r
+\f\r
+/*                                             WinMain\r
+ */\r
+int PASCAL \r
+WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)\r
+{\r
+    DebugPrintString("Hello\n");\r
+\r
+    return 0;\r
+#if 0    \r
+    HWND       hwnd;\r
+    MSG                msg;\r
+    WNDCLASS   wndclass;\r
+\r
+    if (hPrevInstance)\r
+    {\r
+       MessageBox(NULL, "This application is already running.", szAppName, \r
+                       MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);\r
+       return NULL;\r
+    }\r
+\r
+    wndclass.style             = CS_HREDRAW | CS_VREDRAW;\r
+    wndclass.lpfnWndProc       = WineTestWndProc;\r
+    wndclass.cbClsExtra                = 0;\r
+    wndclass.cbWndExtra                = 0;\r
+    wndclass.hInstance         = hInstance;\r
+    wndclass.hIcon             = LoadIcon(NULL, IDI_APPLICATION);\r
+    wndclass.hCursor           = LoadCursor(NULL, IDC_ARROW);\r
+    wndclass.hbrBackground     = GetStockObject(WHITE_BRUSH);\r
+    wndclass.lpszMenuName      = "MainMenu";\r
+    wndclass.lpszClassName     = szAppName;\r
+\r
+    RegisterClass(&wndclass);\r
+\r
+    hwnd = CreateWindow(szAppName, "Wine Tester",\r
+                       WS_OVERLAPPEDWINDOW,\r
+                       CW_USEDEFAULT,\r
+                       CW_USEDEFAULT,\r
+                       CW_USEDEFAULT,\r
+                       CW_USEDEFAULT,\r
+                       NULL, \r
+                       NULL,\r
+                       hInstance, \r
+                       NULL);\r
+    ShowWindow(hwnd, cmdShow);\r
+    UpdateWindow(hwnd);\r
+\r
+    while (GetMessage(&msg, NULL, NULL, NULL))\r
+    {\r
+        TranslateMessage((LPMSG) &msg);\r
+       DispatchMessage((LPMSG) &msg);\r
+    }\r
+\r
+    return msg.wParam;\r
+#endif /* 0 */\r
+}\r
+\r
+\f\r
+/*                                             WineTestWndProc\r
+ */\r
+long FAR PASCAL \r
+WineTestWndProc(HWND hwnd, unsigned message, WORD wParam, LONG lParam)\r
+{\r
+    static HANDLE hInstance;\r
+    FARPROC DlgProcInst;\r
+    LONG parm;\r
+\r
+    switch (message)\r
+    {\r
+       case WM_CREATE:\r
+           hInstance = ((LPCREATESTRUCT) lParam)->hInstance;\r
+           return 0;\r
+\r
+        case WM_DESTROY:\r
+            PostQuitMessage(0);\r
+            return 0;\r
+    }\r
+\r
+    return DefWindowProc(hwnd, message, wParam, lParam);\r
+}\r
diff --git a/winetest/makefile b/winetest/makefile
new file mode 100755 (executable)
index 0000000..5f111dd
--- /dev/null
@@ -0,0 +1,47 @@
+####################################################################\r
+#\r
+#   PPI standard windows makefile\r
+#\r
+####################################################################\r
+\r
+####################################################################\r
+#\r
+#   Compiler options\r
+#\r
+AFLAGS=/ML /LA\r
+CFLAGS=-AM -Ozaxb2 -Gr -G2 -Zpei -W3 -DWINVER=0x0301\r
+LFLAGS=/CO\r
+\r
+####################################################################\r
+#\r
+#   Object files and target\r
+#\r
+OBJS=main.obj\r
+DIALOGS=\r
+TARGET=winetest\r
+\r
+####################################################################\r
+#\r
+#   Standard rules\r
+#\r
+ROOTS=$(OBJS:.obj=)\r
+\r
+all: $(TARGET).exe\r
+\r
+version:\r
+       coall -r$(RELEASE)\r
+       $(MAKE) all\r
+\r
+$(TARGET).res: $(TARGET).rc $(TARGET).h $(DIALOGS)\r
+       rc -r $(TARGET).rc\r
+\r
+$(TARGET).exe: $(TARGET).res $(TARGET).def $(TARGET).h $(OBJS)\r
+        link @<<\r
+$(ROOTS) /NOD $(LFLAGS)\r
+$@\r
+$(TARGET) /MAP:FULL\r
+libw slibcewn oldnames\r
+$(TARGET).def\r
+<<\r
+       rc -30 $(TARGET).res\r
+\r
diff --git a/winetest/winetest.def b/winetest/winetest.def
new file mode 100755 (executable)
index 0000000..bd9dbcc
--- /dev/null
@@ -0,0 +1,11 @@
+NAME        WINETEST\r
+\r
+DESCRIPTION  'Wine Tester'\r
+EXETYPE      WINDOWS\r
+STUB        'WINSTUB.EXE'\r
+CODE        PRELOAD MOVEABLE DISCARDABLE\r
+DATA        PRELOAD MOVEABLE SINGLE \r
+HEAPSIZE     8192\r
+STACKSIZE    8192\r
+EXPORTS      WineTestWndProc\r
+IMPORTS      UNIXLIB._DebugPrintString\r
diff --git a/winetest/winetest.h b/winetest/winetest.h
new file mode 100755 (executable)
index 0000000..c280412
--- /dev/null
@@ -0,0 +1,2 @@
+/*  $Id$\r
+ */\r
diff --git a/winetest/winetest.rc b/winetest/winetest.rc
new file mode 100755 (executable)
index 0000000..af8228e
--- /dev/null
@@ -0,0 +1,11 @@
+#include <windows.h>\r
+\r
+MainMenu MENU\r
+BEGIN\r
+    POPUP "&File"\r
+    BEGIN\r
+        MENUITEM "E&xit",                      100\r
+        MENUITEM SEPARATOR\r
+        MENUITEM "&About...",                  101\r
+    END\r
+END\r