/* This file is DPMIUTIL.C ** Copyright (c) Rainer Schnitker 10/91 */ /* This file need Turbo C to compile, ** but there are only TurboC specials like asm { statement } ** Function used : allocmem(),MK_FP(),FP_SEG(),FP_OFF() ** Compile options : -ms (because of other segments in protected mode) ** -2 (protected mode) ** -B (Assembler lines) */ #include "DPMI.H" #include #include #include /* CPU switching for DPMI 0.9 */ void real_to_protected() { unsigned int speicherseg; WORD rax,seg,off,hostreq; DWORD PM_jump ; int status; asm { mov ax,1687h /* DMPI supported ? */ int 2fh mov rax,ax mov off,di mov seg,es mov hostreq,si } if (rax){ printf("no dpmi supported\n"); exit(1); } PM_jump = (long)seg ; PM_jump <<= 16 ; PM_jump += (long)off ; status=allocmem(hostreq,&speicherseg); /* for DPMI-Stack */ if (status!=-1) { /* reserve */ printf("allocmem() error\n"); exit(1); } asm { mov es,speicherseg ; mov ax,0 ; call DWORD PTR PM_jump ; jnc PMOK ; } printf("Can't switch to Protected Mode!"); exit(1); PMOK: printf("CPU in Protected Mode\n"); printf("CS=%X DS=%X ES=%X SS=%X\n",_CS,_DS,_ES,_SS); _BL=0x23 ; /* Control Break -> protected_to_real() */ _CX=_CS ; asm mov dx,OFFSET MYINT ; DPMI(0x0205); } void protected_to_real() { printf("CPU in Real Mode\n"); asm MYINT LABEL byte ; asm { mov ax,4C00h int 21h } /* program ends here */ } /* LDT Descriptor management services DPMI 0.9 */ WORD AllocLDT(WORD anzahl) { _CX=anzahl; DPMI(0x0000); asm jnc OKallocldt ; return 0; OKallocldt: return _AX; } int FreeLDT(WORD sel) { _BX=sel; DPMI(0x0001); asm jnc OKfreeldt; return -1; OKfreeldt: return 0; } WORD SegtoSel(WORD seg) { _BX=seg; DPMI(0x0002); asm jnc OKsegsel; return 0; OKsegsel: return _AX; } WORD SelInc() { DPMI(0x0003); return _AX ; } int LockSel(WORD sel) { _BX=sel ; DPMI(0x0004); asm jnc OKlocksel; return -1; OKlocksel: return 0; } int UnlockSel(WORD sel) { _BX=sel ; DPMI(0x0005); asm jnc OKunlocksel; return -1; OKunlocksel: return 0; } DWORD GetBaseAddress(WORD sel) { _BX=sel; DPMI(0x0006); asm jnc OKgetbase; return 0; OKgetbase: return ( (DWORD)_DX | ( (DWORD)_CX <<16 ) ); } int SetBaseAddress(WORD sel,DWORD address) { _CX=(WORD) (address>>16); _DX=(WORD) address ; _BX=sel; DPMI(0x0007); asm jnc OKsetbase; return -1; OKsetbase: return 0; } int SetLimit(WORD sel,DWORD limit) { _BX=sel; _CX=(WORD) (limit>>16) ; _DX=(WORD) limit ; DPMI(0x0008); asm jnc OKsetlimit; return -1; OKsetlimit: return 0; } int SetAccess(WORD sel,BYTE access,BYTE extaccess) { _BX=sel; _CL=access; _CH=extaccess; DPMI(0x0009); asm jnc OKsetaccess; return -1; OKsetaccess: return 0; } WORD CreatAlias(WORD segsel) { _BX=segsel; DPMI(0x000a); asm jnc OKcreatalias; return 0; OKcreatalias: return _AX ; } int GetDescriptor(WORD sel,DESCRIPTOR *d) { asm push es ; _BX=sel; _ES=FP_SEG(d); _DI=FP_OFF(d); DPMI(0x000b); asm pop es ; asm jnc OKgetdisc ; return -1; OKgetdisc: return 0; } int SetDescriptor(WORD sel,DESCRIPTOR *d) { asm push es ; _BX=sel; _ES=FP_SEG(d); _DI=FP_OFF(d); DPMI(0x000c); asm pop es ; asm jnc OKsetdisc ; return -1; OKsetdisc: return 0; } int AllocSpecialLDT(WORD sel) { _BX=sel; DPMI(0x000d); asm jnc OKspecial; return -1 ; OKspecial: return 0 ; } /* Interrupt Services DPMI 0.9 */ int GetExceptionVector(BYTE b,WORD *sel,WORD *off) { _BL=b; DPMI(0x0202); asm jnc OKgetexeption; return -1; OKgetexeption: *sel=_CX; *off=_DX; return 0; } int SetExceptionVector(BYTE b,WORD sel,WORD off) { _BL=b; _CX= sel; _DX= off; DPMI(0x0203); asm jnc OKsetexeption; return -1; OKsetexeption: return 0; } int GetPMinterruptVector(BYTE b,WORD *sel,WORD *off) { _BL=b; DPMI(0x0204); asm jnc OKgetpmiv; return -1; OKgetpmiv: *sel=_CX; *off=_DX; return 0; } int SetPMinterruptVector(BYTE b,WORD sel,WORD off) { _BL=b; _CX= sel; _DX= off; DPMI(0x0205); asm jnc OKsetpmiv; return -1; OKsetpmiv: return 0; } /* Memory managment services DPMI 0.9 */ void getfreeinfo(FREEMEMINFO *fm) { asm push es ; _ES=FP_SEG(fm) ; _DI=FP_OFF(fm) ; DPMI(0x500); asm pop es ; } void printfreeinfo(FREEMEMINFO *fm) { printf("Largest available block : %lu Byte \n",fm->i1); printf("Number free pages : %3lu = %4lu KB\n",fm->i2,fm->i2*4); printf("Number free pages to lock : %3lu = %4lu KB\n",fm->i3,fm->i3*4); printf("Number pages of linear addr space : %3lu = %4lu KB\n",fm->i4,fm->i4*4); printf("Number pages not locked : %3lu = %4lu KB\n",fm->i5,fm->i5*4); printf("Number pages not used : %3lu = %4lu KB\n",fm->i6,fm->i6*4); printf("Number pages managed by the Dpmi : %3lu = %4lu KB\n",fm->i7,fm->i7*4); printf("Number pages free addr space : %3lu = %4lu KB\n",fm->i8,fm->i8*4); printf("Number pages in swapfile : %3lu = %4lu KB\n",fm->i9,fm->i9*4); } DWORD GlobalAlloc(DWORD bytes,DWORD *memhandle) { _BX=(WORD) (bytes>>16); _CX=(WORD) bytes ; DPMI(0x501); asm jnc OKalloc; return 0 ; OKalloc: *memhandle = (DWORD)_CX | ( (DWORD)_BX <<16 ) ; return ( (DWORD)_DI | ( (DWORD)_SI <<16 ) ); } int GlobalFree(DWORD handle) { _SI=(WORD) (handle>>16); _DI=(WORD) handle ; DPMI(0x0502); asm jnc OKFREE ; return -1 ; OKFREE: return 0 ; } /* Page locking services DPMI 0.9 */ int LockLinRegion(DWORD size,DWORD address) { _BX=(WORD) (address>>16); _CX=(WORD) address; _SI=(WORD) (size>>16); _DI=(WORD) size; DPMI(0x0600); asm jnc oklocklin; return -1; oklocklin: return 0; } int UnlockLinRegion(DWORD size,DWORD address) { _BX=(WORD) (address>>16); _CX=(WORD) address; _SI=(WORD) (size>>16); _DI=(WORD) size; DPMI(0x0600); asm jnc okunlocklin; return -1; okunlocklin: return 0; } /* Other multiplex int 2F */ void Yield() /* give control to operating system (like GetMassage) */ { _AX=0x1680 ; asm int 2Fh ; } /* Protected mode API */ DWORD lsl(WORD sel) /* load selector limit */ { asm { db 66h; sub ax,ax; /* sub eax,eax */ db 66h; mov bx,ax; /* mov ebx,eax */ mov bx,sel db 66h; lsl ax,bx; /* lsl eax,ebx */ db 66h; mov dx,ax ; /* mov eax,eax ax:low word */ db 66h ; shr dx,16 /* shr edx,16 dx:high word */ } } WORD lsl16(WORD sel) /* 16-bit version of lsl for 80286 */ { asm sub ax,ax asm lsl ax,sel return _AX ; } WORD lar(WORD sel) /* load access rights */ { asm sub ax,ax ; asm lar ax,sel; asm shr ax,8 ; return _AX ; } WORD verr(WORD sel) /* verify read */ { asm mov ax,1 ; asm verr sel ; asm je okr ; asm dec ax ; okr: return _AX ; } WORD verw(WORD sel) /* verify write */ { asm mov ax,1 ; asm verw sel ; asm je okw ; asm dec ax ; okw: return _AX ; } void sgdt(GDTR *g) /* save gdt table */ { asm mov si,g ; asm sgdt [si] ; } void sidt(GDTR *g) /* save idt table */ { asm mov si,g ; asm sidt [si] ; } WORD sldt(void) /* save ldt-selector */ { asm sldt ax ; return _AX ; } WORD str(void) /* save task-register */ { asm str ax ; return _AX ; } /* Protected mode utilities */ void far * incfp(void far *a) /* get next selector */ { FP_SEG(a)+=SelInc(); return(a); } void far * decfp(void far *a) /* get previous selector */ { FP_SEG(a)-=SelInc(); return(a); } void printdescriptor(DESCRIPTOR d) { printf("b=%02X%02X%04X lim=%01X%04X p=%u dpl=%u %s t4=%X t=%u %s %s\n", d.base_hi,d.base_mi,d.base_lo, d.lim_hi&15,d.lim_lo, (d.access&128)>>7, (d.access&96)>>5, (d.access&16) ? "MEMseg" : "SYSseg", (d.access&15), (d.access&7), (d.lim_hi & 64) ? "32bit" : "16bit" , (d.lim_hi & 128) ? "paging": " " ); } void farcopy(void far *dest,void far *source,DWORD bytes) { unsigned long i ; bytes++; /* if bytes %2 = 1 */ bytes>>=1; poke( FP_SEG(dest),FP_OFF(dest),peek(FP_SEG(source),FP_OFF(source)) ); for (i=1; i< bytes ; i++) { FP_OFF(dest)+=2 ; if (FP_OFF(dest)==0) dest=incfp(dest); FP_OFF(source)+=2 ; if (FP_OFF(source)==0) source=incfp(source); poke( FP_SEG(dest),FP_OFF(dest),peek(FP_SEG(source),FP_OFF(source)) ); } } /* high level C-function using DPMI-API */ /* malloc,free */ #define PAGESIZE 4096 #define PAGEBUCKET 11 #define NBUCKETS 30 #define MAGIC 0xFFF0 union overhead { struct { WORD page; WORD offset; } free ; struct { WORD magic ; WORD index ; } use ; } ; static union overhead nextf[NBUCKETS]; void far * morepages(WORD bucket) { WORD nblks,i,page,nsel,nextpage; DWORD sz,handle,memaddress; sz = ((DWORD)1) << (bucket + 2) ; if (sz second block */ nextf[bucket].free.offset=sz; for (i=1;i< (nblks);i++) /* fill header of blocks */ { poke(page,i*sz,page); poke(page,i*sz +2,(i+1)*sz); } poke(page,nblks*sz,0); /* last block -> NULL */ poke(page,nblks*sz+2,0); } else { /* 2.nd case : one selectors per 64 KB */ if ((handle=GlobalAlloc(sz,&memaddress))==0) return NULL ; nsel=(WORD) ((sz-1)>>16); /* nsel = number of selectors */ nsel++; if ((page=AllocLDT(nsel))==0) { /* no more selectors? */ GlobalFree(handle) ; /* free memory */ return NULL; } if (sz>0x10000L) sz=0x10000L ; /* divide in 64KB */ nextpage=page; for (i=1;i<=nsel;i++) { if (SetBaseAddress(nextpage,memaddress)==-1) printf("error set Base\n"); if (SetLimit(nextpage,sz-1)==-1) printf("error set Limit\n"); memaddress+=0x10000L ; nextpage+=SelInc(); /* get next selector number */ } } return (MK_FP(page,0)) ; } void far *extmalloc(DWORD nbytes) { WORD bucket, n=0 ; DWORD amt ; union overhead far *fp; if (nbytes == 0 ) return NULL; nbytes+= sizeof(union overhead) ; if (nbytes <= PAGESIZE ) { /* nbytes <= PAGE */ amt = 4; /* bucket = 1..12 */ bucket = 0; n = 0 ; } else { /* nbytes > PAGE */ amt = PAGESIZE; /* bucket = 13..30 */ bucket = PAGEBUCKET; n=PAGESIZE; } while (nbytes > amt + n) { amt <<= 1; if (amt == 0) return NULL; bucket++; } if (nextf[bucket].free.page == 0) { /* no mem in list */ fp=(union overhead far *)morepages(bucket); if ((fp) == NULL) /* no mem from dpmi */ return NULL; } else { /* mem available in list */ /* now : nextf[] -> myblock -> nextp */ /* fp -> myblock */ fp=(union overhead far *)MK_FP(nextf[bucket].free.page,nextf[bucket].free.offset); /* nextf[] -> nextp */ nextf[bucket].free.page =fp->free.page; nextf[bucket].free.offset=fp->free.offset; } fp->use.magic= MAGIC ; fp->use.index= bucket; return ((void far *)(fp+1)); } void extfree(void far *p) { union overhead far *fp ; WORD bucket ; fp=(union overhead far *)p - 1; /* get header */ if (fp->use.magic!= MAGIC) return ; /* bad pointer */ bucket = fp->use.index ; /* get size of pointer */ /* nextf[] -> nextp */ /* wanted : nextf[] -> fp -> nextf */ fp->free.page=nextf[bucket].free.page; fp->free.offset=nextf[bucket].free.offset; nextf[bucket].free.page = FP_SEG(fp); nextf[bucket].free.offset=FP_OFF(fp); }