// Author: Chris Somers AJR: This file contains 3 .h files and two .c files, and some notes all glued together. you'll have to cut them apart to compile. // Author: Chris Somers To use memory.c, a few notes are in order. This file was originally used in an event-driven windowing environment, so there are several headers you won't need (so I didn't include 'em). AJR - I nuked all uneeded references from the code This code was written for Borland C/C++ v3.1 and has _not_ been tested under any other version. The first set of conventional memory calls (those flanked by #ifndef USEBORLIB) are to replace Borland's malloc library when using 3rd party libraries or APIs which called DOS's malloc. Add a -DUSEBORLIB to the compile command line to remove this code. The file, tasks.h (application specific - not included), optionally #define'd EMM_SUPPORT and TCPCOM. #define the first and not the second. AJR - I modified these sources so this isn't neccessary - all references to TCPCOM have been deleted. Add memory.p to your application to have access to the EMM calls. Don't include memory.h - it's got static calls and variables you don't want direct access to. AJR - I added memory.p to memory.c, and cleaned up memory.h so it can be included. Please see emm.c for an example. returns.h and sizes.h just have the #defines for (duh!) return codes and size constants. Unfortunately, the values used for some of the return codes may not be safely changed. If they clash with codes in your program, it might be safer to rename them than to change their values and try to see where the EMM code got broken. AJR: I renamed returns.h to emmret.h and sizes.h to emmsize.h to avoid file name clashes. Here are some notes on the calls: OpenEMM() - call this first, period. CloseEMM() - call this last. It'll even free any EMS you forgot to free in your program (this isn't like conventional memory, y'know) EMMInstalled() - returns TRUE or FALSE. Use only after OpenEMM() is called. EMMalloc() - returns a pointer to the first EMM page (EMMSeg:0000 hex). Also stuffs a new handle into *Handle (*Handle == NULL is not checked for, so be careful or fix the code). You gotta supply Pages (i.e. number of 16K blocks). EMMRealloc() - increases/decreases number of pages allocated to your handle. EMMFree() - frees all the pages and voids the handle. MapEMM() - places 1 to 4 Pages into the page frame starting with page, Start. UnmapEMM() - removes the pages from the page frame so nothing else trashes your data. UseEMM() - same as MapEMM() but saves the frame state before mapping. SaveEMM() - same as UnmapEMM() but restores a saved frame state after unmapping. EMMCoreLeft() - returns the number of bytes of EMM left to allocate. The comments in the MapEMM() and UseEMM() (and UnmapEMM() and SaveEMM()) speak of 'applications' and 'devices'. These refer to layers in the development environment using this .c file. The application layer could use EMS as long as it kept track of it's own usage. So it wouldn't have to keep track of the environment's usage, 'devices' (i.e. lower layers) saved the page frame state to use EMS themselves, so as not to trash the application layer's data, and restored the original state upon returning. More notes: Alexander J Russell wrote: >How do you USE emm memory? >With xms it is obvious - you copy mem back and forth. >What the parameters for mapemm() etc... mean isn't documented well enough >for a newbie to use it. EMM is alot like XMS except that the EMM driver does the copying for you, without really copying (the 386's LDTs are used to point to appropriate parts of physical memory when mapping EMM). Here's how it works. EMM has a 64K (typically) page frame in conventional memory, often at E000-EFFF. The page frame consists of four 16K pages. When you call EMMalloc(), you supply the number of 16K pages you need and it returns 1) a handle, and 2) a pointer to the page frame (i.e. E000:0000). This memory is allocated somewhere in extended memory but still unavailable. To use it, you must 'map' it into the page frame so conventional memory pointers can access it. The MapEMM() function maps the pages you need (up to four) associated with that handle into the page frame. You can now use your alloc'd memory at E000. When you're finished accessing the memory, you can unmap it using UnmapEMM(). This removes the mapping from the page frame so you can map other allocations or just protect what you've already written (i.e. writing to the page frame segment won't touch your data). N.B. You never *have to* unmap your pages. Mapping new pages automagically unmaps existing mappings - but it's good practice to unmap when you're finished. Another way to look at EMS is to consider the page frame as a window over the extended memory area. Mapping is like moving the window to some area of XMS and making it available with a conventional memory pointer - at the page frame address, which never changes. In other words, EMS 'bank switches' segments of XMS memory into conventional memory. >I think I call openemm() the use map and unmap to utilize the mem. >what does map do, what do the parms mean? Once mapped how is the mem used. Pretty close. OpenEMM() makes sure the driver is loaded and gets the page frame address (EMMSeg:0000). Then EMMalloc() reserves the specified number of 16K pages, associates them to a handle, and gives your app the page frame address. Then MapEMM() lets you use up to four pages at a time (at the address returned by EMMalloc()). The parameters for MapEMM() are: - the handle you got from EMMalloc() - the memory page # to map to the first page frame page. - the number of pages to map to the page frame (max. of 4) BTW, all numbering is zero-based. >Could you send a quick overview of how you actually use emm mem in a dos >program. -------------------- see emm.c for example --------------- >Can I re-post your code and notes on my page? Yup. Leaving my name in the comments at the top would be much appreciated. I learnt most of this from DOS Programmer's Reference by Terry Dettmann from Que publishing (it's (C)1989 and I *still* use it!). You can check out other references dealing with int67h (the EMS API) too. Hope I didn't leave anything out. Email me again if any points aren't clear. Chris S. AJR adds: memory.c, and the h files all you need to use emm! emm.c is just a test program to show how it is used. /* ********************************************************************* ********************************************************************* next file ********************************************************************* ********************************************************************* */ // Cut this out as emmsize.h /* File: EmmSize.h * Module: All Modules * Author(s): Chris Somers * Date: May 8, 1992 * Version: V.1.0 */ #ifndef _EMMSIZES_DEF #define _EMMSIZES_DEF 1 /* Module size constants */ #define MAXACTIONS 29 #define MAXCHANNELS 4 #define MAXFOCUS 3 #define MAXBUFTYPES 64 #define MAXEMHANDLES 64 /* up to a max of 255 */ #define MAXTIMERS 32 #define MAXTITEMS 128 #define MAXQUEUES 24 #ifdef PRINTER #define MAXPRNS 4 #else #define MAXPRNS 0 #endif #ifdef UTSCOM #define MAXUTSSCRNS 2 #else #define MAXUTSSCRNS 0 #endif #ifdef CAPTURE #define MAXCAPTURE 1 #else #define MAXCAPTURE 0 #endif #define MAXIRQS 10 #define MAXTCPDSCPTITEMS 16 /*max # of TCP connections*/ #define FREEBUFF 1 /* CallIODevice flag for BuffSize arrays */ #define DSCONLY 2 /* allocate a BufDscpt, only - no buffer */ #define EMMPAGESIZE 0x4000 /* 16K EMM page size */ #define SETUPLEN 32 #define NAMELEN 40 #define UNIXLEN 32 #define ADDRLEN 16 #define TITLELEN 128 #define TSLEN 80 #define COMMENTLEN 65 #define PALSIZE 768 #define QSTRLEN 254 #define PRNBUFSIZ 2048 #define TXTSCRNSIZE 4096 #define UTSBUFSIZ 4096 #define UTSSCRNSIZ 1920 #define QMEMSIZE 15 #define KBUFLEN 16 #define GXBUFFSIZE 0x4000 #define TCPNDBUFFSIZE 0x1000 /*router auto-allocation buff size*/ /* graphics printing scale values */ #define SCALE_HALF 1 /* value must not change */ #define SCALE_ONE 2 #define SCALE_QUART 3 /* value must not change */ #define SIXTH_SECOND 3L /* shade over 1/6 of a second*/ #define HALF_SECOND 9L #define ONE_SECOND 18L #define TWO_SECONDS 36L #define FIVE_SECONDS 91L #define TEN_SECONDS 182L #define HALF_MINUTE 182*3L /* same as 18.2*30, right? */ #define ONE_MINUTE 182*6L /* same as 18.2*60, right? */ #define TWO_MINUTES 182*12L /* same as 18.2*120, right? */ #define FIVE_MINUTES 182*30L /* same as 18.2*300, right? */ #define TEN_MINUTES 182*60L /* same as 18.2*600, right? */ #define HALF_HOUR 182*180L /* same as 18.2*1800, right? */ #define ONE_HOUR 182*360L /* same as 18.2*3600, right? */ #define MAXROUTMOVES 24 /*max # of routing moves at one time*/ /*also max # of Move Complete Events*/ /* Event Channel Defines */ #define MAXRECALLEVENTS 1 /*max nm of Recall Event Channels*/ #define MAXKBDEVENTS 1 /*max nm of Kbd Event Channels*/ #define MAXPRNEVENTS 4 /*max nm of Prt Prog & Prt Cmplte Event Chan*/ #define MAXUTSRCVEVENTS MAXUTSSCRNS /*max nm of Uts Rx Event Chans*/ #define MAXUTSXMTEVENTS MAXUTSSCRNS /*max nm of Uts Tx Event Chans*/ #define MAXCAPEVENTS 2 /* max number of capture event channels */ #define MAXOP1CMPLTEVENTS 1 /*max nm of Operation 1 Cmplt Event Channels*/ #define MAXOP2CMPLTEVENTS 1 /*max nm of Operation 2 Cmplt Event Channels*/ #define MAXOP3CMPLTEVENTS MAXTCPDSCPTITEMS /*max nm of Op 3 Event Chans*/ #define MAXTCPEVENTS MAXTCPDSCPTITEMS /* max nm of TCP Event types */ #endif /* ********************************************************************* ********************************************************************* next file ********************************************************************* ********************************************************************* */ // AJR notes: some of these are not used by the emm code // Cut this out as emmret.h /* File: EmmRet.h * Module: All Modules * Author(s): Chris Somers * Date: May 8, 1992 * Version: V.1.0 */ #ifndef _EMM_RETURNS_DEF #define _EMM_RETURNS_DEF 1 /* Module return values */ /* Return Values */ #define START 8 #define END 7 #define MOVABORT 6 #define PRN_COMPLETE 5 #define PRN_PROGRESS 4 #define INCOMPLETE 3 #define HAVEROOM 2 #define SUCCESS 1 #define TRUE 1 #define YES 1 #define FALSE 0 #define NO 0 #define NOTREADY 0 #define NO_DATA 0 #define NONE -1 /* Start of Recoverable error codes */ #define NO_SPACE -1001 #define NOTPOLLING -1002 #define ALREADYDONE -1003 #define NO_PRN_DEV -1004 #define OUTF_PAPER -1005 #define NO_VIDEO -1006 #define TIMEOUT -1007 #define FILENOPEN -1008 #define ABORT_REQ -1009 #define DEV_IOERR -1010 #define MAXRERR 10 #define RECOVERABLE -1999 /* all above errors are recoverable */ /* Start of Threadfatal error codes */ #define NOT_OPEN -2001 #define NOT_ATTACHED -2002 #define NO_CONNECTION -2003 #define INSUFF_MEM -2004 #define NR_TIMEOUT -2005 #define MAXTERR 5 #define THREADFATAL -2999 /* above errors force task to cancel */ /* Start of Systemfatal error codes */ #define BAD_TASKNUM -3001 #define BAD_HANDLE -3002 #define BAD_HARDWARE -3003 #define INVALIDACTION -3004 #define NOFREEITEMS -3005 #define NO_MEMORY -3006 #define NO_EMS -3007 #define VALUE_OUTF_RANGE -3008 #define BAD_MODE -3009 #define NO_PALETTE -3010 #define BAD_DISPPAGE -3011 #define NO_TSR -3012 #define BUFTOOSMALL -3013 #define BAD_NAME -3014 #define BAD_DISPHW -3015 #define NO_FLOPPY -3016 #define MAXSERR 16 #define SYSTEMFATAL -3999 /* above errors are fatal to system */ #endif /* ********************************************************************* ********************************************************************* next file ********************************************************************* ********************************************************************* */ // Cut this out as memory.h /* File: Memory.h * Module: All Modules * Author(s): Chris Somers * Date: August 5, 1993 * Version: V.1.1 modified by Alex Russell to simplify. */ #ifndef _MEMORY_DEF #define _MEMORY_DEF 1 #include "emmret.h" #include "emmsize.h" #define CMM 0 #define EMM 1 extern int OpenEMM(void); extern void CloseEMM(void); extern int EMMInstalled(void); extern void far *EMMalloc(int *Handle, int Pages); extern int EMMRealloc(int Handle, int Pages); extern void EMMFree(int Handle); extern int MapEMM(int Handle, int Start, int Pages); extern void UnmapEMM(int Handle, int Start, int Pages); extern int UseEMM(int Handle, int Start, int Pages); extern void SaveEMM(int Handle, int Start, int Pages); extern unsigned long EMMCoreLeft(void); #endif /* ********************************************************************* ********************************************************************* next file ********************************************************************* ********************************************************************* */ /* File: Memory.c * Module: All Modules * Author(s): Chris Somers * Date: December 1, 1992 * Version: V.1.1 minor mods by Alex Russell to simplify Must use memory model with FAR code */ #if !defined(__LARGE__) && !defined(__COMPACT__) && !defined(__HUGE__) #error Invalid memory model for compiling MEMORY.C #endif #include #include #include #include "memory.h" // static globals -------------------------------- static int ActiveEMList[MAXEMHANDLES]; static unsigned int EMMSeg; // forward declarations --------------------------------- static int EMPresent(void); static int EMReady(void); static unsigned int GetEMMSeg(void); static int GetEMHandle(int NumPages); static int EMMap(int Handle, int LogPg, int PhyPg); static int FreeEMHandle(int Handle); static int GetNumPages(int Handle); static int EMStateSave(int Handle); static void EMStateRestore(int Handle); /********************************************************************/ int OpenEMM(void) { if (!EMPresent() || !EMReady()) return(NOTREADY); if (!(EMMSeg = GetEMMSeg())) return(NOTREADY); /*lint !e720 */ return(SUCCESS); } /* End of OpenEMM() */ /********************************************************************/ void CloseEMM(void) { int i; if (!EMMSeg) return; for (i = 0; i < MAXEMHANDLES; i++) { if (ActiveEMList[i]) { FreeEMHandle(ActiveEMList[i]); ActiveEMList[i] = 0; } } EMMSeg = 0; } /* End of CloseEMM() */ /********************************************************************/ int EMMInstalled(void) { return((EMMSeg) ? TRUE : FALSE); /* successfully opened? */ } /* End of EMMInstalled() */ /********************************************************************/ unsigned long EMMCoreLeft(void) { unsigned Pages; unsigned long RtnVal = 0UL; _asm { mov ah,0x42 /* get EMM free page count */ int 0x67 or ah,ah js InternalError /* returns 80, 81, or 84 hex on error */ mov Pages,bx /* number of unallocated 16K pages */ } RtnVal = ((unsigned long)Pages << 14); /* Pages * 16K rtns bytes*/ InternalError: return(RtnVal); } /* End of EMMCoreLeft() */ /********************************************************************/ void far * EMMalloc(int *Handle, int Pages) { int i; char *RtnPtr = NULL; if (!EMMSeg) { *Handle = NOTREADY; return(NULL); } if ((Pages < 1) || (Pages > 1020)) { *Handle = VALUE_OUTF_RANGE; return (NULL); } for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i]); i++) ; if (i == MAXEMHANDLES) { *Handle = NOFREEITEMS; return (NULL); } if ((ActiveEMList[i] = GetEMHandle(Pages)) > 0) { RtnPtr = MK_FP(EMMSeg, 0); } *Handle = ActiveEMList[i]; return((void far *)RtnPtr); } /* End of EMMalloc() */ /********************************************************************/ int EMMRealloc(int Handle, int Pages) { int RtnCode = FALSE; if (!EMMSeg || (Pages < 0) || (Pages > 1020)) { return (FALSE); } _asm { mov ah,0x51 /* change # of pages */ mov bx,Pages mov dx,Handle int 0x67 or ah,ah js NoGo /* returns 80 to 88 hex on error */ } RtnCode = TRUE; NoGo: return(RtnCode); } /* End of EMMRealloc() */ /********************************************************************/ void EMMFree(int Handle) { int i, j; if (!EMMSeg) return; for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i] != Handle); i++) ; if (i >= MAXEMHANDLES) return; j = 16; while (j--) { if (FreeEMHandle(ActiveEMList[i])) break; } ActiveEMList[i] = 0; } /* End of EMMFree() */ /********************************************************************/ int /* EMM map for application */ MapEMM(int Handle, int Start, int Pages) { int i; if (!EMMSeg) return(NOTREADY); for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i] != Handle); i++) ; if (i == MAXEMHANDLES) return (NO_DATA); if ((GetNumPages(Handle) < Pages) || (Pages < 1) || (Pages > 4)) { return (VALUE_OUTF_RANGE); } for (i = Start; i < Start + Pages; i++) { if (!EMMap(Handle, i, i - Start)) return(NO_DATA); } return(SUCCESS); } /* End of MapEMM() */ /********************************************************************/ void /* EMM unmap for application */ UnmapEMM(int Handle, int Start, int Pages) { int i, j; if (!EMMSeg) return; for (i = 0; (i < MAXEMHANDLES) && (ActiveEMList[i] != Handle); i++) ; if (i == MAXEMHANDLES) return; j = Start + Pages; if ((Pages < 1) || (j > 4)) return; for (i = Start; i < j; i++) { EMMap(Handle, NONE, i); } } /* End of UnmapEMM() */ /********************************************************************/ int /* EMM map for devices - saves EMM state */ UseEMM(int Handle, int Start, int Pages) { EMStateSave(Handle); return(MapEMM(Handle, Start, Pages)); } /* End of UseEMM() */ /********************************************************************/ void /* EMM unmap for devices - restores EMM state */ SaveEMM(int Handle, int Start, int Pages) { UnmapEMM(Handle, Start, Pages); EMStateRestore(Handle); } /* End of SaveEMM() */ /********************************************************************/ static int EMPresent(void) { int i, Segment; char EMName[] = "EMMXXXX0"; char *s, *t; _asm { /* can be replaced with getvect() */ push es mov ax,0x3567 /* get vector for int 67h */ int 0x21 mov ax,es mov Segment,ax pop es } t = MK_FP(Segment, 0x0A); /* point to driver name */ s = EMName; for (i = 0; (i < 8) && (*s++ == *t++); i++) ; /* strncmp equivalent */ if (i == 8) return(TRUE); return(FALSE); } /*End of EMPresent() */ /********************************************************************/ static int EMReady(void) { _asm { mov ah,0x40 /* get EM Manager Status */ int 0x67 or ah,ah jns Ready /* returns 80, 81, or 84 hex on error */ } return(FALSE); Ready: return(TRUE); } /* End of EMReady() */ /********************************************************************/ static unsigned int GetEMMSeg(void) { unsigned int EMSegment; _asm { mov ah,0x41 /* get EMM page frame segment */ int 0x67 or ah,ah js NotReady /* returns 80, 81, or 84 hex on error */ mov EMSegment,bx } return(EMSegment); /*lint !e530 */ NotReady: return(NOTREADY); } /* End of GetEMMSeg() */ /********************************************************************/ static int GetEMHandle(int NumPages) { int NewHandle; _asm { mov ah,0x43 /* get handle and allocate EM */ mov bx,NumPages /* number of 16K pages to allocate */ int 0x67 or ah,ah /* returns 80 to 89 hex on error */ js NoHandle mov NewHandle,dx /* retrieve handle */ } return(NewHandle); NoHandle: return(NO_DATA); } /* End of GetEMHandle() */ /********************************************************************/ static int EMMap(int Handle, int LogPg, int PhyPg) { int RtnCode = NO_DATA; _asm { mov ax,PhyPg /* physical page: 0 - 3 in AL only */ mov ah,0x44 /* map logical to physical page */ mov bx,LogPg /* logical page: 0 - 1020 */ mov dx,Handle int 0x67 or ah,ah /* returns 80 to 8B hex on error */ js NoMapping } RtnCode = SUCCESS; NoMapping: return(RtnCode); } /* End of EMMap() */ /********************************************************************/ static int FreeEMHandle(int Handle) { _asm { mov ah,0x45 /* free handle and deallocate EM */ mov dx,Handle int 0x67 or ah,ah /* returns 80 to 86 hex on error */ js NotFreed } return(SUCCESS); NotFreed: /* must retry if unsuccessful */ return(NO_DATA); } /* End of FreeEMHandle() */ /********************************************************************/ static int GetNumPages(int Handle) { int NumPages = 0; _asm { mov ah,0x4C /* get allocated pages for Handle */ mov dx,Handle int 0x67 or ah,ah /* returns 80 to 84 hex on error */ js BadHandle mov NumPages,bx } BadHandle: return(NumPages); } /* End of GetNumPages() */ /********************************************************************/ static int EMStateSave(int Handle) { int RtnCode = NO_MEMORY; _asm { mov ah,0x47 /* save page map under Handle */ mov dx,Handle int 0x67 or ah,ah js Unsaved /* out of save space error */ } RtnCode = SUCCESS; Unsaved: return(RtnCode); } /* End of EMStateSave() */ /********************************************************************/ static void EMStateRestore(int Handle) { _asm { mov ah,0x48 /* restore page map for Handle */ mov dx,Handle int 0x67 /* ignore error */ } } /* End of EMStateRestore() */ /********************************************************************/ /* ********************************************************************* ********************************************************************* next file ********************************************************************* ********************************************************************* */ // Cut this out as emm.c /* File: emm.c * Module: All Modules * Author(s): Chris Somers * Date: December 1, 1992 * Version: V.1.1 minor mods by Alex Russell to simplify Must use memory model with FAR code */ #include #include #include #include "memory.h" void TransformData(char *pEmmData, unsigned int len) { while ( len ) { (*pEmmData)++; pEmmData++; len--; } } void main(void) { char *pEmmData; int hEData; if ( OpenEMM() != SUCCESS ) { // make sure we got EMM printf("EMM unavailable.\n"); exit(1); } else printf("Emm available\n"); pEmmData = EMMalloc(&hEData, 6); // get 6 * 16K bytes - 96K if ( pEmmData == NULL ) { printf("Not enough EMM or out of handles.\n"); exit(2); } else printf("emm alloced OK\n"); printf("Map 1st 4 pages\n"); MapEMM(hEData, 0, 4); // load 1st 4 pages into page frame: 0-3 memset(pEmmData, 0x0e, 64000u); UnmapEMM(hEData, 0, 4); // not absolutely necessary printf("Map next 2 pages\n"); MapEMM(hEData, 4, 2); // map last 2 pages: 4-5 memset(pEmmData, 0x0e, 32768u); MapEMM(hEData, 0, 4); // do some stuff with the first 64K of file data. printf("Transform data\n"); TransformData(pEmmData, 64000UL); MapEMM(hEData, 4, 2); // only unmaps 1st two pages of prior 64k mapping // do stuff with remaining 32K of data TransformData(pEmmData, 32768UL); UnmapEMM(hEData, 0, 4); // should unmap before freeing printf("Close emm\n"); EMMFree(hEData); // finished with the file data CloseEMM(); }