Improved set descriptor access rights Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1198
2942 lines
93 KiB
C++
2942 lines
93 KiB
C++
/*
|
||
* Copyright (C) 2002-2003 The DOSBox Team
|
||
*
|
||
* This program is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU Library General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program; if not, write to the Free Software
|
||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
*/
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "dosbox.h"
|
||
#include "dos_inc.h"
|
||
#include "callback.h"
|
||
#include "mem.h"
|
||
#include "regs.h"
|
||
#include "dos_system.h"
|
||
#include "setup.h"
|
||
#include "inout.h"
|
||
#include "cpu.h"
|
||
|
||
//#define DPMI_LOG LOG(LOG_MISC,LOG_ERROR)
|
||
#define DPMI_LOG
|
||
|
||
#define DPMI_LOG_ERROR LOG(LOG_MISC,LOG_ERROR)
|
||
//#define DPMI_LOG_ERROR
|
||
|
||
|
||
#define DPMI_ALLOC_NEEDEDMEM_HIGH 1
|
||
|
||
#define DPMI_DPL 3
|
||
|
||
#define GDT_ZERO 0
|
||
#define GDT_LDT ((0x1 << 3) | DPMI_DPL)
|
||
#define GDT_CODE ((0x2 << 3) | DPMI_DPL)
|
||
#define GDT_PROTCODE ((0x3 << 3) | DPMI_DPL)
|
||
#define GDT_DOSDATA ((0x4 << 3) | DPMI_DPL)
|
||
#define GDT_ENVIRONMENT ((0x5 << 3) | DPMI_DPL)
|
||
|
||
// TEMP
|
||
#define GDT_DOSSEG40 (0x40)
|
||
|
||
/* Amount of descriptors in each table */
|
||
#define GDT_SIZE 32
|
||
#define IDT_SIZE 256
|
||
#define LDT_SIZE 2048
|
||
#define INT_SIZE 256
|
||
|
||
#define TOTAL_SIZE ((GDT_SIZE+IDT_SIZE+LDT_SIZE+INT_SIZE)*8)
|
||
|
||
#define LDT_ENTRY(BLAH_) (BLAH_ << 3)
|
||
|
||
#define LDT_FIRSTSELECTOR 16
|
||
|
||
#define DPMI_ERROR_UNSUPPORTED 0x8001
|
||
#define DPMI_ERROR_DESCRIPTOR_UNAVAILABLE 0x8011
|
||
#define DPMI_ERROR_LINEAR_MEMORY_UNAVAILABLE 0x8012
|
||
#define DPMI_ERROR_PHYSICAL_MEMORY_UNAVAILABLE 0x8013
|
||
#define DPMI_ERROR_CALLBACK_UNAVAILABLE 0x8015
|
||
#define DPMI_ERROR_INVALID_SELECTOR 0x8022
|
||
#define DPMI_ERROR_INVALID_VALUE 0x8022
|
||
#define DPMI_ERROR_INVALID_HANDLE 0x8023
|
||
#define DPMI_ERROR_INVALID_CALLBACK 0x8024
|
||
#define DPMI_ERROR_INVALID_LINEAR_ADDRESS 0x8025
|
||
|
||
#define DPMI_XMSHANDLES_MAX 256
|
||
#define DPMI_XMSHANDLE_FREE 0xFFFF
|
||
#define DPMI_EXCEPTION_MAX 0x20
|
||
#define DPMI_PAGE_SIZE (4*1024)
|
||
#define DPMI_REALMODE_CALLBACK_MAX 32
|
||
#define DPMI_REALMODE_STACKSIZE 4096
|
||
#define DPMI_PROTMODE_STACK_MAX 3
|
||
#define DPMI_PROTMODE_STACKSIZE (4*1024)
|
||
#define DPMI_REALVEC_MAX 17
|
||
#define DPMI_SAVESTACK_MAX 1024
|
||
|
||
#define DPMI_CB_APIMSDOSENTRY_OFFSET 256*8
|
||
#define DPMI_CB_ENTERREALMODE_OFFSET 257*8
|
||
#define DPMI_CB_SAVESTATE_OFFSET 258*8
|
||
#define DPMI_CB_EXCEPTION_OFFSET 259*8
|
||
#define DPMI_CB_EXCEPTIONRETURN_OFFSET 260*8
|
||
#define DPMI_CB_VENDORENTRY_OFFSET 261*8
|
||
|
||
#define DPMI_HOOK_HARDWARE_INTS 1
|
||
|
||
static Bitu rmIndexToInt[DPMI_REALVEC_MAX] =
|
||
{ 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x1C };
|
||
|
||
// General functions
|
||
void CALLBACK32_SCF(bool val)
|
||
{
|
||
Bit32u tempf=mem_readd(SegPhys(ss)+reg_esp+8) & 0xFFFFFFFE;
|
||
Bit32u newCF=(val==true);
|
||
mem_writed(SegPhys(ss)+reg_esp+8,(tempf | newCF));
|
||
};
|
||
|
||
#define DPMI_CALLBACK_SCF(b) if (dpmi.client.bit32) CALLBACK32_SCF(b); else CALLBACK_SCF(b)
|
||
|
||
// **********************************************
|
||
// SetDescriptor Class
|
||
// **********************************************
|
||
|
||
#pragma pack(1)
|
||
class SetDescriptor : public Descriptor {
|
||
public:
|
||
void Save(PhysPt address) {
|
||
Bit32u* data = (Bit32u*)&saved;
|
||
mem_writed(address,*data);
|
||
mem_writed(address+4,*(data+1));
|
||
}
|
||
|
||
void SetBase(Bitu _base) {
|
||
saved.seg.base_24_31=_base >> 24;
|
||
saved.seg.base_16_23=_base >> 16;
|
||
saved.seg.base_0_15=_base;
|
||
}
|
||
void SetLimit (Bitu _limit) {
|
||
if (_limit<1048576) saved.seg.g=false;
|
||
else {
|
||
saved.seg.g=true;
|
||
_limit>>=12;
|
||
}
|
||
saved.seg.limit_0_15=_limit;
|
||
saved.seg.limit_16_19=_limit>>16;
|
||
}
|
||
void SetOffset(Bitu _offset) {
|
||
saved.gate.offset_0_15=_offset;
|
||
saved.gate.offset_16_31=(_offset>>16);
|
||
}
|
||
void SetSelector(Bitu _selector) {
|
||
saved.gate.selector=_selector;
|
||
}
|
||
void SetType(Bitu _type) {
|
||
saved.seg.type=_type;
|
||
}
|
||
void Clear(void) {
|
||
saved.fill[0]=saved.fill[1]=0;
|
||
}
|
||
};
|
||
#pragma pack()
|
||
|
||
// **********************************************
|
||
// Shared Memory
|
||
// **********************************************
|
||
|
||
typedef struct SSharedMem {
|
||
|
||
std::string name;
|
||
Bitu handle;
|
||
Bitu pages;
|
||
|
||
} TSharedMem;
|
||
|
||
std::list<TSharedMem*> g_sharedMemList;
|
||
|
||
// **********************************************
|
||
// DPMI Class
|
||
// **********************************************
|
||
|
||
class DPMI {
|
||
|
||
public:
|
||
DPMI (void);
|
||
~DPMI (void);
|
||
|
||
// Settp/Startup methods
|
||
void Setup (void);
|
||
Bitu Entrypoint (void);
|
||
RealPt HookInterrupt (Bitu num, Bitu intHandler);
|
||
void RestoreHookedInterrupt (Bitu num, RealPt oldVec);
|
||
void CreateStackSpace (void);
|
||
bool HasClient (void) { return dpmi.client.have; };
|
||
void Terminate (void);
|
||
void Reactivate (void);
|
||
|
||
// DPMI Services
|
||
Bitu AllocateLDTDescriptor (Bitu count,Bitu & base);
|
||
Bitu AllocateLDTDescriptor2 (Bitu count,Bitu & base); // TEMP
|
||
bool AllocateMem (Bitu size, Bitu& outHandle, Bitu& linear);
|
||
Bitu CreateAlias (Bitu selector, Bit16u& alias);
|
||
void ReloadSegments (Bitu selector);
|
||
bool SetAccessRights (Bitu selector, SetDescriptor& desc, Bitu rights);
|
||
|
||
// Special Interrupt handlers
|
||
Bitu Int2fHandler (void);
|
||
Bitu Int31Handler (void);
|
||
|
||
// Exceptions
|
||
void CreateException (Bitu num, Bitu errorCode);
|
||
Bitu ExceptionReturn (void);
|
||
|
||
// Realmode callbacks
|
||
bool AllocateRealModeCallback(Bitu codeSel,Bitu codeOff,Bitu dataSel, Bitu dataOff, Bitu& segment, Bitu& offset);
|
||
Bitu RealModeCallback (void);
|
||
Bitu RealModeCallbackReturn (void);
|
||
|
||
// Real mode reflection callbacks
|
||
void PrepareReflectToReal (Bitu num);
|
||
Bitu CallRealIRETFrame (void);
|
||
Bitu CallRealIRETFrameReturn (void);
|
||
Bitu SimulateInt (void);
|
||
Bitu SimulateIntReturn (void);
|
||
Bitu ptorHandler (void);
|
||
Bitu ptorHandlerReturn (void);
|
||
Bitu Int21Handler (void);
|
||
Bitu Int21HandlerReturn (void);
|
||
Bitu HWIntDefaultHandler (void);
|
||
void RemoveIntCallbacks (void);
|
||
void RestoreIntCallbacks (void);
|
||
|
||
// Switching modes
|
||
void SaveRegisterState (Bitu num);
|
||
void LoadRegisterState (Bitu num);
|
||
Bitu EnterProtMode (void);
|
||
Bitu EnterRealMode (void);
|
||
Bitu RealSaveState (void);
|
||
Bitu ProtSaveState (void);
|
||
|
||
// virtual interrupt flag
|
||
bool GetVirtualIntFlag (void);
|
||
void SetVirtualIntFlag (bool on);
|
||
|
||
// Internal Stack for saving processor status
|
||
void PushStack (Bitu val) { saveStack[savePtr++] = val; };
|
||
Bitu PopStack (void) { return saveStack[--savePtr]; };
|
||
void SaveSegments (void);
|
||
void SaveRegister (void);
|
||
void RestoreSegments (void);
|
||
void RestoreRegister (void);
|
||
|
||
void CopyRegistersToBuffer (PhysPt data);
|
||
void LoadRegistersFromBuffer (PhysPt data);
|
||
|
||
void ProvideRealModeStack (PhysPt prStack, Bitu toCopy);
|
||
void UpdateRealModeStack (void);
|
||
|
||
// xms handle information
|
||
void SetXMSHandle (Bitu handle);
|
||
void ClearXMSHandles (void);
|
||
void FreeXMSHandle (Bitu handle);
|
||
|
||
// shared memory
|
||
void SetSharedMem (const char* name, Bitu handle, Bitu pages);
|
||
bool GetSharedMem (const char* name, Bitu& handle, Bitu& pages);
|
||
bool IsSharedMem (Bitu handle);
|
||
bool RemoveSharedMem (Bitu handle);
|
||
|
||
// special msdos api stuff
|
||
Bitu GetSegmentFromSelector (Bitu selector);
|
||
bool GetMsdosSelector (Bitu realseg, Bitu realoff, Bitu &protsel, Bitu &protoff);
|
||
void API_Init_MSDOS (void);
|
||
Bitu API_Entry_MSDOS (void);
|
||
Bitu API_Int21_MSDOS (void);
|
||
|
||
private:
|
||
Bitu Mask (Bitu value);
|
||
|
||
Bitu saveStack[DPMI_SAVESTACK_MAX];
|
||
Bitu savePtr;
|
||
Bitu rm_ss, rm_sp;
|
||
|
||
struct {
|
||
struct {
|
||
bool have;
|
||
bool bit32;
|
||
Bitu psp;
|
||
} client;
|
||
Bit16u mem_handle; /* Handle for GDT/IDT */
|
||
struct {
|
||
PhysPt base;
|
||
Bitu limit;
|
||
} gdt,idt,ldt;
|
||
struct {
|
||
bool inCall;
|
||
bool inUse;
|
||
bool stop;
|
||
Bitu callCount;
|
||
Bitu id;
|
||
Bitu dataSelector,dataOffset;
|
||
Bitu codeSelector,codeOffset;
|
||
Bitu realSegment ,realOffset;
|
||
} rmCallback[DPMI_REALMODE_CALLBACK_MAX];
|
||
|
||
RealPt realModeVec [DPMI_REALVEC_MAX];
|
||
Bitu oldRealVec [DPMI_REALVEC_MAX];
|
||
Bitu defaultHWIntFromProtMode[DPMI_REALVEC_MAX];
|
||
|
||
PhysPt ptorint_base; /* Base of pmode int handlers that reflect to realmode */
|
||
Bitu exceptionSelector[DPMI_EXCEPTION_MAX],exceptionOffset[DPMI_EXCEPTION_MAX];
|
||
|
||
Bitu xmsHandles[DPMI_XMSHANDLES_MAX];
|
||
Bitu protStack;
|
||
|
||
Bitu protStackSelector[DPMI_PROTMODE_STACK_MAX];
|
||
Bitu realStackSelector[DPMI_PROTMODE_STACK_MAX];
|
||
Bitu dataSelector [DPMI_PROTMODE_STACK_MAX];
|
||
Bitu protStackCurrent;
|
||
|
||
Bitu vIntFlag;
|
||
|
||
bool pharlap;
|
||
bool suppressRMCB;
|
||
} dpmi;
|
||
|
||
Bit32u* modIntTable;
|
||
DPMI* prevDPMI;
|
||
|
||
Bitu dtaAddress;
|
||
Bitu save_cs[2],save_ds[2],save_es[2],save_fs[2],save_gs[2],save_ss[2];
|
||
Bitu save_eax[2],save_ebx[2],save_ecx[2],save_edx[2],save_esi[2],save_edi[2];
|
||
Bitu save_ebp[2],save_esp[2],save_eip[2],save_fl[2];
|
||
};
|
||
|
||
struct {
|
||
Bitu entry;
|
||
Bitu ptorint;
|
||
Bitu ptorintReturn;
|
||
Bitu int31;
|
||
Bitu int21;
|
||
Bitu int21Return;
|
||
Bitu int2f;
|
||
Bitu enterpmode;
|
||
Bitu enterrmode;
|
||
Bitu protsavestate;
|
||
Bitu realsavestate;
|
||
Bitu simint;
|
||
Bitu simintReturn;
|
||
Bitu rmIntFrame;
|
||
Bitu rmIntFrameReturn;
|
||
Bitu rmCallbackReturn;
|
||
Bitu exception;
|
||
Bitu exceptionret;
|
||
// Special callbacks for special dos extenders
|
||
Bitu apimsdosentry;
|
||
Bitu int21msdos;
|
||
} callback;
|
||
|
||
// ************************************************
|
||
// DPMI static functions
|
||
// ************************************************
|
||
|
||
static DPMI* activeDPMI = 0;
|
||
static Bit32u originalIntTable[256];
|
||
|
||
bool DPMI_IsActive(void)
|
||
{
|
||
return (cpu.cr0 & CR0_PROTECTION) && activeDPMI && activeDPMI->HasClient();
|
||
}
|
||
|
||
void DPMI_SetVirtualIntFlag(bool on)
|
||
{
|
||
if (activeDPMI) activeDPMI->SetVirtualIntFlag(on);
|
||
}
|
||
|
||
void DPMI_CreateException(Bitu num, Bitu errorCode)
|
||
{
|
||
if (activeDPMI) activeDPMI->CreateException(num,errorCode);
|
||
}
|
||
|
||
// ************************************************
|
||
// DPMI Methods
|
||
// ************************************************
|
||
|
||
DPMI::DPMI(void)
|
||
{
|
||
memset(&dpmi,0,sizeof(dpmi));
|
||
savePtr = 0;
|
||
dtaAddress = 0;
|
||
rm_ss = rm_sp = 0;
|
||
modIntTable = 0;
|
||
prevDPMI = activeDPMI;
|
||
};
|
||
|
||
DPMI::~DPMI(void)
|
||
{
|
||
MEM_ReleasePages(dpmi.mem_handle);
|
||
// TODO: Free all memory allocated with DOS_GetMemory
|
||
// Activate previous dpmi
|
||
activeDPMI = prevDPMI;
|
||
};
|
||
|
||
void DPMI::ClearXMSHandles(void)
|
||
{
|
||
for (Bitu i=0; i<DPMI_XMSHANDLES_MAX; i++) dpmi.xmsHandles[i]=DPMI_XMSHANDLE_FREE;
|
||
};
|
||
|
||
void DPMI::SetSharedMem(const char* name, Bitu handle, Bitu pages)
|
||
{
|
||
TSharedMem* smem = new TSharedMem();
|
||
smem->name = name;
|
||
smem->handle= handle;
|
||
smem->pages = pages;
|
||
g_sharedMemList.push_back(smem);
|
||
};
|
||
|
||
bool DPMI::GetSharedMem(const char* name, Bitu& handle, Bitu& pages)
|
||
{
|
||
TSharedMem* smem;
|
||
std::list<TSharedMem*>::iterator i;
|
||
for(i = g_sharedMemList.begin(); i != g_sharedMemList.end(); i++) {
|
||
smem = static_cast<TSharedMem*>(*i);
|
||
if (smem->name.compare(name)==0) {
|
||
handle = smem->handle;
|
||
pages = smem->pages;
|
||
return true;
|
||
}
|
||
|
||
};
|
||
return false;
|
||
};
|
||
|
||
bool DPMI::IsSharedMem(Bitu handle)
|
||
{
|
||
std::list<TSharedMem*>::iterator i;
|
||
for(i = g_sharedMemList.begin(); i != g_sharedMemList.end(); i++) {
|
||
if ((*i)->handle==handle) return true;
|
||
};
|
||
return false;
|
||
};
|
||
|
||
bool DPMI::RemoveSharedMem(Bitu handle)
|
||
{
|
||
TSharedMem* smem;
|
||
std::list<TSharedMem*>::iterator i;
|
||
for(i = g_sharedMemList.begin(); i != g_sharedMemList.end(); i++) {
|
||
smem = static_cast<TSharedMem*>(*i);
|
||
if (smem->handle==handle) {
|
||
g_sharedMemList.remove(*i);
|
||
delete smem;
|
||
return true;
|
||
}
|
||
|
||
};
|
||
return false;
|
||
};
|
||
|
||
void DPMI::SetXMSHandle(Bitu handle) {
|
||
for (Bitu i=0; i<DPMI_XMSHANDLES_MAX; i++) {
|
||
if (dpmi.xmsHandles[i]==DPMI_XMSHANDLE_FREE) {
|
||
dpmi.xmsHandles[i]=handle;
|
||
return;
|
||
}
|
||
};
|
||
E_Exit("DPMI: No more DPMI XMS Handles available.");
|
||
};
|
||
|
||
void DPMI::FreeXMSHandle(Bitu handle) {
|
||
|
||
RemoveSharedMem(handle);
|
||
for (Bitu i=0; i<DPMI_XMSHANDLES_MAX; i++) {
|
||
if (dpmi.xmsHandles[i]==handle) {
|
||
dpmi.xmsHandles[i]=DPMI_XMSHANDLE_FREE;
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
void DPMI::SaveSegments(void)
|
||
{
|
||
if (savePtr+5>=DPMI_SAVESTACK_MAX) E_Exit("DPMI: Stack too small.");
|
||
saveStack[savePtr++] = SegValue(ds);
|
||
saveStack[savePtr++] = SegValue(es);
|
||
saveStack[savePtr++] = SegValue(fs);
|
||
saveStack[savePtr++] = SegValue(gs);
|
||
saveStack[savePtr++] = SegValue(ss);
|
||
}
|
||
|
||
void DPMI::SaveRegister(void)
|
||
{
|
||
SaveSegments();
|
||
if (savePtr+8>=DPMI_SAVESTACK_MAX) E_Exit("DPMI: Stack too small.");
|
||
saveStack[savePtr++] = reg_eax;
|
||
saveStack[savePtr++] = reg_ebx;
|
||
saveStack[savePtr++] = reg_ecx;
|
||
saveStack[savePtr++] = reg_edx;
|
||
saveStack[savePtr++] = reg_esi;
|
||
saveStack[savePtr++] = reg_edi;
|
||
saveStack[savePtr++] = reg_ebp;
|
||
saveStack[savePtr++] = reg_esp;
|
||
};
|
||
|
||
void DPMI::RestoreSegments(void)
|
||
{
|
||
CPU_SetSegGeneral(ss,saveStack[--savePtr]);
|
||
CPU_SetSegGeneral(gs,saveStack[--savePtr]);
|
||
CPU_SetSegGeneral(fs,saveStack[--savePtr]);
|
||
CPU_SetSegGeneral(es,saveStack[--savePtr]);
|
||
CPU_SetSegGeneral(ds,saveStack[--savePtr]);
|
||
};
|
||
|
||
void DPMI::RestoreRegister(void)
|
||
{
|
||
reg_esp = saveStack[--savePtr];
|
||
reg_ebp = saveStack[--savePtr];
|
||
reg_edi = saveStack[--savePtr];
|
||
reg_esi = saveStack[--savePtr];
|
||
reg_edx = saveStack[--savePtr];
|
||
reg_ecx = saveStack[--savePtr];
|
||
reg_ebx = saveStack[--savePtr];
|
||
reg_eax = saveStack[--savePtr];
|
||
RestoreSegments();
|
||
};
|
||
|
||
void DPMI::CopyRegistersToBuffer(PhysPt data)
|
||
{
|
||
// Save Values in structure
|
||
mem_writed(data+0x00, reg_edi);
|
||
mem_writed(data+0x04, reg_esi);
|
||
mem_writed(data+0x08, reg_ebp);
|
||
mem_writed(data+0x0C, 0x0000);
|
||
mem_writed(data+0x10, reg_ebx);
|
||
mem_writed(data+0x14, reg_edx);
|
||
mem_writed(data+0x18, reg_ecx);
|
||
mem_writed(data+0x1C, reg_eax);
|
||
mem_writew(data+0x20, flags.word);
|
||
mem_writew(data+0x22, SegValue(es));
|
||
mem_writew(data+0x24, SegValue(ds));
|
||
mem_writew(data+0x26, SegValue(fs));
|
||
mem_writew(data+0x28, SegValue(gs));
|
||
mem_writew(data+0x2A, reg_ip);
|
||
mem_writew(data+0x2C, SegValue(cs));
|
||
mem_writew(data+0x2E, reg_sp);
|
||
mem_writew(data+0x30, SegValue(ss));
|
||
}
|
||
|
||
void DPMI::LoadRegistersFromBuffer(PhysPt data)
|
||
{
|
||
reg_edi = mem_readd(data+0x00);
|
||
reg_esi = mem_readd(data+0x04);
|
||
reg_ebp = mem_readd(data+0x08);
|
||
reg_ebx = mem_readd(data+0x10);
|
||
reg_edx = mem_readd(data+0x14);
|
||
reg_ecx = mem_readd(data+0x18);
|
||
reg_eax = mem_readd(data+0x1C);
|
||
CPU_SetFlagsw(mem_readw(data+0x20));
|
||
SegSet16(es,mem_readw(data+0x22));
|
||
SegSet16(ds,mem_readw(data+0x24));
|
||
SegSet16(fs,mem_readw(data+0x26));
|
||
SegSet16(gs,mem_readw(data+0x28));
|
||
reg_esp = mem_readw(data+0x2E);
|
||
SegSet16(ss,mem_readw(data+0x30));
|
||
if (!dpmi.client.bit32) {
|
||
reg_eax &= 0xFFFF;
|
||
reg_ebx &= 0xFFFF;
|
||
reg_ecx &= 0xFFFF;
|
||
reg_edx &= 0xFFFF;
|
||
reg_edi &= 0xFFFF;
|
||
reg_esi &= 0xFFFF;
|
||
reg_ebp &= 0xFFFF;
|
||
reg_esp &= 0xFFFF;
|
||
};
|
||
};
|
||
|
||
void DPMI::ProvideRealModeStack(PhysPt prStack, Bitu toCopy)
|
||
{
|
||
// Check stack, if zero provide it
|
||
if ((SegValue(ss)==0) && (reg_sp==0)) {
|
||
SegSet16(ss,rm_ss);
|
||
reg_esp = rm_sp;
|
||
} else {
|
||
if (SegValue(ss)==rm_ss) reg_esp = rm_sp;
|
||
};
|
||
// We have to be in realmode here
|
||
if (toCopy>0) {
|
||
Bitu numBytes = toCopy*2;
|
||
if (reg_esp<numBytes) E_Exit("DPMI:CopyStack: SP invalid.");
|
||
PhysPt targetStack = SegValue(ss)+reg_esp-numBytes;
|
||
MEM_BlockCopy(targetStack,prStack,numBytes);
|
||
reg_esp -= numBytes;
|
||
}
|
||
};
|
||
|
||
void DPMI::UpdateRealModeStack()
|
||
{
|
||
if (SegValue(ss)==rm_ss) {
|
||
if (reg_esp>DPMI_REALMODE_STACKSIZE) E_Exit("DPMI:Realmode stack out of range: %04X",reg_esp);
|
||
rm_sp = reg_sp;
|
||
}
|
||
};
|
||
|
||
Bitu DPMI::AllocateLDTDescriptor(Bitu count,Bitu & base) {
|
||
|
||
SetDescriptor test;
|
||
Bitu i=16, found=0;
|
||
PhysPt address = dpmi.ldt.base + LDT_FIRSTSELECTOR*8;
|
||
while (i<LDT_SIZE) {
|
||
test.Load(address);
|
||
if (test.saved.seg.p) found=0;
|
||
else found++;
|
||
i++;
|
||
address+=8;
|
||
if (found==count) {
|
||
/* Init allocated descriptors */
|
||
test.Clear();
|
||
test.SetType(DESC_DATA_EU_RW_NA);
|
||
test.saved.seg.p = 1;
|
||
test.saved.seg.big = dpmi.client.bit32;
|
||
test.saved.seg.dpl = DPMI_DPL;
|
||
base = ((i-found) << 3)|(4|DPMI_DPL); /* Make it an LDT Entry */
|
||
address = dpmi.ldt.base+(base & ~7);
|
||
for (;found>0;found--) {
|
||
test.Save(address);
|
||
address+=8;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
Bitu DPMI::AllocateLDTDescriptor2(Bitu count,Bitu & base) {
|
||
|
||
static Bitu allocated = 0;
|
||
|
||
SetDescriptor desc;
|
||
Bitu nr = LDT_FIRSTSELECTOR + allocated;
|
||
if (nr+count < LDT_SIZE) {
|
||
desc.Clear();
|
||
desc.SetType(DESC_DATA_EU_RW_NA);
|
||
desc.saved.seg.p = 1;
|
||
desc.saved.seg.big = dpmi.client.bit32;
|
||
desc.saved.seg.dpl = DPMI_DPL;
|
||
base = (nr << 3)|(4|DPMI_DPL); /* Make it an LDT Entry */
|
||
allocated += count;
|
||
Bitu address = dpmi.ldt.base+(base & ~7);
|
||
for (;count>0;count--) {
|
||
desc.Save(address);
|
||
address+=8;
|
||
}
|
||
return true;
|
||
};
|
||
return false;
|
||
}
|
||
|
||
Bitu DPMI::CreateAlias(Bitu selector, Bit16u& alias)
|
||
{
|
||
Descriptor oldDesc;
|
||
Bitu base;
|
||
if (!cpu.gdt.GetDescriptor(selector,oldDesc)) { alias = DPMI_ERROR_INVALID_SELECTOR; return false; };
|
||
if (!AllocateLDTDescriptor(1,base)) { alias = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE; return false; };
|
||
SetDescriptor desc;
|
||
desc.Clear();
|
||
desc.SetLimit(oldDesc.GetLimit());
|
||
desc.SetBase (oldDesc.GetBase());
|
||
desc.SetType (DESC_DATA_ED_RW_A);
|
||
desc.saved.seg.p=1;
|
||
desc.saved.seg.dpl = DPMI_DPL;
|
||
desc.Save (dpmi.ldt.base+(base & ~7));
|
||
alias = base;
|
||
return true;
|
||
};
|
||
|
||
void DPMI::ReloadSegments(Bitu selector)
|
||
{
|
||
if (SegValue(cs)==selector) CPU_SetSegGeneral(cs,selector);
|
||
if (SegValue(ds)==selector) CPU_SetSegGeneral(ds,selector);
|
||
if (SegValue(es)==selector) CPU_SetSegGeneral(es,selector);
|
||
if (SegValue(fs)==selector) CPU_SetSegGeneral(fs,selector);
|
||
if (SegValue(gs)==selector) CPU_SetSegGeneral(gs,selector);
|
||
if (SegValue(ss)==selector) CPU_SetSegGeneral(ss,selector);
|
||
};
|
||
|
||
void DPMI::CreateException(Bitu num, Bitu errorCode)
|
||
{
|
||
if (dpmi.client.bit32) {
|
||
CPU_Push32(SegValue(ss));
|
||
CPU_Push32(reg_esp);
|
||
CPU_Push32(flags.word);
|
||
CPU_Push32(SegValue(cs));
|
||
CPU_Push32(reg_eip-2); // FIXME: Fake !
|
||
CPU_Push32(errorCode);
|
||
CPU_Push32(GDT_PROTCODE); // return cs
|
||
CPU_Push32(DPMI_CB_EXCEPTIONRETURN_OFFSET); // return eip
|
||
} else {
|
||
CPU_Push16(SegValue(ss));
|
||
CPU_Push16(reg_sp);
|
||
CPU_Push16(flags.word);
|
||
CPU_Push16(SegValue(cs));
|
||
CPU_Push16(reg_ip-2); // FIXME: Fake !
|
||
CPU_Push16(errorCode);
|
||
CPU_Push16(GDT_PROTCODE); // return cs
|
||
CPU_Push16(DPMI_CB_EXCEPTIONRETURN_OFFSET); // return eip
|
||
};
|
||
DPMI_LOG("DPMI: Exception occured : %04X (%04X:%08X)",num,dpmi.exceptionSelector[num],dpmi.exceptionOffset[num]);
|
||
CPU_JMP(dpmi.client.bit32,dpmi.exceptionSelector[num],dpmi.exceptionOffset[num]);
|
||
};
|
||
|
||
Bitu DPMI::ExceptionReturn(void)
|
||
{
|
||
Bitu error;
|
||
// Restore Registers
|
||
Bitu newcs;
|
||
if (dpmi.client.bit32) {
|
||
error = CPU_Pop32();
|
||
reg_eip = CPU_Pop32();
|
||
newcs = CPU_Pop32();
|
||
CPU_SetFlagsd(CPU_Pop32());
|
||
reg_esp = CPU_Pop32();
|
||
CPU_SetSegGeneral(ss,CPU_Pop32());
|
||
} else {
|
||
error = CPU_Pop16();
|
||
reg_eip = CPU_Pop16();
|
||
newcs = CPU_Pop16();
|
||
CPU_SetFlagsw(CPU_Pop16());
|
||
reg_esp = CPU_Pop16();
|
||
CPU_SetSegGeneral(ss,CPU_Pop16());
|
||
};
|
||
DPMI_LOG("DPMI: Return from Exception. Jump to %04X:%08X",SegValue(cs),reg_eip);
|
||
CPU_JMP(dpmi.client.bit32,newcs,reg_eip);
|
||
return 0;
|
||
};
|
||
|
||
void DPMI::RemoveIntCallbacks()
|
||
// When switching dpmi clients, remove active callbacks from hardware int
|
||
{
|
||
Bitu i;
|
||
modIntTable = new Bit32u[256];
|
||
// read and store interrupt table
|
||
for (i=0; i<256; i++) modIntTable[i] = mem_readd(i*4);
|
||
// set a clean interrupt table
|
||
for (i=0; i<256; i++) mem_writed(i*4,originalIntTable[i]);
|
||
};
|
||
|
||
void DPMI::RestoreIntCallbacks()
|
||
{
|
||
if (modIntTable) {
|
||
// restore modified interrupt table
|
||
for (int i=0; i<256; i++) mem_writed(i*4,modIntTable[i]);
|
||
delete[] modIntTable; modIntTable = 0;
|
||
}
|
||
};
|
||
|
||
bool DPMI::AllocateRealModeCallback(Bitu codeSel,Bitu codeOff,Bitu dataSel, Bitu dataOff, Bitu& segment, Bitu& offset)
|
||
{
|
||
Bitu num = 0;
|
||
for (Bitu i=0; i<DPMI_REALMODE_CALLBACK_MAX; i++) if (!dpmi.rmCallback[i].inUse) { num = i; break; };
|
||
if (num<DPMI_REALMODE_CALLBACK_MAX) {
|
||
RealPt entry = CALLBACK_RealPointer(dpmi.rmCallback[num].id);
|
||
dpmi.rmCallback[num].codeSelector = codeSel;
|
||
dpmi.rmCallback[num].codeOffset = codeOff;
|
||
dpmi.rmCallback[num].dataSelector = dataSel;
|
||
dpmi.rmCallback[num].dataOffset = dataOff;
|
||
dpmi.rmCallback[num].realSegment = segment = RealSeg(entry);
|
||
dpmi.rmCallback[num].realOffset = offset = RealOff(entry);
|
||
dpmi.rmCallback[num].inCall = false;
|
||
dpmi.rmCallback[num].inUse = true;
|
||
dpmi.rmCallback[num].callCount = 0;
|
||
return true;
|
||
}
|
||
return false;
|
||
};
|
||
|
||
Bitu DPMI::RealModeCallback(void)
|
||
{
|
||
// Call protected mode function
|
||
Bitu num = mem_readw(PhysPt(SegPhys(cs)+reg_eip-2));
|
||
num -= dpmi.rmCallback[0].id;
|
||
if ((num>=DPMI_REALMODE_CALLBACK_MAX) || !dpmi.rmCallback[num].inUse) E_Exit("DPMI: Illegal Realmode callback %02X.",num);
|
||
|
||
if (dpmi.rmCallback[num].inCall) DPMI_LOG("DPMI: Recursive Realmode callback %02X",num);
|
||
if (dpmi.protStackCurrent>DPMI_PROTMODE_STACK_MAX) E_Exit("DPMI: Too many recursive Realmode callbacks. Stack failure.");
|
||
|
||
PushStack(num);
|
||
|
||
DPMI_LOG("DPMI: Realmode Callback %02X (%04X:%08X) enter",num,dpmi.rmCallback[num].codeSelector,dpmi.rmCallback[num].codeOffset);
|
||
dpmi.rmCallback[num].inCall= true;
|
||
dpmi.rmCallback[num].callCount++;
|
||
|
||
// Important! Update realmode stack
|
||
UpdateRealModeStack();
|
||
// Setup stack selector of real mode stack
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(dpmi.realStackSelector[dpmi.protStackCurrent],desc)) {
|
||
desc.SetBase (SegValue(ss)<<4);
|
||
desc.SetLimit(0xFFFF);
|
||
desc.Save (dpmi.ldt.base+(dpmi.realStackSelector[dpmi.protStackCurrent] & ~7));
|
||
} else E_Exit("DPMI: RealmodeCB: Could not provide real mode stack descriptor.");
|
||
/* Switch to protected mode */
|
||
CPU_SET_CRX(0,cpu.cr0 | CR0_PROTECTION);
|
||
// Setup dataSelector
|
||
Descriptor data;
|
||
Bitu dataSelector;
|
||
if (dpmi.rmCallback[num].dataSelector==0x0000) dataSelector = dpmi.dataSelector[dpmi.protStackCurrent];
|
||
else dataSelector = dpmi.rmCallback[num].dataSelector;
|
||
if (!cpu.gdt.GetDescriptor(dataSelector,data)) E_Exit("DPMI: Init RM-Callback failed.");
|
||
|
||
DPMI_LOG("DPMI: CB: Writing RegData at = %04X:%04X",dataSelector,dpmi.rmCallback[num].dataOffset);
|
||
// Prepare data buffer
|
||
CopyRegistersToBuffer(PhysPt(data.GetBase()+dpmi.rmCallback[num].dataOffset));
|
||
DPMI_LOG("DPMI: CB: Stored cs:ip = %04X:%04X",SegValue(cs),reg_ip);
|
||
// setup registers for protected mode func
|
||
CPU_SetSegGeneral(ds,dpmi.realStackSelector[dpmi.protStackCurrent]); // DS:ESI = RM Stack
|
||
reg_esi = reg_esp;
|
||
CPU_SetSegGeneral(es,dataSelector); // ES:EDI = RM Register data
|
||
reg_edi = dpmi.rmCallback[num].dataOffset;
|
||
// SS:ESP = API stack
|
||
CPU_SetSegGeneral(ss,dpmi.protStackSelector[dpmi.protStackCurrent++]);
|
||
reg_esp = DPMI_PROTMODE_STACKSIZE;
|
||
// prepare stack for iret
|
||
if (dpmi.client.bit32) CPU_Push32(flags.word); else CPU_Push16(flags.word);
|
||
// Setup cs:ip to return to DPMI_ReturnFromRealModeCallback
|
||
CPU_SetSegGeneral(cs,GDT_CODE);
|
||
reg_eip = RealOff(CALLBACK_RealPointer(callback.rmCallbackReturn));
|
||
// call protected mode func
|
||
SETFLAGBIT(IF,false);
|
||
SETFLAGBIT(TF,false);
|
||
CPU_Push32(flags.word);
|
||
CPU_CALL(dpmi.client.bit32,dpmi.rmCallback[num].codeSelector,dpmi.rmCallback[num].codeOffset);
|
||
return 0;
|
||
};
|
||
|
||
Bitu DPMI::RealModeCallbackReturn(void)
|
||
{
|
||
// returning from protected mode function, now back to real mode
|
||
Bitu num = PopStack();
|
||
DPMI_LOG("DPMI: Realmode Callback leave %02X",num);
|
||
dpmi.suppressRMCB = false;
|
||
dpmi.rmCallback[num].inCall = false;
|
||
dpmi.rmCallback[num].stop = false;
|
||
dpmi.rmCallback[num].callCount--;
|
||
PhysPt data = PhysPt(SegPhys(es)+reg_edi);
|
||
DPMI_LOG("DPMI: CB: Reading RegData at = %04X:%04X",SegValue(es),reg_edi);
|
||
/* Swtich to real mode */
|
||
CPU_SET_CRX(0,cpu.cr0 & ~CR0_PROTECTION);
|
||
dpmi.protStackCurrent--;
|
||
// Restore Registers
|
||
LoadRegistersFromBuffer(data);
|
||
Bitu newCS = mem_readw(data+0x2C);
|
||
Bitu newIP = mem_readw(data+0x2A);
|
||
UpdateRealModeStack();
|
||
DPMI_LOG("DPMI: CB: Retored cs:ip = %04X:%04X (%d)",newCS,newIP);
|
||
CPU_JMP(false,newCS,newIP);
|
||
return 0;
|
||
};
|
||
|
||
static Bitu count = 0;
|
||
|
||
Bitu DPMI::CallRealIRETFrame(void)
|
||
{
|
||
Bitu calledIP = mem_readd(SegPhys(ss)+reg_esp);
|
||
Bitu calledCS = mem_readd(SegPhys(ss)+reg_esp+4);
|
||
DPMI_LOG("DPMI: ENTER REAL PROC IRETF %04X:%08X",calledCS,calledIP);
|
||
// Save changed registers
|
||
PushStack(SegValue(cs));
|
||
SaveRegister();
|
||
Bitu toCopy = reg_cx;
|
||
// Load Registers
|
||
PhysPt data = SegPhys(es) + reg_edi;
|
||
PhysPt prStack = SegPhys(ss) + reg_esp;
|
||
LoadRegistersFromBuffer(data);
|
||
PushStack(data);
|
||
/* Switch to real mode */
|
||
CPU_SET_CRX(0,cpu.cr0 & ~CR0_PROTECTION);
|
||
// Provide Stack
|
||
ProvideRealModeStack(prStack,toCopy);
|
||
// Push flags
|
||
CPU_Push16(flags.word);
|
||
// Setup IP
|
||
Bitu newCS = mem_readw(data+0x2C);
|
||
Bitu newIP = mem_readw(data+0x2A);
|
||
// Setup cs:ip to return to DPMI_CallRealIRETFrame callback
|
||
SegSet16(cs,RealSeg(CALLBACK_RealPointer(callback.rmIntFrameReturn)));
|
||
reg_ip = RealOff(CALLBACK_RealPointer(callback.rmIntFrameReturn));
|
||
SETFLAGBIT(IF,false);
|
||
SETFLAGBIT(TF,false);
|
||
CPU_CALL(false,newCS,newIP);
|
||
return 0;
|
||
}
|
||
|
||
Bitu DPMI::CallRealIRETFrameReturn(void)
|
||
{
|
||
UpdateRealModeStack();
|
||
// returning from realmode func
|
||
DPMI_LOG("DPMI: LEAVE REAL PROC IRETF %d",count);
|
||
/* Switch to protected mode */
|
||
CPU_SET_CRX(0,cpu.cr0 | CR0_PROTECTION);
|
||
// Save registers into real mode structure
|
||
CopyRegistersToBuffer(PopStack());
|
||
// Restore changed Resgisters
|
||
RestoreRegister();
|
||
Bitu newcs = PopStack();
|
||
|
||
CPU_JMP(dpmi.client.bit32,newcs,reg_eip);
|
||
|
||
DPMI_CALLBACK_SCF(false);
|
||
return 0;
|
||
};
|
||
|
||
Bitu DPMI::SimulateInt(void)
|
||
{
|
||
Bitu num = reg_bl;
|
||
// TEMP
|
||
if (num==0x5C) {
|
||
int brk = 0;
|
||
}
|
||
DPMI_LOG("DPMI: SIM INT %02X %04X called. cs = %04X",num,reg_ax,SegValue(cs));
|
||
// Save changed registers
|
||
PushStack(SegValue(cs));
|
||
SaveRegister();
|
||
Bitu toCopy = reg_cx;
|
||
// Load Registers
|
||
PhysPt data = SegPhys(es) + reg_edi;
|
||
PhysPt prStack = SegPhys(ss) + reg_esp;
|
||
LoadRegistersFromBuffer(data);
|
||
PushStack(data);
|
||
/* Switch to real mode */
|
||
CPU_SET_CRX(0,cpu.cr0 & ~CR0_PROTECTION);
|
||
// Provide Stack
|
||
ProvideRealModeStack(prStack,toCopy);
|
||
// prepare for return
|
||
SegSet16(cs,RealSeg(CALLBACK_RealPointer(callback.simintReturn)));
|
||
reg_ip = RealOff(CALLBACK_RealPointer(callback.simintReturn));
|
||
// Push flags from structure on stack
|
||
DPMI_LOG("DPMI: SimInt1: StackInfo %04X:%04X (%02X %02X)",SegValue(ss),reg_esp,mem_readb(0xD0100+0x01FA),mem_readb(0xD0100+0x01FB));
|
||
flags.word = mem_readw(data+0x20);
|
||
Interrupt(num);
|
||
DPMI_LOG("DPMI: SimInt2: StackInfo %04X:%04X (%02X %02X)",SegValue(ss),reg_esp,mem_readb(0xD0100+0x01FA),mem_readb(0xD0100+0x01FB));
|
||
return 0;
|
||
};
|
||
|
||
Bitu DPMI::SimulateIntReturn(void)
|
||
{
|
||
// returning from realmode func
|
||
DPMI_LOG("DPMI: SIM INT return");
|
||
DPMI_LOG("DPMI: SimIntRet1: StackInfo %04X:%04X (%02X %02X)",SegValue(ss),reg_esp,mem_readb(0xD0100+0x01FA),mem_readb(0xD0100+0x01FB));
|
||
|
||
UpdateRealModeStack();
|
||
/* Switch to protected mode */
|
||
CPU_SET_CRX(0,cpu.cr0 | CR0_PROTECTION);
|
||
// Save registers into real mode structure
|
||
CopyRegistersToBuffer(PopStack());
|
||
// Restore changed Resgisters
|
||
RestoreRegister();
|
||
Bitu newcs = PopStack();
|
||
DPMI_LOG("DPMI: SimIntRet: JUMP to %04X:%08X",newcs,reg_eip);
|
||
CPU_JMP(dpmi.client.bit32,newcs,reg_eip);
|
||
// Free last realmode stack
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: SimIntRet2: StackInfo %04X:%04X (%02X %02X)",SegValue(ss),reg_esp,mem_readb(0xD0100+0x01FA),mem_readb(0xD0100+0x01FB));
|
||
return 0;
|
||
};
|
||
|
||
void DPMI::PrepareReflectToReal(Bitu num)
|
||
{
|
||
// Save segment and stack register
|
||
SaveSegments();
|
||
PushStack(reg_esp);
|
||
PushStack(num);
|
||
PushStack(reg_eip);
|
||
PushStack(SegValue(cs));
|
||
/* Swtich to real mode */
|
||
CPU_SET_CRX(0,cpu.cr0 & ~CR0_PROTECTION);
|
||
// Setup cs:ip to return to intreturn
|
||
Bitu retcs = RealSeg(CALLBACK_RealPointer(callback.ptorintReturn));
|
||
Bitu retip = RealOff(CALLBACK_RealPointer(callback.ptorintReturn));
|
||
|
||
SegSet16(cs,RealSeg(CALLBACK_RealPointer(callback.ptorintReturn)));
|
||
reg_ip = RealOff(CALLBACK_RealPointer(callback.ptorintReturn));
|
||
// setup stack
|
||
SegSet16(ss,rm_ss);
|
||
reg_esp = rm_sp;
|
||
}
|
||
|
||
Bitu DPMI::ptorHandler(void)
|
||
{
|
||
/* Pmode interrupt handler that maps the interrupt to realmode */
|
||
Bitu num = reg_eip >> 3;
|
||
if (!dpmi.vIntFlag) {
|
||
if ((num>=0x08) && (num<=0x0F)) return 0;
|
||
if ((num>=0x70) && (num<=0x77)) return 0;
|
||
};
|
||
PrepareReflectToReal(num);
|
||
// if (num==0x0F)
|
||
DPMI_LOG("DPMI: INT %02X %04X called.",num,reg_ax);
|
||
// Prepare flags for real int
|
||
// CPU_SetFlagsw(flags.word & 0x3ED5); // 0011111011010101b
|
||
Interrupt(num);
|
||
return 0;
|
||
}
|
||
|
||
Bitu DPMI::ptorHandlerReturn(void)
|
||
// Return from reflected real mode int
|
||
{
|
||
UpdateRealModeStack();
|
||
/* Switch to protected mode */
|
||
CPU_SET_CRX(0,cpu.cr0 | CR0_PROTECTION);
|
||
// Restore Registers
|
||
Bitu newcs = PopStack();
|
||
reg_eip = PopStack();
|
||
Bitu num = PopStack();
|
||
reg_esp = PopStack();
|
||
RestoreSegments();
|
||
// if (num==0x0F)
|
||
DPMI_LOG("DPMI: INT %02X RETURN",num);
|
||
// hardware ints exit here
|
||
if (((num>=0x08) && (num<=0x0F)) || ((num>=0x70) && (num<=0x77))) {
|
||
CPU_JMP(dpmi.client.bit32,newcs,reg_eip);
|
||
return 0;
|
||
}
|
||
// Change flags on stack to reflect possible results from ints
|
||
if (dpmi.client.bit32) {
|
||
Bit32u oldFlags = mem_readd(SegPhys(ss)+reg_esp+8) & ~FLAG_MASK;// leave only flags that cannot be changed by int
|
||
Bit32u userFlags = flags.word & FLAG_MASK; // Mask out illegal flags not to change by int (0011111011010101b)
|
||
mem_writed(SegPhys(ss)+reg_esp+8,oldFlags|userFlags);
|
||
} else {
|
||
Bit16u oldFlags = mem_readw(SegPhys(ss)+reg_sp+4) & ~FLAG_MASK; // leave only flags that cannot be changed by int
|
||
Bit16u userFlags = flags.word & FLAG_MASK; // Mask out illegal flags not to change by int (0011111011010101b)
|
||
mem_writew(SegPhys(ss)+reg_sp+4,oldFlags|userFlags);
|
||
};
|
||
CPU_JMP(dpmi.client.bit32,newcs,reg_eip);
|
||
return 0;
|
||
}
|
||
|
||
Bitu DPMI::Int21Handler(void)
|
||
{
|
||
// Check for exit
|
||
if (reg_ah==0x4C) {
|
||
DPMI_LOG("DPMI: INT 21: Terminating.");
|
||
Terminate();
|
||
}
|
||
// Save segment and stack register
|
||
PushStack(SegValue(ss));
|
||
PushStack(reg_esp);
|
||
PushStack(SegValue(ds));
|
||
PushStack(SegValue(es));
|
||
PushStack(SegValue(cs));
|
||
|
||
/* Swtich to real mode */
|
||
CPU_SET_CRX(0,cpu.cr0 & ~CR0_PROTECTION);
|
||
// Setup cs:ip to return to intreturn
|
||
SegSet16(cs,RealSeg(CALLBACK_RealPointer(callback.int21Return)));
|
||
reg_ip = RealOff(CALLBACK_RealPointer(callback.int21Return));
|
||
// setup stack
|
||
SegSet16(ss,rm_ss);
|
||
reg_esp = rm_sp;
|
||
// Call realmode interrupt
|
||
DPMI_LOG("DPMI: INT 21 %04X called.",reg_ax);
|
||
Interrupt(0x21);
|
||
if (reg_ah==0x4C) {
|
||
// Shut doen dpmi and restore previous one
|
||
delete this;
|
||
if (activeDPMI) activeDPMI->Reactivate();
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
Bitu DPMI::Int21HandlerReturn(void)
|
||
{
|
||
UpdateRealModeStack();
|
||
/* Switch to protected mode */
|
||
CPU_SET_CRX(0,cpu.cr0 | CR0_PROTECTION);
|
||
// Restore Registers
|
||
Bitu newcs = PopStack();
|
||
CPU_SetSegGeneral(es,PopStack());
|
||
CPU_SetSegGeneral(ds,PopStack());
|
||
reg_esp = PopStack();
|
||
CPU_SetSegGeneral(ss,PopStack());
|
||
// Set carry flag
|
||
DPMI_CALLBACK_SCF(flags.word & 1);
|
||
DPMI_LOG("DPMI: INT 21 RETURN");
|
||
CPU_JMP(dpmi.client.bit32,newcs,reg_eip);
|
||
return 0;
|
||
}
|
||
|
||
Bitu DPMI::HWIntDefaultHandler()
|
||
// Wir sind hier im Protected mode
|
||
// a) durch einen INTerrupt im protected mode
|
||
// b) durch einen INTerrupt im real mode (durch RMCB)
|
||
{
|
||
Bitu index = mem_readw(PhysPt(SegPhys(cs)+reg_eip-2)) - dpmi.defaultHWIntFromProtMode[0];
|
||
if (index>=DPMI_REALVEC_MAX) E_Exit("DPMI: Illegal realmode interrupt callback: %02X",index);
|
||
Bitu num = rmIndexToInt[index];
|
||
|
||
RealPt vec = RealGetVec(num);
|
||
|
||
if (dpmi.rmCallback[index].callCount==0) {
|
||
// INT PROT (Use Handler is already done).
|
||
// Wenn rmcb noch in Realmode Int table installiert, dann originalMethode aufrufef
|
||
if (vec==dpmi.realModeVec[index]) {
|
||
// originalroutine aufrufen
|
||
dpmi.rmCallback[index].stop = false;
|
||
PrepareReflectToReal(num);
|
||
CPU_Push16(flags.word);
|
||
SETFLAGBIT(IF,false);
|
||
SETFLAGBIT(TF,false);
|
||
CPU_CALL(false,RealSeg(dpmi.oldRealVec[index]),RealOff(dpmi.oldRealVec[index]));
|
||
} else {
|
||
// user real mode handler in real mode int table aktiv.
|
||
// Moeglich, dass dieser den RMCB von Hand noch aufruft
|
||
// dann wird aber callCount>0 sein (da RMCB aktiv) und
|
||
// dann die alte Routine aufgerufen...
|
||
// RMCB sperren, um einen erneuten Aufruf des User Handlers zu vermeiden,..
|
||
|
||
// This is a hack for cybermage wich wont work otherwise. But why ?
|
||
if (num==0x0F) {
|
||
if (dpmi.suppressRMCB) {
|
||
dpmi.suppressRMCB = false;
|
||
return 0;
|
||
} else {
|
||
dpmi.suppressRMCB = true;
|
||
}
|
||
};
|
||
PrepareReflectToReal(num);
|
||
SETFLAGBIT(IF,false);
|
||
SETFLAGBIT(TF,false);
|
||
CPU_Push16(flags.word);
|
||
CPU_CALL(false,RealSeg(vec),RealOff(vec));
|
||
}
|
||
} else {
|
||
// INT REAL (vom RMCB aktiviert)
|
||
// Falls user handler schon aktiv war (int von prot->reflected to real)
|
||
// rufe original routine auf
|
||
if (dpmi.rmCallback[index].stop) {
|
||
dpmi.rmCallback[index].stop = false;
|
||
PrepareReflectToReal(num);
|
||
CPU_Push16(flags.word);
|
||
SETFLAGBIT(IF,false);
|
||
SETFLAGBIT(TF,false);
|
||
CPU_CALL(false,RealSeg(dpmi.oldRealVec[index]),RealOff(dpmi.oldRealVec[index]));
|
||
} else {
|
||
// User routine wurde noch nicht aktiviert, callback aber ausgef<65>hrt
|
||
// falls spezieller protected mode handler aktiviert wurde,
|
||
// wird dieser jetzt aufgerufen (user routine im protected mode)
|
||
Descriptor gate;
|
||
gate.Load(dpmi.idt.base+num*8);
|
||
if ((gate.GetSelector()!=GDT_CODE) || (gate.GetOffset()!=RealOff(dpmi.defaultHWIntFromProtMode[index]))) {
|
||
dpmi.rmCallback[index].stop = true; // vermeide rekursion
|
||
CPU_JMP(dpmi.client.bit32,gate.GetSelector(),gate.GetOffset());
|
||
} else {
|
||
// kein spezieller Protmode handler - Rufe originalroutine auf
|
||
PrepareReflectToReal(num);
|
||
CPU_Push16(flags.word);
|
||
SETFLAGBIT(IF,false);
|
||
SETFLAGBIT(TF,false);
|
||
CPU_CALL(false,RealSeg(dpmi.oldRealVec[index]),RealOff(dpmi.oldRealVec[index]));
|
||
};
|
||
};
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
void DPMI::SaveRegisterState(Bitu num)
|
||
// Copy Current Registers to structure
|
||
{
|
||
save_cs[num] = SegValue(cs);
|
||
save_ds[num] = SegValue(ds);
|
||
save_es[num] = SegValue(es);
|
||
save_fs[num] = SegValue(fs);
|
||
save_gs[num] = SegValue(gs);
|
||
save_ss[num] = SegValue(ss);
|
||
save_eip[num] = reg_eip;
|
||
save_eax[num] = reg_eax;
|
||
save_ebx[num] = reg_ebx;
|
||
save_ecx[num] = reg_ecx;
|
||
save_edx[num] = reg_edx;
|
||
save_esi[num] = reg_esi;
|
||
save_edi[num] = reg_edi;
|
||
save_ebp[num] = reg_ebp;
|
||
save_esp[num] = reg_esp;
|
||
save_fl [num] = flags.word;
|
||
};
|
||
|
||
void DPMI::LoadRegisterState(Bitu num)
|
||
// Copy Current Registers to structure
|
||
{
|
||
CPU_SetSegGeneral(fs,save_fs[num]);
|
||
CPU_SetSegGeneral(gs,save_gs[num]);
|
||
reg_eax = save_eax[num];
|
||
reg_ebx = save_ebx[num];
|
||
reg_ecx = save_ecx[num];
|
||
reg_edx = save_edx[num];
|
||
reg_esi = save_esi[num];
|
||
reg_edi = save_edi[num];
|
||
flags.word = save_fl [num];
|
||
};
|
||
|
||
Bitu DPMI::EnterProtMode(void) {
|
||
|
||
/* Save real mode register state */
|
||
SaveRegisterState(0);
|
||
|
||
/* Switch to protected mode */
|
||
CPU_SET_CRX(0,cpu.cr0 | CR0_PROTECTION);
|
||
|
||
CPU_SetSegGeneral(ds,reg_ax);
|
||
CPU_SetSegGeneral(es,reg_cx);
|
||
CPU_SetSegGeneral(ss,reg_dx);
|
||
CPU_SetSegGeneral(ds,reg_ax);
|
||
|
||
if (dpmi.client.bit32) {
|
||
reg_esp = reg_ebx;
|
||
CPU_JMP(true,reg_si,reg_edi);
|
||
} else {
|
||
reg_sp = reg_bx;
|
||
CPU_JMP(false,reg_si,reg_di);
|
||
};
|
||
|
||
/* Load prot mode register state (all other unchanged registers */
|
||
LoadRegisterState(1);
|
||
|
||
DPMI_LOG("DPMI: Switch to protected mode.");
|
||
return 0;
|
||
}
|
||
|
||
Bitu DPMI::EnterRealMode(void) {
|
||
|
||
/* Save Prot Mode Registers */
|
||
SaveRegisterState(1);
|
||
|
||
/* Swtich to real mode */
|
||
CPU_SET_CRX(0,cpu.cr0 & ~CR0_PROTECTION);
|
||
// (E)BP will be preserved across the mode switch call so it can be used as a pointer.
|
||
// TODO: If interrupts are disabled when the mode switch procedure is invoked,
|
||
// they will not be re-enabled by the DPMI host (even temporarily).
|
||
SegSet16(ds,reg_ax);
|
||
SegSet16(es,reg_cx);
|
||
SegSet16(ss,reg_dx);
|
||
SegSet16(fs,0);
|
||
SegSet16(gs,0);
|
||
if (dpmi.client.bit32) {
|
||
reg_esp = reg_ebx;
|
||
CPU_JMP(true,reg_si,reg_edi);
|
||
} else {
|
||
reg_sp = reg_bx;
|
||
CPU_JMP(false,reg_si,reg_di);
|
||
};
|
||
|
||
/* Load real mode register state (all other unchanged registers) */
|
||
LoadRegisterState(0);
|
||
DPMI_LOG("DPMI: Switch to real mode.");
|
||
return CBRET_NONE;
|
||
};
|
||
|
||
Bitu DPMI::RealSaveState(void)
|
||
{
|
||
return CBRET_NONE;
|
||
/* Save Protected mode state */
|
||
if (reg_al==0) {
|
||
PhysPt data = SegPhys(es) + reg_edi;
|
||
mem_writew(data+ 0,save_cs[1]);
|
||
mem_writew(data+ 2,save_ds[1]);
|
||
mem_writew(data+ 4,save_es[1]);
|
||
mem_writew(data+ 6,save_fs[1]);
|
||
mem_writew(data+ 8,save_gs[1]);
|
||
mem_writew(data+10,save_ss[1]);
|
||
mem_writed(data+12,save_eax[1]);
|
||
mem_writed(data+16,save_ebx[1]);
|
||
mem_writed(data+20,save_ecx[1]);
|
||
mem_writed(data+24,save_edx[1]);
|
||
mem_writed(data+28,save_esi[1]);
|
||
mem_writed(data+32,save_edi[1]);
|
||
mem_writed(data+36,save_ebp[1]);
|
||
mem_writed(data+40,save_esp[1]);
|
||
mem_writed(data+44,save_fl [1]);
|
||
DPMI_LOG("DPMI: Prot Save State.");
|
||
} else if (reg_al==1) {
|
||
/* restore state of prot mode registers */
|
||
PhysPt data = SegPhys(es) + reg_edi;
|
||
save_cs [1] = mem_readw(data+ 0);
|
||
save_ds [1] = mem_readw(data+ 2);
|
||
save_es [1] = mem_readw(data+ 4);
|
||
save_fs [1] = mem_readw(data+ 6);
|
||
save_gs [1] = mem_readw(data+ 8);
|
||
save_ss [1] = mem_readw(data+10);
|
||
save_eax[1] = mem_readd(data+12);
|
||
save_ebx[1] = mem_readd(data+16);
|
||
save_ecx[1] = mem_readd(data+20);
|
||
save_edx[1] = mem_readd(data+24);
|
||
save_edi[1] = mem_readd(data+28);
|
||
save_esi[1] = mem_readd(data+32);
|
||
save_ebp[1] = mem_readd(data+36);
|
||
save_esp[1] = mem_readd(data+40);
|
||
// save_eip[1] = mem_readd(data+44);
|
||
save_fl [1] = mem_readd(data+44);
|
||
DPMI_LOG("DPMI: Prot Restore State.");
|
||
};
|
||
return CBRET_NONE;
|
||
};
|
||
|
||
Bitu DPMI::ProtSaveState(void)
|
||
{
|
||
return CBRET_NONE;
|
||
if (reg_al==0) {
|
||
/* Save State of real mode registers */
|
||
PhysPt data = SegPhys(es) + reg_edi;
|
||
mem_writew(data+ 0,save_cs[0]);
|
||
mem_writew(data+ 2,save_ds[0]);
|
||
mem_writew(data+ 4,save_es[0]);
|
||
mem_writew(data+ 6,save_fs[0]);
|
||
mem_writew(data+ 8,save_gs[0]);
|
||
mem_writew(data+10,save_ss[0]);
|
||
mem_writed(data+12,save_eax[0]);
|
||
mem_writed(data+16,save_ebx[0]);
|
||
mem_writed(data+20,save_ecx[0]);
|
||
mem_writed(data+24,save_edx[0]);
|
||
mem_writed(data+28,save_esi[0]);
|
||
mem_writed(data+32,save_edi[0]);
|
||
mem_writed(data+36,save_ebp[0]);
|
||
mem_writed(data+40,save_esp[0]);
|
||
mem_writed(data+44,save_eip[0]);
|
||
mem_writed(data+48,save_fl [0]);
|
||
DPMI_LOG("DPMI: Real Save State.");
|
||
} else if (reg_al==1) {
|
||
/* restore state of real mode registers */
|
||
PhysPt data = SegPhys(es) + reg_edi;
|
||
save_cs [0] = mem_readw(data+ 0);
|
||
save_ds [0] = mem_readw(data+ 2);
|
||
save_es [0] = mem_readw(data+ 4);
|
||
save_fs [0] = mem_readw(data+ 6);
|
||
save_gs [0] = mem_readw(data+ 8);
|
||
save_ss [0] = mem_readw(data+10);
|
||
save_eax[0] = mem_readd(data+12);
|
||
save_ebx[0] = mem_readd(data+16);
|
||
save_ecx[0] = mem_readd(data+20);
|
||
save_edx[0] = mem_readd(data+24);
|
||
save_edi[0] = mem_readd(data+28);
|
||
save_esi[0] = mem_readd(data+32);
|
||
save_ebp[0] = mem_readd(data+36);
|
||
save_esp[0] = mem_readd(data+40);
|
||
save_eip[0] = mem_readd(data+44);
|
||
save_fl [0] = mem_readd(data+48);
|
||
DPMI_LOG("DPMI: Real Restore State.");
|
||
};
|
||
return CBRET_NONE;
|
||
};
|
||
|
||
bool DPMI::GetVirtualIntFlag(void)
|
||
// only to call from int 31 cos it uses the pushed flags on int stack
|
||
{
|
||
if (dpmi.client.bit32) return (mem_readd(SegPhys(ss)+reg_esp+8) & FLAG_IF)>0;
|
||
else return (mem_readd(SegPhys(ss)+reg_sp+4) & FLAG_IF)>0;
|
||
};
|
||
|
||
void DPMI::SetVirtualIntFlag(bool on)
|
||
{
|
||
dpmi.vIntFlag = on;
|
||
};
|
||
|
||
bool DPMI::AllocateMem(Bitu size, Bitu& outHandle, Bitu& linear)
|
||
{
|
||
Bitu pages = (size/DPMI_PAGE_SIZE) + ((size%DPMI_PAGE_SIZE)>0); // Convert to 4KB pages
|
||
outHandle = MEM_AllocatePages(pages,true);
|
||
linear = outHandle*DPMI_PAGE_SIZE;
|
||
if (outHandle!=0) SetXMSHandle(outHandle);
|
||
return (outHandle!=0);
|
||
};
|
||
|
||
bool DPMI::SetAccessRights(Bitu selector, SetDescriptor& desc, Bitu rights)
|
||
{
|
||
// must equal caller DPL
|
||
if (((rights & 0x60)>>5)!=DPMI_DPL) {
|
||
DPMI_LOG("DPMI: Set Rights %04X : %04X failure (dpl=%02X)",selector,rights,(rights & 0x60)>>5);
|
||
return false;
|
||
}
|
||
// must be 1
|
||
if ((rights & 0x10)==0) {
|
||
DPMI_LOG_ERROR("DPMI: Set Rights %04X : %04X failure (must be 1)",selector,rights);
|
||
return false;
|
||
};
|
||
// must be 0
|
||
if (dpmi.client.bit32 && desc.saved.seg.p && (rights & 0x2000)) {
|
||
DPMI_LOG_ERROR("DPMI: Set Rights %04X : %04X failure (must be 0)",selector,rights);
|
||
return false;
|
||
};
|
||
// all tests passed, set rights for 16 + 32 Bit
|
||
desc.SetType (rights&0x1F);
|
||
desc.saved.seg.dpl = (rights&0x60)>>5;
|
||
// desc.saved.seg.dpl = DPMI_DPL;
|
||
desc.saved.seg.p = (rights&0x80)>0;
|
||
// extended rights for 32 Bit apps
|
||
if (dpmi.client.bit32) {
|
||
desc.saved.seg.avl = (rights&0x1000)>0;
|
||
desc.saved.seg.r = (rights&0x2000)>0;
|
||
desc.saved.seg.big = (rights&0x4000)>0;
|
||
desc.saved.seg.g = (rights&0x8000)>0;
|
||
};
|
||
return true;
|
||
};
|
||
|
||
Bitu DPMI::Int31Handler(void)
|
||
{
|
||
switch (reg_ax) {
|
||
|
||
case 0x0000:{// Allocate LDT Descriptors
|
||
Bitu base;
|
||
Descriptor desc;
|
||
if (AllocateLDTDescriptor(reg_cx,base)) {
|
||
reg_ax = base;
|
||
DPMI_LOG("DPMI: 0000: Allocate %d descriptors: %04X",reg_cx,base);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0000: Allocate %d descriptors failure",reg_cx);
|
||
reg_ax = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x0001:{// Free Descriptor
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
desc.saved.seg.p = 0;
|
||
desc.Save (dpmi.ldt.base+(reg_bx & ~7));
|
||
DPMI_LOG("DPMI: 0001: Free Descriptor: %04X",reg_bx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0001: Free Descriptor failure : %04X",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_SELECTOR;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x0002:{// Segment to Descriptor
|
||
SetDescriptor desc; Bitu base;
|
||
if (AllocateLDTDescriptor(1,base)) {
|
||
desc.Load (dpmi.ldt.base+(base & ~7));
|
||
desc.SetLimit(0xFFFF);
|
||
desc.SetBase (reg_bx<<4);
|
||
desc.saved.seg.dpl=3;
|
||
desc.Save (dpmi.ldt.base+(base & ~7));
|
||
reg_ax = base;
|
||
DPMI_LOG("DPMI: 0000: Seg %04X to Desc: %04X",reg_bx,base);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
// No more Descriptors available
|
||
DPMI_LOG_ERROR("DPMI: 0002: No more Descriptors available.");
|
||
reg_ax = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x0003:// Get Next Selector Increment Value
|
||
reg_ax = 8;
|
||
DPMI_LOG("DPMI: 0003: Get Selector Inc Value: %04X",reg_ax);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0004:// undocumented (reserved) lock selector
|
||
case 0x0005:// undocumented (reserved) unlock selector
|
||
DPMI_LOG("DPMI: 0004: Undoc: (un)lock selector",reg_ax);
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
case 0x0006:{ // Get Segment Base Address
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
DPMI_LOG("DPMI: 0006: Get Base %04X : B:%08X",reg_bx,desc.GetBase());
|
||
reg_cx = desc.GetBase()>>16;
|
||
reg_dx = desc.GetBase()&0xFFFF;
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0006: Invalid Selector: %04X",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_SELECTOR;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x0007:{// Set Segment base address
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
Bitu base;
|
||
if (!dpmi.client.bit32) base = (reg_cl<<16)+reg_dx;
|
||
else base = (reg_cx<<16)+reg_dx;
|
||
desc.SetBase(base);
|
||
desc.Save (dpmi.ldt.base+(reg_bx & ~7));
|
||
ReloadSegments(reg_bx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 0007: Set Base %04X : B:%08X",reg_bx,base);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0007: Invalid Selector: %04X",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_SELECTOR;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x0008:{// Set Segment limit
|
||
SetDescriptor desc;
|
||
if ((!dpmi.client.bit32) && (reg_cx!=0)) {
|
||
// 16-bit DPMI implementations can not set segment limits greater
|
||
// than 0FFFFh (64K) so CX must be zero when calling
|
||
DPMI_LOG_ERROR("DPMI: 0008: Set Segment Limit invalid: %04X ",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_VALUE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
} else if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
desc.SetLimit((reg_cx<<16)+reg_dx);
|
||
desc.Save (dpmi.ldt.base+(reg_bx & ~7));
|
||
ReloadSegments(reg_bx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 0008: Set Limit %08X",(reg_cx<<16)+reg_dx);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0008: Invalid Selector: %04X",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_SELECTOR;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x0009:{// Set Descriptor Access Rights
|
||
SetDescriptor desc;
|
||
Bit8u rcl = reg_cl;
|
||
Bit8u rch = reg_ch;
|
||
if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
if (!SetAccessRights(reg_bx,desc,reg_cx)) {
|
||
DPMI_LOG_ERROR("DPMI: 0009: Set Rights %04X : failure",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_VALUE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
};
|
||
desc.Save(dpmi.ldt.base+(reg_bx & ~7));
|
||
ReloadSegments(reg_bx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 0009: Set Rights %04X : %04X",reg_bx,reg_cx);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0009: Set Rights %04X : invalid selector",reg_bx);
|
||
reg_ax = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x000A:{// Create Alias Descriptor
|
||
Descriptor desc;
|
||
if (CreateAlias(reg_bx, reg_ax)) {
|
||
DPMI_LOG("DPMI: 000A: Create Alias : %04X - %04X",reg_bx,reg_ax);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_CALLBACK_SCF(true);
|
||
DPMI_LOG_ERROR("DPMI: 000A: Invalid Selector: %04X",reg_bx);
|
||
}; }; break;
|
||
case 0x000B:{//Get Descriptor
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
desc.Save(SegPhys(es)+reg_edi);
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 000B: Get Descriptor %04X : B:%08X L:%08X",reg_bx,desc.GetBase(),desc.GetLimit());
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 000B: Get Descriptor %04X : failure",reg_bx);
|
||
reg_ax = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x000C:{//Set Descriptor
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
desc.Load (SegPhys(es)+reg_edi);
|
||
Bitu rights = (mem_readb(SegPhys(es)+reg_edi+6)<<8) + mem_readb(SegPhys(es)+reg_edi+5);
|
||
if (!SetAccessRights(reg_bx,desc,rights)) {
|
||
DPMI_LOG_ERROR("DPMI: 000C: Set Rights %04X : failure",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_VALUE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
};
|
||
desc.Save(dpmi.ldt.base+(reg_bx & ~7));
|
||
ReloadSegments(reg_bx);
|
||
DPMI_LOG("DPMI: 000B: Set Descriptor %04X : B:%08X L:%08X : P %01X",reg_bx,desc.GetBase(),desc.GetLimit(),desc.saved.seg.p);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 000C: Set Descriptor %04X failed",reg_bx);
|
||
reg_ax = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x000D:{ // Allocate specific LDT Descriptor : TODO: Support it
|
||
DPMI_LOG("DPMI: 000D: Alloc Specific LDT Selector: %04X",reg_bx);
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(reg_bx,desc)) {
|
||
if (!desc.saved.seg.p) {
|
||
desc.saved.seg.p = 1;
|
||
desc.SetLimit(0);
|
||
desc.SetBase (0);
|
||
desc.Save (dpmi.ldt.base+(reg_bx & ~7));
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 000D: Invalid Selector: %04X",reg_bx);
|
||
reg_ax = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE;
|
||
};
|
||
} else reg_ax = DPMI_ERROR_INVALID_SELECTOR;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}; break;
|
||
case 0x0100:{// Allocate DOS Memory Block
|
||
Bit16u blocks = reg_bx;
|
||
DPMI_LOG("DPMI: 0100: Allocate DOS Mem: (%04X Blocks)",blocks);
|
||
if (DOS_AllocateMemory(®_ax,&blocks)) {
|
||
// Allocate Selector for block
|
||
SetDescriptor desc; Bitu base; Bitu numDesc;
|
||
numDesc = reg_bx/0x1000 + ((reg_bx%0x1000)>0);
|
||
if (AllocateLDTDescriptor(numDesc,base)) {
|
||
reg_dx = base;
|
||
// First selector
|
||
if (numDesc>1) {
|
||
Bitu descBase = reg_ax*16;
|
||
Bitu length = reg_bx*16;
|
||
desc.Load (dpmi.ldt.base+(base & ~7));
|
||
desc.SetBase (descBase);
|
||
desc.SetLimit(dpmi.client.bit32?length:0xFFFF);
|
||
desc.Save (dpmi.ldt.base+(base & ~7));
|
||
for (Bitu i=1; i<numDesc; i++) {
|
||
base += 8;
|
||
descBase += 0x10000;
|
||
length -= 0x10000;
|
||
desc.Load (dpmi.ldt.base+(base & ~7));
|
||
desc.SetBase (descBase);
|
||
desc.SetLimit((length<=0x10000)?length-1:0xFFFF);
|
||
desc.Save (dpmi.ldt.base+(base & ~7));
|
||
}
|
||
} else {
|
||
// one descriptor
|
||
desc.Load (dpmi.ldt.base+(base & ~7));
|
||
desc.SetBase (reg_ax*16);
|
||
desc.SetLimit(reg_bx*16);
|
||
desc.Save (dpmi.ldt.base+(base & ~7));
|
||
};
|
||
DPMI_LOG("DPMI: 0100: Allocation success: (%04X)",blocks);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
// No more Descriptors available
|
||
DPMI_LOG_ERROR("DPMI: 0100: Allocation failure: %04X (No Descriptor)",blocks);
|
||
reg_ax = DPMI_ERROR_DESCRIPTOR_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
} else {
|
||
DPMI_LOG("DPMI: 0100: Allocation failure : %04X (R:%04X)",reg_bx,blocks);
|
||
reg_bx = blocks;
|
||
reg_ax = 0x008; // Insufficient memory
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
};break;
|
||
case 0x0101:{// Free DOS Memory Block
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(reg_dx,desc)) {
|
||
Bitu sel = reg_dx;
|
||
Bitu seg = desc.GetBase()>>4;
|
||
DOS_MCB mcb(seg-1);
|
||
Bitu size = mcb.GetSize()*16;
|
||
if (DOS_FreeMemory(seg)) {
|
||
while (size>0) {
|
||
desc.Load(dpmi.ldt.base+(sel & ~7));
|
||
desc.saved.seg.p = 0;
|
||
desc.Save(dpmi.ldt.base+(sel & ~7));
|
||
size -= (size>=0x10000)?0x10000:size;
|
||
sel+=8;
|
||
};
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 0101: Free Dos Mem: %04X",reg_dx);
|
||
break;
|
||
}
|
||
}
|
||
DPMI_LOG_ERROR("DPMI: 0101: Invalid Selector: %04X",reg_bx);
|
||
reg_ax = DPMI_ERROR_INVALID_SELECTOR;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};break;
|
||
case 0x0200:{// Get Real Mode Interrupt Vector
|
||
RealPt vec = RealGetVec(reg_bl);
|
||
reg_cx = RealSeg(vec);
|
||
reg_dx = RealOff(vec);
|
||
DPMI_LOG("DPMI: 0200: Get Real Int Vector %02X (%04X:%04X)",reg_bl,reg_cx,reg_dx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0201:{// Set Real Mode Interrupt Vector
|
||
DPMI_LOG("DPMI: 0201: Set Real Int Vector %02X (%04X:%04X)",reg_bl,reg_cx,reg_dx);
|
||
RealSetVec(reg_bl,RealMake(reg_cx,reg_dx));
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0202:// Get Processor Exception Handler Vector
|
||
if (reg_bl<DPMI_EXCEPTION_MAX) {
|
||
reg_cx = dpmi.exceptionSelector[reg_bl];
|
||
reg_edx = dpmi.exceptionOffset[reg_bl];
|
||
DPMI_LOG("DPMI: 0202: Get Exception Vector %02X (%04X:%08X)",reg_bl,reg_cx,reg_edx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: Get Exception Vector failed : %02X",reg_bl);
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
break;
|
||
case 0x0203:// Set Processor Exception Handler Vector
|
||
if (reg_bl<DPMI_EXCEPTION_MAX) {
|
||
dpmi.exceptionSelector[reg_bl] = reg_cx;
|
||
dpmi.exceptionOffset[reg_bl] = reg_edx;
|
||
DPMI_LOG("DPMI: 0203: Set Exception Vector %02X (%04X:%08X)",reg_bl,reg_cx,reg_edx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: Set Exception Vector failed : %02X",reg_bl);
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
break;
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0204:{// Get Protected Mode Interrupt Vector
|
||
SetDescriptor gate;
|
||
gate.Load(dpmi.idt.base+reg_bl*8);
|
||
reg_cx = gate.GetSelector();
|
||
reg_edx = gate.GetOffset();
|
||
DPMI_LOG("DPMI: 0204: Get Prot Int Vector %02X (%04X:%08X)",reg_bl,reg_cx,reg_edx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0205:{// Set Protected Mode Interrupt Vector
|
||
SetDescriptor gate;
|
||
gate.Clear();
|
||
gate.saved.seg.p=1;
|
||
gate.SetSelector(reg_cx);
|
||
gate.SetOffset(reg_edx);
|
||
gate.SetType(dpmi.client.bit32?DESC_386_INT_GATE:DESC_286_INT_GATE);
|
||
gate.saved.seg.dpl = DPMI_DPL;
|
||
gate.Save(dpmi.idt.base+reg_bl*8);
|
||
DPMI_LOG("DPMI: 0205: Set Prot Int Vector %02X (%04X:%08X)",reg_bl,reg_cx,reg_edx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
Bitu num = reg_bl;
|
||
};break;
|
||
case 0x0300:// Simulate Real Mode Interrupt
|
||
SimulateInt();
|
||
break;
|
||
case 0x0302:// Call Real Mode Procedure With IRET Frame
|
||
CallRealIRETFrame();
|
||
break;
|
||
case 0x0303:{//Allocate Real Mode Callback Address
|
||
Bitu num = 0;
|
||
for (Bitu i=0; i<DPMI_REALMODE_CALLBACK_MAX; i++) if (!dpmi.rmCallback[i].inUse) { num = i; break; };
|
||
if (num<DPMI_REALMODE_CALLBACK_MAX) {
|
||
Bitu segment, offset;
|
||
if (AllocateRealModeCallback(SegValue(ds),reg_esi,SegValue(es),reg_edi,segment,offset)) {
|
||
reg_cx = segment; reg_dx = offset;
|
||
DPMI_LOG("DPMI: 0303: Allocate Callback (%04X:%04X)",reg_cx,reg_dx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
}
|
||
}
|
||
DPMI_LOG_ERROR("DPMI: 0303: Callback unavailable.");
|
||
reg_ax = DPMI_ERROR_CALLBACK_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}; break;
|
||
case 0x0304:{//Free Real Mode Call-Back Address
|
||
Bitu num = DPMI_REALMODE_CALLBACK_MAX;
|
||
for (Bitu i=0; i<DPMI_REALMODE_CALLBACK_MAX; i++) {
|
||
if ((dpmi.rmCallback[i].realSegment==reg_cx) && (dpmi.rmCallback[i].realOffset==reg_dx)) {
|
||
num = i; break;
|
||
}
|
||
}
|
||
if (num<DPMI_REALMODE_CALLBACK_MAX) {
|
||
DPMI_LOG("DPMI: 0304: Free Callback (%04X:%04X)",reg_cx,reg_dx);
|
||
dpmi.rmCallback[num].inUse = false;
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0304: Invalid Callback");
|
||
reg_ax = DPMI_ERROR_INVALID_CALLBACK;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
};break;
|
||
case 0x0305:{// Get State Save/Restore Addresses
|
||
RealPt entry = CALLBACK_RealPointer(callback.realsavestate);
|
||
reg_bx = RealSeg(entry);
|
||
reg_cx = RealOff(entry);
|
||
reg_si = GDT_PROTCODE;
|
||
reg_edi= DPMI_CB_SAVESTATE_OFFSET;
|
||
reg_ax = 0; // 20 bytes buffer needed
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 0305: Get State Save/Rest : R:%04X:%04X P:%04X:%08X",reg_bx,reg_cx,reg_si,reg_edi);
|
||
}; break;
|
||
case 0x0306:{// Get raw mode switch address
|
||
RealPt entry=CALLBACK_RealPointer(callback.enterpmode);
|
||
reg_bx = RealSeg(entry);
|
||
reg_cx = RealOff(entry);
|
||
reg_si = GDT_PROTCODE;
|
||
reg_edi= DPMI_CB_ENTERREALMODE_OFFSET;
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 0306: Get Raw Switch : R:%04X:%04X P:%04X:%08X",reg_bx,reg_cx,reg_si,reg_edi);
|
||
}; break;
|
||
case 0x0400:// Get Version
|
||
DPMI_LOG("DPMI: 0400: Get Version");
|
||
reg_ax = 90; // 0.9
|
||
reg_bx = 0x0003; // 32 Bit DPMI
|
||
reg_cl = 0x04; // 486
|
||
reg_dx = 0x0870; // FIXME: Read this from ports
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0401: // Get DPMI Capabilities - always fails in 0.9
|
||
DPMI_LOG("DPMI: 0401: Get Capabilities");
|
||
reg_ax = 0x08; // CONVENTIONAL MEMORY MAPPING capability supported
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0500:{// Get Free Memory Information
|
||
PhysPt data = SegPhys(es) + (dpmi.client.bit32 ? reg_edi:reg_di);
|
||
Bitu large = MEM_FreeLargest();
|
||
Bitu total = MEM_FreeTotal();
|
||
Bitu size = large;
|
||
mem_writed(data+0x00,large*DPMI_PAGE_SIZE); // Size in bytes
|
||
mem_writed(data+0x04,large); // total number of pages
|
||
mem_writed(data+0x08,large); // largest block in pages
|
||
mem_writed(data+0x0C,size); // total linear address space in pages
|
||
mem_writed(data+0x10,total); // num of unlocked pages - no info
|
||
mem_writed(data+0x14,total); // num of physical pages not in use
|
||
mem_writed(data+0x18,size); // total num of physical pages
|
||
mem_writed(data+0x1C,total); // free linear address space in pages
|
||
mem_writed(data+0x20,0xFFFFFFFF); // size of paging file in pages
|
||
mem_writed(data+0x24,0xFFFFFFFF); // reserved
|
||
mem_writed(data+0x28,0xFFFFFFFF); // reserved
|
||
mem_writed(data+0x2C,0xFFFFFFFF); // reserved
|
||
DPMI_CALLBACK_SCF(false);
|
||
DPMI_LOG("DPMI: 0500: Get Mem Info (%d KB total)",total*4);
|
||
}; break;
|
||
case 0x0501:{// Allocate Memory
|
||
Bitu handle,linear;
|
||
Bitu length = (reg_bx<<16)+reg_cx;
|
||
//DPMI_LOG("DPMI: 0501: Allocate memory (%d KB)",length/1024);
|
||
if (AllocateMem(length,handle,linear)) {
|
||
reg_si = handle>>16;
|
||
reg_di = handle&0xFFFF;
|
||
reg_bx = linear>>16;
|
||
reg_cx = linear&0xFFFF;
|
||
DPMI_CALLBACK_SCF(false);
|
||
// TEMP
|
||
Bitu total = MEM_FreeLargest(); // in KB
|
||
DPMI_LOG("DPMI: 0501: Allocation success: H:%04X%04X (%d KB) (R:%d KB)",reg_si,reg_di,length/1024 + ((length%1024)>0),total*4);
|
||
} else {
|
||
reg_ax = DPMI_ERROR_PHYSICAL_MEMORY_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
// TEMP
|
||
Bitu total = MEM_FreeLargest(); // in KB
|
||
DPMI_LOG_ERROR("DPMI: 0501: Allocation failure (%d KB) (R:%d KB)",length/1024 + ((length%1024)>0),total*4);
|
||
};
|
||
}; break;
|
||
case 0x0502://Free Memory Block
|
||
DPMI_LOG("DPMI: 0502: Free Mem: H:%04X%04X",reg_si,reg_di);
|
||
MEM_ReleasePages((reg_si<<16)+reg_di);
|
||
FreeXMSHandle((reg_si<<16)+reg_di);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0503:{//Resize Memory Block
|
||
Bitu linear,newHandle;
|
||
Bitu newByte = (reg_bx<<16)+reg_cx;
|
||
Bitu newSize = (newByte/DPMI_PAGE_SIZE)+((newByte & (DPMI_PAGE_SIZE-1))>0);
|
||
MemHandle handle = (reg_si<<16)+reg_di;
|
||
DPMI_LOG_ERROR("DPMI: 0503: Resize Memory: H:%08X (%d KB)",handle,newSize*4);
|
||
if (MEM_ReAllocatePages(handle,newSize,true)) {
|
||
linear = handle * DPMI_PAGE_SIZE;
|
||
reg_si = handle>>16;
|
||
reg_di = handle&0xFFFF;
|
||
reg_bx = linear>>16;
|
||
reg_cx = linear&0xFFFF;
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else if (AllocateMem(newByte,newHandle,linear)) {
|
||
// Not possible, try to allocate
|
||
DPMI_LOG_ERROR("DPMI: 0503: Reallocated Memory: %d KB",newSize*4);
|
||
reg_si = newHandle>>16;
|
||
reg_di = newHandle&0xFFFF;
|
||
reg_bx = linear>>16;
|
||
reg_cx = linear&0xFFFF;
|
||
// copy contents
|
||
Bitu size = MEM_AllocatedPages(handle);
|
||
if (newSize<size) size = newSize;
|
||
MEM_BlockCopy(linear,handle*DPMI_PAGE_SIZE,size*DPMI_PAGE_SIZE);
|
||
// Release old handle
|
||
MEM_ReleasePages(handle);
|
||
FreeXMSHandle(handle);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI: 0503: Memory unavailable . %08X",newSize);
|
||
reg_ax = DPMI_ERROR_PHYSICAL_MEMORY_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x0506:// Get Page Attributes
|
||
DPMI_LOG("DPMI: 0506: Get Page Attributes");
|
||
reg_ax = DPMI_ERROR_UNSUPPORTED;
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
case 0x0507:// Set Page Attributes
|
||
DPMI_LOG("DPMI: 0507: Set Page Attributes");
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0509:{//Map Conventional Memory in Memory Block
|
||
Bitu xmsAddress = reg_esi*DPMI_PAGE_SIZE;
|
||
Bitu handle = reg_esi;
|
||
Bitu offset = reg_ebx;
|
||
Bitu numPages = reg_ecx;
|
||
Bitu linearAdr = reg_edx;
|
||
if ((linearAdr & 3) || ((xmsAddress+offset) & 3)) {
|
||
// Not page aligned
|
||
DPMI_LOG_ERROR("DPMI: Cannot map conventional memory (address not page aligned).");
|
||
reg_ax = DPMI_ERROR_INVALID_LINEAR_ADDRESS;
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
}
|
||
MEM_MapPagesDirect(linearAdr/DPMI_PAGE_SIZE,(xmsAddress+offset)/DPMI_PAGE_SIZE,numPages);
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0600:{//Lock Linear Region
|
||
DPMI_LOG("DPMI: 0600: Lock Linear Region");
|
||
Bitu address = (reg_bx<<16)+reg_cx;
|
||
Bitu size = (reg_si<<16)+reg_di;
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0601://unlock Linear Region
|
||
DPMI_LOG("DPMI: 0601: Unlock Linear Region");
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0602:// Mark Real Mode Region as Pageable
|
||
DPMI_LOG("DPMI: 0602: Mark Realmode Region pageable");
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0603:// Relock Real Mode Region
|
||
DPMI_LOG("DPMI: 0603: Relock Realmode Region");
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0604:// Get page size
|
||
reg_bx=0; reg_cx=DPMI_PAGE_SIZE;
|
||
DPMI_LOG("DPMI: 0604: Get Page Size: %04X",reg_cx);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0701:// Undocumented discard page contents
|
||
DPMI_LOG("DPMI: 0701: Discard Page contents");
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
case 0x0702://Mark Page as Demand Paging Candidate
|
||
DPMI_LOG("DPMI: 0702: Mark page as demand paging candidate");
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0703://Discard Page contents
|
||
DPMI_LOG("DPMI: 0703: Discard Page contents");
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0800:{//Physical Address Mapping
|
||
// bx and cx remain the same linear address = physical address
|
||
Bitu phys = (reg_bx<<16) + reg_cx;
|
||
Bitu size = (reg_si<<16) + reg_di;
|
||
MEM_MapPagesDirect(phys/DPMI_PAGE_SIZE,phys/DPMI_PAGE_SIZE,size/DPMI_PAGE_SIZE);
|
||
Bitu linear = phys;
|
||
reg_bx = linear>>16;
|
||
reg_cx = linear & 0xFFFF;
|
||
DPMI_LOG_ERROR("DPMI: 0800: Phys-adr-map not supported : %08X (%08X) - %08X.",phys,size,linear);
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0801:// Free physical address mapping
|
||
DPMI_LOG("DPMI: 0801: Free physical address mapping");
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0900://Get and Disable Virtual Interrupt State
|
||
reg_al = dpmi.vIntFlag;
|
||
dpmi.vIntFlag = 0;
|
||
DPMI_LOG("DPMI: 0900: Get and disbale vi : %01X",reg_al);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0901://Get and Enable Virtual Interrupt State
|
||
reg_al = dpmi.vIntFlag;
|
||
dpmi.vIntFlag = 1;
|
||
DPMI_LOG("DPMI: 0901: Get and enable vi : %01X",reg_al);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0902:{//Get Virtual Interrupt State
|
||
reg_al = dpmi.vIntFlag;
|
||
reg_al = 0; // TEMP
|
||
DPMI_LOG("DPMI: 0900: Get vi : %01X",reg_al);
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0A00:{//Get Vendor Specific API Entry Point
|
||
char name[256];
|
||
MEM_StrCopy(SegPhys(ds)+reg_esi,name,255);
|
||
LOG(LOG_MISC,LOG_WARN)("DPMI: Get API: %s",name);
|
||
if (strcmp(name,"MS-DOS")==0) {
|
||
CPU_SetSegGeneral(es,GDT_PROTCODE);
|
||
reg_edi = DPMI_CB_APIMSDOSENTRY_OFFSET;
|
||
API_Init_MSDOS();
|
||
DPMI_CALLBACK_SCF(false);
|
||
// } else if (strstr(name,"HWINT")!=0) {
|
||
// reg_ax = DPMI_ERROR_UNSUPPORTED;
|
||
// DPMI_CALLBACK_SCF(true);
|
||
} else if (strstr(name,"PHARLAP")!=0) {
|
||
CPU_SetSegGeneral(es,GDT_PROTCODE);
|
||
reg_edi = DPMI_CB_APIMSDOSENTRY_OFFSET;
|
||
API_Init_MSDOS();
|
||
DPMI_CALLBACK_SCF(false);
|
||
dpmi.pharlap = true;
|
||
} else {
|
||
reg_ax = DPMI_ERROR_UNSUPPORTED;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
}; break;
|
||
case 0x0D00:{//Allocate Shared Memory
|
||
char name[256];
|
||
PhysPt data = SegPhys(es)+reg_edi;
|
||
Bitu length = mem_readd(data);
|
||
Bitu pages = (length/DPMI_PAGE_SIZE)+((length%DPMI_PAGE_SIZE)>0);
|
||
Bitu handle = mem_readd(data+0x08);
|
||
Bitu linear = mem_readd(data+0x0C);
|
||
Bitu strOffset = mem_readd(data+0x10);
|
||
Bitu strSelect = mem_readw(data+0x14);
|
||
|
||
Descriptor desc;
|
||
if (!cpu.gdt.GetDescriptor(strSelect,desc)) {
|
||
DPMI_LOG_ERROR("DPMI: 0D00: shared memory: invalid name selector");
|
||
reg_ax = DPMI_ERROR_INVALID_VALUE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
return false;
|
||
};
|
||
MEM_StrCopy(desc.GetBase()+strOffset,name,256);
|
||
|
||
// Already allocated ?
|
||
if (!GetSharedMem(name,handle,pages)) {
|
||
if (!AllocateMem(length,handle,linear)) {
|
||
DPMI_LOG_ERROR("DPMI: 0D00: Allocation shared failure %s (%d KB)",name,pages*4);
|
||
reg_ax = DPMI_ERROR_PHYSICAL_MEMORY_UNAVAILABLE;
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
};
|
||
// Init first paragraph with zeros
|
||
for (Bitu i=0; i<16; i++) mem_writeb(linear+i,0);
|
||
SetSharedMem(name,handle,pages);
|
||
DPMI_LOG("DPMI: 0D00: Allocate shared memory %s (%d KB) ",name,pages*4);
|
||
} else {
|
||
linear = handle*DPMI_PAGE_SIZE;
|
||
DPMI_LOG("DPMI: 0D00: Reuse shared memory %s (%d KB) ",name,pages*4);
|
||
};
|
||
|
||
mem_writed(data+0x04,pages*DPMI_PAGE_SIZE);
|
||
mem_writed(data+0x08,handle);
|
||
mem_writed(data+0x0C,linear);
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
case 0x0B00:// Set debug watchpoint
|
||
case 0x0B01:// Clear debug watchpoint
|
||
DPMI_CALLBACK_SCF(true);
|
||
break;
|
||
case 0x0E00:// Get Coprocessor Status
|
||
DPMI_LOG("DPMI: 0E00: Get Coprocessor status");
|
||
reg_ax = 0x45; // nope, no coprocessor
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
case 0x0E01:// Set Coprocessor Emulation
|
||
DPMI_LOG("DPMI: 0E01: Set Coprocessor emulation");
|
||
DPMI_CALLBACK_SCF(true); // failure
|
||
break;
|
||
default :LOG(LOG_MISC,LOG_ERROR)("DPMI: Unsupported func %04X",reg_ax);
|
||
reg_ax = DPMI_ERROR_UNSUPPORTED;
|
||
DPMI_CALLBACK_SCF(true); // failure
|
||
break;
|
||
};
|
||
return 0;
|
||
}
|
||
|
||
Bitu DPMI::Int2fHandler(void)
|
||
{
|
||
// Only available in ProtectedMode
|
||
// LOG(LOG_MISC,LOG_WARN)("DPMI: 0x2F %04x",reg_ax);
|
||
switch (reg_ax) {
|
||
case 0x1686: /* Get CPU Mode */
|
||
reg_ax = 0;
|
||
break;
|
||
case 0x168A: // Only available in protected mode
|
||
// Get Vendor-Specific API Entry Point
|
||
char name[256];
|
||
MEM_StrCopy(SegPhys(ds)+reg_esi,name,255);
|
||
LOG(LOG_MISC,LOG_WARN)("DPMI: 0x2F 0x168A: Get Specific API :%s",name);
|
||
if (strcmp(name,"MS-DOS")==0) {
|
||
CPU_SetSegGeneral(es,GDT_PROTCODE);
|
||
reg_edi = DPMI_CB_APIMSDOSENTRY_OFFSET;
|
||
reg_al = 0x00; // Success, whatever they want...
|
||
API_Init_MSDOS();
|
||
};
|
||
break;
|
||
default : // reflect to real
|
||
ptorHandler();
|
||
break;
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
// *********************************************************************
|
||
// Callbacks and Callback-Returns
|
||
// *********************************************************************
|
||
|
||
static Bitu DPMI_ExceptionReturn(void) { if (activeDPMI) return activeDPMI->ExceptionReturn(); return 0;};
|
||
static Bitu DPMI_RealModeCallback(void) { if (activeDPMI) return activeDPMI->RealModeCallback(); return 0;};
|
||
static Bitu DPMI_RealModeCallbackReturn(void) { if (activeDPMI) return activeDPMI->RealModeCallbackReturn(); return 0;};
|
||
static Bitu DPMI_CallRealIRETFrame(void) { if (activeDPMI) return activeDPMI->CallRealIRETFrame(); return 0;};
|
||
static Bitu DPMI_CallRealIRETFrameReturn(void) { if (activeDPMI) return activeDPMI->CallRealIRETFrameReturn(); return 0;};
|
||
static Bitu DPMI_SimulateInt(void) { if (activeDPMI) return activeDPMI->SimulateInt(); return 0;};
|
||
static Bitu DPMI_SimulateIntReturn(void) { if (activeDPMI) return activeDPMI->SimulateIntReturn(); return 0;};
|
||
static Bitu DPMI_ptorHandler(void) { if (activeDPMI) return activeDPMI->ptorHandler(); return 0;};
|
||
static Bitu DPMI_ptorHandlerReturn(void) { if (activeDPMI) return activeDPMI->ptorHandlerReturn(); return 0;};
|
||
static Bitu DPMI_Int21Handler(void) { if (activeDPMI) return activeDPMI->Int21Handler(); return 0;};
|
||
static Bitu DPMI_Int21HandlerReturn(void) { if (activeDPMI) return activeDPMI->Int21HandlerReturn(); return 0;};
|
||
static Bitu DPMI_HWIntDefaultHandler(void) { if (activeDPMI) return activeDPMI->HWIntDefaultHandler(); return 0;};
|
||
static Bitu DPMI_EnterProtMode(void) { if (activeDPMI) return activeDPMI->EnterProtMode(); return 0;};
|
||
static Bitu DPMI_EnterRealMode(void) { if (activeDPMI) return activeDPMI->EnterRealMode(); return 0;};
|
||
static Bitu DPMI_RealSaveState(void) { if (activeDPMI) return activeDPMI->RealSaveState(); return 0;};
|
||
static Bitu DPMI_ProtSaveState(void) { if (activeDPMI) return activeDPMI->ProtSaveState(); return 0;};
|
||
static Bitu DPMI_Int2fHandler(void) { if (activeDPMI) return activeDPMI->Int2fHandler(); return 0;};
|
||
static Bitu DPMI_Int31Handler(void) { if (activeDPMI) return activeDPMI->Int31Handler(); return 0;};
|
||
static Bitu DPMI_API_Int21_MSDOS(void) { if (activeDPMI) return activeDPMI->API_Int21_MSDOS(); return 0;};
|
||
static Bitu DPMI_API_Entry_MSDOS(void) { if (activeDPMI) return activeDPMI->API_Entry_MSDOS(); return 0;};
|
||
|
||
|
||
// ****************************************************************
|
||
// Setup stuff
|
||
// ****************************************************************
|
||
|
||
RealPt DPMI::HookInterrupt(Bitu num, Bitu intHandler)
|
||
{
|
||
// Setup realmode hook
|
||
RealPt oldVec;
|
||
Bitu segment, offset;
|
||
// Allocate Realmode callback
|
||
RealPt func = CALLBACK_RealPointer(intHandler);
|
||
if (AllocateRealModeCallback(GDT_CODE,RealOff(func),0x0000,0x0000,segment,offset)) {
|
||
oldVec = RealGetVec(num);
|
||
RealSetVec(num,RealMake(segment,offset));
|
||
} else E_Exit("DPMI: Couldnt allocate Realmode-Callback for INT %04X",num);
|
||
// Setup protmode hook
|
||
func = CALLBACK_RealPointer(intHandler);
|
||
SetDescriptor gate;
|
||
gate.Load (dpmi.idt.base+num*8);
|
||
gate.SetSelector(GDT_CODE);
|
||
gate.SetOffset (RealOff(func));
|
||
gate.Save (dpmi.idt.base+num*8);
|
||
return oldVec;
|
||
}
|
||
|
||
void DPMI::RestoreHookedInterrupt(Bitu num, RealPt oldVec)
|
||
{
|
||
//.Restore hooked int
|
||
RealSetVec(num,oldVec);
|
||
RealPt func = CALLBACK_RealPointer(callback.ptorint);
|
||
SetDescriptor gate;
|
||
gate.Load (dpmi.idt.base+num*8);
|
||
gate.SetSelector(GDT_CODE);
|
||
gate.SetOffset (RealOff(func));
|
||
gate.Save (dpmi.idt.base+num*8);
|
||
}
|
||
|
||
void DPMI::Terminate(void)
|
||
{
|
||
Bitu i;
|
||
cpu.cpl = 0;
|
||
dpmi.client.have = false;
|
||
// 1. Clear the LDT
|
||
for (i=0; i<LDT_SIZE*8; i++) mem_writeb(dpmi.ldt.base+i,0);
|
||
// 2.Deallocate Callbacks
|
||
for (i=0; i<DPMI_REALMODE_CALLBACK_MAX; i++) dpmi.rmCallback[i].inUse = false;
|
||
|
||
// 3.Deallocate XMS Memory
|
||
for (i=0; i<DPMI_XMSHANDLES_MAX; i++) {
|
||
if ((dpmi.xmsHandles[i]!=0xFFFF) && !IsSharedMem(dpmi.xmsHandles[i]))
|
||
MEM_ReleasePages(dpmi.xmsHandles[i]);
|
||
}
|
||
|
||
#if DPMI_HOOK_HARDWARE_INTS
|
||
// 4.Restore hooked ints
|
||
for (i=0; i<DPMI_REALVEC_MAX; i++) {
|
||
if (RealGetVec(rmIndexToInt[i])!=0)
|
||
RestoreHookedInterrupt(rmIndexToInt[i],dpmi.oldRealVec[i]);
|
||
}
|
||
#endif
|
||
};
|
||
|
||
void DPMI::CreateStackSpace(void)
|
||
{
|
||
// Alloocate protected mode stack
|
||
Bitu i,base;
|
||
SetDescriptor desc;
|
||
if (!AllocateLDTDescriptor(DPMI_PROTMODE_STACK_MAX,base)) E_Exit("DPMI: Couldnt allocate protected mode stack for callbacks");
|
||
for (i=0; i<DPMI_PROTMODE_STACK_MAX; i++) {
|
||
dpmi.protStackSelector[i] = base;
|
||
desc.Load (dpmi.ldt.base+(base & ~7));
|
||
desc.SetLimit(DPMI_PROTMODE_STACKSIZE-1);
|
||
desc.SetBase (dpmi.protStack + i*DPMI_PROTMODE_STACKSIZE);
|
||
desc.Save (dpmi.ldt.base+(base & ~7));
|
||
base += 8;
|
||
};
|
||
// Allocate Descriptors for real mode stack in realmode callback func
|
||
if (!AllocateLDTDescriptor(DPMI_PROTMODE_STACK_MAX,base)) E_Exit("DPMI: Couldnt allocate real mode stack for callbacks");
|
||
for (i=0; i<DPMI_PROTMODE_STACK_MAX; i++) {
|
||
dpmi.realStackSelector[i] = base;
|
||
base += 8;
|
||
};
|
||
// Allocate Descriptors for real mode datasegment in realmode callback func
|
||
if (!AllocateLDTDescriptor(DPMI_PROTMODE_STACK_MAX,base)) E_Exit("DPMI: Couldnt allocate data area for callbacks");
|
||
for (i=0; i<DPMI_PROTMODE_STACK_MAX; i++) {
|
||
// We need mem & descriptor for register data area
|
||
dpmi.dataSelector[i] = base;
|
||
desc.Load (dpmi.ldt.base+(base & ~7));
|
||
desc.SetLimit(63);
|
||
desc.SetBase (DOS_GetMemory(64/16)<<4);
|
||
desc.Save (dpmi.ldt.base+(base & ~7));
|
||
base += 8;
|
||
};
|
||
|
||
dpmi.protStackCurrent = 0;
|
||
};
|
||
|
||
static Bitu DPMI_EntryPoint(void)
|
||
{
|
||
if (!activeDPMI) {
|
||
// First client - read int table
|
||
for (Bitu i=0; i<256; i++) originalIntTable[i] = mem_readd(i*4);
|
||
} else {
|
||
// Another client already running, remove active callbacks from int table
|
||
activeDPMI->RemoveIntCallbacks();
|
||
}
|
||
activeDPMI = new DPMI();
|
||
return activeDPMI->Entrypoint();
|
||
}
|
||
|
||
Bitu DPMI::Entrypoint(void)
|
||
{
|
||
/* This should switch to pmode */
|
||
if (dpmi.client.have) E_Exit("DPMI:Already have a client");
|
||
|
||
LOG(LOG_MISC,LOG_ERROR)("DPMI: Entrypoint (%d Bit)",(reg_ax & 1) ? 32:16);
|
||
|
||
MEM_A20_Enable(true);
|
||
// Create gdt, ldt, idt and other stuff
|
||
Setup();
|
||
|
||
// Save Realmode Registers
|
||
SaveRegisterState(0);
|
||
|
||
dpmi.client.have = true;
|
||
dpmi.client.bit32 = reg_ax & 1;
|
||
|
||
// Clear XMS Handles
|
||
ClearXMSHandles();
|
||
/* Clear the LDT */
|
||
Bitu i;
|
||
for (i=0;i<LDT_SIZE*8;i++) mem_writeb(dpmi.ldt.base+i,0);
|
||
/* Setup IDT */
|
||
SetDescriptor gate;
|
||
Bitu selIntType = dpmi.client.bit32 ? DESC_386_INT_GATE:DESC_286_INT_GATE;
|
||
for (i=0;i<256;i++) {
|
||
gate.Clear();
|
||
gate.SetSelector(GDT_PROTCODE);
|
||
gate.SetOffset (i*8);
|
||
gate.SetType (selIntType);
|
||
gate.saved.seg.p = 1;
|
||
gate.saved.seg.dpl = DPMI_DPL;
|
||
gate.Save(dpmi.idt.base+i*8);
|
||
}
|
||
|
||
/* Load GDT and IDT */
|
||
CPU_LIDT(dpmi.idt.limit,dpmi.idt.base);
|
||
CPU_LGDT(dpmi.gdt.limit,dpmi.gdt.base);
|
||
/* Switch to pmode */
|
||
Bitu old_cr0=CPU_GET_CRX(0);
|
||
CPU_SET_CRX(0,old_cr0 | 1);
|
||
/* Setup LDT and rest of descriptors for client startup */
|
||
SetDescriptor desc;
|
||
Bitu first;
|
||
AllocateLDTDescriptor(7,first);
|
||
CPU_LLDT(GDT_LDT);
|
||
// Set code segments according to dpmi client
|
||
Descriptor code;
|
||
if (cpu.gdt.GetDescriptor(GDT_CODE,code)) {
|
||
// DMPI callback code (0xC800)
|
||
code.saved.seg.big = dpmi.client.bit32;
|
||
code.Save(dpmi.gdt.base+(GDT_CODE & ~7));
|
||
} else E_Exit("DPMI: cannot initialize code selector 1.");
|
||
if (cpu.gdt.GetDescriptor(GDT_PROTCODE|DPMI_DPL,code)) {
|
||
// DMPI callback code (XMS)
|
||
code.saved.seg.big = dpmi.client.bit32;
|
||
code.Save(dpmi.gdt.base+(GDT_PROTCODE & ~7));
|
||
} else E_Exit("DPMI: cannot initialize code selector 2.");
|
||
|
||
/* Setup Selector for PSP, which will be ES */
|
||
DOS_PSP psp(dos.psp);
|
||
dpmi.client.psp=psp.GetSegment();
|
||
desc.Clear();
|
||
desc.SetLimit(0xff);
|
||
desc.SetBase (dpmi.client.psp << 4);
|
||
desc.SetType (DESC_DATA_ED_RW_A);
|
||
desc.saved.seg.p = 1;
|
||
desc.saved.seg.dpl = DPMI_DPL;
|
||
desc.Save(dpmi.ldt.base+(first & ~7));
|
||
CPU_SetSegGeneral(es,first);
|
||
first+=8;
|
||
/* Setup Selector for environment */
|
||
Bitu adr = psp.GetEnvironment()<<4;
|
||
if ((!adr) && psp.GetParent()) {
|
||
DOS_PSP parent = DOS_PSP(psp.GetParent());
|
||
adr = parent.GetEnvironment()<<4;
|
||
}
|
||
if (!adr) E_Exit("DPMI: Couldnt get environment.");
|
||
|
||
desc.Clear();
|
||
desc.SetBase (adr);
|
||
desc.SetLimit(0xFF);
|
||
desc.SetType (DESC_DATA_ED_RW_A);
|
||
desc.saved.seg.p = 1;
|
||
desc.saved.seg.big = 1;
|
||
desc.saved.seg.dpl = DPMI_DPL;
|
||
desc.Save (dpmi.ldt.base+(first & ~7));
|
||
psp.SetEnvironment(first);
|
||
first+=8;
|
||
/* Setup Selector for DS */
|
||
desc.Clear();
|
||
desc.SetLimit(0xffff);
|
||
desc.SetBase (SegValue(ds) << 4);
|
||
desc.SetType (DESC_DATA_ED_RW_A);
|
||
desc.saved.seg.p = 1;
|
||
desc.saved.seg.dpl = DPMI_DPL;
|
||
desc.Save(dpmi.ldt.base+(first & ~7));
|
||
CPU_SetSegGeneral(ds,first);
|
||
first+=8;
|
||
/* Get the CS;IP of the stack before changing it */
|
||
Bitu old_cs,old_eip;
|
||
old_eip=mem_readw(SegPhys(ss)+reg_sp);
|
||
old_cs=mem_readw(SegPhys(ss)+reg_sp+2);
|
||
reg_esp+=4;
|
||
/* Setup Selector for SS and clear high word of ESP */
|
||
desc.Clear();
|
||
desc.SetLimit(0xffff);
|
||
desc.SetBase(SegValue(ss) << 4);
|
||
desc.SetType(DESC_DATA_ED_RW_A);
|
||
desc.saved.seg.p = 1;
|
||
desc.saved.seg.big = dpmi.client.bit32;
|
||
desc.saved.seg.dpl = DPMI_DPL;
|
||
desc.Save(dpmi.ldt.base+(first & ~7));
|
||
CPU_SetSegGeneral(ss,first);
|
||
reg_esp=reg_sp;
|
||
first+=8;
|
||
/* Setup CS:IP and jmp there */
|
||
desc.Clear();
|
||
desc.SetLimit(0xffff);
|
||
desc.SetBase(old_cs << 4);
|
||
desc.SetType(DESC_CODE_R_NC_A);
|
||
desc.saved.seg.p = 1;
|
||
desc.saved.seg.big = 0; //Start up in 16-bit segment
|
||
desc.saved.seg.dpl = DPMI_DPL;
|
||
desc.Save(dpmi.ldt.base+(first & ~7));
|
||
// Init exception handlers
|
||
for (i=0; i<DPMI_EXCEPTION_MAX; i++) {
|
||
dpmi.exceptionSelector[i] = GDT_PROTCODE;
|
||
dpmi.exceptionOffset[i] = DPMI_CB_EXCEPTION_OFFSET;
|
||
};
|
||
|
||
// Create Real and ProtMode Stacks
|
||
CreateStackSpace();
|
||
|
||
#if DPMI_HOOK_HARDWARE_INTS
|
||
// Hook Interrupts in real mode to reflect them to protected mode
|
||
Bitu num;
|
||
for (i=0; i<DPMI_REALVEC_MAX; i++) {
|
||
num = rmIndexToInt[i];
|
||
dpmi.oldRealVec[i] = HookInterrupt(num, dpmi.defaultHWIntFromProtMode[i]);
|
||
dpmi.realModeVec[i] = RealGetVec(num);
|
||
};
|
||
#endif
|
||
|
||
dpmi.vIntFlag = 1;
|
||
cpu.cpl = DPMI_DPL;
|
||
/* The final jump to start up the code */
|
||
CPU_JMP(false,first,old_eip);
|
||
return 0;
|
||
}
|
||
|
||
static bool DPMI_Multiplex(void) {
|
||
switch (reg_ax) {
|
||
case 0x1600: // Windows check
|
||
reg_al = 0x00; // No windows
|
||
return true;
|
||
case 0x1686: /* Get CPU Mode */
|
||
reg_ax = 1;
|
||
return true;
|
||
case 0x1687:{ /* Get Mode switch entry point */
|
||
DPMI_LOG("DPMI: 0x2F 0x1687: Get DPMI entry point.");
|
||
reg_ax=0; /* supported */
|
||
reg_bx=1; /* Support 32-bit */
|
||
reg_cl=4; /* 486 */
|
||
reg_dh=00; /* dpmi 0.90 */
|
||
reg_dl=90;
|
||
reg_si=0; /* No need for private data */
|
||
RealPt entry=CALLBACK_RealPointer(callback.entry);
|
||
SegSet16(es,RealSeg(entry));
|
||
reg_di=RealOff(entry);
|
||
return true; };
|
||
|
||
case 0xED00:/* TNT DOS Extender Detection */
|
||
/* DPMI_LOG("DPMI:INT 2F:TNT Extender detection");
|
||
reg_ax = 0xEDFF; // Installed
|
||
reg_si = 0x5048; // "PH"
|
||
reg_di = 0x4152; // "AR"
|
||
reg_cx = 0x0400; // Majr/Minor Version
|
||
reg_dx = 0x0001; // DPMI
|
||
reg_bx = 0x0100; // DPMI Version
|
||
return true;*/
|
||
case 0xED03:
|
||
case 0xF100: DPMI_LOG("DPMI:INT 2F: Pharlap Detection : %04X.",reg_ax);
|
||
};
|
||
return false;
|
||
}
|
||
|
||
void DPMI_ShutDown(Section* sec)
|
||
{
|
||
// Delete global shared mem list
|
||
std::list<TSharedMem*>::iterator i;
|
||
for(i=g_sharedMemList.begin(); i != g_sharedMemList.end(); i++)
|
||
delete static_cast<TSharedMem*>(*i);
|
||
(g_sharedMemList.clear)();
|
||
};
|
||
|
||
void DPMI_Init(Section* sec)
|
||
{
|
||
Section_prop * section=static_cast<Section_prop *>(sec);
|
||
if (!section->Get_bool("dpmi")) return;
|
||
|
||
memset(&callback,0,sizeof(callback));
|
||
|
||
/* setup Real mode Callbacks */
|
||
callback.entry=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.entry,DPMI_EntryPoint,CB_RETF);
|
||
callback.enterpmode=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.enterpmode,DPMI_EnterProtMode,CB_RETF);
|
||
callback.realsavestate=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.realsavestate,DPMI_RealSaveState,CB_RETF);
|
||
callback.simint=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.simint,DPMI_SimulateInt,CB_IRET);
|
||
callback.simintReturn=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.simintReturn,DPMI_SimulateIntReturn,CB_IRET);
|
||
callback.rmIntFrame=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.rmIntFrame,DPMI_CallRealIRETFrame,CB_IRET);
|
||
callback.rmIntFrameReturn=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.rmIntFrameReturn,DPMI_CallRealIRETFrameReturn,CB_IRET);
|
||
callback.ptorint=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.ptorint,DPMI_ptorHandler,CB_IRET);
|
||
callback.ptorintReturn=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.ptorintReturn,DPMI_ptorHandlerReturn,CB_IRET);
|
||
callback.int21Return=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.int21Return,DPMI_Int21HandlerReturn,CB_IRET);
|
||
callback.rmCallbackReturn=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.rmCallbackReturn,DPMI_RealModeCallbackReturn,CB_IRET);
|
||
callback.int21msdos=CALLBACK_Allocate();
|
||
CALLBACK_Setup(callback.int21msdos,DPMI_API_Int21_MSDOS,CB_IRET);
|
||
|
||
/* Setup multiplex */
|
||
DOS_AddMultiplexHandler(DPMI_Multiplex);
|
||
|
||
/* shutdown function */
|
||
sec->AddDestroyFunction(&DPMI_ShutDown);
|
||
}
|
||
|
||
void DPMI::Reactivate()
|
||
{
|
||
/* Load GDT and IDT */
|
||
CPU_LIDT(dpmi.idt.limit,dpmi.idt.base);
|
||
CPU_LGDT(dpmi.gdt.limit,dpmi.gdt.base);
|
||
CPU_LLDT(GDT_LDT);
|
||
cpu.cpl = DPMI_DPL;
|
||
RestoreIntCallbacks();
|
||
};
|
||
|
||
void DPMI::Setup()
|
||
{
|
||
Bitu i;
|
||
Bitu xmssize = (TOTAL_SIZE|(DPMI_PAGE_SIZE-1))+1;
|
||
Bitu protStackSize = ((DPMI_PROTMODE_STACK_MAX*DPMI_PROTMODE_STACKSIZE)|(DPMI_PAGE_SIZE-1))+1;
|
||
Bitu numPages = ((xmssize+protStackSize) >> 12);
|
||
|
||
#if DPMI_ALLOC_NEEDEDMEM_HIGH
|
||
/* Allocate the GDT,LDT,IDT Stack space (High Mem) */
|
||
dpmi.mem_handle = MEM_AllocatePages(numPages,true);
|
||
if (dpmi.mem_handle==0) {
|
||
LOG_MSG("DPMI:Can't allocate XMS memory, disabling dpmi support.");
|
||
return;
|
||
}
|
||
Bitu address = dpmi.mem_handle*DPMI_PAGE_SIZE;;
|
||
#else
|
||
// load LDT and stuff in low mem (
|
||
Bit16u segment;
|
||
Bit16u blocks = numPages*4096/16;
|
||
if (!DOS_AllocateMemory(&segment,&blocks)) {
|
||
LOG_MSG("DPMI:Can't allocate XMS memory, disabling dpmi support.");
|
||
return;
|
||
};
|
||
Bitu address = segment * 16;
|
||
#endif
|
||
// Allocate real mode stack space
|
||
rm_ss = DOS_GetMemory(DPMI_REALMODE_STACKSIZE/16);
|
||
rm_sp = DPMI_REALMODE_STACKSIZE;
|
||
// Get Begin of protected mode stack
|
||
dpmi.protStack = address + xmssize;
|
||
/* Clear the memory */
|
||
PhysPt w;
|
||
for (w=address;w<xmssize;w++) mem_writeb(w,0);
|
||
dpmi.gdt.base=address;
|
||
dpmi.gdt.limit=(GDT_SIZE*8)-1;
|
||
address+=GDT_SIZE*8;
|
||
dpmi.idt.base=address;
|
||
dpmi.idt.limit=(IDT_SIZE*8)-1;
|
||
address+=IDT_SIZE*8;
|
||
address+=4;
|
||
dpmi.ldt.base=address;
|
||
dpmi.ldt.limit=(LDT_SIZE*8)-1;
|
||
address+=LDT_SIZE*8;
|
||
dpmi.ptorint_base=address;
|
||
address+=INT_SIZE*8;
|
||
/* Setup LDT and CODE descriptors in GDT */
|
||
SetDescriptor ldt;
|
||
ldt.Clear();
|
||
ldt.SetBase (dpmi.ldt.base);
|
||
ldt.SetLimit(dpmi.ldt.limit);
|
||
ldt.SetType (DESC_LDT);
|
||
ldt.saved.seg.p = 1;
|
||
ldt.saved.seg.dpl = DPMI_DPL;
|
||
ldt.Save(dpmi.gdt.base+(GDT_LDT & ~7));
|
||
SetDescriptor code;
|
||
/* Setup Code Descriptor for real mode calls */
|
||
code;
|
||
code.Clear();
|
||
code.SetBase (CB_SEG<<4);
|
||
code.SetLimit(0xFFFF);
|
||
code.SetType (DESC_CODE_R_NC_A);
|
||
code.saved.seg.p = 1;
|
||
code.saved.seg.big = 1;
|
||
code.saved.seg.dpl = DPMI_DPL;
|
||
code.Save (dpmi.gdt.base+(GDT_CODE & ~7));
|
||
/* Setup Code Descriptor for protected mode calls */
|
||
code.Clear();
|
||
code.SetBase (dpmi.ptorint_base);
|
||
code.SetLimit(0xFFFF);
|
||
code.SetType (DESC_CODE_R_NC_A);
|
||
code.saved.seg.p = 1;
|
||
code.saved.seg.big = 1;
|
||
code.saved.seg.dpl = DPMI_DPL;
|
||
code.Save (dpmi.gdt.base+(GDT_PROTCODE & ~7));
|
||
/* Setup data Descriptor to access first megabyte */
|
||
code.Clear();
|
||
code.SetBase (0);
|
||
code.SetLimit(0xFFFFF);
|
||
code.SetType (DESC_DATA_ED_RW_A);
|
||
code.saved.seg.p = 1;
|
||
code.saved.seg.big = 1;
|
||
code.saved.seg.dpl = DPMI_DPL;
|
||
code.Save (dpmi.gdt.base+(GDT_DOSDATA & ~7));
|
||
/* Setup data Descriptor to access Dos Segment 0x40 */
|
||
code.Clear();
|
||
code.SetBase (0x40<<4);
|
||
code.SetLimit(0xFFFF);
|
||
code.SetType (DESC_DATA_ED_RW_A);
|
||
code.saved.seg.p = 1;
|
||
code.saved.seg.big = 0;
|
||
code.saved.seg.dpl = 0;
|
||
code.Save (dpmi.gdt.base+(GDT_DOSSEG40 & ~7));
|
||
|
||
#if DPMI_HOOK_HARDWARE_INTS
|
||
// Setup Hardware Interrupt handler
|
||
for (i=0; i<DPMI_REALVEC_MAX; i++) {
|
||
dpmi.defaultHWIntFromProtMode[i]=CALLBACK_Allocate();
|
||
CALLBACK_Setup(dpmi.defaultHWIntFromProtMode[i],DPMI_HWIntDefaultHandler,CB_IRET);
|
||
};
|
||
#endif
|
||
|
||
// Init Realmode Callbacks
|
||
for (i=0; i<DPMI_REALMODE_CALLBACK_MAX; i++) {
|
||
dpmi.rmCallback[i].id = CALLBACK_Allocate();
|
||
CALLBACK_Setup(dpmi.rmCallback[i].id,DPMI_RealModeCallback,CB_IRET);
|
||
dpmi.rmCallback[i].inUse = false;
|
||
};
|
||
|
||
/* Setup some callbacks used only in pmode */
|
||
callback.apimsdosentry=CALLBACK_Allocate();
|
||
CALLBACK_SetupAt(callback.apimsdosentry,DPMI_API_Entry_MSDOS,CB_RETF,dpmi.ptorint_base+DPMI_CB_APIMSDOSENTRY_OFFSET);
|
||
callback.enterrmode=CALLBACK_Allocate();
|
||
CALLBACK_SetupAt(callback.enterrmode,DPMI_EnterRealMode,CB_RETF,dpmi.ptorint_base+DPMI_CB_ENTERREALMODE_OFFSET);
|
||
callback.protsavestate=CALLBACK_Allocate();
|
||
CALLBACK_SetupAt(callback.protsavestate,DPMI_ProtSaveState,CB_RETF,dpmi.ptorint_base+DPMI_CB_SAVESTATE_OFFSET);
|
||
// callback.exception=CALLBACK_Allocate();
|
||
// CALLBACK_SetupAt(callback.exception,DPMI_Exception,CB_RETF,dpmi.ptorint_base+DPMI_CB_EXCEPTION_OFFSET);
|
||
callback.exceptionret=CALLBACK_Allocate();
|
||
CALLBACK_SetupAt(callback.exceptionret,DPMI_ExceptionReturn,CB_RETF,dpmi.ptorint_base+DPMI_CB_EXCEPTIONRETURN_OFFSET);
|
||
|
||
/* Setup table to reflect pmode ints to realmode */
|
||
w=dpmi.ptorint_base;
|
||
for (i=0;i<256;i++) {
|
||
mem_writeb(w,0xFE); //GRP 4
|
||
mem_writeb(w+1,0x38); //Extra Callback instruction
|
||
mem_writew(w+2,callback.ptorint); //The immediate word
|
||
mem_writeb(w+4,0xcf); //IRET
|
||
w+=8;
|
||
}
|
||
|
||
// Set Special 0x31 and 0x21 Handler
|
||
callback.int31=CALLBACK_Allocate();
|
||
CALLBACK_SetupAt(callback.int31,DPMI_Int31Handler,CB_IRET,dpmi.ptorint_base+0x31*8);
|
||
callback.int21=CALLBACK_Allocate();
|
||
CALLBACK_SetupAt(callback.int21,DPMI_Int21Handler,CB_IRET,dpmi.ptorint_base+0x21*8);
|
||
callback.int2f=CALLBACK_Allocate();
|
||
CALLBACK_SetupAt(callback.int2f,DPMI_Int2fHandler,CB_IRET,dpmi.ptorint_base+0x2f*8);
|
||
}
|
||
|
||
// *********************************************************************
|
||
// Special Extender capabilities : MS-DOS
|
||
// *********************************************************************
|
||
|
||
Bitu DPMI::GetSegmentFromSelector(Bitu selector)
|
||
{
|
||
Bitu base = 0xDEAD;
|
||
SetDescriptor desc;
|
||
if (cpu.gdt.GetDescriptor(selector,desc)) {
|
||
base = desc.GetBase();
|
||
if ((base>0xFFFFF) || (base & 0x0F)) E_Exit("DPMI:MSDOS: Invalid Selector (convert to segment not possible)");
|
||
base >>= 4;
|
||
} else E_Exit("DPMI:MSDOS: Invalid Selector (not found)");
|
||
return base;
|
||
};
|
||
|
||
bool DPMI::GetMsdosSelector(Bitu realseg, Bitu realoff, Bitu &protsel, Bitu &protoff)
|
||
{
|
||
if (AllocateLDTDescriptor(1,protsel)) {
|
||
SetDescriptor desc;
|
||
desc.Load (dpmi.ldt.base+(protsel & ~7));
|
||
desc.SetBase (realseg<<4);
|
||
desc.SetLimit (0xFFFF);
|
||
desc.Save (dpmi.ldt.base+(protsel & ~7));
|
||
} else E_Exit("DPMI:MSDOS: No more selectors.");
|
||
protoff = realoff;
|
||
return true;
|
||
};
|
||
|
||
void DPMI::API_Init_MSDOS(void)
|
||
{
|
||
// Enable special Int 21 Handler....
|
||
RealPt func = CALLBACK_RealPointer(callback.int21msdos);
|
||
SetDescriptor gate;
|
||
gate.Load (dpmi.idt.base+0x21*8);
|
||
gate.SetSelector(GDT_CODE);
|
||
gate.SetOffset (RealOff(func));
|
||
gate.Save (dpmi.idt.base+0x21*8);
|
||
};
|
||
|
||
Bitu DPMI::API_Entry_MSDOS(void)
|
||
{
|
||
LOG(LOG_MISC,LOG_WARN)("DPMI: MSDOS Extension API Entry.");
|
||
switch (reg_ax) {
|
||
case 0x0000:// Get MS-DOS Extension Version
|
||
reg_ax = 0x0000;
|
||
SETFLAGBIT(CF,false);
|
||
break;
|
||
case 0x0100:// Get Selector to Base of LDT
|
||
// Note that the DPMI host has the option of either failing
|
||
// this call, or to return a read-only descriptor (we fail it).
|
||
SETFLAGBIT(CF,true);
|
||
break;
|
||
default: SETFLAGBIT(CF,true);
|
||
LOG(LOG_MISC,LOG_ERROR)("DPMI:MSDOS-API:Unknown ax on entry point %04X.",reg_ax);
|
||
break;
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
Bitu DPMI::Mask(Bitu value)
|
||
{
|
||
if (dpmi.client.bit32) return value;
|
||
else return value & 0xFFFF;
|
||
};
|
||
|
||
Bitu DPMI::API_Int21_MSDOS(void)
|
||
{
|
||
DPMI_LOG("DPMI:MSDOS-API:INT 21 %04X",reg_ax);
|
||
Bitu protsel,protoff,seg,off;
|
||
Bitu sax = reg_ax;
|
||
switch (reg_ah) {
|
||
|
||
case 0x1a: /* Set Disk Transfer Area Address */
|
||
dtaAddress = SegPhys(ds) + Mask(reg_edx);
|
||
break;
|
||
case 0x25: { // Set Protected mode Interrupt Vector
|
||
if (dpmi.pharlap) {
|
||
//LOG(LOG_MISC,LOG_ERROR)
|
||
switch (reg_al) {
|
||
|
||
case 0x05: // Set Real mode Int Vector
|
||
RealSetVec(reg_cl,Mask(reg_ebx));
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
|
||
default : E_Exit("DPMI:PHARLAP:System call %04X",reg_ax);
|
||
};
|
||
|
||
} else {
|
||
// ms dos api
|
||
SetDescriptor gate;
|
||
gate.Clear();
|
||
gate.saved.seg.p=1;
|
||
gate.SetSelector(SegValue(ds));
|
||
gate.SetOffset (Mask(reg_edx));
|
||
gate.SetType (dpmi.client.bit32?DESC_386_INT_GATE:DESC_286_INT_GATE);
|
||
gate.saved.seg.dpl = DPMI_DPL;
|
||
gate.Save(dpmi.idt.base+reg_al*8);
|
||
}
|
||
}; break;
|
||
case 0x35: { // Get Protected Mode Interrupt Vector
|
||
SetDescriptor gate;
|
||
gate.Load(dpmi.idt.base+reg_al*8);
|
||
CPU_SetSegGeneral(es,gate.GetSelector());
|
||
reg_ebx = gate.GetOffset();
|
||
DPMI_CALLBACK_SCF(false);
|
||
}; break;
|
||
|
||
case 0x2f: /* Get Disk Transfer Area */
|
||
seg = RealSeg(dos.dta);
|
||
off = RealOff(dos.dta);
|
||
GetMsdosSelector(seg,off,protsel,protoff);
|
||
CPU_SetSegGeneral(es,protsel);
|
||
reg_ebx = protoff;
|
||
break;
|
||
|
||
case 0x34 : // Get INDOS Flag address
|
||
seg = RealSeg(dos.tables.indosflag);
|
||
off = RealOff(dos.tables.indosflag);
|
||
GetMsdosSelector(seg,off,protsel,protoff);
|
||
CPU_SetSegGeneral(es,protsel);
|
||
reg_bx = protoff;
|
||
break;
|
||
case 0x39:{ // MKDIR Create directory
|
||
char name1[256];
|
||
MEM_StrCopy(SegPhys(ds)+Mask(reg_edx),name1,255);
|
||
if (DOS_MakeDir(name1)) {
|
||
CALLBACK_SCF(false);
|
||
} else {
|
||
reg_ax=dos.errorcode;
|
||
CALLBACK_SCF(true);
|
||
}
|
||
}; break;
|
||
case 0x3c: { /* CREATE Create of truncate file */
|
||
char name1[256];
|
||
MEM_StrCopy(SegPhys(ds)+Mask(reg_edx),name1,255);
|
||
if (DOS_CreateFile(name1,reg_cx,®_ax)) {
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
reg_ax=dos.errorcode;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
}; break;
|
||
case 0x3d: { /* OPEN Open existing file */
|
||
char name1[256];
|
||
MEM_StrCopy(SegPhys(ds)+Mask(reg_edx),name1,255);
|
||
if (DOS_OpenFile(name1,reg_al,®_ax)) {
|
||
DPMI_LOG("DOS: Open success: %s",name1);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DOS_PSP psp(dos.psp);
|
||
psp.SetNumFiles(40);
|
||
if (DOS_OpenFile(name1,reg_al,®_ax)) {
|
||
DPMI_LOG_ERROR("DOS: Open success (Hack): %s",name1);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
};
|
||
reg_ax=dos.errorcode;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
};break;
|
||
case 0x3f: /* READ Read from file or device */
|
||
{
|
||
if (reg_ecx>0xFFFF) {
|
||
E_Exit("DPMI:DOS: Read file size > 0xffff");
|
||
};
|
||
|
||
Bit16u toread = Mask(reg_ecx);
|
||
dos.echo = true;
|
||
if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
|
||
MEM_BlockWrite(SegPhys(ds)+Mask(reg_edx),dos_copybuf,toread);
|
||
reg_eax=toread;
|
||
DPMI_CALLBACK_SCF(false);
|
||
|
||
} else {
|
||
reg_ax=dos.errorcode;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
dos.echo=false;
|
||
break;
|
||
}
|
||
case 0x40: {/* WRITE Write to file or device */
|
||
Bit16u towrite = Mask(reg_ecx);
|
||
MEM_BlockRead(SegPhys(ds)+Mask(reg_edx),dos_copybuf,towrite);
|
||
if (reg_bx>=5) LOG(LOG_MISC,LOG_ERROR)("INT 21 40: %s",dos_copybuf);
|
||
if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) {
|
||
reg_eax=towrite;
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_LOG_ERROR("DPMI:MSDOS:Write file failure.");
|
||
reg_ax=dos.errorcode;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
}; break;
|
||
case 0x41: { /* UNLINK Delete file */
|
||
char name1[256];
|
||
MEM_StrCopy(SegPhys(ds)+Mask(reg_edx),name1,255);
|
||
if (DOS_UnlinkFile(name1)) {
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
reg_ax=dos.errorcode;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
}; break;
|
||
case 0x42: /* LSEEK Set current file position */
|
||
{
|
||
Bit32u pos=(reg_cx<<16) + reg_dx;
|
||
if (DOS_SeekFile(reg_bx,&pos,reg_al)) {
|
||
reg_dx=(Bit16u)(pos >> 16);
|
||
reg_ax=(Bit16u)(pos & 0xFFFF);
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
reg_ax=dos.errorcode;
|
||
DPMI_CALLBACK_SCF(true);
|
||
}
|
||
break;
|
||
}
|
||
case 0x43: { /* Get/Set file attributes */
|
||
char name1[256];
|
||
MEM_StrCopy(SegPhys(ds)+Mask(reg_edx),name1,255);
|
||
switch (reg_al)
|
||
case 0x00: /* Get */
|
||
{
|
||
if (DOS_GetFileAttr(name1,®_cx)) {
|
||
DPMI_CALLBACK_SCF(false);
|
||
} else {
|
||
DPMI_CALLBACK_SCF(true);
|
||
reg_ax=dos.errorcode;
|
||
}
|
||
break;
|
||
case 0x01: /* Set */
|
||
DPMI_LOG_ERROR("DOS:Set File Attributes for %s not supported",name1);
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
default:
|
||
E_Exit("DOS:0x43:Illegal subfunction %2X",reg_al);
|
||
}
|
||
}; break;
|
||
|
||
case 0x4E: {/* Get first dir entry */
|
||
char name1[256];
|
||
MEM_StrCopy(SegPhys(ds)+Mask(reg_edx),name1,255);
|
||
if (DOS_FindFirst(name1,reg_cx)) {
|
||
DPMI_CALLBACK_SCF(false);
|
||
// Copy result to internal dta
|
||
if (dtaAddress) MEM_BlockCopy(dtaAddress,PhysMake(RealSeg(dos.dta),RealOff(dos.dta)),dpmi.pharlap?43:128);
|
||
reg_ax=0; /* Undocumented */
|
||
} else {
|
||
reg_ax=dos.errorcode;
|
||
DPMI_CALLBACK_SCF(true);
|
||
};
|
||
}; break;
|
||
case 0x4f: /* FINDNEXT Find next matching file */
|
||
// Copy data to dos dta
|
||
if (dtaAddress) MEM_BlockCopy(PhysMake(RealSeg(dos.dta),RealOff(dos.dta)),dtaAddress,dpmi.pharlap?43:128);
|
||
if (DOS_FindNext()) {
|
||
CALLBACK_SCF(false);
|
||
// Copy result to internal dta
|
||
if (dtaAddress) MEM_BlockCopy(dtaAddress,PhysMake(RealSeg(dos.dta),RealOff(dos.dta)),dpmi.pharlap?43:128);
|
||
reg_ax=0xffff; /* Undocumented */
|
||
} else {
|
||
reg_ax=dos.errorcode;
|
||
CALLBACK_SCF(true);
|
||
};
|
||
break;
|
||
case 0x50: /* Set current PSP */
|
||
if (dpmi.pharlap) dos.psp = reg_bx; // pharlap uses real mode paragraph address
|
||
else
|
||
dos.psp = GetSegmentFromSelector(reg_bx);
|
||
DPMI_LOG("DPMI:MSDOS:0x50:Set current psp:%04X",reg_bx);
|
||
break;
|
||
case 0x51: /* Get current PSP */
|
||
if (dpmi.pharlap) reg_bx = dos.psp; // pharlap uses real mode paragraph address
|
||
else {
|
||
GetMsdosSelector(dos.psp,0x0000,protsel,protoff);
|
||
reg_bx = protsel;
|
||
};
|
||
DPMI_LOG("DPMI:MSDOS:0x51:Get current psp:%04X",reg_bx);
|
||
break;
|
||
case 0x55 : { // Neuen PSP erstellen
|
||
Bitu segment = GetSegmentFromSelector(reg_dx);
|
||
DOS_ChildPSP(segment,reg_si);
|
||
dos.psp = segment;
|
||
if (dpmi.pharlap) {
|
||
DOS_PSP psp(dos.psp);
|
||
psp.SetNumFiles(40);
|
||
};
|
||
DPMI_LOG("DPMI:MSDOS:0x55:Create new psp:%04X",segment);
|
||
}; break;
|
||
case 0x5D : // Get Address of dos swappable area
|
||
// FIXME: This is totally faked...
|
||
// FIXME: Add size in bytes (at least pharlap)
|
||
// FIXME: Depending on al, two functions (pharlap)
|
||
GetMsdosSelector(0xDEAD,0xDEAD,protsel,protoff);
|
||
CPU_SetSegGeneral(ds,protsel);
|
||
reg_si = protoff;
|
||
DPMI_LOG("DPMI:MSDOS:0x5D:Get Addres of DOS SwapArea:%04X",reg_si);
|
||
break;
|
||
case 0x62 : /* Get Current PSP Address */
|
||
GetMsdosSelector(dos.psp,0x0000,protsel,protoff);
|
||
reg_bx = protsel;
|
||
DPMI_LOG("DPMI:MSDOS:0x62:Get current psp:%04X",reg_bx);
|
||
break;
|
||
case 0x68: // Flush file to disc
|
||
DPMI_CALLBACK_SCF(false);
|
||
break;
|
||
|
||
case 0x09:
|
||
case 0x0A:
|
||
case 0x0C:
|
||
case 0x1B:
|
||
case 0x1C:
|
||
case 0x26: // Pharlap != MS-DOS
|
||
// case 0x30: // Pharlap extended information
|
||
case 0x31:
|
||
case 0x32:
|
||
case 0x38:
|
||
case 0x3A:
|
||
case 0x3B:
|
||
case 0x47:
|
||
case 0x48: // Pharlap = 4KB mem pages
|
||
case 0x49:
|
||
case 0x4A: // Pharlap = 4KB mem pages
|
||
case 0x4B:
|
||
case 0x52:
|
||
case 0x53:
|
||
case 0x56:
|
||
case 0x59:
|
||
case 0x5A:
|
||
case 0x5B:
|
||
case 0x5E:
|
||
case 0x5F:
|
||
case 0x60:
|
||
// case 0x62:
|
||
case 0x65:
|
||
case 0x6C:
|
||
E_Exit("DPMI:MSDOS-API:function %04X not yet supported.",reg_ax);
|
||
break;
|
||
|
||
// *** PASS THROUGH ***
|
||
case 0x44: if ((reg_al==0x02) || (reg_al==0x03) || (reg_al==0x04) || (reg_al==0x05) || (reg_al==0x0C) || (reg_al==0x0D)) {
|
||
E_Exit("DPMI:MSDOS-API:function %04X not yet supported.",reg_ax);
|
||
};
|
||
case 0x0E: case 0x19: case 0x2A: case 0x2C: case 0x2D: case 0x30: case 0x36:
|
||
case 0x3E: case 0x4C: case 0x58: case 0x67:
|
||
{
|
||
// reflect to real mode
|
||
DPMI_Int21Handler();
|
||
};
|
||
break;
|
||
default: E_Exit("DPMI:MSDOS-API:Missing function %04X",reg_ax);
|
||
|
||
};
|
||
return 0;
|
||
};
|
||
|
||
|