pm.c

来自「BIOS emulator and interface to Realmode 」· C语言 代码 · 共 873 行 · 第 1/2 页

C
873
字号
{	switch (port) {		case 0:	return 0x3F8;		case 1:	return 0x2F8;		}	return 0;}int PMAPI PM_getLPTPort(int port){	switch (port) {		case 0:	return 0x3BC;		case 1: return 0x378;		case 2:	return 0x278;		}	return 0;}PM_MODULE PMAPI PM_loadLibrary(	const char *szDLLName){	(void)szDLLName;	return NULL;}void * PMAPI PM_getProcAddress(	PM_MODULE hModule,	const char *szProcName){	(void)hModule;	(void)szProcName;	return NULL;}void PMAPI PM_freeLibrary(	PM_MODULE hModule){	(void)hModule;}int PMAPI PM_setIOPL(	int level){	return level;}/*-------------------------------------------------------------------------*//* Generic DPMI routines common to 16/32 bit code						   *//*-------------------------------------------------------------------------*/ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit){	PMREGS  r;	ulong	physOfs;	if (physAddr < 0x100000L) {		/* We can't map memory below 1Mb, but the linear address are already		 * mapped 1:1 for this memory anyway so we just return the base address.		 */		return physAddr;		}	/* Round the physical address to a 4Kb boundary and the limit to a	 * 4Kb-1 boundary before passing the values to DPMI as some extenders	 * will fail the calls unless this is the case. If we round the	 * physical address, then we also add an extra offset into the address	 * that we return.	 */	physOfs = physAddr & 4095;	physAddr = physAddr & ~4095;	limit = ((limit+physOfs+1+4095) & ~4095)-1;	r.x.ax = 0x800;                 /* DPMI map physical to linear      */	r.x.bx = physAddr >> 16;	r.x.cx = physAddr & 0xFFFF;	r.x.si = limit >> 16;	r.x.di = limit & 0xFFFF;	PM_int386(0x31, &r, &r);	if (r.x.cflag)		return 0xFFFFFFFFUL;	return ((ulong)r.x.bx << 16) + r.x.cx + physOfs;}int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr){	PMREGS  r;	r.x.ax = 7;                     /* DPMI set selector base address   */	r.x.bx = sel;	r.x.cx = linAddr >> 16;	r.x.dx = linAddr & 0xFFFF;	PM_int386(0x31, &r, &r);	if (r.x.cflag)		return 0;	return 1;}ulong PMAPI DPMI_getSelectorBase(ushort sel){	PMREGS  r;	r.x.ax = 6;                     /* DPMI get selector base address   */	r.x.bx = sel;	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;	/* 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.regint 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;}void *	PMAPI PM_allocLockedMem(uint size,ulong *physAddr){	/* Not implemented yet */	(void)size;	(void)physAddr;	return NULL;}void PMAPI PM_freeLockedMem(void *p,uint size){	(void)p;	(void)size;}

⌨️ 快捷键说明

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