1 ;/****************************************************************************
3 * SciTech OS Portability Manager Library
5 * ========================================================================
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
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.
17 * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 * The Initial Developer of the Original Code is SciTech Software, Inc.
20 * All Rights Reserved.
22 * ========================================================================
24 * Portions copyright (C) Josh Vanderhoof
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.
35 ****************************************************************************/
38 #include "drvlib/os/os.h"
44 #include <sys/ioctl.h>
48 #include <sys/types.h>
59 #include <asm/types.h>
68 /*--------------------------- Global variables ----------------------------*/
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
77 /* Quick and dirty fix for vm86() syscall from lrmi 0.6 */
79 vm86(struct vm86_struct
*vm
)
89 : "0" (113), "r" (vm
));
94 : "0" (113), "b" (vm
));
102 unsigned short ret_seg
, ret_off
;
103 unsigned short stack_seg
, stack_off
;
104 struct vm86_struct vm
;
108 unsigned int size
: 20;
109 unsigned int free
: 1;
115 struct mem_block blocks
[REAL_MEM_BLOCKS
];
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;
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 */
134 static ulong traceAddr
;
137 static void (PMAPIP fatalErrorCleanup
)(void) = NULL
;
139 /*----------------------------- Implementation ----------------------------*/
142 extern void printk(char *msg
,...);
145 static inline void port_out(int value
, int port
)
148 printk("%04X:%04X: outb.%04X <- %02X\n", traceAddr
>> 16, traceAddr
& 0xFFFF, (ushort
)port
, (uchar
)value
);
150 asm volatile ("outb %0,%1"
151 ::"a" ((unsigned char) value
), "d"((unsigned short) port
));
154 static inline void port_outw(int value
, int port
)
157 printk("%04X:%04X: outw.%04X <- %04X\n", traceAddr
>> 16,traceAddr
& 0xFFFF, (ushort
)port
, (ushort
)value
);
159 asm volatile ("outw %0,%1"
160 ::"a" ((unsigned short) value
), "d"((unsigned short) port
));
163 static inline void port_outl(int value
, int port
)
166 printk("%04X:%04X: outl.%04X <- %08X\n", traceAddr
>> 16,traceAddr
& 0xFFFF, (ushort
)port
, (ulong
)value
);
168 asm volatile ("outl %0,%1"
169 ::"a" ((unsigned long) value
), "d"((unsigned short) port
));
172 static inline unsigned int port_in(int port
)
175 asm volatile ("inb %1,%0"
176 :"=a" ((unsigned char)value
)
177 :"d"((unsigned short) port
));
179 printk("%04X:%04X: inb.%04X -> %02X\n", traceAddr
>> 16,traceAddr
& 0xFFFF, (ushort
)port
, (uchar
)value
);
184 static inline unsigned int port_inw(int port
)
186 unsigned short value
;
187 asm volatile ("inw %1,%0"
188 :"=a" ((unsigned short)value
)
189 :"d"((unsigned short) port
));
191 printk("%04X:%04X: inw.%04X -> %04X\n", traceAddr
>> 16,traceAddr
& 0xFFFF, (ushort
)port
, (ushort
)value
);
196 static inline unsigned int port_inl(int port
)
199 asm volatile ("inl %1,%0"
200 :"=a" ((unsigned long)value
)
201 :"d"((unsigned short) port
));
203 printk("%04X:%04X: inl.%04X -> %08X\n", traceAddr
>> 16,traceAddr
& 0xFFFF, (ushort
)port
, (ulong
)value
);
208 static int real_mem_init(void)
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) {
222 PM_fatalError("You must have root privledges to run this program!");
226 mem_info
.blocks
[0].size
= REAL_MEM_SIZE
;
227 mem_info
.blocks
[0].free
= 1;
231 static void insert_block(int i
)
234 mem_info
.blocks
+ i
+ 1,
236 (mem_info
.count
- i
) * sizeof(struct mem_block
));
240 static void delete_block(int i
)
246 mem_info
.blocks
+ i
+ 1,
247 (mem_info
.count
- i
) * sizeof(struct mem_block
));
250 static inline void set_bit(unsigned int bit
, void *array
)
252 unsigned char *a
= array
;
253 a
[bit
/ 8] |= (1 << (bit
% 8));
256 static inline unsigned int get_int_seg(int i
)
258 return *(unsigned short *)(i
* 4 + 2);
261 static inline unsigned int get_int_off(int i
)
263 return *(unsigned short *)(i
* 4);
266 static inline void pushw(unsigned short i
)
268 struct vm86_regs
*r
= &context
.vm
.regs
;
270 *(unsigned short *)(((unsigned int)r
->ss
<< 4) + r
->esp
) = i
;
273 ibool PMAPI
PM_haveBIOSAccess(void)
276 void PMAPI
PM_init(void)
284 /* Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
285 * and the physical framebuffer and ROM images from (0xa0000 - 0x100000)
288 if (!fd_mem
&& (fd_mem
= open("/dev/mem", O_RDWR
)) == -1) {
289 PM_fatalError("You must have root privileges to run this program!");
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!");
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!");
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!");
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!");
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
;
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
));
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
);
331 mtrr_fd
= open("/dev/cpu/mtrr", O_RDWR
, 0);
333 mtrr_fd
= open("/proc/mtrr", O_RDWR
, 0);
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.
344 ioperm(0x400,0x10000-0x400,1);
349 long PMAPI
PM_getOSType(void)
350 { return _OS_LINUX
; }
352 int PMAPI
PM_getModeType(void)
355 void PMAPI
PM_backslash(char *s
)
357 uint pos
= strlen(s
);
358 if (s
[pos
-1] != '/') {
364 void PMAPI
PM_setFatalErrorCleanup(
365 void (PMAPIP cleanup
)(void))
367 fatalErrorCleanup
= cleanup
;
370 void PMAPI
PM_fatalError(const char *msg
)
372 if (fatalErrorCleanup
)
374 fprintf(stderr
,"%s\n", msg
);
379 static void ExitVBEBuf(void)
382 PM_freeRealSeg(VESABuf_ptr
);
386 void * PMAPI
PM_getVESABuf(uint
*len
,uint
*rseg
,uint
*roff
)
389 /* Allocate a global buffer for communicating with the VESA VBE */
390 if ((VESABuf_ptr
= PM_allocRealSeg(VESABuf_len
, &VESABuf_rseg
, &VESABuf_roff
)) == NULL
)
395 *rseg
= VESABuf_rseg
;
396 *roff
= VESABuf_roff
;
400 /* New raw console based getch and kbhit functions */
402 #define KB_CAPS LED_CAP /* 4 */
403 #define KB_NUMLOCK LED_NUM /* 2 */
404 #define KB_SCROLL LED_SCR /* 1 */
406 #define KB_CONTROL 16
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.
414 struct termios termios
;
421 /* Name of the file used to save keyboard mode information */
423 #define KBMODE_DAT "kbmode.dat"
425 /****************************************************************************
427 Open the keyboard mode file on disk.
428 ****************************************************************************/
429 static FILE *open_kb_mode(
433 if (!PM_findBPD("graphics.bpd",path
))
436 strcat(path
,KBMODE_DAT
);
437 return fopen(path
,mode
);
440 /****************************************************************************
442 Restore the keyboard to normal mode
443 ****************************************************************************/
444 void _PM_restore_kb_mode(void)
448 char path
[PM_MAX_PATH
];
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
);
465 /****************************************************************************
467 Safely abort the event module upon catching a fatal error.
468 ****************************************************************************/
474 sprintf(buf
,"Terminating on signal %d",signo
);
475 _PM_restore_kb_mode();
479 /****************************************************************************
481 Put the keyboard into raw mode
482 ****************************************************************************/
483 void _PM_keyboard_rawmode(void)
488 char path
[PM_MAX_PATH
];
490 static int sig_list
[] = {
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
))
510 ioctl(_PM_console_fd
, KDGETLED
, &mode
.leds
);
511 _PM_leds
= mode
.leds
& 0xF;
513 tcgetattr(_PM_console_fd
, &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
);
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
))
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!");
536 int PMAPI
PM_kbhit(void)
539 struct timeval tv
= { 0, 0 };
541 if (console_count
== 0)
542 PM_fatalError("You *must* open a console before using PM_kbhit!");
544 _PM_keyboard_rawmode();
546 FD_SET(_PM_console_fd
, &s
);
547 return select(_PM_console_fd
+1, &s
, NULL
, NULL
, &tv
) > 0;
550 int PMAPI
PM_getch(void)
554 static struct kbentry ke
;
556 if (console_count
== 0)
557 PM_fatalError("You *must* open a console before using PM_getch!");
559 _PM_keyboard_rawmode();
560 while (read(_PM_console_fd
, &c
, 1) > 0) {
565 case 42: case 54: /* Shift */
566 _PM_modifiers
&= ~KB_SHIFT
;
568 case 29: case 97: /* Control */
569 _PM_modifiers
&= ~KB_CONTROL
;
571 case 56: case 100: /* Alt / AltGr */
572 _PM_modifiers
&= ~KB_ALT
;
578 case 42: case 54: /* Shift */
579 _PM_modifiers
|= KB_SHIFT
;
581 case 29: case 97: /* Control */
582 _PM_modifiers
|= KB_CONTROL
;
584 case 56: case 100: /* Alt / AltGr */
585 _PM_modifiers
|= KB_ALT
;
587 case 58: /* Caps Lock */
588 _PM_modifiers
^= KB_CAPS
;
589 ioctl(_PM_console_fd
, KDSETLED
, _PM_modifiers
& 7);
591 case 69: /* Num Lock */
592 _PM_modifiers
^= KB_NUMLOCK
;
593 ioctl(_PM_console_fd
, KDSETLED
, _PM_modifiers
& 7);
595 case 70: /* Scroll Lock */
596 _PM_modifiers
^= KB_SCROLL
;
597 ioctl(_PM_console_fd
, KDSETLED
, _PM_modifiers
& 7);
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;
616 /****************************************************************************
618 Sleep until the virtual terminal is active
619 ****************************************************************************/
620 static void wait_vt_active(
623 while (ioctl(_PM_console_fd
, VT_WAITACTIVE
, tty_vc
) < 0) {
624 if ((errno
!= EAGAIN
) && (errno
!= EINTR
)) {
625 perror("ioctl(VT_WAITACTIVE)");
632 /****************************************************************************
634 Checks the owner of the specified virtual console.
635 ****************************************************************************/
636 static int check_owner(
642 sprintf(fname
, "/dev/tty%d", vc
);
643 if ((stat(fname
, &sbuf
) >= 0) && (getuid() == sbuf
.st_uid
))
645 printf("You must be the owner of the current console to use this program.\n");
649 /****************************************************************************
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(
660 if (ioctl(console_id
, KDSETMODE
, KD_TEXT
) < 0)
661 LOGWARN("ioctl(KDSETMODE) failed");
662 _PM_restore_kb_mode();
665 /****************************************************************************
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(
683 /* Check if we have already opened the console */
685 return _PM_console_fd
;
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.
692 for (_PM_console_fd
= 0; _PM_console_fd
< 3; _PM_console_fd
++) {
693 if (fstat(_PM_console_fd
, &sbuf
) < 0)
695 if (ioctl(_PM_console_fd
, VT_GETMODE
, &vtm
) < 0)
697 if ((sbuf
.st_rdev
& 0xFF00) != 0x400)
699 if (!(sbuf
.st_rdev
& 0xFF))
701 tty_vc
= sbuf
.st_rdev
& 0xFF;
702 restore_text_console(_PM_console_fd
);
703 return _PM_console_fd
;
705 if ((_PM_console_fd
= open("/dev/console", O_RDWR
)) < 0) {
706 printf("open_dev_console: can't open /dev/console \n");
709 if (ioctl(_PM_console_fd
, VT_OPENQRY
, &tty_vc
) < 0)
713 sprintf(fname
, "/dev/tty%d", tty_vc
);
714 close(_PM_console_fd
);
716 /* Change our control terminal */
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
))
724 restore_text_console(_PM_console_fd
);
726 /* Success, redirect all stdios */
737 /* clear screen and switch to it */
738 fwrite("\e[H\e[J", 6, 1, 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
);
746 return _PM_console_fd
;
749 if (_PM_console_fd
> 2)
750 close(_PM_console_fd
);
753 "Not running in a graphics capable console,\n"
754 "and unable to find one.\n");
758 #define FONT_C 0x10000 /* 64KB for font data */
760 /****************************************************************************
762 Returns the size of the console state buffer.
763 ****************************************************************************/
764 int PMAPI
PM_getConsoleStateSize(void)
768 return PM_getVGAStateSize() + FONT_C
*2;
771 /****************************************************************************
773 Save the state of the Linux console.
774 ****************************************************************************/
775 void PMAPI
PM_saveConsoleState(void *stateBuf
,int console_id
)
777 uchar
*regs
= stateBuf
;
779 /* Save the current console font */
780 if (ioctl(console_id
,GIO_FONT
,®s
[PM_getVGAStateSize()]) < 0)
781 perror("ioctl(GIO_FONT)");
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)");
787 /* Save state of VGA registers */
788 PM_saveVGAState(stateBuf
);
791 void PMAPI
PM_setSuspendAppCallback(int (_ASMAPIP saveState
)(int flags
))
793 /* TODO: Implement support for allowing console switching! */
796 /****************************************************************************
798 Restore the state of the Linux console.
799 ****************************************************************************/
800 void PMAPI
PM_restoreConsoleState(const void *stateBuf
,PM_HWND console_id
)
802 const uchar
*regs
= stateBuf
;
804 /* Restore the state of the VGA compatible registers */
805 PM_restoreVGAState(stateBuf
);
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");
811 /* Restore the old console font */
812 if (ioctl(console_id
,PIO_FONT
,®s
[PM_getVGAStateSize()]) < 0)
813 LOGWARN("ioctl(KDSETMODE) failed");
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.
821 printf("\033[H\033[J");
825 /****************************************************************************
827 Close the Linux console and put it back to normal.
828 ****************************************************************************/
829 void PMAPI
PM_closeConsole(PM_HWND _PM_console_fd
)
831 /* Restore console to normal operation */
832 if (--console_count
== 0) {
833 /* Re-activate the original virtual console */
835 ioctl(_PM_console_fd
, VT_ACTIVATE
, startup_vc
);
837 /* Close the console file descriptor */
838 if (_PM_console_fd
> 2)
839 close(_PM_console_fd
);
844 void PM_setOSCursorLocation(int x
,int y
)
846 /* Nothing to do in here */
849 /****************************************************************************
851 Set the screen width and height for the Linux console.
852 ****************************************************************************/
853 void PM_setOSScreenWidth(int width
,int height
)
858 /* Resize the software terminal */
861 ioctl(_PM_console_fd
, TIOCSWINSZ
, &ws
);
863 /* And the hardware */
867 ioctl(_PM_console_fd
, VT_RESIZE
, &vs
);
870 ibool PMAPI
PM_setRealTimeClockHandler(PM_intHandler ih
, int frequency
)
872 /* TODO: Implement this for Linux */
876 void PMAPI
PM_setRealTimeClockFrequency(int frequency
)
878 /* TODO: Implement this for Linux */
881 void PMAPI
PM_restoreRealTimeClockHandler(void)
883 /* TODO: Implement this for Linux */
886 char * PMAPI
PM_getCurrentPath(
890 return getcwd(path
,maxLen
);
893 char PMAPI
PM_getBootDrive(void)
896 const char * PMAPI
PM_getVBEAFPath(void)
897 { return PM_getNucleusConfigPath(); }
899 const char * PMAPI
PM_getNucleusPath(void)
901 char *env
= getenv("NUCLEUS_PATH");
902 return env
? env
: "/usr/lib/nucleus";
905 const char * PMAPI
PM_getNucleusConfigPath(void)
907 static char path
[256];
908 strcpy(path
,PM_getNucleusPath());
910 strcat(path
,"config");
914 const char * PMAPI
PM_getUniqueID(void)
916 static char buf
[128];
917 gethostname(buf
, 128);
921 const char * PMAPI
PM_getMachineName(void)
923 static char buf
[128];
924 gethostname(buf
, 128);
928 void * PMAPI
PM_getBIOSPointer(void)
930 static uchar
*zeroPtr
= NULL
;
932 zeroPtr
= PM_mapPhysicalAddr(0,0xFFFFF,true);
933 return (void*)(zeroPtr
+ 0x400);
936 void * PMAPI
PM_getA0000Pointer(void)
938 /* PM_init maps in the 0xA0000 framebuffer region 1:1 with our
939 * address mapping, so we can return the address here.
943 return (void*)(0xA0000);
946 void * PMAPI
PM_mapPhysicalAddr(ulong base
,ulong limit
,ibool isCached
)
949 ulong baseAddr
,baseOfs
;
953 if (base
>= 0xA0000 && base
< 0x100000)
955 if (!fd_mem
&& (fd_mem
= open("/dev/mem", O_RDWR
)) == -1)
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
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)
970 return (void*)(p
+baseOfs
);
973 void PMAPI
PM_freePhysicalAddr(void *ptr
,ulong limit
)
975 if ((ulong
)ptr
>= 0x100000)
979 ulong PMAPI
PM_getPhysicalAddr(void *p
)
981 /* TODO: This function should find the physical address of a linear */
986 ibool PMAPI
PM_getPhysicalAddrRange(void *p
,ulong length
,ulong
*physAddress
)
988 /* TODO: This function should find a range of physical addresses */
989 /* for a linear address. */
993 void PMAPI
PM_sleep(ulong milliseconds
)
995 /* TODO: Put the process to sleep for milliseconds */
998 int PMAPI
PM_getCOMPort(int port
)
1000 /* TODO: Re-code this to determine real values using the Plug and Play */
1001 /* manager for the OS. */
1003 case 0: return 0x3F8;
1004 case 1: return 0x2F8;
1009 int PMAPI
PM_getLPTPort(int port
)
1011 /* TODO: Re-code this to determine real values using the Plug and Play */
1012 /* manager for the OS. */
1014 case 0: return 0x3BC;
1015 case 1: return 0x378;
1016 case 2: return 0x278;
1021 void * PMAPI
PM_mallocShared(long size
)
1023 return PM_malloc(size
);
1026 void PMAPI
PM_freeShared(void *ptr
)
1031 void * PMAPI
PM_mapToProcess(void *base
,ulong limit
)
1032 { return (void*)base
; }
1034 void * PMAPI
PM_mapRealPointer(uint r_seg
,uint r_off
)
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.
1042 return (void*)MK_PHYS(r_seg
,r_off
);
1045 void * PMAPI
PM_allocRealSeg(uint size
,uint
*r_seg
,uint
*r_off
)
1048 char *r
= (char *)REAL_MEM_BASE
;
1052 if (!mem_info
.ready
)
1054 if (mem_info
.count
== REAL_MEM_BLOCKS
)
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
) {
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;
1067 r
+= mem_info
.blocks
[i
].size
;
1072 void PMAPI
PM_freeRealSeg(void *mem
)
1075 char *r
= (char *)REAL_MEM_BASE
;
1077 if (!mem_info
.ready
)
1080 while (mem
!= (void *)r
) {
1081 r
+= mem_info
.blocks
[i
].size
;
1083 if (i
== mem_info
.count
)
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);
1091 if (i
- 1 >= 0 && mem_info
.blocks
[i
- 1].free
) {
1092 mem_info
.blocks
[i
- 1].size
+= mem_info
.blocks
[i
].size
;
1097 #define DIRECTION_FLAG (1 << 10)
1099 static void em_ins(int size
)
1101 unsigned int edx
, edi
;
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
) {
1108 asm volatile ("std; insl; cld"
1109 : "=D" (edi
) : "d" (edx
), "0" (edi
));
1111 asm volatile ("std; insw; cld"
1112 : "=D" (edi
) : "d" (edx
), "0" (edi
));
1114 asm volatile ("std; insb; cld"
1115 : "=D" (edi
) : "d" (edx
), "0" (edi
));
1119 asm volatile ("cld; insl"
1120 : "=D" (edi
) : "d" (edx
), "0" (edi
));
1122 asm volatile ("cld; insw"
1123 : "=D" (edi
) : "d" (edx
), "0" (edi
));
1125 asm volatile ("cld; insb"
1126 : "=D" (edi
) : "d" (edx
), "0" (edi
));
1128 edi
-= (unsigned int)context
.vm
.regs
.ds
<< 4;
1129 context
.vm
.regs
.edi
&= 0xffff0000;
1130 context
.vm
.regs
.edi
|= edi
& 0xffff;
1133 static void em_rep_ins(int size
)
1135 unsigned int ecx
, edx
, edi
;
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
) {
1143 asm volatile ("std; rep; insl; cld"
1144 : "=D" (edi
), "=c" (ecx
)
1145 : "d" (edx
), "0" (edi
), "1" (ecx
));
1147 asm volatile ("std; rep; insw; cld"
1148 : "=D" (edi
), "=c" (ecx
)
1149 : "d" (edx
), "0" (edi
), "1" (ecx
));
1151 asm volatile ("std; rep; insb; cld"
1152 : "=D" (edi
), "=c" (ecx
)
1153 : "d" (edx
), "0" (edi
), "1" (ecx
));
1157 asm volatile ("cld; rep; insl"
1158 : "=D" (edi
), "=c" (ecx
)
1159 : "d" (edx
), "0" (edi
), "1" (ecx
));
1161 asm volatile ("cld; rep; insw"
1162 : "=D" (edi
), "=c" (ecx
)
1163 : "d" (edx
), "0" (edi
), "1" (ecx
));
1165 asm volatile ("cld; rep; insb"
1166 : "=D" (edi
), "=c" (ecx
)
1167 : "d" (edx
), "0" (edi
), "1" (ecx
));
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;
1177 static void em_outs(int size
)
1179 unsigned int edx
, esi
;
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
) {
1186 asm volatile ("std; outsl; cld"
1187 : "=S" (esi
) : "d" (edx
), "0" (esi
));
1189 asm volatile ("std; outsw; cld"
1190 : "=S" (esi
) : "d" (edx
), "0" (esi
));
1192 asm volatile ("std; outsb; cld"
1193 : "=S" (esi
) : "d" (edx
), "0" (esi
));
1197 asm volatile ("cld; outsl"
1198 : "=S" (esi
) : "d" (edx
), "0" (esi
));
1200 asm volatile ("cld; outsw"
1201 : "=S" (esi
) : "d" (edx
), "0" (esi
));
1203 asm volatile ("cld; outsb"
1204 : "=S" (esi
) : "d" (edx
), "0" (esi
));
1207 esi
-= (unsigned int)context
.vm
.regs
.ds
<< 4;
1208 context
.vm
.regs
.esi
&= 0xffff0000;
1209 context
.vm
.regs
.esi
|= esi
& 0xffff;
1212 static void em_rep_outs(int size
)
1214 unsigned int ecx
, edx
, esi
;
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
) {
1222 asm volatile ("std; rep; outsl; cld"
1223 : "=S" (esi
), "=c" (ecx
)
1224 : "d" (edx
), "0" (esi
), "1" (ecx
));
1226 asm volatile ("std; rep; outsw; cld"
1227 : "=S" (esi
), "=c" (ecx
)
1228 : "d" (edx
), "0" (esi
), "1" (ecx
));
1230 asm volatile ("std; rep; outsb; cld"
1231 : "=S" (esi
), "=c" (ecx
)
1232 : "d" (edx
), "0" (esi
), "1" (ecx
));
1236 asm volatile ("cld; rep; outsl"
1237 : "=S" (esi
), "=c" (ecx
)
1238 : "d" (edx
), "0" (esi
), "1" (ecx
));
1240 asm volatile ("cld; rep; outsw"
1241 : "=S" (esi
), "=c" (ecx
)
1242 : "d" (edx
), "0" (esi
), "1" (ecx
));
1244 asm volatile ("cld; rep; outsb"
1245 : "=S" (esi
), "=c" (ecx
)
1246 : "d" (edx
), "0" (esi
), "1" (ecx
));
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;
1256 static int emulate(void)
1258 unsigned char *insn
;
1260 unsigned int size
: 1;
1261 unsigned int rep
: 1;
1262 } prefix
= { 0, 0 };
1265 insn
= (unsigned char *)((unsigned int)context
.vm
.regs
.cs
<< 4);
1266 insn
+= context
.vm
.regs
.eip
;
1270 traceAddr
= ((ulong
)context
.vm
.regs
.cs
<< 16) + context
.vm
.regs
.eip
+ i
;
1272 if (insn
[i
] == 0x66) {
1273 prefix
.size
= 1 - prefix
.size
;
1276 else if (insn
[i
] == 0xf3) {
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 */
1288 else if (insn
[i
] == 0x6c) {
1296 else if (insn
[i
] == 0x6d) {
1312 else if (insn
[i
] == 0x6e) {
1320 else if (insn
[i
] == 0x6f) {
1336 else if (insn
[i
] == 0xec) {
1337 *((uchar
*)&context
.vm
.regs
.eax
) = port_in(context
.vm
.regs
.edx
);
1341 else if (insn
[i
] == 0xed) {
1343 *((ulong
*)&context
.vm
.regs
.eax
) = port_inl(context
.vm
.regs
.edx
);
1345 *((ushort
*)&context
.vm
.regs
.eax
) = port_inw(context
.vm
.regs
.edx
);
1349 else if (insn
[i
] == 0xee) {
1350 port_out(context
.vm
.regs
.eax
,context
.vm
.regs
.edx
);
1354 else if (insn
[i
] == 0xef) {
1356 port_outl(context
.vm
.regs
.eax
,context
.vm
.regs
.edx
);
1358 port_outw(context
.vm
.regs
.eax
,context
.vm
.regs
.edx
);
1366 context
.vm
.regs
.eip
+= i
;
1370 static void debug_info(int vret
)
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
);
1401 static int run_vm86(void)
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
)
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
);
1419 if (VM86_TYPE(vret
) != VM86_UNKNOWN
)
1428 #define IND(ereg) context.vm.regs.ereg = regs->ereg
1429 #define OUTD(ereg) regs->ereg = context.vm.regs.ereg
1431 void PMAPI
DPMI_int86(int intno
, DPMI_regs
*regs
)
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
);
1446 OUTD(eax
); OUTD(ebx
); OUTD(ecx
); OUTD(edx
); OUTD(esi
); OUTD(edi
);
1447 regs
->flags
= context
.vm
.regs
.eflags
;
1450 #define IN(ereg) context.vm.regs.ereg = in->e.ereg
1451 #define OUT(ereg) out->e.ereg = context.vm.regs.ereg
1453 int PMAPI
PM_int86(int intno
, RMREGS
*in
, RMREGS
*out
)
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
);
1468 OUT(eax
); OUT(ebx
); OUT(ecx
); OUT(edx
); OUT(esi
); OUT(edi
);
1469 out
->x
.cflag
= context
.vm
.regs
.eflags
& 1;
1473 int PMAPI
PM_int86x(int intno
, RMREGS
*in
, RMREGS
*out
,
1478 if (intno
== 0x21) {
1479 time_t today
= time(NULL
);
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
;
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
);
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;
1515 #define OUTR(ereg) in->e.ereg = context.vm.regs.ereg
1517 void PMAPI
PM_callRealMode(uint seg
,uint off
, RMREGS
*in
,
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
);
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;
1545 void PMAPI
PM_availableMemory(ulong
*physical
,ulong
*total
)
1547 FILE *mem
= fopen("/proc/meminfo","r");
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
);
1556 *total
+= *physical
;
1559 void * PMAPI
PM_allocLockedMem(uint size
,ulong
*physAddr
,ibool contiguous
,ibool below16M
)
1561 /* TODO: Implement this for Linux */
1565 void PMAPI
PM_freeLockedMem(void *p
,uint size
,ibool contiguous
)
1567 /* TODO: Implement this for Linux */
1570 void * PMAPI
PM_allocPage(
1573 /* TODO: Implement this for Linux */
1577 void PMAPI
PM_freePage(
1580 /* TODO: Implement this for Linux */
1583 void PMAPI
PM_setBankA(int bank
)
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
);
1602 void PMAPI
PM_setBankAB(int bank
)
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
);
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
);
1633 void PMAPI
PM_setCRTStart(int x
,int y
,int waitVRT
)
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
);
1653 int PMAPI
PM_enableWriteCombine(ulong base
,ulong length
,uint type
)
1656 struct mtrr_sentry sentry
;
1659 return PM_MTRR_ERR_NO_OS_SUPPORT
;
1661 sentry
.size
= length
;
1663 if (ioctl(mtrr_fd
, MTRRIOC_ADD_ENTRY
, &sentry
) == -1) {
1664 /* TODO: Need to decode MTRR error codes!! */
1665 return PM_MTRR_NOT_SUPPORTED
;
1667 return PM_MTRR_ERR_OK
;
1669 return PM_MTRR_ERR_NO_OS_SUPPORT
;
1673 /****************************************************************************
1675 callback - Function to callback with write combine information
1678 Function to enumerate all write combine regions currently enabled for the
1680 ****************************************************************************/
1681 int PMAPI
PM_enumWriteCombine(
1682 PM_enumWriteCombine_t callback
)
1685 struct mtrr_gentry gentry
;
1688 return PM_MTRR_ERR_NO_OS_SUPPORT
;
1690 for (gentry
.regnum
= 0; ioctl (mtrr_fd
, MTRRIOC_GET_ENTRY
, &gentry
) == 0;
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
);
1699 return PM_MTRR_ERR_OK
;
1701 return PM_MTRR_ERR_NO_OS_SUPPORT
;
1705 ibool PMAPI
PM_doBIOSPOST(
1711 char *bios_ptr
= (char*)0xC0000;
1713 ulong Current10
, Current6D
, *rvec
= 0;
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.
1723 if ((old_bios
= PM_malloc(BIOSLen
)) == NULL
)
1725 if (BIOSPhysAddr
!= 0xC0000) {
1726 memcpy(old_bios
,bios_ptr
,BIOSLen
);
1727 memcpy(bios_ptr
,copyOfBIOS
,BIOSLen
);
1730 /* The interrupt vectors should already be mmap()'ed from 0-0x400 in PM_init */
1731 Current10
= rvec
[0x10];
1732 Current6D
= rvec
[0x6D];
1734 /* POST the secondary BIOS */
1735 rvec
[0x10] = rvec
[0x42]; /* Restore int 10h to STD-BIOS */
1737 PM_callRealMode(0xC000,0x0003,®s
,&sregs
);
1739 /* Restore interrupt vectors */
1740 rvec
[0x10] = Current10
;
1741 rvec
[0x6D] = Current6D
;
1743 /* Restore original BIOS image */
1744 if (BIOSPhysAddr
!= 0xC0000)
1745 memcpy(bios_ptr
,old_bios
,BIOSLen
);
1750 int PMAPI
PM_lockDataPages(void *p
,uint len
,PM_lockHandle
*lh
)
1756 int PMAPI
PM_unlockDataPages(void *p
,uint len
,PM_lockHandle
*lh
)
1762 int PMAPI
PM_lockCodePages(void (*p
)(),uint len
,PM_lockHandle
*lh
)
1768 int PMAPI
PM_unlockCodePages(void (*p
)(),uint len
,PM_lockHandle
*lh
)
1774 PM_MODULE PMAPI
PM_loadLibrary(
1775 const char *szDLLName
)
1777 /* TODO: Implement this to load shared libraries! */
1782 void * PMAPI
PM_getProcAddress(
1784 const char *szProcName
)
1786 /* TODO: Implement this! */
1792 void PMAPI
PM_freeLibrary(
1795 /* TODO: Implement this! */
1799 int PMAPI
PM_setIOPL(
1802 /* TODO: Move the IOPL switching into this function!! */
1806 void PMAPI
PM_flushTLB(void)
1808 /* Do nothing on Linux. */