home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / bios / dpmi.c < prev    next >
Text File  |  1998-06-08  |  12KB  |  438 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/bios/rcs/dpmi.c $
  15.  * $Revision: 1.19 $
  16.  * $Author: john $
  17.  * $Date: 1995/02/23 09:02:57 $
  18.  * 
  19.  * Routines that access DPMI services...
  20.  * 
  21.  * $Log: dpmi.c $
  22.  * Revision 1.19  1995/02/23  09:02:57  john
  23.  * Fixed bug with dos_selector.
  24.  * 
  25.  * Revision 1.18  1995/02/02  11:10:22  john
  26.  * Made real mode calls have a 2K stack.
  27.  * 
  28.  * Revision 1.17  1995/01/14  19:20:28  john
  29.  * Added function to set a selector's base address.
  30.  * 
  31.  * Revision 1.16  1994/12/14  16:11:40  john
  32.  * Locked down the memory referenced by GETDS.
  33.  * 
  34.  * Revision 1.15  1994/12/06  16:08:06  john
  35.  * MAde memory checking return better results.
  36.  * 
  37.  * Revision 1.14  1994/12/05  23:34:54  john
  38.  * Made dpmi_init lock down GETDS and chain_intr.
  39.  * 
  40.  * Revision 1.13  1994/11/28  21:19:02  john
  41.  * Made memory checking a bit better.
  42.  * 
  43.  * Revision 1.12  1994/11/28  20:22:18  john
  44.  * Added some variables that return the amount of available 
  45.  * memory.
  46.  * 
  47.  * Revision 1.11  1994/11/15  18:27:21  john
  48.  * *** empty log message ***
  49.  * 
  50.  * Revision 1.10  1994/11/15  18:26:45  john
  51.  * Added verbose flag.
  52.  * 
  53.  * Revision 1.9  1994/10/27  19:54:37  john
  54.  * Added unlock region function,.
  55.  * 
  56.  * Revision 1.8  1994/10/05  16:17:31  john
  57.  * Took out locked down message.
  58.  * 
  59.  * Revision 1.7  1994/10/03  17:21:20  john
  60.  * Added the code that allocates a 1K DOS buffer.
  61.  * 
  62.  * Revision 1.6  1994/09/29  18:29:40  john
  63.  * Shorted mem info printout
  64.  * 
  65.  * Revision 1.5  1994/09/27  11:54:35  john
  66.  * Added DPMI init function.
  67.  * 
  68.  * Revision 1.4  1994/09/19  14:50:43  john
  69.  * Took out mono debug.
  70.  * 
  71.  * Revision 1.3  1994/09/19  14:41:23  john
  72.  * Fixed some bugs with allocating selectors.
  73.  * 
  74.  * Revision 1.2  1994/08/24  18:53:51  john
  75.  * Made Cyberman read like normal mouse; added dpmi module; moved
  76.  * mouse from assembly to c. Made mouse buttons return time_down.
  77.  * 
  78.  * Revision 1.1  1994/08/24  10:22:34  john
  79.  * Initial revision
  80.  * 
  81.  * 
  82.  */
  83.  
  84.  
  85. #pragma off (unreferenced)
  86. static char rcsid[] = "$Id: dpmi.c 1.19 1995/02/23 09:02:57 john Exp $";
  87. #pragma on (unreferenced)
  88.  
  89. #include <i86.h>
  90. #include <dos.h>
  91. #include <stdio.h>
  92. #include <string.h>
  93. #include <malloc.h>
  94. #include <stdlib.h>
  95. #include <conio.h>
  96.  
  97. #include "types.h"
  98. #include "mono.h"
  99. #include "error.h"
  100. #include "dpmi.h"
  101.  
  102. int dpmi_find_dos_memory()
  103. {
  104.     union REGS r;
  105.  
  106.     memset(&r,0,sizeof(r));
  107.     r.x.eax = 0x0100;                // DPMI allocate DOS memory 
  108.     r.x.ebx = 0xffff;    // Number of paragraphs requested
  109.     int386 (0x31, &r, &r);
  110.     //if ( (r.x.eax & 0xffff) == 0x08 )
  111.     //if ( (r.x.eax & 0xffff) == 0x08 )
  112.     if ( r.x.cflag )
  113.         return ((r.x.ebx & 0xffff)*16);
  114.     else
  115.         return 640*1024;
  116. }
  117.  
  118. void *dpmi_real_malloc( int size, ushort *selector )
  119. {
  120.     union REGS r;
  121.  
  122.     memset(&r,0,sizeof(r));
  123.     r.x.eax = 0x0100;                // DPMI allocate DOS memory 
  124.     r.x.ebx = (size + 15) >> 4;    // Number of paragraphs requested
  125.     int386 (0x31, &r, &r);
  126.  
  127.     if (r.x.cflag)  // Failed
  128.         return ((uint) 0);
  129.  
  130.     if(selector!=NULL)
  131.         *selector = r.x.edx & 0xFFFF;
  132.  
  133.     return (void *) ((r.x.eax & 0xFFFF) << 4);
  134. }
  135.  
  136. void dpmi_real_free( ushort selector )
  137. {
  138.     union REGS r;
  139.  
  140.     memset(&r,0,sizeof(r));
  141.     r.x.eax = 0x0101;                // DPMI free DOS memory 
  142.     r.x.ebx = selector;            // Selector to free
  143.     int386 (0x31, &r, &r);
  144. }
  145.  
  146.  
  147. void dpmi_real_int386x( ubyte intno, dpmi_real_regs * rregs )
  148. {
  149.     union REGS regs;
  150.     struct SREGS sregs;
  151.  
  152.     /* Use DMPI call 300h to issue the DOS interrupt */
  153.  
  154.     memset(®s,0,sizeof(regs));
  155.     memset(&sregs,0,sizeof(sregs));
  156.    regs.w.ax = 0x0300;
  157.    regs.h.bl = intno;
  158.    regs.h.bh = 0;
  159.    regs.w.cx = 0;
  160.    sregs.es = FP_SEG(rregs);
  161.    regs.x.edi = FP_OFF(rregs);
  162.    int386x( 0x31, ®s, ®s, &sregs );
  163. }
  164.  
  165. int dos_stack_initialized = 0;
  166. ubyte * dos_stack = NULL;
  167. ubyte * dos_stack_top = NULL;
  168. #define DOS_STACK_SIZE (4*1024)            // A big ol' 4K stack!!!
  169.  
  170. void dpmi_real_call(dpmi_real_regs * rregs)
  171. {
  172.     ushort temp_selector;
  173.     union REGS regs;
  174.     struct SREGS sregs;
  175.  
  176.     if ( !dos_stack_initialized )    {
  177.         dos_stack_initialized = 1;
  178.         dos_stack = dpmi_real_malloc( DOS_STACK_SIZE, &temp_selector );
  179.         if ( dos_stack == NULL )    {
  180.             printf( "Error allocating real mode stack!\n" );
  181.             dos_stack_top = NULL;
  182.         } else {
  183.             dos_stack_top = &dos_stack[DOS_STACK_SIZE];
  184.         }
  185.     }
  186.     
  187.     // Give this puppy a stack!!!
  188.     if ( dos_stack_top )    {
  189.         rregs->ss = DPMI_real_segment(dos_stack_top);
  190.         rregs->sp = DPMI_real_offset(dos_stack_top);
  191.     }
  192.  
  193.     /* Use DMPI call 301h to call real mode procedure */
  194.     memset(®s,0,sizeof(regs));
  195.     memset(&sregs,0,sizeof(sregs));
  196.    regs.w.ax = 0x0301;
  197.    regs.h.bh = 0;
  198.    regs.w.cx = 0;
  199.    sregs.es = FP_SEG(rregs);
  200.    regs.x.edi = FP_OFF(rregs);
  201.    int386x( 0x31, ®s, ®s, &sregs );
  202.     if ( regs.x.cflag )
  203.         exit(regs.w.ax);
  204. }
  205.  
  206. int total_bytes = 0;
  207.  
  208. int dpmi_unlock_region(void *address, unsigned length)
  209. {
  210.     union REGS regs;
  211.     unsigned int linear;
  212.  
  213.     linear = (unsigned int) address;
  214.  
  215.     total_bytes -= length;
  216.     //mprintf( 1, "DPMI unlocked %d bytes\n", total_bytes );
  217.  
  218.     memset(®s,0,sizeof(regs));
  219.     regs.w.ax = 0x601;                    // DPMI Unlock Linear Region
  220.     regs.w.bx = (linear >> 16);        // Linear address in BX:CX
  221.     regs.w.cx = (linear & 0xFFFF);
  222.  
  223.     regs.w.si = (length >> 16);        // Length in SI:DI
  224.     regs.w.di = (length & 0xFFFF);
  225.     int386 (0x31, ®s, ®s);
  226.     return (! regs.w.cflag);            // Return 0 if can't lock
  227. }
  228.  
  229. int dpmi_lock_region(void *address, unsigned length)
  230. {
  231.     union REGS regs;
  232.     unsigned int linear;
  233.  
  234.     linear = (unsigned int) address;
  235.  
  236.     total_bytes += length;
  237.     //mprintf( 1, "DPMI Locked down %d bytes\n", total_bytes );
  238.  
  239.     memset(®s,0,sizeof(regs));
  240.     regs.w.ax = 0x600;                    // DPMI Lock Linear Region
  241.     regs.w.bx = (linear >> 16);        // Linear address in BX:CX
  242.     regs.w.cx = (linear & 0xFFFF);
  243.  
  244.     regs.w.si = (length >> 16);        // Length in SI:DI
  245.     regs.w.di = (length & 0xFFFF);
  246.     int386 (0x31, ®s, ®s);
  247.     return (! regs.w.cflag);            // Return 0 if can't lock
  248. }
  249.  
  250.  
  251. int dpmi_modify_selector_base( ushort selector, void * address )
  252. {
  253.     union REGS regs;
  254.     unsigned int linear;
  255.  
  256.     linear = (unsigned int)address;
  257.  
  258.     memset(®s,0,sizeof(regs));
  259.     regs.w.ax = 0x0007;                    // DPMI Change Selector Base Addres
  260.     regs.w.bx = selector;                // Selector to change
  261.     regs.w.cx = (linear >> 16);        // Base address
  262.     regs.w.dx = (linear & 0xFFFF);
  263.     int386 (0x31, ®s, ®s);        // call dpmi
  264.     if (regs.w.cflag)
  265.         return 0;                            // Return 0 if error
  266.  
  267.     return 1;
  268. }
  269.  
  270.  
  271. int dpmi_modify_selector_limit( ushort selector, int size  )
  272. {
  273.     union REGS regs;
  274.     unsigned int segment_limit;
  275.  
  276.     segment_limit = (unsigned int) size;
  277.  
  278.     memset(®s,0,sizeof(regs));
  279.     regs.w.ax = 0x0008;                    // DPMI Change Selector Limit
  280.     regs.w.bx = selector;                // Selector to change
  281.     regs.w.cx = (segment_limit >> 16);        // Size of selector
  282.     regs.w.dx = (segment_limit & 0xFFFF);
  283.     int386 (0x31, ®s, ®s);        // call dpmi
  284.     if (regs.w.cflag)
  285.         return 0;                            // Return 0 if error
  286.  
  287.     return 1;
  288. }
  289.  
  290.  
  291. int dpmi_allocate_selector( void * address, int size, ushort * selector )
  292. {
  293.     union REGS regs;
  294.  
  295.  
  296.     memset(®s,0,sizeof(regs));
  297.     regs.w.ax = 0;                            // DPMI Allocate Selector
  298.     regs.w.cx = 1;                            // Allocate 1 selector
  299.     int386 (0x31, ®s, ®s);        // call dpmi
  300.     if (regs.w.cflag)
  301.         return 0;                            // Return 0 if error
  302.     *selector = regs.w.ax;
  303.  
  304.     if ( !dpmi_modify_selector_base( *selector, address ) )
  305.         return 0;
  306.  
  307.     if ( !dpmi_modify_selector_limit( *selector, size ) )
  308.         return 0;
  309.  
  310. //    mprintf( 0, "Selector 0x%4x has base of 0x%8x, size %d bytes\n", *selector, linear,segment_limit);
  311.  
  312.     return 1;
  313. }
  314.  
  315. static void * dpmi_dos_buffer = NULL;
  316. static ushort dpmi_dos_selector = 0;
  317.  
  318. void dpmi_close()
  319. {
  320.     if (dpmi_dos_selector!=0)    {
  321.         dpmi_dos_buffer = NULL;
  322.         dpmi_dos_selector = 0;
  323.     }
  324. }
  325.  
  326. typedef struct mem_data {
  327.     int    largest_block_bytes;
  328.     int    max_unlocked_page_allocation;
  329.     int    largest_lockable_pages;
  330.     int    total_pages;
  331.     int    unlocked_pages;
  332.     int    unused_physical_pages;
  333.     int    total_physical_pages;
  334.     int     free_linear_pages;
  335.     int    paging_size_pages;
  336.     int    reserved[3];
  337. } mem_data;
  338.  
  339. unsigned int dpmi_virtual_memory=0;
  340. unsigned int dpmi_available_memory=0;
  341. unsigned int dpmi_physical_memory=0;
  342. unsigned int dpmi_dos_memory = 0;
  343.  
  344. extern void cdecl _GETDS();
  345. extern void cdecl cstart_();
  346.  
  347. int dpmi_init(int verbose)
  348. {
  349.     union REGS regs;
  350.     struct SREGS sregs;
  351.     mem_data mi;
  352.  
  353.     dpmi_dos_memory = dpmi_find_dos_memory();
  354.     
  355.     dpmi_dos_buffer = dpmi_real_malloc( 1024, &dpmi_dos_selector);
  356.     if (!dpmi_dos_buffer) {
  357.         dpmi_dos_selector = 0;
  358.         printf( "Error allocating 1K of DOS memory\n" );
  359.         exit(1);
  360.     }
  361.     atexit(dpmi_close);
  362.  
  363.     // Check dpmi
  364.     memset(®s,0,sizeof(regs));
  365.     regs.x.eax = 0x400;                            // DPMI Get Memory Info
  366.    int386( 0x31, ®s, ®s );
  367.     if (!regs.w.cflag)    {
  368.         if (verbose) printf( "V%d.%d, CPU:%d, VMM:", regs.h.ah, regs.h.al, regs.h.cl );
  369.         if (regs.w.bx & 4)    {
  370.             if (verbose) printf( "1" );
  371.             dpmi_virtual_memory = 1;
  372.         } else {
  373.              if (verbose) printf( "0" );
  374.         }
  375.     }
  376.  
  377.     //--------- Find available memory
  378.     memset(®s,0,sizeof(regs));
  379.     memset(&sregs,0,sizeof(sregs));
  380.     regs.x.eax = 0x500;                            // DPMI Get Memory Info
  381.    sregs.es = FP_SEG(&mi);
  382.    regs.x.edi = FP_OFF(&mi);
  383.    int386x( 0x31, ®s, ®s, &sregs );
  384.     if (!regs.w.cflag)    {
  385.         if (verbose) printf( ", P:%dK", mi.largest_lockable_pages*4 );
  386.         if (dpmi_virtual_memory)
  387.             if (verbose) printf( ", A:%dK", mi.largest_block_bytes/1024 );
  388.         //dpmi_physical_memory = mi.largest_lockable_pages*4096;
  389.         //dpmi_available_memory = mi.largest_block_bytes;
  390.         dpmi_physical_memory = mi.total_physical_pages*4096;
  391.         dpmi_available_memory = mi.total_pages * 4096;
  392.     } else {
  393.         if (verbose) printf( "MemInfo failed!" );
  394.         dpmi_physical_memory = 16*1024*1024;        // Assume 16 MB
  395.         dpmi_available_memory = 16*1024*1024;        // Assume 16 MB
  396.     }
  397.     
  398.     if (!dpmi_lock_region( _GETDS, 4096 ))    {
  399.         printf( "Error locking _GETDS" );
  400.         exit(1);
  401.     }
  402.     if (!dpmi_lock_region( cstart_, 4096 ))    {
  403.         printf( "Error locking cstart" );
  404.         exit(1);
  405.     }
  406.     if (!dpmi_lock_region( _chain_intr, 4096 ))    {
  407.         printf( "Error locking _chain_intr" );
  408.         exit(1);
  409.     }
  410.     return 1;
  411. }
  412.  
  413. void *dpmi_get_temp_low_buffer( int size )
  414. {
  415.     if ( dpmi_dos_buffer == NULL ) return NULL;
  416.     if ( size > 1024 ) return NULL;
  417.  
  418.     return dpmi_dos_buffer;
  419. }
  420.  
  421. int dpmi_set_pm_handler(unsigned intnum, void far * isr )
  422. {
  423.     union REGS regs;
  424.  
  425.     /* Use DMPI call 204h to get pm interrrupt */
  426.     memset(®s,0,sizeof(regs));
  427.    regs.w.ax = 0x0205;
  428.    regs.h.bl = intnum;
  429.     regs.w.cx = FP_SEG(isr);
  430.     regs.x.edx = FP_OFF(isr);
  431.     int386( 0x31, ®s, ®s );
  432.     if (!regs.w.cflag)    
  433.         return 0;
  434.     return 1;
  435. }
  436.  
  437. 
  438.