home *** CD-ROM | disk | FTP | other *** search
- ----------
- DISCLAIMER
- ----------
- There's no real need for this section; it just makes it look more
- official. The only thing I can think of to put here is that if
- there's something wrong in here, too bad. No false statements were
- put in here on purpose. And, if the earth implodes because something
- I wrote in here, so be it. I will not be responsible.
-
- Hey, I don't know much about copyrights and trademarks, and what I
- have to include in this document regarding them - if you feel you've
- been discredited because I didn't put your name in here for your
- trademark or whatever, too bad. Send me a note and I'll fix it (you
- might want to tell me how to fix it, too).
-
- -------------
- THE BEGINNING
- -------------
- Long, long ago, in a galaxy just around the corner...
-
- BOY BORN - RICHARD VUDUC IS NAME!
-
- Yes, one fateful day in 1975, a young 6+lb boy was born to the
- delight of his parents. It was summer; it was hot; it was very
- uncomfortable; but it was a day that would live in infamy (or
- something like that).
-
- Yes, friends, my name is Richard Vuduc and I am 15 years old. And,
- for your viewing pleasure, I have assembled a library of neet little
- tools to help you make use of extended memory.
-
- Early this summer, I bought a copy of Turbo C++. Here, I would like
- to present something I threw together for other owners of Turbo C++
- (and soon, if I get a reasonable response, owners of a lot of other
- compilers, C or otherwise, including Pascal and Assembly).
-
- -------------------
- WHERE TO CONTACT ME
- -------------------
- Forward your messages to me at my CIS account (actually, it's the
- account of the place where I work, but I use it for them):
-
- Richard Vuduc, CIS 70022,1332
-
- I LOVE getting mail, so please send something.
-
- Also, there's no charge for this library of routines. If you like
- them and want to send money to a starving high school student, who
- has nothing but the clothes on his back and some loose leaf notebook
- paper (keep in mind school starts soon), please feel free to send
- donations of money ($1.00 and up, please) to me at:
-
- Richard Vuduc
- 3711 S. George Mason Drive, Suite C-1-W
- Falls Church, Va 22041
-
- You can, if you want, send me a check made out to your favorite
- charity and I'll forward it to you.
-
- To register yourself, please leave a note for me at my CIS account
- and I'll do so. Senders of money should also leave a note to let me
- know it's coming and for immediate registration. You don't have to
- pay to register (but if you want to see another kid go to college,
- you better send something). Also feel free to distribute this
- elsewhere PROVIDED you DO NOT charge anyone for this. That's my
- job, so DON'T DO IT.
-
- -----
- INTRO
- -----
- You here all about extended memory in all the IBM computer magazine
- headlines these days - but what is it, really? How can I use it?
- What good is it? I wondered these same things, mon ami, and I
- decided to go out and find out instead of partying all summer.
- Here's what I found...
-
- - There are a couple of ways to access extended memory. Most
- AT's have BIOS routines (int 15h) that provide a means by which to
- access extended memory.
-
- - Microsoft's eXtended Memory Manager (XMM) is another way to
- access extended memory. Windows 286 and Windows 3 have HIMEM.SYS
- bundled with them. Not only do they allow access to extended memory,
- but also to the High Memory Area (HMA). This is (I'm sure you know
- this already) the area just above the 1MB region. More on this
- later.
-
- - Using the VDISK interface protocol. This is basically access
- to extended memory just like VDISK would.
-
- - Some VCPI thing is another way. I think you need a 386 for
- this one (something I do not currently possess in my home), and is
- really some DOS Extender type thing (you can look it up yourself).
-
- Anyway, I wanted to be able to access extended memory, too. Why
- extended memory? Well, it seems like such an untapped resource
- (unlike EMS, which you can get three zillion articles on), I decided
- to do the public a favor and assemble a FREE library you can use it
- with (see the about the author section for more details). Since I
- also have a new compiler (Turbo C++, and the other Tools like the
- Turbo Debugger and Assembler), I decided to take this opportunity to
- do something great and spectacular and, well, just something "me."
-
- --------------
- IMPLEMENTATION
- --------------
- One day I sat down and though about which of the four methods for
- accessing extended memory I should use. It occurred to me that the
- easiest one to implement were the BIOS routines. Unfortunately, I
- decided against that for now. The BIOS routines were clunky to use;
- I eventually opted for the Microsoft HIMEM.SYS method.
-
- Two things brought me to HIMEM. The first was the fact that I did
- have the HIMEM driver (with Windows 286 and the upgrade to 3). I
- also saw an article on writing a RAM disk thing using HIMEM as the
- interface. Great - I had example code so this should be easy.
- Unfortunately, the article didn't document much, so I continued
- onward looking for more documentation...and eventually found
- HIMEM.ARC, available in the Microsoft Systems Forum on CompuServe.
-
- Using the document in there, I continued to code (in assembly for
- low-level routines, and used C++ for the upper level routines) and
- created a single class for managing extended memory - XMSDriver.
-
- Although I'm not releasing the source code yet (a teenager is very
- self conscious about zits, hair, clothes, and code), I don't want to
- get harrased about how this C++ class isn't a good object oriented
- class design, blah, blah blah... I realize I didn't design the
- heirarchy well (there's only one method), but I didn't need to. The
- real purpose of putting into a class was to encapsulate all the code
- and internal data without using globals, etc. Classes were the
- perfectly neet way to put everything together in one package. So
- there.
-
- This initial release is for small model programs only. Before school
- starts (Sept. 4 for me), I'll try to get it uploaded. If you need it
- desperately, please leave a note for me at my CIS Mail account
- address thing.
-
- -----
- HIMEM
- -----
- Here's some background info on the theories behind HIMEM. If you
- think you already know enough, so be it. If you need more info, you
- can also get HIMEM.ARC from the MSSYS forum on CompuServe (I'm sure
- it's on BIX, too).
-
- Okay, here's the run down on what HIMEM is supposed to do for the
- average "joe programmer":
- - HIMEM will provide a standard method to gain access to the
- loads and loads of extended memory that exist in 286, 386, and 486
- machines (and I'm sure for the 586, 686, 786, 886, 986, and the
- 81086, 81186, 81286, 81386,...88086, 88186, 88286,...90086,...). It
- should also take care of fragmentation and provide support routines
- for accessing, allocating, releasing, and moving extended memory.
-
- - HIMEM will provide a standard method by which to access Upper
- Memory Blocks. UMB's are the area betwee 640K and 1024K (normally
- used as video memory, LAN and EMS space, BIOS, etc. Basically, it
- returns a segment pointer to that block.
-
- - HIMEM let's you use and execute code from the High Memory Area.
- The HMA is the area between 1024K and 1088K without leaving real
- mode. It does it like this: Let's say you have the segment:offset
- pointer 0xFFFF:0000. On 286 and 386 systems, you have enough address
- lines to access more memory than a regular old 8086. On 286+
- machines, you can enable the 21st address line (8086's have only 20
- address lines) and access a little more extended memory, making this
- a valid pointer -> 0xFFFF:0BA3. On 8086's, this would just wrap
- around to the beginning of RAM.
-
- ---------
- THE CLASS
- ---------
- Here is the class declaration as it appears in the file, XMS.H:
-
- // XMSDriver class
- // Handles allocation and deallocation of XMS blocks
- class XMSDriver
- {
- static long Avail; // Extended Memory available to application
- static long Total; // Total extended memory installed
- static boolean Installed; // XMM installed?
- boolean InstHMA; // XMM HMA available
- char far *HMAPtr; // Pointer into High Memory Area
- XMSHandle *CurrHandle, // Linked list - Current handle
- *First, // First handle in linked list
- *Last; // Last handle in linked list
- public:
- XMSDriver( void ); // constructor
-
- // ***************** High Memory Area management functions (1024K-1088K)
- boolean ReqHMA( void ); // Allocate HMA
- void RelHMA( void ); // Deallocate HMA
- boolean A20Enable( void ); // Globally enable A20 line
- void A20Disable( void ); // Globally disable A20 line
- boolean A20LEnable( void ); // Locally enable the A20 line
- void A20LDisable( void ); // Locally disable the A20 line
- boolean A20Query( void ); // Query state of A20 line
- void far *HMAWrite( unsigned ItemSize, unsigned Index, unsigned Length,
- void far *Data ); // Write a block to high memory
- // Read from HMA
- void far *HMARead( unsigned ItemSize, unsigned Index, unsigned Length,
- void far *Data );
-
- // **************** Extended Memory Block Functions... (1088K+)
- unsigned EMBAlloc( unsigned size ); // Allocate EMB
- void EMBFree( unsigned handle ); // Free EMB
- long EMBLock( unsigned handle ); // Lock EMB
- boolean EMBUnlock( unsigned handle ); // Unlock EMB
- boolean EMBMoveToExt( unsigned dhandle, unsigned doff,
- void far *p, long size );
- boolean EMBMoveToCon( void far *p, unsigned shandle, unsigned soff,
- long size );
- boolean EMBExtToExt( unsigned dhandle, unsigned doff,
- unsigned shandle, unsigned soff, long size );
- boolean EMBRealloc( unsigned handle, unsigned size ); // Realloc block
-
- // **************** Upper Memory Block management routines (640K - 1024K)
-
- // **************** Miscellaneous Management routines
- long GetAvail( void ); // Get available Extended Memory
- boolean Inst( void ) { return Installed; } // XMS Installed?
- boolean HMAInst( void ) { return InstHMA; } // HMA Installed?
- long GetTotal( void ) { return Total; }
- private:
- void CopyBlock( char far *dest, char far *src, unsigned len );
- void XMSChainHandle( unsigned int handle, unsigned int size );
- void XMSFreeHandle( unsigned int handle );
- XMSHandle *XMSFindLastHandle( void ) { return (CurrHandle=Last); }
- XMSHandle *XMSFindFirstHandle( void ) { return (CurrHandle=First); }
- XMSHandle *XMSFindHandle( unsigned handle );
- };
-
- I have not implemented the Upper Memory Block functions yet; I need
- to get something started and distributed so I can get a feel for the
- response. For more info on High Mem, just get a copy of HIMEM.ARC on
- the Microsoft Systems Forum (go MSSYS, I think).
-
- Note that there are some "private:" functions. These are for
- internal function use ONLY. Please do not tamper with these
- declarations. Danke.
-
- ------------
- THE ROUTINES
- ------------
- When you want to access some extended memory, you need to declare a
- class variable (called an "instance," I guess) called whatever you
- want to call it (check out the demo, XMSDEMO.CPP, for an example), of
- type XMSDriver. Then you can start calling methods...
- * Example:
-
- void main( void )
- {
- XMSDriver XMM; // Declare an XMM
- ...
- Available = XMM.GetAvail( ); // Get available memory
- if( !XMM.ReqHMA( ) ) // Requesting HMA...
- ...
- }
-
- I have, in the header file, declared an enumerated type called
- 'boolean'. The values in this are True and False. I hope they don't
- collide with any booleans you declare.
-
- Also note that I have not implemented any serious error checking. If
- a function returns False (meaning an error occurred), you'll be hard
- pressed to find out why. This is easy to implement - I'm sorry I
- didn't do it. Yeah, yeah, yeah...I know there isn't any way to find
- out currently, aside from dumping the registers (the error code is
- in the BL register).
-
- Here is a list of all the routines and what they do. Check out the
- header files for info on structures.
-
- XMSDriver::XMSDriver( void );
- ----------------------------
- This is a constructor for the driver (wa la!). This constructor
- performs all the necessary initialization functions, including
- determining the presence of the HIMEM driver. This is automatically
- called for you when you declare (don't feel stupid if this is
- blatantly obvious to you).
-
- boolean XMSDriver::Inst( void );
- --------------------------------
- This routine returns True if HIMEM is installed, and XMSDriver has
- set everything up for using it; otherwise it returns False if HIMEM
- is not installed.
-
- long XMSDriver::GetAvail( void );
- ---------------------------------
- This routine returns the largest available memory block. Note that
- this is not always the same as the Total amount of memory installed
- or the total amount of memory free (confused?). Because extended
- memory can be fragmented, this only returns the largest availble
- unfragmented block.
-
- long XMSDriver::GetTotal( void );
- ---------------------------------
- Upon return, this function returns the amount of extended memory
- free. This is greater than or equal to the largest available block
- of extended memory.
-
- ******************* High Memory Functions ***************************
- boolean XMSDriver::InstHMA( void )
- ----------------------------------
- This function determines whether or not the High Memory Area has been
- allocated. It returns True if the high memory area is available,
- False if not.
-
- boolean XMSDriver::ReqHMA( void )
- ---------------------------------
- This function requests use of the High Memory Area from HIMEM.SYS.
- It returns True if HMA access is granted to the application, False
- otherwise. Only allocate the HMA if you plan to use a good portion
- of it, as other applications may need the HMA. The HMA is only given
- out as one large block to an application, so use it wisely. Also,
- don't forget to cleanup after yourself (where have I heard that
- before?) and release the HMA when you are through.
-
- void XMSDriver::RelHMA( void )
- ------------------------------
- This function attempts to free the High Memory Area. There is no
- return, because the only way the High Memory Area could be not
- released is if you didn't own it in the first place, or if it didn't
- exist.
-
- ********A20 line functions
- Recall that the HMA is possible because the 286+ machines have
- additional address lines (the 21st line in particular). The A20 line
- is off on the 286 by default, because some applications depend on the
- wrap around at the top (I have no idea what applications depend on
- this, but that's what Microsoft says). In order to use the HMA, you
- must enable the A20 address line. Don't forget to disable it after
- you are through.
-
- boolean XMSDriver::A20Enable( void )
- ------------------------------------
- This function attempts to enable the A20 line so folks like you can
- access the HMA. It returns True when the A20 line has been
- successfully enabled.
-
- void XMSDriver::A20Disable( void )
- ----------------------------------
- This function disables the A20 line. There is no return value.
-
- boolean XMSDriver::A20LEnable( void )
- -------------------------------------
- This function enables the A20 line locally. I'm not quite sure what
- this means, but I suspect it's so you can enable the line and not
- worry about the state of line currently. In other words, you can
- enable the line for your own purposes, regardless of the current
- state of the A20 line. You need to perform a local disable when
- you're through.
-
- void XMSDriver::A20LDisable( void )
- ------------------------------------
- "Locally Disable the A20 line" this function has been dubbed (I had
- to use a different intro so you wouldn't get too bored). There is no
- return.
-
- boolean XMSDriver::A20Query( void )
- -----------------------------------
- This function queries the state of the A20 line. It returns True if
- the A20 line is enabled, False otherwise.
-
- void far *HMAWrite( unsigned ItemSize, unsigned Index, unsigned Length,
- void far *Data );
- ----------------------------------------------------------------------
- This function is kind of involved, but I'll explain it as best I can.
- Basically, it's a high level write to high memory area function. It
- might be simpler to just maintain a pointer to the High Memory Area
- (the HMA begins at 0xFFFF:000A; 64k - 16 bytes long) than to use this
- function, but it's up to you. This function treats the "Data" (last
- parameter) as an array. Each array element is ItemSize long. The
- function will begin copying at Data[ Index ], and will copy Length
- elements of the array (including that point). It returns a pointer
- to the High Memory Area pointing to the first element if Data that
- was copied, or NULL if the function failed.
-
- void far *HMARead( unsigned ItemSize, unsigned Index, unsigned Length,
- void far *Data );
- ----------------------------------------------------------------------
- This function is similar to HMAWrite except that it reads from the
- High Memory Area, and returns a pointer to Data (NULL on failure).
- It treats the High Memory Area as an array, each element is ItemSize
- bytes long. It copies Length elements starting at the beginning of
- the High Memory Area + Index (in other words, it starts reading at
- Index offset into the HMA). It copies all this junk into Data, and
- returns the pointer to Data (NULL on failure, as I already said 5 or
- 6 lines up).
-
- **End of High Memory Area Management Functions (what a mouth full)
-
- **************** Extended Memory Block functions
- The following functions allow the management of extended memory.
- Basically, you call a function requesting some extended memory. The
- function returns a handle to that memory, and you use that handle to
- access the memory block later. Every time you allocate a block of
- extended memory, you are getting what's called an Extended Memory
- Block (EMB). You must use the handle to use the EMB. For your
- convenience, I have provided some routines to copy blocks of data to
- and from extended memory. Actually, I think that you are forced to
- use them, whether or not you want to.
-
- By the way, one of the Extended Memory Block Management Functions in
- Microsoft's HiMEM.SYS is not implemented. That is function 0x0E -
- Query Extended Memory block. It's used to get info on the Extended
- Memory Block. I will implement it later, so don't cry.
-
- NOTE: For from-to extended memory transfers, 'size' must be even. The
- function will not succeed unless size is even. It's also advisable to
- word align data you store in the EMB because they generally run much
- faster on 2/3/486 type machines.
-
- unsigned XMSDriver::EMBAlloc( unsigned size )
- ---------------------------------------------
- This routine will try as hard as it can to allocate a block of
- extended memory 'size' bytes in length. It returns a handle to the
- EMB on success, otherwise it will return 0. The location of this
- block in extended memory is not known as it may be moved around by
- the driver to relieve fragmentation.
-
- void XMSDriver::EMBFree( unsigned handle )
- ------------------------------------------
- This function frees the handle specified by 'handle.' There is no
- return.
-
- long XMSDriver::EMBLock( unsigned handle )
- ------------------------------------------
- I'm not totally sure I understand what this is for, but I'll take a
- stab. This function locks a previously allocated EMB. Locking the
- block guarantees that the HIMEM driver will NOT move it around. This
- way, you can get direct access to the block using the BIOS routines,
- or whatever. This function returns a 32-bit linear address pointer
- to the extended memory block, or 0 if an error occurred.
-
- boolean XMSDriver::EMBUnlock( unsigned handle )
- --------------------------------------------
- This function releases the lock that was put on the handle
- previously. Lock counts are maintained, meaning if you lock a block
- 3 times, you have to unlock it 3 times as well before it is actually
- unlocked (I guess). It returns True on success, False on failure (so
- don't make me feel like a failure and send money or 10 pages of
- praise) (just kidding) (not) (way) (no way)...
-
- boolean XMSDriver::EMBMoveToExt( unsigned dhandle, unsigned doff,
- void far *p, long size );
- -----------------------------------------------------------------
- This function moves a block of conventional memory to extended
- memory. Actually, it really copies the block as opposed to freeing
- it. dhandle is the handle of the destination EMB, and doff is the
- offset into the EMB to begin the transfer. It returns True if the
- move was a success, False if it failed. By the way, 'size' is the
- size of the block to move in bytes.
-
- boolean XMSDriver::EMBMoveToCon( void far *p,
- unsigned shandle, unsigned soff,
- long size );
- ------------------------------------------------------------------
- This function moves a block of extended memory to conventional memory
- (the pointer *p). shandle is the handle number of the source EMB,
- and soff is the offset into the shandle to begin copying. 'size' is
- the size in bytes to transfer. Returns True on success and False on
- failure (say, you wouldn't happen to see a pattern in the return
- values, would you?).
-
- boolean XMSDriver::EMBExtToExt( unsigned dhandle, unsigned doff,
- unsigned shandle, unsigned soff
- long size);
- --------------------------------------------------------------------
- This function copies data from one EMB to another EMB. dhandle and
- shandle are the destination and source handles respectively (gee, i
- bet you would've never guessed that) and doff and soff the offsets
- into the block. 'size' is the size in bytes of the transfer. It
- returns True on success, and False on failure.
-
- ********************* The End (almost) *****************************
- I know it seems like there's is no end in site for this document.
- Well, just scroll down a few more lines and then you can start
- partying to your heart's content. Just some parting words...
-
- I worked pretty hard on this, and it's still far from perfect (what a
- bummer, dude). I released it in it's "far from perfect" state
- because I wanted to see if it was worth all the time I spent. This
- is why it's very important that I get some feedback from you guys.
- It's also a way for me to assess whether or not it's worth it for me
- to program all kinds of apps and libraries for other people. It's
- hard to find friends who do this kind of system level programming, so
- I'm on my own on most of this stuff.
-
- Thanks for reading this far into the document (assuming you read this
- far). See ya!