Implemented DOS INT21 AH=4B (EXEC).

This commit is contained in:
Ove Kaaven 2000-10-17 00:33:02 +00:00 committed by Alexandre Julliard
parent 7b0bf0f08d
commit 7c4bee569c
5 changed files with 242 additions and 60 deletions

View File

@ -14,7 +14,7 @@
struct _DOSEVENT; struct _DOSEVENT;
typedef struct _DOSTASK { typedef struct _DOSTASK {
WORD psp_seg; WORD psp_seg, retval;
WORD dpmi_flag; WORD dpmi_flag;
} DOSTASK, *LPDOSTASK; } DOSTASK, *LPDOSTASK;
@ -31,6 +31,8 @@ typedef struct _DOSTASK {
#define V86_FLAG 0x00020000 #define V86_FLAG 0x00020000
extern BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename ); extern BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename );
extern BOOL MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk );
extern void MZ_Exit( CONTEXT86 *context, BOOL cs_psp, WORD retval );
extern LPDOSTASK MZ_Current( void ); extern LPDOSTASK MZ_Current( void );
extern LPDOSTASK MZ_AllocDPMITask( void ); extern LPDOSTASK MZ_AllocDPMITask( void );
extern int DOSVM_Enter( CONTEXT86 *context ); extern int DOSVM_Enter( CONTEXT86 *context );

View File

@ -26,7 +26,7 @@ typedef struct
WORD parentPSP; /* 16 Selector of parent PSP */ WORD parentPSP; /* 16 Selector of parent PSP */
BYTE fileHandles[20]; /* 18 Open file handles */ BYTE fileHandles[20]; /* 18 Open file handles */
HANDLE16 environment; /* 2c Selector of environment */ HANDLE16 environment; /* 2c Selector of environment */
WORD reserved2[2]; DWORD saveStack; /* 2e SS:SP on last int21 call */
WORD nbFiles; /* 32 Number of file handles */ WORD nbFiles; /* 32 Number of file handles */
SEGPTR fileHandlesPtr; /* 34 Pointer to file handle table */ SEGPTR fileHandlesPtr; /* 34 Pointer to file handle table */
HANDLE16 hFileHandles; /* 38 Handle to fileHandlesPtr */ HANDLE16 hFileHandles; /* 38 Handle to fileHandlesPtr */

View File

@ -55,6 +55,26 @@ static LPDOSTASK dos_current;
#define SEG16(ptr,seg) ((LPVOID)((BYTE*)ptr+((DWORD)(seg)<<4))) #define SEG16(ptr,seg) ((LPVOID)((BYTE*)ptr+((DWORD)(seg)<<4)))
#define SEGPTR16(ptr,segptr) ((LPVOID)((BYTE*)ptr+((DWORD)SELECTOROF(segptr)<<4)+OFFSETOF(segptr))) #define SEGPTR16(ptr,segptr) ((LPVOID)((BYTE*)ptr+((DWORD)SELECTOROF(segptr)<<4)+OFFSETOF(segptr)))
/* structures for EXEC */
typedef struct {
WORD env_seg;
DWORD cmdline WINE_PACKED;
DWORD fcb1 WINE_PACKED;
DWORD fcb2 WINE_PACKED;
WORD init_sp;
WORD init_ss;
WORD init_ip;
WORD init_cs;
} ExecBlock;
typedef struct {
WORD load_seg;
WORD rel_seg;
} OverlayBlock;
/* global variables */
static WORD init_cs,init_ip,init_ss,init_sp; static WORD init_cs,init_ip,init_ss,init_sp;
static char mm_name[128]; static char mm_name[128];
@ -66,15 +86,20 @@ static void MZ_Launch(void);
static BOOL MZ_InitTask(void); static BOOL MZ_InitTask(void);
static void MZ_KillTask(void); static void MZ_KillTask(void);
static void MZ_CreatePSP( LPVOID lpPSP, WORD env ) static void MZ_CreatePSP( LPVOID lpPSP, WORD env, WORD par )
{ {
PDB16*psp=lpPSP; PDB16*psp=lpPSP;
psp->int20=0x20CD; /* int 20 */ psp->int20=0x20CD; /* int 20 */
/* some programs use this to calculate how much memory they need */ /* some programs use this to calculate how much memory they need */
psp->nextParagraph=0x9FFF; psp->nextParagraph=0x9FFF; /* FIXME: use a real value */
psp->environment=env; /* FIXME: dispatcher */
/* FIXME: more PSP stuff */ psp->savedint22 = INT_GetRMHandler(0x22);
psp->savedint23 = INT_GetRMHandler(0x23);
psp->savedint24 = INT_GetRMHandler(0x24);
psp->parentPSP=par;
psp->environment=env;
/* FIXME: more PSP stuff */
} }
static void MZ_FillPSP( LPVOID lpPSP, LPCSTR cmdline ) static void MZ_FillPSP( LPVOID lpPSP, LPCSTR cmdline )
@ -178,25 +203,30 @@ static BOOL MZ_InitMemory(void)
return TRUE; return TRUE;
} }
BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename ) BOOL MZ_DoLoadImage( HMODULE module, HANDLE hFile, LPCSTR filename, OverlayBlock *oblk )
{ {
LPDOSTASK lpDosTask = dos_current; LPDOSTASK lpDosTask = dos_current;
IMAGE_NT_HEADERS *win_hdr = PE_HEADER(module);
IMAGE_DOS_HEADER mz_header; IMAGE_DOS_HEADER mz_header;
DWORD image_start,image_size,min_size,max_size,avail; DWORD image_start,image_size,min_size,max_size,avail;
BYTE*psp_start,*load_start; BYTE*psp_start,*load_start,*oldenv;
int x, old_com=0, alloc=0; int x, old_com=0, alloc;
SEGPTR reloc; SEGPTR reloc;
WORD env_seg, load_seg; WORD env_seg, load_seg, rel_seg, oldpsp_seg;
DWORD len; DWORD len;
win_hdr->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; if (lpDosTask) {
win_hdr->OptionalHeader.AddressOfEntryPoint = (LPBYTE)MZ_Launch - (LPBYTE)module; /* DOS process already running, inherit from it */
PDB16* par_psp = (PDB16*)((DWORD)lpDosTask->psp_seg << 4);
if (!lpDosTask) { alloc=0;
oldenv = (LPBYTE)((DWORD)par_psp->environment << 4);
oldpsp_seg = lpDosTask->psp_seg;
} else {
/* allocate new DOS process, inheriting from Wine environment */
alloc=1; alloc=1;
lpDosTask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSTASK)); lpDosTask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSTASK));
dos_current = lpDosTask; dos_current = lpDosTask;
oldenv = GetEnvironmentStringsA();
oldpsp_seg = 0;
} }
SetFilePointer(hFile,0,NULL,FILE_BEGIN); SetFilePointer(hFile,0,NULL,FILE_BEGIN);
@ -220,29 +250,37 @@ BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
max_size=image_size+((DWORD)mz_header.e_maxalloc<<4)+(PSP_SIZE<<4); max_size=image_size+((DWORD)mz_header.e_maxalloc<<4)+(PSP_SIZE<<4);
} }
MZ_InitMemory(); if (alloc) MZ_InitMemory();
/* allocate environment block */ if (oblk) {
env_seg=MZ_InitEnvironment(GetEnvironmentStringsA(),filename); /* 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 */
env_seg=MZ_InitEnvironment(oldenv, filename);
/* allocate memory for the executable */ /* allocate memory for the executable */
TRACE("Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size); TRACE("Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size);
avail=DOSMEM_Available(); avail=DOSMEM_Available();
if (avail<min_size) { if (avail<min_size) {
ERR("insufficient DOS memory\n"); ERR("insufficient DOS memory\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto load_error; goto load_error;
} }
if (avail>max_size) avail=max_size; if (avail>max_size) avail=max_size;
psp_start=DOSMEM_GetBlock(avail,&lpDosTask->psp_seg); psp_start=DOSMEM_GetBlock(avail,&lpDosTask->psp_seg);
if (!psp_start) { if (!psp_start) {
ERR("error allocating DOS memory\n"); ERR("error allocating DOS memory\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto load_error; goto load_error;
} }
load_seg=lpDosTask->psp_seg+(old_com?0:PSP_SIZE); load_seg=lpDosTask->psp_seg+(old_com?0:PSP_SIZE);
load_start=psp_start+(PSP_SIZE<<4); rel_seg=load_seg;
MZ_CreatePSP(psp_start, env_seg); load_start=psp_start+(PSP_SIZE<<4);
MZ_CreatePSP(psp_start, env_seg, oldpsp_seg);
}
/* load executable image */ /* load executable image */
TRACE("loading DOS %s image, %08lx bytes\n",old_com?"COM":"EXE",image_size); TRACE("loading DOS %s image, %08lx bytes\n",old_com?"COM":"EXE",image_size);
@ -262,18 +300,20 @@ BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
SetLastError(ERROR_BAD_FORMAT); SetLastError(ERROR_BAD_FORMAT);
goto load_error; goto load_error;
} }
*(WORD*)SEGPTR16(load_start,reloc)+=load_seg; *(WORD*)SEGPTR16(load_start,reloc)+=rel_seg;
} }
} }
init_cs = load_seg+mz_header.e_cs; if (!oblk) {
init_ip = mz_header.e_ip; init_cs = load_seg+mz_header.e_cs;
init_ss = load_seg+mz_header.e_ss; init_ip = mz_header.e_ip;
init_sp = mz_header.e_sp; init_ss = load_seg+mz_header.e_ss;
init_sp = mz_header.e_sp;
TRACE("entry point: %04x:%04x\n",init_cs,init_ip); TRACE("entry point: %04x:%04x\n",init_cs,init_ip);
}
if (!MZ_InitTask()) { if (alloc && !MZ_InitTask()) {
MZ_KillTask(); MZ_KillTask();
SetLastError(ERROR_GEN_FAILURE); SetLastError(ERROR_GEN_FAILURE);
return FALSE; return FALSE;
@ -282,6 +322,7 @@ BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
return TRUE; return TRUE;
load_error: load_error:
lpDosTask->psp_seg = oldpsp_seg;
if (alloc) { if (alloc) {
dos_current = NULL; dos_current = NULL;
if (mm_name[0]!=0) unlink(mm_name); if (mm_name[0]!=0) unlink(mm_name);
@ -290,6 +331,80 @@ load_error:
return FALSE; return FALSE;
} }
BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
{
IMAGE_NT_HEADERS *win_hdr = PE_HEADER(module);
if (win_hdr) {
win_hdr->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
win_hdr->OptionalHeader.AddressOfEntryPoint = (LPBYTE)MZ_Launch - (LPBYTE)module;
}
return MZ_DoLoadImage( module, hFile, filename, NULL );
}
BOOL MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk )
{
/* this may only be called from existing DOS processes
* (i.e. one DOS app spawning another) */
/* FIXME: do we want to check binary type first, to check
* whether it's a NE/PE executable? */
LPDOSTASK lpDosTask = MZ_Current();
HFILE hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, -1);
BOOL ret = FALSE;
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)lpDosTask->psp_seg << 4);
PDB16 *psp = (PDB16 *)psp_start;
psp->saveStack = (DWORD)PTR_SEG_OFF_TO_SEGPTR(context->SegSs, LOWORD(context->Esp));
}
ret = MZ_DoLoadImage( NULL, hFile, filename, NULL );
if (ret) {
/* MZ_LoadImage created a new PSP and loaded new values into lpDosTask,
* let's work on the new values now */
LPBYTE psp_start = (LPBYTE)((DWORD)lpDosTask->psp_seg << 4);
ExecBlock *blk = (ExecBlock *)paramblk;
MZ_FillPSP(psp_start, DOSMEM_MapRealToLinear(blk->cmdline));
/* the lame MS-DOS engineers decided that the return address should be in int22 */
INT_SetRMHandler(0x22, (FARPROC16)PTR_SEG_OFF_TO_SEGPTR(context->SegCs, LOWORD(context->Eip)));
if (func) {
/* don't execute, just return startup state */
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 = lpDosTask->psp_seg;
context->SegEs = lpDosTask->psp_seg;
context->Eax = 0;
}
}
break;
case 3: /* load overlay */
{
OverlayBlock *blk = (OverlayBlock *)paramblk;
ret = MZ_DoLoadImage( NULL, hFile, filename, blk );
}
break;
default:
FIXME("EXEC load type %d not implemented\n", func);
SetLastError(ERROR_INVALID_FUNCTION);
break;
}
CloseHandle(hFile);
return ret;
}
LPDOSTASK MZ_AllocDPMITask( void ) LPDOSTASK MZ_AllocDPMITask( void )
{ {
LPDOSTASK lpDosTask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSTASK)); LPDOSTASK lpDosTask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSTASK));
@ -435,21 +550,70 @@ static void MZ_KillTask(void)
kill(dosmod_pid,SIGTERM); kill(dosmod_pid,SIGTERM);
} }
void MZ_Exit( CONTEXT86 *context, BOOL cs_psp, WORD retval )
{
LPDOSTASK lpDosTask = MZ_Current();
if (lpDosTask) {
WORD psp_seg = cs_psp ? context->SegCs : lpDosTask->psp_seg;
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 = INT_GetRMHandler(0x22);
/* restore interrupts */
INT_SetRMHandler(0x22, psp->savedint22);
INT_SetRMHandler(0x23, psp->savedint23);
INT_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(DOSMEM_MapRealToLinear(MAKELONG(0,psp->environment)));
DOSMEM_FreeBlock(DOSMEM_MapRealToLinear(MAKELONG(0,lpDosTask->psp_seg)));
/* switch to parent's PSP */
lpDosTask->psp_seg = parpsp;
psp_start = (LPBYTE)((DWORD)parpsp << 4);
psp = (PDB16 *)psp_start;
/* now return to parent */
lpDosTask->retval = retval;
context->SegCs = SELECTOROF(retaddr);
context->Eip = OFFSETOF(retaddr);
context->SegSs = SELECTOROF(psp->saveStack);
context->Esp = OFFSETOF(psp->saveStack);
return;
} else
MZ_KillTask();
}
ExitThread( retval );
}
#else /* !MZ_SUPPORTED */ #else /* !MZ_SUPPORTED */
BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename ) BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
{ {
WARN("DOS executables not supported on this architecture\n"); WARN("DOS executables not supported on this platform\n");
SetLastError(ERROR_BAD_FORMAT); SetLastError(ERROR_BAD_FORMAT);
return FALSE; return FALSE;
}
BOOL MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk )
{
/* can't happen */
SetLastError(ERROR_BAD_FORMAT);
return FALSE;
} }
LPDOSTASK MZ_AllocDPMITask( void ) LPDOSTASK MZ_AllocDPMITask( void )
{ {
ERR("Actual real-mode calls not supported on this architecture!\n"); ERR("Actual real-mode calls not supported on this platform!\n");
return NULL; return NULL;
} }
void MZ_Exit( CONTEXT86 *context, BOOL cs_psp, WORD retval )
{
ExitThread( retval );
}
#endif /* !MZ_SUPPORTED */ #endif /* !MZ_SUPPORTED */
LPDOSTASK MZ_Current( void ) LPDOSTASK MZ_Current( void )

View File

@ -8,6 +8,7 @@
/* #define DEBUG_INT */ /* #define DEBUG_INT */
#include "debugtools.h" #include "debugtools.h"
#include "task.h" #include "task.h"
#include "dosexe.h"
/********************************************************************** /**********************************************************************
* INT_Int20Handler * INT_Int20Handler
@ -16,5 +17,5 @@
*/ */
void WINAPI INT_Int20Handler( CONTEXT86 *context ) void WINAPI INT_Int20Handler( CONTEXT86 *context )
{ {
ExitThread( 0 ); MZ_Exit( context, TRUE, 0 );
} }

View File

@ -954,7 +954,7 @@ static void INT21_SetCurrentPSP(WORD psp)
ERR("Cannot change PSP for non-DOS task!\n"); ERR("Cannot change PSP for non-DOS task!\n");
} }
static WORD INT21_GetCurrentPSP() static WORD INT21_GetCurrentPSP(void)
{ {
LPDOSTASK lpDosTask = MZ_Current(); LPDOSTASK lpDosTask = MZ_Current();
if (lpDosTask) if (lpDosTask)
@ -963,6 +963,15 @@ static WORD INT21_GetCurrentPSP()
return GetCurrentPDB16(); return GetCurrentPDB16();
} }
static WORD INT21_GetReturnCode(void)
{
LPDOSTASK lpDosTask = MZ_Current();
if (lpDosTask) {
WORD ret = lpDosTask->retval;
lpDosTask->retval = 0;
return ret;
} else return 0;
}
/*********************************************************************** /***********************************************************************
* INT21_GetExtendedError * INT21_GetExtendedError
@ -1136,7 +1145,7 @@ void WINAPI DOS3Call( CONTEXT86 *context )
case 0x00: /* TERMINATE PROGRAM */ case 0x00: /* TERMINATE PROGRAM */
TRACE("TERMINATE PROGRAM\n"); TRACE("TERMINATE PROGRAM\n");
ExitThread( 0 ); MZ_Exit( context, FALSE, 0 );
break; break;
case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */ case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
@ -1835,21 +1844,27 @@ void WINAPI DOS3Call( CONTEXT86 *context )
case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */ case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
TRACE("EXEC %s\n", TRACE("EXEC %s\n",
(LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx )); (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx ));
AX_reg(context) = WinExec16( CTX_SEG_OFF_TO_LIN(context, context->SegDs, if (ISV86(context)) {
context->Edx ), if (!MZ_Exec( context, CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx),
SW_NORMAL ); AL_reg(context), CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx) ))
if (AX_reg(context) < 32) SET_CFLAG(context); bSetDOSExtendedError = TRUE;
} else {
AX_reg(context) = WinExec16( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
context->Edx ),
SW_NORMAL );
if (AX_reg(context) < 32) SET_CFLAG(context);
}
break; break;
case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */ case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
TRACE("EXIT with return code %d\n",AL_reg(context)); TRACE("EXIT with return code %d\n",AL_reg(context));
ExitThread( AL_reg(context) ); MZ_Exit( context, FALSE, AL_reg(context) );
break; break;
case 0x4d: /* GET RETURN CODE */ case 0x4d: /* GET RETURN CODE */
TRACE("GET RETURN CODE (ERRORLEVEL)\n"); TRACE("GET RETURN CODE (ERRORLEVEL)\n");
AX_reg(context) = 0; /* normal exit */ AX_reg(context) = INT21_GetReturnCode();
break; break;
case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */ case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */