📄 pm.c
字号:
/****************************************************************************** SciTech OS Portability Manager Library** ========================================================================** The contents of this file are subject to the SciTech MGL Public* License Version 1.0 (the "License"); you may not use this file* except in compliance with the License. You may obtain a copy of* the License at http://www.scitechsoft.com/mgl-license.txt** Software distributed under the License is distributed on an* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or* implied. See the License for the specific language governing* rights and limitations under the License.** The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.** The Initial Developer of the Original Code is SciTech Software, Inc.* All Rights Reserved.** ========================================================================** Language: ANSI C* Environment: 32-bit OS/2** Description: Implementation for the OS Portability Manager Library, which* contains functions to implement OS specific services in a* generic, cross platform API. Porting the OS Portability* Manager library is the first step to porting any SciTech* products to a new platform.*****************************************************************************/#include "pmapi.h"#include "drvlib/os/os.h"#include "pm_help.h"#include "mtrr.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <process.h>#ifndef __EMX__#include <direct.h>#endif#define INCL_DOSERRORS#define INCL_DOS#define INCL_SUB#define INCL_VIO#define INCL_KBD#include <os2.h>/* Semaphore for communication with our background daemon */#define SHAREDSEM ((PSZ)"\\SEM32\\SDD\\DAEMON")#define DAEMON_NAME "SDDDAEMN.EXE"/*--------------------------- Global variables ----------------------------*//* Public structures used to communicate with VIDEOPMI for implementing * the ability to call the real mode BIOS functions. */typedef struct _VIDEOMODEINFO { ULONG miModeId; USHORT usType; USHORT usInt10ModeSet; USHORT usXResolution; USHORT usYResolution; ULONG ulBufferAddress; ULONG ulApertureSize; BYTE bBitsPerPixel; BYTE bBitPlanes; BYTE bXCharSize; BYTE bYCharSize; USHORT usBytesPerScanLine; USHORT usTextRows; ULONG ulPageLength; ULONG ulSaveSize; BYTE bVrtRefresh; BYTE bHrtRefresh; BYTE bVrtPolPos; BYTE bHrtPolPos; CHAR bRedMaskSize; CHAR bRedFieldPosition; CHAR bGreenMaskSize; CHAR bGreenFieldPosition; CHAR bBlueMaskSize; CHAR bBlueFieldPosition; CHAR bRsvdMaskSize; CHAR bRsvdFieldPosition; ULONG ulColors; ULONG ulReserved[3]; } VIDEOMODEINFO, FAR *PVIDEOMODEINFO;typedef struct _ADAPTERINFO { ULONG ulAdapterID; CHAR szOEMString[128]; CHAR szDACString[128]; CHAR szRevision[128]; ULONG ulTotalMemory; ULONG ulMMIOBaseAddress; ULONG ulPIOBaseAddress; BYTE bBusType; BYTE bEndian; USHORT usDeviceBusID; USHORT usVendorBusID; USHORT SlotID; } ADAPTERINFO, FAR *PADAPTERINFO;typedef struct _VIDEO_ADAPTER { void *hvideo; ADAPTERINFO Adapter; VIDEOMODEINFO ModeInfo; } VIDEO_ADAPTER, FAR *PVIDEO_ADAPTER;/* PMIREQUEST_SOFTWAREINT structures from OS/2 DDK */typedef struct { ULONG ulFlags; /* VDM initialization type */#define VDM_POSTLOAD 0x1 /* adapter just loaded, used internally for initialization */#define VDM_INITIALIZE 0x2 /* force initialization of a permanently open VDM, even if previously initialized */#define VDM_TERMINATE_POSTINITIALIZE 0x6 /*start VDM with initialization, but close it afterwards (includes VDM_INITIALIZE) */#define VDM_QUERY_CAPABILITY 0x10 /* query the current int 10 capability */#define VDM_FULL_VDM_CREATED 0x20 /* a full VDM is created */#define VDM_MINI_VDM_CREATED 0x40 /* a mini VDM is created */#define VDM_MINI_VDM_SUPPORTED 0x80 /* mini VDM support is available */ PCHAR szName; /* VDM initialization program */ PCHAR szArgs; /* VDM initialization arguments */ }INITVDM;typedef struct { BYTE bBufferType;#define BUFFER_NONE 0#define INPUT_BUFFER 1#define OUTPUT_BUFFER 2 BYTE bReserved; BYTE bSelCRF; BYTE bOffCRF; PVOID pAddress; ULONG ulSize; } BUFFER, *PBUFFER;typedef struct vcrf_s { ULONG reg_eax; ULONG reg_ebx; ULONG reg_ecx; ULONG reg_edx; ULONG reg_ebp; ULONG reg_esi; ULONG reg_edi; ULONG reg_ds; ULONG reg_es; ULONG reg_fs; ULONG reg_gs; ULONG reg_cs; ULONG reg_eip; ULONG reg_eflag; ULONG reg_ss; ULONG reg_esp; } VCRF;typedef struct { ULONG ulBIOSIntNo; VCRF aCRF; BUFFER pB[2]; } INTCRF;#define PMIREQUEST_LOADPMIFILE 21#define PMIREQUEST_IDENTIFYADAPTER 22#define PMIREQUEST_SOFTWAREINT 23#ifdef PTR_DECL_IN_FRONT#define EXPENTRYP * EXPENTRY#else#define EXPENTRYP EXPENTRY *#endif/* Entry point to VIDEOPMI32Request. This may be overridden by external * code that has already loaded VIDEOPMI to avoid loading it twice. */APIRET (EXPENTRYP PM_VIDEOPMI32Request)(PVIDEO_ADAPTER, ULONG, PVOID, PVOID) = NULL;static ibool haveInt10 = -1; /* True if we have Int 10 support */static ibool useVPMI = true; /* False if VIDEOPMI unavailable */static VIDEO_ADAPTER Adapter; /* Video adapter for VIDEOPMI */static uchar RMBuf[1024]; /* Fake real mode transfer buffer */static uint VESABuf_len = 1024;/* Length of the VESABuf buffer */static void *VESABuf_ptr = NULL;/* Near pointer to VESABuf */static uint VESABuf_rseg; /* Real mode segment of VESABuf */static uint VESABuf_roff; /* Real mode offset of VESABuf */static uchar * lowMem = NULL;static ibool isSessionSwitching = false;static ulong parmsIn[4]; /* Must not cross 64Kb boundary! */static ulong parmsOut[4]; /* Must not cross 64Kb boundary! */extern ushort _PM_gdt;static void (PMAPIP fatalErrorCleanup)(void) = NULL;/* DosSysCtl prototype. It is not declared in the headers but it is in the * standard import libraries (DOSCALLS.876). Funny. */APIRET APIENTRY DosSysCtl(ULONG ulFunction, PVOID pvData);/* This is the stack size for the threads that track the session switch event */#define SESSION_SWITCH_STACK_SIZE 32768typedef struct { VIOMODEINFO vmi; USHORT CursorX; USHORT CursorY; UCHAR FrameBuffer[1]; } CONSOLE_SAVE;typedef struct _SESWITCHREC { /* The following variable is volatile because of PM_SUSPEND_APP */ volatile int Flags; /* -1 or PM_DEACTIVATE or PM_REACTIVATE */ PM_saveState_cb Callback; /* Save/restore context callback */ HMTX Mutex; /* Exclusive access mutex */ HEV Event; /* Posted after callback is called */ } SESWITCHREC;/* Page sized block cache */#define PAGES_PER_BLOCK 32#define PAGE_BLOCK_SIZE (PAGES_PER_BLOCK * PM_PAGE_SIZE + (PM_PAGE_SIZE-1) + sizeof(pageblock))#define FREELIST_NEXT(p) (*(void**)(p))typedef struct pageblock { struct pageblock *next; struct pageblock *prev; void *freeListStart; void *freeList; void *freeListEnd; int freeCount; PM_lockHandle lockHandle; } pageblock;static pageblock *pageBlocks = NULL;/*----------------------------- Implementation ----------------------------*//****************************************************************************PARAMETERS:func - Helper device driver function to callRETURNS:First return value from the device driver in parmsOut[0]REMARKS:Function to open our helper device driver, call it and close the filehandle. Note that we have to open the device driver for every call becauseof two problems: 1. We cannot open a single file handle in a DLL that is shared amongst programs, since every process must have it's own open file handle. 2. For some reason there appears to be a limit of about 12 open file handles on a device driver in the system. Hence when we open more than about 12 file handles things start to go very strange.Hence we simply open the file handle every time that we need to call thedevice driver to work around these problems.****************************************************************************/static ulong CallSDDHelp( int func){ static ulong inLen; /* Must not cross 64Kb boundary! */ static ulong outLen; /* Must not cross 64Kb boundary! */ HFILE hSDDHelp; ULONG rc; ulong result; if ((rc = DosOpen(PMHELP_NAME,&hSDDHelp,&result,0,0, FILE_OPEN, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL)) != 0) { if (rc == 4) { /* Did we run out of file handles? */ ULONG ulNewFHs; LONG lAddFHs = 5; if (DosSetRelMaxFH(&lAddFHs, &ulNewFHs) != 0) PM_fatalError("Failed to raise the file handles limit!"); else { if ((rc = DosOpen(PMHELP_NAME,&hSDDHelp,&result,0,0, FILE_OPEN, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL)) != 0) { PM_fatalError("Unable to open SDDHELP$ helper device driver! (#2)"); } } } else PM_fatalError("Unable to open SDDHELP$ helper device driver!"); } if (DosDevIOCtl(hSDDHelp,PMHELP_IOCTL,func, &parmsIn, inLen = sizeof(parmsIn), &inLen, &parmsOut, outLen = sizeof(parmsOut), &outLen) != 0) PM_fatalError("Failure calling SDDHELP$ helper device driver!"); DosClose(hSDDHelp); return parmsOut[0];}/****************************************************************************REMARKS:Determine if we're running on a DBCS system.****************************************************************************/ibool __IsDBCSSystem(void){ CHAR achDBCSInfo[12]; COUNTRYCODE ccStruct = {0, 0}; memset(achDBCSInfo, 0, 12); /* Get the DBCS vector - if it's not empty, we're on DBCS */ DosQueryDBCSEnv(sizeof(achDBCSInfo), &ccStruct, achDBCSInfo); if (achDBCSInfo[0] != 0) return true; else return false;}/****************************************************************************REMARKS:Determine if PMSHELL is running - if it isn't, we can't use certain calls****************************************************************************/ibool __isShellLoaded(void){ PVOID ptr; if (DosGetNamedSharedMem(&ptr, (PSZ)"\\SHAREMEM\\PMGLOBAL.MEM", PAG_READ) == NO_ERROR) { DosFreeMem(ptr); return true; } return false;}/****************************************************************************REMARKS:Initialise the PM library and connect to our helper device driver. If wecannot connect to our helper device driver, we bail out with an errormessage.****************************************************************************/void PMAPI PM_init(void){ if (!lowMem) { /* Obtain the 32->16 callgate from the device driver to enable IOPL */ if ((_PM_gdt = CallSDDHelp(PMHELP_GETGDT32)) == 0) PM_fatalError("Unable to obtain call gate selector!"); PM_setIOPL(3); /* Map the first Mb of physical memory into lowMem */ if ((lowMem = PM_mapPhysicalAddr(0,0xFFFFF,true)) == NULL) PM_fatalError("Unable to map first Mb physical memory!"); /* Initialise the MTRR interface functions */ MTRR_init(); }}/****************************************************************************REMARKS:Initialise the PM library for BIOS access via VIDEOPMI. This should workwith any GRADD driver, including SDD/2.****************************************************************************/static ibool InitInt10(void){ HMODULE hModGENPMI,hModSDDPMI,hModVideoPMI; CHAR buf[80],path[_MAX_PATH]; HEV hevDaemon = NULLHANDLE; RESULTCODES resCodes; if (haveInt10 == -1) { /* Connect to VIDEOPMI and get entry point. Note that we only * do this if GENPMI or SDDPMI are already loaded, since we need * a GRADD based driver for this to work. */ PM_init(); haveInt10 = false; if (DosQueryModuleHandle((PSZ)"GENPMI.DLL",&hModGENPMI) != 0) hModGENPMI = NULLHANDLE; if (DosQueryModuleHandle((PSZ)"SDDPMI.DLL",&hModSDDPMI) != 0) hModSDDPMI = NULLHANDLE; if (hModGENPMI || hModSDDPMI) { if (DosLoadModule((PSZ)buf,sizeof(buf),(PSZ)"VIDEOPMI.DLL",&hModVideoPMI) == 0) { if (DosQueryProcAddr(hModVideoPMI,0,(PSZ)"VIDEOPMI32Request",(void*)&PM_VIDEOPMI32Request) != 0) PM_fatalError("Unable to get VIDEOPMI32Request entry point!"); strcpy(path,"X:\\OS2\\SVGADATA.PMI"); path[0] = PM_getBootDrive(); if (PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_LOADPMIFILE,path,NULL) != 0) { DosFreeModule(hModVideoPMI); PM_VIDEOPMI32Request = NULL; haveInt10 = false; } else { /* Attempt to initialise the full VDM in the system. This will only * work if VPRPMI.SYS is loaded, but it provides support for passing * values in ES/DS/ESI/EDI between the BIOS which does not work with * kernel VDM's in fixpacks earlier than FP15. FP15 and later and * the new Warp 4.51 and Warp Server convenience packs should work * fine with the kernel mini-VDM. * * Also the full VDM is the only solution for really old kernels * (but GRADD won't run on them so this is superfluous ;-). */ INITVDM InitVDM = {VDM_INITIALIZE,NULL,NULL};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -