;/**************************************************************************** * * SciTech OS Portability Manager Library * * ======================================================================== * * The contents of this file are subject to the SciTech MGL Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.scitechsoft.com/mgl-license.txt * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. * * The Initial Developer of the Original Code is SciTech Software, Inc. * All Rights Reserved. * * ======================================================================== * * Portions copyright (C) Josh Vanderhoof * * Language: ANSI C * Environment: Linux * * Description: Implementation for the OS Portability Manager Library, which * contains functions to implement OS specific services in a * generic, cross platform API. Porting the OS Portability * Manager library is the first step to porting any SciTech * products to a new platform. * ****************************************************************************/ #include "pmapi.h" #include "drvlib/os/os.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ENABLE_MTRR #include #endif #include #ifdef __GLIBC__ #include #endif /*--------------------------- Global variables ----------------------------*/ #define REAL_MEM_BASE ((void *)0x10000) #define REAL_MEM_SIZE 0x10000 #define REAL_MEM_BLOCKS 0x100 #define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK) #define DEFAULT_STACK_SIZE 0x1000 #define RETURN_TO_32_INT 255 /* Quick and dirty fix for vm86() syscall from lrmi 0.6 */ static int vm86(struct vm86_struct *vm) { int r; #ifdef __PIC__ asm volatile ( "pushl %%ebx\n\t" "movl %2, %%ebx\n\t" "int $0x80\n\t" "popl %%ebx" : "=a" (r) : "0" (113), "r" (vm)); #else asm volatile ( "int $0x80" : "=a" (r) : "0" (113), "b" (vm)); #endif return r; } static struct { int ready; unsigned short ret_seg, ret_off; unsigned short stack_seg, stack_off; struct vm86_struct vm; } context = {0}; struct mem_block { unsigned int size : 20; unsigned int free : 1; }; static struct { int ready; int count; struct mem_block blocks[REAL_MEM_BLOCKS]; } mem_info = {0}; int _PM_console_fd = -1; int _PM_leds = 0,_PM_modifiers = 0; static ibool inited = false; static int tty_vc = 0; static int console_count = 0; static int startup_vc; static int fd_mem = 0; static ibool in_raw_mode = false; #ifdef ENABLE_MTRR static int mtrr_fd; #endif static uint VESABuf_len = 1024; /* Length of the VESABuf buffer */ static void *VESABuf_ptr = NULL; /* Near pointer to VESABuf */ static uint VESABuf_rseg; /* Real mode segment of VESABuf */ static uint VESABuf_roff; /* Real mode offset of VESABuf */ #ifdef TRACE_IO static ulong traceAddr; #endif static void (PMAPIP fatalErrorCleanup)(void) = NULL; /*----------------------------- Implementation ----------------------------*/ #ifdef TRACE_IO extern void printk(char *msg,...); #endif static inline void port_out(int value, int port) { #ifdef TRACE_IO printk("%04X:%04X: outb.%04X <- %02X\n", traceAddr >> 16, traceAddr & 0xFFFF, (ushort)port, (uchar)value); #endif asm volatile ("outb %0,%1" ::"a" ((unsigned char) value), "d"((unsigned short) port)); } static inline void port_outw(int value, int port) { #ifdef TRACE_IO printk("%04X:%04X: outw.%04X <- %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value); #endif asm volatile ("outw %0,%1" ::"a" ((unsigned short) value), "d"((unsigned short) port)); } static inline void port_outl(int value, int port) { #ifdef TRACE_IO printk("%04X:%04X: outl.%04X <- %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value); #endif asm volatile ("outl %0,%1" ::"a" ((unsigned long) value), "d"((unsigned short) port)); } static inline unsigned int port_in(int port) { unsigned char value; asm volatile ("inb %1,%0" :"=a" ((unsigned char)value) :"d"((unsigned short) port)); #ifdef TRACE_IO printk("%04X:%04X: inb.%04X -> %02X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (uchar)value); #endif return value; } static inline unsigned int port_inw(int port) { unsigned short value; asm volatile ("inw %1,%0" :"=a" ((unsigned short)value) :"d"((unsigned short) port)); #ifdef TRACE_IO printk("%04X:%04X: inw.%04X -> %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value); #endif return value; } static inline unsigned int port_inl(int port) { unsigned long value; asm volatile ("inl %1,%0" :"=a" ((unsigned long)value) :"d"((unsigned short) port)); #ifdef TRACE_IO printk("%04X:%04X: inl.%04X -> %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value); #endif return value; } static int real_mem_init(void) { void *m; int fd_zero; if (mem_info.ready) return 1; if ((fd_zero = open("/dev/zero", O_RDONLY)) == -1) PM_fatalError("You must have root privledges to run this program!"); if ((m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd_zero, 0)) == (void *)-1) { close(fd_zero); PM_fatalError("You must have root privledges to run this program!"); } mem_info.ready = 1; mem_info.count = 1; mem_info.blocks[0].size = REAL_MEM_SIZE; mem_info.blocks[0].free = 1; return 1; } static void insert_block(int i) { memmove( mem_info.blocks + i + 1, mem_info.blocks + i, (mem_info.count - i) * sizeof(struct mem_block)); mem_info.count++; } static void delete_block(int i) { mem_info.count--; memmove( mem_info.blocks + i, mem_info.blocks + i + 1, (mem_info.count - i) * sizeof(struct mem_block)); } static inline void set_bit(unsigned int bit, void *array) { unsigned char *a = array; a[bit / 8] |= (1 << (bit % 8)); } static inline unsigned int get_int_seg(int i) { return *(unsigned short *)(i * 4 + 2); } static inline unsigned int get_int_off(int i) { return *(unsigned short *)(i * 4); } static inline void pushw(unsigned short i) { struct vm86_regs *r = &context.vm.regs; r->esp -= 2; *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i; } ibool PMAPI PM_haveBIOSAccess(void) { return true; } void PMAPI PM_init(void) { void *m; uint r_seg,r_off; if (inited) return; /* Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502) * and the physical framebuffer and ROM images from (0xa0000 - 0x100000) */ real_mem_init(); if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1) { PM_fatalError("You must have root privileges to run this program!"); } if ((m = mmap((void *)0, 0x502, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd_mem, 0)) == (void *)-1) { PM_fatalError("You must have root privileges to run this program!"); } if ((m = mmap((void *)0xA0000, 0xC0000 - 0xA0000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd_mem, 0xA0000)) == (void *)-1) { PM_fatalError("You must have root privileges to run this program!"); } if ((m = mmap((void *)0xC0000, 0xD0000 - 0xC0000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd_mem, 0xC0000)) == (void *)-1) { PM_fatalError("You must have root privileges to run this program!"); } if ((m = mmap((void *)0xD0000, 0x100000 - 0xD0000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd_mem, 0xD0000)) == (void *)-1) { PM_fatalError("You must have root privileges to run this program!"); } inited = 1; /* Allocate a stack */ m = PM_allocRealSeg(DEFAULT_STACK_SIZE,&r_seg,&r_off); context.stack_seg = r_seg; context.stack_off = r_off+DEFAULT_STACK_SIZE; /* Allocate the return to 32 bit routine */ m = PM_allocRealSeg(2,&r_seg,&r_off); context.ret_seg = r_seg; context.ret_off = r_off; ((uchar*)m)[0] = 0xCD; /* int opcode */ ((uchar*)m)[1] = RETURN_TO_32_INT; memset(&context.vm, 0, sizeof(context.vm)); /* Enable kernel emulation of all ints except RETURN_TO_32_INT */ memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored)); set_bit(RETURN_TO_32_INT, &context.vm.int_revectored); context.ready = 1; #ifdef ENABLE_MTRR mtrr_fd = open("/dev/cpu/mtrr", O_RDWR, 0); if (mtrr_fd < 0) mtrr_fd = open("/proc/mtrr", O_RDWR, 0); #endif /* Enable I/O permissions to directly access I/O ports. We break the * allocation into two parts, one for the ports from 0-0x3FF and * another for the remaining ports up to 0xFFFF. Standard Linux kernels * only allow the first 0x400 ports to be enabled, so to enable all * 65536 ports you need a patched kernel that will enable the full * 8Kb I/O permissions bitmap. */ #ifndef TRACE_IO ioperm(0x0,0x400,1); ioperm(0x400,0x10000-0x400,1); #endif iopl(3); } long PMAPI PM_getOSType(void) { return _OS_LINUX; } int PMAPI PM_getModeType(void) { return PM_386; } void PMAPI PM_backslash(char *s) { uint pos = strlen(s); if (s[pos-1] != '/') { s[pos] = '/'; s[pos+1] = '\0'; } } void PMAPI PM_setFatalErrorCleanup( void (PMAPIP cleanup)(void)) { fatalErrorCleanup = cleanup; } void PMAPI PM_fatalError(const char *msg) { if (fatalErrorCleanup) fatalErrorCleanup(); fprintf(stderr,"%s\n", msg); fflush(stderr); exit(1); } static void ExitVBEBuf(void) { if (VESABuf_ptr) PM_freeRealSeg(VESABuf_ptr); VESABuf_ptr = 0; } void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff) { if (!VESABuf_ptr) { /* Allocate a global buffer for communicating with the VESA VBE */ if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL) return NULL; atexit(ExitVBEBuf); } *len = VESABuf_len; *rseg = VESABuf_rseg; *roff = VESABuf_roff; return VESABuf_ptr; } /* New raw console based getch and kbhit functions */ #define KB_CAPS LED_CAP /* 4 */ #define KB_NUMLOCK LED_NUM /* 2 */ #define KB_SCROLL LED_SCR /* 1 */ #define KB_SHIFT 8 #define KB_CONTROL 16 #define KB_ALT 32 /* Structure used to save the keyboard mode to disk. We save it to disk * so that we can properly restore the mode later if the program crashed. */ typedef struct { struct termios termios; int kb_mode; int leds; int flags; int startup_vc; } keyboard_mode; /* Name of the file used to save keyboard mode information */ #define KBMODE_DAT "kbmode.dat" /**************************************************************************** REMARKS: Open the keyboard mode file on disk. ****************************************************************************/ static FILE *open_kb_mode( char *mode, char *path) { if (!PM_findBPD("graphics.bpd",path)) return NULL; PM_backslash(path); strcat(path,KBMODE_DAT); return fopen(path,mode); } /**************************************************************************** REMARKS: Restore the keyboard to normal mode ****************************************************************************/ void _PM_restore_kb_mode(void) { FILE *kbmode; keyboard_mode mode; char path[PM_MAX_PATH]; if (_PM_console_fd != -1 && (kbmode = open_kb_mode("rb",path)) != NULL) { if (fread(&mode,1,sizeof(mode),kbmode) == sizeof(mode)) { if (mode.startup_vc > 0) ioctl(_PM_console_fd, VT_ACTIVATE, mode.startup_vc); ioctl(_PM_console_fd, KDSKBMODE, mode.kb_mode); ioctl(_PM_console_fd, KDSETLED, mode.leds); tcsetattr(_PM_console_fd, TCSAFLUSH, &mode.termios); fcntl(_PM_console_fd,F_SETFL,mode.flags); } fclose(kbmode); unlink(path); in_raw_mode = false; } } /**************************************************************************** REMARKS: Safely abort the event module upon catching a fatal error. ****************************************************************************/ void _PM_abort( int signo) { char buf[80]; sprintf(buf,"Terminating on signal %d",signo); _PM_restore_kb_mode(); PM_fatalError(buf); } /**************************************************************************** REMARKS: Put the keyboard into raw mode ****************************************************************************/ void _PM_keyboard_rawmode(void) { struct termios conf; FILE *kbmode; keyboard_mode mode; char path[PM_MAX_PATH]; int i; static int sig_list[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, SIGBUS, SIGFPE, SIGKILL, SIGSEGV, SIGTERM, }; if ((kbmode = open_kb_mode("rb",path)) == NULL) { if ((kbmode = open_kb_mode("wb",path)) == NULL) PM_fatalError("Unable to open kbmode.dat file for writing!"); if (ioctl(_PM_console_fd, KDGKBMODE, &mode.kb_mode)) perror("KDGKBMODE"); ioctl(_PM_console_fd, KDGETLED, &mode.leds); _PM_leds = mode.leds & 0xF; _PM_modifiers = 0; tcgetattr(_PM_console_fd, &mode.termios); conf = mode.termios; conf.c_lflag &= ~(ICANON | ECHO | ISIG); conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF); conf.c_iflag |= (IGNBRK | IGNPAR); conf.c_cc[VMIN] = 1; conf.c_cc[VTIME] = 0; conf.c_cc[VSUSP] = 0; tcsetattr(_PM_console_fd, TCSAFLUSH, &conf); mode.flags = fcntl(_PM_console_fd,F_GETFL); if (ioctl(_PM_console_fd, KDSKBMODE, K_MEDIUMRAW)) perror("KDSKBMODE"); atexit(_PM_restore_kb_mode); for (i = 0; i < sizeof(sig_list)/sizeof(sig_list[0]); i++) signal(sig_list[i], _PM_abort); mode.startup_vc = startup_vc; if (fwrite(&mode,1,sizeof(mode),kbmode) != sizeof(mode)) PM_fatalError("Error writing kbmode.dat!"); fclose(kbmode); in_raw_mode = true; } } int PMAPI PM_kbhit(void) { fd_set s; struct timeval tv = { 0, 0 }; if (console_count == 0) PM_fatalError("You *must* open a console before using PM_kbhit!"); if (!in_raw_mode) _PM_keyboard_rawmode(); FD_ZERO(&s); FD_SET(_PM_console_fd, &s); return select(_PM_console_fd+1, &s, NULL, NULL, &tv) > 0; } int PMAPI PM_getch(void) { static uchar c; int release; static struct kbentry ke; if (console_count == 0) PM_fatalError("You *must* open a console before using PM_getch!"); if (!in_raw_mode) _PM_keyboard_rawmode(); while (read(_PM_console_fd, &c, 1) > 0) { release = c & 0x80; c &= 0x7F; if (release) { switch(c){ case 42: case 54: /* Shift */ _PM_modifiers &= ~KB_SHIFT; break; case 29: case 97: /* Control */ _PM_modifiers &= ~KB_CONTROL; break; case 56: case 100: /* Alt / AltGr */ _PM_modifiers &= ~KB_ALT; break; } continue; } switch (c) { case 42: case 54: /* Shift */ _PM_modifiers |= KB_SHIFT; break; case 29: case 97: /* Control */ _PM_modifiers |= KB_CONTROL; break; case 56: case 100: /* Alt / AltGr */ _PM_modifiers |= KB_ALT; break; case 58: /* Caps Lock */ _PM_modifiers ^= KB_CAPS; ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7); break; case 69: /* Num Lock */ _PM_modifiers ^= KB_NUMLOCK; ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7); break; case 70: /* Scroll Lock */ _PM_modifiers ^= KB_SCROLL; ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7); break; case 28: return 0x1C; default: ke.kb_index = c; ke.kb_table = 0; if ((_PM_modifiers & KB_SHIFT) || (_PM_modifiers & KB_CAPS)) ke.kb_table |= K_SHIFTTAB; if (_PM_modifiers & KB_ALT) ke.kb_table |= K_ALTTAB; ioctl(_PM_console_fd, KDGKBENT, (ulong)&ke); c = ke.kb_value & 0xFF; return c; } } return 0; } /**************************************************************************** REMARKS: Sleep until the virtual terminal is active ****************************************************************************/ static void wait_vt_active( int _PM_console_fd) { while (ioctl(_PM_console_fd, VT_WAITACTIVE, tty_vc) < 0) { if ((errno != EAGAIN) && (errno != EINTR)) { perror("ioctl(VT_WAITACTIVE)"); exit(1); } usleep(150000); } } /**************************************************************************** REMARKS: Checks the owner of the specified virtual console. ****************************************************************************/ static int check_owner( int vc) { struct stat sbuf; char fname[30]; sprintf(fname, "/dev/tty%d", vc); if ((stat(fname, &sbuf) >= 0) && (getuid() == sbuf.st_uid)) return 1; printf("You must be the owner of the current console to use this program.\n"); return 0; } /**************************************************************************** REMARKS: Checks if the console is currently in graphics mode, and if so we forcibly restore it back to text mode again. This handles the case when a Nucleus or MGL program crashes and leaves the console in graphics mode. Running the textmode utility (or any other Nucleus/MGL program) via a telnet session into the machine will restore it back to normal. ****************************************************************************/ static void restore_text_console( int console_id) { if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0) LOGWARN("ioctl(KDSETMODE) failed"); _PM_restore_kb_mode(); } /**************************************************************************** REMARKS: Opens up the console device for output by finding an appropriate virutal console that we can run on. ****************************************************************************/ PM_HWND PMAPI PM_openConsole( PM_HWND hwndUser, int device, int xRes, int yRes, int bpp, ibool fullScreen) { struct vt_mode vtm; struct vt_stat vts; struct stat sbuf; char fname[30]; /* Check if we have already opened the console */ if (console_count++) return _PM_console_fd; /* Now, it would be great if we could use /dev/tty and see what it is * connected to. Alas, we cannot find out reliably what VC /dev/tty is * bound to. Thus we parse stdin through stderr for a reliable VC. */ startup_vc = 0; for (_PM_console_fd = 0; _PM_console_fd < 3; _PM_console_fd++) { if (fstat(_PM_console_fd, &sbuf) < 0) continue; if (ioctl(_PM_console_fd, VT_GETMODE, &vtm) < 0) continue; if ((sbuf.st_rdev & 0xFF00) != 0x400) continue; if (!(sbuf.st_rdev & 0xFF)) continue; tty_vc = sbuf.st_rdev & 0xFF; restore_text_console(_PM_console_fd); return _PM_console_fd; } if ((_PM_console_fd = open("/dev/console", O_RDWR)) < 0) { printf("open_dev_console: can't open /dev/console \n"); exit(1); } if (ioctl(_PM_console_fd, VT_OPENQRY, &tty_vc) < 0) goto Error; if (tty_vc <= 0) goto Error; sprintf(fname, "/dev/tty%d", tty_vc); close(_PM_console_fd); /* Change our control terminal */ setsid(); /* We must use RDWR to allow for output... */ if (((_PM_console_fd = open(fname, O_RDWR)) >= 0) && (ioctl(_PM_console_fd, VT_GETSTATE, &vts) >= 0)) { if (!check_owner(vts.v_active)) goto Error; restore_text_console(_PM_console_fd); /* Success, redirect all stdios */ fflush(stdin); fflush(stdout); fflush(stderr); close(0); close(1); close(2); dup(_PM_console_fd); dup(_PM_console_fd); dup(_PM_console_fd); /* clear screen and switch to it */ fwrite("\e[H\e[J", 6, 1, stderr); fflush(stderr); if (tty_vc != vts.v_active) { startup_vc = vts.v_active; ioctl(_PM_console_fd, VT_ACTIVATE, tty_vc); wait_vt_active(_PM_console_fd); } } return _PM_console_fd; Error: if (_PM_console_fd > 2) close(_PM_console_fd); console_count = 0; PM_fatalError( "Not running in a graphics capable console,\n" "and unable to find one.\n"); return -1; } #define FONT_C 0x10000 /* 64KB for font data */ /**************************************************************************** REMARKS: Returns the size of the console state buffer. ****************************************************************************/ int PMAPI PM_getConsoleStateSize(void) { if (!inited) PM_init(); return PM_getVGAStateSize() + FONT_C*2; } /**************************************************************************** REMARKS: Save the state of the Linux console. ****************************************************************************/ void PMAPI PM_saveConsoleState(void *stateBuf,int console_id) { uchar *regs = stateBuf; /* Save the current console font */ if (ioctl(console_id,GIO_FONT,®s[PM_getVGAStateSize()]) < 0) perror("ioctl(GIO_FONT)"); /* Inform the Linux console that we are going into graphics mode */ if (ioctl(console_id, KDSETMODE, KD_GRAPHICS) < 0) perror("ioctl(KDSETMODE)"); /* Save state of VGA registers */ PM_saveVGAState(stateBuf); } void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags)) { /* TODO: Implement support for allowing console switching! */ } /**************************************************************************** REMARKS: Restore the state of the Linux console. ****************************************************************************/ void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND console_id) { const uchar *regs = stateBuf; /* Restore the state of the VGA compatible registers */ PM_restoreVGAState(stateBuf); /* Inform the Linux console that we are back from graphics modes */ if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0) LOGWARN("ioctl(KDSETMODE) failed"); /* Restore the old console font */ if (ioctl(console_id,PIO_FONT,®s[PM_getVGAStateSize()]) < 0) LOGWARN("ioctl(KDSETMODE) failed"); /* Coming back from graphics mode on Linux also restored the previous * text mode console contents, so we need to clear the screen to get * around this since the cursor does not get homed by our code. */ fflush(stdout); fflush(stderr); printf("\033[H\033[J"); fflush(stdout); } /**************************************************************************** REMARKS: Close the Linux console and put it back to normal. ****************************************************************************/ void PMAPI PM_closeConsole(PM_HWND _PM_console_fd) { /* Restore console to normal operation */ if (--console_count == 0) { /* Re-activate the original virtual console */ if (startup_vc > 0) ioctl(_PM_console_fd, VT_ACTIVATE, startup_vc); /* Close the console file descriptor */ if (_PM_console_fd > 2) close(_PM_console_fd); _PM_console_fd = -1; } } void PM_setOSCursorLocation(int x,int y) { /* Nothing to do in here */ } /**************************************************************************** REMARKS: Set the screen width and height for the Linux console. ****************************************************************************/ void PM_setOSScreenWidth(int width,int height) { struct winsize ws; struct vt_sizes vs; /* Resize the software terminal */ ws.ws_col = width; ws.ws_row = height; ioctl(_PM_console_fd, TIOCSWINSZ, &ws); /* And the hardware */ vs.v_rows = height; vs.v_cols = width; vs.v_scrollsize = 0; ioctl(_PM_console_fd, VT_RESIZE, &vs); } ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency) { /* TODO: Implement this for Linux */ return false; } void PMAPI PM_setRealTimeClockFrequency(int frequency) { /* TODO: Implement this for Linux */ } void PMAPI PM_restoreRealTimeClockHandler(void) { /* TODO: Implement this for Linux */ } char * PMAPI PM_getCurrentPath( char *path, int maxLen) { return getcwd(path,maxLen); } char PMAPI PM_getBootDrive(void) { return '/'; } const char * PMAPI PM_getVBEAFPath(void) { return PM_getNucleusConfigPath(); } const char * PMAPI PM_getNucleusPath(void) { char *env = getenv("NUCLEUS_PATH"); return env ? env : "/usr/lib/nucleus"; } const char * PMAPI PM_getNucleusConfigPath(void) { static char path[256]; strcpy(path,PM_getNucleusPath()); PM_backslash(path); strcat(path,"config"); return path; } const char * PMAPI PM_getUniqueID(void) { static char buf[128]; gethostname(buf, 128); return buf; } const char * PMAPI PM_getMachineName(void) { static char buf[128]; gethostname(buf, 128); return buf; } void * PMAPI PM_getBIOSPointer(void) { static uchar *zeroPtr = NULL; if (!zeroPtr) zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true); return (void*)(zeroPtr + 0x400); } void * PMAPI PM_getA0000Pointer(void) { /* PM_init maps in the 0xA0000 framebuffer region 1:1 with our * address mapping, so we can return the address here. */ if (!inited) PM_init(); return (void*)(0xA0000); } void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached) { uchar *p; ulong baseAddr,baseOfs; if (!inited) PM_init(); if (base >= 0xA0000 && base < 0x100000) return (void*)base; if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1) return NULL; /* Round the physical address to a 4Kb boundary and the limit to a * 4Kb-1 boundary before passing the values to mmap. If we round the * physical address, then we also add an extra offset into the address * that we return. */ baseOfs = base & 4095; baseAddr = base & ~4095; limit = ((limit+baseOfs+1+4095) & ~4095)-1; if ((p = mmap(0, limit+1, PROT_READ | PROT_WRITE, MAP_SHARED, fd_mem, baseAddr)) == (void *)-1) return NULL; return (void*)(p+baseOfs); } void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit) { if ((ulong)ptr >= 0x100000) munmap(ptr,limit+1); } ulong PMAPI PM_getPhysicalAddr(void *p) { /* TODO: This function should find the physical address of a linear */ /* address. */ return 0xFFFFFFFFUL; } ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress) { /* TODO: This function should find a range of physical addresses */ /* for a linear address. */ return false; } void PMAPI PM_sleep(ulong milliseconds) { /* TODO: Put the process to sleep for milliseconds */ } int PMAPI PM_getCOMPort(int port) { /* TODO: Re-code this to determine real values using the Plug and Play */ /* manager for the OS. */ switch (port) { case 0: return 0x3F8; case 1: return 0x2F8; } return 0; } int PMAPI PM_getLPTPort(int port) { /* TODO: Re-code this to determine real values using the Plug and Play */ /* manager for the OS. */ switch (port) { case 0: return 0x3BC; case 1: return 0x378; case 2: return 0x278; } return 0; } void * PMAPI PM_mallocShared(long size) { return PM_malloc(size); } void PMAPI PM_freeShared(void *ptr) { PM_free(ptr); } void * PMAPI PM_mapToProcess(void *base,ulong limit) { return (void*)base; } void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off) { /* PM_init maps in the 0xA0000-0x100000 region 1:1 with our * address mapping, as well as all memory blocks in a 1:1 address * mapping so we can simply return the physical address in here. */ if (!inited) PM_init(); return (void*)MK_PHYS(r_seg,r_off); } void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off) { int i; char *r = (char *)REAL_MEM_BASE; if (!inited) PM_init(); if (!mem_info.ready) return NULL; if (mem_info.count == REAL_MEM_BLOCKS) return NULL; size = (size + 15) & ~15; for (i = 0; i < mem_info.count; i++) { if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) { insert_block(i); mem_info.blocks[i].size = size; mem_info.blocks[i].free = 0; mem_info.blocks[i + 1].size -= size; *r_seg = (uint)(r) >> 4; *r_off = (uint)(r) & 0xF; return (void *)r; } r += mem_info.blocks[i].size; } return NULL; } void PMAPI PM_freeRealSeg(void *mem) { int i; char *r = (char *)REAL_MEM_BASE; if (!mem_info.ready) return; i = 0; while (mem != (void *)r) { r += mem_info.blocks[i].size; i++; if (i == mem_info.count) return; } mem_info.blocks[i].free = 1; if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) { mem_info.blocks[i].size += mem_info.blocks[i + 1].size; delete_block(i + 1); } if (i - 1 >= 0 && mem_info.blocks[i - 1].free) { mem_info.blocks[i - 1].size += mem_info.blocks[i].size; delete_block(i); } } #define DIRECTION_FLAG (1 << 10) static void em_ins(int size) { unsigned int edx, edi; edx = context.vm.regs.edx & 0xffff; edi = context.vm.regs.edi & 0xffff; edi += (unsigned int)context.vm.regs.ds << 4; if (context.vm.regs.eflags & DIRECTION_FLAG) { if (size == 4) asm volatile ("std; insl; cld" : "=D" (edi) : "d" (edx), "0" (edi)); else if (size == 2) asm volatile ("std; insw; cld" : "=D" (edi) : "d" (edx), "0" (edi)); else asm volatile ("std; insb; cld" : "=D" (edi) : "d" (edx), "0" (edi)); } else { if (size == 4) asm volatile ("cld; insl" : "=D" (edi) : "d" (edx), "0" (edi)); else if (size == 2) asm volatile ("cld; insw" : "=D" (edi) : "d" (edx), "0" (edi)); else asm volatile ("cld; insb" : "=D" (edi) : "d" (edx), "0" (edi)); } edi -= (unsigned int)context.vm.regs.ds << 4; context.vm.regs.edi &= 0xffff0000; context.vm.regs.edi |= edi & 0xffff; } static void em_rep_ins(int size) { unsigned int ecx, edx, edi; ecx = context.vm.regs.ecx & 0xffff; edx = context.vm.regs.edx & 0xffff; edi = context.vm.regs.edi & 0xffff; edi += (unsigned int)context.vm.regs.ds << 4; if (context.vm.regs.eflags & DIRECTION_FLAG) { if (size == 4) asm volatile ("std; rep; insl; cld" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else if (size == 2) asm volatile ("std; rep; insw; cld" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else asm volatile ("std; rep; insb; cld" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); } else { if (size == 4) asm volatile ("cld; rep; insl" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else if (size == 2) asm volatile ("cld; rep; insw" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); else asm volatile ("cld; rep; insb" : "=D" (edi), "=c" (ecx) : "d" (edx), "0" (edi), "1" (ecx)); } edi -= (unsigned int)context.vm.regs.ds << 4; context.vm.regs.edi &= 0xffff0000; context.vm.regs.edi |= edi & 0xffff; context.vm.regs.ecx &= 0xffff0000; context.vm.regs.ecx |= ecx & 0xffff; } static void em_outs(int size) { unsigned int edx, esi; edx = context.vm.regs.edx & 0xffff; esi = context.vm.regs.esi & 0xffff; esi += (unsigned int)context.vm.regs.ds << 4; if (context.vm.regs.eflags & DIRECTION_FLAG) { if (size == 4) asm volatile ("std; outsl; cld" : "=S" (esi) : "d" (edx), "0" (esi)); else if (size == 2) asm volatile ("std; outsw; cld" : "=S" (esi) : "d" (edx), "0" (esi)); else asm volatile ("std; outsb; cld" : "=S" (esi) : "d" (edx), "0" (esi)); } else { if (size == 4) asm volatile ("cld; outsl" : "=S" (esi) : "d" (edx), "0" (esi)); else if (size == 2) asm volatile ("cld; outsw" : "=S" (esi) : "d" (edx), "0" (esi)); else asm volatile ("cld; outsb" : "=S" (esi) : "d" (edx), "0" (esi)); } esi -= (unsigned int)context.vm.regs.ds << 4; context.vm.regs.esi &= 0xffff0000; context.vm.regs.esi |= esi & 0xffff; } static void em_rep_outs(int size) { unsigned int ecx, edx, esi; ecx = context.vm.regs.ecx & 0xffff; edx = context.vm.regs.edx & 0xffff; esi = context.vm.regs.esi & 0xffff; esi += (unsigned int)context.vm.regs.ds << 4; if (context.vm.regs.eflags & DIRECTION_FLAG) { if (size == 4) asm volatile ("std; rep; outsl; cld" : "=S" (esi), "=c" (ecx) : "d" (edx), "0" (esi), "1" (ecx)); else if (size == 2) asm volatile ("std; rep; outsw; cld" : "=S" (esi), "=c" (ecx) : "d" (edx), "0" (esi), "1" (ecx)); else asm volatile ("std; rep; outsb; cld" : "=S" (esi), "=c" (ecx) : "d" (edx), "0" (esi), "1" (ecx)); } else { if (size == 4) asm volatile ("cld; rep; outsl" : "=S" (esi), "=c" (ecx) : "d" (edx), "0" (esi), "1" (ecx)); else if (size == 2) asm volatile ("cld; rep; outsw" : "=S" (esi), "=c" (ecx) : "d" (edx), "0" (esi), "1" (ecx)); else asm volatile ("cld; rep; outsb" : "=S" (esi), "=c" (ecx) : "d" (edx), "0" (esi), "1" (ecx)); } esi -= (unsigned int)context.vm.regs.ds << 4; context.vm.regs.esi &= 0xffff0000; context.vm.regs.esi |= esi & 0xffff; context.vm.regs.ecx &= 0xffff0000; context.vm.regs.ecx |= ecx & 0xffff; } static int emulate(void) { unsigned char *insn; struct { unsigned int size : 1; unsigned int rep : 1; } prefix = { 0, 0 }; int i = 0; insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4); insn += context.vm.regs.eip; while (1) { #ifdef TRACE_IO traceAddr = ((ulong)context.vm.regs.cs << 16) + context.vm.regs.eip + i; #endif if (insn[i] == 0x66) { prefix.size = 1 - prefix.size; i++; } else if (insn[i] == 0xf3) { prefix.rep = 1; i++; } else if (insn[i] == 0xf0 || insn[i] == 0xf2 || insn[i] == 0x26 || insn[i] == 0x2e || insn[i] == 0x36 || insn[i] == 0x3e || insn[i] == 0x64 || insn[i] == 0x65 || insn[i] == 0x67) { /* these prefixes are just ignored */ i++; } else if (insn[i] == 0x6c) { if (prefix.rep) em_rep_ins(1); else em_ins(1); i++; break; } else if (insn[i] == 0x6d) { if (prefix.rep) { if (prefix.size) em_rep_ins(4); else em_rep_ins(2); } else { if (prefix.size) em_ins(4); else em_ins(2); } i++; break; } else if (insn[i] == 0x6e) { if (prefix.rep) em_rep_outs(1); else em_outs(1); i++; break; } else if (insn[i] == 0x6f) { if (prefix.rep) { if (prefix.size) em_rep_outs(4); else em_rep_outs(2); } else { if (prefix.size) em_outs(4); else em_outs(2); } i++; break; } else if (insn[i] == 0xec) { *((uchar*)&context.vm.regs.eax) = port_in(context.vm.regs.edx); i++; break; } else if (insn[i] == 0xed) { if (prefix.size) *((ulong*)&context.vm.regs.eax) = port_inl(context.vm.regs.edx); else *((ushort*)&context.vm.regs.eax) = port_inw(context.vm.regs.edx); i++; break; } else if (insn[i] == 0xee) { port_out(context.vm.regs.eax,context.vm.regs.edx); i++; break; } else if (insn[i] == 0xef) { if (prefix.size) port_outl(context.vm.regs.eax,context.vm.regs.edx); else port_outw(context.vm.regs.eax,context.vm.regs.edx); i++; break; } else return 0; } context.vm.regs.eip += i; return 1; } static void debug_info(int vret) { int i; unsigned char *p; fputs("vm86() failed\n", stderr); fprintf(stderr, "return = 0x%x\n", vret); fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax); fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx); fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx); fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx); fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi); fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi); fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp); fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip); fprintf(stderr, "cs = 0x%04x\n", context.vm.regs.cs); fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp); fprintf(stderr, "ss = 0x%04x\n", context.vm.regs.ss); fprintf(stderr, "ds = 0x%04x\n", context.vm.regs.ds); fprintf(stderr, "es = 0x%04x\n", context.vm.regs.es); fprintf(stderr, "fs = 0x%04x\n", context.vm.regs.fs); fprintf(stderr, "gs = 0x%04x\n", context.vm.regs.gs); fprintf(stderr, "eflags = 0x%08lx\n", context.vm.regs.eflags); fputs("cs:ip = [ ", stderr); p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff)); for (i = 0; i < 16; ++i) fprintf(stderr, "%02x ", (unsigned int)p[i]); fputs("]\n", stderr); fflush(stderr); } static int run_vm86(void) { unsigned int vret; for (;;) { vret = vm86(&context.vm); if (VM86_TYPE(vret) == VM86_INTx) { unsigned int v = VM86_ARG(vret); if (v == RETURN_TO_32_INT) return 1; pushw(context.vm.regs.eflags); pushw(context.vm.regs.cs); pushw(context.vm.regs.eip); context.vm.regs.cs = get_int_seg(v); context.vm.regs.eip = get_int_off(v); context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK); continue; } if (VM86_TYPE(vret) != VM86_UNKNOWN) break; if (!emulate()) break; } debug_info(vret); return 0; } #define IND(ereg) context.vm.regs.ereg = regs->ereg #define OUTD(ereg) regs->ereg = context.vm.regs.ereg void PMAPI DPMI_int86(int intno, DPMI_regs *regs) { if (!inited) PM_init(); memset(&context.vm.regs, 0, sizeof(context.vm.regs)); IND(eax); IND(ebx); IND(ecx); IND(edx); IND(esi); IND(edi); context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = get_int_seg(intno); context.vm.regs.eip = get_int_off(intno); context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); OUTD(eax); OUTD(ebx); OUTD(ecx); OUTD(edx); OUTD(esi); OUTD(edi); regs->flags = context.vm.regs.eflags; } #define IN(ereg) context.vm.regs.ereg = in->e.ereg #define OUT(ereg) out->e.ereg = context.vm.regs.ereg int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out) { if (!inited) PM_init(); memset(&context.vm.regs, 0, sizeof(context.vm.regs)); IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = get_int_seg(intno); context.vm.regs.eip = get_int_off(intno); context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi); out->x.cflag = context.vm.regs.eflags & 1; return out->x.ax; } int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs) { if (!inited) PM_init(); if (intno == 0x21) { time_t today = time(NULL); struct tm *t; t = localtime(&today); out->x.cx = t->tm_year + 1900; out->h.dh = t->tm_mon + 1; out->h.dl = t->tm_mday; } else { unsigned int seg, off; seg = get_int_seg(intno); off = get_int_off(intno); memset(&context.vm.regs, 0, sizeof(context.vm.regs)); IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = seg; context.vm.regs.eip = off; context.vm.regs.es = sregs->es; context.vm.regs.ds = sregs->ds; context.vm.regs.fs = sregs->fs; context.vm.regs.gs = sregs->gs; context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi); sregs->es = context.vm.regs.es; sregs->ds = context.vm.regs.ds; sregs->fs = context.vm.regs.fs; sregs->gs = context.vm.regs.gs; out->x.cflag = context.vm.regs.eflags & 1; } return out->e.eax; } #define OUTR(ereg) in->e.ereg = context.vm.regs.ereg void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in, RMSREGS *sregs) { if (!inited) PM_init(); memset(&context.vm.regs, 0, sizeof(context.vm.regs)); IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi); context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = seg; context.vm.regs.eip = off; context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; context.vm.regs.es = sregs->es; context.vm.regs.ds = sregs->ds; context.vm.regs.fs = sregs->fs; context.vm.regs.gs = sregs->gs; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); OUTR(eax); OUTR(ebx); OUTR(ecx); OUTR(edx); OUTR(esi); OUTR(edi); sregs->es = context.vm.regs.es; sregs->ds = context.vm.regs.ds; sregs->fs = context.vm.regs.fs; sregs->gs = context.vm.regs.gs; in->x.cflag = context.vm.regs.eflags & 1; } void PMAPI PM_availableMemory(ulong *physical,ulong *total) { FILE *mem = fopen("/proc/meminfo","r"); char buf[1024]; fgets(buf,1024,mem); fgets(buf,1024,mem); sscanf(buf,"Mem: %*d %*d %ld", physical); fgets(buf,1024,mem); sscanf(buf,"Swap: %*d %*d %ld", total); fclose(mem); *total += *physical; } void * PMAPI PM_allocLockedMem(uint size,ulong *physAddr,ibool contiguous,ibool below16M) { /* TODO: Implement this for Linux */ return NULL; } void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous) { /* TODO: Implement this for Linux */ } void * PMAPI PM_allocPage( ibool locked) { /* TODO: Implement this for Linux */ return NULL; } void PMAPI PM_freePage( void *p) { /* TODO: Implement this for Linux */ } void PMAPI PM_setBankA(int bank) { if (!inited) PM_init(); memset(&context.vm.regs, 0, sizeof(context.vm.regs)); context.vm.regs.eax = 0x4F05; context.vm.regs.ebx = 0x0000; context.vm.regs.edx = bank; context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = get_int_seg(0x10); context.vm.regs.eip = get_int_off(0x10); context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); } void PMAPI PM_setBankAB(int bank) { if (!inited) PM_init(); memset(&context.vm.regs, 0, sizeof(context.vm.regs)); context.vm.regs.eax = 0x4F05; context.vm.regs.ebx = 0x0000; context.vm.regs.edx = bank; context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = get_int_seg(0x10); context.vm.regs.eip = get_int_off(0x10); context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); context.vm.regs.eax = 0x4F05; context.vm.regs.ebx = 0x0001; context.vm.regs.edx = bank; context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = get_int_seg(0x10); context.vm.regs.eip = get_int_off(0x10); context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); } void PMAPI PM_setCRTStart(int x,int y,int waitVRT) { if (!inited) PM_init(); memset(&context.vm.regs, 0, sizeof(context.vm.regs)); context.vm.regs.eax = 0x4F07; context.vm.regs.ebx = waitVRT; context.vm.regs.ecx = x; context.vm.regs.edx = y; context.vm.regs.eflags = DEFAULT_VM86_FLAGS; context.vm.regs.cs = get_int_seg(0x10); context.vm.regs.eip = get_int_off(0x10); context.vm.regs.ss = context.stack_seg; context.vm.regs.esp = context.stack_off; pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); run_vm86(); } int PMAPI PM_enableWriteCombine(ulong base,ulong length,uint type) { #ifdef ENABLE_MTRR struct mtrr_sentry sentry; if (mtrr_fd < 0) return PM_MTRR_ERR_NO_OS_SUPPORT; sentry.base = base; sentry.size = length; sentry.type = type; if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) { /* TODO: Need to decode MTRR error codes!! */ return PM_MTRR_NOT_SUPPORTED; } return PM_MTRR_ERR_OK; #else return PM_MTRR_ERR_NO_OS_SUPPORT; #endif } /**************************************************************************** PARAMETERS: callback - Function to callback with write combine information REMARKS: Function to enumerate all write combine regions currently enabled for the processor. ****************************************************************************/ int PMAPI PM_enumWriteCombine( PM_enumWriteCombine_t callback) { #ifdef ENABLE_MTRR struct mtrr_gentry gentry; if (mtrr_fd < 0) return PM_MTRR_ERR_NO_OS_SUPPORT; for (gentry.regnum = 0; ioctl (mtrr_fd, MTRRIOC_GET_ENTRY, &gentry) == 0; ++gentry.regnum) { if (gentry.size > 0) { /* WARNING: This code assumes that the types in pmapi.h match the ones */ /* in the Linux kernel (mtrr.h) */ callback(gentry.base, gentry.size, gentry.type); } } return PM_MTRR_ERR_OK; #else return PM_MTRR_ERR_NO_OS_SUPPORT; #endif } ibool PMAPI PM_doBIOSPOST( ushort axVal, ulong BIOSPhysAddr, void *copyOfBIOS, ulong BIOSLen) { char *bios_ptr = (char*)0xC0000; char *old_bios; ulong Current10, Current6D, *rvec = 0; RMREGS regs; RMSREGS sregs; /* The BIOS is mapped to 0xC0000 with a private memory mapping enabled * which means we have a copy on write scheme. Hence we simply copy * the secondary BIOS image over the top of the old one. */ if (!inited) PM_init(); if ((old_bios = PM_malloc(BIOSLen)) == NULL) return false; if (BIOSPhysAddr != 0xC0000) { memcpy(old_bios,bios_ptr,BIOSLen); memcpy(bios_ptr,copyOfBIOS,BIOSLen); } /* The interrupt vectors should already be mmap()'ed from 0-0x400 in PM_init */ Current10 = rvec[0x10]; Current6D = rvec[0x6D]; /* POST the secondary BIOS */ rvec[0x10] = rvec[0x42]; /* Restore int 10h to STD-BIOS */ regs.x.ax = axVal; PM_callRealMode(0xC000,0x0003,®s,&sregs); /* Restore interrupt vectors */ rvec[0x10] = Current10; rvec[0x6D] = Current6D; /* Restore original BIOS image */ if (BIOSPhysAddr != 0xC0000) memcpy(bios_ptr,old_bios,BIOSLen); PM_free(old_bios); return true; } int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh) { p = p; len = len; return 1; } int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh) { p = p; len = len; return 1; } int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh) { p = p; len = len; return 1; } int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh) { p = p; len = len; return 1; } PM_MODULE PMAPI PM_loadLibrary( const char *szDLLName) { /* TODO: Implement this to load shared libraries! */ (void)szDLLName; return NULL; } void * PMAPI PM_getProcAddress( PM_MODULE hModule, const char *szProcName) { /* TODO: Implement this! */ (void)hModule; (void)szProcName; return NULL; } void PMAPI PM_freeLibrary( PM_MODULE hModule) { /* TODO: Implement this! */ (void)hModule; } int PMAPI PM_setIOPL( int level) { /* TODO: Move the IOPL switching into this function!! */ return level; } void PMAPI PM_flushTLB(void) { /* Do nothing on Linux. */ }