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.
15 * $Source: /cvs/cvsroot/d2x/arch/dos/dpmi.c,v $
18 * $Date: 2001-10-19 09:01:56 $
22 * $Log: not supported by cvs2svn $
23 * Revision 1.2 2001/01/29 13:35:08 bradleyb
24 * Fixed build system, minor fixes
33 #define _BORLAND_DOS_REGS 1
35 #include <sys/segments.h>
36 #include <sys/nearptr.h>
38 #define FP_SEG(p) _my_ds()
39 #define FP_OFF(p) (int)p
40 int _crt0_startup_flags=_CRT0_FLAG_NONMOVE_SBRK+_CRT0_FLAG_FILL_SBRK_MEMORY+_CRT0_FLAG_FILL_DEADBEEF+_CRT0_FLAG_NEARPTR+_CRT0_FLAG_NO_LFN;
54 int dpmi_find_dos_memory()
58 memset(&r,0,sizeof(r));
59 r.x.eax = 0x0100; // DPMI allocate DOS memory
60 r.x.ebx = 0xffff; // Number of paragraphs requested
61 int386 (0x31, &r, &r);
62 //if ( (r.x.eax & 0xffff) == 0x08 )
63 //if ( (r.x.eax & 0xffff) == 0x08 )
65 return ((r.x.ebx & 0xffff)*16);
70 void *dpmi_real_malloc( int size, ushort *selector )
74 memset(&r,0,sizeof(r));
75 r.x.eax = 0x0100; // DPMI allocate DOS memory
76 r.x.ebx = (size + 15) >> 4; // Number of paragraphs requested
77 int386 (0x31, &r, &r);
79 if (r.x.cflag) // Failed
83 *selector = r.x.edx & 0xFFFF;
86 return (void *) ((r.x.eax & 0xFFFF) << 4)+__djgpp_conventional_base;
88 return (void *) ((r.x.eax & 0xFFFF) << 4);
92 void dpmi_real_free( ushort selector )
96 memset(&r,0,sizeof(r));
97 r.x.eax = 0x0101; // DPMI free DOS memory
98 r.x.ebx = selector; // Selector to free
99 int386 (0x31, &r, &r);
102 int dos_stack_initialized = 0;
103 ubyte * dos_stack = NULL;
104 ubyte * dos_stack_top = NULL;
105 #define DOS_STACK_SIZE (4*1024) // A big ol' 4K stack!!!
107 static void dpmi_setup_stack(dpmi_real_regs *rregs) {
108 ushort temp_selector;
110 if ( !dos_stack_initialized ) {
111 dos_stack_initialized = 1;
112 dos_stack = dpmi_real_malloc( DOS_STACK_SIZE, &temp_selector );
113 if ( dos_stack == NULL ) {
114 printf( "Error allocating real mode stack!\n" );
115 dos_stack_top = NULL;
117 dos_stack_top = &dos_stack[DOS_STACK_SIZE];
121 // Give this puppy a stack!!!
122 if ( dos_stack_top ) {
123 rregs->ss = DPMI_real_segment(dos_stack_top);
124 rregs->sp = DPMI_real_offset(dos_stack_top);
129 void dpmi_real_int386x( ubyte intno, dpmi_real_regs * rregs )
134 /* Use DMPI call 300h to issue the DOS interrupt */
136 dpmi_setup_stack(rregs);
137 memset(®s,0,sizeof(regs));
138 memset(&sregs,0,sizeof(sregs));
143 sregs.es = FP_SEG(rregs);
144 regs.x.edi = FP_OFF(rregs);
145 int386x( 0x31, ®s, ®s, &sregs );
148 void dpmi_real_call(dpmi_real_regs * rregs)
153 dpmi_setup_stack(rregs);
155 /* Use DMPI call 301h to call real mode procedure */
156 memset(®s,0,sizeof(regs));
157 memset(&sregs,0,sizeof(sregs));
161 sregs.es = FP_SEG(rregs);
162 regs.x.edi = FP_OFF(rregs);
163 int386x( 0x31, ®s, ®s, &sregs );
170 int dpmi_unlock_region(void *address, unsigned length)
175 linear = (unsigned int) address;
177 linear += __djgpp_base_address;
180 total_bytes -= length;
181 //mprintf( 1, "DPMI unlocked %d bytes\n", total_bytes );
183 memset(®s,0,sizeof(regs));
184 regs.w.ax = 0x601; // DPMI Unlock Linear Region
185 regs.w.bx = (linear >> 16); // Linear address in BX:CX
186 regs.w.cx = (linear & 0xFFFF);
188 regs.w.si = (length >> 16); // Length in SI:DI
189 regs.w.di = (length & 0xFFFF);
190 int386 (0x31, ®s, ®s);
191 return (! regs.w.cflag); // Return 0 if can't lock
194 int dpmi_lock_region(void *address, unsigned length)
199 linear = (unsigned int) address;
201 linear += __djgpp_base_address;
204 total_bytes += length;
205 //mprintf( 1, "DPMI Locked down %d bytes\n", total_bytes );
207 memset(®s,0,sizeof(regs));
208 regs.w.ax = 0x600; // DPMI Lock Linear Region
209 regs.w.bx = (linear >> 16); // Linear address in BX:CX
210 regs.w.cx = (linear & 0xFFFF);
212 regs.w.si = (length >> 16); // Length in SI:DI
213 regs.w.di = (length & 0xFFFF);
214 int386 (0x31, ®s, ®s);
215 return (! regs.w.cflag); // Return 0 if can't lock
219 int dpmi_modify_selector_base( ushort selector, void * address )
224 linear = (unsigned int)address;
226 linear += __djgpp_base_address;
229 memset(®s,0,sizeof(regs));
230 regs.w.ax = 0x0007; // DPMI Change Selector Base Addres
231 regs.w.bx = selector; // Selector to change
232 regs.w.cx = (linear >> 16); // Base address
233 regs.w.dx = (linear & 0xFFFF);
234 int386 (0x31, ®s, ®s); // call dpmi
236 return 0; // Return 0 if error
242 int dpmi_modify_selector_limit( ushort selector, int size )
245 unsigned int segment_limit;
247 segment_limit = (unsigned int) size;
249 memset(®s,0,sizeof(regs));
250 regs.w.ax = 0x0008; // DPMI Change Selector Limit
251 regs.w.bx = selector; // Selector to change
252 regs.w.cx = (segment_limit >> 16); // Size of selector
253 regs.w.dx = (segment_limit & 0xFFFF);
254 int386 (0x31, ®s, ®s); // call dpmi
256 return 0; // Return 0 if error
262 int dpmi_allocate_selector( void * address, int size, ushort * selector )
267 memset(®s,0,sizeof(regs));
268 regs.w.ax = 0; // DPMI Allocate Selector
269 regs.w.cx = 1; // Allocate 1 selector
270 int386 (0x31, ®s, ®s); // call dpmi
272 return 0; // Return 0 if error
273 *selector = regs.w.ax;
275 if ( !dpmi_modify_selector_base( *selector, address ) )
278 if ( !dpmi_modify_selector_limit( *selector, size ) )
281 // mprintf( 0, "Selector 0x%4x has base of 0x%8x, size %d bytes\n", *selector, linear,segment_limit);
286 static void * dpmi_dos_buffer = NULL;
287 static ushort dpmi_dos_selector = 0;
291 if (dpmi_dos_selector!=0) {
292 dpmi_dos_buffer = NULL;
293 dpmi_dos_selector = 0;
297 typedef struct mem_data {
298 int largest_block_bytes;
299 int max_unlocked_page_allocation;
300 int largest_lockable_pages;
303 int unused_physical_pages;
304 int total_physical_pages;
305 int free_linear_pages;
306 int paging_size_pages;
310 unsigned int dpmi_virtual_memory=0;
311 unsigned int dpmi_available_memory=0;
312 unsigned int dpmi_physical_memory=0;
313 unsigned int dpmi_dos_memory = 0;
316 extern void cdecl _GETDS();
317 extern void cdecl cstart_();
320 int dpmi_init(int verbose)
326 dpmi_dos_memory = dpmi_find_dos_memory();
328 dpmi_dos_buffer = dpmi_real_malloc( 1024, &dpmi_dos_selector);
329 if (!dpmi_dos_buffer) {
330 dpmi_dos_selector = 0;
331 printf( "Error allocating 1K of DOS memory\n" );
337 memset(®s,0,sizeof(regs));
338 regs.x.eax = 0x400; // DPMI Get Memory Info
339 int386( 0x31, ®s, ®s );
341 if (verbose) printf( "V%d.%d, CPU:%d, VMM:", regs.h.ah, regs.h.al, regs.h.cl );
343 if (verbose) printf( "1" );
344 dpmi_virtual_memory = 1;
346 if (verbose) printf( "0" );
350 //--------- Find available memory
351 memset(®s,0,sizeof(regs));
352 memset(&sregs,0,sizeof(sregs));
353 regs.x.eax = 0x500; // DPMI Get Memory Info
354 sregs.es = FP_SEG(&mi);
355 regs.x.edi = FP_OFF(&mi);
356 int386x( 0x31, ®s, ®s, &sregs );
358 if (verbose) printf( ", P:%dK", mi.largest_lockable_pages*4 );
359 if (dpmi_virtual_memory)
360 if (verbose) printf( ", A:%dK", mi.largest_block_bytes/1024 );
361 //dpmi_physical_memory = mi.largest_lockable_pages*4096;
362 //dpmi_available_memory = mi.largest_block_bytes;
363 dpmi_physical_memory = mi.total_physical_pages*4096;
364 dpmi_available_memory = mi.total_pages * 4096;
366 if (verbose) printf( "MemInfo failed!" );
367 dpmi_physical_memory = 16*1024*1024; // Assume 16 MB
368 dpmi_available_memory = 16*1024*1024; // Assume 16 MB
372 if (!dpmi_lock_region( _GETDS, 4096 )) {
373 printf( "Error locking _GETDS" );
376 if (!dpmi_lock_region( cstart_, 4096 )) {
377 printf( "Error locking cstart" );
380 if (!dpmi_lock_region( _chain_intr, 4096 )) {
381 printf( "Error locking _chain_intr" );
388 void *dpmi_get_temp_low_buffer( int size )
390 if ( dpmi_dos_buffer == NULL ) return NULL;
391 if ( size > 1024 ) return NULL;
393 return dpmi_dos_buffer;
396 int dpmi_set_pm_handler(unsigned intnum, void far * isr )
400 /* Use DMPI call 204h to get pm interrrupt */
401 memset(®s,0,sizeof(regs));
404 regs.w.cx = FP_SEG(isr);
405 regs.x.edx = FP_OFF(isr);
406 int386( 0x31, ®s, ®s );