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.
14 * $Source: /cvs/cvsroot/d2x/arch/dos/dpmi.c,v $
15 * $Revision: 1.1.1.1 $
17 * $Date: 2001-01-19 03:30:15 $
19 * Routines that access DPMI services...
21 * $Log: not supported by cvs2svn $
22 * Revision 1.1.1.1 1999/06/14 21:58:16 donut
23 * Import of d1x 1.37 source.
25 * Revision 1.19 1995/02/23 09:02:57 john
26 * Fixed bug with dos_selector.
28 * Revision 1.18 1995/02/02 11:10:22 john
29 * Made real mode calls have a 2K stack.
31 * Revision 1.17 1995/01/14 19:20:28 john
32 * Added function to set a selector's base address.
34 * Revision 1.16 1994/12/14 16:11:40 john
35 * Locked down the memory referenced by GETDS.
37 * Revision 1.15 1994/12/06 16:08:06 john
38 * MAde memory checking return better results.
40 * Revision 1.14 1994/12/05 23:34:54 john
41 * Made dpmi_init lock down GETDS and chain_intr.
43 * Revision 1.13 1994/11/28 21:19:02 john
44 * Made memory checking a bit better.
46 * Revision 1.12 1994/11/28 20:22:18 john
47 * Added some variables that return the amount of available
50 * Revision 1.11 1994/11/15 18:27:21 john
51 * *** empty log message ***
53 * Revision 1.10 1994/11/15 18:26:45 john
56 * Revision 1.9 1994/10/27 19:54:37 john
57 * Added unlock region function,.
59 * Revision 1.8 1994/10/05 16:17:31 john
60 * Took out locked down message.
62 * Revision 1.7 1994/10/03 17:21:20 john
63 * Added the code that allocates a 1K DOS buffer.
65 * Revision 1.6 1994/09/29 18:29:40 john
66 * Shorted mem info printout
68 * Revision 1.5 1994/09/27 11:54:35 john
69 * Added DPMI init function.
71 * Revision 1.4 1994/09/19 14:50:43 john
72 * Took out mono debug.
74 * Revision 1.3 1994/09/19 14:41:23 john
75 * Fixed some bugs with allocating selectors.
77 * Revision 1.2 1994/08/24 18:53:51 john
78 * Made Cyberman read like normal mouse; added dpmi module; moved
79 * mouse from assembly to c. Made mouse buttons return time_down.
81 * Revision 1.1 1994/08/24 10:22:34 john
89 static char rcsid[] = "$Id: dpmi.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
93 #define _BORLAND_DOS_REGS 1
95 #include <sys/segments.h>
96 #include <sys/nearptr.h>
98 #define FP_SEG(p) _my_ds()
99 #define FP_OFF(p) (int)p
100 int _crt0_startup_flags=_CRT0_FLAG_NONMOVE_SBRK+_CRT0_FLAG_FILL_SBRK_MEMORY+_CRT0_FLAG_FILL_DEADBEEF+_CRT0_FLAG_NEARPTR+_CRT0_FLAG_NO_LFN;
116 int dpmi_find_dos_memory()
120 memset(&r,0,sizeof(r));
121 r.x.eax = 0x0100; // DPMI allocate DOS memory
122 r.x.ebx = 0xffff; // Number of paragraphs requested
123 int386 (0x31, &r, &r);
124 //if ( (r.x.eax & 0xffff) == 0x08 )
125 //if ( (r.x.eax & 0xffff) == 0x08 )
127 return ((r.x.ebx & 0xffff)*16);
132 void *dpmi_real_malloc( int size, ushort *selector )
136 memset(&r,0,sizeof(r));
137 r.x.eax = 0x0100; // DPMI allocate DOS memory
138 r.x.ebx = (size + 15) >> 4; // Number of paragraphs requested
139 int386 (0x31, &r, &r);
141 if (r.x.cflag) // Failed
145 *selector = r.x.edx & 0xFFFF;
148 return (void *) ((r.x.eax & 0xFFFF) << 4)+__djgpp_conventional_base;
150 return (void *) ((r.x.eax & 0xFFFF) << 4);
154 void dpmi_real_free( ushort selector )
158 memset(&r,0,sizeof(r));
159 r.x.eax = 0x0101; // DPMI free DOS memory
160 r.x.ebx = selector; // Selector to free
161 int386 (0x31, &r, &r);
164 int dos_stack_initialized = 0;
165 ubyte * dos_stack = NULL;
166 ubyte * dos_stack_top = NULL;
167 #define DOS_STACK_SIZE (4*1024) // A big ol' 4K stack!!!
169 static void dpmi_setup_stack(dpmi_real_regs *rregs) {
170 ushort temp_selector;
172 if ( !dos_stack_initialized ) {
173 dos_stack_initialized = 1;
174 dos_stack = dpmi_real_malloc( DOS_STACK_SIZE, &temp_selector );
175 if ( dos_stack == NULL ) {
176 printf( "Error allocating real mode stack!\n" );
177 dos_stack_top = NULL;
179 dos_stack_top = &dos_stack[DOS_STACK_SIZE];
183 // Give this puppy a stack!!!
184 if ( dos_stack_top ) {
185 rregs->ss = DPMI_real_segment(dos_stack_top);
186 rregs->sp = DPMI_real_offset(dos_stack_top);
191 void dpmi_real_int386x( ubyte intno, dpmi_real_regs * rregs )
196 /* Use DMPI call 300h to issue the DOS interrupt */
198 dpmi_setup_stack(rregs);
199 memset(®s,0,sizeof(regs));
200 memset(&sregs,0,sizeof(sregs));
205 sregs.es = FP_SEG(rregs);
206 regs.x.edi = FP_OFF(rregs);
207 int386x( 0x31, ®s, ®s, &sregs );
210 void dpmi_real_call(dpmi_real_regs * rregs)
215 dpmi_setup_stack(rregs);
217 /* Use DMPI call 301h to call real mode procedure */
218 memset(®s,0,sizeof(regs));
219 memset(&sregs,0,sizeof(sregs));
223 sregs.es = FP_SEG(rregs);
224 regs.x.edi = FP_OFF(rregs);
225 int386x( 0x31, ®s, ®s, &sregs );
232 int dpmi_unlock_region(void *address, unsigned length)
237 linear = (unsigned int) address;
239 linear += __djgpp_base_address;
242 total_bytes -= length;
243 //mprintf( 1, "DPMI unlocked %d bytes\n", total_bytes );
245 memset(®s,0,sizeof(regs));
246 regs.w.ax = 0x601; // DPMI Unlock Linear Region
247 regs.w.bx = (linear >> 16); // Linear address in BX:CX
248 regs.w.cx = (linear & 0xFFFF);
250 regs.w.si = (length >> 16); // Length in SI:DI
251 regs.w.di = (length & 0xFFFF);
252 int386 (0x31, ®s, ®s);
253 return (! regs.w.cflag); // Return 0 if can't lock
256 int dpmi_lock_region(void *address, unsigned length)
261 linear = (unsigned int) address;
263 linear += __djgpp_base_address;
266 total_bytes += length;
267 //mprintf( 1, "DPMI Locked down %d bytes\n", total_bytes );
269 memset(®s,0,sizeof(regs));
270 regs.w.ax = 0x600; // DPMI Lock Linear Region
271 regs.w.bx = (linear >> 16); // Linear address in BX:CX
272 regs.w.cx = (linear & 0xFFFF);
274 regs.w.si = (length >> 16); // Length in SI:DI
275 regs.w.di = (length & 0xFFFF);
276 int386 (0x31, ®s, ®s);
277 return (! regs.w.cflag); // Return 0 if can't lock
281 int dpmi_modify_selector_base( ushort selector, void * address )
286 linear = (unsigned int)address;
288 linear += __djgpp_base_address;
291 memset(®s,0,sizeof(regs));
292 regs.w.ax = 0x0007; // DPMI Change Selector Base Addres
293 regs.w.bx = selector; // Selector to change
294 regs.w.cx = (linear >> 16); // Base address
295 regs.w.dx = (linear & 0xFFFF);
296 int386 (0x31, ®s, ®s); // call dpmi
298 return 0; // Return 0 if error
304 int dpmi_modify_selector_limit( ushort selector, int size )
307 unsigned int segment_limit;
309 segment_limit = (unsigned int) size;
311 memset(®s,0,sizeof(regs));
312 regs.w.ax = 0x0008; // DPMI Change Selector Limit
313 regs.w.bx = selector; // Selector to change
314 regs.w.cx = (segment_limit >> 16); // Size of selector
315 regs.w.dx = (segment_limit & 0xFFFF);
316 int386 (0x31, ®s, ®s); // call dpmi
318 return 0; // Return 0 if error
324 int dpmi_allocate_selector( void * address, int size, ushort * selector )
329 memset(®s,0,sizeof(regs));
330 regs.w.ax = 0; // DPMI Allocate Selector
331 regs.w.cx = 1; // Allocate 1 selector
332 int386 (0x31, ®s, ®s); // call dpmi
334 return 0; // Return 0 if error
335 *selector = regs.w.ax;
337 if ( !dpmi_modify_selector_base( *selector, address ) )
340 if ( !dpmi_modify_selector_limit( *selector, size ) )
343 // mprintf( 0, "Selector 0x%4x has base of 0x%8x, size %d bytes\n", *selector, linear,segment_limit);
348 static void * dpmi_dos_buffer = NULL;
349 static ushort dpmi_dos_selector = 0;
353 if (dpmi_dos_selector!=0) {
354 dpmi_dos_buffer = NULL;
355 dpmi_dos_selector = 0;
359 typedef struct mem_data {
360 int largest_block_bytes;
361 int max_unlocked_page_allocation;
362 int largest_lockable_pages;
365 int unused_physical_pages;
366 int total_physical_pages;
367 int free_linear_pages;
368 int paging_size_pages;
372 unsigned int dpmi_virtual_memory=0;
373 unsigned int dpmi_available_memory=0;
374 unsigned int dpmi_physical_memory=0;
375 unsigned int dpmi_dos_memory = 0;
378 extern void cdecl _GETDS();
379 extern void cdecl cstart_();
382 int dpmi_init(int verbose)
388 dpmi_dos_memory = dpmi_find_dos_memory();
390 dpmi_dos_buffer = dpmi_real_malloc( 1024, &dpmi_dos_selector);
391 if (!dpmi_dos_buffer) {
392 dpmi_dos_selector = 0;
393 printf( "Error allocating 1K of DOS memory\n" );
399 memset(®s,0,sizeof(regs));
400 regs.x.eax = 0x400; // DPMI Get Memory Info
401 int386( 0x31, ®s, ®s );
403 if (verbose) printf( "V%d.%d, CPU:%d, VMM:", regs.h.ah, regs.h.al, regs.h.cl );
405 if (verbose) printf( "1" );
406 dpmi_virtual_memory = 1;
408 if (verbose) printf( "0" );
412 //--------- Find available memory
413 memset(®s,0,sizeof(regs));
414 memset(&sregs,0,sizeof(sregs));
415 regs.x.eax = 0x500; // DPMI Get Memory Info
416 sregs.es = FP_SEG(&mi);
417 regs.x.edi = FP_OFF(&mi);
418 int386x( 0x31, ®s, ®s, &sregs );
420 if (verbose) printf( ", P:%dK", mi.largest_lockable_pages*4 );
421 if (dpmi_virtual_memory)
422 if (verbose) printf( ", A:%dK", mi.largest_block_bytes/1024 );
423 //dpmi_physical_memory = mi.largest_lockable_pages*4096;
424 //dpmi_available_memory = mi.largest_block_bytes;
425 dpmi_physical_memory = mi.total_physical_pages*4096;
426 dpmi_available_memory = mi.total_pages * 4096;
428 if (verbose) printf( "MemInfo failed!" );
429 dpmi_physical_memory = 16*1024*1024; // Assume 16 MB
430 dpmi_available_memory = 16*1024*1024; // Assume 16 MB
434 if (!dpmi_lock_region( _GETDS, 4096 )) {
435 printf( "Error locking _GETDS" );
438 if (!dpmi_lock_region( cstart_, 4096 )) {
439 printf( "Error locking cstart" );
442 if (!dpmi_lock_region( _chain_intr, 4096 )) {
443 printf( "Error locking _chain_intr" );
450 void *dpmi_get_temp_low_buffer( int size )
452 if ( dpmi_dos_buffer == NULL ) return NULL;
453 if ( size > 1024 ) return NULL;
455 return dpmi_dos_buffer;
458 int dpmi_set_pm_handler(unsigned intnum, void far * isr )
462 /* Use DMPI call 204h to get pm interrrupt */
463 memset(®s,0,sizeof(regs));
466 regs.w.cx = FP_SEG(isr);
467 regs.x.edx = FP_OFF(isr);
468 int386( 0x31, ®s, ®s );