summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTormod Volden <debian.tormod@gmail.com>2011-11-19 14:42:10 +0100
committerTormod Volden <debian.tormod@gmail.com>2011-11-19 15:19:17 +0100
commit1592c09bc3fbb87dcb8e286a0201006456878533 (patch)
treeb2d7f9af5f4b1a45d7849e4be876ff65897f0569
parent5baec03151d4b6c17f0f4e12c575187c6f9bd7c9 (diff)
Update lrmi.c and lrmi.h from upstream CVS
Main changes: - support for OpenBSD and FreeBSD - reworded license statement (MIT style) Signed-off-by: Tormod Volden <debian.tormod@gmail.com>
-rw-r--r--lrmi.c1002
-rw-r--r--lrmi.h39
2 files changed, 622 insertions, 419 deletions
diff --git a/lrmi.c b/lrmi.c
index c2d01ec..f5bb88e 100644
--- a/lrmi.c
+++ b/lrmi.c
@@ -3,21 +3,56 @@ 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.
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL JOSH VANDERHOOF BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
*/
+#if defined(__i386__) && (defined(__linux__) || defined(__NetBSD__) \
+ || defined(__FreeBSD__) || defined(__OpenBSD__))
+
#include <stdio.h>
#include <string.h>
+
+#if defined(__linux__)
+
#include <asm/vm86.h>
+#include <signal.h>
#ifdef USE_LIBC_VM86
#include <sys/vm86.h>
#endif
+#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+
+#include <sys/param.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <machine/psl.h>
+#include <machine/vm86.h>
+#include <machine/sysarch.h>
+
+#endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
+
+#if defined(__FreeBSD__)
+#include <sys/ucontext.h>
+#endif
+
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
@@ -26,58 +61,79 @@ This software has NO WARRANTY. Use it at your own risk.
#include "lrmi.h"
-/* flag names changed in 2.6.26 kernel */
-#ifndef TF_MASK
-#define TF_MASK X86_EFLAGS_TF
-#define IF_MASK X86_EFLAGS_IF
-#define IOPL_MASK X86_EFLAGS_IOPL
-#define VIF_MASK X86_EFLAGS_VIF
-#define VIP_MASK X86_EFLAGS_VIP
-#endif
-
#define REAL_MEM_BASE ((void *)0x10000)
-#define REAL_MEM_SIZE 0x10000
+#define REAL_MEM_SIZE 0x40000
#define REAL_MEM_BLOCKS 0x100
-struct mem_block
- {
+struct mem_block {
unsigned int size : 20;
unsigned int free : 1;
- };
+};
-static struct
- {
+static struct {
int ready;
int count;
struct mem_block blocks[REAL_MEM_BLOCKS];
- } mem_info = { 0 };
+} mem_info = { 0 };
static int
-real_mem_init(void)
- {
+read_file(char *name, void *p, size_t n)
+{
+ int fd;
+
+ fd = open(name, O_RDONLY);
+
+ if (fd == -1) {
+ perror("open");
+ return 0;
+ }
+
+ if (read(fd, p, n) != n) {
+ perror("read");
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ return 1;
+}
+
+static int
+map_file(void *start, size_t length, int prot, int flags, char *name, long offset)
+{
void *m;
- int fd_zero;
+ int fd;
- if (mem_info.ready)
- return 1;
+ fd = open(name, (flags & MAP_SHARED) ? O_RDWR : O_RDONLY);
- fd_zero = open("/dev/zero", O_RDONLY);
- if (fd_zero == -1)
- {
- perror("open /dev/zero");
+ if (fd == -1) {
+ perror("open");
return 0;
- }
+ }
- m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, fd_zero, 0);
+ m = mmap(start, length, prot, flags, fd, offset);
- if (m == (void *)-1)
- {
- perror("mmap /dev/zero");
- close(fd_zero);
+ if (m == (void *)-1) {
+ perror("mmap");
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+ return 1;
+}
+
+static int
+real_mem_init(void)
+{
+ if (mem_info.ready)
+ return 1;
+
+ if (!map_file((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, "/dev/zero", 0))
return 0;
- }
mem_info.ready = 1;
mem_info.count = 1;
@@ -85,34 +141,43 @@ real_mem_init(void)
mem_info.blocks[0].free = 1;
return 1;
+}
+
+static void
+real_mem_deinit(void)
+{
+ if (mem_info.ready) {
+ munmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE);
+ mem_info.ready = 0;
}
+}
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;
@@ -124,10 +189,8 @@ LRMI_alloc_real(int size)
size = (size + 15) & ~15;
- for (i = 0; i < mem_info.count; i++)
- {
- if (mem_info.blocks[i].free && size < mem_info.blocks[i].size)
- {
+ 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;
@@ -135,18 +198,18 @@ LRMI_alloc_real(int size)
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;
@@ -154,80 +217,112 @@ LRMI_free_real(void *m)
return;
i = 0;
- while (m != (void *)r)
- {
+ 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)
- {
+ 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)
- {
+ if (i - 1 >= 0 && mem_info.blocks[i - 1].free) {
mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
delete_block(i);
- }
}
+}
+#if defined(__linux__)
+#ifndef TF_MASK
+#define TF_MASK X86_EFLAGS_TF
+#define IF_MASK X86_EFLAGS_IF
+#define IOPL_MASK X86_EFLAGS_IOPL
+#define VIF_MASK X86_EFLAGS_VIF
+#define VIP_MASK X86_EFLAGS_VIP
+#endif
#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
+#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#define DEFAULT_VM86_FLAGS (PSL_I | PSL_IOPL)
+#define TF_MASK PSL_T
+#define VIF_MASK PSL_VIF
+#endif
#define DEFAULT_STACK_SIZE 0x1000
#define RETURN_TO_32_INT 255
-static struct
- {
+#if defined(__linux__)
+#define CONTEXT_REGS context.vm.regs
+#define REG(x) x
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#define CONTEXT_REGS context.vm.substr.regs
+#define REG(x) vmsc.sc_ ## x
+#elif defined(__FreeBSD__)
+#define CONTEXT_REGS context.vm.uc
+#define REG(x) uc_mcontext.mc_ ## x
+#endif
+
+static struct {
int ready;
unsigned short ret_seg, ret_off;
unsigned short stack_seg, stack_off;
+#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
struct vm86_struct vm;
- } context = { 0 };
+#elif defined(__FreeBSD__)
+ struct {
+ struct vm86_init_args init;
+ ucontext_t uc;
+ } vm;
+#endif
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ int success;
+ jmp_buf env;
+ void *old_sighandler;
+ int vret;
+#endif
+} 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;
- }
+{
+ CONTEXT_REGS.REG(esp) -= 2;
+ *(unsigned short *)(((unsigned int)CONTEXT_REGS.REG(ss) << 4) +
+ CONTEXT_REGS.REG(esp)) = i;
+}
int
LRMI_init(void)
- {
+{
void *m;
- int fd_mem;
if (context.ready)
return 1;
@@ -239,34 +334,26 @@ LRMI_init(void)
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,
+ if (!map_file((void *)0, 0x502,
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, fd_mem, 0);
+ MAP_FIXED | MAP_PRIVATE, "/dev/zero", 0)) {
+ real_mem_deinit();
+ return 0;
+ }
- if (m == (void *)-1)
- {
- perror("mmap /dev/mem");
+ if (!read_file("/dev/mem", (void *)0, 0x502)) {
+ munmap((void *)0, 0x502);
+ real_mem_deinit();
return 0;
- }
+ }
- m = mmap((void *)0xa0000, 0x100000 - 0xa0000,
+ if (!map_file((void *)0xa0000, 0x100000 - 0xa0000,
PROT_READ | PROT_WRITE,
- MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000);
-
- if (m == (void *)-1)
- {
- perror("mmap /dev/mem");
+ MAP_FIXED | MAP_SHARED, "/dev/mem", 0xa0000)) {
+ munmap((void *)0, 0x502);
+ real_mem_deinit();
return 0;
- }
-
+ }
/*
Allocate a stack
@@ -292,63 +379,73 @@ LRMI_init(void)
/*
Enable kernel emulation of all ints except RETURN_TO_32_INT
*/
+#if defined(__linux__)
memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+ set_bit(RETURN_TO_32_INT, &context.vm.int_byuser);
+#elif defined(__FreeBSD__)
+ set_bit(RETURN_TO_32_INT, &context.vm.init.int_map);
+#endif
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;
- }
+{
+ CONTEXT_REGS.REG(edi) = r->edi;
+ CONTEXT_REGS.REG(esi) = r->esi;
+ CONTEXT_REGS.REG(ebp) = r->ebp;
+ CONTEXT_REGS.REG(ebx) = r->ebx;
+ CONTEXT_REGS.REG(edx) = r->edx;
+ CONTEXT_REGS.REG(ecx) = r->ecx;
+ CONTEXT_REGS.REG(eax) = r->eax;
+ CONTEXT_REGS.REG(eflags) = DEFAULT_VM86_FLAGS;
+ CONTEXT_REGS.REG(es) = r->es;
+ CONTEXT_REGS.REG(ds) = r->ds;
+ CONTEXT_REGS.REG(fs) = r->fs;
+ CONTEXT_REGS.REG(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;
- }
+{
+ r->edi = CONTEXT_REGS.REG(edi);
+ r->esi = CONTEXT_REGS.REG(esi);
+ r->ebp = CONTEXT_REGS.REG(ebp);
+ r->ebx = CONTEXT_REGS.REG(ebx);
+ r->edx = CONTEXT_REGS.REG(edx);
+ r->ecx = CONTEXT_REGS.REG(ecx);
+ r->eax = CONTEXT_REGS.REG(eax);
+ r->flags = CONTEXT_REGS.REG(eflags);
+ r->es = CONTEXT_REGS.REG(es);
+ r->ds = CONTEXT_REGS.REG(ds);
+ r->fs = CONTEXT_REGS.REG(fs);
+ r->gs = CONTEXT_REGS.REG(gs);
+}
#define DIRECTION_FLAG (1 << 10)
+enum {
+ CSEG = 0x2e, SSEG = 0x36, DSEG = 0x3e,
+ ESEG = 0x26, FSEG = 0x64, GSEG = 0x65,
+};
+
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;
+ edx = CONTEXT_REGS.REG(edx) & 0xffff;
+ edi = CONTEXT_REGS.REG(edi) & 0xffff;
+ edi += (unsigned int)CONTEXT_REGS.REG(es) << 4;
- if (context.vm.regs.eflags & DIRECTION_FLAG)
- {
+ if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
if (size == 4)
asm volatile ("std; insl; cld"
: "=D" (edi) : "d" (edx), "0" (edi));
@@ -358,9 +455,7 @@ em_ins(int size)
else
asm volatile ("std; insb; cld"
: "=D" (edi) : "d" (edx), "0" (edi));
- }
- else
- {
+ } else {
if (size == 4)
asm volatile ("cld; insl"
: "=D" (edi) : "d" (edx), "0" (edi));
@@ -370,75 +465,48 @@ em_ins(int size)
else
asm volatile ("cld; insb"
: "=D" (edi) : "d" (edx), "0" (edi));
- }
+ }
- edi -= (unsigned int)context.vm.regs.ds << 4;
+ edi -= (unsigned int)CONTEXT_REGS.REG(es) << 4;
- context.vm.regs.edi &= 0xffff0000;
- context.vm.regs.edi |= edi & 0xffff;
- }
+ CONTEXT_REGS.REG(edi) &= 0xffff0000;
+ CONTEXT_REGS.REG(edi) |= edi & 0xffff;
+}
static void
em_rep_ins(int size)
- {
- unsigned int ecx, edx, edi;
+{
+ unsigned int cx;
- 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;
+ cx = CONTEXT_REGS.REG(ecx) & 0xffff;
- 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));
- }
+ while (cx--)
+ em_ins(size);
- 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;
- }
+ CONTEXT_REGS.REG(ecx) &= 0xffff0000;
+}
static void
-em_outs(int size)
- {
- unsigned int edx, esi;
+em_outs(int size, int seg)
+{
+ unsigned int edx, esi, base;
+
+ edx = CONTEXT_REGS.REG(edx) & 0xffff;
+ esi = CONTEXT_REGS.REG(esi) & 0xffff;
+
+ switch (seg) {
+ case CSEG: base = CONTEXT_REGS.REG(cs); break;
+ case SSEG: base = CONTEXT_REGS.REG(ss); break;
+ case ESEG: base = CONTEXT_REGS.REG(es); break;
+ case FSEG: base = CONTEXT_REGS.REG(fs); break;
+ case GSEG: base = CONTEXT_REGS.REG(gs); break;
+ default:
+ case DSEG: base = CONTEXT_REGS.REG(ds); break;
+ }
- edx = context.vm.regs.edx & 0xffff;
- esi = context.vm.regs.esi & 0xffff;
- esi += (unsigned int)context.vm.regs.ds << 4;
+ esi += base << 4;
- if (context.vm.regs.eflags & DIRECTION_FLAG)
- {
+ if (CONTEXT_REGS.REG(eflags) & DIRECTION_FLAG) {
if (size == 4)
asm volatile ("std; outsl; cld"
: "=S" (esi) : "d" (edx), "0" (esi));
@@ -448,9 +516,7 @@ em_outs(int size)
else
asm volatile ("std; outsb; cld"
: "=S" (esi) : "d" (edx), "0" (esi));
- }
- else
- {
+ } else {
if (size == 4)
asm volatile ("cld; outsl"
: "=S" (esi) : "d" (edx), "0" (esi));
@@ -460,226 +526,187 @@ em_outs(int size)
else
asm volatile ("cld; outsb"
: "=S" (esi) : "d" (edx), "0" (esi));
- }
+ }
- esi -= (unsigned int)context.vm.regs.ds << 4;
+ esi -= base << 4;
- context.vm.regs.esi &= 0xffff0000;
- context.vm.regs.esi |= esi & 0xffff;
- }
+ CONTEXT_REGS.REG(esi) &= 0xffff0000;
+ CONTEXT_REGS.REG(esi) |= esi & 0xffff;
+}
static void
-em_rep_outs(int size)
- {
- unsigned int ecx, edx, esi;
+em_rep_outs(int size, int seg)
+{
+ unsigned int cx;
- 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;
+ cx = CONTEXT_REGS.REG(ecx) & 0xffff;
- 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;
+ while (cx--)
+ em_outs(size, seg);
- context.vm.regs.esi &= 0xffff0000;
- context.vm.regs.esi |= esi & 0xffff;
+ CONTEXT_REGS.REG(ecx) &= 0xffff0000;
+}
- context.vm.regs.ecx &= 0xffff0000;
- context.vm.regs.ecx |= ecx & 0xffff;
- }
+static void
+em_inbl(unsigned char literal)
+{
+ asm volatile ("inb %w1, %b0"
+ : "=a" (CONTEXT_REGS.REG(eax))
+ : "d" (literal), "0" (CONTEXT_REGS.REG(eax)));
+}
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));
- }
+{
+ asm volatile ("inb %w1, %b0"
+ : "=a" (CONTEXT_REGS.REG(eax))
+ : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(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));
- }
+{
+ asm volatile ("inw %w1, %w0"
+ : "=a" (CONTEXT_REGS.REG(eax))
+ : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));
+}
static void
em_inl(void)
- {
- asm volatile ("inl (%w1), %0"
- : "=a" (context.vm.regs.eax)
- : "d" (context.vm.regs.edx));
- }
+{
+ asm volatile ("inl %w1, %0"
+ : "=a" (CONTEXT_REGS.REG(eax))
+ : "d" (CONTEXT_REGS.REG(edx)));
+}
+
+static void
+em_outbl(unsigned char literal)
+{
+ asm volatile ("outb %b0, %w1"
+ : : "a" (CONTEXT_REGS.REG(eax)),
+ "d" (literal));
+}
static void
em_outb(void)
- {
- asm volatile ("outb %b0, (%w1)"
- : : "a" (context.vm.regs.eax),
- "d" (context.vm.regs.edx));
- }
+{
+ asm volatile ("outb %b0, %w1"
+ : : "a" (CONTEXT_REGS.REG(eax)),
+ "d" (CONTEXT_REGS.REG(edx)));
+}
static void
em_outw(void)
- {
- asm volatile ("outw %w0, (%w1)"
- : : "a" (context.vm.regs.eax),
- "d" (context.vm.regs.edx));
- }
+{
+ asm volatile ("outw %w0, %w1"
+ : : "a" (CONTEXT_REGS.REG(eax)),
+ "d" (CONTEXT_REGS.REG(edx)));
+}
static void
em_outl(void)
- {
- asm volatile ("outl %0, (%w1)"
- : : "a" (context.vm.regs.eax),
- "d" (context.vm.regs.edx));
- }
+{
+ asm volatile ("outl %0, %w1"
+ : : "a" (CONTEXT_REGS.REG(eax)),
+ "d" (CONTEXT_REGS.REG(edx)));
+}
static int
emulate(void)
- {
+{
unsigned char *insn;
- struct
- {
+ struct {
+ unsigned char seg;
unsigned int size : 1;
unsigned int rep : 1;
- } prefix = { 0, 0 };
+ } prefix = { DSEG, 0, 0 };
int i = 0;
- insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4);
- insn += context.vm.regs.eip;
+ insn = (unsigned char *)((unsigned int)CONTEXT_REGS.REG(cs) << 4);
+ insn += CONTEXT_REGS.REG(eip);
- while (1)
- {
- if (insn[i] == 0x66)
- {
+ while (1) {
+ if (insn[i] == 0x66) {
prefix.size = 1 - prefix.size;
i++;
- }
- else if (insn[i] == 0xf3)
- {
+ } 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)
- {
+ } else if (insn[i] == CSEG || insn[i] == SSEG
+ || insn[i] == DSEG || insn[i] == ESEG
+ || insn[i] == FSEG || insn[i] == GSEG) {
+ prefix.seg = insn[i];
+ i++;
+ } else if (insn[i] == 0xf0 || insn[i] == 0xf2
+ || insn[i] == 0x67) {
/* these prefixes are just ignored */
i++;
- }
- else if (insn[i] == 0x6c)
- {
+ } 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)
- {
+ } else if (insn[i] == 0x6d) {
+ if (prefix.rep) {
if (prefix.size)
em_rep_ins(4);
else
em_rep_ins(2);
- }
- else
- {
+ } else {
if (prefix.size)
em_ins(4);
else
em_ins(2);
- }
+ }
i++;
break;
- }
- else if (insn[i] == 0x6e)
- {
+ } else if (insn[i] == 0x6e) {
if (prefix.rep)
- em_rep_outs(1);
+ em_rep_outs(1, prefix.seg);
else
- em_outs(1);
+ em_outs(1, prefix.seg);
i++;
break;
- }
- else if (insn[i] == 0x6f)
- {
- if (prefix.rep)
- {
+ } else if (insn[i] == 0x6f) {
+ if (prefix.rep) {
if (prefix.size)
- em_rep_outs(4);
+ em_rep_outs(4, prefix.seg);
else
- em_rep_outs(2);
- }
- else
- {
+ em_rep_outs(2, prefix.seg);
+ } else {
if (prefix.size)
- em_outs(4);
+ em_outs(4, prefix.seg);
else
- em_outs(2);
- }
+ em_outs(2, prefix.seg);
+ }
i++;
break;
- }
- else if (insn[i] == 0xec)
- {
+ } else if (insn[i] == 0xe4) {
+ em_inbl(insn[i + 1]);
+ i += 2;
+ break;
+ } else if (insn[i] == 0xec) {
em_inb();
i++;
break;
- }
- else if (insn[i] == 0xed)
- {
+ } else if (insn[i] == 0xed) {
if (prefix.size)
em_inl();
else
em_inw();
i++;
break;
- }
- else if (insn[i] == 0xee)
- {
+ } else if (insn[i] == 0xe6) {
+ em_outbl(insn[i + 1]);
+ i += 2;
+ break;
+ } else if (insn[i] == 0xee) {
em_outb();
i++;
break;
- }
- else if (insn[i] == 0xef)
- {
+ } else if (insn[i] == 0xef) {
if (prefix.size)
em_outl();
else
@@ -687,16 +714,16 @@ emulate(void)
i++;
break;
- }
- else
+ } else
return 0;
- }
+ }
- context.vm.regs.eip += i;
+ CONTEXT_REGS.REG(eip) += i;
return 1;
- }
+}
+#if defined(__linux__)
/*
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)
@@ -709,7 +736,7 @@ emulate(void)
#if !defined(USE_LIBC_VM86)
static int
lrmi_vm86(struct vm86_struct *vm)
- {
+{
int r;
#ifdef __PIC__
asm volatile (
@@ -726,110 +753,262 @@ lrmi_vm86(struct vm86_struct *vm)
: "0" (113), "b" (vm));
#endif
return r;
- }
+}
#else
#define lrmi_vm86 vm86
#endif
+#endif /* __linux__ */
static void
debug_info(int vret)
- {
+{
+#ifdef LRMI_DEBUG
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);
+ fprintf(stderr, "eax = 0x%08x\n", CONTEXT_REGS.REG(eax));
+ fprintf(stderr, "ebx = 0x%08x\n", CONTEXT_REGS.REG(ebx));
+ fprintf(stderr, "ecx = 0x%08x\n", CONTEXT_REGS.REG(ecx));
+ fprintf(stderr, "edx = 0x%08x\n", CONTEXT_REGS.REG(edx));
+ fprintf(stderr, "esi = 0x%08x\n", CONTEXT_REGS.REG(esi));
+ fprintf(stderr, "edi = 0x%08x\n", CONTEXT_REGS.REG(edi));
+ fprintf(stderr, "ebp = 0x%08x\n", CONTEXT_REGS.REG(ebp));
+ fprintf(stderr, "eip = 0x%08x\n", CONTEXT_REGS.REG(eip));
+ fprintf(stderr, "cs = 0x%04x\n", CONTEXT_REGS.REG(cs));
+ fprintf(stderr, "esp = 0x%08x\n", CONTEXT_REGS.REG(esp));
+ fprintf(stderr, "ss = 0x%04x\n", CONTEXT_REGS.REG(ss));
+ fprintf(stderr, "ds = 0x%04x\n", CONTEXT_REGS.REG(ds));
+ fprintf(stderr, "es = 0x%04x\n", CONTEXT_REGS.REG(es));
+ fprintf(stderr, "fs = 0x%04x\n", CONTEXT_REGS.REG(fs));
+ fprintf(stderr, "gs = 0x%04x\n", CONTEXT_REGS.REG(gs));
+ fprintf(stderr, "eflags = 0x%08x\n", CONTEXT_REGS.REG(eflags));
fputs("cs:ip = [ ", stderr);
- p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff));
+ p = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + (CONTEXT_REGS.REG(eip) & 0xffff));
for (i = 0; i < 16; ++i)
fprintf(stderr, "%02x ", (unsigned int)p[i]);
fputs("]\n", stderr);
- }
+#endif
+}
+#if defined(__linux__)
static int
run_vm86(void)
- {
+{
unsigned int vret;
-
- while (1)
- {
+ sigset_t all_sigs, old_sigs;
+ unsigned long old_gs, old_fs;
+
+ while (1) {
+ // FIXME: may apply this to BSD equivalents?
+ sigfillset(&all_sigs);
+ sigprocmask(SIG_SETMASK, &all_sigs, &old_sigs);
+ asm volatile ("mov %%gs, %0" : "=rm" (old_gs));
+ asm volatile ("mov %%fs, %0" : "=rm" (old_fs));
vret = lrmi_vm86(&context.vm);
+ asm volatile ("mov %0, %%gs" :: "rm" (old_gs));
+ asm volatile ("mov %0, %%fs" :: "rm" (old_fs));
+ sigprocmask(SIG_SETMASK, &old_sigs, NULL);
- if (VM86_TYPE(vret) == VM86_INTx)
- {
+ 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);
+ pushw(CONTEXT_REGS.REG(eflags));
+ pushw(CONTEXT_REGS.REG(cs));
+ pushw(CONTEXT_REGS.REG(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);
+ CONTEXT_REGS.REG(cs) = get_int_seg(v);
+ CONTEXT_REGS.REG(eip) = get_int_off(v);
+ CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
continue;
- }
+ }
if (VM86_TYPE(vret) != VM86_UNKNOWN)
break;
if (!emulate())
break;
- }
+ }
debug_info(vret);
return 0;
+}
+#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+static void
+vm86_callback(int sig, int code, struct sigcontext *sc)
+{
+ /* Sync our context with what the kernel develivered to us. */
+ memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
+
+ switch (VM86_TYPE(code)) {
+ case VM86_INTx:
+ {
+ unsigned int v = VM86_ARG(code);
+
+ if (v == RETURN_TO_32_INT) {
+ context.success = 1;
+ longjmp(context.env, 1);
+ }
+
+ pushw(CONTEXT_REGS.REG(eflags));
+ pushw(CONTEXT_REGS.REG(cs));
+ pushw(CONTEXT_REGS.REG(eip));
+
+ CONTEXT_REGS.REG(cs) = get_int_seg(v);
+ CONTEXT_REGS.REG(eip) = get_int_off(v);
+ CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
+
+ break;
+ }
+
+ case VM86_UNKNOWN:
+ if (emulate() == 0) {
+ context.success = 0;
+ context.vret = code;
+ longjmp(context.env, 1);
+ }
+ break;
+
+ default:
+ context.success = 0;
+ context.vret = code;
+ longjmp(context.env, 1);
+ return;
+ }
+
+ /* ...and sync our context back to the kernel. */
+ memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
+}
+#elif defined(__FreeBSD__)
+static void
+vm86_callback(int sig, int code, struct sigcontext *sc)
+{
+ unsigned char *addr;
+
+ /* Sync our context with what the kernel develivered to us. */
+ memcpy(&CONTEXT_REGS, sc, sizeof(*sc));
+
+ if (code) {
+ /* XXX probably need to call original signal handler here */
+ context.success = 0;
+ context.vret = code;
+ longjmp(context.env, 1);
}
+ addr = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) +
+ CONTEXT_REGS.REG(eip));
+
+ if (addr[0] == 0xcd) { /* int opcode */
+ if (addr[1] == RETURN_TO_32_INT) {
+ context.success = 1;
+ longjmp(context.env, 1);
+ }
+
+ pushw(CONTEXT_REGS.REG(eflags));
+ pushw(CONTEXT_REGS.REG(cs));
+ pushw(CONTEXT_REGS.REG(eip));
+
+ CONTEXT_REGS.REG(cs) = get_int_seg(addr[1]);
+ CONTEXT_REGS.REG(eip) = get_int_off(addr[1]);
+ CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK);
+ } else {
+ if (emulate() == 0) {
+ context.success = 0;
+ longjmp(context.env, 1);
+ }
+ }
+
+ /* ...and sync our context back to the kernel. */
+ memcpy(sc, &CONTEXT_REGS, sizeof(*sc));
+}
+#endif /* __FreeBSD__ */
+
+static int
+run_vm86(void)
+{
+ if (context.old_sighandler) {
+#ifdef LRMI_DEBUG
+ fprintf(stderr, "run_vm86: callback already installed\n");
+#endif
+ return (0);
+ }
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ context.old_sighandler = signal(SIGURG, (void (*)(int))vm86_callback);
+#elif defined(__FreeBSD__)
+ context.old_sighandler = signal(SIGBUS, (void (*)(int))vm86_callback);
+#endif
+
+ if (context.old_sighandler == (void *)-1) {
+ context.old_sighandler = NULL;
+#ifdef LRMI_DEBUG
+ fprintf(stderr, "run_vm86: cannot install callback\n");
+#endif
+ return (0);
+ }
+
+ if (setjmp(context.env)) {
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ (void) signal(SIGURG, context.old_sighandler);
+#elif defined(__FreeBSD__)
+ (void) signal(SIGBUS, context.old_sighandler);
+#endif
+ context.old_sighandler = NULL;
+
+ if (context.success)
+ return (1);
+ debug_info(context.vret);
+ return (0);
+ }
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ if (i386_vm86(&context.vm) == -1)
+ return (0);
+#elif defined(__FreeBSD__)
+ if (i386_vm86(VM86_INIT, &context.vm.init))
+ return 0;
+
+ CONTEXT_REGS.REG(eflags) |= PSL_VM | PSL_VIF;
+ sigreturn(&context.vm.uc);
+#endif /* __FreeBSD__ */
+
+ /* NOTREACHED */
+ return (0);
+}
+#endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
int
LRMI_call(struct LRMI_regs *r)
- {
+{
unsigned int vret;
- memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
set_regs(r);
- context.vm.regs.cs = r->cs;
- context.vm.regs.eip = r->ip;
+ CONTEXT_REGS.REG(cs) = r->cs;
+ CONTEXT_REGS.REG(eip) = r->ip;
- if (r->ss == 0 && r->sp == 0)
- {
- context.vm.regs.ss = context.stack_seg;
- context.vm.regs.esp = context.stack_off;
- }
- else
- {
- context.vm.regs.ss = r->ss;
- context.vm.regs.esp = r->sp;
- }
+ if (r->ss == 0 && r->sp == 0) {
+ CONTEXT_REGS.REG(ss) = context.stack_seg;
+ CONTEXT_REGS.REG(esp) = context.stack_off;
+ } else {
+ CONTEXT_REGS.REG(ss) = r->ss;
+ CONTEXT_REGS.REG(esp) = r->sp;
+ }
pushw(context.ret_seg);
pushw(context.ret_off);
@@ -839,12 +1018,12 @@ LRMI_call(struct LRMI_regs *r)
get_regs(r);
return vret;
- }
+}
int
LRMI_int(int i, struct LRMI_regs *r)
- {
+{
unsigned int vret;
unsigned int seg, off;
@@ -855,29 +1034,27 @@ LRMI_int(int i, struct LRMI_regs *r)
If the interrupt is in regular memory, it's probably
still pointing at a dos TSR (which is now gone).
*/
- if (seg < 0xa000 || (seg << 4) + off >= 0x100000)
- {
+ if (seg < 0xa000 || (seg << 4) + off >= 0x100000) {
+#ifdef LRMI_DEBUG
fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);
+#endif
return 0;
- }
+ }
- memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
set_regs(r);
- context.vm.regs.cs = seg;
- context.vm.regs.eip = off;
+ CONTEXT_REGS.REG(cs) = seg;
+ CONTEXT_REGS.REG(eip) = off;
- if (r->ss == 0 && r->sp == 0)
- {
- context.vm.regs.ss = context.stack_seg;
- context.vm.regs.esp = context.stack_off;
- }
- else
- {
- context.vm.regs.ss = r->ss;
- context.vm.regs.esp = r->sp;
- }
+ if (r->ss == 0 && r->sp == 0) {
+ CONTEXT_REGS.REG(ss) = context.stack_seg;
+ CONTEXT_REGS.REG(esp) = context.stack_off;
+ } else {
+ CONTEXT_REGS.REG(ss) = r->ss;
+ CONTEXT_REGS.REG(esp) = r->sp;
+ }
pushw(DEFAULT_VM86_FLAGS);
pushw(context.ret_seg);
@@ -888,5 +1065,8 @@ LRMI_int(int i, struct LRMI_regs *r)
get_regs(r);
return vret;
- }
+}
+#else /* (__linux__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__) && __i386__ */
+#warning "LRMI is not supported on your system!"
+#endif
diff --git a/lrmi.h b/lrmi.h
index c9c1863..1f7f0ee 100644
--- a/lrmi.h
+++ b/lrmi.h
@@ -3,18 +3,33 @@ 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.
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
-This software has NO WARRANTY. Use it at your own risk.
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL JOSH VANDERHOOF BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LRMI_H
#define LRMI_H
-struct LRMI_regs
- {
+#if defined(__i386__) && (defined(__linux__) || defined(__NetBSD__) \
+ || defined(__FreeBSD__) || defined(__OpenBSD__))
+
+struct LRMI_regs {
unsigned int edi;
unsigned int esi;
unsigned int ebp;
@@ -32,8 +47,7 @@ struct LRMI_regs
unsigned short int cs;
unsigned short int sp;
unsigned short int ss;
- };
-
+};
#ifndef LRMI_PREFIX
#define LRMI_PREFIX LRMI_
@@ -44,6 +58,11 @@ struct LRMI_regs
#define LRMI_MAKENAME(a) LRMI_CONCAT(LRMI_PREFIX, a)
/*
+ Package version (high 16bit = major, low 16bit minor)
+*/
+#define LRMI_version 0x0009 /* 0.9 */
+
+/*
Initialize
returns 1 if sucessful, 0 for failure
*/
@@ -82,4 +101,8 @@ LRMI_alloc_real(int size);
void
LRMI_free_real(void *m);
+#else /* (__linux__ || __NetBSD__ || __FreeBSD__) && __i386__ */
+#warning "LRMI is not supported on your system!"
+#endif
+
#endif