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 + -
显示快捷键?