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,&regs,&regs,&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,&regs,&regs,&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,&regs,&regs,&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,&regs,&regs);
	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,&regs,&regs);
	    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(&regs,0,sizeof(regs));
	regs.eax = API_NUM(PMHELP_ENABLELFBCOMB);
	regs.ebx = base;
	regs.ecx = size;
	regs.edx = type;
	_PM_VxDCall(&regs,_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, &regs, &regs, &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, &regs, &regs, &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 + -
显示快捷键?