pm.c

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

C
1,188
字号
    PM_int386(0x31, &r, &r);
    return ((ulong)r.x.cx << 16) + r.x.dx;
}

int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit)
{
    PMREGS  r;

    r.x.ax = 8;                     /* DPMI set selector limit          */
    r.x.bx = sel;
    r.x.cx = limit >> 16;
    r.x.dx = limit & 0xFFFF;
    PM_int386(0x31, &r, &r);
    if (r.x.cflag)
	return 0;
    return 1;
}

uint PMAPI DPMI_createSelector(ulong base,ulong limit)
{
    uint    sel;
    PMREGS  r;

    /* Allocate 1 descriptor */
    r.x.ax = 0;
    r.x.cx = 1;
    PM_int386(0x31, &r, &r);
    if (r.x.cflag) return 0;
    sel = r.x.ax;

    /* Set the descriptor access rights (for a 32 bit page granular
     * segment, ring 0).
     */
    r.x.ax = 9;
    r.x.bx = sel;
    r.x.cx = 0x4093;
    PM_int386(0x31, &r, &r);

    /* Map physical memory and create selector */
    if ((base = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFFUL)
	return 0;
    if (!DPMI_setSelectorBase(sel,base))
	return 0;
    if (!DPMI_setSelectorLimit(sel,limit))
	return 0;
    return sel;
}

void PMAPI DPMI_freeSelector(uint sel)
{
    PMREGS  r;

    r.x.ax = 1;
    r.x.bx = sel;
    PM_int386(0x31, &r, &r);
}

int PMAPI DPMI_lockLinearPages(ulong linear,ulong len)
{
    PMREGS  r;

    r.x.ax = 0x600;                     /* DPMI Lock Linear Region      */
    r.x.bx = (linear >> 16);            /* Linear address in BX:CX      */
    r.x.cx = (linear & 0xFFFF);
    r.x.si = (len >> 16);               /* Length in SI:DI              */
    r.x.di = (len & 0xFFFF);
    PM_int386(0x31, &r, &r);
    return (!r.x.cflag);
}

int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len)
{
    PMREGS  r;

    r.x.ax = 0x601;                     /* DPMI Unlock Linear Region    */
    r.x.bx = (linear >> 16);            /* Linear address in BX:CX      */
    r.x.cx = (linear & 0xFFFF);
    r.x.si = (len >> 16);               /* Length in SI:DI              */
    r.x.di = (len & 0xFFFF);
    PM_int386(0x31, &r, &r);
    return (!r.x.cflag);
}

void * PMAPI DPMI_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
{
    PMSREGS sregs;
    ulong   linAddr;
    ulong   DSBaseAddr;

    /* Get the base address for the default DS selector */
    PM_segread(&sregs);
    DSBaseAddr = DPMI_getSelectorBase(sregs.ds);
    if ((base < 0x100000) && (DSBaseAddr == 0)) {
	/* DS is zero based, so we can directly access the first 1Mb of
	 * system memory (like under DOS4GW).
	 */
	return (void*)base;
	}

    /* Map the memory to a linear address using DPMI function 0x800 */
    if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0) {
	if (base >= 0x100000)
	    return NULL;
	/* If the linear address mapping fails but we are trying to
	 * map an area in the first 1Mb of system memory, then we must
	 * be running under a Windows or OS/2 DOS box. Under these
	 * environments we can use the segment wrap around as a fallback
	 * measure, as this does work properly.
	 */
	linAddr = base;
	}

    /* Now expand the default DS selector to 4Gb so we can access it */
    if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL))
	return NULL;

    /* Finally enable caching for the page tables that we just mapped in,
     * since DOS4GW and PMODE/W create the page table entries without
     * caching enabled which hurts the performance of the linear framebuffer
     * as it disables write combining on Pentium Pro and above processors.
     *
     * For those processors cache disabling is better handled through the
     * MTRR registers anyway (we can write combine a region but disable
     * caching) so that MMIO register regions do not screw up.
     */
    if (isCached) {
	if ((PDB = _PM_getPDB()) != 0 && DSBaseAddr == 0) {
	    int     startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
	    ulong   pageTable,*pPageTable;
	    if (!pPDB) {
		if (PDB >= 0x100000)
		    pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF);
		else
		    pPDB = (ulong*)PDB;
		}
	    if (pPDB) {
		startPDB = (linAddr >> 22) & 0x3FF;
		startPage = (linAddr >> 12) & 0x3FF;
		endPDB = ((linAddr+limit) >> 22) & 0x3FF;
		endPage = ((linAddr+limit) >> 12) & 0x3FF;
		for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
		    pageTable = pPDB[iPDB] & ~0xFFF;
		    if (pageTable >= 0x100000)
			pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF);
		    else
			pPageTable = (ulong*)pageTable;
		    start = (iPDB == startPDB) ? startPage : 0;
		    end = (iPDB == endPDB) ? endPage : 0x3FF;
		    for (iPage = start; iPage <= end; iPage++)
			pPageTable[iPage] &= ~0x18;
		    }
		}
	    }
	}

    /* Now return the base address of the memory into the default DS */
    return (void*)(linAddr - DSBaseAddr);
}

/* Some DOS extender implementations do not directly support calling a
 * real mode procedure from protected mode. However we can simulate what
 * we need temporarily hooking the INT 6Ah vector with a small real mode
 * stub that will call our real mode code for us.
 */

static uchar int6AHandler[] = {
    0x00,0x00,0x00,0x00,        /*  __PMODE_callReal variable           */
    0xFB,                       /*  sti                                 */
    0x2E,0xFF,0x1E,0x00,0x00,   /*  call    [cs:__PMODE_callReal]       */
    0xCF,                       /*  iretf                               */
    };
static uchar *crPtr = NULL; /* Pointer to of int 6A handler         */
static uint crRSeg,crROff;  /* Real mode seg:offset of handler      */

void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
    RMSREGS *sregs)
{
    uchar   *p;
    uint    oldSeg,oldOff;

    if (!crPtr) {
	/* Allocate and copy the memory block only once */
	crPtr = PM_allocRealSeg(sizeof(int6AHandler), &crRSeg, &crROff);
	memcpy(crPtr,int6AHandler,sizeof(int6AHandler));
	}
    PM_setWord(crPtr,off);              /* Plug in address to call  */
    PM_setWord(crPtr+2,seg);
    p = PM_mapRealPointer(0,0x6A * 4);
    oldOff = PM_getWord(p);             /* Save old handler address */
    oldSeg = PM_getWord(p+2);
    PM_setWord(p,crROff+4);             /* Hook 6A handler          */
    PM_setWord(p+2,crRSeg);
    PM_int86x(0x6A, in, in, sregs);     /* Call real mode code      */
    PM_setWord(p,oldOff);               /* Restore old handler      */
    PM_setWord(p+2,oldSeg);
}

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)
{ return DPMI_mapPhysicalAddr(base,limit,isCached); }

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

ulong PMAPI PM_getPhysicalAddr(void *p)
{
    /* TODO: This function should find the physical address of a linear */
    /*       address. */
    (void)p;
    return 0xFFFFFFFFUL;
}

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;

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

/* These real mode ints may cause crashes. */
/*AM:   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;

/*AM:   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;
}

/****************************************************************************
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 + -
显示快捷键?