pm.c

来自「适合KS8695X」· C语言 代码 · 共 2,244 行 · 第 1/5 页

C
2,244
字号
    regs.x.ax = 0x2511;
    regs.e.edx = (uint)(&rmregs);
    PM_segread(&pmsregs);
    PM_int386x(0x21,&regs,&regs,&pmsregs);

    OUT(eax); OUT(ebx); OUT(ecx); OUT(esi); OUT(edi);
    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_getBIOSPointer(void)
{
    return (void*)((ulong)_x386_zero_base_ptr + 0x400);
}

void * PMAPI PM_getA0000Pointer(void)
{
    return (void*)((ulong)_x386_zero_base_ptr + 0xA0000);
}

void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
{
    VXD_regs    regs;

    /* If we have connected to our helper VxD in a Windows DOS box, use
     * the helper VxD services to map memory instead of the DPMI services.
     * We do this because the helper VxD can properly disable caching
     * where necessary, which we can only do directly here if we are
     * running at ring 0 (ie: under real DOS).
     */
    if (VXD_version == -1)
	PM_init();
    if (VXD_version) {
	memset(&regs,0,sizeof(regs));
	regs.eax = API_NUM(PMHELP_MAPPHYS);
	regs.ebx = base;
	regs.ecx = limit;
	regs.edx = isCached;
	_PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
	return (void*)regs.eax;
	}

    if (base > 0x100000)
	return _x386_map_physical_address((void*)base,limit);
    return (void*)((ulong)_x386_zero_base_ptr + base);
}

void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
{
    /* Mapping cannot be freed */
}

ulong PMAPI PM_getPhysicalAddr(void *p)
{ return 0xFFFFFFFFUL; }

ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
{ return false; }

void * PMAPI PM_mapToProcess(void *base,ulong limit)
{ return (void*)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,&regs,&regs);
    *total = regs.e.eax;

    /* Get physical memory available */
    *physical = _X32_getPhysMem();
    if (*physical > *total)
	*physical = *total;
}

#endif

/*-------------------------------------------------------------------------*/
/* Borland's DPMI32, Watcom DOS4GW and DJGPP DPMI support routines         */
/*-------------------------------------------------------------------------*/

#if defined(DPMI32) || defined(DOS4GW) || defined(DJGPP)

void * PMAPI PM_getBIOSPointer(void)
{
    return PM_mapPhysicalAddr(0x400,0xFFFF,true);
}

void * PMAPI PM_getA0000Pointer(void)
{
    return PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
}

void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
{
    VXD_regs    regs;

#ifdef  DJGPP
    /* Enable near pointers for DJGPP V2 */
    __djgpp_nearptr_enable();
#endif
    /* If we have connected to our helper VxD in a Windows DOS box, use
     * the helper VxD services to map memory instead of the DPMI services.
     * We do this because the helper VxD can properly disable caching
     * where necessary, which we can only do directly here if we are
     * running at ring 0 (ie: under real DOS).
     */
    if (VXD_version == -1)
	PM_init();
    if (VXD_version) {
	memset(&regs,0,sizeof(regs));
	regs.eax = API_NUM(PMHELP_MAPPHYS);
	regs.ebx = base;
	regs.ecx = limit;
	regs.edx = isCached;
	_PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
	return (void*)regs.eax;
	}
    return DPMI_mapPhysicalAddr(base,limit,isCached);
}

void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
{
    /* Mapping cannot be freed */
    (void)ptr;
    (void)limit;
}

ulong PMAPI PM_getPhysicalAddr(void *p)
{
    ulong   physAddr;
    if (!PM_getPhysicalAddrRange(p,1,&physAddr))
	return 0xFFFFFFFF;
    return physAddr | ((ulong)p & 0xFFF);
}

ibool PMAPI PM_getPhysicalAddrRange(
    void *p,
    ulong length,
    ulong *physAddress)
{
    VXD_regs    regs;
    ulong       pte;
    PMSREGS     sregs;
    ulong       DSBaseAddr;

    /* If we have connected to our helper VxD in a Windows DOS box, use the
     * helper VxD services to find the physical address of an address.
     */
    if (VXD_version) {
	memset(&regs,0,sizeof(regs));
	regs.eax = API_NUM(PMHELP_GETPHYSICALADDRRANGE);
	regs.ebx = (ulong)p;
	regs.ecx = (ulong)length;
	regs.edx = (ulong)physAddress;
	_PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
	return regs.eax;
	}

    /* Find base address for default DS selector */
    PM_segread(&sregs);
    DSBaseAddr = DPMI_getSelectorBase(sregs.ds);

    /* Otherwise directly access the page tables to determine the
     * physical memory address. Note that we touch the memory before
     * calling, otherwise the memory may not be paged in correctly.
     */
    pte = *((ulong*)p);
#ifdef  DOS4GW
    if (_PM_pagingEnabled() == 0) {
	int     count;
	ulong   linAddr = (ulong)p;

	/* When paging is disabled physical=linear */
	for (count = (length+0xFFF) >> 12; count > 0; count--) {
	    *physAddress++ = linAddr;
	    linAddr += 4096;
	    }
	return true;
	}
    else if ((PDB = _PM_getPDB()) != 0 && DSBaseAddr == 0) {
	int     startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
	ulong   pageTable,*pPageTable,linAddr = (ulong)p;
	ulong   limit = length-1;

	pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF);
	if (pPDB) {
	    startPDB = (linAddr >> 22) & 0x3FFL;
	    startPage = (linAddr >> 12) & 0x3FFL;
	    endPDB = ((linAddr+limit) >> 22) & 0x3FFL;
	    endPage = ((linAddr+limit) >> 12) & 0x3FFL;
	    for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
		pageTable = pPDB[iPDB] & ~0xFFFL;
		pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF);
		start = (iPDB == startPDB) ? startPage : 0;
		end = (iPDB == endPDB) ? endPage : 0x3FFL;
		for (iPage = start; iPage <= end; iPage++)
		    *physAddress++ = (pPageTable[iPage] & ~0xFFF);
		}
	    return true;
	    }
	}
#endif
    return false;
}

void * PMAPI PM_mapToProcess(void *base,ulong limit)
{
    (void)limit;
    return (void*)base;
}

void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
{
    static uchar *zeroPtr = NULL;

    if (!zeroPtr)
	zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
    return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
}

void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
{
    PMREGS      r;
    void        *p;

    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                 */
    *r_seg = r.x.ax;                /* Real mode segment                */
    *r_off = 0;
    p = PM_mapRealPointer(*r_seg,*r_off);
    _PM_addRealModeBlock(p,r.x.dx);
    return p;
}

void PMAPI PM_freeRealSeg(void *mem)
{
    PMREGS  r;

    if (mem) {
	r.x.ax = 0x101;                     /* DPMI free DOS memory         */
	r.x.dx = _PM_findRealModeBlock(mem);/* DX := selector from 0x100    */
	PM_int386(0x31, &r, &r);
	}
}

static DPMI_handler_t   DPMI_int10 = NULL;

void PMAPI DPMI_setInt10Handler(DPMI_handler_t handler)
{
    DPMI_int10 = handler;
}

void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
{
    PMREGS      r;
    PMSREGS     sr;

    if (intno == 0x10 && DPMI_int10) {
	if (DPMI_int10(regs))
	    return;
	}
    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)regs;
    PM_int386x(0x31, &r, &r, &sr);  /* Issue the interrupt          */
}

#define IN(reg)     rmregs.reg = in->e.reg
#define OUT(reg)    out->e.reg = rmregs.reg

int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
{
    DPMI_regs   rmregs;

    memset(&rmregs, 0, sizeof(rmregs));
    IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);

    DPMI_int86(intno,&rmregs);      /* DPMI issue real interrupt    */

    OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
    out->x.cflag = rmregs.flags & 0x1;
    return out->x.ax;
}

int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
    RMSREGS *sregs)
{
    DPMI_regs   rmregs;

    memset(&rmregs, 0, sizeof(rmregs));
    IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
    rmregs.es = sregs->es;
    rmregs.ds = sregs->ds;

    DPMI_int86(intno,&rmregs);      /* DPMI issue real interrupt    */

    OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
    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;
}

#pragma pack(1)

typedef struct {
	uint    LargestBlockAvail;
	uint    MaxUnlockedPage;
	uint    LargestLockablePage;
	uint    LinAddrSpace;
	uint    NumFreePagesAvail;
	uint    NumPhysicalPagesFree;
	uint    TotalPhysicalPages;
	uint    FreeLinAddrSpace;
	uint    SizeOfPageFile;
	uint    res[3];
	} MemInfo;

#pragma pack()

void PMAPI PM_availableMemory(ulong *physical,ulong *total)
{
    PMREGS  r;
    PMSREGS sr;
    MemInfo 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

#ifndef __16BIT__

/****************************************************************************
REMARKS:
Call the VBE/Core software interrupt to change display banks.
****************************************************************************/
void PMAPI PM_setBankA(
    int bank)
{
    DPMI_regs   regs;
    memset(&regs, 0, sizeof(regs));
    regs.eax = 0x4F05;
    regs.ebx = 0x0000;
    regs.edx = bank;
    DPMI_int86(0x10,&regs);
}

/****************************************************************************
REMARKS:
Call the VBE/Core software interrupt to change display banks.
****************************************************************************/
void PMAPI PM_setBankAB(
    int bank)
{
    DPMI_regs   regs;
    memset(&regs, 0, sizeof(regs));
    regs.eax = 0x4F05;
    regs.ebx = 0x0000;
    regs.edx = bank;
    DPMI_int86(0x10,&regs);
    regs.eax = 0x4F05;
    regs.ebx = 0x0001;
    regs.edx = bank;
    DPMI_int86(0x10,&regs);
}

/****************************************************************************
REMARKS:
Call the VBE/Core software interrupt to change display start address.
****************************************************************************/
void PMAPI PM_setCRTStart(
    int x,
    int y,
    int waitVRT)
{
    DPMI_regs   regs;
    memset(&regs, 0, sizeof(regs));
    regs.eax = 0x4F07;
    regs.ebx = waitVRT;
    regs.ecx = x;
    regs.edx = y;
    DPMI_int86(0x10,&regs);
}

#endif

/****************************************************************************
REMARKS:
Function to get the file attributes for a specific file.
****************************************************************************/
uint PMAPI PM_getFileAttr(
    const char *filename)
{
    /* TODO: Implement this! */
    return 0;
}

/****************************************************************************
REMARKS:
Function to get the file time and date for a specific file.
****************************************************************************/
ibool PMAPI PM_getFileTime(
    const char *filename,
    ibool gmTime,
    PM_time *time)
{
    /* TODO: Implement this! */
    return false;
}

/****************************************************************************
REMARKS:
Function to set the file time and date for a specific file.
****************************************************************************/
ibool PMAPI PM_setFileTime(
    const char *filename,
    ibool gmTime,
    PM_time *time)
{
    /* TODO: Implement this! */
    return false;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?