diff options
author | arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2003-02-09 20:18:23 +0000 |
---|---|---|
committer | arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2003-02-09 20:18:23 +0000 |
commit | 7ff83a71810233276517bc497e93ac15267bc830 (patch) | |
tree | 23e697fbbe48eae893b8c28c383199bc6ca000ad /osdep | |
parent | c98692a0bf56e79781ae7ca2a1e358f518838dac (diff) | |
download | mpv-7ff83a71810233276517bc497e93ac15267bc830.tar.bz2 mpv-7ff83a71810233276517bc497e93ac15267bc830.tar.xz |
linux->osdep
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9381 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'osdep')
-rw-r--r-- | osdep/.cvsignore | 1 | ||||
-rw-r--r-- | osdep/Makefile | 46 | ||||
-rw-r--r-- | osdep/getch2.c | 256 | ||||
-rw-r--r-- | osdep/getch2.h | 20 | ||||
-rw-r--r-- | osdep/keycodes.h | 36 | ||||
-rw-r--r-- | osdep/lrmi.c | 912 | ||||
-rw-r--r-- | osdep/lrmi.h | 86 | ||||
-rw-r--r-- | osdep/scandir.c | 134 | ||||
-rw-r--r-- | osdep/shmem.c | 107 | ||||
-rw-r--r-- | osdep/shmem.h | 4 | ||||
-rw-r--r-- | osdep/strsep.c | 42 | ||||
-rw-r--r-- | osdep/timer-lx.c | 67 | ||||
-rw-r--r-- | osdep/timer.h | 17 | ||||
-rw-r--r-- | osdep/vbelib.c | 730 | ||||
-rw-r--r-- | osdep/vbelib.h | 227 | ||||
-rw-r--r-- | osdep/vsscanf.c | 20 |
16 files changed, 2705 insertions, 0 deletions
diff --git a/osdep/.cvsignore b/osdep/.cvsignore new file mode 100644 index 0000000000..4671378aef --- /dev/null +++ b/osdep/.cvsignore @@ -0,0 +1 @@ +.depend diff --git a/osdep/Makefile b/osdep/Makefile new file mode 100644 index 0000000000..f42b913d07 --- /dev/null +++ b/osdep/Makefile @@ -0,0 +1,46 @@ + +include ../config.mak + +LIBNAME = libosdep.a + +SRCS=getch2.c timer-lx.c shmem.c strsep.c vsscanf.c scandir.c # timer.c +OBJS=$(SRCS:.c=.o) + +ifeq ($(TARGET_ARCH_X86),yes) +ifeq ($(TARGET_OS),Linux) +SRCS += lrmi.c vbelib.c +endif +endif + +CFLAGS = $(OPTFLAGS) -I. -I.. $(EXTRA_INC) +# -I/usr/X11R6/include/ + +.SUFFIXES: .c .o + +# .PHONY: all clean + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< + +$(LIBNAME): $(OBJS) + $(AR) r $(LIBNAME) $(OBJS) + +all: $(LIBNAME) + +clean: + rm -f *.o *.a *~ + +distclean: + rm -f Makefile.bak *.o *.a *~ .depend + +dep: depend + +depend: + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +# +# include dependency files if they exist +# +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/osdep/getch2.c b/osdep/getch2.c new file mode 100644 index 0000000000..dec9b91a0f --- /dev/null +++ b/osdep/getch2.c @@ -0,0 +1,256 @@ +/* GyS-TermIO v2.0 (for GySmail v3) (C) 1999 A'rpi/ESP-team */ + +#include "../config.h" + +//#define USE_TERMCAP +#ifndef __OS2__ +#define USE_IOCTL +#endif + +#define MAX_KEYS 64 +#define BUF_LEN 256 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#ifdef USE_IOCTL +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_TERMIOS +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#endif +#ifdef HAVE_SYS_TERMIOS_H +#include <sys/termios.h> +#endif +#endif + +#include <unistd.h> + +#include "keycodes.h" + +#ifdef HAVE_TERMIOS +static struct termios tio_orig; +#endif +static int getch2_len=0; +static char getch2_buf[BUF_LEN]; + +int screen_width=80; +int screen_height=24; + +typedef struct { + int len; + int code; + char chars[8]; +} keycode_st; +static keycode_st getch2_keys[MAX_KEYS]; +static int getch2_key_db=0; + +#ifdef USE_TERMCAP + +#if 0 +#include <termcap.h> +#else + extern int tgetent (char *BUFFER, char *TERMTYPE); + extern int tgetnum (char *NAME); + extern int tgetflag (char *NAME); + extern char *tgetstr (char *NAME, char **AREA); +#endif + +static char term_buffer[4096]; +static char term_buffer2[4096]; +static char *term_p=term_buffer2; + +static void termcap_add(char *id,int code){ +char *p=tgetstr(id,&term_p); + if(!p) return; + if(getch2_key_db>=MAX_KEYS) return; + getch2_keys[getch2_key_db].len=strlen(p); + strncpy(getch2_keys[getch2_key_db].chars,p,8); + getch2_keys[getch2_key_db].code=code; + ++getch2_key_db; +/* printf("%s=%s\n",id,p); */ +} + +static int success=0; + +int load_termcap(char *termtype){ + if(!termtype) termtype=getenv("TERM"); + if(!termtype) termtype="unknown"; + success=tgetent(term_buffer, termtype); + if(success<0){ printf("Could not access the 'termcap' data base.\n"); return 0; } + if(success==0){ printf("Terminal type `%s' is not defined.\n", termtype);return 0;} + + screen_width=tgetnum("co"); + screen_height=tgetnum("li"); + if(screen_width<1 || screen_width>255) screen_width=80; + if(screen_height<1 || screen_height>255) screen_height=24; + + termcap_add("kP",KEY_PGUP); + termcap_add("kN",KEY_PGDWN); + termcap_add("kh",KEY_HOME); + termcap_add("kH",KEY_END); + termcap_add("kI",KEY_INS); + termcap_add("kD",KEY_DEL); + termcap_add("kb",KEY_BS); + termcap_add("kl",KEY_LEFT); + termcap_add("kd",KEY_DOWN); + termcap_add("ku",KEY_UP); + termcap_add("kr",KEY_RIGHT); + termcap_add("k0",KEY_F+0); + termcap_add("k1",KEY_F+1); + termcap_add("k2",KEY_F+2); + termcap_add("k3",KEY_F+3); + termcap_add("k4",KEY_F+4); + termcap_add("k5",KEY_F+5); + termcap_add("k6",KEY_F+6); + termcap_add("k7",KEY_F+7); + termcap_add("k8",KEY_F+8); + termcap_add("k9",KEY_F+9); + termcap_add("k;",KEY_F+10); + return getch2_key_db; +} + +#endif + +void get_screen_size(){ +#ifdef USE_IOCTL + struct winsize ws; + if (ioctl(0, TIOCGWINSZ, &ws) < 0 || !ws.ws_row || !ws.ws_col) return; +/* printf("Using IOCTL\n"); */ + screen_width=ws.ws_col; + screen_height=ws.ws_row; +#endif +} + +int getch2(int time){ + int len=0; + int code=0; + int i=0; + + while(!getch2_len || (getch2_len==1 && getch2_buf[0]==27)){ + fd_set rfds; + struct timeval tv; + int retval; + /* Watch stdin (fd 0) to see when it has input. */ + FD_ZERO(&rfds); FD_SET(0,&rfds); + /* Wait up to 'time' microseconds. */ + tv.tv_sec=time/1000; tv.tv_usec = (time%1000)*1000; + retval=select(1, &rfds, NULL, NULL, &tv); + if(retval<=0) return -1; + /* Data is available now. */ + retval=read(0,&getch2_buf[getch2_len],BUF_LEN-getch2_len); + if(retval<1) return -1; + getch2_len+=retval; + } + + /* First find in the TERMCAP database: */ + for(i=0;i<getch2_key_db;i++){ + if((len=getch2_keys[i].len)<=getch2_len) + if(memcmp(getch2_keys[i].chars,getch2_buf,len)==0){ + code=getch2_keys[i].code; goto found; + } + } + len=1;code=getch2_buf[0]; + /* Check the well-known codes... */ + if(code!=27){ + if(code=='A'-64){ code=KEY_HOME; goto found;} + if(code=='E'-64){ code=KEY_END; goto found;} + if(code=='D'-64){ code=KEY_DEL; goto found;} + if(code=='H'-64){ code=KEY_BS; goto found;} + if(code=='U'-64){ code=KEY_PGUP; goto found;} + if(code=='V'-64){ code=KEY_PGDWN; goto found;} + if(code==8 || code==127){ code=KEY_BS; goto found;} + if(code==10 || code==13){ + if(getch2_len>1){ + int c=getch2_buf[1]; + if(c==10 || c==13) if(c!=code) len=2; + } + code=KEY_ENTER; + goto found; + } + } else if(getch2_len>1){ + int c=getch2_buf[1]; + if(c==27){ code=KEY_ESC; len=2; goto found;} + if(c>='0' && c<='9'){ code=c-'0'+KEY_F; len=2; goto found;} + if(getch2_len>=4 && c=='[' && getch2_buf[2]=='['){ + int c=getch2_buf[3]; + if(c>='A' && c<'A'+12){ code=KEY_F+1+c-'A';len=4;goto found;} + } + if(c=='[' || c=='O') if(getch2_len>=3){ + int c=getch2_buf[2]; + static short int ctable[]={ KEY_UP,KEY_DOWN,KEY_RIGHT,KEY_LEFT,0, + KEY_END,KEY_PGDWN,KEY_HOME,KEY_PGUP,0,0,KEY_INS,0,0,0, + KEY_F+1,KEY_F+2,KEY_F+3,KEY_F+4}; + if(c>='A' && c<='S') + if(ctable[c-'A']){ code=ctable[c-'A']; len=3; goto found;} + } + if(getch2_len>=4 && c=='[' && getch2_buf[3]=='~'){ + int c=getch2_buf[2]; + int ctable[8]={KEY_HOME,KEY_INS,KEY_DEL,KEY_END,KEY_PGUP,KEY_PGDWN,KEY_HOME,KEY_END}; + if(c>='1' && c<='8'){ code=ctable[c-'1']; len=4; goto found;} + } + if(getch2_len>=5 && c=='[' && getch2_buf[4]=='~'){ + int i=getch2_buf[2]-'0'; + int j=getch2_buf[3]-'0'; + if(i>=0 && i<=9 && j>=0 && j<=9){ + static short int ftable[20]={ + 11,12,13,14,15, 17,18,19,20,21, + 23,24,25,26,28, 29,31,32,33,34 }; + int a=i*10+j; + for(i=0;i<20;i++) if(ftable[i]==a){ code=KEY_F+1+i;len=5;goto found;} + } + } + } +found: + if((getch2_len-=len)>0){ + int i; + for(i=0;i<getch2_len;i++) getch2_buf[i]=getch2_buf[len+i]; + } + return code; +} + +static int getch2_status=0; + +void getch2_enable(){ +#ifdef HAVE_TERMIOS +struct termios tio_new; +#if defined(__NetBSD__) || defined(__svr4__) || defined(__CYGWIN__) || defined(__OS2__) || defined(__GNU__) + tcgetattr(0,&tio_orig); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) + ioctl(0,TIOCGETA,&tio_orig); +#else + ioctl(0,TCGETS,&tio_orig); +#endif + tio_new=tio_orig; + tio_new.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ + tio_new.c_cc[VMIN] = 1; + tio_new.c_cc[VTIME] = 0; +#if defined(__NetBSD__) || defined(__svr4__) || defined(__CYGWIN__) || defined(__OS2__) || defined(__GNU__) + tcsetattr(0,TCSANOW,&tio_new); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) + ioctl(0,TIOCSETA,&tio_new); +#else + ioctl(0,TCSETS,&tio_new); +#endif +#endif + getch2_status=1; +} + +void getch2_disable(){ + if(!getch2_status) return; // already disabled / never enabled +#ifdef HAVE_TERMIOS +#if defined(__NetBSD__) || defined(__svr4__) || defined(__CYGWIN__) || defined(__OS2__) || defined(__GNU__) + tcsetattr(0,TCSANOW,&tio_orig); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) + ioctl(0,TIOCSETA,&tio_orig); +#else + ioctl(0,TCSETS,&tio_orig); +#endif +#endif + getch2_status=0; +} + diff --git a/osdep/getch2.h b/osdep/getch2.h new file mode 100644 index 0000000000..016de5ae9e --- /dev/null +++ b/osdep/getch2.h @@ -0,0 +1,20 @@ +/* GyS-TermIO v2.0 (for GySmail v3) (C) 1999 A'rpi/ESP-team */ +/* a very small replacement of ncurses library */ + +/* Screen size. Initialized by load_termcap() and get_screen_size() */ +extern int screen_width; +extern int screen_height; + +/* Get screen-size using IOCTL call. */ +extern void get_screen_size(); + +/* Load key definitions from the TERMCAP database. 'termtype' can be NULL */ +extern int load_termcap(char *termtype); + +/* Enable and disable STDIN line-buffering */ +extern void getch2_enable(); +extern void getch2_disable(); + +/* Read a character or a special key code (see keycodes.h) */ +extern int getch2(int halfdelay_time); + diff --git a/osdep/keycodes.h b/osdep/keycodes.h new file mode 100644 index 0000000000..e0b963535c --- /dev/null +++ b/osdep/keycodes.h @@ -0,0 +1,36 @@ +/* KEY code definitions for GyS-TermIO v2.0 (C) 1999 A'rpi/ESP-team */ + +#define KEY_ENTER 13 +#define KEY_TAB 9 + +#define KEY_BASE 0x100 + +/* Function keys */ +#define KEY_F (KEY_BASE+64) + +/* Control keys */ +#define KEY_CTRL (KEY_BASE) +#define KEY_BACKSPACE (KEY_CTRL+0) +#define KEY_DELETE (KEY_CTRL+1) +#define KEY_INSERT (KEY_CTRL+2) +#define KEY_HOME (KEY_CTRL+3) +#define KEY_END (KEY_CTRL+4) +#define KEY_PAGE_UP (KEY_CTRL+5) +#define KEY_PAGE_DOWN (KEY_CTRL+6) +#define KEY_ESC (KEY_CTRL+7) + +/* Control keys short name */ +#define KEY_BS KEY_BACKSPACE +#define KEY_DEL KEY_DELETE +#define KEY_INS KEY_INSERT +#define KEY_PGUP KEY_PAGE_UP +#define KEY_PGDOWN KEY_PAGE_DOWN +#define KEY_PGDWN KEY_PAGE_DOWN + +/* Cursor movement */ +#define KEY_CRSR (KEY_BASE+16) +#define KEY_RIGHT (KEY_CRSR+0) +#define KEY_LEFT (KEY_CRSR+1) +#define KEY_DOWN (KEY_CRSR+2) +#define KEY_UP (KEY_CRSR+3) + diff --git a/osdep/lrmi.c b/osdep/lrmi.c new file mode 100644 index 0000000000..ce77a6767a --- /dev/null +++ b/osdep/lrmi.c @@ -0,0 +1,912 @@ +/* +Linux Real Mode Interface - A library of DPMI-like functions for Linux. + +Copyright (C) 1998 by Josh Vanderhoof + +You are free to distribute and modify this file, as long as you +do not remove this copyright notice and clearly label modified +versions as being modified. + +This software has NO WARRANTY. Use it at your own risk. +Original location: http://cvs.debian.org/lrmi/ +*/ + +#include <stdio.h> +#include <string.h> +#include <sys/io.h> +#include <asm/vm86.h> + +#ifdef USE_LIBC_VM86 +#include <sys/vm86.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> + +#include "lrmi.h" + +#define REAL_MEM_BASE ((void *)0x10000) +#define REAL_MEM_SIZE 0x10000 +#define REAL_MEM_BLOCKS 0x100 + +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 }; + +static int +real_mem_init(void) + { + void *m; + int fd_zero; + + if (mem_info.ready) + return 1; + + fd_zero = open("/dev/zero", O_RDONLY); + if (fd_zero == -1) + { + perror("open /dev/zero"); + return 0; + } + + m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd_zero, 0); + + if (m == (void *)-1) + { + perror("mmap /dev/zero"); + close(fd_zero); + return 0; + } + + 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)); + } + +void * +LRMI_alloc_real(int size) + { + int i; + char *r = (char *)REAL_MEM_BASE; + + 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; + + return (void *)r; + } + + r += mem_info.blocks[i].size; + } + + return NULL; + } + + +void +LRMI_free_real(void *m) + { + int i; + char *r = (char *)REAL_MEM_BASE; + + if (!mem_info.ready) + return; + + i = 0; + while (m != (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 DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK) +#define DEFAULT_STACK_SIZE 0x1000 +#define RETURN_TO_32_INT 255 + +static struct + { + int ready; + unsigned short ret_seg, ret_off; + unsigned short stack_seg, stack_off; + struct vm86_struct vm; + } context = { 0 }; + + +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; + } + + +int +LRMI_init(void) + { + void *m; + int fd_mem; + + if (context.ready) + return 1; + + if (!real_mem_init()) + return 0; + + /* + Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502) + and the ROM (0xa0000 - 0x100000) + */ + fd_mem = open("/dev/mem", O_RDWR); + + if (fd_mem == -1) + { + perror("open /dev/mem"); + return 0; + } + + m = mmap((void *)0, 0x502, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd_mem, 0); + + if (m == (void *)-1) + { + perror("mmap /dev/mem"); + return 0; + } + + m = mmap((void *)0xa0000, 0x100000 - 0xa0000, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000); + + if (m == (void *)-1) + { + perror("mmap /dev/mem"); + return 0; + } + + + /* + Allocate a stack + */ + m = LRMI_alloc_real(DEFAULT_STACK_SIZE); + + context.stack_seg = (unsigned int)m >> 4; + context.stack_off = DEFAULT_STACK_SIZE; + + /* + Allocate the return to 32 bit routine + */ + m = LRMI_alloc_real(2); + + context.ret_seg = (unsigned int)m >> 4; + context.ret_off = (unsigned int)m & 0xf; + + ((unsigned char *)m)[0] = 0xcd; /* int opcode */ + ((unsigned char *)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; + + return 1; + } + + +static void +set_regs(struct LRMI_regs *r) + { + context.vm.regs.edi = r->edi; + context.vm.regs.esi = r->esi; + context.vm.regs.ebp = r->ebp; + context.vm.regs.ebx = r->ebx; + context.vm.regs.edx = r->edx; + context.vm.regs.ecx = r->ecx; + context.vm.regs.eax = r->eax; + context.vm.regs.eflags = DEFAULT_VM86_FLAGS; + context.vm.regs.es = r->es; + context.vm.regs.ds = r->ds; + context.vm.regs.fs = r->fs; + context.vm.regs.gs = r->gs; + } + + +static void +get_regs(struct LRMI_regs *r) + { + r->edi = context.vm.regs.edi; + r->esi = context.vm.regs.esi; + r->ebp = context.vm.regs.ebp; + r->ebx = context.vm.regs.ebx; + r->edx = context.vm.regs.edx; + r->ecx = context.vm.regs.ecx; + r->eax = context.vm.regs.eax; + r->flags = context.vm.regs.eflags; + r->es = context.vm.regs.es; + r->ds = context.vm.regs.ds; + r->fs = context.vm.regs.fs; + r->gs = context.vm.regs.gs; + } + +#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 void +em_inbl(unsigned char literal) + { + context.vm.regs.eax = inb(literal) & 0xff; + } + +static void +em_inb(void) + { + asm volatile ("inb (%w1), %b0" + : "=a" (context.vm.regs.eax) + : "d" (context.vm.regs.edx), "0" (context.vm.regs.eax)); + } + +static void +em_inw(void) + { + asm volatile ("inw (%w1), %w0" + : "=a" (context.vm.regs.eax) + : "d" (context.vm.regs.edx), "0" (context.vm.regs.eax)); + } + +static void +em_inl(void) + { + asm volatile ("inl (%w1), %0" + : "=a" (context.vm.regs.eax) + : "d" (context.vm.regs.edx)); + } + +static void +em_outbl(unsigned char literal) + { + outb(context.vm.regs.eax & 0xff, literal); + } + +static void +em_outb(void) + { + asm volatile ("outb %b0, (%w1)" + : : "a" (context.vm.regs.eax), + "d" (context.vm.regs.edx)); + } + +static void +em_outw(void) + { + asm volatile ("outw %w0, (%w1)" + : : "a" (context.vm.regs.eax), + "d" (context.vm.regs.edx)); + } + +static void +em_outl(void) + { + asm volatile ("outl %0, (%w1)" + : : "a" (context.vm.regs.eax), + "d" (context.vm.regs.edx)); + } + +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) + { + 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] == 0xe4) + { + em_inbl(insn[i + 1]); + i += 2; + break; + } + else if (insn[i] == 0xe6) + { + em_outbl(insn[i + 1]); + i += 2; + break; + } + else if (insn[i] == 0xec) + { + em_inb(); + i++; + break; + } + else if (insn[i] == 0xed) + { + if (prefix.size) + em_inl(); + else + em_inw(); + i++; + break; + } + else if (insn[i] == 0xee) + { + em_outb(); + i++; + break; + } + else if (insn[i] == 0xef) + { + if (prefix.size) + em_outl(); + else + em_outw(); + + i++; + break; + } + else + return 0; + } + + context.vm.regs.eip += i; + return 1; + } + + +/* + I don't know how to make sure I get the right vm86() from libc. + The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc) + which should be declared as "int vm86(struct vm86_struct *);" in + <sys/vm86.h>. + + This just does syscall 113 with inline asm, which should work + for both libc's (I hope). +*/ +#if !defined(USE_LIBC_VM86) +static int +lrmi_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 |