Implemented DOS INT21 AH=4B (EXEC).
This commit is contained in:
parent
7b0bf0f08d
commit
7c4bee569c
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue