pm.c
来自「适合KS8695X」· C语言 代码 · 共 1,051 行 · 第 1/3 页
C
1,051 行
REMARKS:
Maps a physical memory range to a linear memory range.
****************************************************************************/
ulong MapPhysicalToLinear(
ulong base,
ulong limit,
int *npages)
{
ulong linear,length = limit+1;
int i,ppage,flags;
#if 0
ppage = base >> 12;
*npages = (length + (base & 0xFFF) + 4095) >> 12;
flags = PR_FIXED | PR_STATIC;
if (base == 0xA0000) {
/* We require the linear address to be aligned to a 64Kb boundary
* for mapping the banked framebuffer (so we can do efficient
* carry checking for bank changes in the assembler code). The only
* way to ensure this is to force the linear address to be aligned
* to a 4Mb boundary.
*/
flags |= PR_4MEG;
}
if ((linear = (ulong)PageReserve(PR_SYSTEM,*npages,flags)) == (ulong)-1)
return 0;
if (!PageCommitPhys(linear >> 12,*npages,ppage,PC_INCR | PC_USER | PC_WRITEABLE))
return 0;
#endif
return linear + (base & 0xFFF);
}
/****************************************************************************
PARAMETERS:
base - Physical base address of the memory to map in
limit - Limit of physical memory to region to map in
isCached - True if the memory should be cached, false if not
RETURNS:
Linear address of the newly mapped memory.
REMARKS:
This function maps physical memory to linear memory, which can then be used
to create a selector or used directly from 32-bit protected mode programs.
This is better than DPMI 0x800, since it allows you to maps physical
memory below 1Mb, which gets this memory out of the way of the Windows VxD's
sticky paws.
NOTE: If the memory is not expected to be cached, this function will
directly re-program the PCD (Page Cache Disable) bit in the
page tables. There does not appear to be a mechanism in the VMM
to control this bit via the regular interface.
****************************************************************************/
void * PMAPI PM_mapPhysicalAddr(
ulong base,
ulong limit,
ibool isCached)
{
ulong linear,length = limit+1;
int i,npages;
ulong PDB,*pPDB;
/* Search table of existing mappings to see if we have already mapped
* a region of memory that will serve this purpose.
*/
for (i = 0; i < numMappings; i++) {
if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached)
return (void*)maps[i].linear;
}
if (numMappings == MAX_MEMORY_MAPPINGS)
return NULL;
/* We did not find any previously mapped memory region, so map it in.
* Note that we do not use MapPhysToLinear, since this function appears
* to have problems mapping memory in the 1Mb physical address space.
* Hence we use PageReserve and PageCommitPhys.
*/
if ((linear = MapPhysicalToLinear(base,limit,&npages)) == 0)
return NULL;
maps[numMappings].physical = base;
maps[numMappings].length = length;
maps[numMappings].linear = linear;
maps[numMappings].npages = npages;
maps[numMappings].isCached = isCached;
numMappings++;
#if 0
/* Finally disable caching where necessary */
if (!isCached && (PDB = _PM_getPDB()) != 0) {
int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
ulong pageTable,*pPageTable;
if (PDB >= 0x100000)
pPDB = (ulong*)MapPhysicalToLinear(PDB,0xFFF,&npages);
else
pPDB = (ulong*)PDB;
if (pPDB) {
startPDB = (linear >> 22) & 0x3FF;
startPage = (linear >> 12) & 0x3FF;
endPDB = ((linear+limit) >> 22) & 0x3FF;
endPage = ((linear+limit) >> 12) & 0x3FF;
for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
pageTable = pPDB[iPDB] & ~0xFFF;
if (pageTable >= 0x100000)
pPageTable = (ulong*)MapPhysicalToLinear(pageTable,0xFFF,&npages);
else
pPageTable = (ulong*)pageTable;
start = (iPDB == startPDB) ? startPage : 0;
end = (iPDB == endPDB) ? endPage : 0x3FF;
for (iPage = start; iPage <= end; iPage++)
pPageTable[iPage] |= 0x10;
PageFree((ulong)pPageTable,PR_STATIC);
}
PageFree((ulong)pPDB,PR_STATIC);
}
}
#endif
return (void*)linear;
}
void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
{
/* We never free the mappings */
}
void PMAPI PM_sleep(ulong milliseconds)
{
/* We never sleep in a VDD */
}
int PMAPI PM_getCOMPort(int port)
{
/* TODO: Re-code this to determine real values using the Plug and Play */
/* manager for the OS. */
switch (port) {
case 0: return 0x3F8;
case 1: return 0x2F8;
}
return 0;
}
int PMAPI PM_getLPTPort(int port)
{
/* TODO: Re-code this to determine real values using the Plug and Play */
/* manager for the OS. */
switch (port) {
case 0: return 0x3BC;
case 1: return 0x378;
case 2: return 0x278;
}
return 0;
}
ulong PMAPI PM_getPhysicalAddr(void *p)
{
/* TODO: This function should find the physical address of a linear */
/* address. */
return 0xFFFFFFFFUL;
}
void PMAPI _PM_freeMemoryMappings(void)
{
int i;
/* for (i = 0; i < numMappings; i++) */
/* PageFree(maps[i].linear,PR_STATIC); */
}
void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
{ return (void*)MK_PHYS(r_seg,r_off); }
void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
{ return NULL; }
void PMAPI PM_freeRealSeg(void *mem)
{ }
void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
{
/* Unsed in VDDs */
}
/****************************************************************************
REMARKS:
Load the V86 registers in the client state, and save the original state
before loading the registers.
****************************************************************************/
static void LoadV86Registers(
PCRF saveRegs,
RMREGS *in,
RMSREGS *sregs)
{
PCRF pcrf; /* current client register frame */
/* get pointer to registers */
pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);
/* Note: We could do VDHPushRegs instead but this should be safer as it */
/* doesn't rely on the VDM session having enough free stack space. */
*saveRegs = *pcrf; /* save all registers */
pcrf->crf_eax = in->e.eax; /* load new values */
pcrf->crf_ebx = in->e.ebx;
pcrf->crf_ecx = in->e.ecx;
pcrf->crf_edx = in->e.edx;
pcrf->crf_esi = in->e.esi;
pcrf->crf_edi = in->e.edi;
pcrf->crf_es = sregs->es;
pcrf->crf_ds = sregs->ds;
}
/****************************************************************************
REMARKS:
Read the V86 registers from the client state and restore the original state.
****************************************************************************/
static void ReadV86Registers(
PCRF saveRegs,
RMREGS *out,
RMSREGS *sregs)
{
PCRF pcrf; /* current client register frame */
/* get pointer to registers */
pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);
/* read new register values */
out->e.eax = pcrf->crf_eax;
out->e.ebx = pcrf->crf_ebx;
out->e.ecx = pcrf->crf_ecx;
out->e.edx = pcrf->crf_edx;
out->e.esi = pcrf->crf_esi;
out->e.edi = pcrf->crf_edi;
sregs->es = pcrf->crf_es;
sregs->ds = pcrf->crf_ds;
/* restore original client registers */
*pcrf = *saveRegs;
}
/****************************************************************************
REMARKS: Used for far calls into V86 code
****************************************************************************/
VOID HOOKENTRY UserReturnHook(
PVOID pRefData,
PCRF pcrf )
{
VDHPostEventSem(hevFarCallRet);
}
/****************************************************************************
REMARKS: Used for calling BIOS interrupts
****************************************************************************/
VOID HOOKENTRY UserIRetHook(
PVOID pRefData,
PCRF pcrf )
{
VDHPostEventSem(hevIRet);
}
/****************************************************************************
REMARKS:
Call a V86 real mode function with the specified register values
loaded before the call. The call returns with a far ret.
Must be called from within a DOS session context!
****************************************************************************/
void PMAPI PM_callRealMode(
uint seg,
uint off,
RMREGS *regs,
RMSREGS *sregs)
{
CRF saveRegs;
FPFN fnAddress;
ULONG rc;
TRACE("SDDHELP: Entering PM_callRealMode()\n");
LoadV86Registers(SSToDS(&saveRegs),regs,sregs);
/* set up return hook for call */
rc = VDHArmReturnHook(hhookUserReturnHook, VDHARH_CSEIP_HOOK);
VDHResetEventSem(hevFarCallRet);
/* the address is a 16:32 pointer */
OFFSETOF32(fnAddress) = off;
SEGMENTOF32(fnAddress) = seg;
rc = VDHPushFarCall(fnAddress);
VDHYield(0);
/* wait until the V86 call returns - our return hook posts the semaphore */
rc = VDHWaitEventSem(hevFarCallRet, SEM_INDEFINITE_WAIT);
ReadV86Registers(SSToDS(&saveRegs),regs,sregs);
TRACE("SDDHELP: Exiting PM_callRealMode()\n");
}
/****************************************************************************
REMARKS:
Issue a V86 real mode interrupt with the specified register values
loaded before the interrupt.
Must be called from within a DOS session context!
****************************************************************************/
int PMAPI PM_int86(
int intno,
RMREGS *in,
RMREGS *out)
{
RMSREGS sregs = {0};
CRF saveRegs;
ushort oldDisable;
ULONG rc;
memset(SSToDS(&sregs), 0, sizeof(sregs));
#if 0 /* do we need this?? */
/* Disable pass-up to our VDD handler so we directly call BIOS */
TRACE("SDDHELP: Entering PM_int86()\n");
if (disableTSRFlag) {
oldDisable = *disableTSRFlag;
*disableTSRFlag = 0;
}
#endif
LoadV86Registers(SSToDS(&saveRegs), in, SSToDS(&sregs));
VDHResetEventSem(hevIRet);
rc = VDHPushInt(intno);
/* set up return hook for interrupt */
rc = VDHArmReturnHook(hhookUserIRetHook, VDHARH_NORMAL_IRET);
VDHYield(0);
/* wait until the V86 IRETs - our return hook posts the semaphore */
rc = VDHWaitEventSem(hevIRet, 5000); /*SEM_INDEFINITE_WAIT); */
ReadV86Registers(SSToDS(&saveRegs), out, SSToDS(&sregs));
#if 0
/* Re-enable pass-up to our VDD handler if previously enabled */
if (disableTSRFlag)
*disableTSRFlag = oldDisable;
#endif
TRACE("SDDHELP: Exiting PM_int86()\n");
return out->x.ax;
}
/****************************************************************************
REMARKS:
Issue a V86 real mode interrupt with the specified register values
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?