Skip to content
Snippets Groups Projects
Commit 2c25c3e9 authored by Alexandre Julliard's avatar Alexandre Julliard
Browse files

Release 0.0.2

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.
parents
No related branches found
No related tags found
No related merge requests found
/* $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();
/**********************************************************************
* GetDOSEnvironment
*/
void *
GetDOSEnvironment()
{
return SelectorTable[EnvironmentSelectorIdx].base_addr;
}
/**********************************************************************
* 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");
}
}
/**********************************************************************
* 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");
}
}
/**********************************************************************
* 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;
}
test.exe 0 → 100755
File added
name unixlib
id 4
length 256
1 c _DebugPrintString(ptr) DebugPrintString(1)
\ No newline at end of file
user.c 0 → 100644
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;
}
name user
id 2
length 256
5 pascal InitApp(word) USER_InitApp(1)
\ No newline at end of file
wine 0 → 100755
File added
wine.c 0 → 100644
/* $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);
}
/**********************************************************************
* 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);
}
/**********************************************************************
* 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;
}
/**********************************************************************
* 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;
}
/* MAIN.C
*
* PURPOSE:
*
* FUNCTIONS:
* WinMain() - Initializes app, calls all other functions.
*/
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/*
* Globals
*/
char szAppName[] = "WineTest";
extern long FAR PASCAL WineTestWndProc(HWND hwnd, unsigned message,
WORD wParam, LONG lParam);
/* extern void FAR __cdecl DebugPrintString(const char FAR *str); */
/* WinMain
*/
int PASCAL
WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
{
DebugPrintString("Hello\n");
return 0;
#if 0
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
if (hPrevInstance)
{
MessageBox(NULL, "This application is already running.", szAppName,
MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
return NULL;
}
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WineTestWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = "MainMenu";
wndclass.lpszClassName = szAppName;
RegisterClass(&wndclass);
hwnd = CreateWindow(szAppName, "Wine Tester",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, cmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage((LPMSG) &msg);
DispatchMessage((LPMSG) &msg);
}
return msg.wParam;
#endif /* 0 */
}
/* WineTestWndProc
*/
long FAR PASCAL
WineTestWndProc(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
{
static HANDLE hInstance;
FARPROC DlgProcInst;
LONG parm;
switch (message)
{
case WM_CREATE:
hInstance = ((LPCREATESTRUCT) lParam)->hInstance;
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
####################################################################
#
# PPI standard windows makefile
#
####################################################################
####################################################################
#
# Compiler options
#
AFLAGS=/ML /LA
CFLAGS=-AM -Ozaxb2 -Gr -G2 -Zpei -W3 -DWINVER=0x0301
LFLAGS=/CO
####################################################################
#
# Object files and target
#
OBJS=main.obj
DIALOGS=
TARGET=winetest
####################################################################
#
# Standard rules
#
ROOTS=$(OBJS:.obj=)
all: $(TARGET).exe
version:
coall -r$(RELEASE)
$(MAKE) all
$(TARGET).res: $(TARGET).rc $(TARGET).h $(DIALOGS)
rc -r $(TARGET).rc
$(TARGET).exe: $(TARGET).res $(TARGET).def $(TARGET).h $(OBJS)
link @<<
$(ROOTS) /NOD $(LFLAGS)
$@
$(TARGET) /MAP:FULL
libw slibcewn oldnames
$(TARGET).def
<<
rc -30 $(TARGET).res
NAME WINETEST
DESCRIPTION 'Wine Tester'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 8192
STACKSIZE 8192
EXPORTS WineTestWndProc
IMPORTS UNIXLIB._DebugPrintString
/* $Id$
*/
#include <windows.h>
MainMenu MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", 100
MENUITEM SEPARATOR
MENUITEM "&About...", 101
END
END
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment