Moved arch/sdl_* to arch/sdl
[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  * $Source: /cvs/cvsroot/d2x/arch/dos/dpmi.c,v $
16  * $Revision: 1.3 $
17  * $Author: bradleyb $
18  * $Date: 2001-10-19 09:01:56 $
19  *
20  * Dos DPMI
21  *
22  * $Log: not supported by cvs2svn $
23  * Revision 1.2  2001/01/29 13:35:08  bradleyb
24  * Fixed build system, minor fixes
25  *
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include <conf.h>
30 #endif
31
32 #ifdef __DJGPP__
33 #define _BORLAND_DOS_REGS 1
34 #define far
35 #include <sys/segments.h>
36 #include <sys/nearptr.h>
37 #include <crt0.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;
41 #endif
42
43 #include <dos.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <malloc.h>
47 #include <stdlib.h>
48
49 #include "pstypes.h"
50 #include "mono.h"
51 #include "error.h"
52 #include "u_dpmi.h"
53
54 int dpmi_find_dos_memory()
55 {
56         union REGS r;
57
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 )
64         if ( r.x.cflag )
65                 return ((r.x.ebx & 0xffff)*16);
66         else
67                 return 640*1024;
68 }
69
70 void *dpmi_real_malloc( int size, ushort *selector )
71 {
72         union REGS r;
73
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);
78
79         if (r.x.cflag)  // Failed
80                 return ((uint) 0);
81
82         if(selector!=NULL)
83                 *selector = r.x.edx & 0xFFFF;
84
85 #ifdef __DJGPP__
86         return (void *) ((r.x.eax & 0xFFFF) << 4)+__djgpp_conventional_base;
87 #else
88         return (void *) ((r.x.eax & 0xFFFF) << 4);
89 #endif
90 }
91
92 void dpmi_real_free( ushort selector )
93 {
94         union REGS r;
95
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);
100 }
101
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!!!
106
107 static void dpmi_setup_stack(dpmi_real_regs *rregs)  {
108         ushort temp_selector;
109
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;
116                 } else {
117                         dos_stack_top = &dos_stack[DOS_STACK_SIZE];
118                 }
119         }
120         
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);
125         }
126 }
127
128
129 void dpmi_real_int386x( ubyte intno, dpmi_real_regs * rregs )
130 {
131         union REGS regs;
132         struct SREGS sregs;
133
134     /* Use DMPI call 300h to issue the DOS interrupt */
135
136    dpmi_setup_stack(rregs);
137         memset(&regs,0,sizeof(regs));
138         memset(&sregs,0,sizeof(sregs));
139    regs.w.ax = 0x0300;
140    regs.h.bl = intno;
141    regs.h.bh = 0;
142    regs.w.cx = 0;
143    sregs.es = FP_SEG(rregs);
144    regs.x.edi = FP_OFF(rregs);
145    int386x( 0x31, &regs, &regs, &sregs );
146 }
147
148 void dpmi_real_call(dpmi_real_regs * rregs)
149 {
150         union REGS regs;
151         struct SREGS sregs;
152
153    dpmi_setup_stack(rregs);
154
155     /* Use DMPI call 301h to call real mode procedure */
156         memset(&regs,0,sizeof(regs));
157         memset(&sregs,0,sizeof(sregs));
158    regs.w.ax = 0x0301;
159    regs.h.bh = 0;
160    regs.w.cx = 0;
161    sregs.es = FP_SEG(rregs);
162    regs.x.edi = FP_OFF(rregs);
163    int386x( 0x31, &regs, &regs, &sregs );
164         if ( regs.x.cflag )
165                 exit(regs.w.ax);
166 }
167
168 int total_bytes = 0;
169
170 int dpmi_unlock_region(void *address, unsigned length)
171 {
172         union REGS regs;
173         unsigned int linear;
174
175         linear = (unsigned int) address;
176 #ifdef __DJGPP__
177         linear += __djgpp_base_address;
178 #endif
179
180         total_bytes -= length;
181         //mprintf( 1, "DPMI unlocked %d bytes\n", total_bytes );
182
183         memset(&regs,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);
187
188         regs.w.si = (length >> 16);             // Length in SI:DI
189         regs.w.di = (length & 0xFFFF);
190         int386 (0x31, &regs, &regs);
191         return (! regs.w.cflag);                        // Return 0 if can't lock
192 }
193
194 int dpmi_lock_region(void *address, unsigned length)
195 {
196         union REGS regs;
197         unsigned int linear;
198
199         linear = (unsigned int) address;
200 #ifdef __DJGPP__
201         linear += __djgpp_base_address;
202 #endif
203
204         total_bytes += length;
205         //mprintf( 1, "DPMI Locked down %d bytes\n", total_bytes );
206
207         memset(&regs,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);
211
212         regs.w.si = (length >> 16);             // Length in SI:DI
213         regs.w.di = (length & 0xFFFF);
214         int386 (0x31, &regs, &regs);
215         return (! regs.w.cflag);                        // Return 0 if can't lock
216 }
217
218
219 int dpmi_modify_selector_base( ushort selector, void * address )
220 {
221         union REGS regs;
222         unsigned int linear;
223
224         linear = (unsigned int)address;
225 #ifdef __DJGPP__
226         linear += __djgpp_base_address;
227 #endif
228
229         memset(&regs,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, &regs, &regs);            // call dpmi
235         if (regs.w.cflag)
236                 return 0;                                                       // Return 0 if error
237
238         return 1;
239 }
240
241
242 int dpmi_modify_selector_limit( ushort selector, int size  )
243 {
244         union REGS regs;
245         unsigned int segment_limit;
246
247         segment_limit = (unsigned int) size;
248
249         memset(&regs,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, &regs, &regs);            // call dpmi
255         if (regs.w.cflag)
256                 return 0;                                                       // Return 0 if error
257
258         return 1;
259 }
260
261
262 int dpmi_allocate_selector( void * address, int size, ushort * selector )
263 {
264         union REGS regs;
265
266
267         memset(&regs,0,sizeof(regs));
268         regs.w.ax = 0;                                                  // DPMI Allocate Selector
269         regs.w.cx = 1;                                                  // Allocate 1 selector
270         int386 (0x31, &regs, &regs);            // call dpmi
271         if (regs.w.cflag)
272                 return 0;                                                       // Return 0 if error
273         *selector = regs.w.ax;
274
275         if ( !dpmi_modify_selector_base( *selector, address ) )
276                 return 0;
277
278         if ( !dpmi_modify_selector_limit( *selector, size ) )
279                 return 0;
280
281 //      mprintf( 0, "Selector 0x%4x has base of 0x%8x, size %d bytes\n", *selector, linear,segment_limit);
282
283         return 1;
284 }
285
286 static void * dpmi_dos_buffer = NULL;
287 static ushort dpmi_dos_selector = 0;
288
289 void dpmi_close()
290 {
291         if (dpmi_dos_selector!=0)       {
292                 dpmi_dos_buffer = NULL;
293                 dpmi_dos_selector = 0;
294         }
295 }
296
297 typedef struct mem_data {
298         int     largest_block_bytes;
299         int     max_unlocked_page_allocation;
300         int     largest_lockable_pages;
301         int     total_pages;
302         int     unlocked_pages;
303         int     unused_physical_pages;
304         int     total_physical_pages;
305         int     free_linear_pages;
306         int     paging_size_pages;
307         int     reserved[3];
308 } mem_data;
309
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;
314
315 #ifdef __WATCOMC__
316 extern void cdecl _GETDS();
317 extern void cdecl cstart_();
318 #endif
319
320 int dpmi_init(int verbose)
321 {
322         union REGS regs;
323         struct SREGS sregs;
324         mem_data mi;
325
326         dpmi_dos_memory = dpmi_find_dos_memory();
327         
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" );
332                 exit(1);
333         }
334         atexit(dpmi_close);
335
336         // Check dpmi
337         memset(&regs,0,sizeof(regs));
338         regs.x.eax = 0x400;                                                     // DPMI Get Memory Info
339    int386( 0x31, &regs, &regs );
340         if (!regs.w.cflag)      {
341                 if (verbose) printf( "V%d.%d, CPU:%d, VMM:", regs.h.ah, regs.h.al, regs.h.cl );
342                 if (regs.w.bx & 4)      {
343                         if (verbose) printf( "1" );
344                         dpmi_virtual_memory = 1;
345                 } else {
346                         if (verbose) printf( "0" );
347                 }
348         }
349
350         //--------- Find available memory
351         memset(&regs,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, &regs, &regs, &sregs );
357         if (!regs.w.cflag)      {
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;
365         } else {
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
369         }
370         
371 #ifdef __WATCOMC__
372         if (!dpmi_lock_region( _GETDS, 4096 ))  {
373                 printf( "Error locking _GETDS" );
374                 exit(1);
375         }
376         if (!dpmi_lock_region( cstart_, 4096 )) {
377                 printf( "Error locking cstart" );
378                 exit(1);
379         }
380         if (!dpmi_lock_region( _chain_intr, 4096 ))     {
381                 printf( "Error locking _chain_intr" );
382                 exit(1);
383         }
384 #endif
385         return 1;
386 }
387
388 void *dpmi_get_temp_low_buffer( int size )
389 {
390         if ( dpmi_dos_buffer == NULL ) return NULL;
391         if ( size > 1024 ) return NULL;
392
393         return dpmi_dos_buffer;
394 }
395
396 int dpmi_set_pm_handler(unsigned intnum, void far * isr )
397 {
398         union REGS regs;
399
400     /* Use DMPI call 204h to get pm interrrupt */
401         memset(&regs,0,sizeof(regs));
402    regs.w.ax = 0x0205;
403    regs.h.bl = intnum;
404         regs.w.cx = FP_SEG(isr);
405         regs.x.edx = FP_OFF(isr);
406         int386( 0x31, &regs, &regs );
407         if (!regs.w.cflag)      
408                 return 0;
409         return 1;
410 }