📄 pm.c
字号:
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 inlimit - Limit of physical memory to region to map inisCached - True if the memory should be cached, false if notRETURNS:Linear address of the newly mapped memory.REMARKS:This function maps physical memory to linear memory, which can then be usedto create a selector or used directly from 32-bit protected mode programs.This is better than DPMI 0x800, since it allows you to maps physicalmemory below 1Mb, which gets this memory out of the way of the Windows VxD'ssticky 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 statebefore 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 valuesloaded 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 valuesloaded 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -