pm.c

来自「适合KS8695X」· C语言 代码 · 共 1,810 行 · 第 1/4 页

C
1,810
字号
;/****************************************************************************
*
*                   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 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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?