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