/**************************************************************************** * * PM/Lite Library * * Copyright (C) 1996 SciTech Software. * All rights reserved. * * Filename: $Workfile: pmlite.c $ * Version: $Revision: 1.1 $ * * Language: ANSI C * Environment: IBM PC (MSDOS) Real mode and 16/32 bit Protected Mode * * Description: Module implementing DOS extender independant protected * mode programming. This module will need to be included in * all programs that use SciTech Software's products that * are to be compiled in protected mode, and will need to be * compiled with the correct defines for the DOS extender that * you will be using (or with no defines for real mode * emulation of these routines). * * The Lite version of this library is freely redistributable * in source code form. * * $Date: 12 Feb 1996 21:58:56 $ $Author: KendallB $ * ****************************************************************************/ #include #include #include "pmode.h" #pragma pack(1) /*--------------------------- Global variables ----------------------------*/ /* Set the type of target being compiled for so that we can do switching at * runtime as well as compile time. */ #if defined(REALMODE) PRIVATE int _PM_modeType = PM_realMode; #elif defined(PM286) PRIVATE int _PM_modeType = PM_286; #elif defined(PM386) PRIVATE int _PM_modeType = PM_386; #endif /*----------------------------- Implementation ----------------------------*/ /*-------------------------------------------------------------------------*/ /* Generic routines common to all extenders */ /*-------------------------------------------------------------------------*/ int PMAPI PM_getModeType(void) { return _PM_modeType; } uint PMAPI PM_getBIOSSelector(void) { static uint BIOS_sel = 0; if (!BIOS_sel) BIOS_sel = PM_createSelector(0x400,0xFFFF); return BIOS_sel; } uint PMAPI PM_getVGASelector(void) { switch (PM_getByte(PM_getBIOSSelector(),0x49)) { case 0x3: return PM_getVGAColorTextSelector(); case 0x7: return PM_getVGAMonoTextSelector(); default: return PM_getVGAGraphSelector(); } } uint PMAPI PM_getVGAColorTextSelector(void) { static long VGA_sel = 0; if (!VGA_sel) VGA_sel = PM_createSelector(0xB8000L,0xFFFF); return (uint)VGA_sel; } uint PMAPI PM_getVGAMonoTextSelector(void) { static long VGA_sel = 0; if (!VGA_sel) VGA_sel = PM_createSelector(0xB0000L,0xFFFF); return (uint)VGA_sel; } uint PMAPI PM_getVGAGraphSelector(void) { static long VGA_sel = 0; if (!VGA_sel) VGA_sel = PM_createSelector(0xA0000L,0xFFFF); return (uint)VGA_sel; } int PMAPI PM_int386(int intno, PMREGS *in, PMREGS *out) { PMSREGS sregs; PM_segread(&sregs); return PM_int386x(intno,in,out,&sregs); } /* Routines to set and get the real mode interrupt vectors, by making * direct real mode calls to DOS and bypassing the DOS extenders API. * This is the safest way to handle this, as some servers try to be * smart about changing real mode vectors. */ void PMAPI _PM_getRMvect(int intno, long *realisr) { RMREGS regs; RMSREGS sregs; PM_saveDS(); regs.h.ah = 0x35; regs.h.al = intno; PM_int86x(0x21, ®s, ®s, &sregs); *realisr = ((long)sregs.es << 16) | regs.x.bx; } void PMAPI _PM_setRMvect(int intno, long realisr) { RMREGS regs; RMSREGS sregs; PM_saveDS(); regs.h.ah = 0x25; regs.h.al = intno; sregs.ds = (int)(realisr >> 16); regs.x.dx = (int)(realisr & 0xFFFF); PM_int86x(0x21, ®s, ®s, &sregs); } /*-------------------------------------------------------------------------*/ /* Generic DPMI routines common to 16/32 bit code */ /*-------------------------------------------------------------------------*/ #ifndef REALMODE ulong DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit) { PMREGS r; ulong physOfs; /* Round the physical address to a 4Kb boundary and the limit to a * 4Kb-1 boundary before passing the values to DPMI as some extenders * will fail the calls unless this is the case. If we round the * physical address, then we also add an extra offset into the address * that we return. */ physOfs = physAddr & 4095; physAddr = physAddr & ~4095; limit = ((limit+physOfs+1+4095) & ~4095)-1; r.x.ax = 0x800; /* DPMI map physical to linear */ r.x.bx = physAddr >> 16; r.x.cx = physAddr & 0xFFFF; r.x.si = limit >> 16; r.x.di = limit & 0xFFFF; PM_int386(0x31, &r, &r); if (r.x.cflag) return 0; return ((ulong)r.x.bx << 16) + r.x.cx + physOfs; } int DPMI_setSelectorBase(ushort sel,ulong linAddr) { PMREGS r; r.x.ax = 7; /* DPMI set selector base address */ r.x.bx = sel; r.x.cx = linAddr >> 16; r.x.dx = linAddr & 0xFFFF; PM_int386(0x31, &r, &r); if (r.x.cflag) return 0; return 1; } ulong DPMI_getSelectorBase(ushort sel) { PMREGS r; r.x.ax = 6; /* DPMI get selector base address */ r.x.bx = sel; PM_int386(0x31, &r, &r); return ((ulong)r.x.cx << 16) + r.x.dx; } int DPMI_setSelectorLimit(ushort sel,ulong limit) { PMREGS r; r.x.ax = 8; /* DPMI set selector limit */ r.x.bx = sel; r.x.cx = limit >> 16; r.x.dx = limit & 0xFFFF; PM_int386(0x31, &r, &r); if (r.x.cflag) return 0; return 1; } uint DPMI_createSelector(ulong base,ulong limit) { uint sel; PMREGS r; /* Allocate 1 descriptor */ r.x.ax = 0; r.x.cx = 1; PM_int386(0x31, &r, &r); if (r.x.cflag) return 0; sel = r.x.ax; if (base > 0x100000L) { /* Set the descriptor access rights (for a 32 bit page granular * segment). */ r.x.ax = 9; r.x.bx = sel; r.x.cx = 0x8092; PM_int386(0x31, &r, &r); /* Map physical memory above 1Mb */ if ((base = DPMI_mapPhysicalToLinear(base,limit)) == 0) return 0; } if (!DPMI_setSelectorBase(sel,base)) return 0; if (!DPMI_setSelectorLimit(sel,limit)) return 0; return sel; } void DPMI_freeSelector(uint sel) { PMREGS r; r.x.ax = 1; r.x.bx = sel; PM_int386(0x31, &r, &r); } int DPMI_lockLinearPages(ulong linear,ulong len) { PMREGS r; r.x.ax = 0x600; /* DPMI Lock Linear Region */ r.x.bx = (linear >> 16); /* Linear address in BX:CX */ r.x.cx = (linear & 0xFFFF); r.x.si = (len >> 16); /* Length in SI:DI */ r.x.di = (len & 0xFFFF); PM_int386(0x31, &r, &r); return (!r.x.cflag); } int DPMI_unlockLinearPages(ulong linear,ulong len) { PMREGS r; r.x.ax = 0x601; /* DPMI Unlock Linear Region */ r.x.bx = (linear >> 16); /* Linear address in BX:CX */ r.x.cx = (linear & 0xFFFF); r.x.si = (len >> 16); /* Length in SI:DI */ r.x.di = (len & 0xFFFF); PM_int386(0x31, &r, &r); return (!r.x.cflag); } #if defined(PM386) && !defined(__WINDOWS32__) /* Some DOS extender implementations do not directly support calling a * real mode procedure from protected mode. However we can simulate what * we need temporarily hooking the INT 2Fh vector with a small real mode * stub that will call our real mode code for us. */ static uchar int2FHandler[] = { 0x00,0x00,0x00,0x00, /* __PMODE_callReal variable */ 0xFB, /* sti */ 0x2E,0xFF,0x1E,0x00,0x00, /* call [cs:__PMODE_callReal] */ 0xCF, /* iretf */ }; static uint crSel=0,crOff; /* Selector:offset of int 2F handler */ static uint crRSeg,crROff; /* Real mode seg:offset of handler */ void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in, RMSREGS *sregs) { uint psel,poff; uint oldSeg,oldOff; if (!crSel) { /* Allocate and copy the memory block only once */ PM_allocRealSeg(sizeof(int2FHandler), &crSel, &crOff, &crRSeg, &crROff); PM_memcpyfn(crSel,crOff,int2FHandler,sizeof(int2FHandler)); } PM_setWord(crSel,crOff,off); /* Plug in address to call */ PM_setWord(crSel,crOff+2,seg); PM_mapRealPointer(&psel,&poff,0,0x2F * 4); oldOff = PM_getWord(psel,poff); /* Save old handler address */ oldSeg = PM_getWord(psel,poff+2); PM_setWord(psel,poff,crROff+4); /* Hook 2F handler */ PM_setWord(psel,poff+2,crRSeg); PM_int86x(0x2F, in, in, sregs); /* Call real mode code */ PM_setWord(psel,poff,oldOff); /* Restore old handler */ PM_setWord(psel,poff+2,oldSeg); } #endif #endif /*-------------------------------------------------------------------------*/ /* DOS Real Mode support. */ /*-------------------------------------------------------------------------*/ #ifdef REALMODE #ifndef MK_FP #define MK_FP(s,o) ( (void far *)( ((ulong)(s) << 16) + \ (ulong)(o) )) #endif uchar PMAPI PM_getByte(uint s, uint o) { return *((uchar*)MK_FP(s,o)); } ushort PMAPI PM_getWord(uint s, uint o) { return *((uint*)MK_FP(s,o)); } ulong PMAPI PM_getLong(uint s, uint o) { return *((ulong*)MK_FP(s,o)); } void PMAPI PM_setByte(uint s, uint o, uchar v) { *((uchar*)MK_FP(s,o)) = v; } void PMAPI PM_setWord(uint s, uint o, ushort v) { *((ushort *)MK_FP(s,o)) = v; } void PMAPI PM_setLong(uint s, uint o, ulong v) { *((ulong*)MK_FP(s,o)) = v; } void PMAPI PM_memcpynf(void *dst,uint src_s,uint src_o,uint n) { memcpy(dst,MK_FP(src_s,src_o),n); } void PMAPI PM_memcpyfn(uint dst_s,uint dst_o,void *src,uint n) { memcpy(MK_FP(dst_s,dst_o),src,n); } void PMAPI PM_mapRealPointer(uint *sel,uint *off,uint r_seg, uint r_off) { *sel = r_seg; *off = r_off; } uint PMAPI PM_createSelector(ulong base,ulong limit) { limit = limit; return (uint)(base >> 4); } void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit) { uint sel = base >> 4; uint off = base & 0xF; limit = limit; return MK_FP(sel,off); } void PMAPI PM_freeSelector(uint sel) { sel = sel; } int PMAPI PM_allocRealSeg(uint size, uint *sel,uint *off, uint *r_seg, uint *r_off) { /* Call malloc() to allocate the memory for us */ void *p = malloc(size); *sel = *r_seg = FP_SEG(p); *off = *r_off = FP_OFF(p); return 1; } void PMAPI PM_freeRealSeg(uint sel,uint off) { free(MK_FP(sel,off)); } int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) { return int86(intno,in,out); } int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs) { return int86x(intno,in,out,sregs); } void PMAPI PM_availableMemory(ulong *physical,ulong *total) { union REGS regs; regs.h.ah = 0x48; regs.x.bx = 0xFFFF; int86(0x21,®s,®s); *physical = *total = regs.x.bx * 16UL; } #endif /*-------------------------------------------------------------------------*/ /* Windows 3.1 16 bit DPMI and Borland DPMI16 DOS Power Pack support. */ /*-------------------------------------------------------------------------*/ #if defined(__WINDOWS16__) || defined(DPMI16) uchar PMAPI PM_getByte(uint s, uint o) { return *((uchar*)MK_FP(s,o)); } ushort PMAPI PM_getWord(uint s, uint o) { return *((uint*)MK_FP(s,o)); } ulong PMAPI PM_getLong(uint s, uint o) { return *((ulong*)MK_FP(s,o)); } void PMAPI PM_setByte(uint s, uint o, uchar v) { *((uchar*)MK_FP(s,o)) = v; } void PMAPI PM_setWord(uint s, uint o, ushort v) { *((ushort *)MK_FP(s,o)) = v; } void PMAPI PM_setLong(uint s, uint o, ulong v) { *((ulong*)MK_FP(s,o)) = v; } void PMAPI PM_memcpynf(void *dst,uint src_s,uint src_o,uint n) { memcpy(dst,MK_FP(src_s,src_o),n); } void PMAPI PM_memcpyfn(uint dst_s,uint dst_o,void *src,uint n) { memcpy(MK_FP(dst_s,dst_o),src,n); } uint PMAPI PM_createSelector(ulong base,ulong limit) { return DPMI_createSelector(base,limit); } void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit) { uint sel = PM_createSelector(base,limit); return MK_FP(sel,0); } void PMAPI PM_freeSelector(uint sel) { DPMI_freeSelector(sel); } void PMAPI PM_mapRealPointer(uint *sel,uint *off,uint r_seg, uint r_off) { static uint staticSel = 0; if (staticSel) PM_freeSelector(staticSel); staticSel = PM_createSelector(MK_PHYS(r_seg,r_off), 0xFFFF); *sel = staticSel; *off = 0; } uint PMAPI PM_createCode32Alias(uint sel) { uint alias; union REGS r; r.x.ax = 0xA; r.x.bx = sel; int86(0x31,&r,&r); /* Create Alias descriptor */ if (r.x.cflag) return 0; alias = r.x.ax; /* Set descriptor access rights (for a 32 bit code segment) */ r.x.ax = 9; r.x.bx = alias; r.x.cx = 0x40FB; int86(0x31, &r, &r); if (r.x.cflag) return 0; return alias; } #pragma pack(1) typedef struct { long edi; long esi; long ebp; long reserved; long ebx; long edx; long ecx; long eax; short flags; short es,ds,fs,gs,ip,cs,sp,ss; } _RMREGS; #pragma pack() #define IN(reg) rmregs.e##reg = in->x.reg #define OUT(reg) out->x.reg = (int)rmregs.e##reg #define OUT1(reg) in->x.reg = (int)rmregs.e##reg void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in, RMSREGS *sregs) { _RMREGS rmregs; union REGS r; struct SREGS sr; void *p; memset(&rmregs, 0, sizeof(rmregs)); IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di); rmregs.es = sregs->es; rmregs.ds = sregs->ds; rmregs.cs = seg; rmregs.ip = off; memset(&sr, 0, sizeof(sr)); r.x.ax = 0x301; /* DPMI call real mode */ r.h.bh = 0; r.x.cx = 0; p = &rmregs; sr.es = FP_SEG(p); r.x.di = FP_OFF(p); int86x(0x31, &r, &r, &sr); /* Issue the interrupt */ OUT1(ax); OUT1(bx); OUT1(cx); OUT1(dx); OUT1(si); OUT1(di); sregs->es = rmregs.es; sregs->ds = rmregs.ds; } int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) { _RMREGS rmregs; union REGS r; struct SREGS sr; void *p; memset(&rmregs, 0, sizeof(rmregs)); IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di); memset(&sr, 0, sizeof(sr)); r.x.ax = 0x300; /* DPMI issue real interrupt */ r.h.bl = intno; r.h.bh = 0; r.x.cx = 0; p = &rmregs; sr.es = FP_SEG(p); r.x.di = FP_OFF(p); int86x(0x31, &r, &r, &sr); /* Issue the interrupt */ OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di); out->x.cflag = rmregs.flags & 0x1; return out->x.ax; } int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs) { _RMREGS rmregs; union REGS r; struct SREGS sr; void *p; memset(&rmregs, 0, sizeof(rmregs)); IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di); rmregs.es = sregs->es; rmregs.ds = sregs->ds; memset(&sr, 0, sizeof(sr)); r.x.ax = 0x300; /* DPMI issue real interrupt */ r.h.bl = intno; r.h.bh = 0; r.x.cx = 0; p = &rmregs; sr.es = FP_SEG(p); r.x.di = FP_OFF(p); int86x(0x31, &r, &r, &sr); /* Issue the interrupt */ OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di); sregs->es = rmregs.es; sregs->cs = rmregs.cs; sregs->ss = rmregs.ss; sregs->ds = rmregs.ds; out->x.cflag = rmregs.flags & 0x1; return out->x.ax; } void PMAPI PM_availableMemory(ulong *physical,ulong *total) { union REGS r; struct SREGS sr; struct MemInfo { ulong LargestBlockAvail; ulong MaxUnlockedPage; ulong LargestLockablePage; ulong LinAddrSpace; ulong NumFreePagesAvail; ulong NumPhysicalPagesFree; ulong TotalPhysicalPages; ulong FreeLinAddrSpace; ulong SizeOfPageFile; ulong res[3]; } memInfo; void *p; memset(&sr, 0, sizeof(sr)); r.x.ax = 0x500; /* DPMI get free memory info */ p = &memInfo; sr.es = FP_SEG(p); r.x.di = FP_OFF(p); int86x(0x31, &r, &r, &sr); /* Issue the interrupt */ *physical = memInfo.NumPhysicalPagesFree * 4096; *total = memInfo.LargestBlockAvail; if (*total < *physical) *physical = *total; } #endif /*-------------------------------------------------------------------------*/ /* Borland DPMI16 DOS Power Pack support. */ /*-------------------------------------------------------------------------*/ #if defined(DPMI16) int PMAPI PM_allocRealSeg(uint size, uint *sel,uint *off, uint *r_seg, uint *r_off) { union REGS r; r.x.ax = 0x100; /* DPMI allocate DOS memory */ r.x.bx = (size + 0xF) >> 4; /* number of paragraphs */ int86(0x31, &r, &r); if (r.x.cflag) return NULL; /* DPMI call failed */ *sel = r.x.dx; /* Protected mode selector */ *off = 0; *r_seg = r.x.ax; /* Real mode segment */ *r_off = 0; return 1; } void PMAPI PM_freeRealSeg(uint sel,uint off) { union REGS r; r.x.ax = 0x101; /* DPMI free DOS memory */ r.x.dx = sel; /* DX := selector from 0x100 */ off = off; int86(0x31, &r, &r); } #endif /*-------------------------------------------------------------------------*/ /* Phar Lap TNT DOS Extender support. */ /*-------------------------------------------------------------------------*/ #ifdef TNT #include #include #include void PMAPI PM_mapRealPointer(uint *sel,uint *off,uint r_seg, uint r_off) { CONFIG_INF config; _dx_config_inf(&config, (UCHAR*)&config); *sel = config.c_dos_sel; *off = MK_PHYS(r_seg,r_off); } uint PMAPI _PL_allocsel(void); uint PMAPI PM_createSelector(ulong base,ulong limit) { USHORT sel; ULONG off; CD_DES desc; if ((sel = _PL_allocsel()) == 0) return 0; if (base > 0xFFFFFL) { /* Map in the physical memory above the 1Mb memory boundary */ _dx_map_phys(sel,base,(limit + 4095) / 4096,&off); } else { if (_dx_ldt_rd(sel,(UCHAR*)&desc) != 0) return 0; if (limit >= 0x100000) { limit >>= 12; /* Page granular for > 1Mb limit */ desc.limit0_15 = limit & 0xFFFF; desc.limit16_19 = ((limit >> 16) & 0xF) | DOS_32 | SG_PAGE; } else { /* Byte granular for < 1Mb limit */ desc.limit0_15 = limit & 0xFFFF; desc.limit16_19 = ((limit >> 16) & 0xF) | DOS_32 | SG_BYTE; } desc.base0_15 = base & 0xFFFF; desc.base16_23 = (base >> 16) & 0xFF; desc.base24_31 = (base >> 24) & 0xFF; desc.arights = AR_DATA | AR_DPL3; if (_dx_ldt_wr(sel,(UCHAR*)&desc) != 0) return 0; } return sel; } void PMAPI PM_freeSelector(uint sel) { CD_DES desc; /* Set the selector's values to all zero's, so that Phar Lap will * re-use the selector entry. */ if (_dx_ldt_rd(sel,(UCHAR*)&desc) != 0) return; desc.limit0_15 = 0; desc.limit16_19 = 0; desc.base0_15 = 0; desc.base16_23 = 0; desc.base24_31 = 0; desc.arights = 0; _dx_ldt_wr(sel,(UCHAR*)&desc); } int PMAPI PM_allocRealSeg(uint size, uint *sel,uint *off, uint *r_seg, uint *r_off) { CONFIG_INF config; USHORT addr,t; if (_dx_real_alloc((size + 0xF) >> 4,&addr,&t) != 0) return 0; _dx_config_inf(&config, (UCHAR*)&config); *sel = config.c_dos_sel; /* Map with DOS 1Mb selector */ *off = (ULONG)addr << 4; *r_seg = addr; /* Real mode segment address */ *r_off = 0; /* Real mode segment offset */ return 1; } void PMAPI PM_freeRealSeg(uint sel,uint off) { sel = sel; _dx_real_free(off >> 4); } #define IN(reg) rmregs.e##reg = in->x.reg #define OUT(reg) out->x.reg = rmregs.e##reg int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) { SWI_REGS rmregs; memset(&rmregs, 0, sizeof(rmregs)); IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di); _dx_real_int(intno,&rmregs); OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di); out->x.cflag = rmregs.flags & 0x1; return out->x.ax; } int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs) { SWI_REGS rmregs; memset(&rmregs, 0, sizeof(rmregs)); IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di); rmregs.es = sregs->es; rmregs.ds = sregs->ds; _dx_real_int(intno,&rmregs); OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di); sregs->es = rmregs.es; sregs->cs = rmregs.cs; sregs->ss = rmregs.ss; sregs->ds = rmregs.ds; out->x.cflag = rmregs.flags & 0x1; return out->x.ax; } void PMAPI PM_availableMemory(ulong *physical,ulong *total) { PMREGS r; uint data[25]; r.x.ax = 0x2520; /* Get free memory info */ r.x.bx = 0; r.e.edx = (uint)data; PM_int386(0x21, &r, &r); *physical = data[21] * 4096; *total = data[23] * 4096; } #endif /*-------------------------------------------------------------------------*/ /* Symantec C++ DOSX and FlashTek X-32/X-32VM support */ /*-------------------------------------------------------------------------*/ #if defined(DOSX) || defined(X32VM) #include #ifdef X32VM #include #define _x386_mk_protected_ptr(p) _x32_mk_protected_ptr((void*)p) #define _x386_free_protected_ptr(p) _x32_free_protected_ptr(p) #define _x386_zero_base_ptr _x32_zero_base_ptr #else extern void *_x386_zero_base_ptr; #endif void PMAPI PM_mapRealPointer(uint *sel,uint *off,uint r_seg, uint r_off) { *sel = _x386_zero_base_selector; *off = MK_PHYS(r_seg,r_off); } uint PMAPI PM_createSelector(ulong base,ulong limit) { void _far *p; p = (void _far *)_x386_mk_protected_ptr(base); limit = limit; return FP_SEG(p); } void PMAPI PM_freeSelector(uint sel) { _x386_free_protected_ptr(MK_FP(sel,0)); } int PMAPI PM_allocRealSeg(uint size, uint *sel,uint *off, uint *r_seg, uint *r_off) { PMREGS r; r.h.ah = 0x48; /* DOS function 48h - allocate mem */ r.x.bx = (size + 0xF) >> 4; /* Number of paragraphs to allocate */ PM_int386(0x21, &r, &r); /* Call DOS extender */ if (r.x.cflag) return 0; /* Could not allocate the memory */ *sel = _x386_zero_base_selector; *off = r.e.eax << 4; *r_seg = r.e.eax; *r_off = 0; return 1; } void PMAPI PM_freeRealSeg(uint sel,uint off) { /* Cannot de-allocate this memory */ sel = sel; off = off; } #pragma pack(1) typedef struct { ushort intno; ushort ds; ushort es; ushort fs; ushort gs; ulong eax; ulong edx; } _RMREGS; #pragma pack() #define IN(reg) regs.e.e##reg = in->x.reg #define OUT(reg) out->x.reg = regs.x.reg int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) { _RMREGS rmregs; PMREGS regs; PMSREGS pmsregs; rmregs.intno = intno; rmregs.eax = in->x.ax; rmregs.edx = in->x.dx; IN(bx); IN(cx); IN(si); IN(di); regs.x.ax = 0x2511; regs.e.edx = (uint)(&rmregs); PM_segread(&pmsregs); PM_int386x(0x21,®s,®s,&pmsregs); OUT(ax); OUT(bx); OUT(cx); OUT(si); OUT(di); out->x.dx = rmregs.edx; out->x.cflag = regs.x.cflag; return out->x.ax; } int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs) { _RMREGS rmregs; PMREGS regs; PMSREGS pmsregs; rmregs.intno = intno; rmregs.eax = in->x.ax; rmregs.edx = in->x.dx; rmregs.es = sregs->es; rmregs.ds = sregs->ds; IN(bx); IN(cx); IN(si); IN(di); regs.x.ax = 0x2511; regs.e.edx = (uint)(&rmregs); PM_segread(&pmsregs); PM_int386x(0x21,®s,®s,&pmsregs); OUT(ax); OUT(bx); OUT(cx); OUT(si); OUT(di); sregs->es = rmregs.es; sregs->ds = rmregs.ds; out->x.dx = rmregs.edx; out->x.cflag = regs.x.cflag; return out->x.ax; } void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit) { if (base > 0x100000) return _x386_map_physical_address((void*)base,limit); return (void*)((ulong)_x386_zero_base_ptr + base); } ulong _cdecl _X32_getPhysMem(void); void PMAPI PM_availableMemory(ulong *physical,ulong *total) { PMREGS regs; /* Get total memory available, including virtual memory */ regs.x.ax = 0x350B; PM_int386(0x21,®s,®s); *total = regs.e.eax; /* Get physical memory available */ *physical = _X32_getPhysMem(); if (*physical > *total) *physical = *total; } #endif /*-------------------------------------------------------------------------*/ /* Borland's DPMI32 DOS Power Pack Extender support. */ /*-------------------------------------------------------------------------*/ #ifdef DPMI32 #define GENERIC_DPMI32 /* Use generic 32 bit DPMI routines */ #endif /*-------------------------------------------------------------------------*/ /* Watcom C/C++ with Rational DOS/4GW support. */ /*-------------------------------------------------------------------------*/ #ifdef DOS4GW #define GENERIC_DPMI32 /* Use generic 32 bit DPMI routines */ #endif /*-------------------------------------------------------------------------*/ /* DJGPP port of GNU C++ support. */ /*-------------------------------------------------------------------------*/ #ifdef DJGPP #define GENERIC_DPMI32 /* Use generic 32 bit DPMI routines */ #endif /*-------------------------------------------------------------------------*/ /* Generic 32 bit DPMI routines */ /*-------------------------------------------------------------------------*/ #if defined(GENERIC_DPMI32) void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit) { PMSREGS sregs; ulong linAddr; ulong DSBaseAddr; /* Get the base address for the default DS selector */ PM_segread(&sregs); DSBaseAddr = DPMI_getSelectorBase(sregs.ds); if ((base < 0x100000) && (DSBaseAddr == 0)) { /* DS is zero based, so we can directly access the first 1Mb of * system memory (like under DOS4GW). */ return (void*)base; } /* Map the memory to a linear address using DPMI function 0x800 */ if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0) { if (base >= 0x100000) return NULL; /* If the linear address mapping fails but we are trying to * map an area in the first 1Mb of system memory, then we must * be running under a Windows or OS/2 DOS box. Under these * environments we can use the segment wrap around as a fallback * measure, as this does work properly. */ linAddr = base; } /* Now expand the default DS selector to 4Gb so we can access it */ if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL)) return NULL; /* Now return the base address of the memory into the default DS */ return (void*)(linAddr - DSBaseAddr); } void PMAPI PM_mapRealPointer(uint *sel,uint *off,uint r_seg, uint r_off) { static uint lowMem = 0; if (!lowMem) lowMem = PM_createSelector(0, 0xFFFFF); *sel = lowMem; *off = MK_PHYS(r_seg,r_off); } int PMAPI PM_allocRealSeg(uint size, uint *sel,uint *off, uint *r_seg, uint *r_off) { PMREGS r; r.x.ax = 0x100; /* DPMI allocate DOS memory */ r.x.bx = (size + 0xF) >> 4; /* number of paragraphs */ PM_int386(0x31, &r, &r); if (r.x.cflag) return NULL; /* DPMI call failed */ *sel = r.x.dx; /* Protected mode selector */ *off = 0; *r_seg = r.x.ax; /* Real mode segment */ *r_off = 0; return 1; } void PMAPI PM_freeRealSeg(uint sel,uint off) { PMREGS r; r.x.ax = 0x101; /* DPMI free DOS memory */ r.x.dx = sel; /* DX := selector from 0x100 */ off = off; PM_int386(0x31, &r, &r); } #pragma pack(1) typedef struct { long edi; long esi; long ebp; long reserved; long ebx; long edx; long ecx; long eax; short flags; short es,ds,fs,gs,ip,cs,sp,ss; } _RMREGS; #pragma pack() #define IN(reg) rmregs.e##reg = in->x.reg #define OUT(reg) out->x.reg = rmregs.e##reg int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) { _RMREGS rmregs; PMREGS r; PMSREGS sr; memset(&rmregs, 0, sizeof(rmregs)); IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di); PM_segread(&sr); r.x.ax = 0x300; /* DPMI issue real interrupt */ r.h.bl = intno; r.h.bh = 0; r.x.cx = 0; sr.es = sr.ds; r.e.edi = (uint)&rmregs; PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */ OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di); out->x.cflag = rmregs.flags & 0x1; return out->x.ax; } int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs) { _RMREGS rmregs; PMREGS r; PMSREGS sr; memset(&rmregs, 0, sizeof(rmregs)); IN(ax); IN(bx); IN(cx); IN(dx); IN(si); IN(di); rmregs.es = sregs->es; rmregs.ds = sregs->ds; PM_segread(&sr); r.x.ax = 0x300; /* DPMI issue real interrupt */ r.h.bl = intno; r.h.bh = 0; r.x.cx = 0; sr.es = sr.ds; r.e.edi = (uint)&rmregs; PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */ OUT(ax); OUT(bx); OUT(cx); OUT(dx); OUT(si); OUT(di); sregs->es = rmregs.es; sregs->cs = rmregs.cs; sregs->ss = rmregs.ss; sregs->ds = rmregs.ds; out->x.cflag = rmregs.flags & 0x1; return out->x.ax; } uint PMAPI PM_createSelector(ulong base,ulong limit) { return DPMI_createSelector(base,limit); } void PMAPI PM_freeSelector(uint sel) { DPMI_freeSelector(sel); } void PMAPI PM_availableMemory(ulong *physical,ulong *total) { PMREGS r; PMSREGS sr; struct MemInfo { uint LargestBlockAvail; uint MaxUnlockedPage; uint LargestLockablePage; uint LinAddrSpace; uint NumFreePagesAvail; uint NumPhysicalPagesFree; uint TotalPhysicalPages; uint FreeLinAddrSpace; uint SizeOfPageFile; uint res[3]; } memInfo; PM_segread(&sr); r.x.ax = 0x500; /* DPMI get free memory info */ sr.es = sr.ds; r.e.edi = (uint)&memInfo; PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */ *physical = memInfo.NumPhysicalPagesFree * 4096; *total = memInfo.LargestBlockAvail; if (*total < *physical) *physical = *total; } #endif