home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c100 / 2.ddi / XMSCPP.ZIP / XMSCPP.TXT < prev    next >
Encoding:
Text File  |  1990-08-19  |  22.3 KB  |  494 lines

  1. ----------
  2. DISCLAIMER
  3. ----------
  4. There's no real need for this section; it just makes it look more
  5. official.  The only thing I can think of to put here is that if
  6. there's something wrong in here, too bad.  No false statements were
  7. put in here on purpose.  And, if the earth implodes because something
  8. I wrote in here, so be it.  I will not be responsible.
  9.  
  10. Hey, I don't know much about copyrights and trademarks, and what I
  11. have to include in this document regarding them - if you feel you've
  12. been discredited because I didn't put your name in here for your
  13. trademark or whatever, too bad.  Send me a note and I'll fix it (you
  14. might want to tell me how to fix it, too).
  15.  
  16. -------------
  17. THE BEGINNING
  18. -------------
  19. Long, long ago, in a galaxy just around the corner...
  20.  
  21. BOY BORN - RICHARD VUDUC IS NAME!
  22.  
  23. Yes, one fateful day in 1975, a young 6+lb boy was born to the
  24. delight of his parents.  It was summer; it was hot; it was very
  25. uncomfortable; but it was a day that would live in infamy (or
  26. something like that).
  27.  
  28. Yes, friends, my name is Richard Vuduc and I am 15 years old.  And,
  29. for your viewing pleasure, I have assembled a library of neet little
  30. tools to help you make use of extended memory.
  31.  
  32. Early this summer, I bought a copy of Turbo C++.  Here, I would like
  33. to present something I threw together for other owners of Turbo C++
  34. (and soon, if I get a reasonable response, owners of a lot of other
  35. compilers, C or otherwise, including Pascal and Assembly).
  36.  
  37. -------------------
  38. WHERE TO CONTACT ME
  39. -------------------
  40. Forward your messages to me at my CIS account (actually, it's the
  41. account of the place where I work, but I use it for them):
  42.  
  43.         Richard Vuduc, CIS 70022,1332
  44.  
  45. I LOVE getting mail, so please send something.
  46.  
  47. Also, there's no charge for this library of routines.  If you like
  48. them and want to send money to a starving high school student, who
  49. has nothing but the clothes on his back and some loose leaf notebook
  50. paper (keep in mind school starts soon), please feel free to send
  51. donations of money ($1.00 and up, please) to me at:
  52.  
  53.     Richard Vuduc
  54.     3711 S. George Mason Drive, Suite C-1-W
  55.     Falls Church, Va 22041
  56.  
  57. You can, if you want, send me a check made out to your favorite
  58. charity and I'll forward it to you.
  59.  
  60. To register yourself, please leave a note for me at my CIS account
  61. and I'll do so.  Senders of money should also leave a note to let me
  62. know it's coming and for immediate registration.  You don't have to
  63. pay to register (but if you want to see another kid go to college,
  64. you better send something).  Also feel free to distribute this
  65. elsewhere PROVIDED you DO NOT charge anyone for this.  That's my
  66. job, so DON'T DO IT.
  67.  
  68. -----
  69. INTRO
  70. -----
  71. You here all about extended memory in all the IBM computer magazine
  72. headlines these days - but what is it, really?  How can I use it? 
  73. What good is it?  I wondered these same things, mon ami, and I
  74. decided to go out and find out instead of partying all summer. 
  75. Here's what I found...
  76.  
  77.     - There are a couple of ways to access extended memory.  Most
  78. AT's have BIOS routines (int 15h) that provide a means by which to
  79. access extended memory.
  80.  
  81.     - Microsoft's eXtended Memory Manager (XMM) is another way to
  82. access extended memory.  Windows 286 and Windows 3 have HIMEM.SYS
  83. bundled with them.  Not only do they allow access to extended memory,
  84. but also to the High Memory Area (HMA).  This is (I'm sure you know
  85. this already) the area just above the 1MB region.  More on this
  86. later.
  87.  
  88.     - Using the VDISK interface protocol.  This is basically access
  89. to extended memory just like VDISK would.
  90.  
  91.     - Some VCPI thing is another way.  I think you need a 386 for
  92. this one (something I do not currently possess in my home), and is
  93. really some DOS Extender type thing (you can look it up yourself).
  94.  
  95. Anyway, I wanted to be able to access extended memory, too.  Why
  96. extended memory?  Well, it seems like such an untapped resource
  97. (unlike EMS, which you can get three zillion articles on), I decided
  98. to do the public a favor and assemble a FREE library you can use it
  99. with (see the about the author section for more details).  Since I
  100. also have a new compiler (Turbo C++, and the other Tools like the
  101. Turbo Debugger and Assembler), I decided to take this opportunity to
  102. do something great and spectacular and, well, just something "me."
  103.  
  104. --------------
  105. IMPLEMENTATION
  106. --------------
  107. One day I sat down and though about which of the four methods for
  108. accessing extended memory I should use.  It occurred to me that the
  109. easiest one to implement were the BIOS routines.  Unfortunately, I
  110. decided against that for now.  The BIOS routines were clunky to use;
  111. I eventually opted for the Microsoft HIMEM.SYS method.
  112.  
  113. Two things brought me to HIMEM.  The first was the fact that I did
  114. have the HIMEM driver (with Windows 286 and the upgrade to 3).  I
  115. also saw an article on writing a RAM disk thing using HIMEM as the
  116. interface.  Great - I had example code so this should be easy. 
  117. Unfortunately, the article didn't document much, so I continued
  118. onward looking for more documentation...and eventually found
  119. HIMEM.ARC, available in the Microsoft Systems Forum on CompuServe.
  120.  
  121. Using the document in there, I continued to code (in assembly for
  122. low-level routines, and used C++ for the upper level routines) and
  123. created a single class for managing extended memory - XMSDriver.
  124.  
  125. Although I'm not releasing the source code yet (a teenager is very
  126. self conscious about zits, hair, clothes, and code), I don't want to
  127. get harrased about how this C++ class isn't a good object oriented
  128. class design, blah, blah blah...  I realize I didn't design the
  129. heirarchy well (there's only one method), but I didn't need to.  The
  130. real purpose of putting into a class was to encapsulate all the code
  131. and internal data without using globals, etc.  Classes were the
  132. perfectly neet way to put everything together in one package.  So
  133. there.
  134.  
  135. This initial release is for small model programs only.  Before school
  136. starts (Sept. 4 for me), I'll try to get it uploaded.  If you need it
  137. desperately, please leave a note for me at my CIS Mail account
  138. address thing.
  139.  
  140. -----
  141. HIMEM
  142. -----
  143. Here's some background info on the theories behind HIMEM.  If you
  144. think you already know enough, so be it.  If you need more info, you
  145. can also get HIMEM.ARC from the MSSYS forum on CompuServe (I'm sure
  146. it's on BIX, too).
  147.  
  148. Okay, here's the run down on what HIMEM is supposed to do for the
  149. average "joe programmer":
  150.     - HIMEM will provide a standard method to gain access to the
  151. loads and loads of extended memory that exist in 286, 386, and 486
  152. machines (and I'm sure for the 586, 686, 786, 886, 986, and the
  153. 81086, 81186, 81286, 81386,...88086, 88186, 88286,...90086,...).  It
  154. should also take care of fragmentation and provide support routines
  155. for accessing, allocating, releasing, and moving extended memory.
  156.  
  157.     - HIMEM will provide a standard method by which to access Upper
  158. Memory Blocks.  UMB's are the area betwee 640K and 1024K (normally
  159. used as video memory, LAN and EMS space, BIOS, etc.  Basically, it
  160. returns a segment pointer to that block.
  161.  
  162.     - HIMEM let's you use and execute code from the High Memory Area. 
  163. The HMA is the area between 1024K and 1088K without leaving real
  164. mode.  It does it like this:  Let's say you have the segment:offset
  165. pointer 0xFFFF:0000.  On 286 and 386 systems, you have enough address
  166. lines to access more memory than a regular old 8086.  On 286+
  167. machines, you can enable the 21st address line (8086's have only 20
  168. address lines) and access a little more extended memory, making this
  169. a valid pointer -> 0xFFFF:0BA3.  On 8086's, this would just wrap
  170. around to the beginning of RAM.
  171.  
  172. ---------
  173. THE CLASS
  174. ---------
  175. Here is the class declaration as it appears in the file, XMS.H:
  176.  
  177. // XMSDriver class
  178. // Handles allocation and deallocation of XMS blocks
  179. class XMSDriver
  180. {
  181.     static long Avail;        // Extended Memory available to application
  182.     static long Total;        // Total extended memory installed
  183.     static boolean Installed;    // XMM installed?
  184.     boolean InstHMA;        // XMM HMA available
  185.     char far *HMAPtr;        // Pointer into High Memory Area
  186.     XMSHandle *CurrHandle,   // Linked list - Current handle
  187.             *First,        // First handle in linked list
  188.             *Last;        // Last handle in linked list
  189. public:
  190.     XMSDriver( void );        // constructor
  191.  
  192.     // ***************** High Memory Area management functions (1024K-1088K)
  193.     boolean   ReqHMA( void );    // Allocate HMA
  194.     void      RelHMA( void );    // Deallocate HMA
  195.     boolean   A20Enable( void );    // Globally enable A20 line
  196.     void      A20Disable( void );    // Globally disable A20 line
  197.     boolean   A20LEnable( void );    // Locally enable the A20 line
  198.     void      A20LDisable( void );    // Locally disable the A20 line
  199.     boolean   A20Query( void );    // Query state of A20 line
  200.     void far *HMAWrite( unsigned ItemSize, unsigned Index, unsigned Length,
  201.                     void far *Data );    // Write a block to high memory
  202.         // Read from HMA
  203.     void far *HMARead( unsigned ItemSize, unsigned Index, unsigned Length, 
  204.                     void far *Data );
  205.  
  206.     // **************** Extended Memory Block Functions... (1088K+)
  207.     unsigned EMBAlloc( unsigned size );        // Allocate EMB
  208.     void     EMBFree( unsigned handle );        // Free EMB
  209.     long     EMBLock( unsigned handle );        // Lock EMB
  210.     boolean  EMBUnlock( unsigned handle );        // Unlock EMB
  211.     boolean  EMBMoveToExt( unsigned dhandle, unsigned doff, 
  212.                        void far *p, long size );
  213.     boolean  EMBMoveToCon( void far *p, unsigned shandle, unsigned soff,
  214.                        long size );
  215.     boolean  EMBExtToExt( unsigned dhandle, unsigned doff,
  216.                       unsigned shandle, unsigned soff, long size );
  217.     boolean  EMBRealloc( unsigned handle, unsigned size );    // Realloc block
  218.  
  219.     // **************** Upper Memory Block management routines (640K - 1024K)
  220.  
  221.     // **************** Miscellaneous Management routines
  222.     long    GetAvail( void );    // Get available Extended Memory
  223.     boolean Inst( void ) { return Installed; }    // XMS Installed?
  224.     boolean HMAInst( void ) { return InstHMA; }    // HMA Installed?
  225.     long    GetTotal( void ) { return Total; }
  226. private:
  227.     void CopyBlock( char far *dest, char far *src, unsigned len );
  228.     void XMSChainHandle( unsigned int handle, unsigned int size );
  229.     void XMSFreeHandle( unsigned int handle );
  230.     XMSHandle *XMSFindLastHandle( void ) { return (CurrHandle=Last); }
  231.     XMSHandle *XMSFindFirstHandle( void ) { return (CurrHandle=First); }
  232.     XMSHandle *XMSFindHandle( unsigned handle );
  233. };
  234.  
  235. I have not implemented the Upper Memory Block functions yet; I need
  236. to get something started and distributed so I can get a feel for the
  237. response.  For more info on High Mem, just get a copy of HIMEM.ARC on
  238. the Microsoft Systems Forum (go MSSYS, I think).
  239.  
  240. Note that there are some "private:" functions.  These are for
  241. internal function use ONLY.  Please do not tamper with these
  242. declarations.  Danke.
  243.  
  244. ------------
  245. THE ROUTINES
  246. ------------
  247. When you want to access some extended memory, you need to declare a
  248. class variable (called an "instance," I guess) called whatever you
  249. want to call it (check out the demo, XMSDEMO.CPP, for an example), of
  250. type XMSDriver.  Then you can start calling methods...
  251. * Example:
  252.  
  253. void main( void )
  254. {
  255.     XMSDriver XMM;                  // Declare an XMM
  256.     ...
  257.     Available = XMM.GetAvail( );    // Get available memory
  258.     if( !XMM.ReqHMA( ) )            // Requesting HMA...
  259.     ...
  260. }
  261.  
  262. I have, in the header file, declared an enumerated type called
  263. 'boolean'.  The values in this are True and False.  I hope they don't
  264. collide with any booleans you declare.
  265.  
  266. Also note that I have not implemented any serious error checking.  If
  267. a function returns False (meaning an error occurred), you'll be hard
  268. pressed to find out why.  This is easy to implement - I'm sorry I
  269. didn't do it.  Yeah, yeah, yeah...I know there isn't any way to find
  270. out currently, aside from dumping the registers (the error code is
  271. in the BL register).
  272.  
  273. Here is a list of all the routines and what they do.  Check out the
  274. header files for info on structures.
  275.  
  276. XMSDriver::XMSDriver( void );
  277. ----------------------------
  278. This is a constructor for the driver (wa la!).  This constructor
  279. performs all the necessary initialization functions, including
  280. determining the presence of the HIMEM driver.  This is automatically
  281. called for you when you declare (don't feel stupid if this is
  282. blatantly obvious to you).
  283.  
  284. boolean XMSDriver::Inst( void );
  285. --------------------------------
  286. This routine returns True if HIMEM is installed, and XMSDriver has
  287. set everything up for using it; otherwise it returns False if HIMEM
  288. is not installed.
  289.  
  290. long XMSDriver::GetAvail( void );
  291. ---------------------------------
  292. This routine returns the largest available memory block.  Note that
  293. this is not always the same as the Total amount of memory installed
  294. or the total amount of memory free (confused?).  Because extended
  295. memory can be fragmented, this only returns the largest availble
  296. unfragmented block.
  297.  
  298. long XMSDriver::GetTotal( void );
  299. ---------------------------------
  300. Upon return, this function returns the amount of extended memory
  301. free.  This is greater than or equal to the largest available block
  302. of extended memory.
  303.  
  304. ******************* High Memory Functions ***************************
  305. boolean XMSDriver::InstHMA( void )
  306. ----------------------------------
  307. This function determines whether or not the High Memory Area has been
  308. allocated.  It returns True if the high memory area is available,
  309. False if not.
  310.  
  311. boolean XMSDriver::ReqHMA( void )
  312. ---------------------------------
  313. This function requests use of the High Memory Area from HIMEM.SYS. 
  314. It returns True if HMA access is granted to the application, False
  315. otherwise.  Only allocate the HMA if you plan to use a good portion
  316. of it, as other applications may need the HMA.  The HMA is only given
  317. out as one large block to an application, so use it wisely.  Also,
  318. don't forget to cleanup after yourself (where have I heard that
  319. before?) and release the HMA when you are through.
  320.  
  321. void XMSDriver::RelHMA( void )
  322. ------------------------------
  323. This function attempts to free the High Memory Area.  There is no
  324. return, because the only way the High Memory Area could be not
  325. released is if you didn't own it in the first place, or if it didn't
  326. exist.
  327.  
  328. ********A20 line functions
  329. Recall that the HMA is possible because the 286+ machines have
  330. additional address lines (the 21st line in particular).  The A20 line
  331. is off on the 286 by default, because some applications depend on the
  332. wrap around at the top (I have no idea what applications depend on
  333. this, but that's what Microsoft says).  In order to use the HMA, you
  334. must enable the A20 address line.  Don't forget to disable it after
  335. you are through.
  336.  
  337. boolean XMSDriver::A20Enable( void )
  338. ------------------------------------
  339. This function attempts to enable the A20 line so folks like you can
  340. access the HMA.  It returns True when the A20 line has been
  341. successfully enabled.
  342.  
  343. void XMSDriver::A20Disable( void )
  344. ----------------------------------
  345. This function disables the A20 line.  There is no return value.
  346.  
  347. boolean XMSDriver::A20LEnable( void )
  348. -------------------------------------
  349. This function enables the A20 line locally.  I'm not quite sure what
  350. this means, but I suspect it's so you can enable the line and not
  351. worry about the state of line currently.  In other words, you can
  352. enable the line for your own purposes, regardless of the current
  353. state of the A20 line.  You need to perform a local disable when
  354. you're through.
  355.  
  356. void XMSDriver::A20LDisable( void )
  357. ------------------------------------
  358. "Locally Disable the A20 line" this function has been dubbed (I had
  359. to use a different intro so you wouldn't get too bored).  There is no
  360. return.
  361.  
  362. boolean XMSDriver::A20Query( void )
  363. -----------------------------------
  364. This function queries the state of the A20 line.  It returns True if
  365. the A20 line is enabled, False otherwise.
  366.  
  367. void far *HMAWrite( unsigned ItemSize, unsigned Index, unsigned Length,
  368.                 void far *Data );
  369. ----------------------------------------------------------------------
  370. This function is kind of involved, but I'll explain it as best I can. 
  371. Basically, it's a high level write to high memory area function.  It
  372. might be simpler to just maintain a pointer to the High Memory Area
  373. (the HMA begins at 0xFFFF:000A; 64k - 16 bytes long) than to use this
  374. function, but it's up to you.  This function treats the "Data" (last
  375. parameter) as an array.  Each array element is ItemSize long.  The
  376. function will begin copying at Data[ Index ], and will copy Length
  377. elements of the array (including that point).  It returns a pointer
  378. to the High Memory Area pointing to the first element if Data that
  379. was copied, or NULL if the function failed.
  380.  
  381. void far *HMARead( unsigned ItemSize, unsigned Index, unsigned Length, 
  382.                 void far *Data );
  383. ----------------------------------------------------------------------
  384. This function is similar to HMAWrite except that it reads from the
  385. High Memory Area, and returns a pointer to Data (NULL on failure). 
  386. It treats the High Memory Area as an array, each element is ItemSize
  387. bytes long.  It copies Length elements starting at the beginning of
  388. the High Memory Area + Index (in other words, it starts reading at
  389. Index offset into the HMA).  It copies all this junk into Data, and
  390. returns the pointer to Data (NULL on failure, as I already said 5 or
  391. 6 lines up).
  392.  
  393. **End of High Memory Area Management Functions (what a mouth full)
  394.  
  395. **************** Extended Memory Block functions
  396. The following functions allow the management of extended memory. 
  397. Basically, you call a function requesting some extended memory.  The
  398. function returns a handle to that memory, and you use that handle to
  399. access the memory block later.  Every time you allocate a block of
  400. extended memory, you are getting what's called an Extended Memory
  401. Block (EMB).  You must use the handle to use the EMB.  For your
  402. convenience, I have provided some routines to copy blocks of data to
  403. and from extended memory.  Actually, I think that you are forced to
  404. use them, whether or not you want to.
  405.  
  406. By the way, one of the Extended Memory Block Management Functions in
  407. Microsoft's HiMEM.SYS is not implemented.  That is function 0x0E -
  408. Query Extended Memory block.  It's used to get info on the Extended
  409. Memory Block.  I will implement it later, so don't cry.
  410.  
  411. NOTE: For from-to extended memory transfers, 'size' must be even. The
  412. function will not succeed unless size is even.  It's also advisable to
  413. word align data you store in the EMB because they generally run much
  414. faster on 2/3/486 type machines.
  415.  
  416. unsigned XMSDriver::EMBAlloc( unsigned size )
  417. ---------------------------------------------
  418. This routine will try as hard as it can to allocate a block of
  419. extended memory 'size' bytes in length.  It returns a handle to the
  420. EMB on success, otherwise it will return 0.  The location of this
  421. block in extended memory is not known as it may be moved around by
  422. the driver to relieve fragmentation.
  423.  
  424. void XMSDriver::EMBFree( unsigned handle )
  425. ------------------------------------------
  426. This function frees the handle specified by 'handle.'  There is no
  427. return.
  428.  
  429. long XMSDriver::EMBLock( unsigned handle )
  430. ------------------------------------------
  431. I'm not totally sure I understand what this is for, but I'll take a
  432. stab.  This function locks a previously allocated EMB.  Locking the
  433. block guarantees that the HIMEM driver will NOT move it around.  This
  434. way, you can get direct access to the block using the BIOS routines,
  435. or whatever.  This function returns a 32-bit linear address pointer
  436. to the extended memory block, or 0 if an error occurred.
  437.  
  438. boolean XMSDriver::EMBUnlock( unsigned handle )
  439. --------------------------------------------
  440. This function releases the lock that was put on the handle
  441. previously.  Lock counts are maintained, meaning if you lock a block
  442. 3 times, you have to unlock it 3 times as well before it is actually
  443. unlocked (I guess).  It returns True on success, False on failure (so
  444. don't make me feel like a failure and send money or 10 pages of
  445. praise) (just kidding) (not) (way) (no way)...
  446.  
  447. boolean XMSDriver::EMBMoveToExt( unsigned dhandle, unsigned doff,
  448.                             void far *p, long size );
  449. -----------------------------------------------------------------
  450. This function moves a block of conventional memory to extended
  451. memory.  Actually, it really copies the block as opposed to freeing
  452. it.  dhandle is the handle of the destination EMB, and doff is the
  453. offset into the EMB to begin the transfer.  It returns True if the
  454. move was a success, False if it failed.  By the way, 'size' is the
  455. size of the block to move in bytes.
  456.  
  457. boolean XMSDriver::EMBMoveToCon( void far *p,
  458.                             unsigned shandle, unsigned soff,
  459.                             long size );
  460. ------------------------------------------------------------------
  461. This function moves a block of extended memory to conventional memory
  462. (the pointer *p).  shandle is the handle number of the source EMB,
  463. and soff is the offset into the shandle to begin copying.  'size' is
  464. the size in bytes to transfer.  Returns True on success and False on
  465. failure (say, you wouldn't happen to see a pattern in the return
  466. values, would you?).
  467.  
  468. boolean XMSDriver::EMBExtToExt( unsigned dhandle, unsigned doff,
  469.                             unsigned shandle, unsigned soff 
  470.                             long size);
  471. --------------------------------------------------------------------
  472. This function copies data from one EMB to another EMB.  dhandle and
  473. shandle are the destination and source handles respectively (gee, i
  474. bet you would've never guessed that) and doff and soff the offsets
  475. into the block.  'size' is the size in bytes of the transfer.  It
  476. returns True on success, and False on failure.
  477.  
  478. ********************* The End (almost) *****************************
  479. I know it seems like there's is no end in site for this document. 
  480. Well, just scroll down a few more lines and then you can start
  481. partying to your heart's content.  Just some parting words...
  482.  
  483. I worked pretty hard on this, and it's still far from perfect (what a
  484. bummer, dude).  I released it in it's "far from perfect" state
  485. because I wanted to see if it was worth all the time I spent.  This
  486. is why it's very important that I get some feedback from you guys. 
  487. It's also a way for me to assess whether or not it's worth it for me
  488. to program all kinds of apps and libraries for other people.  It's
  489. hard to find friends who do this kind of system level programming, so
  490. I'm on my own on most of this stuff.
  491.  
  492. Thanks for reading this far into the document (assuming you read this
  493. far).  See ya!
  494.