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;
typedef struct _DOSTASK {
WORD psp_seg;
WORD psp_seg, retval;
WORD dpmi_flag;
} DOSTASK, *LPDOSTASK;
@ -31,6 +31,8 @@ typedef struct _DOSTASK {
#define V86_FLAG 0x00020000
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_AllocDPMITask( void );
extern int DOSVM_Enter( CONTEXT86 *context );

View File

@ -26,7 +26,7 @@ typedef struct
WORD parentPSP; /* 16 Selector of parent PSP */
BYTE fileHandles[20]; /* 18 Open file handles */
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 */
SEGPTR fileHandlesPtr; /* 34 Pointer to file handle table */
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 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 char mm_name[128];
@ -66,13 +86,18 @@ static void MZ_Launch(void);
static BOOL MZ_InitTask(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;
psp->int20=0x20CD; /* int 20 */
/* some programs use this to calculate how much memory they need */
psp->nextParagraph=0x9FFF;
psp->nextParagraph=0x9FFF; /* FIXME: use a real value */
/* FIXME: dispatcher */
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 */
}
@ -178,25 +203,30 @@ static BOOL MZ_InitMemory(void)
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;
IMAGE_NT_HEADERS *win_hdr = PE_HEADER(module);
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, alloc=0;
BYTE*psp_start,*load_start,*oldenv;
int x, old_com=0, alloc;
SEGPTR reloc;
WORD env_seg, load_seg;
WORD env_seg, load_seg, rel_seg, oldpsp_seg;
DWORD len;
win_hdr->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
win_hdr->OptionalHeader.AddressOfEntryPoint = (LPBYTE)MZ_Launch - (LPBYTE)module;
if (!lpDosTask) {
if (lpDosTask) {
/* DOS process already running, inherit from it */
PDB16* par_psp = (PDB16*)((DWORD)lpDosTask->psp_seg << 4);
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;
lpDosTask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSTASK));
dos_current = lpDosTask;
oldenv = GetEnvironmentStringsA();
oldpsp_seg = 0;
}
SetFilePointer(hFile,0,NULL,FILE_BEGIN);
@ -220,10 +250,16 @@ BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
max_size=image_size+((DWORD)mz_header.e_maxalloc<<4)+(PSP_SIZE<<4);
}
MZ_InitMemory();
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 */
env_seg=MZ_InitEnvironment(GetEnvironmentStringsA(),filename);
env_seg=MZ_InitEnvironment(oldenv, filename);
/* allocate memory for the executable */
TRACE("Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size);
@ -241,8 +277,10 @@ BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
goto load_error;
}
load_seg=lpDosTask->psp_seg+(old_com?0:PSP_SIZE);
rel_seg=load_seg;
load_start=psp_start+(PSP_SIZE<<4);
MZ_CreatePSP(psp_start, env_seg);
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);
@ -262,18 +300,20 @@ BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
SetLastError(ERROR_BAD_FORMAT);
goto load_error;
}
*(WORD*)SEGPTR16(load_start,reloc)+=load_seg;
*(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;
TRACE("entry point: %04x:%04x\n",init_cs,init_ip);
}
if (!MZ_InitTask()) {
if (alloc && !MZ_InitTask()) {
MZ_KillTask();
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
@ -282,6 +322,7 @@ BOOL MZ_LoadImage( HMODULE module, HANDLE hFile, LPCSTR filename )
return TRUE;
load_error:
lpDosTask->psp_seg = oldpsp_seg;
if (alloc) {
dos_current = NULL;
if (mm_name[0]!=0) unlink(mm_name);
@ -290,6 +331,80 @@ load_error:
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 lpDosTask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSTASK));
@ -435,21 +550,70 @@ static void MZ_KillTask(void)
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 */
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);
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 )
{
ERR("Actual real-mode calls not supported on this architecture!\n");
ERR("Actual real-mode calls not supported on this platform!\n");
return NULL;
}
void MZ_Exit( CONTEXT86 *context, BOOL cs_psp, WORD retval )
{
ExitThread( retval );
}
#endif /* !MZ_SUPPORTED */
LPDOSTASK MZ_Current( void )

View File

@ -8,6 +8,7 @@
/* #define DEBUG_INT */
#include "debugtools.h"
#include "task.h"
#include "dosexe.h"
/**********************************************************************
* INT_Int20Handler
@ -16,5 +17,5 @@
*/
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");
}
static WORD INT21_GetCurrentPSP()
static WORD INT21_GetCurrentPSP(void)
{
LPDOSTASK lpDosTask = MZ_Current();
if (lpDosTask)
@ -963,6 +963,15 @@ static WORD INT21_GetCurrentPSP()
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
@ -1136,7 +1145,7 @@ void WINAPI DOS3Call( CONTEXT86 *context )
case 0x00: /* TERMINATE PROGRAM */
TRACE("TERMINATE PROGRAM\n");
ExitThread( 0 );
MZ_Exit( context, FALSE, 0 );
break;
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 */
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 ));
if (ISV86(context)) {
if (!MZ_Exec( context, CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx),
AL_reg(context), CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx) ))
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;
case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
TRACE("EXIT with return code %d\n",AL_reg(context));
ExitThread( AL_reg(context) );
MZ_Exit( context, FALSE, AL_reg(context) );
break;
case 0x4d: /* GET RETURN CODE */
TRACE("GET RETURN CODE (ERRORLEVEL)\n");
AX_reg(context) = 0; /* normal exit */
AX_reg(context) = INT21_GetReturnCode();
break;
case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */