]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/linux/pm.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / linux / pm.c
1 ;/****************************************************************************
2 *
3 *                   SciTech OS Portability Manager Library
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 *                   Portions copyright (C) Josh Vanderhoof
25 *
26 * Language:     ANSI C
27 * Environment:  Linux
28 *
29 * Description:  Implementation for the OS Portability Manager Library, which
30 *               contains functions to implement OS specific services in a
31 *               generic, cross platform API. Porting the OS Portability
32 *               Manager library is the first step to porting any SciTech
33 *               products to a new platform.
34 *
35 ****************************************************************************/
36
37 #include "pmapi.h"
38 #include "drvlib/os/os.h"
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/mman.h>
43 #include <sys/kd.h>
44 #include <sys/ioctl.h>
45 #include <sys/stat.h>
46 #include <sys/vt.h>
47 #include <sys/wait.h>
48 #include <sys/types.h>
49 #include <sys/time.h>
50 #include <unistd.h>
51 #include <termios.h>
52 #include <fcntl.h>
53 #include <syscall.h>
54 #include <signal.h>
55 #include <time.h>
56 #include <ctype.h>
57 #include <errno.h>
58 #include <asm/io.h>
59 #include <asm/types.h>
60 #ifdef ENABLE_MTRR
61 #include <asm/mtrr.h>
62 #endif
63 #include <asm/vm86.h>
64 #ifdef __GLIBC__
65 #include <sys/perm.h>
66 #endif
67
68 /*--------------------------- Global variables ----------------------------*/
69
70 #define REAL_MEM_BASE       ((void *)0x10000)
71 #define REAL_MEM_SIZE       0x10000
72 #define REAL_MEM_BLOCKS     0x100
73 #define DEFAULT_VM86_FLAGS  (IF_MASK | IOPL_MASK)
74 #define DEFAULT_STACK_SIZE  0x1000
75 #define RETURN_TO_32_INT    255
76
77 /* Quick and dirty fix for vm86() syscall from lrmi 0.6 */
78 static int
79 vm86(struct vm86_struct *vm)
80     {
81     int r;
82 #ifdef __PIC__
83     asm volatile (
84      "pushl %%ebx\n\t"
85      "movl %2, %%ebx\n\t"
86      "int $0x80\n\t"
87      "popl %%ebx"
88      : "=a" (r)
89      : "0" (113), "r" (vm));
90 #else
91     asm volatile (
92      "int $0x80"
93      : "=a" (r)
94      : "0" (113), "b" (vm));
95 #endif
96     return r;
97     }
98
99
100 static struct {
101     int                 ready;
102     unsigned short      ret_seg, ret_off;
103     unsigned short      stack_seg, stack_off;
104     struct vm86_struct  vm;
105     } context = {0};
106
107 struct mem_block {
108     unsigned int size : 20;
109     unsigned int free : 1;
110     };
111
112 static struct {
113     int ready;
114     int count;
115     struct mem_block blocks[REAL_MEM_BLOCKS];
116     } mem_info = {0};
117
118 int                     _PM_console_fd = -1;
119 int                     _PM_leds = 0,_PM_modifiers = 0;
120 static ibool            inited = false;
121 static int              tty_vc = 0;
122 static int              console_count = 0;
123 static int              startup_vc;
124 static int              fd_mem = 0;
125 static ibool            in_raw_mode = false;
126 #ifdef ENABLE_MTRR
127 static int              mtrr_fd;
128 #endif
129 static uint VESABuf_len = 1024;     /* Length of the VESABuf buffer     */
130 static void *VESABuf_ptr = NULL;    /* Near pointer to VESABuf          */
131 static uint VESABuf_rseg;           /* Real mode segment of VESABuf     */
132 static uint VESABuf_roff;           /* Real mode offset of VESABuf      */
133 #ifdef TRACE_IO
134 static ulong            traceAddr;
135 #endif
136
137 static void (PMAPIP fatalErrorCleanup)(void) = NULL;
138
139 /*----------------------------- Implementation ----------------------------*/
140
141 #ifdef  TRACE_IO
142 extern void printk(char *msg,...);
143 #endif
144
145 static inline void port_out(int value, int port)
146 {
147 #ifdef TRACE_IO
148     printk("%04X:%04X: outb.%04X <- %02X\n", traceAddr >> 16, traceAddr & 0xFFFF, (ushort)port, (uchar)value);
149 #endif
150     asm volatile ("outb %0,%1"
151           ::"a" ((unsigned char) value), "d"((unsigned short) port));
152 }
153
154 static inline void port_outw(int value, int port)
155 {
156 #ifdef TRACE_IO
157     printk("%04X:%04X: outw.%04X <- %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value);
158 #endif
159     asm volatile ("outw %0,%1"
160          ::"a" ((unsigned short) value), "d"((unsigned short) port));
161 }
162
163 static inline void port_outl(int value, int port)
164 {
165 #ifdef TRACE_IO
166     printk("%04X:%04X: outl.%04X <- %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value);
167 #endif
168     asm volatile ("outl %0,%1"
169          ::"a" ((unsigned long) value), "d"((unsigned short) port));
170 }
171
172 static inline unsigned int port_in(int port)
173 {
174     unsigned char value;
175     asm volatile ("inb %1,%0"
176               :"=a" ((unsigned char)value)
177               :"d"((unsigned short) port));
178 #ifdef TRACE_IO
179     printk("%04X:%04X:  inb.%04X -> %02X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (uchar)value);
180 #endif
181     return value;
182 }
183
184 static inline unsigned int port_inw(int port)
185 {
186     unsigned short value;
187     asm volatile ("inw %1,%0"
188               :"=a" ((unsigned short)value)
189               :"d"((unsigned short) port));
190 #ifdef TRACE_IO
191     printk("%04X:%04X:  inw.%04X -> %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value);
192 #endif
193     return value;
194 }
195
196 static inline unsigned int port_inl(int port)
197 {
198     unsigned long value;
199     asm volatile ("inl %1,%0"
200               :"=a" ((unsigned long)value)
201               :"d"((unsigned short) port));
202 #ifdef TRACE_IO
203     printk("%04X:%04X:  inl.%04X -> %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value);
204 #endif
205     return value;
206 }
207
208 static int real_mem_init(void)
209 {
210     void    *m;
211     int     fd_zero;
212
213     if (mem_info.ready)
214         return 1;
215
216     if ((fd_zero = open("/dev/zero", O_RDONLY)) == -1)
217         PM_fatalError("You must have root privledges to run this program!");
218     if ((m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
219             PROT_READ | PROT_WRITE | PROT_EXEC,
220             MAP_FIXED | MAP_PRIVATE, fd_zero, 0)) == (void *)-1) {
221         close(fd_zero);
222         PM_fatalError("You must have root privledges to run this program!");
223         }
224     mem_info.ready = 1;
225     mem_info.count = 1;
226     mem_info.blocks[0].size = REAL_MEM_SIZE;
227     mem_info.blocks[0].free = 1;
228     return 1;
229 }
230
231 static void insert_block(int i)
232 {
233     memmove(
234         mem_info.blocks + i + 1,
235         mem_info.blocks + i,
236         (mem_info.count - i) * sizeof(struct mem_block));
237     mem_info.count++;
238 }
239
240 static void delete_block(int i)
241 {
242     mem_info.count--;
243
244     memmove(
245         mem_info.blocks + i,
246         mem_info.blocks + i + 1,
247         (mem_info.count - i) * sizeof(struct mem_block));
248 }
249
250 static inline void set_bit(unsigned int bit, void *array)
251 {
252     unsigned char *a = array;
253     a[bit / 8] |= (1 << (bit % 8));
254 }
255
256 static inline unsigned int get_int_seg(int i)
257 {
258     return *(unsigned short *)(i * 4 + 2);
259 }
260
261 static inline unsigned int get_int_off(int i)
262 {
263     return *(unsigned short *)(i * 4);
264 }
265
266 static inline void pushw(unsigned short i)
267 {
268     struct vm86_regs *r = &context.vm.regs;
269     r->esp -= 2;
270     *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i;
271 }
272
273 ibool PMAPI PM_haveBIOSAccess(void)
274 { return true; }
275
276 void PMAPI PM_init(void)
277 {
278     void    *m;
279     uint    r_seg,r_off;
280
281     if (inited)
282         return;
283
284     /* Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
285      * and the physical framebuffer and ROM images from (0xa0000 - 0x100000)
286      */
287     real_mem_init();
288     if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1) {
289         PM_fatalError("You must have root privileges to run this program!");
290         }
291     if ((m = mmap((void *)0, 0x502,
292             PROT_READ | PROT_WRITE | PROT_EXEC,
293             MAP_FIXED | MAP_PRIVATE, fd_mem, 0)) == (void *)-1) {
294         PM_fatalError("You must have root privileges to run this program!");
295         }
296     if ((m = mmap((void *)0xA0000, 0xC0000 - 0xA0000,
297             PROT_READ | PROT_WRITE,
298             MAP_FIXED | MAP_SHARED, fd_mem, 0xA0000)) == (void *)-1) {
299         PM_fatalError("You must have root privileges to run this program!");
300         }
301     if ((m = mmap((void *)0xC0000, 0xD0000 - 0xC0000,
302             PROT_READ | PROT_WRITE | PROT_EXEC,
303             MAP_FIXED | MAP_PRIVATE, fd_mem, 0xC0000)) == (void *)-1) {
304         PM_fatalError("You must have root privileges to run this program!");
305         }
306     if ((m = mmap((void *)0xD0000, 0x100000 - 0xD0000,
307             PROT_READ | PROT_WRITE,
308             MAP_FIXED | MAP_SHARED, fd_mem, 0xD0000)) == (void *)-1) {
309         PM_fatalError("You must have root privileges to run this program!");
310         }
311     inited = 1;
312
313     /* Allocate a stack */
314     m = PM_allocRealSeg(DEFAULT_STACK_SIZE,&r_seg,&r_off);
315     context.stack_seg = r_seg;
316     context.stack_off = r_off+DEFAULT_STACK_SIZE;
317
318     /* Allocate the return to 32 bit routine */
319     m = PM_allocRealSeg(2,&r_seg,&r_off);
320     context.ret_seg = r_seg;
321     context.ret_off = r_off;
322     ((uchar*)m)[0] = 0xCD;         /* int opcode */
323     ((uchar*)m)[1] = RETURN_TO_32_INT;
324     memset(&context.vm, 0, sizeof(context.vm));
325
326     /* Enable kernel emulation of all ints except RETURN_TO_32_INT */
327     memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
328     set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
329     context.ready = 1;
330 #ifdef ENABLE_MTRR
331     mtrr_fd =  open("/dev/cpu/mtrr", O_RDWR, 0);
332     if (mtrr_fd < 0)
333        mtrr_fd =  open("/proc/mtrr", O_RDWR, 0);
334 #endif
335     /* Enable I/O permissions to directly access I/O ports. We break the
336      * allocation into two parts, one for the ports from 0-0x3FF and
337      * another for the remaining ports up to 0xFFFF. Standard Linux kernels
338      * only allow the first 0x400 ports to be enabled, so to enable all
339      * 65536 ports you need a patched kernel that will enable the full
340      * 8Kb I/O permissions bitmap.
341      */
342 #ifndef TRACE_IO
343     ioperm(0x0,0x400,1);
344     ioperm(0x400,0x10000-0x400,1);
345 #endif
346     iopl(3);
347 }
348
349 long PMAPI PM_getOSType(void)
350 { return _OS_LINUX; }
351
352 int PMAPI PM_getModeType(void)
353 { return PM_386; }
354
355 void PMAPI PM_backslash(char *s)
356 {
357     uint pos = strlen(s);
358     if (s[pos-1] != '/') {
359         s[pos] = '/';
360         s[pos+1] = '\0';
361         }
362 }
363
364 void PMAPI PM_setFatalErrorCleanup(
365     void (PMAPIP cleanup)(void))
366 {
367     fatalErrorCleanup = cleanup;
368 }
369
370 void PMAPI PM_fatalError(const char *msg)
371 {
372     if (fatalErrorCleanup)
373         fatalErrorCleanup();
374     fprintf(stderr,"%s\n", msg);
375     fflush(stderr);
376     exit(1);
377 }
378
379 static void ExitVBEBuf(void)
380 {
381     if (VESABuf_ptr)
382         PM_freeRealSeg(VESABuf_ptr);
383     VESABuf_ptr = 0;
384 }
385
386 void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff)
387 {
388     if (!VESABuf_ptr) {
389         /* Allocate a global buffer for communicating with the VESA VBE */
390         if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL)
391             return NULL;
392         atexit(ExitVBEBuf);
393         }
394     *len = VESABuf_len;
395     *rseg = VESABuf_rseg;
396     *roff = VESABuf_roff;
397     return VESABuf_ptr;
398 }
399
400 /* New raw console based getch and kbhit functions */
401
402 #define KB_CAPS     LED_CAP /* 4 */
403 #define KB_NUMLOCK  LED_NUM /* 2 */
404 #define KB_SCROLL   LED_SCR /* 1 */
405 #define KB_SHIFT    8
406 #define KB_CONTROL  16
407 #define KB_ALT      32
408
409 /* Structure used to save the keyboard mode to disk. We save it to disk
410  * so that we can properly restore the mode later if the program crashed.
411  */
412
413 typedef struct {
414     struct termios  termios;
415     int             kb_mode;
416     int             leds;
417     int             flags;
418     int             startup_vc;
419     } keyboard_mode;
420
421 /* Name of the file used to save keyboard mode information */
422
423 #define KBMODE_DAT  "kbmode.dat"
424
425 /****************************************************************************
426 REMARKS:
427 Open the keyboard mode file on disk.
428 ****************************************************************************/
429 static FILE *open_kb_mode(
430     char *mode,
431     char *path)
432 {
433     if (!PM_findBPD("graphics.bpd",path))
434         return NULL;
435     PM_backslash(path);
436     strcat(path,KBMODE_DAT);
437     return fopen(path,mode);
438 }
439
440 /****************************************************************************
441 REMARKS:
442 Restore the keyboard to normal mode
443 ****************************************************************************/
444 void _PM_restore_kb_mode(void)
445 {
446     FILE            *kbmode;
447     keyboard_mode   mode;
448     char            path[PM_MAX_PATH];
449
450     if (_PM_console_fd != -1 && (kbmode = open_kb_mode("rb",path)) != NULL) {
451         if (fread(&mode,1,sizeof(mode),kbmode) == sizeof(mode)) {
452             if (mode.startup_vc > 0)
453                 ioctl(_PM_console_fd, VT_ACTIVATE, mode.startup_vc);
454             ioctl(_PM_console_fd, KDSKBMODE, mode.kb_mode);
455             ioctl(_PM_console_fd, KDSETLED, mode.leds);
456             tcsetattr(_PM_console_fd, TCSAFLUSH, &mode.termios);
457             fcntl(_PM_console_fd,F_SETFL,mode.flags);
458             }
459         fclose(kbmode);
460         unlink(path);
461         in_raw_mode = false;
462         }
463 }
464
465 /****************************************************************************
466 REMARKS:
467 Safely abort the event module upon catching a fatal error.
468 ****************************************************************************/
469 void _PM_abort(
470     int signo)
471 {
472     char    buf[80];
473
474     sprintf(buf,"Terminating on signal %d",signo);
475     _PM_restore_kb_mode();
476     PM_fatalError(buf);
477 }
478
479 /****************************************************************************
480 REMARKS:
481 Put the keyboard into raw mode
482 ****************************************************************************/
483 void _PM_keyboard_rawmode(void)
484 {
485     struct termios conf;
486     FILE            *kbmode;
487     keyboard_mode   mode;
488     char            path[PM_MAX_PATH];
489     int             i;
490     static int sig_list[] = {
491         SIGHUP,
492         SIGINT,
493         SIGQUIT,
494         SIGILL,
495         SIGTRAP,
496         SIGABRT,
497         SIGIOT,
498         SIGBUS,
499         SIGFPE,
500         SIGKILL,
501         SIGSEGV,
502         SIGTERM,
503         };
504
505     if ((kbmode = open_kb_mode("rb",path)) == NULL) {
506         if ((kbmode = open_kb_mode("wb",path)) == NULL)
507             PM_fatalError("Unable to open kbmode.dat file for writing!");
508         if (ioctl(_PM_console_fd, KDGKBMODE, &mode.kb_mode))
509             perror("KDGKBMODE");
510         ioctl(_PM_console_fd, KDGETLED, &mode.leds);
511         _PM_leds = mode.leds & 0xF;
512         _PM_modifiers = 0;
513         tcgetattr(_PM_console_fd, &mode.termios);
514         conf = mode.termios;
515         conf.c_lflag &= ~(ICANON | ECHO | ISIG);
516         conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
517         conf.c_iflag  |= (IGNBRK | IGNPAR);
518         conf.c_cc[VMIN] = 1;
519         conf.c_cc[VTIME] = 0;
520         conf.c_cc[VSUSP] = 0;
521         tcsetattr(_PM_console_fd, TCSAFLUSH, &conf);
522         mode.flags = fcntl(_PM_console_fd,F_GETFL);
523         if (ioctl(_PM_console_fd, KDSKBMODE, K_MEDIUMRAW))
524             perror("KDSKBMODE");
525         atexit(_PM_restore_kb_mode);
526         for (i = 0; i < sizeof(sig_list)/sizeof(sig_list[0]); i++)
527             signal(sig_list[i], _PM_abort);
528         mode.startup_vc = startup_vc;
529         if (fwrite(&mode,1,sizeof(mode),kbmode) != sizeof(mode))
530             PM_fatalError("Error writing kbmode.dat!");
531         fclose(kbmode);
532         in_raw_mode = true;
533         }
534 }
535
536 int PMAPI PM_kbhit(void)
537 {
538     fd_set s;
539     struct timeval tv = { 0, 0 };
540
541     if (console_count == 0)
542         PM_fatalError("You *must* open a console before using PM_kbhit!");
543     if (!in_raw_mode)
544         _PM_keyboard_rawmode();
545     FD_ZERO(&s);
546     FD_SET(_PM_console_fd, &s);
547     return select(_PM_console_fd+1, &s, NULL, NULL, &tv) > 0;
548 }
549
550 int PMAPI PM_getch(void)
551 {
552     static uchar    c;
553     int release;
554     static struct kbentry ke;
555
556     if (console_count == 0)
557         PM_fatalError("You *must* open a console before using PM_getch!");
558     if (!in_raw_mode)
559         _PM_keyboard_rawmode();
560     while (read(_PM_console_fd, &c, 1) > 0) {
561         release = c & 0x80;
562         c &= 0x7F;
563         if (release) {
564             switch(c){
565                 case 42: case 54: // Shift
566                     _PM_modifiers &= ~KB_SHIFT;
567                     break;
568                 case 29: case 97: // Control
569                     _PM_modifiers &= ~KB_CONTROL;
570                     break;
571                 case 56: case 100: // Alt / AltGr
572                     _PM_modifiers &= ~KB_ALT;
573                     break;
574                 }
575             continue;
576             }
577         switch (c) {
578             case 42: case 54: // Shift
579                 _PM_modifiers |= KB_SHIFT;
580                  break;
581             case 29: case 97: // Control
582                 _PM_modifiers |= KB_CONTROL;
583                 break;
584             case 56: case 100: // Alt / AltGr
585                 _PM_modifiers |= KB_ALT;
586                 break;
587             case 58: // Caps Lock
588                 _PM_modifiers ^= KB_CAPS;
589                 ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
590                 break;
591             case 69: // Num Lock
592                 _PM_modifiers ^= KB_NUMLOCK;
593                 ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
594                 break;
595             case 70: // Scroll Lock
596                 _PM_modifiers ^= KB_SCROLL;
597                 ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
598                 break;
599             case 28:
600                 return 0x1C;
601             default:
602                 ke.kb_index = c;
603                 ke.kb_table = 0;
604                 if ((_PM_modifiers & KB_SHIFT) || (_PM_modifiers & KB_CAPS))
605                     ke.kb_table |= K_SHIFTTAB;
606                 if (_PM_modifiers & KB_ALT)
607                     ke.kb_table |= K_ALTTAB;
608                 ioctl(_PM_console_fd, KDGKBENT, (ulong)&ke);
609                 c = ke.kb_value & 0xFF;
610                 return c;
611             }
612         }
613     return 0;
614 }
615
616 /****************************************************************************
617 REMARKS:
618 Sleep until the virtual terminal is active
619 ****************************************************************************/
620 static void wait_vt_active(
621     int _PM_console_fd)
622 {
623     while (ioctl(_PM_console_fd, VT_WAITACTIVE, tty_vc) < 0) {
624         if ((errno != EAGAIN) && (errno != EINTR)) {
625             perror("ioctl(VT_WAITACTIVE)");
626             exit(1);
627             }
628         usleep(150000);
629         }
630 }
631
632 /****************************************************************************
633 REMARKS:
634 Checks the owner of the specified virtual console.
635 ****************************************************************************/
636 static int check_owner(
637     int vc)
638 {
639     struct stat sbuf;
640     char fname[30];
641
642     sprintf(fname, "/dev/tty%d", vc);
643     if ((stat(fname, &sbuf) >= 0) && (getuid() == sbuf.st_uid))
644         return 1;
645     printf("You must be the owner of the current console to use this program.\n");
646     return 0;
647 }
648
649 /****************************************************************************
650 REMARKS:
651 Checks if the console is currently in graphics mode, and if so we forcibly
652 restore it back to text mode again. This handles the case when a Nucleus or
653 MGL program crashes and leaves the console in graphics mode. Running the
654 textmode utility (or any other Nucleus/MGL program) via a telnet session
655 into the machine will restore it back to normal.
656 ****************************************************************************/
657 static void restore_text_console(
658     int console_id)
659 {
660     if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
661         LOGWARN("ioctl(KDSETMODE) failed");
662     _PM_restore_kb_mode();
663 }
664
665 /****************************************************************************
666 REMARKS:
667 Opens up the console device for output by finding an appropriate virutal
668 console that we can run on.
669 ****************************************************************************/
670 PM_HWND PMAPI PM_openConsole(
671     PM_HWND hwndUser,
672     int device,
673     int xRes,
674     int yRes,
675     int bpp,
676     ibool fullScreen)
677 {
678     struct vt_mode  vtm;
679     struct vt_stat  vts;
680     struct stat     sbuf;
681     char            fname[30];
682
683     /* Check if we have already opened the console */
684     if (console_count++)
685         return _PM_console_fd;
686
687     /* Now, it would be great if we could use /dev/tty and see what it is
688      * connected to. Alas, we cannot find out reliably what VC /dev/tty is
689      * bound to. Thus we parse stdin through stderr for a reliable VC.
690      */
691     startup_vc = 0;
692     for (_PM_console_fd = 0; _PM_console_fd < 3; _PM_console_fd++) {
693         if (fstat(_PM_console_fd, &sbuf) < 0)
694             continue;
695         if (ioctl(_PM_console_fd, VT_GETMODE, &vtm) < 0)
696             continue;
697         if ((sbuf.st_rdev & 0xFF00) != 0x400)
698             continue;
699         if (!(sbuf.st_rdev & 0xFF))
700             continue;
701         tty_vc = sbuf.st_rdev & 0xFF;
702         restore_text_console(_PM_console_fd);
703         return _PM_console_fd;
704         }
705     if ((_PM_console_fd = open("/dev/console", O_RDWR)) < 0) {
706         printf("open_dev_console: can't open /dev/console \n");
707         exit(1);
708         }
709     if (ioctl(_PM_console_fd, VT_OPENQRY, &tty_vc) < 0)
710         goto Error;
711     if (tty_vc <= 0)
712         goto Error;
713     sprintf(fname, "/dev/tty%d", tty_vc);
714     close(_PM_console_fd);
715
716     /* Change our control terminal */
717     setsid();
718
719     /* We must use RDWR to allow for output... */
720     if (((_PM_console_fd = open(fname, O_RDWR)) >= 0) &&
721             (ioctl(_PM_console_fd, VT_GETSTATE, &vts) >= 0)) {
722         if (!check_owner(vts.v_active))
723             goto Error;
724         restore_text_console(_PM_console_fd);
725
726         /* Success, redirect all stdios */
727         fflush(stdin);
728         fflush(stdout);
729         fflush(stderr);
730         close(0);
731         close(1);
732         close(2);
733         dup(_PM_console_fd);
734         dup(_PM_console_fd);
735         dup(_PM_console_fd);
736
737         /* clear screen and switch to it */
738         fwrite("\e[H\e[J", 6, 1, stderr);
739         fflush(stderr);
740         if (tty_vc != vts.v_active) {
741             startup_vc = vts.v_active;
742             ioctl(_PM_console_fd, VT_ACTIVATE, tty_vc);
743             wait_vt_active(_PM_console_fd);
744             }
745         }
746     return _PM_console_fd;
747
748 Error:
749     if (_PM_console_fd > 2)
750         close(_PM_console_fd);
751     console_count = 0;
752     PM_fatalError(
753         "Not running in a graphics capable console,\n"
754         "and unable to find one.\n");
755     return -1;
756 }
757
758 #define FONT_C  0x10000     /* 64KB for font data                       */
759
760 /****************************************************************************
761 REMARKS:
762 Returns the size of the console state buffer.
763 ****************************************************************************/
764 int PMAPI PM_getConsoleStateSize(void)
765 {
766     if (!inited)
767         PM_init();
768     return PM_getVGAStateSize() + FONT_C*2;
769 }
770
771 /****************************************************************************
772 REMARKS:
773 Save the state of the Linux console.
774 ****************************************************************************/
775 void PMAPI PM_saveConsoleState(void *stateBuf,int console_id)
776 {
777     uchar   *regs = stateBuf;
778
779     /* Save the current console font */
780     if (ioctl(console_id,GIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
781         perror("ioctl(GIO_FONT)");
782
783     /* Inform the Linux console that we are going into graphics mode */
784     if (ioctl(console_id, KDSETMODE, KD_GRAPHICS) < 0)
785         perror("ioctl(KDSETMODE)");
786
787     /* Save state of VGA registers */
788     PM_saveVGAState(stateBuf);
789 }
790
791 void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
792 {
793     /* TODO: Implement support for allowing console switching! */
794 }
795
796 /****************************************************************************
797 REMARKS:
798 Restore the state of the Linux console.
799 ****************************************************************************/
800 void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND console_id)
801 {
802     const uchar *regs = stateBuf;
803
804     /* Restore the state of the VGA compatible registers */
805     PM_restoreVGAState(stateBuf);
806
807     /* Inform the Linux console that we are back from graphics modes */
808     if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
809         LOGWARN("ioctl(KDSETMODE) failed");
810
811     /* Restore the old console font */
812     if (ioctl(console_id,PIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
813         LOGWARN("ioctl(KDSETMODE) failed");
814
815     /* Coming back from graphics mode on Linux also restored the previous
816      * text mode console contents, so we need to clear the screen to get
817      * around this since the cursor does not get homed by our code.
818      */
819     fflush(stdout);
820     fflush(stderr);
821     printf("\033[H\033[J");
822     fflush(stdout);
823 }
824
825 /****************************************************************************
826 REMARKS:
827 Close the Linux console and put it back to normal.
828 ****************************************************************************/
829 void PMAPI PM_closeConsole(PM_HWND _PM_console_fd)
830 {
831     /* Restore console to normal operation */
832     if (--console_count == 0) {
833         /* Re-activate the original virtual console */
834         if (startup_vc > 0)
835             ioctl(_PM_console_fd, VT_ACTIVATE, startup_vc);
836
837         /* Close the console file descriptor */
838         if (_PM_console_fd > 2)
839             close(_PM_console_fd);
840         _PM_console_fd = -1;
841         }
842 }
843
844 void PM_setOSCursorLocation(int x,int y)
845 {
846     /* Nothing to do in here */
847 }
848
849 /****************************************************************************
850 REMARKS:
851 Set the screen width and height for the Linux console.
852 ****************************************************************************/
853 void PM_setOSScreenWidth(int width,int height)
854 {
855     struct winsize  ws;
856     struct vt_sizes vs;
857
858     // Resize the software terminal
859     ws.ws_col = width;
860     ws.ws_row = height;
861     ioctl(_PM_console_fd, TIOCSWINSZ, &ws);
862
863     // And the hardware
864     vs.v_rows = height;
865     vs.v_cols = width;
866     vs.v_scrollsize = 0;
867     ioctl(_PM_console_fd, VT_RESIZE, &vs);
868 }
869
870 ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency)
871 {
872     // TODO: Implement this for Linux
873     return false;
874 }
875
876 void PMAPI PM_setRealTimeClockFrequency(int frequency)
877 {
878     // TODO: Implement this for Linux
879 }
880
881 void PMAPI PM_restoreRealTimeClockHandler(void)
882 {
883     // TODO: Implement this for Linux
884 }
885
886 char * PMAPI PM_getCurrentPath(
887     char *path,
888     int maxLen)
889 {
890     return getcwd(path,maxLen);
891 }
892
893 char PMAPI PM_getBootDrive(void)
894 { return '/'; }
895
896 const char * PMAPI PM_getVBEAFPath(void)
897 { return PM_getNucleusConfigPath(); }
898
899 const char * PMAPI PM_getNucleusPath(void)
900 {
901     char *env = getenv("NUCLEUS_PATH");
902     return env ? env : "/usr/lib/nucleus";
903 }
904
905 const char * PMAPI PM_getNucleusConfigPath(void)
906 {
907     static char path[256];
908     strcpy(path,PM_getNucleusPath());
909     PM_backslash(path);
910     strcat(path,"config");
911     return path;
912 }
913
914 const char * PMAPI PM_getUniqueID(void)
915 {
916     static char buf[128];
917     gethostname(buf, 128);
918     return buf;
919 }
920
921 const char * PMAPI PM_getMachineName(void)
922 {
923     static char buf[128];
924     gethostname(buf, 128);
925     return buf;
926 }
927
928 void * PMAPI PM_getBIOSPointer(void)
929 {
930     static uchar *zeroPtr = NULL;
931     if (!zeroPtr)
932         zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
933     return (void*)(zeroPtr + 0x400);
934 }
935
936 void * PMAPI PM_getA0000Pointer(void)
937 {
938     /* PM_init maps in the 0xA0000 framebuffer region 1:1 with our
939      * address mapping, so we can return the address here.
940      */
941     if (!inited)
942         PM_init();
943     return (void*)(0xA0000);
944 }
945
946 void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
947 {
948     uchar   *p;
949     ulong   baseAddr,baseOfs;
950
951     if (!inited)
952         PM_init();
953     if (base >= 0xA0000 && base < 0x100000)
954         return (void*)base;
955     if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1)
956         return NULL;
957
958     /* Round the physical address to a 4Kb boundary and the limit to a
959      * 4Kb-1 boundary before passing the values to mmap. If we round the
960      * physical address, then we also add an extra offset into the address
961      * that we return.
962      */
963     baseOfs = base & 4095;
964     baseAddr = base & ~4095;
965     limit = ((limit+baseOfs+1+4095) & ~4095)-1;
966     if ((p = mmap(0, limit+1,
967             PROT_READ | PROT_WRITE, MAP_SHARED,
968             fd_mem, baseAddr)) == (void *)-1)
969         return NULL;
970     return (void*)(p+baseOfs);
971 }
972
973 void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
974 {
975     if ((ulong)ptr >= 0x100000)
976         munmap(ptr,limit+1);
977 }
978
979 ulong PMAPI PM_getPhysicalAddr(void *p)
980 {
981     // TODO: This function should find the physical address of a linear
982     //       address.
983     return 0xFFFFFFFFUL;
984 }
985
986 ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
987 {
988     // TODO: This function should find a range of physical addresses
989     //       for a linear address.
990     return false;
991 }
992
993 void PMAPI PM_sleep(ulong milliseconds)
994 {
995     // TODO: Put the process to sleep for milliseconds
996 }
997
998 int PMAPI PM_getCOMPort(int port)
999 {
1000     // TODO: Re-code this to determine real values using the Plug and Play
1001     //       manager for the OS.
1002     switch (port) {
1003         case 0: return 0x3F8;
1004         case 1: return 0x2F8;
1005         }
1006     return 0;
1007 }
1008
1009 int PMAPI PM_getLPTPort(int port)
1010 {
1011     // TODO: Re-code this to determine real values using the Plug and Play
1012     //       manager for the OS.
1013     switch (port) {
1014         case 0: return 0x3BC;
1015         case 1: return 0x378;
1016         case 2: return 0x278;
1017         }
1018     return 0;
1019 }
1020
1021 void * PMAPI PM_mallocShared(long size)
1022 {
1023     return PM_malloc(size);
1024 }
1025
1026 void PMAPI PM_freeShared(void *ptr)
1027 {
1028     PM_free(ptr);
1029 }
1030
1031 void * PMAPI PM_mapToProcess(void *base,ulong limit)
1032 { return (void*)base; }
1033
1034 void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
1035 {
1036     /* PM_init maps in the 0xA0000-0x100000 region 1:1 with our
1037      * address mapping, as well as all memory blocks in a 1:1 address
1038      * mapping so we can simply return the physical address in here.
1039      */
1040     if (!inited)
1041         PM_init();
1042     return (void*)MK_PHYS(r_seg,r_off);
1043 }
1044
1045 void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
1046 {
1047     int     i;
1048     char    *r = (char *)REAL_MEM_BASE;
1049
1050     if (!inited)
1051         PM_init();
1052     if (!mem_info.ready)
1053         return NULL;
1054     if (mem_info.count == REAL_MEM_BLOCKS)
1055         return NULL;
1056     size = (size + 15) & ~15;
1057     for (i = 0; i < mem_info.count; i++) {
1058         if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) {
1059             insert_block(i);
1060             mem_info.blocks[i].size = size;
1061             mem_info.blocks[i].free = 0;
1062             mem_info.blocks[i + 1].size -= size;
1063             *r_seg = (uint)(r) >> 4;
1064             *r_off = (uint)(r) & 0xF;
1065             return (void *)r;
1066             }
1067         r += mem_info.blocks[i].size;
1068         }
1069     return NULL;
1070 }
1071
1072 void PMAPI PM_freeRealSeg(void *mem)
1073 {
1074     int     i;
1075     char    *r = (char *)REAL_MEM_BASE;
1076
1077     if (!mem_info.ready)
1078         return;
1079     i = 0;
1080     while (mem != (void *)r) {
1081         r += mem_info.blocks[i].size;
1082         i++;
1083         if (i == mem_info.count)
1084             return;
1085         }
1086     mem_info.blocks[i].free = 1;
1087     if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) {
1088         mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
1089         delete_block(i + 1);
1090         }
1091     if (i - 1 >= 0 && mem_info.blocks[i - 1].free) {
1092         mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
1093         delete_block(i);
1094         }
1095 }
1096
1097 #define DIRECTION_FLAG  (1 << 10)
1098
1099 static void em_ins(int size)
1100 {
1101     unsigned int edx, edi;
1102
1103     edx = context.vm.regs.edx & 0xffff;
1104     edi = context.vm.regs.edi & 0xffff;
1105     edi += (unsigned int)context.vm.regs.ds << 4;
1106     if (context.vm.regs.eflags & DIRECTION_FLAG) {
1107         if (size == 4)
1108             asm volatile ("std; insl; cld"
1109              : "=D" (edi) : "d" (edx), "0" (edi));
1110         else if (size == 2)
1111             asm volatile ("std; insw; cld"
1112              : "=D" (edi) : "d" (edx), "0" (edi));
1113         else
1114             asm volatile ("std; insb; cld"
1115              : "=D" (edi) : "d" (edx), "0" (edi));
1116         }
1117     else {
1118         if (size == 4)
1119             asm volatile ("cld; insl"
1120              : "=D" (edi) : "d" (edx), "0" (edi));
1121         else if (size == 2)
1122             asm volatile ("cld; insw"
1123              : "=D" (edi) : "d" (edx), "0" (edi));
1124         else
1125             asm volatile ("cld; insb"
1126              : "=D" (edi) : "d" (edx), "0" (edi));
1127         }
1128     edi -= (unsigned int)context.vm.regs.ds << 4;
1129     context.vm.regs.edi &= 0xffff0000;
1130     context.vm.regs.edi |= edi & 0xffff;
1131 }
1132
1133 static void em_rep_ins(int size)
1134 {
1135     unsigned int ecx, edx, edi;
1136
1137     ecx = context.vm.regs.ecx & 0xffff;
1138     edx = context.vm.regs.edx & 0xffff;
1139     edi = context.vm.regs.edi & 0xffff;
1140     edi += (unsigned int)context.vm.regs.ds << 4;
1141     if (context.vm.regs.eflags & DIRECTION_FLAG) {
1142         if (size == 4)
1143             asm volatile ("std; rep; insl; cld"
1144              : "=D" (edi), "=c" (ecx)
1145              : "d" (edx), "0" (edi), "1" (ecx));
1146         else if (size == 2)
1147             asm volatile ("std; rep; insw; cld"
1148              : "=D" (edi), "=c" (ecx)
1149              : "d" (edx), "0" (edi), "1" (ecx));
1150         else
1151             asm volatile ("std; rep; insb; cld"
1152              : "=D" (edi), "=c" (ecx)
1153              : "d" (edx), "0" (edi), "1" (ecx));
1154         }
1155     else {
1156         if (size == 4)
1157             asm volatile ("cld; rep; insl"
1158              : "=D" (edi), "=c" (ecx)
1159              : "d" (edx), "0" (edi), "1" (ecx));
1160         else if (size == 2)
1161             asm volatile ("cld; rep; insw"
1162              : "=D" (edi), "=c" (ecx)
1163              : "d" (edx), "0" (edi), "1" (ecx));
1164         else
1165             asm volatile ("cld; rep; insb"
1166              : "=D" (edi), "=c" (ecx)
1167              : "d" (edx), "0" (edi), "1" (ecx));
1168         }
1169
1170     edi -= (unsigned int)context.vm.regs.ds << 4;
1171     context.vm.regs.edi &= 0xffff0000;
1172     context.vm.regs.edi |= edi & 0xffff;
1173     context.vm.regs.ecx &= 0xffff0000;
1174     context.vm.regs.ecx |= ecx & 0xffff;
1175 }
1176
1177 static void em_outs(int size)
1178 {
1179     unsigned int edx, esi;
1180
1181     edx = context.vm.regs.edx & 0xffff;
1182     esi = context.vm.regs.esi & 0xffff;
1183     esi += (unsigned int)context.vm.regs.ds << 4;
1184     if (context.vm.regs.eflags & DIRECTION_FLAG) {
1185         if (size == 4)
1186             asm volatile ("std; outsl; cld"
1187              : "=S" (esi) : "d" (edx), "0" (esi));
1188         else if (size == 2)
1189             asm volatile ("std; outsw; cld"
1190              : "=S" (esi) : "d" (edx), "0" (esi));
1191         else
1192             asm volatile ("std; outsb; cld"
1193              : "=S" (esi) : "d" (edx), "0" (esi));
1194         }
1195     else {
1196         if (size == 4)
1197             asm volatile ("cld; outsl"
1198              : "=S" (esi) : "d" (edx), "0" (esi));
1199         else if (size == 2)
1200             asm volatile ("cld; outsw"
1201              : "=S" (esi) : "d" (edx), "0" (esi));
1202         else
1203             asm volatile ("cld; outsb"
1204              : "=S" (esi) : "d" (edx), "0" (esi));
1205         }
1206
1207     esi -= (unsigned int)context.vm.regs.ds << 4;
1208     context.vm.regs.esi &= 0xffff0000;
1209     context.vm.regs.esi |= esi & 0xffff;
1210 }
1211
1212 static void em_rep_outs(int size)
1213 {
1214     unsigned int ecx, edx, esi;
1215
1216     ecx = context.vm.regs.ecx & 0xffff;
1217     edx = context.vm.regs.edx & 0xffff;
1218     esi = context.vm.regs.esi & 0xffff;
1219     esi += (unsigned int)context.vm.regs.ds << 4;
1220     if (context.vm.regs.eflags & DIRECTION_FLAG) {
1221         if (size == 4)
1222             asm volatile ("std; rep; outsl; cld"
1223              : "=S" (esi), "=c" (ecx)
1224              : "d" (edx), "0" (esi), "1" (ecx));
1225         else if (size == 2)
1226             asm volatile ("std; rep; outsw; cld"
1227              : "=S" (esi), "=c" (ecx)
1228              : "d" (edx), "0" (esi), "1" (ecx));
1229         else
1230             asm volatile ("std; rep; outsb; cld"
1231              : "=S" (esi), "=c" (ecx)
1232              : "d" (edx), "0" (esi), "1" (ecx));
1233         }
1234     else {
1235         if (size == 4)
1236             asm volatile ("cld; rep; outsl"
1237              : "=S" (esi), "=c" (ecx)
1238              : "d" (edx), "0" (esi), "1" (ecx));
1239         else if (size == 2)
1240             asm volatile ("cld; rep; outsw"
1241              : "=S" (esi), "=c" (ecx)
1242              : "d" (edx), "0" (esi), "1" (ecx));
1243         else
1244             asm volatile ("cld; rep; outsb"
1245              : "=S" (esi), "=c" (ecx)
1246              : "d" (edx), "0" (esi), "1" (ecx));
1247         }
1248
1249     esi -= (unsigned int)context.vm.regs.ds << 4;
1250     context.vm.regs.esi &= 0xffff0000;
1251     context.vm.regs.esi |= esi & 0xffff;
1252     context.vm.regs.ecx &= 0xffff0000;
1253     context.vm.regs.ecx |= ecx & 0xffff;
1254 }
1255
1256 static int emulate(void)
1257 {
1258     unsigned char *insn;
1259     struct {
1260         unsigned int size : 1;
1261         unsigned int rep : 1;
1262         } prefix = { 0, 0 };
1263     int i = 0;
1264
1265     insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4);
1266     insn += context.vm.regs.eip;
1267
1268     while (1) {
1269 #ifdef TRACE_IO
1270         traceAddr = ((ulong)context.vm.regs.cs << 16) + context.vm.regs.eip + i;
1271 #endif
1272         if (insn[i] == 0x66) {
1273             prefix.size = 1 - prefix.size;
1274             i++;
1275             }
1276         else if (insn[i] == 0xf3) {
1277             prefix.rep = 1;
1278             i++;
1279             }
1280         else if (insn[i] == 0xf0 || insn[i] == 0xf2
1281              || insn[i] == 0x26 || insn[i] == 0x2e
1282              || insn[i] == 0x36 || insn[i] == 0x3e
1283              || insn[i] == 0x64 || insn[i] == 0x65
1284              || insn[i] == 0x67) {
1285             /* these prefixes are just ignored */
1286             i++;
1287             }
1288         else if (insn[i] == 0x6c) {
1289             if (prefix.rep)
1290                 em_rep_ins(1);
1291             else
1292                 em_ins(1);
1293             i++;
1294             break;
1295             }
1296         else if (insn[i] == 0x6d) {
1297             if (prefix.rep) {
1298                 if (prefix.size)
1299                     em_rep_ins(4);
1300                 else
1301                     em_rep_ins(2);
1302                 }
1303             else {
1304                 if (prefix.size)
1305                     em_ins(4);
1306                 else
1307                     em_ins(2);
1308                 }
1309             i++;
1310             break;
1311             }
1312         else if (insn[i] == 0x6e) {
1313             if (prefix.rep)
1314                 em_rep_outs(1);
1315             else
1316                 em_outs(1);
1317             i++;
1318             break;
1319             }
1320         else if (insn[i] == 0x6f) {
1321             if (prefix.rep) {
1322                 if (prefix.size)
1323                     em_rep_outs(4);
1324                 else
1325                     em_rep_outs(2);
1326                 }
1327             else {
1328                 if (prefix.size)
1329                     em_outs(4);
1330                 else
1331                     em_outs(2);
1332                 }
1333             i++;
1334             break;
1335             }
1336         else if (insn[i] == 0xec) {
1337             *((uchar*)&context.vm.regs.eax) = port_in(context.vm.regs.edx);
1338             i++;
1339             break;
1340             }
1341         else if (insn[i] == 0xed) {
1342             if (prefix.size)
1343                 *((ulong*)&context.vm.regs.eax) = port_inl(context.vm.regs.edx);
1344             else
1345                 *((ushort*)&context.vm.regs.eax) = port_inw(context.vm.regs.edx);
1346             i++;
1347             break;
1348             }
1349         else if (insn[i] == 0xee) {
1350             port_out(context.vm.regs.eax,context.vm.regs.edx);
1351             i++;
1352             break;
1353             }
1354         else if (insn[i] == 0xef) {
1355             if (prefix.size)
1356                 port_outl(context.vm.regs.eax,context.vm.regs.edx);
1357             else
1358                 port_outw(context.vm.regs.eax,context.vm.regs.edx);
1359             i++;
1360             break;
1361             }
1362         else
1363             return 0;
1364         }
1365
1366     context.vm.regs.eip += i;
1367     return 1;
1368 }
1369
1370 static void debug_info(int vret)
1371 {
1372     int i;
1373     unsigned char *p;
1374
1375     fputs("vm86() failed\n", stderr);
1376     fprintf(stderr, "return = 0x%x\n", vret);
1377     fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax);
1378     fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx);
1379     fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx);
1380     fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx);
1381     fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi);
1382     fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi);
1383     fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp);
1384     fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip);
1385     fprintf(stderr, "cs  = 0x%04x\n", context.vm.regs.cs);
1386     fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp);
1387     fprintf(stderr, "ss  = 0x%04x\n", context.vm.regs.ss);
1388     fprintf(stderr, "ds  = 0x%04x\n", context.vm.regs.ds);
1389     fprintf(stderr, "es  = 0x%04x\n", context.vm.regs.es);
1390     fprintf(stderr, "fs  = 0x%04x\n", context.vm.regs.fs);
1391     fprintf(stderr, "gs  = 0x%04x\n", context.vm.regs.gs);
1392     fprintf(stderr, "eflags  = 0x%08lx\n", context.vm.regs.eflags);
1393     fputs("cs:ip = [ ", stderr);
1394     p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff));
1395     for (i = 0; i < 16; ++i)
1396             fprintf(stderr, "%02x ", (unsigned int)p[i]);
1397     fputs("]\n", stderr);
1398     fflush(stderr);
1399 }
1400
1401 static int run_vm86(void)
1402 {
1403     unsigned int vret;
1404
1405     for (;;) {
1406         vret = vm86(&context.vm);
1407         if (VM86_TYPE(vret) == VM86_INTx) {
1408             unsigned int v = VM86_ARG(vret);
1409             if (v == RETURN_TO_32_INT)
1410                 return 1;
1411             pushw(context.vm.regs.eflags);
1412             pushw(context.vm.regs.cs);
1413             pushw(context.vm.regs.eip);
1414             context.vm.regs.cs = get_int_seg(v);
1415             context.vm.regs.eip = get_int_off(v);
1416             context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK);
1417             continue;
1418             }
1419         if (VM86_TYPE(vret) != VM86_UNKNOWN)
1420             break;
1421         if (!emulate())
1422             break;
1423         }
1424     debug_info(vret);
1425     return 0;
1426 }
1427
1428 #define IND(ereg) context.vm.regs.ereg = regs->ereg
1429 #define OUTD(ereg) regs->ereg = context.vm.regs.ereg
1430
1431 void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
1432 {
1433     if (!inited)
1434         PM_init();
1435     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
1436     IND(eax); IND(ebx); IND(ecx); IND(edx); IND(esi); IND(edi);
1437     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1438     context.vm.regs.cs = get_int_seg(intno);
1439     context.vm.regs.eip = get_int_off(intno);
1440     context.vm.regs.ss = context.stack_seg;
1441     context.vm.regs.esp = context.stack_off;
1442     pushw(DEFAULT_VM86_FLAGS);
1443     pushw(context.ret_seg);
1444     pushw(context.ret_off);
1445     run_vm86();
1446     OUTD(eax); OUTD(ebx); OUTD(ecx); OUTD(edx); OUTD(esi); OUTD(edi);
1447     regs->flags = context.vm.regs.eflags;
1448 }
1449
1450 #define IN(ereg) context.vm.regs.ereg = in->e.ereg
1451 #define OUT(ereg) out->e.ereg = context.vm.regs.ereg
1452
1453 int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
1454 {
1455     if (!inited)
1456         PM_init();
1457     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
1458     IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
1459     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1460     context.vm.regs.cs = get_int_seg(intno);
1461     context.vm.regs.eip = get_int_off(intno);
1462     context.vm.regs.ss = context.stack_seg;
1463     context.vm.regs.esp = context.stack_off;
1464     pushw(DEFAULT_VM86_FLAGS);
1465     pushw(context.ret_seg);
1466     pushw(context.ret_off);
1467     run_vm86();
1468     OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
1469     out->x.cflag = context.vm.regs.eflags & 1;
1470     return out->x.ax;
1471 }
1472
1473 int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
1474     RMSREGS *sregs)
1475 {
1476     if (!inited)
1477         PM_init();
1478     if (intno == 0x21) {
1479         time_t today = time(NULL);
1480         struct tm *t;
1481         t = localtime(&today);
1482         out->x.cx = t->tm_year + 1900;
1483         out->h.dh = t->tm_mon + 1;
1484         out->h.dl = t->tm_mday;
1485         }
1486     else {
1487         unsigned int seg, off;
1488         seg = get_int_seg(intno);
1489         off = get_int_off(intno);
1490         memset(&context.vm.regs, 0, sizeof(context.vm.regs));
1491         IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
1492         context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1493         context.vm.regs.cs = seg;
1494         context.vm.regs.eip = off;
1495         context.vm.regs.es = sregs->es;
1496         context.vm.regs.ds = sregs->ds;
1497         context.vm.regs.fs = sregs->fs;
1498         context.vm.regs.gs = sregs->gs;
1499         context.vm.regs.ss = context.stack_seg;
1500         context.vm.regs.esp = context.stack_off;
1501         pushw(DEFAULT_VM86_FLAGS);
1502         pushw(context.ret_seg);
1503         pushw(context.ret_off);
1504         run_vm86();
1505         OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
1506         sregs->es = context.vm.regs.es;
1507         sregs->ds = context.vm.regs.ds;
1508         sregs->fs = context.vm.regs.fs;
1509         sregs->gs = context.vm.regs.gs;
1510         out->x.cflag = context.vm.regs.eflags & 1;
1511         }
1512     return out->e.eax;
1513 }
1514
1515 #define OUTR(ereg) in->e.ereg = context.vm.regs.ereg
1516
1517 void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
1518     RMSREGS *sregs)
1519 {
1520     if (!inited)
1521         PM_init();
1522     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
1523     IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
1524     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1525     context.vm.regs.cs = seg;
1526     context.vm.regs.eip = off;
1527     context.vm.regs.ss = context.stack_seg;
1528     context.vm.regs.esp = context.stack_off;
1529     context.vm.regs.es = sregs->es;
1530     context.vm.regs.ds = sregs->ds;
1531     context.vm.regs.fs = sregs->fs;
1532     context.vm.regs.gs = sregs->gs;
1533     pushw(DEFAULT_VM86_FLAGS);
1534     pushw(context.ret_seg);
1535     pushw(context.ret_off);
1536     run_vm86();
1537     OUTR(eax); OUTR(ebx); OUTR(ecx); OUTR(edx); OUTR(esi); OUTR(edi);
1538     sregs->es = context.vm.regs.es;
1539     sregs->ds = context.vm.regs.ds;
1540     sregs->fs = context.vm.regs.fs;
1541     sregs->gs = context.vm.regs.gs;
1542     in->x.cflag = context.vm.regs.eflags & 1;
1543 }
1544
1545 void PMAPI PM_availableMemory(ulong *physical,ulong *total)
1546 {
1547     FILE    *mem = fopen("/proc/meminfo","r");
1548     char    buf[1024];
1549
1550     fgets(buf,1024,mem);
1551     fgets(buf,1024,mem);
1552     sscanf(buf,"Mem: %*d %*d %ld", physical);
1553     fgets(buf,1024,mem);
1554     sscanf(buf,"Swap: %*d %*d %ld", total);
1555     fclose(mem);
1556     *total += *physical;
1557 }
1558
1559 void * PMAPI PM_allocLockedMem(uint size,ulong *physAddr,ibool contiguous,ibool below16M)
1560 {
1561     // TODO: Implement this for Linux
1562     return NULL;
1563 }
1564
1565 void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
1566 {
1567     // TODO: Implement this for Linux
1568 }
1569
1570 void * PMAPI PM_allocPage(
1571     ibool locked)
1572 {
1573     // TODO: Implement this for Linux
1574     return NULL;
1575 }
1576
1577 void PMAPI PM_freePage(
1578     void *p)
1579 {
1580     // TODO: Implement this for Linux
1581 }
1582
1583 void PMAPI PM_setBankA(int bank)
1584 {
1585     if (!inited)
1586         PM_init();
1587     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
1588     context.vm.regs.eax = 0x4F05;
1589     context.vm.regs.ebx = 0x0000;
1590     context.vm.regs.edx = bank;
1591     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1592     context.vm.regs.cs = get_int_seg(0x10);
1593     context.vm.regs.eip = get_int_off(0x10);
1594     context.vm.regs.ss = context.stack_seg;
1595     context.vm.regs.esp = context.stack_off;
1596     pushw(DEFAULT_VM86_FLAGS);
1597     pushw(context.ret_seg);
1598     pushw(context.ret_off);
1599     run_vm86();
1600 }
1601
1602 void PMAPI PM_setBankAB(int bank)
1603 {
1604     if (!inited)
1605         PM_init();
1606     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
1607     context.vm.regs.eax = 0x4F05;
1608     context.vm.regs.ebx = 0x0000;
1609     context.vm.regs.edx = bank;
1610     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1611     context.vm.regs.cs = get_int_seg(0x10);
1612     context.vm.regs.eip = get_int_off(0x10);
1613     context.vm.regs.ss = context.stack_seg;
1614     context.vm.regs.esp = context.stack_off;
1615     pushw(DEFAULT_VM86_FLAGS);
1616     pushw(context.ret_seg);
1617     pushw(context.ret_off);
1618     run_vm86();
1619     context.vm.regs.eax = 0x4F05;
1620     context.vm.regs.ebx = 0x0001;
1621     context.vm.regs.edx = bank;
1622     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1623     context.vm.regs.cs = get_int_seg(0x10);
1624     context.vm.regs.eip = get_int_off(0x10);
1625     context.vm.regs.ss = context.stack_seg;
1626     context.vm.regs.esp = context.stack_off;
1627     pushw(DEFAULT_VM86_FLAGS);
1628     pushw(context.ret_seg);
1629     pushw(context.ret_off);
1630     run_vm86();
1631 }
1632
1633 void PMAPI PM_setCRTStart(int x,int y,int waitVRT)
1634 {
1635     if (!inited)
1636         PM_init();
1637     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
1638     context.vm.regs.eax = 0x4F07;
1639     context.vm.regs.ebx = waitVRT;
1640     context.vm.regs.ecx = x;
1641     context.vm.regs.edx = y;
1642     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
1643     context.vm.regs.cs = get_int_seg(0x10);
1644     context.vm.regs.eip = get_int_off(0x10);
1645     context.vm.regs.ss = context.stack_seg;
1646     context.vm.regs.esp = context.stack_off;
1647     pushw(DEFAULT_VM86_FLAGS);
1648     pushw(context.ret_seg);
1649     pushw(context.ret_off);
1650     run_vm86();
1651 }
1652
1653 int PMAPI PM_enableWriteCombine(ulong base,ulong length,uint type)
1654 {
1655 #ifdef ENABLE_MTRR
1656     struct mtrr_sentry sentry;
1657
1658     if (mtrr_fd < 0)
1659         return PM_MTRR_ERR_NO_OS_SUPPORT;
1660     sentry.base = base;
1661     sentry.size = length;
1662     sentry.type = type;
1663     if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) {
1664         // TODO: Need to decode MTRR error codes!!
1665         return PM_MTRR_NOT_SUPPORTED;
1666         }
1667     return PM_MTRR_ERR_OK;
1668 #else
1669     return PM_MTRR_ERR_NO_OS_SUPPORT;
1670 #endif
1671 }
1672
1673 /****************************************************************************
1674 PARAMETERS:
1675 callback    - Function to callback with write combine information
1676
1677 REMARKS:
1678 Function to enumerate all write combine regions currently enabled for the
1679 processor.
1680 ****************************************************************************/
1681 int PMAPI PM_enumWriteCombine(
1682     PM_enumWriteCombine_t callback)
1683 {
1684 #ifdef ENABLE_MTRR
1685     struct mtrr_gentry gentry;
1686
1687     if (mtrr_fd < 0)
1688         return PM_MTRR_ERR_NO_OS_SUPPORT;
1689
1690     for (gentry.regnum = 0; ioctl (mtrr_fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
1691          ++gentry.regnum) {
1692         if (gentry.size > 0) {
1693             // WARNING: This code assumes that the types in pmapi.h match the ones
1694             // in the Linux kernel (mtrr.h)
1695             callback(gentry.base, gentry.size, gentry.type);
1696         }
1697     }
1698
1699     return PM_MTRR_ERR_OK;
1700 #else
1701     return PM_MTRR_ERR_NO_OS_SUPPORT;
1702 #endif
1703 }
1704
1705 ibool PMAPI PM_doBIOSPOST(
1706     ushort axVal,
1707     ulong BIOSPhysAddr,
1708     void *copyOfBIOS,
1709     ulong BIOSLen)
1710 {
1711     char        *bios_ptr = (char*)0xC0000;
1712     char        *old_bios;
1713     ulong       Current10, Current6D, *rvec = 0;
1714     RMREGS      regs;
1715     RMSREGS     sregs;
1716
1717     /* The BIOS is mapped to 0xC0000 with a private memory mapping enabled
1718      * which means we have a copy on write scheme. Hence we simply copy
1719      * the secondary BIOS image over the top of the old one.
1720      */
1721     if (!inited)
1722         PM_init();
1723     if ((old_bios = PM_malloc(BIOSLen)) == NULL)
1724         return false;
1725     if (BIOSPhysAddr != 0xC0000) {
1726         memcpy(old_bios,bios_ptr,BIOSLen);
1727         memcpy(bios_ptr,copyOfBIOS,BIOSLen);
1728         }
1729
1730     /* The interrupt vectors should already be mmap()'ed from 0-0x400 in PM_init */
1731     Current10 = rvec[0x10];
1732     Current6D = rvec[0x6D];
1733
1734     /* POST the secondary BIOS */
1735     rvec[0x10] = rvec[0x42]; /* Restore int 10h to STD-BIOS */
1736     regs.x.ax = axVal;
1737     PM_callRealMode(0xC000,0x0003,&regs,&sregs);
1738
1739     /* Restore interrupt vectors */
1740     rvec[0x10] = Current10;
1741     rvec[0x6D] = Current6D;
1742
1743     /* Restore original BIOS image */
1744     if (BIOSPhysAddr != 0xC0000)
1745         memcpy(bios_ptr,old_bios,BIOSLen);
1746     PM_free(old_bios);
1747     return true;
1748 }
1749
1750 int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
1751 {
1752     p = p;  len = len;
1753     return 1;
1754 }
1755
1756 int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
1757 {
1758     p = p;  len = len;
1759     return 1;
1760 }
1761
1762 int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1763 {
1764     p = p;  len = len;
1765     return 1;
1766 }
1767
1768 int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1769 {
1770     p = p;  len = len;
1771     return 1;
1772 }
1773
1774 PM_MODULE PMAPI PM_loadLibrary(
1775     const char *szDLLName)
1776 {
1777     // TODO: Implement this to load shared libraries!
1778     (void)szDLLName;
1779     return NULL;
1780 }
1781
1782 void * PMAPI PM_getProcAddress(
1783     PM_MODULE hModule,
1784     const char *szProcName)
1785 {
1786     // TODO: Implement this!
1787     (void)hModule;
1788     (void)szProcName;
1789     return NULL;
1790 }
1791
1792 void PMAPI PM_freeLibrary(
1793     PM_MODULE hModule)
1794 {
1795     // TODO: Implement this!
1796     (void)hModule;
1797 }
1798
1799 int PMAPI PM_setIOPL(
1800     int level)
1801 {
1802     // TODO: Move the IOPL switching into this function!!
1803     return level;
1804 }
1805
1806 void PMAPI PM_flushTLB(void)
1807 {
1808     // Do nothing on Linux.
1809 }
1810