Moved some system dependencies to loader/dos/dosvm.c. Implemented
environmental argv[0] passing to DOS apps. Added XMS hooks.

diff --git a/include/dosexe.h b/include/dosexe.h
index 04d9ffb..a7fb8cc 100644
--- a/include/dosexe.h
+++ b/include/dosexe.h
@@ -6,20 +6,16 @@
 
 #ifdef linux
 
-#include <unistd.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/vm86.h>
 #include "wintypes.h"
 
 typedef struct _DOSTASK {
  LPVOID img;
  unsigned img_ofs;
  WORD psp_seg,load_seg;
+ WORD init_cs,init_ip,init_ss,init_sp;
+ WORD xms_seg;
  WORD dpmi_seg,dpmi_sel,dpmi_flag;
  HMODULE16 hModule;
- struct vm86plus_struct VM86;
- int fn, state;
  char mm_name[128];
  int mm_fd;
  int read_pipe,write_pipe;
@@ -30,9 +26,7 @@
 
 extern int MZ_InitTask( LPDOSTASK lpDosTask );
 extern int MZ_InitMemory( LPDOSTASK lpDosTask, NE_MODULE *pModule );
-extern int MZ_RunModule( LPDOSTASK lpDosTask );
 extern void MZ_KillModule( LPDOSTASK lpDosTask );
-extern int DOSVM_Process( LPDOSTASK lpDosTask );
 
 #endif /* linux */
 
diff --git a/include/miscemu.h b/include/miscemu.h
index a9cb741..8728ac4 100644
--- a/include/miscemu.h
+++ b/include/miscemu.h
@@ -59,9 +59,12 @@
 /* msdos/int2f.c */
 extern void WINAPI INT_Int2fHandler(CONTEXT*);
 
-/* msdos/int31.c */
+/* msdos/dpmi.c */
 extern void WINAPI INT_Int31Handler(CONTEXT*);
 
+/* msdos/xms.c */
+extern void WINAPI XMS_Handler(CONTEXT*);
+
 /* loader/signal.c */
 extern BOOL32 SIGNAL_Init(void);
 extern void SIGNAL_SetHandler( int sig, void (*func)(), int flags );
diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c
index 2223a08..93d8338 100644
--- a/loader/dos/dosvm.c
+++ b/loader/dos/dosvm.c
@@ -21,6 +21,7 @@
 #include "msdos.h"
 #include "miscemu.h"
 #include "debug.h"
+#include "debugger.h"
 #include "module.h"
 #include "task.h"
 #include "ldt.h"
@@ -28,19 +29,23 @@
 
 #ifdef MZ_SUPPORTED
 
-static void DOSVM_Dump( LPDOSTASK lpDosTask)
+#include <sys/mman.h>
+#include <sys/vm86.h>
+
+static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn,
+                        struct vm86plus_struct*VM86 )
 {
  unsigned iofs;
  BYTE*inst;
  int x;
 
- switch (VM86_TYPE(lpDosTask->fn)) {
+ switch (VM86_TYPE(fn)) {
   case VM86_SIGNAL:
    printf("Trapped signal\n"); break;
   case VM86_UNKNOWN:
    printf("Trapped unhandled GPF\n"); break;
   case VM86_INTx:
-   printf("Trapped INT %02x\n",VM86_ARG(lpDosTask->fn)); break;
+   printf("Trapped INT %02x\n",VM86_ARG(fn)); break;
   case VM86_STI:
    printf("Trapped STI\n"); break;
   case VM86_PICRETURN:
@@ -48,7 +53,7 @@
   case VM86_TRAP:
    printf("Trapped debug request\n"); break;
  }
-#define REGS lpDosTask->VM86.regs
+#define REGS VM86->regs
  fprintf(stderr,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS.eax,REGS.ebx,REGS.ecx,REGS.edx);
  fprintf(stderr,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS.esi,REGS.edi,REGS.esp,REGS.ebp);
  fprintf(stderr,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS.cs,REGS.ds,REGS.es,REGS.ss);
@@ -77,27 +82,28 @@
            CP(ss,SegSs); CP(fs,SegFs); CP(gs,SegGs); \
            CP(eip,Eip); CP(eflags,EFlags)
 
-int DOSVM_Process( LPDOSTASK lpDosTask )
+static int DOSVM_Process( LPDOSTASK lpDosTask, int fn,
+                          struct vm86plus_struct*VM86 )
 {
  CONTEXT context;
  int ret=0;
 
-#define CP(x,y) context.y = lpDosTask->VM86.regs.x
+#define CP(x,y) context.y = VM86->regs.x
  CV;
 #undef CP
  (void*)V86BASE(&context)=lpDosTask->img;
 
- switch (VM86_TYPE(lpDosTask->fn)) {
+ switch (VM86_TYPE(fn)) {
   case VM86_SIGNAL:
    printf("Trapped signal\n");
    ret=-1; break;
   case VM86_UNKNOWN: /* unhandled GPF */
-   DOSVM_Dump(lpDosTask);
+   DOSVM_Dump(lpDosTask,fn,VM86);
    ctx_debug(SIGSEGV,&context);
    break;
   case VM86_INTx:
-   TRACE(int,"DOS EXE calls INT %02x with AX=%04lx\n",VM86_ARG(lpDosTask->fn),context.Eax);
-   ret=DOSVM_Int(VM86_ARG(lpDosTask->fn),&context); break;
+   TRACE(int,"DOS EXE calls INT %02x with AX=%04lx\n",VM86_ARG(fn),context.Eax);
+   ret=DOSVM_Int(VM86_ARG(fn),&context); break;
   case VM86_STI:
    break;
   case VM86_PICRETURN:
@@ -106,11 +112,10 @@
    ctx_debug(SIGTRAP,&context);
    break;
   default:
-   DOSVM_Dump(lpDosTask);
+   DOSVM_Dump(lpDosTask,fn,VM86);
  }
 
- lpDosTask->fn=VM86_ENTER;
-#define CP(x,y) lpDosTask->VM86.regs.x = context.y
+#define CP(x,y) VM86->regs.x = context.y
  CV;
 #undef CP
  return ret;
@@ -121,6 +126,7 @@
  TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
  NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
  LPDOSTASK lpDosTask;
+ struct vm86plus_struct VM86;
  int stat;
 
  GlobalUnlock16( GetCurrentTask() );
@@ -147,18 +153,47 @@
  } else lpDosTask=pModule->lpDosTask;
 
  if (context) {
-#define CP(x,y) lpDosTask->VM86.regs.x = context->y
+#define CP(x,y) VM86.regs.x = context->y
   CV;
 #undef CP
+ } else {
+/* initial setup */
+  memset(&VM86,0,sizeof(VM86));
+  VM86.regs.cs=lpDosTask->init_cs;
+  VM86.regs.eip=lpDosTask->init_ip;
+  VM86.regs.ss=lpDosTask->init_ss;
+  VM86.regs.esp=lpDosTask->init_sp;
+  VM86.regs.ds=lpDosTask->psp_seg;
+  VM86.regs.es=lpDosTask->psp_seg;
+  /* hmm, what else do we need? */
  }
 
- /* main loop */
- while ((stat = MZ_RunModule(lpDosTask)) >= 0)
-  if (stat > 0 && DOSVM_Process(lpDosTask) < 0)
-   break;
+ /* main exchange loop */
+ stat = VM86_ENTER;
+ do {
+  /* transmit VM86 structure to dosmod task */
+  if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat))
+   return -1;
+  if (write(lpDosTask->write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86))
+   return -1;
+  /* wait for response */
+  do {
+   if (read(lpDosTask->read_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
+    if ((errno==EINTR)||(errno==EAGAIN)) continue;
+    return -1;
+   }
+  } while (0);
+  do {
+   if (read(lpDosTask->read_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) {
+    if ((errno==EINTR)||(errno==EAGAIN)) continue;
+    return -1;
+   }
+  } while (0);
+  /* got response */
+ } while (DOSVM_Process(lpDosTask,stat,&VM86)>=0);
 
  if (context) {
-#define CP(x,y) context->y = lpDosTask->VM86.regs.x
+#define CP(x,y) context->y = VM86.regs.x
   CV;
 #undef CP
  }
diff --git a/loader/dos/module.c b/loader/dos/module.c
index c0f7e85..9573030 100644
--- a/loader/dos/module.c
+++ b/loader/dos/module.c
@@ -31,7 +31,6 @@
 #ifdef MZ_SUPPORTED
 
 #include <sys/mman.h>
-#include <sys/vm86.h>
 
 /* define this to try mapping through /proc/pid/mem instead of a temp file,
    but Linus doesn't like mmapping /proc/pid/mem, so it doesn't work for me */
@@ -44,7 +43,7 @@
 #define SEG16(ptr,seg) ((LPVOID)((BYTE*)ptr+((DWORD)(seg)<<4)))
 #define SEGPTR16(ptr,segptr) ((LPVOID)((BYTE*)ptr+((DWORD)SELECTOROF(segptr)<<4)+OFFSETOF(segptr)))
 
-static void MZ_InitPSP( LPVOID lpPSP, LPCSTR cmdline, LPCSTR env )
+static void MZ_InitPSP( LPVOID lpPSP, LPCSTR cmdline, WORD env )
 {
  PDB*psp=lpPSP;
  const char*cmd=cmdline?strchr(cmdline,' '):NULL;
@@ -52,6 +51,7 @@
  psp->int20=0x20CD; /* int 20 */
  /* some programs use this to calculate how much memory they need */
  psp->nextParagraph=0x9FFF;
+ psp->environment=env;
  /* copy parameters */
  if (cmd) {
 #if 0
@@ -66,36 +66,78 @@
  /* FIXME: integrate the PDB stuff from Wine (loader/task.c) */
 }
 
+static char enter_xms[]={
+/* XMS hookable entry point */
+ 0xEB,0x03,      /* jmp entry */
+ 0x90,0x90,0x90, /* nop;nop;nop */
+                 /* entry: */
+/* real entry point */
+/* for simplicity, we'll just use the same hook as DPMI below */
+ 0xCD,0x31,      /* int 0x31 */
+ 0xCB            /* retf */
+};
+
+static void MZ_InitXMS( LPDOSTASK lpDosTask )
+{
+ LPBYTE start=DOSMEM_GetBlock(lpDosTask->hModule,sizeof(enter_xms),&(lpDosTask->xms_seg));
+ memcpy(start,enter_xms,sizeof(enter_xms));
+}
+
 static char enter_pm[]={
- 0x50,           /* pushw %ax */
- 0x52,           /* pushw %dx */
- 0x55,           /* pushw %bp */
- 0x89,0xE5,      /* movw %sp,%bp */
+ 0x50,                /* pushw %ax */
+ 0x52,                /* pushw %dx */
+ 0x55,                /* pushw %bp */
+ 0x89,0xE5,           /* movw %sp,%bp */
 /* get return CS */
- 0x8B,0x56,0x08, /* movw 8(%bp),%dx */
+ 0x8B,0x56,0x08,      /* movw 8(%bp),%dx */
 /* just call int 31 here to get into protected mode... */
 /* it'll check whether it was called from dpmi_seg... */
- 0xCD,0x31,      /* int 0x31 */
-/* fixup our stack; return address will be lost, but we won't worry quite yet */
- 0x8E,0xD0,      /* movw %ax,%ss */
- 0x89,0xEC,      /* movw %bp,%sp */
+ 0xCD,0x31,           /* int 0x31 */
+/* we are now in the context of a 16-bit relay call */
+/* need to fixup our stack;
+ * 16-bit relay return address will be lost, but we won't worry quite yet */
+ 0x8E,0xD0,           /* movw %ax,%ss */
+ 0x66,0x0F,0xB7,0xE5, /* movzwl %bp,%esp */
 /* set return CS */
- 0x89,0x56,0x08, /* movw %dx,8(%bp) */
- 0x5D,           /* popw %bp */
- 0x5A,           /* popw %dx */
- 0x58,           /* popw %ax */
- 0xCB            /* retf */
+ 0x89,0x56,0x08,      /* movw %dx,8(%bp) */
+ 0x5D,                /* popw %bp */
+ 0x5A,                /* popw %dx */
+ 0x58,                /* popw %ax */
+ 0xCB                 /* retf */
 };
 
 static void MZ_InitDPMI( LPDOSTASK lpDosTask )
 {
  LPBYTE start=DOSMEM_GetBlock(lpDosTask->hModule,sizeof(enter_pm),&(lpDosTask->dpmi_seg));
  
- lpDosTask->dpmi_sel = SELECTOR_AllocBlock( start, sizeof(enter_pm), SEGMENT_CODE, FALSE, TRUE );
+ lpDosTask->dpmi_sel = SELECTOR_AllocBlock( start, sizeof(enter_pm), SEGMENT_CODE, FALSE, FALSE );
 
  memcpy(start,enter_pm,sizeof(enter_pm));
 }
 
+static WORD MZ_InitEnvironment( LPDOSTASK lpDosTask, LPCSTR env, LPCSTR name )
+{
+ unsigned sz=0;
+ WORD seg;
+ LPSTR envblk;
+
+ if (env) {
+  /* get size of environment block */
+  while (env[sz++]) sz+=strlen(env+sz);
+ } else sz++;
+ /* allocate it */
+ envblk=DOSMEM_GetBlock(lpDosTask->hModule,sz+sizeof(WORD)+strlen(name)+1,&seg);
+ /* fill it */
+ if (env) {
+  memcpy(envblk,env,sz);
+ } else envblk[0]=0;
+ /* DOS 3.x: the block contains 1 additional string */
+ *(WORD*)(envblk+sz)=1;
+ /* being the program name itself */
+ strcpy(envblk+sz+sizeof(WORD),name);
+ return seg;
+}
+
 int MZ_InitMemory( LPDOSTASK lpDosTask, NE_MODULE *pModule )
 {
  int x;
@@ -129,18 +171,20 @@
  /* initialize the memory */
  TRACE(module,"Initializing DOS memory structures\n");
  DOSMEM_Init(lpDosTask->hModule);
+ MZ_InitXMS(lpDosTask);
  MZ_InitDPMI(lpDosTask);
  return 32;
 }
 
-static int MZ_LoadImage( HFILE16 hFile, LPCSTR cmdline, LPCSTR env,
-                         LPDOSTASK lpDosTask, NE_MODULE *pModule )
+static int MZ_LoadImage( HFILE16 hFile, LPCSTR name, LPCSTR cmdline,
+                         LPCSTR env, LPDOSTASK lpDosTask, NE_MODULE *pModule )
 {
  IMAGE_DOS_HEADER mz_header;
  DWORD image_start,image_size,min_size,max_size,avail;
  BYTE*psp_start,*load_start;
  int x,old_com=0;
  SEGPTR reloc;
+ WORD env_seg;
 
  if ((_hread16(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
      (mz_header.e_magic != IMAGE_DOS_SIGNATURE)) {
@@ -166,7 +210,8 @@
 
  MZ_InitMemory(lpDosTask,pModule);
 
- /* FIXME: allocate memory for environment variables */
+ /* allocate environment block */
+ env_seg=MZ_InitEnvironment(lpDosTask,env,name);
 
  /* allocate memory for the executable */
  TRACE(module,"Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size);
@@ -183,10 +228,10 @@
  }
  lpDosTask->load_seg=lpDosTask->psp_seg+(old_com?0:PSP_SIZE);
  load_start=psp_start+(PSP_SIZE<<4);
- MZ_InitPSP(psp_start, cmdline, env);
+ MZ_InitPSP(psp_start, cmdline, env_seg);
 
  /* load executable image */
- TRACE(module,"loading DOS %s image size, %08lx bytes\n",old_com?"COM":"EXE",image_size);
+ TRACE(module,"loading DOS %s image, %08lx bytes\n",old_com?"COM":"EXE",image_size);
  _llseek16(hFile,image_start,FILE_BEGIN);
  if ((_hread16(hFile,load_start,image_size)) != image_size)
   return 11; /* invalid exe */
@@ -203,26 +248,12 @@
   }
  }
 
- /* initialize module variables */
- pModule->cs=lpDosTask->load_seg+mz_header.e_cs;
- pModule->ip=mz_header.e_ip;
- pModule->ss=lpDosTask->load_seg+mz_header.e_ss;
- pModule->sp=mz_header.e_sp;
- pModule->self_loading_sel=lpDosTask->psp_seg;
+ lpDosTask->init_cs=lpDosTask->load_seg+mz_header.e_cs;
+ lpDosTask->init_ip=mz_header.e_ip;
+ lpDosTask->init_ss=lpDosTask->load_seg+mz_header.e_ss;
+ lpDosTask->init_sp=mz_header.e_sp;
 
- TRACE(module,"entry point: %04x:%04x\n",pModule->cs,pModule->ip);
-
- /* initialize vm86 struct */
- /* note: this may be moved soon, to be able to remove VM86 from lpDosTask
-    (got tired of all those compiler warnings, and don't like the system dependency) */
- memset(&lpDosTask->VM86,0,sizeof(lpDosTask->VM86));
- lpDosTask->VM86.regs.cs=lpDosTask->load_seg+mz_header.e_cs;
- lpDosTask->VM86.regs.eip=mz_header.e_ip;
- lpDosTask->VM86.regs.ss=lpDosTask->load_seg+mz_header.e_ss;
- lpDosTask->VM86.regs.esp=mz_header.e_sp;
- lpDosTask->VM86.regs.ds=lpDosTask->psp_seg;
- lpDosTask->VM86.regs.es=lpDosTask->psp_seg;
- /* hmm, what else do we need? */
+ TRACE(module,"entry point: %04x:%04x\n",lpDosTask->init_cs,lpDosTask->init_ip);
 
  return 32;
 }
@@ -240,8 +271,6 @@
  }
  lpDosTask->read_pipe=read_fd[0];
  lpDosTask->write_pipe=write_fd[1];
- lpDosTask->fn=VM86_ENTER;
- lpDosTask->state=1;
  /* if we have a mapping file, use it */
  fname=lpDosTask->mm_name; farg=NULL;
  if (!fname[0]) {
@@ -251,7 +280,7 @@
   fname=fproc; farg=arg;
  }
 
- TRACE(module,"Preparing to load DOS VM support module: forking\n");
+ TRACE(module,"Loading DOS VM support module (hmodule=%04x)\n",lpDosTask->hModule);
  if ((child=fork())<0) {
   close(write_fd[0]); close(write_fd[1]);
   close(read_fd[0]); close(read_fd[1]); return 0;
@@ -331,7 +360,7 @@
  
   lpDosTask->img=NULL; lpDosTask->mm_name[0]=0; lpDosTask->mm_fd=-1;
  } else lpDosTask=pModule->lpDosTask;
- err = MZ_LoadImage( hFile, cmdline, env, lpDosTask, pModule );
+ err = MZ_LoadImage( hFile, name, cmdline, env, lpDosTask, pModule );
  _lclose16(hFile);
  if (alloc) {
   pModule->dos_image = lpDosTask->img;
@@ -368,38 +397,11 @@
  close(lpDosTask->read_pipe);
  close(lpDosTask->write_pipe);
  kill(lpDosTask->task,SIGTERM);
+#if 0
+ /* FIXME: this seems to crash */
  if (lpDosTask->dpmi_sel)
   UnMapLS(PTR_SEG_OFF_TO_SEGPTR(lpDosTask->dpmi_sel,0));
-}
-
-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
 }
 
 #else /* !MZ_SUPPORTED */