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