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