pm.c
来自「适合KS8695X」· C语言 代码 · 共 2,244 行 · 第 1/5 页
C
2,244 行
/****************************************************************************
*
* 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 10
static 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 DOS4GW
static ulong PDB = 0,*pPDB = NULL;
#endif
#ifndef REALMODE
static 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 100
typedef 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 number
RETURNS:
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.VXD
helper VxD, and check that it is a version we can use. If not we try to
dynamically 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 region
size - The size in bytes of the region
type - Type to place into the MTRR register
RETURNS:
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!");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?