summaryrefslogtreecommitdiff
path: root/src/lrmi/backend-vm86.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lrmi/backend-vm86.c')
-rw-r--r--src/lrmi/backend-vm86.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/lrmi/backend-vm86.c b/src/lrmi/backend-vm86.c
new file mode 100644
index 0000000..29342b1
--- /dev/null
+++ b/src/lrmi/backend-vm86.c
@@ -0,0 +1,219 @@
+/*
+Linux Real Mode Interface - A library of DPMI-like functions for Linux.
+
+Copyright (C) 1998 by Josh Vanderhoof
+
+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 <string.h>
+#include "libx86.h"
+#include "common.h"
+#include "vm86.h"
+
+#if defined(__linux__)
+#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
+#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#define DEFAULT_VM86_FLAGS (PSL_I | PSL_IOPL)
+#endif
+#define DEFAULT_STACK_SIZE 0x1000
+
+extern vm86context context;
+
+static inline void
+set_bit(unsigned int bit, void *array)
+{
+ unsigned char *a = array;
+
+ a[bit / 8] |= (1 << (bit % 8));
+}
+
+int
+LRMI_init(void)
+{
+ void *m;
+
+ if (context.ready)
+ return 1;
+
+ if (!LRMI_common_init())
+ 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
+ */
+#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_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_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);
+}
+
+int
+LRMI_call(struct LRMI_regs *r)
+{
+ unsigned int vret;
+
+ memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
+
+ set_regs(r);
+
+ CONTEXT_REGS.REG(cs) = r->cs;
+ CONTEXT_REGS.REG(eip) = r->ip;
+
+ 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);
+
+ vret = run_vm86();
+
+ get_regs(r);
+
+ return vret;
+}
+
+int
+LRMI_int(int i, struct LRMI_regs *r)
+{
+ unsigned int vret;
+ unsigned int seg, off;
+
+ seg = get_int_seg(i);
+ off = get_int_off(i);
+
+ /*
+ 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) {
+#ifdef LRMI_DEBUG
+ fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);
+#endif
+ return 0;
+ }
+
+ memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS));
+
+ set_regs(r);
+
+ CONTEXT_REGS.REG(cs) = seg;
+ CONTEXT_REGS.REG(eip) = off;
+
+ 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);
+ pushw(context.ret_off);
+
+ vret = run_vm86();
+
+ get_regs(r);
+
+ return vret;
+}
+
+size_t
+LRMI_base_addr(void)
+{
+ return 0;
+}
+
+#else /* (__linux__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__) && __i386__ */
+#warning "LRMI is not supported on your system!"
+#endif