pm.c

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

C
2,244
字号
    ibool locked)
{
#ifndef REALMODE
    VXD_regs        regs;
    pageblock       *block;
    void            *p;
    PM_lockHandle   lh; /* Unused in DOS */

    /* Call the helper VxD for this service if we are running in a DOS box */
    if (VXD_version) {
	memset(&regs,0,sizeof(regs));
	regs.eax = API_NUM(PMHELP_ALLOCPAGE);
	regs.ebx = locked;
	_PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
	return (void*)regs.eax;
	}

    /* Scan the block list looking for any free blocks. Allocate a new
     * page block if no free blocks are found.
     */
    for (block = pageBlocks; block != NULL; block = block->next) {
	if (block->freeCount)
	    break;
	}
    if (block == NULL && (block = PM_addNewPageBlock()) == NULL)
	return NULL;
    block->freeCount--;
    p = block->freeList;
    block->freeList = FREELIST_NEXT(p);
    if (locked)
	PM_lockDataPages(p,PM_PAGE_SIZE,&lh);
    return p;
#else
    return NULL;
#endif
}

/****************************************************************************
REMARKS:
Free a page aligned and page sized block of memory
****************************************************************************/
void PMAPI PM_freePage(
    void *p)
{
#ifndef REALMODE
    VXD_regs    regs;
    pageblock   *block;

    /* Call the helper VxD for this service if we are running in a DOS box */
    if (VXD_version) {
	memset(&regs,0,sizeof(regs));
	regs.eax = API_NUM(PMHELP_FREEPAGE);
	regs.ebx = (ulong)p;
	_PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
	return;
	}

    /* First find the page block that this page belongs to */
    for (block = pageBlocks; block != NULL; block = block->next) {
	if (p >= block->freeListStart && p <= block->freeListEnd)
	    break;
	}
    CHECK(block != NULL);

    /* Now free the block by adding it to the free list */
    FREELIST_NEXT(p) = block->freeList;
    block->freeList = p;
    if (++block->freeCount == PAGES_PER_BLOCK) {
	/* If all pages in the page block are now free, free the entire
	 * page block itself.
	 */
	if (block == pageBlocks) {
	    /* Delete from head */
	    pageBlocks = block->next;
	    if (block->next)
		block->next->prev = NULL;
	    }
	else {
	    /* Delete from middle of list */
	    CHECK(block->prev != NULL);
	    block->prev->next = block->next;
	    if (block->next)
		block->next->prev = block->prev;
	    }
	PM_free(block);
	}
#else
    (void)p;
#endif
}

/*-------------------------------------------------------------------------*/
/* DOS Real Mode support.                                                  */
/*-------------------------------------------------------------------------*/

#ifdef REALMODE

#ifndef MK_FP
#define MK_FP(s,o)  ( (void far *)( ((ulong)(s) << 16) + \
		    (ulong)(o) ))
#endif

void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
{ return MK_FP(r_seg,r_off); }

void * PMAPI PM_getBIOSPointer(void)
{
    return MK_FP(0x40,0);
}

void * PMAPI PM_getA0000Pointer(void)
{
    return MK_FP(0xA000,0);
}

void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
{
    uint sel = base >> 4;
    uint off = base & 0xF;
    limit = limit;
    return MK_FP(sel,off);
}

void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
{ ptr = ptr; }

ulong PMAPI PM_getPhysicalAddr(void *p)
{
    return ((((ulong)p >> 16) << 4) + (ushort)p);
}

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

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

void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
{
    /* Call malloc() to allocate the memory for us */
    void *p = PM_malloc(size);
    *r_seg = FP_SEG(p);
    *r_off = FP_OFF(p);
    return p;
}

void PMAPI PM_freeRealSeg(void *mem)
{
    if (mem) PM_free(mem);
}

int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
{
    return PM_int386(intno,in,out);
}

int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
    RMSREGS *sregs)
{
    return PM_int386x(intno,in,out,sregs);
}

void PMAPI PM_availableMemory(ulong *physical,ulong *total)
{
    PMREGS regs;

    regs.h.ah = 0x48;
    regs.x.bx = 0xFFFF;
    PM_int86(0x21,&regs,&regs);
    *physical = *total = regs.x.bx * 16UL;
}

#endif

/*-------------------------------------------------------------------------*/
/* Phar Lap TNT DOS Extender support.                                      */
/*-------------------------------------------------------------------------*/

#ifdef TNT

#include <pldos32.h>
#include <pharlap.h>
#include <hw386.h>

static uchar *zeroPtr = NULL;

void * PMAPI PM_getBIOSPointer(void)
{
    if (!zeroPtr)
	zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
    return (void*)(zeroPtr + 0x400);
}

void * PMAPI PM_getA0000Pointer(void)
{
    static void *bankPtr;
    if (!bankPtr)
	bankPtr = PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
    return bankPtr;
}

void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
{
    CONFIG_INF  config;
    ULONG       offset;
    int         err;
    ulong       baseAddr,baseOfs,newLimit;
    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;
	}

    /* Round the physical address to a 4Kb boundary and the limit to a
     * 4Kb-1 boundary before passing the values to TNT. If we round the
     * physical address, then we also add an extra offset into the address
     * that we return.
     */
    baseOfs = base & 4095;
    baseAddr = base & ~4095;
    newLimit = ((limit+baseOfs+1+4095) & ~4095)-1;
    _dx_config_inf(&config, (UCHAR*)&config);
    err = _dx_map_phys(config.c_ds_sel,baseAddr,(newLimit + 4095) / 4096,&offset);
    if (err == 130) {
	/* If the TNT function failed, we are running in a DPMI environment
	 * and this function does not work. However we know how to handle
	 * DPMI properly, so we use our generic DPMI functions to do
	 * what the TNT runtime libraries can't.
	 */
	return DPMI_mapPhysicalAddr(base,limit,isCached);
	}
    if (err == 0)
	return (void*)(offset + baseOfs);
    return NULL;
}

void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
{
}

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; }

void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
{
    if (!zeroPtr)
	zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF);
    return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
}

void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
{
    USHORT  addr,t;
    void    *p;

    if (_dx_real_alloc((size + 0xF) >> 4,&addr,&t) != 0)
	return 0;
    *r_seg = addr;                  /* Real mode segment address    */
    *r_off = 0;                     /* Real mode segment offset     */
    p = PM_mapRealPointer(*r_seg,*r_off);
    _PM_addRealModeBlock(p,addr);
    return p;
}

void PMAPI PM_freeRealSeg(void *mem)
{
    if (mem) _dx_real_free(_PM_findRealModeBlock(mem));
}

#define INDPMI(reg)     rmregs.reg = regs->reg
#define OUTDPMI(reg)    regs->reg = rmregs.reg

void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
{
    SWI_REGS    rmregs;

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

    _dx_real_int(intno,&rmregs);

    OUTDPMI(eax); OUTDPMI(ebx); OUTDPMI(ecx); OUTDPMI(edx); OUTDPMI(esi); OUTDPMI(edi);
    regs->flags = rmregs.flags;
}

#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)
{
    SWI_REGS    rmregs;

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

    _dx_real_int(intno,&rmregs);

    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)
{
    SWI_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;

    _dx_real_int(intno,&rmregs);

    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;
}

void PMAPI PM_availableMemory(ulong *physical,ulong *total)
{
    PMREGS  r;
    uint    data[25];

    r.x.ax = 0x2520;                /* Get free memory info */
    r.x.bx = 0;
    r.e.edx = (uint)data;
    PM_int386(0x21, &r, &r);
    *physical = data[21] * 4096;
    *total = data[23] * 4096;
}

#endif

/*-------------------------------------------------------------------------*/
/* Symantec C++ DOSX and FlashTek X-32/X-32VM support                      */
/*-------------------------------------------------------------------------*/

#if defined(DOSX) || defined(X32VM)

#ifdef  X32VM
#include <x32.h>

#define _x386_mk_protected_ptr(p)   _x32_mk_protected_ptr((void*)p)
#define _x386_free_protected_ptr(p) _x32_free_protected_ptr(p)
#define _x386_zero_base_ptr         _x32_zero_base_ptr
#else
extern void *_x386_zero_base_ptr;
#endif

void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
{
    return (void*)((ulong)_x386_zero_base_ptr + MK_PHYS(r_seg,r_off));
}

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

    r.h.ah = 0x48;                  /* DOS function 48h - allocate mem  */
    r.x.bx = (size + 0xF) >> 4;     /* Number of paragraphs to allocate */
    PM_int386(0x21, &r, &r);        /* Call DOS extender                */
    if (r.x.cflag)
	return 0;                   /* Could not allocate the memory    */
    *r_seg = r.e.eax;
    *r_off = 0;
    return PM_mapRealPointer(*r_seg,*r_off);
}

void PMAPI PM_freeRealSeg(void *mem)
{
    /* Cannot de-allocate this memory */
    mem = mem;
}

#pragma pack(1)

typedef struct {
    ushort  intno;
    ushort  ds;
    ushort  es;
    ushort  fs;
    ushort  gs;
    ulong   eax;
    ulong   edx;
    } _RMREGS;

#pragma pack()

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

int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
{
    _RMREGS rmregs;
    PMREGS  regs;
    PMSREGS pmsregs;

    rmregs.intno = intno;
    rmregs.eax = in->e.eax;
    rmregs.edx = in->e.edx;
    IN(ebx); IN(ecx); IN(esi); IN(edi);
    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);
    out->x.dx = rmregs.edx;
    out->x.cflag = regs.x.cflag;
    return out->x.ax;
}

int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs)
{
    _RMREGS rmregs;
    PMREGS  regs;
    PMSREGS pmsregs;

    rmregs.intno = intno;
    rmregs.eax = in->e.eax;
    rmregs.edx = in->e.edx;
    rmregs.es = sregs->es;
    rmregs.ds = sregs->ds;
    IN(ebx); IN(ecx); IN(esi); IN(edi);

⌨️ 快捷键说明

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