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