wine/loader/dos/module.c

314 lines
9.5 KiB
C
Raw Normal View History

Release 980809 Sat Aug 8 19:11:46 1998 Marcus Meissner <marcus@jet.franken.de> * [*/*] Added some missing WINAPI and some missing prototypes for functions. * [controls/static.c] Got rid of the MODULE32_LookupHMODULE error showing up for every message box. * [windows/winproc.c] WM_NOTIFY 16->32 mapping (AOL Instant Messenger or however it is called). * [misc/winsock.c] hostent/servent/protoent should not use the same static buffers. (has broken nt3.15 finger.exe which does hp=gethostbyname(), then getservbyname("finger","tcp") and the references hp->h_addr_list[0]). Sat Aug 8 13:21:24 1998 Alexandre Julliard <julliard@lrc.epfl.ch> * [include/server.h] [tools/make_requests] [server/request.c] [server/trace.c] Automated part of the client/server request code generation. Added tracing of client/server communication. * [scheduler/*.c] [server/process.c] Added support for server-side handles. * [scheduler/thread.c] Added DLL_THREAD_ATTACH/DETACH notifications. * [configure.in] Added check for -lsocket. * [windows/winproc.c] Return the thunk address in WINPROC_GetProc if the function types don't match. Sat Aug 8 02:44:04 1998 Douglas Ridgway <ridgway@winehq.com> * [windows/winproc.c][windows/win.c][windows/message.c] Documentation for CallWindowProc, SetWindowLong, DispatchMessage, WaitMessage, GetMessage, and PeekMessage. Sat Aug 8 01:00:00 1998 Juergen Schmied <juergen.schmied@metronet.de> * [controls/commctrl.c][controls/widgets.c][include/builtin32.h] [include/commctrl.h][relay32/builtin32.c][relay32/comctl32.spec] [tools/build.c] [relay32/shell32.spec] Added the functionality of the LibMain function. The common controls are properly initialized now. * [controls/treeview.c][memory/atom.c][scheduler/thread.c][windows/class.c] [windows/msgbox.c][windows/win.c] Put TRACE in, put SetLastError() in. * [include/interfaces.h] Added IClassFactory::LockServer. * [include/ole2.h] Added struct for LPOLEMENUGROUPWIDTHS32, HOLEMENU32. * [include/shell.h][include/shlobj.h][misc/shell.c][ole/folders.c] Reorganized and many structs and classes (IShellBrowser,IShellView) added. shell32.dll should work in many cases now. Started SHGetFileInfoA implementeation, rewrote SHGetPathFromIDList32A. New Shell32LibMain started ShellIconCache Implementation. * [misc/shellord.c] Rewrote ILCombine, ILGetSize New stubs SHFind_InitMenuPopup, FileMenu_Create, ShellExecuteEx, SHSetInstanceExplorer, SHGetInstanceExplorer, SHFreeUnusedLibraries. * [include/winerror.h] Class and window related error codes added. * [memory/heap.c] Changed lstrlen32A to strlen to get rid of milions of TRACE lines. * [misc/ddeml.c] First lines for DdeCreateStringHandle32A / DdeFreeStringHandle32. * [misc/network.c][relay32/mpr.spec] Fixed some bugs, changed ordinals. * [windows/class.c] Workarounds for incorrect hInstance handling. Fixes parts of MSWord95/Excel95 and Money95. Thu Aug 6 21:05:35 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de> * [windows/nonclient.c][misc/tweak.c][include/tweak.h] [documentation/win95look] Removed some tweak variables. They are no longer needed. * [files/dos_fs.c] Added check for null pointer in DOSFS_GetDevice(). * [controls/tooltips.c][include/commctrl.h] Improved tooltips. * [controls/status.c][include/commctrl.h] Cleaned up code and added tooltip support. * [controls/toolbar.c][include/commctrl.h] Added tooltip support. * [documentation/common_controls] Updated. Thu Aug 6 00:05:22 1998 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de> * [include/ver.h] [misc/ver.c] Write VIF_BUFFTOOSMALL, not VIF_BUFTOSMALL. * [debugger/hash.c] [debugger/stabs.c] Make debug output more friendly for posting. * [files/file.c] Partial implementation of OF_SHARE_EXCLUSIVE. Needed for Quicklogic/QuickChip (InstallShield). * [files/profile.c] When a cached-only entry is found, return it. * [graphics/x11drv/xfont.c] Accept a space as delimiter for a fontname and inhibit overrun (Make xplasim.ex from the Phillips Coolrunner CPLD suite proceed). * [miscemu/main.c] Delay setting IF1632_CallLargeStack after loading the executables. Stops fpgaexp.exe from the Viewlogic FPGA suite from crashing when showing the Blinker error Message Box. * [misc/network.c] Make WNetGetConnection16 recognise a CDROM as a local drive. * [multimedia/mmsystem.c] Preliminary check for MCI_ALL_DEVICE_ID in MCI_Close by a FIXME. Tue Aug 4 21:15:23 1998 James Juran <jrj120@psu.edu> * [ole/ole2nls.c] Fixed bug in CompareString32A. strcmp() doesn't necessarily return -1, 0, or 1, which the previous code depended on. Changed name of is_punctuation to OLE2NLS_isPunctuation. Made NORM_IGNOREWIDTH not print a FIXME message in LCMapString32A. Other debugging messages, documentation, and code cleanups. * [objects/font.c] [relay32/gdi32.spec] [include/winerror.h] Added stub for GetFontData32, and added GDI_ERROR constant to winerror.h. Tue Aug 4 07:44:43 1998 Ove Kaaven <ovek@arcticnet.no> * [multimedia/mmio.c] Implemented mmioSetBuffer, mmioAdvance, mmioAscend, and mmioCreateChunk to the best of my knowledge. But watch out, there's bound to be bugs in there... * [include/mmsystem.h] [multimedia/mmsystem.c] Hacked in support for 32-bit multimedia function callbacks. * [AUTHORS] [misc/shell.c] Selfishly credited my authorship. Hopefully I'm excused. * [include/dosexe.h] [include/module.h] [loader/dos/*] [loader/module.c] [loader/task.c] [Makefile.in] [configure.in] [Makefile.in] Added DOS EXE (MZ) loader and virtual machine. Task structure integration thanks to Ulrich Weigand. * [files/dos_fs.c] Work around a null pointer dereference if ioctlGetDeviceInfo-ing a FILE_DupUnixHandle'd file (i.e. GetStdHandle'd). * [include/miscemu.h] [include/winnt.h] [loader/main.c] [memory/global.c] [msdos/dpmi.c] [msdos/dosmem.c] Added support for DOS memory images, and added DOSMEM_ResizeBlock() and DOSMEM_Available(). * [msdos/int21.c] Added support for the DOS virtual machine, tweaked handle assignment to avoid stdio clashes, forced INT21_FindNext to exit wildcardless searches after finding one entry, added AH=7, 8, 9, C, 48, 49, 4A, and 7160 CL=1 (Get Short Filename), and made the long filename calls only respond if running with with -winver win95. * [objects/cursoricon.c] DestroyCursor32 and DestroyIcon32 should now free the objects (hopefully) correctly. Sun Aug 2 21:42:09 1998 Huw D M Davies <daviesh@abacus.physics.ox.ac.uk> * [graphics/psdrv/*] [include/psdrv.h] Added PPD file parsing - at the moment it reads a file called default.ppd from the directory in which you start Wine. Page sizes other than A4 should now work (landscape may not). All fonts that are present on your printer (according to the PPD) should be available, providing you have the AFM files. Fonts should now be the correct size. Graphics is still basically lines only. See graphics/psdrv/README . * [misc/printdrv.c] Yet more Drv[Get/Set]PrinterData fixes. Fri Jul 31 21:33:22 1998 Per Lindström <pelinstr@algonet.se> * [relay32/crtdll.spec] [misc/crtdll.c] Added stub for freopen, _findfirst, _findnext, _fstat and _read. * [files/directory.c] Modified warning message. Wed Jul 29 11:25:28 1998 Luiz Otavio L. Zorzella <zorzella@nr.conexware.com> * [objects/font.c] Added stub for GetFontData. * [multimedia/msvideo.c] Created this file to hold the msvideo.dll calls (and maybe also msvfw32.dll). * [objects/cursoricon.c] Added search in Global Heap for cursor when trying to destroy it with DestroyCursor16. This test should be done in many (all?) other functions that use FreeResource. * [controls/treeview.c] [include/commctrl.h] Minor correction in name and addition of many placeholders for TVM messages in TREEVIEW_WindowProc. * [msdos/dpmi.c] Fixed a bug in DPMI_xrealloc where in a copy of a memory region "A" of size "a" to a region "B" of size "b", "b" bytes were being copied, instead of "a", as the new version does. This both increases speed, as well as avoids segfaults.
1998-08-09 12:47:43 +00:00
/*
* DOS (MZ) loader
*
* Copyright 1998 Ove K<EFBFBD>ven
*/
#ifdef linux
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef MZ_USESYSV
#include <sys/ipc.h>
#include <sys/shm.h>
#else
#include <sys/mman.h>
#endif
#include <sys/vm86.h>
#ifdef MZ_USESYSV
#include <linux/mm.h> /* FIXME: where else should I fetch the PAGE_SIZE define? */
#endif
#include "windows.h"
#include "winbase.h"
#include "module.h"
#include "task.h"
#include "ldt.h"
#include "process.h"
#include "miscemu.h"
#include "debug.h"
#include "dosexe.h"
#define BIOS_DATA_SEGMENT 0x40
#define BIOS_SEGMENT BIOSSEG /* BIOSSEG is defined to 0xf000 in sys/vm86.h */
#define STUB_SEGMENT BIOS_SEGMENT
#ifdef MZ_USESYSV
/* it might be that SYSV supports START_OFFSET 0 after all, haven't checked */
#define START_OFFSET PAGE_SIZE
#else
#define START_OFFSET 0
#endif
#define PSP_SIZE 0x10
#define SEG16(ptr,seg) ((LPVOID)((BYTE*)ptr+((DWORD)(seg)<<4)))
#define SEGPTR16(ptr,segptr) ((LPVOID)((BYTE*)ptr+((DWORD)SELECTOROF(segptr)<<4)+OFFSETOF(segptr)))
#define STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
static void MZ_InitSystem( LPVOID lpImage )
{
SEGPTR*isr=lpImage;
DWORD*stub=SEG16(lpImage,STUB_SEGMENT);
int x;
/* initialize ISR table to make it point to INT stubs in BIOSSEG;
Linux only sends INTs performed from or destined to BIOSSEG at us,
if the int_revectored table is empty.
This allows DOS programs to hook interrupts, as well as use their
familiar retf tricks to call them... */
/* (note that the hooking might not actually work since DOS3Call stuff
isn't fully integrated with the DOS VM yet...) */
TRACE(module,"Initializing interrupt vector table\n");
for (x=0; x<256; x++) isr[x]=PTR_SEG_OFF_TO_SEGPTR(STUB_SEGMENT,x*4);
TRACE(module,"Initializing interrupt stub table\n");
for (x=0; x<256; x++) stub[x]=STUB(x);
}
static void MZ_InitPSP( LPVOID lpPSP, LPCSTR cmdline, LPCSTR env )
{
PDB*psp=lpPSP;
const char*cmd=cmdline?strchr(cmdline,' '):NULL;
psp->int20=0x20CD; /* int 20 */
/* some programs use this to calculate how much memory they need */
psp->nextParagraph=0x9FFF;
/* copy parameters */
if (cmd) {
while (*cmd == ' ') cmd++;
psp->cmdLine[0]=strlen(cmd);
strcpy(psp->cmdLine+1,cmd);
psp->cmdLine[psp->cmdLine[0]+1]='\r';
} else psp->cmdLine[1]='\r';
/* FIXME: integrate the memory stuff from Wine (msdos/dosmem.c) */
/* FIXME: integrate the PDB stuff from Wine (loader/task.c) */
}
static int MZ_LoadImage( HFILE16 hFile, LPCSTR cmdline, LPCSTR env, LPDOSTASK lpDosTask )
{
IMAGE_DOS_HEADER mz_header;
DWORD image_start,image_size,min_size,max_size,avail;
WORD psp_seg,load_seg;
BYTE*psp_start,*load_start;
int x;
SEGPTR reloc;
if ((_hread16(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
(mz_header.e_magic != IMAGE_DOS_SIGNATURE))
return 11; /* invalid exe */
/* calculate load size */
image_start=mz_header.e_cparhdr<<4;
image_size=mz_header.e_cp<<9; /* pages are 512 bytes */
if ((mz_header.e_cblp!=0)&&(mz_header.e_cblp!=4)) image_size-=512-mz_header.e_cblp;
image_size-=image_start;
min_size=image_size+((DWORD)mz_header.e_minalloc<<4)+(PSP_SIZE<<4);
max_size=image_size+((DWORD)mz_header.e_maxalloc<<4)+(PSP_SIZE<<4);
/* allocate 1MB+64K shared memory */
lpDosTask->img_ofs=START_OFFSET;
#ifdef MZ_USESYSV
lpDosTask->key=ftok(".",'d'); /* FIXME: this is from my IPC intro doc */
lpDosTask->shm_id=shmget(lpDosTask->key,0x110000-START_OFFSET,IPC_CREAT|SHM_R|SHM_W);
lpDosTask->img=shmat(lpDosTask->shm_id,NULL,0);
#else
tmpnam(lpDosTask->mm_name);
/* strcpy(lpDosTask->mm_name,"/tmp/mydosimage"); */
lpDosTask->mm_fd=open(lpDosTask->mm_name,O_RDWR|O_CREAT /* |O_TRUNC */,S_IRUSR|S_IWUSR);
if (lpDosTask->mm_fd<0) ERR(module,"file %s could not be opened\n",lpDosTask->mm_name);
/* expand file to 1MB+64K */
lseek(lpDosTask->mm_fd,0x110000-1,SEEK_SET);
x=0; write(lpDosTask->mm_fd,&x,1);
/* map it in */
lpDosTask->img=mmap(NULL,0x110000-START_OFFSET,PROT_READ|PROT_WRITE,MAP_SHARED,lpDosTask->mm_fd,0);
#endif
if (lpDosTask->img==(LPVOID)-1) {
ERR(module,"could not map shared memory, error=%s\n",strerror(errno));
return 0;
}
TRACE(module,"DOS VM86 image mapped at %08lx\n",(DWORD)lpDosTask->img);
/* initialize the memory */
MZ_InitSystem(lpDosTask->img);
TRACE(module,"Initializing DOS memory structures\n");
DOSMEM_Init(lpDosTask->hModule);
/* FIXME: allocate memory for environment variables */
/* allocate memory for the executable */
TRACE(module,"Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size);
avail=DOSMEM_Available(lpDosTask->hModule);
if (avail<min_size) {
ERR(module, "insufficient DOS memory\n");
return 0;
}
if (avail>max_size) avail=max_size;
psp_start=DOSMEM_GetBlock(lpDosTask->hModule,avail,&psp_seg);
if (!psp_start) {
ERR(module, "error allocating DOS memory\n");
return 0;
}
load_seg=psp_seg+PSP_SIZE;
load_start=psp_start+(PSP_SIZE<<4);
MZ_InitPSP(psp_start, cmdline, env);
/* load executable image */
TRACE(module,"loading DOS EXE image size, %08lx bytes\n",image_size);
_llseek16(hFile,image_start,FILE_BEGIN);
if ((_hread16(hFile,load_start,image_size)) != image_size)
return 11; /* invalid exe */
/* load relocation table */
TRACE(module,"loading DOS EXE relocation table, %d entries\n",mz_header.e_lfarlc);
/* FIXME: is this too slow without read buffering? */
_llseek16(hFile,mz_header.e_lfarlc,FILE_BEGIN);
for (x=0; x<mz_header.e_crlc; x++) {
if (_lread16(hFile,&reloc,sizeof(reloc)) != sizeof(reloc))
return 11; /* invalid exe */
*(WORD*)SEGPTR16(load_start,reloc)+=load_seg;
}
/* initialize vm86 struct */
memset(&lpDosTask->VM86,0,sizeof(lpDosTask->VM86));
lpDosTask->VM86.regs.cs=load_seg+mz_header.e_cs;
lpDosTask->VM86.regs.eip=mz_header.e_ip;
lpDosTask->VM86.regs.ss=load_seg+mz_header.e_ss;
lpDosTask->VM86.regs.esp=mz_header.e_sp;
lpDosTask->VM86.regs.ds=psp_seg;
lpDosTask->VM86.regs.es=psp_seg;
/* hmm, what else do we need? */
return 32;
}
static int MZ_InitTask( LPDOSTASK lpDosTask )
{
int read_fd[2],write_fd[2];
pid_t child;
/* create read pipe */
if (pipe(read_fd)<0) return 0;
if (pipe(write_fd)<0) {
close(read_fd[0]); close(read_fd[1]); return 0;
}
lpDosTask->read_pipe=read_fd[0];
lpDosTask->write_pipe=write_fd[1];
lpDosTask->fn=VM86_ENTER;
lpDosTask->state=1;
TRACE(module,"Preparing to load DOS EXE support module: forking\n");
if ((child=fork())<0) {
close(write_fd[0]); close(write_fd[1]);
close(read_fd[0]); close(read_fd[1]); return 0;
}
if (child!=0) {
/* parent process */
close(read_fd[1]); close(write_fd[0]);
lpDosTask->task=child;
} else {
/* child process */
close(read_fd[0]); close(write_fd[1]);
/* put our pipes somewhere dosmod can find them */
dup2(write_fd[0],0); /* stdin */
dup2(read_fd[1],1); /* stdout */
/* now load dosmod */
execlp("dosmod",lpDosTask->mm_name,NULL);
execl("dosmod",lpDosTask->mm_name,NULL);
execl("loader/dos/dosmod",lpDosTask->mm_name,NULL);
/* if failure, exit */
ERR(module,"Failed to spawn dosmod, error=%s\n",strerror(errno));
exit(1);
}
return 32;
}
HINSTANCE16 MZ_LoadModule( LPCSTR name, LPCSTR cmdline,
LPCSTR env, UINT16 show_cmd )
{
LPDOSTASK lpDosTask;
HMODULE16 hModule;
HINSTANCE16 hInstance;
NE_MODULE *pModule;
HFILE16 hFile;
OFSTRUCT ofs;
PROCESS_INFORMATION info;
int err;
if ((lpDosTask = calloc(1, sizeof(DOSTASK))) == NULL)
return 0;
if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16)
return 2; /* File not found */
if ((hModule = MODULE_CreateDummyModule(&ofs)) < 32)
return hModule;
lpDosTask->hModule = hModule;
pModule = (NE_MODULE *)GlobalLock16(hModule);
pModule->lpDosTask = lpDosTask;
lpDosTask->img=NULL; lpDosTask->mm_name[0]=0; lpDosTask->mm_fd=-1;
err = MZ_LoadImage( hFile, cmdline, env, lpDosTask );
_lclose16(hFile);
if (err<32) {
if (lpDosTask->img!=NULL) munmap(lpDosTask->img,0x110000-START_OFFSET);
if (lpDosTask->mm_fd>=0) close(lpDosTask->mm_fd);
if (lpDosTask->mm_name[0]!=0) unlink(lpDosTask->mm_name);
return err;
}
MZ_InitTask( lpDosTask );
hInstance = NE_CreateInstance(pModule, NULL, (cmdline == NULL));
PROCESS_Create( pModule, cmdline, env, hInstance, 0, show_cmd, &info );
/* we don't need the handles for now */
CloseHandle( info.hThread );
CloseHandle( info.hProcess );
return hInstance;
}
void MZ_KillModule( LPDOSTASK lpDosTask )
{
munmap(lpDosTask->img,0x110000-START_OFFSET);
close(lpDosTask->mm_fd);
unlink(lpDosTask->mm_name);
close(lpDosTask->read_pipe);
close(lpDosTask->write_pipe);
kill(lpDosTask->task,SIGTERM);
}
int MZ_RunModule( LPDOSTASK lpDosTask )
{
/* transmit the current context structure to the DOS task */
if (lpDosTask->state==1) {
if (write(lpDosTask->write_pipe,&lpDosTask->fn,sizeof(lpDosTask->fn))!=sizeof(lpDosTask->fn))
return -1;
if (write(lpDosTask->write_pipe,&lpDosTask->VM86,sizeof(lpDosTask->VM86))!=sizeof(lpDosTask->VM86))
return -1;
lpDosTask->state=2;
}
/* wait for another context structure to appear (this may block) */
if (lpDosTask->state==2) {
if (read(lpDosTask->read_pipe,&lpDosTask->fn,sizeof(lpDosTask->fn))!=sizeof(lpDosTask->fn)) {
if ((errno==EINTR)||(errno==EAGAIN)) return 0;
return -1;
}
lpDosTask->state=3;
}
if (lpDosTask->state==3) {
if (read(lpDosTask->read_pipe,&lpDosTask->VM86,sizeof(lpDosTask->VM86))!=sizeof(lpDosTask->VM86)) {
if ((errno==EINTR)||(errno==EAGAIN)) return 0;
return -1;
}
/* got one */
lpDosTask->state=1;
return 1;
}
return 0;
}
#endif /* linux */