📄 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: 16/32 bit DOS** 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 "ztimerc.h"#include "mtrr.h"#include "pm_help.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <dos.h>#include <conio.h>#ifdef __GNUC__#include <unistd.h>#include <sys/nearptr.h>#include <sys/stat.h>#else#include <direct.h>#endif#ifdef __BORLANDC__#pragma warn -par#endif/*--------------------------- Global variables ----------------------------*/typedef struct { int oldMode; int old50Lines; } DOS_stateBuf;#define MAX_RM_BLOCKS 10static struct { void *p; uint tag; } rmBlocks[MAX_RM_BLOCKS];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 void (PMAPIP fatalErrorCleanup)(void) = NULL;ushort _VARAPI _PM_savedDS = 0;#ifdef DOS4GWstatic ulong PDB = 0,*pPDB = NULL;#endif#ifndef REALMODEstatic char VXD_name[] = PMHELP_NAME;static char VXD_module[] = PMHELP_MODULE;static char VXD_DDBName[] = PMHELP_DDBNAME;static uint VXD_version = -1;static uint VXD_loadOff = 0;static uint VXD_loadSel = 0;uint _VARAPI _PM_VXD_off = 0;uint _VARAPI _PM_VXD_sel = 0;int _VARAPI _PM_haveCauseWay = -1;/* Memory mapping cache */#define MAX_MEMORY_MAPPINGS 100typedef struct { ulong physical; ulong linear; ulong limit; } mmapping;static mmapping maps[MAX_MEMORY_MAPPINGS] = {0};static int numMaps = 0;/* Page sized block cache */#define PAGES_PER_BLOCK 100#define FREELIST_NEXT(p) (*(void**)(p))typedef struct pageblock { struct pageblock *next; struct pageblock *prev; void *freeListStart; void *freeList; void *freeListEnd; int freeCount; } pageblock;static pageblock *pageBlocks = NULL;#endif/* Start of all page tables in CauseWay */#define CW_PAGE_TABLE_START (1024UL*4096UL*1023UL)/*----------------------------- Implementation ----------------------------*//* External assembler functions */ulong _ASMAPI _PM_getPDB(void);int _ASMAPI _PM_pagingEnabled(void);void _ASMAPI _PM_VxDCall(VXD_regs *regs,uint off,uint sel);#ifndef REALMODE/****************************************************************************REMARKS:Exit function to unload the dynamically loaded VxD****************************************************************************/static void UnloadVxD(void){ PMSREGS sregs; VXD_regs r; r.eax = 2; r.ebx = 0; r.edx = (uint)VXD_module; PM_segread(&sregs);#ifdef __16BIT__ r.ds = ((ulong)VXD_module) >> 16;#else r.ds = sregs.ds;#endif r.es = sregs.es; _PM_VxDCall(&r,VXD_loadOff,VXD_loadSel);}/****************************************************************************REMARKS:External function to call the PMHELP helper VxD.****************************************************************************/void PMAPI PM_VxDCall( VXD_regs *regs){ if (_PM_VXD_sel != 0 || _PM_VXD_off != 0) _PM_VxDCall(regs,_PM_VXD_off,_PM_VXD_sel);}/****************************************************************************RETURNS:BCD coded version number of the VxD, or 0 if not loaded (ie: 0x202 - 2.2)REMARKS:This function gets the version number for the VxD that we have connected to.****************************************************************************/uint PMAPI PMHELP_getVersion(void){ VXD_regs r; /* Call the helper VxD to determine the version number */ if (_PM_VXD_sel != 0 || _PM_VXD_off != 0) { memset(&r,0,sizeof(r)); r.eax = API_NUM(PMHELP_GETVER); _PM_VxDCall(&r,_PM_VXD_off,_PM_VXD_sel); return VXD_version = (uint)r.eax; } return VXD_version = 0;}/****************************************************************************DESCRIPTION:Connects to the helper VxD and returns the version numberRETURNS:True if the VxD was found and loaded, false otherwise.REMARKS:This function connects to the VxD (loading it if it is dynamically loadable)and returns the version number of the VxD.****************************************************************************/static ibool PMHELP_connect(void){ PMREGS regs; PMSREGS sregs; VXD_regs r; /* Bail early if we have alread connected */ if (VXD_version != -1) return VXD_version != 0; /* Get the static SDDHELP.VXD entry point if available */ PM_segread(&sregs); regs.x.ax = 0x1684; regs.x.bx = SDDHELP_DeviceID; regs.x.di = 0; sregs.es = 0; PM_int386x(0x2F,®s,®s,&sregs); _PM_VXD_sel = sregs.es; _PM_VXD_off = regs.x.di; if (_PM_VXD_sel != 0 || _PM_VXD_off != 0) { if (PMHELP_getVersion() >= PMHELP_VERSION) return true; } /* If we get here, then either SDDHELP.VXD is not loaded, or it is an * earlier version. In this case try to dynamically load the PMHELP.VXD * helper VxD instead. */ PM_segread(&sregs); regs.x.ax = 0x1684; regs.x.bx = VXDLDR_DeviceID; regs.x.di = 0; sregs.es = 0; PM_int386x(0x2F,®s,®s,&sregs); VXD_loadSel = sregs.es; VXD_loadOff = regs.x.di; if (VXD_loadSel == 0 && VXD_loadOff == 0) return VXD_version = 0; r.eax = 1; r.ebx = 0; r.edx = (uint)VXD_name; PM_segread(&sregs); r.ds = sregs.ds; r.es = sregs.es; _PM_VxDCall(&r,VXD_loadOff,VXD_loadSel); if (r.eax != 0) return VXD_version = 0; /* Get the dynamic VxD entry point so we can call it */ atexit(UnloadVxD); PM_segread(&sregs); regs.x.ax = 0x1684; regs.x.bx = 0; regs.e.edi = (uint)VXD_DDBName; PM_int386x(0x2F,®s,®s,&sregs); _PM_VXD_sel = sregs.es; _PM_VXD_off = regs.x.di; if (_PM_VXD_sel == 0 && _PM_VXD_off == 0) return VXD_version = 0; if (PMHELP_getVersion() >= PMHELP_VERSION) return true; return VXD_version = 0;}#endif/****************************************************************************REMARKS:Initialise the PM library. First we try to connect to a static SDDHELP.VXDhelper VxD, and check that it is a version we can use. If not we try todynamically load the PMHELP.VXD helper VxD****************************************************************************/void PMAPI PM_init(void){#ifndef REALMODE PMREGS regs; /* Check if we are running under CauseWay under real DOS */ if (_PM_haveCauseWay == -1) { /* Check if we are running under DPMI in which case we will not be * able to use our special ring 0 CauseWay functions. */ _PM_haveCauseWay = false; regs.x.ax = 0xFF00; PM_int386(0x31,®s,®s); if (regs.x.cflag || !(regs.e.edi & 8)) { /* We are not under DPMI, so now check if CauseWay is active */ regs.x.ax = 0xFFF9; PM_int386(0x31,®s,®s); if (!regs.x.cflag && regs.e.ecx == 0x43415553 && regs.e.edx == 0x45574159) _PM_haveCauseWay = true; } /* Now connect to PMHELP.VXD and initialise MTRR module */ if (!PMHELP_connect()) MTRR_init(); }#endif}/****************************************************************************PARAMETERS:base - The starting physical base address of the regionsize - The size in bytes of the regiontype - Type to place into the MTRR registerRETURNS:Error code describing the result.REMARKS:Function to enable write combining for the specified region of memory.****************************************************************************/int PMAPI PM_enableWriteCombine( ulong base, ulong size, uint type){#ifndef REALMODE VXD_regs regs; if (PMHELP_connect()) { memset(®s,0,sizeof(regs)); regs.eax = API_NUM(PMHELP_ENABLELFBCOMB); regs.ebx = base; regs.ecx = size; regs.edx = type; _PM_VxDCall(®s,_PM_VXD_off,_PM_VXD_sel); return regs.eax; } return MTRR_enableWriteCombine(base,size,type);#else return PM_MTRR_NOT_SUPPORTED;#endif}ibool PMAPI PM_haveBIOSAccess(void){ return true; }long PMAPI PM_getOSType(void){ return _OS_DOS; }int PMAPI PM_getModeType(void){#if defined(REALMODE) return PM_realMode;#elif defined(PM286) return PM_286;#elif defined(PM386) return PM_386;#endif}void PMAPI PM_backslash(char *s){ uint pos = strlen(s); if (s[pos-1] != '\\') { s[pos] = '\\'; s[pos+1] = '\0'; }}void PMAPI PM_setFatalErrorCleanup( void (PMAPIP cleanup)(void)){ fatalErrorCleanup = cleanup;}void PMAPI PM_fatalError(const char *msg){ if (fatalErrorCleanup) fatalErrorCleanup(); fprintf(stderr,"%s\n", msg); exit(1);}static void ExitVBEBuf(void){ if (VESABuf_ptr) PM_freeRealSeg(VESABuf_ptr); VESABuf_ptr = 0;}void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff){ if (!VESABuf_ptr) { /* Allocate a global buffer for communicating with the VESA VBE */ if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL) return NULL; atexit(ExitVBEBuf); } *len = VESABuf_len; *rseg = VESABuf_rseg; *roff = VESABuf_roff; return VESABuf_ptr;}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);}void PMAPI _PM_addRealModeBlock(void *mem,uint tag){ int i; for (i = 0; i < MAX_RM_BLOCKS; i++) { if (rmBlocks[i].p == NULL) { rmBlocks[i].p = mem; rmBlocks[i].tag = tag; return; } } PM_fatalError("To many real mode memory block allocations!");}uint PMAPI _PM_findRealModeBlock(void *mem){ int i; for (i = 0; i < MAX_RM_BLOCKS; i++) { if (rmBlocks[i].p == mem) return rmBlocks[i].tag; } PM_fatalError("Could not find prior real mode memory block allocation!"); return 0;}char * PMAPI PM_getCurrentPath( char *path, int maxLen){ return getcwd(path,maxLen);}char PMAPI PM_getBootDrive(void){ return 'C'; }const char * PMAPI PM_getVBEAFPath(void){ return "c:\\"; }const char * PMAPI PM_getNucleusPath(void){ static char path[256]; char *env; if ((env = getenv("NUCLEUS_PATH")) != NULL) return env; if ((env = getenv("WINBOOTDIR")) != NULL) { /* Running in a Windows 9x DOS box or DOS mode */ strcpy(path,env); strcat(path,"\\system\\nucleus"); return path; } if ((env = getenv("SystemRoot")) != NULL) { /* Running in an NT/2K DOS box */ strcpy(path,env); strcat(path,"\\system32\\nucleus"); return path; } return "c:\\nucleus";}const char * PMAPI PM_getNucleusConfigPath(void){ static char path[256]; strcpy(path,PM_getNucleusPath()); PM_backslash(path); strcat(path,"config"); return path;}const char * PMAPI PM_getUniqueID(void){ return "DOS"; }const char * PMAPI PM_getMachineName(void){ return "DOS"; }int PMAPI PM_kbhit(void){ return kbhit();}int PMAPI PM_getch(void){ return getch();}PM_HWND PMAPI PM_openConsole(PM_HWND hwndUser,int device,int xRes,int yRes,int bpp,ibool fullScreen){ /* Not used for DOS */ (void)hwndUser; (void)device; (void)xRes; (void)yRes; (void)bpp; (void)fullScreen; return 0;}int PMAPI PM_getConsoleStateSize(void){ return sizeof(DOS_stateBuf);}void PMAPI PM_saveConsoleState(void *stateBuf,PM_HWND hwndConsole){ RMREGS regs; DOS_stateBuf *sb = stateBuf; /* Save the old video mode state */ regs.h.ah = 0x0F; PM_int86(0x10,®s,®s); sb->oldMode = regs.h.al & 0x7F; sb->old50Lines = false; if (sb->oldMode == 0x3) { regs.x.ax = 0x1130; regs.x.bx = 0; regs.x.dx = 0; PM_int86(0x10,®s,®s); sb->old50Lines = (regs.h.dl == 42 || regs.h.dl == 49); } (void)hwndConsole;}void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags)){ /* Not used for DOS */ (void)saveState;}void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole){ RMREGS regs; const DOS_stateBuf *sb = stateBuf; /* Retore 50 line mode if set */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -