📄 pm.c
字号:
/****************************************************************************** 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 <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/mman.h>#include <sys/kd.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/vt.h>#include <sys/wait.h>#include <sys/types.h>#include <sys/time.h>#include <unistd.h>#include <termios.h>#include <fcntl.h>#include <syscall.h>#include <signal.h>#include <time.h>#include <ctype.h>#include <errno.h>#include <asm/io.h>#include <asm/types.h>#ifdef ENABLE_MTRR#include <asm/mtrr.h>#endif#include <asm/vm86.h>#ifdef __GLIBC__#include <sys/perm.h>#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 intvm86(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 struct termios old_termios;static ibool in_raw_mode = false;static int old_kb_mode,old_leds,old_flags;static int fd_mem = 0;#ifdef ENABLE_MTRRstatic int mtrr_fd;#endifstatic 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_IOstatic ulong traceAddr;#endifstatic void (PMAPIP fatalErrorCleanup)(void) = NULL;/*----------------------------- Implementation ----------------------------*/#ifdef TRACE_IOextern void printk(char *msg,...);#endifstatic 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); 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/****************************************************************************REMARKS:Restore the keyboard to normal mode****************************************************************************/void _PM_restore_kb_mode(void){ if (_PM_console_fd != -1 && in_raw_mode) { ioctl(_PM_console_fd, KDSKBMODE, old_kb_mode); ioctl(_PM_console_fd, KDSETLED, old_leds); tcsetattr(_PM_console_fd, TCSAFLUSH, &old_termios); fcntl(_PM_console_fd,F_SETFL,old_flags); if (_PM_console_fd > 2) close(_PM_console_fd); _PM_console_fd = -1; 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; if (!in_raw_mode) { if (ioctl(_PM_console_fd, KDGKBMODE, &old_kb_mode)) perror("KDGKBMODE"); ioctl(_PM_console_fd, KDGETLED, &old_leds); _PM_leds = old_leds & 0xF; _PM_modifiers = 0;#ifdef CHECKED if (old_kb_mode != K_XLATE) fprintf(stderr, "Warning: Console is already in raw mode.\n");#endif tcgetattr(_PM_console_fd, &old_termios); conf = old_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -