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