Beispiel #1
0
static DWORD WINAPI MZ_DOSVM( LPVOID lpExtra )
{
  CONTEXT context;
  INT ret;

  dosvm_pid = getpid();

  memset( &context, 0, sizeof(context) );
  context.SegCs  = init_cs;
  context.Eip    = init_ip;
  context.SegSs  = init_ss;
  context.Esp    = init_sp;
  context.SegDs  = DOSVM_psp;
  context.SegEs  = DOSVM_psp;
  context.EFlags = V86_FLAG | VIF_MASK;
  DOSVM_SetTimer(0x10000);
  ret = DOSVM_Enter( &context );
  if (ret == -1)
  {
      /* fetch the app name from the environment */
      PDB16 *psp = PTR_REAL_TO_LIN( DOSVM_psp, 0 );
      char *env = PTR_REAL_TO_LIN( psp->environment, 0 );
      while (*env) env += strlen(env) + 1;
      env += 1 + sizeof(WORD);

      if (GetLastError() == ERROR_NOT_SUPPORTED)
          MESSAGE( "wine: Cannot start DOS application %s\n"
                   "      because vm86 mode is not supported on this platform.\n",
                   debugstr_a(env) );
      else
          FIXME( "vm86 mode failed error %u\n", GetLastError() );
  }
  dosvm_pid = 0;
  return ret != 0;
}
Beispiel #2
0
/**********************************************************************
 *          EMS_access_name
 *
 * Get/set handle name.
 */
static void EMS_access_name( CONTEXT86 *context )
{
  char *ptr;
  int hindex = DX_reg(context);
  if(hindex < 0 || hindex >= EMS_MAX_HANDLES) {
    SET_AH( context, 0x83 ); /* invalid handle */
    return;
  }

  switch AL_reg(context) {
  case 0x00: /* get name */
    ptr = PTR_REAL_TO_LIN(context->SegEs, DI_reg(context));
    memcpy(ptr, EMS_record->handle[hindex].name, 8);
    SET_AH( context, 0 );
    break;

  case 0x01: /* set name */
    ptr = PTR_REAL_TO_LIN(context->SegDs, SI_reg(context));
    memcpy(EMS_record->handle[hindex].name, ptr, 8);
    SET_AH( context, 0 );
    break;

  default:
    INT_BARF(context,0x67);
    break;
  }
}
Beispiel #3
0
/***********************************************************************
 *		MZ_Exit
 */
void WINAPI MZ_Exit( CONTEXT86 *context, BOOL cs_psp, WORD retval )
{
  if (DOSVM_psp) {
    WORD psp_seg = cs_psp ? context->SegCs : DOSVM_psp;
    LPBYTE psp_start = (LPBYTE)((DWORD)psp_seg << 4);
    PDB16 *psp = (PDB16 *)psp_start;
    WORD parpsp = psp->parentPSP; /* check for parent DOS process */
    if (parpsp) {
      /* retrieve parent's return address */
      FARPROC16 retaddr = DOSVM_GetRMHandler(0x22);
      /* restore interrupts */
      DOSVM_SetRMHandler(0x22, psp->savedint22);
      DOSVM_SetRMHandler(0x23, psp->savedint23);
      DOSVM_SetRMHandler(0x24, psp->savedint24);
      /* FIXME: deallocate file handles etc */
      /* free process's associated memory
       * FIXME: walk memory and deallocate all blocks owned by process */
      DOSMEM_FreeBlock( PTR_REAL_TO_LIN(psp->environment,0) );
      DOSMEM_FreeBlock( PTR_REAL_TO_LIN(DOSVM_psp,0) );
      /* switch to parent's PSP */
      DOSVM_psp = parpsp;
      psp_start = (LPBYTE)((DWORD)parpsp << 4);
      psp = (PDB16 *)psp_start;
      /* now return to parent */
      DOSVM_retval = retval;
      context->SegCs = SELECTOROF(retaddr);
      context->Eip   = OFFSETOF(retaddr);
      context->SegSs = SELECTOROF(psp->saveStack);
      context->Esp   = OFFSETOF(psp->saveStack);
      return;
    } else
      TRACE("killing DOS task\n");
  }
  ExitThread( retval );
}
Beispiel #4
0
static void MZ_Launch( LPCSTR cmdtail, int length )
{
  TDB *pTask = GlobalLock16( GetCurrentTask() );
  BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 );
  DWORD rv;
  SYSLEVEL *lock;

  MZ_FillPSP(psp_start, cmdtail, length);
  pTask->flags |= TDBF_WINOLDAP;

  /* DTA is set to PSP:0080h when a program is started. */
  pTask->dta = MAKESEGPTR( DOSVM_psp, 0x80 );

  GetpWin16Lock( &lock );
  _LeaveSysLevel( lock );

  ResumeThread(dosvm_thread);
  rv = DOSVM_Loop(dosvm_thread);

  CloseHandle(dosvm_thread);
  dosvm_thread = 0; dosvm_tid = 0;
  CloseHandle(loop_thread);
  loop_thread = 0; loop_tid = 0;

  VGA_Clean();
  ExitProcess(rv);
}
Beispiel #5
0
static DWORD MZ_Launch( LPCSTR cmdtail, int length )
{
  TDB *pTask = GlobalLock16( GetCurrentTask() );
  BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 );
  DWORD rv;
  SYSLEVEL *lock;
  MSG msg;

  MZ_FillPSP(psp_start, cmdtail, length);
  pTask->flags |= TDBF_WINOLDAP;

  /* DTA is set to PSP:0080h when a program is started. */
  pTask->dta = MAKESEGPTR( DOSVM_psp, 0x80 );

  GetpWin16Lock( &lock );
  _LeaveSysLevel( lock );

  /* force the message queue to be created */
  PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

  ResumeThread(dosvm_thread);
  rv = DOSVM_Loop(dosvm_thread);

  CloseHandle(dosvm_thread);
  dosvm_thread = 0; dosvm_tid = 0;
  CloseHandle(loop_thread);
  loop_thread = 0; loop_tid = 0;
  if (rv) return rv;

  VGA_Clean();
  ExitProcess(0);
}
Beispiel #6
0
void DOSDEV_SetupDevice(const WINEDEV * devinfo,
			WORD seg, WORD off_dev, WORD off_thunk)
{
  DOS_DEVICE_HEADER *dev = PTR_REAL_TO_LIN(seg, off_dev);
  WINEDEV_THUNK *thunk = PTR_REAL_TO_LIN(seg, off_thunk);
  DOS_DATASEG *dataseg = (DOS_DATASEG*)DOSMEM_LOL();

  dev->attr = devinfo->attr;
  dev->strategy  = off_thunk + FIELD_OFFSET(WINEDEV_THUNK, ljmp1);
  dev->interrupt = off_thunk + FIELD_OFFSET(WINEDEV_THUNK, ljmp2);
  memcpy(dev->name, devinfo->name, 8);

  thunk->ljmp1     = LJMP;
  thunk->strategy  = DPMI_AllocInternalRMCB(devinfo->strategy);
  thunk->ljmp2     = LJMP;
  thunk->interrupt = DPMI_AllocInternalRMCB(devinfo->interrupt);

  dev->next_dev = NONEXT;
  if (dataseg->last_dev)
      dataseg->last_dev->next_dev = MAKESEGPTR(seg, off_dev);
  dataseg->last_dev = dev;
}
Beispiel #7
0
DWORD DOSDEV_FindCharDevice(char*name)
{
  SEGPTR cur_ptr = MAKESEGPTR(HIWORD(DOS_LOLSeg), FIELD_OFFSET(DOS_LISTOFLISTS,NUL_dev));
  DOS_DEVICE_HEADER *cur = PTR_REAL_TO_LIN(SELECTOROF(cur_ptr),OFFSETOF(cur_ptr));
  char dname[8];
  int cnt;

  /* get first 8 characters */
  /* if less than 8 characters, pad with spaces */
  for (cnt=0; name[cnt] && cnt<8; cnt++)
    dname[cnt]=name[cnt];

  while(cnt<8) dname[cnt++] = ' ';

  /* search for char devices with the right name */
  while (cur &&
	 ((!(cur->attr & ATTR_CHAR)) ||
	  memcmp(cur->name,dname,8))) {
    cur_ptr = cur->next_dev;
    if (cur_ptr == NONEXT) cur=NULL;
    else cur = PTR_REAL_TO_LIN(SELECTOROF(cur_ptr),OFFSETOF(cur_ptr));
  }
  return cur_ptr;
}
Beispiel #8
0
static void DOSDEV_DoReq(void*req, DWORD dev)
{
  REQUEST_HEADER *hdr = (REQUEST_HEADER *)req;
  DOS_DEVICE_HEADER *dhdr;
  CONTEXT86 ctx;
  char *phdr;

  dhdr = PTR_REAL_TO_LIN(SELECTOROF(dev),OFFSETOF(dev));
  phdr = ((char*)DOSMEM_LOL()) + DOS_DATASEG_OFF(req);

  /* copy request to request scratch area */
  memcpy(phdr, req, hdr->size);

  /* prepare to call device driver */
  memset(&ctx, 0, sizeof(ctx));
  ctx.EFlags |= V86_FLAG;

  /* ES:BX points to request for strategy routine */
  ctx.SegEs = HIWORD(DOS_LOLSeg);
  ctx.Ebx   = DOS_DATASEG_OFF(req);

  /* call strategy routine */
  ctx.SegCs = SELECTOROF(dev);
  ctx.Eip   = dhdr->strategy;
  DPMI_CallRMProc(&ctx, 0, 0, 0);

  /* call interrupt routine */
  ctx.SegCs = SELECTOROF(dev);
  ctx.Eip   = dhdr->interrupt;
  DPMI_CallRMProc(&ctx, 0, 0, 0);

  /* completed, copy request back */
  memcpy(req, phdr, hdr->size);

  if (hdr->status & STAT_ERROR) {
    switch (hdr->status & STAT_MASK) {
    case 0x0F: /* invalid disk change */
      /* this error seems to fit the bill */
      SetLastError(ERROR_NOT_SAME_DEVICE);
      break;
    default:
      SetLastError((hdr->status & STAT_MASK) + 0x13);
      break;
    }
  }
}
Beispiel #9
0
/**********************************************************************
 *          EMS_map_multiple
 *
 * Map multiple logical pages into physical pages.
 */
static void EMS_map_multiple( CONTEXT86 *context )
{
  WORD *ptr = PTR_REAL_TO_LIN(context->SegDs, SI_reg(context));
  BYTE  status = 0;
  int   i;

  for(i=0; i<CX_reg(context) && !status; i++, ptr += 2)
    switch(AL_reg(context)) {
    case 0x00:
      status = EMS_map( ptr[1],
                       DX_reg(context), ptr[0] );
      break;
    case 0x01:
      status = EMS_map( (ptr[1] - EMS_record->frame_selector) >> 10,
                       DX_reg(context), ptr[0] );
      break;
    default:
      status = 0x8f; /* status: undefined subfunction */
    }

  SET_AH( context, status );
}
Beispiel #10
0
static int DPMI_FreeRMCB( DWORD address )
{
    RMCB *CurrRMCB = FirstRMCB;
    RMCB *PrevRMCB = NULL;

    while (CurrRMCB && (CurrRMCB->address != address))
    {
	PrevRMCB = CurrRMCB;
	CurrRMCB = CurrRMCB->next;
    }
    if (CurrRMCB)
    {
	if (PrevRMCB)
	PrevRMCB->next = CurrRMCB->next;
	    else
	FirstRMCB = CurrRMCB->next;
	DOSMEM_FreeBlock(PTR_REAL_TO_LIN(SELECTOROF(CurrRMCB->address),OFFSETOF(CurrRMCB->address)));
	HeapFree(GetProcessHeap(), 0, CurrRMCB);
	return 0;
    }
    return 1;
}
Beispiel #11
0
static BYTE * XMS_Offset( MOVEOFS *ofs )
{
    if (ofs->Handle) return (BYTE*)GlobalLock16(ofs->Handle)+ofs->Offset;
    else return (BYTE*)PTR_REAL_TO_LIN(SELECTOROF(ofs->Offset),OFFSETOF(ofs->Offset));
}
Beispiel #12
0
static struct _DOS_LISTOFLISTS * DOSMEM_LOL(void)
{
    return PTR_REAL_TO_LIN(HIWORD(DOS_LOLSeg),0);
}
Beispiel #13
0
/***********************************************************************
 *		MZ_Exec
 *
 * this may only be called from existing DOS processes
 */
BOOL WINAPI MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk )
{
  DWORD binType;
  STARTUPINFOA st;
  PROCESS_INFORMATION pe;
  HANDLE hFile;

  BOOL ret = FALSE;

  if(!GetBinaryTypeA(filename, &binType))   /* determine what kind of binary this is */
  {
    return FALSE; /* binary is not an executable */
  }

  /* handle non-dos executables */
  if(binType != SCS_DOS_BINARY)
  {
    if(func == 0) /* load and execute */
    {
      LPSTR fullCmdLine;
      WORD fullCmdLength;
      LPBYTE psp_start = (LPBYTE)((DWORD)DOSVM_psp << 4);
      PDB16 *psp = (PDB16 *)psp_start;
      ExecBlock *blk = (ExecBlock *)paramblk;
      LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline));
      LPBYTE envblock = PTR_REAL_TO_LIN(psp->environment, 0);
      int    cmdLength = cmdline[0];

      /*
       * If cmdLength is 127, command tail is truncated and environment 
       * variable CMDLINE should contain full command line 
       * (this includes filename).
       */
      if (cmdLength == 127)
      {
          FIXME( "CMDLINE argument passing is unimplemented.\n" );
          cmdLength = 126; /* FIXME */
      }

      fullCmdLength = (strlen(filename) + 1) + cmdLength + 1; /* filename + space + cmdline + terminating null character */

      fullCmdLine = HeapAlloc(GetProcessHeap(), 0, fullCmdLength);
      if(!fullCmdLine) return FALSE; /* return false on memory alloc failure */

      /* build the full command line from the executable file and the command line being passed in */
      snprintf(fullCmdLine, fullCmdLength, "%s ", filename); /* start off with the executable filename and a space */
      memcpy(fullCmdLine + strlen(fullCmdLine), cmdline + 1, cmdLength); /* append cmdline onto the end */
      fullCmdLine[fullCmdLength - 1] = 0; /* null terminate string */

      ZeroMemory (&st, sizeof(STARTUPINFOA));
      st.cb = sizeof(STARTUPINFOA);
      ret = CreateProcessA (NULL, fullCmdLine, NULL, NULL, TRUE, 0, envblock, NULL, &st, &pe);

      /* wait for the app to finish and clean up PROCESS_INFORMATION handles */
      if(ret)
      {
        WaitForSingleObject(pe.hProcess, INFINITE);  /* wait here until the child process is complete */
        CloseHandle(pe.hProcess);
        CloseHandle(pe.hThread);
      }

      HeapFree(GetProcessHeap(), 0, fullCmdLine);  /* free the memory we allocated */
    }
    else
    {
      FIXME("EXEC type of %d not implemented for non-dos executables\n", func);
      ret = FALSE;
    }

    return ret;
  } /* if(binType != SCS_DOS_BINARY) */


  /* handle dos executables */

  hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
			     NULL, OPEN_EXISTING, 0, 0);
  if (hFile == INVALID_HANDLE_VALUE) return FALSE;

  switch (func) {
  case 0: /* load and execute */
  case 1: /* load but don't execute */
    {
      /* save current process's return SS:SP now */
      LPBYTE psp_start = (LPBYTE)((DWORD)DOSVM_psp << 4);
      PDB16 *psp = (PDB16 *)psp_start;
      psp->saveStack = (DWORD)MAKESEGPTR(context->SegSs, LOWORD(context->Esp));
    }
    ret = MZ_DoLoadImage( hFile, filename, NULL, ((ExecBlock *)paramblk)->env_seg );
    if (ret) {
      /* MZ_LoadImage created a new PSP and loaded new values into it,
       * let's work on the new values now */
      LPBYTE psp_start = (LPBYTE)((DWORD)DOSVM_psp << 4);
      ExecBlock *blk = (ExecBlock *)paramblk;
      LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline));

      /* First character contains the length of the command line. */
      MZ_FillPSP(psp_start, (LPSTR)cmdline + 1, cmdline[0]);

      /* the lame MS-DOS engineers decided that the return address should be in int22 */
      DOSVM_SetRMHandler(0x22, (FARPROC16)MAKESEGPTR(context->SegCs, LOWORD(context->Eip)));
      if (func) {
	/* don't execute, just return startup state */
        /*
         * From Ralph Brown:
         *  For function 01h, the AX value to be passed to the child program 
         *  is put on top of the child's stack
         */
        LPBYTE stack;
        init_sp -= 2;
        stack = (LPBYTE) CTX_SEG_OFF_TO_LIN(context, init_ss, init_sp);
        /* FIXME: push AX correctly */
        stack[0] = 0x00;    /* push AL */
        stack[1] = 0x00;    /* push AH */
	
	blk->init_cs = init_cs;
	blk->init_ip = init_ip;
	blk->init_ss = init_ss;
	blk->init_sp = init_sp;
      } else {
	/* execute by making us return to new process */
	context->SegCs = init_cs;
	context->Eip   = init_ip;
	context->SegSs = init_ss;
	context->Esp   = init_sp;
	context->SegDs = DOSVM_psp;
	context->SegEs = DOSVM_psp;
	context->Eax   = 0;
      }
    }
    break;
  case 3: /* load overlay */
    {
      OverlayBlock *blk = (OverlayBlock *)paramblk;
      ret = MZ_DoLoadImage( hFile, filename, blk, 0);
    }
    break;
  default:
    FIXME("EXEC load type %d not implemented\n", func);
    SetLastError(ERROR_INVALID_FUNCTION);
    break;
  }
  CloseHandle(hFile);
  return ret;
}
Beispiel #14
0
static BOOL MZ_DoLoadImage( HANDLE hFile, LPCSTR filename, OverlayBlock *oblk, WORD par_env_seg )
{
  IMAGE_DOS_HEADER mz_header;
  DWORD image_start,image_size,min_size,max_size,avail;
  BYTE*psp_start,*load_start;
  LPSTR oldenv = 0;
  int x, old_com=0, alloc;
  SEGPTR reloc;
  WORD env_seg, load_seg, rel_seg, oldpsp_seg;
  DWORD len;

  if (DOSVM_psp) {
    /* DOS process already running, inherit from it */
    PDB16* par_psp;
    alloc=0;
    oldpsp_seg = DOSVM_psp;
    if( !par_env_seg) {  
        par_psp = (PDB16*)((DWORD)DOSVM_psp << 4);
        oldenv = (LPSTR)((DWORD)par_psp->environment << 4);
    }
  } else {
    /* allocate new DOS process, inheriting from Wine environment */
    alloc=1;
    oldpsp_seg = 0;
    if( !par_env_seg)
        oldenv = GetEnvironmentStringsA();
  }

 SetFilePointer(hFile,0,NULL,FILE_BEGIN);
 if (   !ReadFile(hFile,&mz_header,sizeof(mz_header),&len,NULL)
     || len != sizeof(mz_header)
     || mz_header.e_magic != IMAGE_DOS_SIGNATURE) {
  char *p = strrchr( filename, '.' );
  if (!p || strcasecmp( p, ".com" ))  /* check for .COM extension */
  {
      SetLastError(ERROR_BAD_FORMAT);
      goto load_error;
  }
  old_com=1; /* assume .COM file */
  image_start=0;
  image_size=GetFileSize(hFile,NULL);
  min_size=0x10000; max_size=0x100000;
  mz_header.e_crlc=0;
  mz_header.e_ss=0; mz_header.e_sp=0xFFFE;
  mz_header.e_cs=0; mz_header.e_ip=0x100;
 } else {
  /* calculate load size */
  image_start=mz_header.e_cparhdr<<4;
  image_size=mz_header.e_cp<<9; /* pages are 512 bytes */
  /* From Ralf Brown Interrupt List: If the word at offset 02h is 4, it should
   * be treated as 00h, since pre-1.10 versions of the MS linker set it that
   * way. */
  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);
 }

  if (alloc) MZ_InitMemory();

  if (oblk) {
    /* load overlay into preallocated memory */
    load_seg=oblk->load_seg;
    rel_seg=oblk->rel_seg;
    load_start=(LPBYTE)((DWORD)load_seg<<4);
  } else {
    /* allocate environment block */
    if( par_env_seg)
        env_seg = par_env_seg;
    else
        env_seg=MZ_InitEnvironment(oldenv, filename);
    if( alloc && oldenv)
        FreeEnvironmentStringsA( oldenv);

    /* allocate memory for the executable */
    TRACE("Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size);
    avail=DOSMEM_Available();
    if (avail<min_size) {
      ERR("insufficient DOS memory\n");
      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
      goto load_error;
    }
    if (avail>max_size) avail=max_size;
    psp_start=DOSMEM_AllocBlock(avail,&DOSVM_psp);
    if (!psp_start) {
      ERR("error allocating DOS memory\n");
      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
      goto load_error;
    }
    load_seg=DOSVM_psp+(old_com?0:PSP_SIZE);
    rel_seg=load_seg;
    load_start=psp_start+(PSP_SIZE<<4);
    MZ_CreatePSP(psp_start, env_seg, oldpsp_seg);
  }

 /* load executable image */
 TRACE("loading DOS %s image, %08lx bytes\n",old_com?"COM":"EXE",image_size);
 SetFilePointer(hFile,image_start,NULL,FILE_BEGIN);
 if (!ReadFile(hFile,load_start,image_size,&len,NULL) || len != image_size) {
  /* check if this is due to the workaround for the pre-1.10 MS linker and we
     realy had only 4 bytes on the last page */
  if (mz_header.e_cblp != 4 || image_size - len != 512 - 4) {
    SetLastError(ERROR_BAD_FORMAT);
    goto load_error;
  }
 }

 if (mz_header.e_crlc) {
  /* load relocation table */
  TRACE("loading DOS EXE relocation table, %d entries\n",mz_header.e_crlc);
  /* FIXME: is this too slow without read buffering? */
  SetFilePointer(hFile,mz_header.e_lfarlc,NULL,FILE_BEGIN);
  for (x=0; x<mz_header.e_crlc; x++) {
   if (!ReadFile(hFile,&reloc,sizeof(reloc),&len,NULL) || len != sizeof(reloc)) {
    SetLastError(ERROR_BAD_FORMAT);
    goto load_error;
   }
   *(WORD*)SEGPTR16(load_start,reloc)+=rel_seg;
  }
 }

  if (!oblk) {
    init_cs = load_seg+mz_header.e_cs;
    init_ip = mz_header.e_ip;
    init_ss = load_seg+mz_header.e_ss;
    init_sp = mz_header.e_sp;
    if (old_com){
      /* .COM files exit with ret. Make sure they jump to psp start (=int 20) */
      WORD* stack = PTR_REAL_TO_LIN(init_ss, init_sp);
      *stack = 0;
    }

    TRACE("entry point: %04x:%04x\n",init_cs,init_ip);
  }

  if (alloc && !MZ_InitTask()) {
    SetLastError(ERROR_GEN_FAILURE);
    return FALSE;
  }

  return TRUE;

load_error:
  DOSVM_psp = oldpsp_seg;

  return FALSE;
}