1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Helper routines for the VBE/AF driver. This file is in charge of
12 * filling in the libc and pmode function export structures used by
13 * the FreeBE/AF extensions, which is mainly needed for compatibility
14 * with the SciTech Nucleus drivers (see the comments at at the top
15 * of vbeaf.c).
16 *
17 * This file is based on the SciTech PM/Lite library API.
18 *
19 * Someday this might want to work on Linux, which is why it lives
20 * in the misc directory, but it isn't going to be much fun trying
21 * to make that happen :-)
22 *
23 * By Shawn Hargreaves.
24 *
25 * See readme.txt for copyright information.
26 */
27
28
29 #include <time.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "allegro.h"
34 #include "allegro/internal/aintern.h"
35
36 #ifdef ALLEGRO_INTERNAL_HEADER
37 #include ALLEGRO_INTERNAL_HEADER
38 #endif
39
40 #ifndef SCAN_DEPEND
41 #ifdef ALLEGRO_DOS
42 #include <dos.h>
43 #include <conio.h>
44 #endif
45
46 #ifdef ALLEGRO_DJGPP
47 #include <crt0.h>
48 #include <sys/nearptr.h>
49 #endif
50 #endif
51
52
53 #define BUFFER_SIZE 256
54
55
56 /* FAFEXT_LIBC extension structure */
57 typedef struct LIBC_DATA
58 {
59 long size;
60 void (*abort)(void);
61 void *(*calloc)(unsigned long num_elements, unsigned long size);
62 void (*exit)(int status);
63 void (*free)(void *ptr);
64 char *(*getenv)(const char *name);
65 void *(*malloc)(unsigned long size);
66 void *(*realloc)(void *ptr, unsigned long size);
67 int (*system)(const char *s);
68 int (*putenv)(const char *val);
69 int (*open)(const char *file, int mode, ...);
70 int (*access)(const char *filename, int flags);
71 int (*close)(int fd);
72 int (*lseek)(int fd, int offset, int whence);
73 int (*read)(int fd, void *buffer, unsigned long count);
74 int (*unlink)(const char *file);
75 int (*write)(int fd, const void *buffer, unsigned long count);
76 int (*isatty)(int fd);
77 int (*remove)(const char *file);
78 int (*rename)(const char *oldname, const char *newname);
79 unsigned int (*time)(unsigned int *t);
80 void (*setfileattr)(const char *filename, unsigned attrib);
81 unsigned long (*getcurrentdate)(void);
82 } LIBC_DATA;
83
84
85
86 /* setfileattr:
87 * Export function for modifying DOS file attributes.
88 */
setfileattr(const char * filename,unsigned attrib)89 static void setfileattr(const char *filename, unsigned attrib)
90 {
91 _dos_setfileattr(filename, attrib);
92 }
93
94
95
96 /* getcurrentdate:
97 * Export function for checking the current date. Returns the number of
98 * days since 1/1/1980.
99 */
getcurrentdate(void)100 static unsigned long getcurrentdate(void)
101 {
102 unsigned long t = time(NULL);
103
104 /* this calculation _might_ be right, but somehow I doubt it :=) */
105
106 t /= (24*60*60); /* convert from seconds to days */
107 t -= (365*10); /* convert from 1970 origin to 1980 */
108 t -= 2; /* adjust for leap years in 1972 and 1976 */
109
110 return t;
111 }
112
113
114
115 /* _fill_vbeaf_libc_exports:
116 * Provides libc function exports for the FAFEXT_LIBC extension.
117 */
_fill_vbeaf_libc_exports(void * ptr)118 void _fill_vbeaf_libc_exports(void *ptr)
119 {
120 LIBC_DATA *lc = (LIBC_DATA *)ptr;
121
122 #define FILL_LIBC(field, func) \
123 { \
124 if ((long)offsetof(LIBC_DATA, field) < lc->size) \
125 lc->field = (void *)func; \
126 }
127
128 FILL_LIBC(abort, abort);
129 FILL_LIBC(calloc, calloc);
130 FILL_LIBC(exit, exit);
131 FILL_LIBC(free, free);
132 FILL_LIBC(getenv, getenv);
133 FILL_LIBC(malloc, malloc);
134 FILL_LIBC(realloc, realloc);
135 FILL_LIBC(system, system);
136 FILL_LIBC(putenv, putenv);
137 FILL_LIBC(open, open);
138 FILL_LIBC(access, access);
139 FILL_LIBC(close, close);
140 FILL_LIBC(lseek, lseek);
141 FILL_LIBC(read, read);
142 FILL_LIBC(unlink, unlink);
143 FILL_LIBC(write, write);
144 FILL_LIBC(isatty, isatty);
145 FILL_LIBC(remove, remove);
146 FILL_LIBC(rename, rename);
147 FILL_LIBC(time, time);
148 FILL_LIBC(setfileattr, setfileattr);
149 FILL_LIBC(getcurrentdate, getcurrentdate);
150 }
151
152
153
154 /* This pmode export structure basically provides the SciTech pmode
155 * library API, which is required by their Nucleus drivers. Why oh why
156 * is there so !"$%^ much of it? They don't need nearly so many callbacks
157 * just to write a simple video driver, and I resent being made to include
158 * all this code just to use their drivers...
159 */
160
161 typedef union
162 {
163 struct {
164 unsigned long eax, ebx, ecx, edx, esi, edi, cflag;
165 } e;
166 struct {
167 unsigned short ax, ax_hi;
168 unsigned short bx, bx_hi;
169 unsigned short cx, cx_hi;
170 unsigned short dx, dx_hi;
171 unsigned short si, si_hi;
172 unsigned short di, di_hi;
173 unsigned short cflag, cflag_hi;
174 } x;
175 struct {
176 unsigned char al, ah; unsigned short ax_hi;
177 unsigned char bl, bh; unsigned short bx_hi;
178 unsigned char cl, ch; unsigned short cx_hi;
179 unsigned char dl, dh; unsigned short dx_hi;
180 } h;
181 } SCITECH_REGS;
182
183
184
185 typedef struct
186 {
187 unsigned short es, cs, ss, ds, fs, gs;
188 } SCITECH_SREGS;
189
190
191
192 /* FAFEXT_PMODE extension structure */
193 typedef struct PMODE_DATA
194 {
195 long size;
196 int (*getModeType)(void);
197 void *(*getBIOSPointer)(void);
198 void *(*getA0000Pointer)(void);
199 void *(*mapPhysicalAddr)(unsigned long base, unsigned long limit);
200 void *(*mallocShared)(long size);
201 int (*mapShared)(void *ptr);
202 void (*freeShared)(void *ptr);
203 void *(*mapToProcess)(void *linear, unsigned long limit);
204 void (*loadDS)(void);
205 void (*saveDS)(void);
206 void *(*mapRealPointer)(unsigned int r_seg, unsigned int r_off);
207 void *(*allocRealSeg)(unsigned int size, unsigned int *r_seg, unsigned int *r_off);
208 void (*freeRealSeg)(void *mem);
209 void *(*allocLockedMem)(unsigned int size, unsigned long *physAddr);
210 void (*freeLockedMem)(void *p);
211 void (*callRealMode)(unsigned int seg, unsigned int off, SCITECH_REGS *regs, SCITECH_SREGS *sregs);
212 int (*int86)(int intno, SCITECH_REGS *in, SCITECH_REGS *out);
213 int (*int86x)(int intno, SCITECH_REGS *in, SCITECH_REGS *out, SCITECH_SREGS *sregs);
214 void (*DPMI_int86)(int intno, __dpmi_regs *regs);
215 void (*segread)(SCITECH_SREGS *sregs);
216 int (*int386)(int intno, SCITECH_REGS *in, SCITECH_REGS *out);
217 int (*int386x)(int intno, SCITECH_REGS *in, SCITECH_REGS *out, SCITECH_SREGS *sregs);
218 void (*availableMemory)(unsigned long *physical, unsigned long *total);
219 void *(*getVESABuf)(unsigned int *len, unsigned int *rseg, unsigned int *roff);
220 long (*getOSType)(void);
221 void (*fatalError)(const char *msg);
222 void (*setBankA)(int bank);
223 void (*setBankAB)(int bank);
224 const char *(*getCurrentPath)(void);
225 const char *(*getVBEAFPath)(void);
226 const char *(*getNucleusPath)(void);
227 const char *(*getNucleusConfigPath)(void);
228 const char *(*getUniqueID)(void);
229 const char *(*getMachineName)(void);
230 int (*VF_available)(void);
231 void *(*VF_init)(unsigned long baseAddr, int bankSize, int codeLen, void *bankFunc);
232 void (*VF_exit)(void);
233 int (*kbhit)(void);
234 int (*getch)(void);
235 int (*openConsole)(void);
236 int (*getConsoleStateSize)(void);
237 void (*saveConsoleState)(void *stateBuf, int console_id);
238 void (*restoreConsoleState)(const void *stateBuf, int console_id);
239 void (*closeConsole)(int console_id);
240 void (*setOSCursorLocation)(int x, int y);
241 void (*setOSScreenWidth)(int width, int height);
242 int (*enableWriteCombine)(unsigned long base, unsigned long length);
243 void (*backslash)(char *filename);
244 } PMODE_DATA;
245
246
247
248 /* get_mode_type:
249 * Return that we are running in 386 mode.
250 */
get_mode_type(void)251 static int get_mode_type(void)
252 {
253 return 2; /* 0=real mode, 1=16 bit pmode, 2=32 bit pmode */
254 }
255
256
257
258 /* get_bios_pointer:
259 * Returns a pointer to the BIOS data area at segment 0x400.
260 */
get_bios_pointer(void)261 static void *get_bios_pointer(void)
262 {
263 if (!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR))
264 if (__djgpp_nearptr_enable() == 0)
265 return NULL;
266
267 return (void *)(__djgpp_conventional_base + 0x400);
268 }
269
270
271
272 /* get_a0000_pointer:
273 * Returns a linear pointer to the VGA frame buffer memory.
274 */
get_a0000_pointer(void)275 static void *get_a0000_pointer(void)
276 {
277 if (!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR))
278 if (__djgpp_nearptr_enable() == 0)
279 return NULL;
280
281 return (void *)(__djgpp_conventional_base + 0xA0000);
282 }
283
284
285
286 /* map_physical_addr:
287 * Maps physical memory into the current DS segment.
288 */
map_physical_addr(unsigned long base,unsigned long limit)289 static void *map_physical_addr(unsigned long base, unsigned long limit)
290 {
291 unsigned long linear;
292
293 if (!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR))
294 if (__djgpp_nearptr_enable() == 0)
295 return NULL;
296
297 if (_create_linear_mapping(&linear, base, limit) != 0)
298 return NULL;
299
300 return (void *)(__djgpp_conventional_base + linear);
301 }
302
303
304
305 /* malloc_shared:
306 * Allocates a memory block in the global shared region.
307 */
malloc_shared(long size)308 static void *malloc_shared(long size)
309 {
310 return _AL_MALLOC(size);
311 }
312
313
314
315 /* map_shared:
316 * Maps a shared memory block into the current process.
317 */
map_shared(void * ptr)318 static int map_shared(void *ptr)
319 {
320 return 0;
321 }
322
323
324
325 /* free_shared:
326 * Frees the allocated shared memory block.
327 */
free_shared(void * ptr)328 static void free_shared(void *ptr)
329 {
330 _AL_FREE(ptr);
331 }
332
333
334
335 /* map_to_process:
336 * Attaches a previously allocated linear mapping to a new process.
337 */
map_to_process(void * linear,unsigned long limit)338 static void *map_to_process(void *linear, unsigned long limit)
339 {
340 return linear;
341 }
342
343
344
345 /* for the save_ds() / load_ds() functions */
346 static unsigned short saved_ds = 0;
347
348
349
350 /* save_ds:
351 * Saves the current data segment selector into a code segment variable.
352 */
save_ds(void)353 static void save_ds(void)
354 {
355 saved_ds = _default_ds();
356 }
357
358
359
360 /* load_ds:
361 * Restores a data segment selector previously stored by save_ds().
362 */
load_ds(void)363 static void load_ds(void)
364 {
365 #ifdef ALLEGRO_GCC
366
367 /* use gcc-style inline asm */
368 asm (
369 " movw %%cs:_saved_ds, %%ax ; "
370 " movw %%ax, %%ds "
371 :
372 :
373 : "%eax"
374 );
375
376 #elif defined ALLEGRO_WATCOM
377
378 /* use Watcom-style inline asm */
379 {
380 int _ds(void);
381
382 #pragma aux _ds = \
383 " mov ax, cs:saved_ds " \
384 " mov ds, ax " \
385 \
386 modify [eax];
387
388 _ds();
389 }
390
391 #endif
392 }
393
394
395
396 /* map_real_pointer:
397 * Maps a real mode pointer into our address space.
398 */
map_real_pointer(unsigned int r_seg,unsigned int r_off)399 static void *map_real_pointer(unsigned int r_seg, unsigned int r_off)
400 {
401 if (!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR))
402 if (__djgpp_nearptr_enable() == 0)
403 return NULL;
404
405 return (void *)(__djgpp_conventional_base + (r_seg<<4) + r_off);
406 }
407
408
409
410 /* cache so we know how to free real mode memory blocks */
411 static struct {
412 void *ptr;
413 int sel;
414 } rm_blocks[] =
415 {
416 { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, { NULL, 0 },
417 { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, { NULL, 0 },
418 { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, { NULL, 0 },
419 { NULL, 0 }, { NULL, 0 }, { NULL, 0 }, { NULL, 0 }
420 };
421
422
423
424 /* alloc_real_seg:
425 * Allocates a block of conventional memory.
426 */
alloc_real_seg(unsigned int size,unsigned int * r_seg,unsigned int * r_off)427 static void *alloc_real_seg(unsigned int size, unsigned int *r_seg, unsigned int *r_off)
428 {
429 int seg, sel, i;
430 void *ptr;
431
432 seg = __dpmi_allocate_dos_memory((size+15)>>4, &sel);
433
434 if (seg < 0)
435 return NULL;
436
437 *r_seg = seg;
438 *r_off = 0;
439
440 ptr = map_real_pointer(seg, 0);
441
442 for (i=0; i<(int)(sizeof(rm_blocks)/sizeof(rm_blocks[0])); i++) {
443 if (!rm_blocks[i].ptr) {
444 rm_blocks[i].ptr = ptr;
445 rm_blocks[i].sel = sel;
446 break;
447 }
448 }
449
450 return ptr;
451 }
452
453
454
455 /* free_real_seg:
456 * Frees a block of conventional memory.
457 */
free_real_seg(void * mem)458 static void free_real_seg(void *mem)
459 {
460 int i;
461
462 for (i=0; i<(int)(sizeof(rm_blocks)/sizeof(rm_blocks[0])); i++) {
463 if (rm_blocks[i].ptr == mem) {
464 __dpmi_free_dos_memory(rm_blocks[i].sel);
465 rm_blocks[i].ptr = NULL;
466 rm_blocks[i].sel = 0;
467 break;
468 }
469 }
470 }
471
472
473
474 /* alloc_locked_mem:
475 * Allocates a block of locked memory.
476 */
alloc_locked_mem(unsigned int size,unsigned long * physAddr)477 static void *alloc_locked_mem(unsigned int size, unsigned long *physAddr)
478 {
479 return NULL;
480 }
481
482
483
484 /* free_locked_mem:
485 * Frees a block of locked memory.
486 */
free_locked_mem(void * p)487 static void free_locked_mem(void *p)
488 {
489 }
490
491
492
493 /* call_real_mode:
494 * Calls a real mode asm procedure.
495 */
call_real_mode(unsigned int seg,unsigned int off,SCITECH_REGS * regs,SCITECH_SREGS * sregs)496 static void call_real_mode(unsigned int seg, unsigned int off, SCITECH_REGS *regs, SCITECH_SREGS *sregs)
497 {
498 __dpmi_regs r;
499
500 memset(&r, 0, sizeof(r));
501
502 r.d.eax = regs->e.eax;
503 r.d.ebx = regs->e.ebx;
504 r.d.ecx = regs->e.ecx;
505 r.d.edx = regs->e.edx;
506 r.d.esi = regs->e.esi;
507 r.d.edi = regs->e.edi;
508
509 r.x.ds = sregs->ds;
510 r.x.es = sregs->es;
511
512 r.x.cs = seg;
513 r.x.ip = off;
514
515 __dpmi_simulate_real_mode_procedure_retf(&r);
516
517 regs->e.eax = r.d.eax;
518 regs->e.ebx = r.d.ebx;
519 regs->e.ecx = r.d.ecx;
520 regs->e.edx = r.d.edx;
521 regs->e.esi = r.d.esi;
522 regs->e.edi = r.d.edi;
523
524 sregs->cs = r.x.cs;
525 sregs->ds = r.x.ds;
526 sregs->es = r.x.es;
527 sregs->ss = r.x.ss;
528
529 regs->x.cflag = (r.x.flags & 1);
530 }
531
532
533
534 /* my_int86:
535 * Generates a real mode interrupt.
536 */
my_int86(int intno,SCITECH_REGS * in,SCITECH_REGS * out)537 static int my_int86(int intno, SCITECH_REGS *in, SCITECH_REGS *out)
538 {
539 __dpmi_regs r;
540
541 memset(&r, 0, sizeof(r));
542
543 r.d.eax = in->e.eax;
544 r.d.ebx = in->e.ebx;
545 r.d.ecx = in->e.ecx;
546 r.d.edx = in->e.edx;
547 r.d.esi = in->e.esi;
548 r.d.edi = in->e.edi;
549
550 __dpmi_simulate_real_mode_interrupt(intno, &r);
551
552 out->e.eax = r.d.eax;
553 out->e.ebx = r.d.ebx;
554 out->e.ecx = r.d.ecx;
555 out->e.edx = r.d.edx;
556 out->e.esi = r.d.esi;
557 out->e.edi = r.d.edi;
558
559 out->x.cflag = (r.x.flags & 1);
560
561 return out->x.ax;
562 }
563
564
565
566 /* my_int86x:
567 * Generates a real mode interrupt.
568 */
my_int86x(int intno,SCITECH_REGS * in,SCITECH_REGS * out,SCITECH_SREGS * sregs)569 static int my_int86x(int intno, SCITECH_REGS *in, SCITECH_REGS *out, SCITECH_SREGS *sregs)
570 {
571 __dpmi_regs r;
572
573 memset(&r, 0, sizeof(r));
574
575 r.d.eax = in->e.eax;
576 r.d.ebx = in->e.ebx;
577 r.d.ecx = in->e.ecx;
578 r.d.edx = in->e.edx;
579 r.d.esi = in->e.esi;
580 r.d.edi = in->e.edi;
581
582 r.x.ds = sregs->ds;
583 r.x.es = sregs->es;
584
585 __dpmi_simulate_real_mode_interrupt(intno, &r);
586
587 out->e.eax = r.d.eax;
588 out->e.ebx = r.d.ebx;
589 out->e.ecx = r.d.ecx;
590 out->e.edx = r.d.edx;
591 out->e.esi = r.d.esi;
592 out->e.edi = r.d.edi;
593
594 sregs->cs = r.x.cs;
595 sregs->ds = r.x.ds;
596 sregs->es = r.x.es;
597 sregs->ss = r.x.ss;
598
599 out->x.cflag = (r.x.flags & 1);
600
601 return out->x.ax;
602 }
603
604
605
606 /* dpmi_int86:
607 * Generates a real mode interrupt.
608 */
dpmi_int86(int intno,__dpmi_regs * regs)609 static void dpmi_int86(int intno, __dpmi_regs *regs)
610 {
611 __dpmi_simulate_real_mode_interrupt(intno, regs);
612 }
613
614
615
616 /* my_segread:
617 * Reads the current selector values.
618 */
my_segread(SCITECH_SREGS * sregs)619 static void my_segread(SCITECH_SREGS *sregs)
620 {
621 #ifdef ALLEGRO_GCC
622
623 /* use gcc-style inline asm */
624 asm (
625 " movw %%cs, %w0 ; "
626 " movw %%ds, %w1 ; "
627 " movw %%es, %w2 ; "
628 " movw %%fs, %w3 ; "
629 " movw %%gs, %w4 ; "
630 " movw %%ss, %w5 ; "
631
632 : "=m" (sregs->cs),
633 "=m" (sregs->ds),
634 "=m" (sregs->es),
635 "=m" (sregs->fs),
636 "=m" (sregs->gs),
637 "=m" (sregs->ss)
638 );
639
640 #elif defined WATCOM
641
642 segread((struct SREGS *)sregs);
643
644 #endif
645 }
646
647
648
649 #ifdef ALLEGRO_GCC /* gcc version of my_int386x() */
650
651
652
653 /* code fragment for issuing interrupt calls */
654 #define INT(n) \
655 { \
656 0xCD, /* int */ \
657 n, \
658 0xC3, /* ret */ \
659 }
660
661
662 #define INTROW(n) \
663 INT(n+0x00), INT(n+0x01), INT(n+0x02), INT(n+0x03), \
664 INT(n+0x04), INT(n+0x05), INT(n+0x06), INT(n+0x07), \
665 INT(n+0x08), INT(n+0x09), INT(n+0x0A), INT(n+0x0B), \
666 INT(n+0x0C), INT(n+0x0D), INT(n+0x0E), INT(n+0x0F)
667
668
669 static unsigned char asm_int_code[256][3] =
670 {
671 INTROW(0x00), INTROW(0x10), INTROW(0x20), INTROW(0x30),
672 INTROW(0x40), INTROW(0x50), INTROW(0x60), INTROW(0x70),
673 INTROW(0x80), INTROW(0x90), INTROW(0xA0), INTROW(0xB0),
674 INTROW(0xC0), INTROW(0xD0), INTROW(0xE0), INTROW(0xF0)
675 };
676
677
678 #undef INT
679 #undef INTROW
680
681
682
683 /* temporary global for storing the data selector
684 * FIXME: this is supposed to be static but that doesn't work with the
685 * following asm code with gcc 4
686 */
687 int __al_vbeafex_int_ds;
688
689
690
691 /* my_int386x:
692 * Generates a protected mode interrupt (gcc version).
693 */
my_int386x(int intno,SCITECH_REGS * in,SCITECH_REGS * out,SCITECH_SREGS * sregs)694 static int my_int386x(int intno, SCITECH_REGS *in, SCITECH_REGS *out, SCITECH_SREGS *sregs)
695 {
696 asm (
697 " pushal ; " /* push lots of stuff */
698 " pushw %%es ; "
699 " pushw %%fs ; "
700 " pushw %%gs ; "
701 " pushl %%esi ; "
702 " pushl %%edx ; "
703 " pushw %%ds ; "
704 " pushl %%ecx ; "
705
706 " movw (%%esi), %%es ; " /* load selectors */
707 " movw 6(%%esi), %%ax ; "
708 " movw %%ax, ___al_vbeafex_int_ds ; "
709 " movw 8(%%esi), %%fs ; "
710 " movw 10(%%esi), %%gs ; "
711
712 " movl (%%edi), %%eax ; " /* load registers */
713 " movl 4(%%edi), %%ebx ; "
714 " movl 8(%%edi), %%ecx ; "
715 " movl 12(%%edi), %%edx ; "
716 " movl 16(%%edi), %%esi ; "
717 " movl 20(%%edi), %%edi ; "
718
719 " movw ___al_vbeafex_int_ds, %%ds ; " /* load %ds selector */
720
721 " clc ; " /* generate the interrupt */
722 " popl %%ebp ; "
723 " call *%%ebp ; "
724
725 " movw %%ds, %%ss:___al_vbeafex_int_ds ; " /* store returned %ds value */
726 " popw %%ds ; " /* restore original %ds */
727
728 " movl %%edi, %%ebp ; " /* store %edi */
729 " popl %%edi ; " /* pop output pointer into %edi */
730
731 " movl %%eax, (%%edi) ; " /* store output registers */
732 " movl %%ebx, 4(%%edi) ; "
733 " movl %%ecx, 8(%%edi) ; "
734 " movl %%edx, 12(%%edi) ; "
735 " movl %%esi, 16(%%edi) ; "
736 " movl %%ebp, 20(%%edi) ; "
737
738 " pushfl ; " /* store output carry flag */
739 " popl %%eax ; "
740 " andl $1, %%eax ; "
741 " movl %%eax, 24(%%edi) ; "
742
743 " popl %%esi ; " /* pop sregs pointer into %esi */
744
745 " movw %%es, (%%esi) ; " /* store output selectors */
746 " movw ___al_vbeafex_int_ds, %%ax ; "
747 " movw %%ax, 6(%%esi) ; "
748 " movw %%fs, 8(%%esi) ; "
749 " movw %%gs, 10(%%esi) ; "
750
751 " popw %%gs ; " /* pop remaining values */
752 " popw %%fs ; "
753 " popw %%es ; "
754 " popal ; "
755
756 : /* no outputs */
757
758 : "S" (sregs), /* sregs in %esi */
759 "D" (in), /* in pointer in %edi */
760 "d" (out), /* out pointer in %edx */
761 "c" (asm_int_code[intno]) /* function pointer in %ecx */
762 );
763
764 return out->e.eax;
765 }
766
767
768
769 #elif defined ALLEGRO_WATCOM
770
771
772
773 /* my_int386x:
774 * Generates a protected mode interrupt (Watcom version).
775 */
my_int386x(int intno,SCITECH_REGS * in,SCITECH_REGS * out,SCITECH_SREGS * sregs)776 static int my_int386x(int intno, SCITECH_REGS *in, SCITECH_REGS *out, SCITECH_SREGS *sregs)
777 {
778 return int386x(intno, (union REGS *)in, (union REGS *)out, (struct SREGS *)sregs);
779 }
780
781
782
783 #endif /* gcc vs. Watcom */
784
785
786
787 /* my_int386:
788 * Generates a protected mode interrupt.
789 */
my_int386(int intno,SCITECH_REGS * in,SCITECH_REGS * out)790 static int my_int386(int intno, SCITECH_REGS *in, SCITECH_REGS *out)
791 {
792 SCITECH_SREGS sregs;
793
794 my_segread(&sregs);
795
796 return my_int386x(intno, in, out, &sregs);
797 }
798
799
800
801 /* available_memory:
802 * Returns the amount of available free memory.
803 */
available_memory(unsigned long * physical,unsigned long * total)804 static void available_memory(unsigned long *physical, unsigned long *total)
805 {
806 __dpmi_free_mem_info info;
807
808 __dpmi_get_free_memory_information(&info);
809
810 *physical = info.total_number_of_free_pages * 4096;
811 *total = info.largest_available_free_block_in_bytes;
812
813 if (*total < *physical)
814 *physical = *total;
815 }
816
817
818
819 /* conventional memory buffer for communicating with VESA */
820 static void *vesa_ptr = NULL;
821
822
823
824 /* free_vesa_buf:
825 * Cleanup routine.
826 */
free_vesa_buf(void)827 static void free_vesa_buf(void)
828 {
829 if (vesa_ptr) {
830 free_real_seg(vesa_ptr);
831 vesa_ptr = NULL;
832 }
833 }
834
835
836
837 /* get_vesa_buf:
838 * Returns the address of a global VESA real mode transfer buffer.
839 */
get_vesa_buf(unsigned int * len,unsigned int * rseg,unsigned int * roff)840 static void *get_vesa_buf(unsigned int *len, unsigned int *rseg, unsigned int *roff)
841 {
842 static unsigned int seg, off;
843
844 if (!vesa_ptr) {
845 vesa_ptr = alloc_real_seg(2048, &seg, &off);
846
847 if (!vesa_ptr)
848 return NULL;
849
850 atexit(free_vesa_buf);
851 }
852
853 *len = 2048;
854 *rseg = seg;
855 *roff = off;
856
857 return vesa_ptr;
858 }
859
860
861
862 /* get_os_type:
863 * Returns the OS type flag.
864 */
get_os_type(void)865 static long get_os_type(void)
866 {
867 return 1; /* _OS_DOS */
868 }
869
870
871
872 /* fatal_error:
873 * Handles a fatal error condition.
874 */
fatal_error(const char * msg)875 static void fatal_error(const char *msg)
876 {
877 fprintf(stderr, "%s\n", msg);
878 fflush(stderr);
879 exit(1);
880 }
881
882
883
884 /* set_banka:
885 * Sets a VBE bank using int 0x10.
886 */
set_banka(int bank)887 static void set_banka(int bank)
888 {
889 __dpmi_regs r;
890
891 r.x.ax = 0x4F05;
892 r.x.bx = 0;
893 r.x.dx = bank;
894
895 __dpmi_int(0x10, &r);
896 }
897
898
899
900 /* set_bankab:
901 * Sets both VBE banks using int 0x10.
902 */
set_bankab(int bank)903 static void set_bankab(int bank)
904 {
905 __dpmi_regs r;
906
907 r.x.ax = 0x4F05;
908 r.x.bx = 0;
909 r.x.dx = bank;
910
911 __dpmi_int(0x10, &r);
912
913 r.x.ax = 0x4F05;
914 r.x.bx = 1;
915 r.x.dx = bank;
916
917 __dpmi_int(0x10, &r);
918 }
919
920
921
922 /* get_current_path:
923 * Returns the current working directory.
924 */
get_current_path(void)925 static const char *get_current_path(void)
926 {
927 static char *buffer = NULL;
928
929 if (!buffer)
930 buffer = _AL_MALLOC(BUFFER_SIZE);
931
932 getcwd(buffer, BUFFER_SIZE-1);
933
934 return buffer;
935 }
936
937
938
939 /* get_vbeaf_path:
940 * Returns the VBE/AF driver directory.
941 */
get_vbeaf_path(void)942 static const char *get_vbeaf_path(void)
943 {
944 return "c:\\";
945 }
946
947
948
949 /* get_nucleus_path:
950 * Returns the Nucleus driver directory.
951 */
get_nucleus_path(void)952 static const char *get_nucleus_path(void)
953 {
954 static char *buffer = NULL;
955 char *p;
956
957 p = getenv("NUCLEUS_PATH");
958 if (p)
959 return p;
960
961 p = getenv("WINBOOTDIR");
962 if (p) {
963 if (!buffer)
964 buffer = _AL_MALLOC(BUFFER_SIZE);
965
966 _al_sane_strncpy(buffer , p, BUFFER_SIZE);
967 strncat(buffer, "\\nucleus", BUFFER_SIZE-1);
968 return buffer;
969 }
970
971 return "c:\\nucleus";
972 }
973
974
975
976 /* get_nucleus_config_path:
977 * Returns the Nucleus config directory.
978 */
get_nucleus_config_path(void)979 static const char *get_nucleus_config_path(void)
980 {
981 static char *buffer = NULL;
982
983 if (!buffer)
984 buffer = _AL_MALLOC(BUFFER_SIZE);
985
986 _al_sane_strncpy(buffer, get_nucleus_path(), BUFFER_SIZE);
987 put_backslash(buffer);
988 strncat(buffer, "config", BUFFER_SIZE-1);
989
990 return buffer;
991 }
992
993
994
995 /* get_unique_id:
996 * Returns a network unique machine identifier as a string.
997 */
get_unique_id(void)998 static const char *get_unique_id(void)
999 {
1000 return "DOS";
1001 }
1002
1003
1004
1005 /* get_machine_name:
1006 * Returns the network machine name as a string.
1007 */
get_machine_name(void)1008 static const char *get_machine_name(void)
1009 {
1010 static char *buffer = NULL;
1011
1012 if (!buffer)
1013 buffer = _AL_MALLOC(BUFFER_SIZE);
1014
1015 #ifdef ALLEGRO_DJGPP
1016 gethostname(buffer, BUFFER_SIZE-1);
1017 #else
1018 _al_sane_strncpy(buffer, "pc", BUFFER_SIZE);
1019 #endif
1020
1021 return buffer;
1022 }
1023
1024
1025
1026 /* vf_available:
1027 * Checks whether the virtual framebuffer mode is avaliable (no, it isn't).
1028 */
vf_available(void)1029 static int vf_available(void)
1030 {
1031 return 0;
1032 }
1033
1034
1035
1036 /* vf_init:
1037 * Initialises the virtual framebuffer mode.
1038 */
vf_init(unsigned long baseAddr,int bankSize,int codeLen,void * bankFunc)1039 static void *vf_init(unsigned long baseAddr, int bankSize, int codeLen, void *bankFunc)
1040 {
1041 return NULL;
1042 }
1043
1044
1045
1046 /* vf_exit:
1047 * Shuts down the virtual framebuffer mode.
1048 */
vf_exit(void)1049 static void vf_exit(void)
1050 {
1051 }
1052
1053
1054
1055 /* stored console state structure */
1056 typedef struct
1057 {
1058 int mode;
1059 int tall;
1060 } CONSOLE_STATE;
1061
1062
1063
1064 /* open_console:
1065 * Prepares the system for console output.
1066 */
open_console(void)1067 static int open_console(void)
1068 {
1069 return 0;
1070 }
1071
1072
1073
1074 /* get_console_state_size:
1075 * Returns the size of a console state buffer.
1076 */
get_console_state_size(void)1077 static int get_console_state_size(void)
1078 {
1079 return sizeof(CONSOLE_STATE);
1080 }
1081
1082
1083
1084 /* save_console_state:
1085 * Stores the current console status.
1086 */
save_console_state(void * stateBuf,int console_id)1087 static void save_console_state(void *stateBuf, int console_id)
1088 {
1089 CONSOLE_STATE *state = stateBuf;
1090 __dpmi_regs r;
1091
1092 r.x.ax = 0x0F00;
1093 __dpmi_int(0x10, &r);
1094
1095 state->mode = r.h.al & 0x7F;
1096
1097 if (state->mode == 0x3) {
1098 r.x.ax = 0x1130;
1099 r.x.bx = 0;
1100 r.x.dx = 0;
1101 __dpmi_int(0x10, &r);
1102
1103 state->tall = ((r.h.dl == 42) || (r.h.dl == 49));
1104 }
1105 else
1106 state->tall = FALSE;
1107 }
1108
1109
1110
1111 /* restore_console_state:
1112 * Restores a previously saved console status.
1113 */
restore_console_state(const void * stateBuf,int console_id)1114 static void restore_console_state(const void *stateBuf, int console_id)
1115 {
1116 const CONSOLE_STATE *state = stateBuf;
1117 __dpmi_regs r;
1118
1119 if (state->tall) {
1120 r.x.ax = 0x1112;
1121 r.x.bx = 0;
1122 __dpmi_int(0x10, &r);
1123 }
1124 }
1125
1126
1127
1128 /* close_console:
1129 * Shuts down the console mode.
1130 */
close_console(int console_id)1131 static void close_console(int console_id)
1132 {
1133 }
1134
1135
1136
1137 /* set_os_cursor_location:
1138 * Positions the text mode cursor.
1139 */
set_os_cursor_location(int x,int y)1140 static void set_os_cursor_location(int x, int y)
1141 {
1142 _farsetsel(_dos_ds);
1143 _farnspokeb(0x450, x);
1144 _farnspokeb(0x451, y);
1145 }
1146
1147
1148
1149 /* set_os_screen_width:
1150 * Sets the console width.
1151 */
set_os_screen_width(int width,int height)1152 static void set_os_screen_width(int width, int height)
1153 {
1154 _farnspokeb(0x44A, width);
1155 _farnspokeb(0x484, height-1);
1156 }
1157
1158
1159
1160 /* enable_write_combine:
1161 * Enables the Intel PPro/PII write combining.
1162 */
enable_write_combine(unsigned long base,unsigned long length)1163 static int enable_write_combine(unsigned long base, unsigned long length)
1164 {
1165 return 0;
1166 }
1167
1168
1169
1170 /* _fill_vbeaf_pmode_exports:
1171 * Provides pmode function exports for the FAFEXT_PMODE extension.
1172 */
_fill_vbeaf_pmode_exports(void * ptr)1173 void _fill_vbeaf_pmode_exports(void *ptr)
1174 {
1175 PMODE_DATA *pm = (PMODE_DATA *)ptr;
1176
1177 #define FILL_PMODE(field, func) \
1178 { \
1179 if ((long)offsetof(PMODE_DATA, field) < pm->size) \
1180 pm->field = func; \
1181 }
1182
1183 FILL_PMODE(getModeType, get_mode_type);
1184 FILL_PMODE(getBIOSPointer, get_bios_pointer);
1185 FILL_PMODE(getA0000Pointer, get_a0000_pointer);
1186 FILL_PMODE(mapPhysicalAddr, map_physical_addr);
1187 FILL_PMODE(mallocShared, malloc_shared);
1188 FILL_PMODE(mapShared, map_shared);
1189 FILL_PMODE(freeShared, free_shared);
1190 FILL_PMODE(mapToProcess, map_to_process);
1191 FILL_PMODE(loadDS, load_ds);
1192 FILL_PMODE(saveDS, save_ds);
1193 FILL_PMODE(mapRealPointer, map_real_pointer);
1194 FILL_PMODE(allocRealSeg, alloc_real_seg);
1195 FILL_PMODE(freeRealSeg, free_real_seg);
1196 FILL_PMODE(allocLockedMem, alloc_locked_mem);
1197 FILL_PMODE(freeLockedMem, free_locked_mem);
1198 FILL_PMODE(callRealMode, call_real_mode);
1199 FILL_PMODE(int86, my_int86);
1200 FILL_PMODE(int86x, my_int86x);
1201 FILL_PMODE(DPMI_int86, dpmi_int86);
1202 FILL_PMODE(segread, my_segread);
1203 FILL_PMODE(int386, my_int386);
1204 FILL_PMODE(int386x, my_int386x);
1205 FILL_PMODE(availableMemory, available_memory);
1206 FILL_PMODE(getVESABuf, get_vesa_buf);
1207 FILL_PMODE(getOSType, get_os_type);
1208 FILL_PMODE(fatalError, fatal_error);
1209 FILL_PMODE(setBankA, set_banka);
1210 FILL_PMODE(setBankAB, set_bankab);
1211 FILL_PMODE(getCurrentPath, get_current_path);
1212 FILL_PMODE(getVBEAFPath, get_vbeaf_path);
1213 FILL_PMODE(getNucleusPath, get_nucleus_path);
1214 FILL_PMODE(getNucleusConfigPath, get_nucleus_config_path);
1215 FILL_PMODE(getUniqueID, get_unique_id);
1216 FILL_PMODE(getMachineName, get_machine_name);
1217 FILL_PMODE(VF_available, vf_available);
1218 FILL_PMODE(VF_init, vf_init);
1219 FILL_PMODE(VF_exit, vf_exit);
1220 FILL_PMODE(kbhit, kbhit);
1221 FILL_PMODE(getch, getch);
1222 FILL_PMODE(openConsole, open_console);
1223 FILL_PMODE(getConsoleStateSize, get_console_state_size);
1224 FILL_PMODE(saveConsoleState, save_console_state);
1225 FILL_PMODE(restoreConsoleState, restore_console_state);
1226 FILL_PMODE(closeConsole, close_console);
1227 FILL_PMODE(setOSCursorLocation, set_os_cursor_location);
1228 FILL_PMODE(setOSScreenWidth, set_os_screen_width);
1229 FILL_PMODE(enableWriteCombine, enable_write_combine);
1230 FILL_PMODE(backslash, put_backslash);
1231 }
1232
1233
1234