]> git.ipfire.org Git - u-boot.git/blame - board/MAI/bios_emulator/scitech/src/pm/linux/pm.c
* Code cleanup:
[u-boot.git] / board / MAI / bios_emulator / scitech / src / pm / linux / pm.c
CommitLineData
c7de829c
WD
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 */
78static int
79vm86(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
100static 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
107struct mem_block {
108 unsigned int size : 20;
109 unsigned int free : 1;
110 };
111
112static struct {
113 int ready;
114 int count;
115 struct mem_block blocks[REAL_MEM_BLOCKS];
116 } mem_info = {0};
117
118int _PM_console_fd = -1;
119int _PM_leds = 0,_PM_modifiers = 0;
120static ibool inited = false;
121static int tty_vc = 0;
122static int console_count = 0;
123static int startup_vc;
124static int fd_mem = 0;
125static ibool in_raw_mode = false;
126#ifdef ENABLE_MTRR
127static int mtrr_fd;
128#endif
129static uint VESABuf_len = 1024; /* Length of the VESABuf buffer */
130static void *VESABuf_ptr = NULL; /* Near pointer to VESABuf */
131static uint VESABuf_rseg; /* Real mode segment of VESABuf */
132static uint VESABuf_roff; /* Real mode offset of VESABuf */
133#ifdef TRACE_IO
134static ulong traceAddr;
135#endif
136
137static void (PMAPIP fatalErrorCleanup)(void) = NULL;
138
139/*----------------------------- Implementation ----------------------------*/
140
141#ifdef TRACE_IO
142extern void printk(char *msg,...);
143#endif
144
145static 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"
8bde7f77 151 ::"a" ((unsigned char) value), "d"((unsigned short) port));
c7de829c
WD
152}
153
154static 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"
8bde7f77 160 ::"a" ((unsigned short) value), "d"((unsigned short) port));
c7de829c
WD
161}
162
163static 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"
8bde7f77 169 ::"a" ((unsigned long) value), "d"((unsigned short) port));
c7de829c
WD
170}
171
172static inline unsigned int port_in(int port)
173{
174 unsigned char value;
175 asm volatile ("inb %1,%0"
8bde7f77
WD
176 :"=a" ((unsigned char)value)
177 :"d"((unsigned short) port));
c7de829c
WD
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
184static inline unsigned int port_inw(int port)
185{
186 unsigned short value;
187 asm volatile ("inw %1,%0"
8bde7f77
WD
188 :"=a" ((unsigned short)value)
189 :"d"((unsigned short) port));
c7de829c
WD
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
196static inline unsigned int port_inl(int port)
197{
198 unsigned long value;
199 asm volatile ("inl %1,%0"
8bde7f77
WD
200 :"=a" ((unsigned long)value)
201 :"d"((unsigned short) port));
c7de829c
WD
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
208static int real_mem_init(void)
209{
210 void *m;
211 int fd_zero;
212
213 if (mem_info.ready)
8bde7f77 214 return 1;
c7de829c
WD
215
216 if ((fd_zero = open("/dev/zero", O_RDONLY)) == -1)
8bde7f77 217 PM_fatalError("You must have root privledges to run this program!");
c7de829c 218 if ((m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
8bde7f77
WD
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 }
c7de829c
WD
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
231static void insert_block(int i)
232{
233 memmove(
8bde7f77
WD
234 mem_info.blocks + i + 1,
235 mem_info.blocks + i,
236 (mem_info.count - i) * sizeof(struct mem_block));
c7de829c
WD
237 mem_info.count++;
238}
239
240static void delete_block(int i)
241{
242 mem_info.count--;
243
244 memmove(
8bde7f77
WD
245 mem_info.blocks + i,
246 mem_info.blocks + i + 1,
247 (mem_info.count - i) * sizeof(struct mem_block));
c7de829c
WD
248}
249
250static inline void set_bit(unsigned int bit, void *array)
251{
252 unsigned char *a = array;
253 a[bit / 8] |= (1 << (bit % 8));
254}
255
256static inline unsigned int get_int_seg(int i)
257{
258 return *(unsigned short *)(i * 4 + 2);
259}
260
261static inline unsigned int get_int_off(int i)
262{
263 return *(unsigned short *)(i * 4);
264}
265
266static 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
273ibool PMAPI PM_haveBIOSAccess(void)
274{ return true; }
275
276void PMAPI PM_init(void)
277{
278 void *m;
279 uint r_seg,r_off;
280
281 if (inited)
8bde7f77 282 return;
c7de829c
WD
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) {
8bde7f77
WD
289 PM_fatalError("You must have root privileges to run this program!");
290 }
c7de829c 291 if ((m = mmap((void *)0, 0x502,
8bde7f77
WD
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 }
c7de829c 296 if ((m = mmap((void *)0xA0000, 0xC0000 - 0xA0000,
8bde7f77
WD
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 }
c7de829c 301 if ((m = mmap((void *)0xC0000, 0xD0000 - 0xC0000,
8bde7f77
WD
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 }
c7de829c 306 if ((m = mmap((void *)0xD0000, 0x100000 - 0xD0000,
8bde7f77
WD
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 }
c7de829c
WD
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
349long PMAPI PM_getOSType(void)
350{ return _OS_LINUX; }
351
352int PMAPI PM_getModeType(void)
353{ return PM_386; }
354
355void PMAPI PM_backslash(char *s)
356{
357 uint pos = strlen(s);
358 if (s[pos-1] != '/') {
8bde7f77
WD
359 s[pos] = '/';
360 s[pos+1] = '\0';
361 }
c7de829c
WD
362}
363
364void PMAPI PM_setFatalErrorCleanup(
365 void (PMAPIP cleanup)(void))
366{
367 fatalErrorCleanup = cleanup;
368}
369
370void PMAPI PM_fatalError(const char *msg)
371{
372 if (fatalErrorCleanup)
8bde7f77 373 fatalErrorCleanup();
c7de829c
WD
374 fprintf(stderr,"%s\n", msg);
375 fflush(stderr);
376 exit(1);
377}
378
379static void ExitVBEBuf(void)
380{
381 if (VESABuf_ptr)
8bde7f77 382 PM_freeRealSeg(VESABuf_ptr);
c7de829c
WD
383 VESABuf_ptr = 0;
384}
385
386void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff)
387{
388 if (!VESABuf_ptr) {
8bde7f77
WD
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 }
c7de829c
WD
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
413typedef 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/****************************************************************************
426REMARKS:
427Open the keyboard mode file on disk.
428****************************************************************************/
429static FILE *open_kb_mode(
430 char *mode,
431 char *path)
432{
433 if (!PM_findBPD("graphics.bpd",path))
8bde7f77 434 return NULL;
c7de829c
WD
435 PM_backslash(path);
436 strcat(path,KBMODE_DAT);
437 return fopen(path,mode);
438}
439
440/****************************************************************************
441REMARKS:
442Restore the keyboard to normal mode
443****************************************************************************/
444void _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) {
8bde7f77
WD
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 }
c7de829c
WD
463}
464
465/****************************************************************************
466REMARKS:
467Safely abort the event module upon catching a fatal error.
468****************************************************************************/
469void _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/****************************************************************************
480REMARKS:
481Put the keyboard into raw mode
482****************************************************************************/
483void _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[] = {
8bde7f77
WD
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 };
c7de829c
WD
504
505 if ((kbmode = open_kb_mode("rb",path)) == NULL) {
8bde7f77
WD
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 }
c7de829c
WD
534}
535
536int PMAPI PM_kbhit(void)
537{
538 fd_set s;
539 struct timeval tv = { 0, 0 };
540
541 if (console_count == 0)
8bde7f77 542 PM_fatalError("You *must* open a console before using PM_kbhit!");
c7de829c 543 if (!in_raw_mode)
8bde7f77 544 _PM_keyboard_rawmode();
c7de829c
WD
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
550int PMAPI PM_getch(void)
551{
552 static uchar c;
553 int release;
554 static struct kbentry ke;
555
556 if (console_count == 0)
8bde7f77 557 PM_fatalError("You *must* open a console before using PM_getch!");
c7de829c 558 if (!in_raw_mode)
8bde7f77 559 _PM_keyboard_rawmode();
c7de829c 560 while (read(_PM_console_fd, &c, 1) > 0) {
8bde7f77
WD
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 }
c7de829c
WD
613 return 0;
614}
615
616/****************************************************************************
617REMARKS:
618Sleep until the virtual terminal is active
619****************************************************************************/
620static void wait_vt_active(
621 int _PM_console_fd)
622{
623 while (ioctl(_PM_console_fd, VT_WAITACTIVE, tty_vc) < 0) {
8bde7f77
WD
624 if ((errno != EAGAIN) && (errno != EINTR)) {
625 perror("ioctl(VT_WAITACTIVE)");
626 exit(1);
627 }
628 usleep(150000);
629 }
c7de829c
WD
630}
631
632/****************************************************************************
633REMARKS:
634Checks the owner of the specified virtual console.
635****************************************************************************/
636static 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))
8bde7f77 644 return 1;
c7de829c
WD
645 printf("You must be the owner of the current console to use this program.\n");
646 return 0;
647}
648
649/****************************************************************************
650REMARKS:
651Checks if the console is currently in graphics mode, and if so we forcibly
652restore it back to text mode again. This handles the case when a Nucleus or
653MGL program crashes and leaves the console in graphics mode. Running the
654textmode utility (or any other Nucleus/MGL program) via a telnet session
655into the machine will restore it back to normal.
656****************************************************************************/
657static void restore_text_console(
658 int console_id)
659{
660 if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
8bde7f77 661 LOGWARN("ioctl(KDSETMODE) failed");
c7de829c
WD
662 _PM_restore_kb_mode();
663}
664
665/****************************************************************************
666REMARKS:
667Opens up the console device for output by finding an appropriate virutal
668console that we can run on.
669****************************************************************************/
670PM_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++)
8bde7f77 685 return _PM_console_fd;
c7de829c
WD
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++) {
8bde7f77
WD
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 }
c7de829c 705 if ((_PM_console_fd = open("/dev/console", O_RDWR)) < 0) {
8bde7f77
WD
706 printf("open_dev_console: can't open /dev/console \n");
707 exit(1);
708 }
c7de829c 709 if (ioctl(_PM_console_fd, VT_OPENQRY, &tty_vc) < 0)
8bde7f77 710 goto Error;
c7de829c 711 if (tty_vc <= 0)
8bde7f77 712 goto Error;
c7de829c
WD
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) &&
8bde7f77
WD
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 }
c7de829c
WD
746 return _PM_console_fd;
747
748Error:
749 if (_PM_console_fd > 2)
8bde7f77 750 close(_PM_console_fd);
c7de829c
WD
751 console_count = 0;
752 PM_fatalError(
8bde7f77
WD
753 "Not running in a graphics capable console,\n"
754 "and unable to find one.\n");
c7de829c
WD
755 return -1;
756}
757
758#define FONT_C 0x10000 /* 64KB for font data */
759
760/****************************************************************************
761REMARKS:
762Returns the size of the console state buffer.
763****************************************************************************/
764int PMAPI PM_getConsoleStateSize(void)
765{
766 if (!inited)
8bde7f77 767 PM_init();
c7de829c
WD
768 return PM_getVGAStateSize() + FONT_C*2;
769}
770
771/****************************************************************************
772REMARKS:
773Save the state of the Linux console.
774****************************************************************************/
775void 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)
8bde7f77 781 perror("ioctl(GIO_FONT)");
c7de829c
WD
782
783 /* Inform the Linux console that we are going into graphics mode */
784 if (ioctl(console_id, KDSETMODE, KD_GRAPHICS) < 0)
8bde7f77 785 perror("ioctl(KDSETMODE)");
c7de829c
WD
786
787 /* Save state of VGA registers */
788 PM_saveVGAState(stateBuf);
789}
790
791void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
792{
793 /* TODO: Implement support for allowing console switching! */
794}
795
796/****************************************************************************
797REMARKS:
798Restore the state of the Linux console.
799****************************************************************************/
800void 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)
8bde7f77 809 LOGWARN("ioctl(KDSETMODE) failed");
c7de829c
WD
810
811 /* Restore the old console font */
812 if (ioctl(console_id,PIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
8bde7f77 813 LOGWARN("ioctl(KDSETMODE) failed");
c7de829c
WD
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/****************************************************************************
826REMARKS:
827Close the Linux console and put it back to normal.
828****************************************************************************/
829void PMAPI PM_closeConsole(PM_HWND _PM_console_fd)
830{
831 /* Restore console to normal operation */
832 if (--console_count == 0) {
8bde7f77
WD
833 /* Re-activate the original virtual console */
834 if (startup_vc > 0)
835 ioctl(_PM_console_fd, VT_ACTIVATE, startup_vc);
c7de829c 836
8bde7f77
WD
837 /* Close the console file descriptor */
838 if (_PM_console_fd > 2)
839 close(_PM_console_fd);
840 _PM_console_fd = -1;
841 }
c7de829c
WD
842}
843
844void PM_setOSCursorLocation(int x,int y)
845{
846 /* Nothing to do in here */
847}
848
849/****************************************************************************
850REMARKS:
851Set the screen width and height for the Linux console.
852****************************************************************************/
853void PM_setOSScreenWidth(int width,int height)
854{
855 struct winsize ws;
856 struct vt_sizes vs;
857
8bde7f77 858 /* Resize the software terminal */
c7de829c
WD
859 ws.ws_col = width;
860 ws.ws_row = height;
861 ioctl(_PM_console_fd, TIOCSWINSZ, &ws);
862
8bde7f77 863 /* And the hardware */
c7de829c
WD
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
870ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency)
871{
8bde7f77 872 /* TODO: Implement this for Linux */
c7de829c
WD
873 return false;
874}
875
876void PMAPI PM_setRealTimeClockFrequency(int frequency)
877{
8bde7f77 878 /* TODO: Implement this for Linux */
c7de829c
WD
879}
880
881void PMAPI PM_restoreRealTimeClockHandler(void)
882{
8bde7f77 883 /* TODO: Implement this for Linux */
c7de829c
WD
884}
885
886char * PMAPI PM_getCurrentPath(
887 char *path,
888 int maxLen)
889{
890 return getcwd(path,maxLen);
891}
892
893char PMAPI PM_getBootDrive(void)
894{ return '/'; }
895
896const char * PMAPI PM_getVBEAFPath(void)
897{ return PM_getNucleusConfigPath(); }
898
899const char * PMAPI PM_getNucleusPath(void)
900{
901 char *env = getenv("NUCLEUS_PATH");
902 return env ? env : "/usr/lib/nucleus";
903}
904
905const 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
914const char * PMAPI PM_getUniqueID(void)
915{
916 static char buf[128];
917 gethostname(buf, 128);
918 return buf;
919}
920
921const char * PMAPI PM_getMachineName(void)
922{
923 static char buf[128];
924 gethostname(buf, 128);
925 return buf;
926}
927
928void * PMAPI PM_getBIOSPointer(void)
929{
930 static uchar *zeroPtr = NULL;
931 if (!zeroPtr)
8bde7f77 932 zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
c7de829c
WD
933 return (void*)(zeroPtr + 0x400);
934}
935
936void * 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)
8bde7f77 942 PM_init();
c7de829c
WD
943 return (void*)(0xA0000);
944}
945
946void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
947{
948 uchar *p;
949 ulong baseAddr,baseOfs;
950
951 if (!inited)
8bde7f77 952 PM_init();
c7de829c 953 if (base >= 0xA0000 && base < 0x100000)
8bde7f77 954 return (void*)base;
c7de829c 955 if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1)
8bde7f77 956 return NULL;
c7de829c
WD
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,
8bde7f77
WD
967 PROT_READ | PROT_WRITE, MAP_SHARED,
968 fd_mem, baseAddr)) == (void *)-1)
969 return NULL;
c7de829c
WD
970 return (void*)(p+baseOfs);
971}
972
973void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
974{
975 if ((ulong)ptr >= 0x100000)
8bde7f77 976 munmap(ptr,limit+1);
c7de829c
WD
977}
978
979ulong PMAPI PM_getPhysicalAddr(void *p)
980{
8bde7f77
WD
981 /* TODO: This function should find the physical address of a linear */
982 /* address. */
c7de829c
WD
983 return 0xFFFFFFFFUL;
984}
985
986ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
987{
8bde7f77
WD
988 /* TODO: This function should find a range of physical addresses */
989 /* for a linear address. */
c7de829c
WD
990 return false;
991}
992
993void PMAPI PM_sleep(ulong milliseconds)
994{
8bde7f77 995 /* TODO: Put the process to sleep for milliseconds */
c7de829c
WD
996}
997
998int PMAPI PM_getCOMPort(int port)
999{
8bde7f77
WD
1000 /* TODO: Re-code this to determine real values using the Plug and Play */
1001 /* manager for the OS. */
c7de829c 1002 switch (port) {
8bde7f77
WD
1003 case 0: return 0x3F8;
1004 case 1: return 0x2F8;
1005 }
c7de829c
WD
1006 return 0;
1007}
1008
1009int PMAPI PM_getLPTPort(int port)
1010{
8bde7f77
WD
1011 /* TODO: Re-code this to determine real values using the Plug and Play */
1012 /* manager for the OS. */
c7de829c 1013 switch (port) {
8bde7f77
WD
1014 case 0: return 0x3BC;
1015 case 1: return 0x378;
1016 case 2: return 0x278;
1017 }
c7de829c
WD
1018 return 0;
1019}
1020
1021void * PMAPI PM_mallocShared(long size)
1022{
1023 return PM_malloc(size);
1024}
1025
1026void PMAPI PM_freeShared(void *ptr)
1027{
1028 PM_free(ptr);
1029}
1030
1031void * PMAPI PM_mapToProcess(void *base,ulong limit)
1032{ return (void*)base; }
1033
1034void * 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)
8bde7f77 1041 PM_init();
c7de829c
WD
1042 return (void*)MK_PHYS(r_seg,r_off);
1043}
1044
1045void * 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)
8bde7f77 1051 PM_init();
c7de829c 1052 if (!mem_info.ready)
8bde7f77 1053 return NULL;
c7de829c 1054 if (mem_info.count == REAL_MEM_BLOCKS)
8bde7f77 1055 return NULL;
c7de829c
WD
1056 size = (size + 15) & ~15;
1057 for (i = 0; i < mem_info.count; i++) {
8bde7f77
WD
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 }
c7de829c
WD
1069 return NULL;
1070}
1071
1072void PMAPI PM_freeRealSeg(void *mem)
1073{
1074 int i;
1075 char *r = (char *)REAL_MEM_BASE;
1076
1077 if (!mem_info.ready)
8bde7f77 1078 return;
c7de829c
WD
1079 i = 0;
1080 while (mem != (void *)r) {
8bde7f77
WD
1081 r += mem_info.blocks[i].size;
1082 i++;
1083 if (i == mem_info.count)
1084 return;
1085 }
c7de829c
WD
1086 mem_info.blocks[i].free = 1;
1087 if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) {
8bde7f77
WD
1088 mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
1089 delete_block(i + 1);
1090 }
c7de829c 1091 if (i - 1 >= 0 && mem_info.blocks[i - 1].free) {
8bde7f77
WD
1092 mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
1093 delete_block(i);
1094 }
c7de829c
WD
1095}
1096
1097#define DIRECTION_FLAG (1 << 10)
1098
1099static 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) {
8bde7f77
WD
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 }
c7de829c 1117 else {
8bde7f77
WD
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 }
c7de829c
WD
1128 edi -= (unsigned int)context.vm.regs.ds << 4;
1129 context.vm.regs.edi &= 0xffff0000;
1130 context.vm.regs.edi |= edi & 0xffff;
1131}
1132
1133static 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) {
8bde7f77
WD
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 }
c7de829c 1155 else {
8bde7f77
WD
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 }
c7de829c
WD
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
1177static 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) {
8bde7f77
WD
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 }
c7de829c 1195 else {
8bde7f77
WD
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 }
c7de829c
WD
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
1212static 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) {
8bde7f77
WD
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 }
c7de829c 1234 else {
8bde7f77
WD
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 }
c7de829c
WD
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
1256static int emulate(void)
1257{
1258 unsigned char *insn;
1259 struct {
8bde7f77
WD
1260 unsigned int size : 1;
1261 unsigned int rep : 1;
1262 } prefix = { 0, 0 };
c7de829c
WD
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
8bde7f77 1270 traceAddr = ((ulong)context.vm.regs.cs << 16) + context.vm.regs.eip + i;
c7de829c 1271#endif
8bde7f77
WD
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 }
c7de829c
WD
1365
1366 context.vm.regs.eip += i;
1367 return 1;
1368}
1369
1370static 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)
8bde7f77 1396 fprintf(stderr, "%02x ", (unsigned int)p[i]);
c7de829c
WD
1397 fputs("]\n", stderr);
1398 fflush(stderr);
1399}
1400
1401static int run_vm86(void)
1402{
1403 unsigned int vret;
1404
1405 for (;;) {
8bde7f77
WD
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 }
c7de829c
WD
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
1431void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
1432{
1433 if (!inited)
8bde7f77 1434 PM_init();
c7de829c
WD
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
1453int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
1454{
1455 if (!inited)
8bde7f77 1456 PM_init();
c7de829c
WD
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
1473int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
1474 RMSREGS *sregs)
1475{
1476 if (!inited)
8bde7f77 1477 PM_init();
c7de829c 1478 if (intno == 0x21) {
8bde7f77
WD
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 }
c7de829c 1486 else {
8bde7f77
WD
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 }
c7de829c
WD
1512 return out->e.eax;
1513}
1514
1515#define OUTR(ereg) in->e.ereg = context.vm.regs.ereg
1516
1517void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
1518 RMSREGS *sregs)
1519{
1520 if (!inited)
8bde7f77 1521 PM_init();
c7de829c
WD
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
1545void 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
1559void * PMAPI PM_allocLockedMem(uint size,ulong *physAddr,ibool contiguous,ibool below16M)
1560{
8bde7f77 1561 /* TODO: Implement this for Linux */
c7de829c
WD
1562 return NULL;
1563}
1564
1565void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
1566{
8bde7f77 1567 /* TODO: Implement this for Linux */
c7de829c
WD
1568}
1569
1570void * PMAPI PM_allocPage(
1571 ibool locked)
1572{
8bde7f77 1573 /* TODO: Implement this for Linux */
c7de829c
WD
1574 return NULL;
1575}
1576
1577void PMAPI PM_freePage(
1578 void *p)
1579{
8bde7f77 1580 /* TODO: Implement this for Linux */
c7de829c
WD
1581}
1582
1583void PMAPI PM_setBankA(int bank)
1584{
1585 if (!inited)
8bde7f77 1586 PM_init();
c7de829c
WD
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
1602void PMAPI PM_setBankAB(int bank)
1603{
1604 if (!inited)
8bde7f77 1605 PM_init();
c7de829c
WD
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
1633void PMAPI PM_setCRTStart(int x,int y,int waitVRT)
1634{
1635 if (!inited)
8bde7f77 1636 PM_init();
c7de829c
WD
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
1653int 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)
8bde7f77 1659 return PM_MTRR_ERR_NO_OS_SUPPORT;
c7de829c
WD
1660 sentry.base = base;
1661 sentry.size = length;
1662 sentry.type = type;
1663 if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) {
8bde7f77
WD
1664 /* TODO: Need to decode MTRR error codes!! */
1665 return PM_MTRR_NOT_SUPPORTED;
1666 }
c7de829c
WD
1667 return PM_MTRR_ERR_OK;
1668#else
1669 return PM_MTRR_ERR_NO_OS_SUPPORT;
1670#endif
1671}
1672
1673/****************************************************************************
1674PARAMETERS:
1675callback - Function to callback with write combine information
1676
1677REMARKS:
1678Function to enumerate all write combine regions currently enabled for the
1679processor.
1680****************************************************************************/
1681int PMAPI PM_enumWriteCombine(
1682 PM_enumWriteCombine_t callback)
1683{
1684#ifdef ENABLE_MTRR
1685 struct mtrr_gentry gentry;
1686
1687 if (mtrr_fd < 0)
8bde7f77 1688 return PM_MTRR_ERR_NO_OS_SUPPORT;
c7de829c
WD
1689
1690 for (gentry.regnum = 0; ioctl (mtrr_fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
8bde7f77
WD
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 }
c7de829c
WD
1697 }
1698
1699 return PM_MTRR_ERR_OK;
1700#else
1701 return PM_MTRR_ERR_NO_OS_SUPPORT;
1702#endif
1703}
1704
1705ibool 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)
8bde7f77 1722 PM_init();
c7de829c 1723 if ((old_bios = PM_malloc(BIOSLen)) == NULL)
8bde7f77 1724 return false;
c7de829c 1725 if (BIOSPhysAddr != 0xC0000) {
8bde7f77
WD
1726 memcpy(old_bios,bios_ptr,BIOSLen);
1727 memcpy(bios_ptr,copyOfBIOS,BIOSLen);
1728 }
c7de829c
WD
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)
8bde7f77 1745 memcpy(bios_ptr,old_bios,BIOSLen);
c7de829c
WD
1746 PM_free(old_bios);
1747 return true;
1748}
1749
1750int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
1751{
1752 p = p; len = len;
1753 return 1;
1754}
1755
1756int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
1757{
1758 p = p; len = len;
1759 return 1;
1760}
1761
1762int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1763{
1764 p = p; len = len;
1765 return 1;
1766}
1767
1768int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1769{
1770 p = p; len = len;
1771 return 1;
1772}
1773
1774PM_MODULE PMAPI PM_loadLibrary(
1775 const char *szDLLName)
1776{
8bde7f77 1777 /* TODO: Implement this to load shared libraries! */
c7de829c
WD
1778 (void)szDLLName;
1779 return NULL;
1780}
1781
1782void * PMAPI PM_getProcAddress(
1783 PM_MODULE hModule,
1784 const char *szProcName)
1785{
8bde7f77 1786 /* TODO: Implement this! */
c7de829c
WD
1787 (void)hModule;
1788 (void)szProcName;
1789 return NULL;
1790}
1791
1792void PMAPI PM_freeLibrary(
1793 PM_MODULE hModule)
1794{
8bde7f77 1795 /* TODO: Implement this! */
c7de829c
WD
1796 (void)hModule;
1797}
1798
1799int PMAPI PM_setIOPL(
1800 int level)
1801{
8bde7f77 1802 /* TODO: Move the IOPL switching into this function!! */
c7de829c
WD
1803 return level;
1804}
1805
1806void PMAPI PM_flushTLB(void)
1807{
8bde7f77 1808 /* Do nothing on Linux. */
c7de829c 1809}