]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/dpmi.c
remove rcs tags
[btb/d2x.git] / arch / dos / dpmi.c
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 /*
15  *
16  * Dos DPMI
17  *
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #ifdef __DJGPP__
26 #define _BORLAND_DOS_REGS 1
27 #define far
28 #include <sys/segments.h>
29 #include <sys/nearptr.h>
30 #include <crt0.h>
31 #define FP_SEG(p) _my_ds()
32 #define FP_OFF(p) (int)p
33  int _crt0_startup_flags=_CRT0_FLAG_NONMOVE_SBRK+_CRT0_FLAG_FILL_SBRK_MEMORY+_CRT0_FLAG_FILL_DEADBEEF+_CRT0_FLAG_NEARPTR+_CRT0_FLAG_NO_LFN;
34 #endif
35
36 #include <dos.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <malloc.h>
40 #include <stdlib.h>
41
42 #include "pstypes.h"
43 #include "mono.h"
44 #include "error.h"
45 #include "u_dpmi.h"
46
47 int dpmi_find_dos_memory()
48 {
49         union REGS r;
50
51         memset(&r,0,sizeof(r));
52         r.x.eax = 0x0100;                               // DPMI allocate DOS memory 
53         r.x.ebx = 0xffff;       // Number of paragraphs requested
54         int386 (0x31, &r, &r);
55         //if ( (r.x.eax & 0xffff) == 0x08 )
56         //if ( (r.x.eax & 0xffff) == 0x08 )
57         if ( r.x.cflag )
58                 return ((r.x.ebx & 0xffff)*16);
59         else
60                 return 640*1024;
61 }
62
63 void *dpmi_real_malloc( int size, ushort *selector )
64 {
65         union REGS r;
66
67         memset(&r,0,sizeof(r));
68         r.x.eax = 0x0100;                               // DPMI allocate DOS memory 
69         r.x.ebx = (size + 15) >> 4;     // Number of paragraphs requested
70         int386 (0x31, &r, &r);
71
72         if (r.x.cflag)  // Failed
73                 return ((uint) 0);
74
75         if(selector!=NULL)
76                 *selector = r.x.edx & 0xFFFF;
77
78 #ifdef __DJGPP__
79         return (void *) ((r.x.eax & 0xFFFF) << 4)+__djgpp_conventional_base;
80 #else
81         return (void *) ((r.x.eax & 0xFFFF) << 4);
82 #endif
83 }
84
85 void dpmi_real_free( ushort selector )
86 {
87         union REGS r;
88
89         memset(&r,0,sizeof(r));
90         r.x.eax = 0x0101;                               // DPMI free DOS memory 
91         r.x.ebx = selector;                     // Selector to free
92         int386 (0x31, &r, &r);
93 }
94
95 int dos_stack_initialized = 0;
96 ubyte * dos_stack = NULL;
97 ubyte * dos_stack_top = NULL;
98 #define DOS_STACK_SIZE (4*1024)                 // A big ol' 4K stack!!!
99
100 static void dpmi_setup_stack(dpmi_real_regs *rregs)  {
101         ushort temp_selector;
102
103         if ( !dos_stack_initialized )   {
104                 dos_stack_initialized = 1;
105                 dos_stack = dpmi_real_malloc( DOS_STACK_SIZE, &temp_selector );
106                 if ( dos_stack == NULL )        {
107                         printf( "Error allocating real mode stack!\n" );
108                         dos_stack_top = NULL;
109                 } else {
110                         dos_stack_top = &dos_stack[DOS_STACK_SIZE];
111                 }
112         }
113         
114         // Give this puppy a stack!!!
115         if ( dos_stack_top )    {
116                 rregs->ss = DPMI_real_segment(dos_stack_top);
117                 rregs->sp = DPMI_real_offset(dos_stack_top);
118         }
119 }
120
121
122 void dpmi_real_int386x( ubyte intno, dpmi_real_regs * rregs )
123 {
124         union REGS regs;
125         struct SREGS sregs;
126
127     /* Use DMPI call 300h to issue the DOS interrupt */
128
129    dpmi_setup_stack(rregs);
130         memset(&regs,0,sizeof(regs));
131         memset(&sregs,0,sizeof(sregs));
132    regs.w.ax = 0x0300;
133    regs.h.bl = intno;
134    regs.h.bh = 0;
135    regs.w.cx = 0;
136    sregs.es = FP_SEG(rregs);
137    regs.x.edi = FP_OFF(rregs);
138    int386x( 0x31, &regs, &regs, &sregs );
139 }
140
141 void dpmi_real_call(dpmi_real_regs * rregs)
142 {
143         union REGS regs;
144         struct SREGS sregs;
145
146    dpmi_setup_stack(rregs);
147
148     /* Use DMPI call 301h to call real mode procedure */
149         memset(&regs,0,sizeof(regs));
150         memset(&sregs,0,sizeof(sregs));
151    regs.w.ax = 0x0301;
152    regs.h.bh = 0;
153    regs.w.cx = 0;
154    sregs.es = FP_SEG(rregs);
155    regs.x.edi = FP_OFF(rregs);
156    int386x( 0x31, &regs, &regs, &sregs );
157         if ( regs.x.cflag )
158                 exit(regs.w.ax);
159 }
160
161 int total_bytes = 0;
162
163 int dpmi_unlock_region(void *address, unsigned length)
164 {
165         union REGS regs;
166         unsigned int linear;
167
168         linear = (unsigned int) address;
169 #ifdef __DJGPP__
170         linear += __djgpp_base_address;
171 #endif
172
173         total_bytes -= length;
174         //mprintf( 1, "DPMI unlocked %d bytes\n", total_bytes );
175
176         memset(&regs,0,sizeof(regs));
177         regs.w.ax = 0x601;                                      // DPMI Unlock Linear Region
178         regs.w.bx = (linear >> 16);             // Linear address in BX:CX
179         regs.w.cx = (linear & 0xFFFF);
180
181         regs.w.si = (length >> 16);             // Length in SI:DI
182         regs.w.di = (length & 0xFFFF);
183         int386 (0x31, &regs, &regs);
184         return (! regs.w.cflag);                        // Return 0 if can't lock
185 }
186
187 int dpmi_lock_region(void *address, unsigned length)
188 {
189         union REGS regs;
190         unsigned int linear;
191
192         linear = (unsigned int) address;
193 #ifdef __DJGPP__
194         linear += __djgpp_base_address;
195 #endif
196
197         total_bytes += length;
198         //mprintf( 1, "DPMI Locked down %d bytes\n", total_bytes );
199
200         memset(&regs,0,sizeof(regs));
201         regs.w.ax = 0x600;                                      // DPMI Lock Linear Region
202         regs.w.bx = (linear >> 16);             // Linear address in BX:CX
203         regs.w.cx = (linear & 0xFFFF);
204
205         regs.w.si = (length >> 16);             // Length in SI:DI
206         regs.w.di = (length & 0xFFFF);
207         int386 (0x31, &regs, &regs);
208         return (! regs.w.cflag);                        // Return 0 if can't lock
209 }
210
211
212 int dpmi_modify_selector_base( ushort selector, void * address )
213 {
214         union REGS regs;
215         unsigned int linear;
216
217         linear = (unsigned int)address;
218 #ifdef __DJGPP__
219         linear += __djgpp_base_address;
220 #endif
221
222         memset(&regs,0,sizeof(regs));
223         regs.w.ax = 0x0007;                                     // DPMI Change Selector Base Addres
224         regs.w.bx = selector;                           // Selector to change
225         regs.w.cx = (linear >> 16);             // Base address
226         regs.w.dx = (linear & 0xFFFF);
227         int386 (0x31, &regs, &regs);            // call dpmi
228         if (regs.w.cflag)
229                 return 0;                                                       // Return 0 if error
230
231         return 1;
232 }
233
234
235 int dpmi_modify_selector_limit( ushort selector, int size  )
236 {
237         union REGS regs;
238         unsigned int segment_limit;
239
240         segment_limit = (unsigned int) size;
241
242         memset(&regs,0,sizeof(regs));
243         regs.w.ax = 0x0008;                                     // DPMI Change Selector Limit
244         regs.w.bx = selector;                           // Selector to change
245         regs.w.cx = (segment_limit >> 16);              // Size of selector
246         regs.w.dx = (segment_limit & 0xFFFF);
247         int386 (0x31, &regs, &regs);            // call dpmi
248         if (regs.w.cflag)
249                 return 0;                                                       // Return 0 if error
250
251         return 1;
252 }
253
254
255 int dpmi_allocate_selector( void * address, int size, ushort * selector )
256 {
257         union REGS regs;
258
259
260         memset(&regs,0,sizeof(regs));
261         regs.w.ax = 0;                                                  // DPMI Allocate Selector
262         regs.w.cx = 1;                                                  // Allocate 1 selector
263         int386 (0x31, &regs, &regs);            // call dpmi
264         if (regs.w.cflag)
265                 return 0;                                                       // Return 0 if error
266         *selector = regs.w.ax;
267
268         if ( !dpmi_modify_selector_base( *selector, address ) )
269                 return 0;
270
271         if ( !dpmi_modify_selector_limit( *selector, size ) )
272                 return 0;
273
274 //      mprintf( 0, "Selector 0x%4x has base of 0x%8x, size %d bytes\n", *selector, linear,segment_limit);
275
276         return 1;
277 }
278
279 static void * dpmi_dos_buffer = NULL;
280 static ushort dpmi_dos_selector = 0;
281
282 void dpmi_close()
283 {
284         if (dpmi_dos_selector!=0)       {
285                 dpmi_dos_buffer = NULL;
286                 dpmi_dos_selector = 0;
287         }
288 }
289
290 typedef struct mem_data {
291         int     largest_block_bytes;
292         int     max_unlocked_page_allocation;
293         int     largest_lockable_pages;
294         int     total_pages;
295         int     unlocked_pages;
296         int     unused_physical_pages;
297         int     total_physical_pages;
298         int     free_linear_pages;
299         int     paging_size_pages;
300         int     reserved[3];
301 } mem_data;
302
303 unsigned int dpmi_virtual_memory=0;
304 unsigned int dpmi_available_memory=0;
305 unsigned int dpmi_physical_memory=0;
306 unsigned int dpmi_dos_memory = 0;
307
308 #ifdef __WATCOMC__
309 extern void cdecl _GETDS();
310 extern void cdecl cstart_();
311 #endif
312
313 int dpmi_init(int verbose)
314 {
315         union REGS regs;
316         struct SREGS sregs;
317         mem_data mi;
318
319         dpmi_dos_memory = dpmi_find_dos_memory();
320         
321         dpmi_dos_buffer = dpmi_real_malloc( 1024, &dpmi_dos_selector);
322         if (!dpmi_dos_buffer) {
323                 dpmi_dos_selector = 0;
324                 printf( "Error allocating 1K of DOS memory\n" );
325                 exit(1);
326         }
327         atexit(dpmi_close);
328
329         // Check dpmi
330         memset(&regs,0,sizeof(regs));
331         regs.x.eax = 0x400;                                                     // DPMI Get Memory Info
332    int386( 0x31, &regs, &regs );
333         if (!regs.w.cflag)      {
334                 if (verbose) printf( "V%d.%d, CPU:%d, VMM:", regs.h.ah, regs.h.al, regs.h.cl );
335                 if (regs.w.bx & 4)      {
336                         if (verbose) printf( "1" );
337                         dpmi_virtual_memory = 1;
338                 } else {
339                         if (verbose) printf( "0" );
340                 }
341         }
342
343         //--------- Find available memory
344         memset(&regs,0,sizeof(regs));
345         memset(&sregs,0,sizeof(sregs));
346         regs.x.eax = 0x500;                                                     // DPMI Get Memory Info
347    sregs.es = FP_SEG(&mi);
348    regs.x.edi = FP_OFF(&mi);
349    int386x( 0x31, &regs, &regs, &sregs );
350         if (!regs.w.cflag)      {
351                 if (verbose) printf( ", P:%dK", mi.largest_lockable_pages*4 );
352                 if (dpmi_virtual_memory)
353                         if (verbose) printf( ", A:%dK", mi.largest_block_bytes/1024 );
354                 //dpmi_physical_memory = mi.largest_lockable_pages*4096;
355                 //dpmi_available_memory = mi.largest_block_bytes;
356                 dpmi_physical_memory = mi.total_physical_pages*4096;
357                 dpmi_available_memory = mi.total_pages * 4096;
358         } else {
359                 if (verbose) printf( "MemInfo failed!" );
360                 dpmi_physical_memory = 16*1024*1024;            // Assume 16 MB
361                 dpmi_available_memory = 16*1024*1024;           // Assume 16 MB
362         }
363         
364 #ifdef __WATCOMC__
365         if (!dpmi_lock_region( _GETDS, 4096 ))  {
366                 printf( "Error locking _GETDS" );
367                 exit(1);
368         }
369         if (!dpmi_lock_region( cstart_, 4096 )) {
370                 printf( "Error locking cstart" );
371                 exit(1);
372         }
373         if (!dpmi_lock_region( _chain_intr, 4096 ))     {
374                 printf( "Error locking _chain_intr" );
375                 exit(1);
376         }
377 #endif
378         return 1;
379 }
380
381 void *dpmi_get_temp_low_buffer( int size )
382 {
383         if ( dpmi_dos_buffer == NULL ) return NULL;
384         if ( size > 1024 ) return NULL;
385
386         return dpmi_dos_buffer;
387 }
388
389 int dpmi_set_pm_handler(unsigned intnum, void far * isr )
390 {
391         union REGS regs;
392
393     /* Use DMPI call 204h to get pm interrrupt */
394         memset(&regs,0,sizeof(regs));
395    regs.w.ax = 0x0205;
396    regs.h.bl = intnum;
397         regs.w.cx = FP_SEG(isr);
398         regs.x.edx = FP_OFF(isr);
399         int386( 0x31, &regs, &regs );
400         if (!regs.w.cflag)      
401                 return 0;
402         return 1;
403 }