OSDN Git Service

initial import
authorChih-Wei Huang <cwhuang@linux.org.tw>
Mon, 21 Feb 2011 09:44:18 +0000 (17:44 +0800)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Mon, 21 Feb 2011 09:44:18 +0000 (17:44 +0800)
16 files changed:
AUTHORS [new file with mode: 0644]
Android.mk [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
MODULE_LICENSE_GPL [new file with mode: 0644]
README [new file with mode: 0644]
README.android [new file with mode: 0644]
config.h [new file with mode: 0644]
lrmi/COPYRIGHT [new file with mode: 0644]
lrmi/lrmi.c [new file with mode: 0644]
lrmi/lrmi.h [new file with mode: 0644]
lrmi/x86-common.c [new file with mode: 0644]
lrmi/x86-common.h [new file with mode: 0644]
v86.c [new file with mode: 0644]
v86.h [new file with mode: 0644]
v86_common.c [new file with mode: 0644]
v86_lrmi.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..a60cb07
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+v86d (c) 2007, Michal Januszewski <spock@gentoo.org>
+
+LRMI (c) Josh Vanderhoof et al., see libs/lrmi-0.10/README
+x86emu (c) SciTech Software, Inc, see libs/x86emu/LICENSE
diff --git a/Android.mk b/Android.mk
new file mode 100644 (file)
index 0000000..a5121bd
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2011, The Android-x86 Open Source Project
+#
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES :=             \
+       v86.c                   \
+       v86_lrmi.c              \
+       v86_common.c            \
+       lrmi/lrmi.c             \
+       lrmi/x86-common.c
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/lrmi
+
+LOCAL_MODULE := v86d
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
+
+include $(BUILD_EXECUTABLE)
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..c23f77d
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,67 @@
+2008-10-04 * 0.1.9
+
+- Fix a off-by-one error in the VBE string copy function.
+- Fix concurrent build.
+- Don't map memory with PROT_EXEC for x86emu.
+- Remove dynamically generated code from LRMI.
+
+2008-09-21 * 0.1.8
+
+- Fix PaX compatibility (patch by the PaX team).
+- Fix a bug where lrmi would not map the last segment of low RAM
+  (patch by PaX team).
+
+2008-09-14 * 0.1.7
+
+- Map the VRAM and Video ROM/System ROM seperately in lrmi (should fix
+  PaX/NX-related problems).
+- Map 0xe0000-0xfffff instead of 0xf0000-0xfffff.
+
+2008-07-26 * 0.1.6
+
+- Add support for BSWAP and CPUID in x86emu.
+- Add support for SMSW and fix a bug in INS/OUTS
+  (patch by Mark Karpeles <mark@hell.ne.jp>).
+- Properly map the BIOS and Video BIOS memory
+  segments.  Try to find and map the EBDA (x86emu).
+
+2008-07-16 * 0.1.5.2
+
+- Fix compatibility with NX and PaX.
+
+2008-07-15 * 0.1.5.1
+
+- Make LRMI compile with 2.6.26 kernel headers.
+
+2008-05-01 * 0.1.5
+
+- Don't map memory beyond 0x10000 (this fixes the problem with
+  devmem_is_allowed() denying access to /dev/mem in recent kernels).
+
+2008-04-19 * 0.1.4
+
+- Fix error handling in the case of a failed v86 memory allocation.
+
+2007-12-03 * 0.1.3
+
+- Fix the VBE Info Block retrieval from the Video ROM.
+
+2007-11-04 * 0.1.2
+
+- Info display formatting changes in testvbe.
+- Add the '--with-debug' configure option.
+
+2007-10-22 * 0.1.1
+
+- LRMI bugfix: map the IVTBDA as shared memory.
+- Update testvbe to display basic information about the Video BIOS.
+
+2007-09-04 * 0.1
+
+- No changes since 0.1-rc5.
+
+2007-08-07 * 0.1-rc5
+
+- Change the v86 memory access functions so that they no longer require
+  mapping files into the first 1 MB of the address space.
+
diff --git a/MODULE_LICENSE_GPL b/MODULE_LICENSE_GPL
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..178c004
--- /dev/null
+++ b/README
@@ -0,0 +1,71 @@
+v86d -- A x86 Emulation Daemon
+------------------------------
+
+1. Purpose
+----------
+v86d provides a backend for kernel drivers that need to execute
+x86 BIOS code.  The code is executed in a controlled environment
+and the results are passed back to the kernel via the netlink
+interface.
+
+2. Suported architectures
+-------------------------
+This version of v86d supports the following architectures:
+x86, x86-64 (amd64).
+
+3. Configuration
+----------------
+
+3.1. The C library
+------------------
+v86d can be compiled against two different C libraries: glibc
+and klibc, glibc being the default.
+
+Compiling against glibc will result in a dynamically linked
+executable that is not suitable for inclusion in initrds.
+
+Compiling against klibc will result in a relatively small,
+statically linked binary, which can be included in an initrd.
+
+To compile v86d against klibc, run ./configure --with-klibc
+after making sure that a recent (1.4 or newer) version of
+klibc is installed on your system.
+
+3.2. The emulator backend
+-------------------------
+On x86, the code executed by v86d can be run either in a fully
+software-emulated environment (x86emu) or a virtualized
+environment (vm86) supported by the CPU.  On other arches
+or 64-bit systems, the code is always run by x86emu.
+
+To choose the x86emu backend on a x86 system, run ./configure
+--with-x86emu.
+
+4. Installation & Usage
+-----------------------
+To configure, build and install v86d with the default settings,
+run:
+
+ # ./configure --default
+ # make
+ # make install
+
+If the kernel that you're currently running doesn't provide
+uvesafb, you can use the KDIR variable to point make to a
+different kernel tree (e.g. `make KDIR=/usr/src/linux`).
+
+v86d isn't meant to be used in an interactive way. It should
+be started and called by the kernel. If you want to see it in
+action, build and load the uvesafb kernel module.
+
+If you want to include v86d into an initramfs image,
+misc/initramfs provides a minimal config file parsable by
+gen_init_cpio.
+
+5. Licensing
+------------
+v86d is licensed under GPL v2.
+
+-- 
+ Michal Januszewski <spock@gentoo.org>
+
diff --git a/README.android b/README.android
new file mode 100644 (file)
index 0000000..24f951b
--- /dev/null
@@ -0,0 +1,13 @@
+NOTICE about v86d Android port
+
+The v86d Android port contains two parts.
+
+* uvesafb::v86d project http://dev.gentoo.org/~spock/projects/uvesafb/
+  Original repository git://repo.or.cz/v86d.git
+
+  I've stripped unused files in the port.
+
+* lrmi of libx86 project http://www.codon.org.uk/~mjg59/libx86/
+
+-- 
+ Chih-Wei Huang
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..eaa0ad5
--- /dev/null
+++ b/config.h
@@ -0,0 +1,3 @@
+#undef CONFIG_DEBUG
+#undef CONFIG_KLIBC
+#undef CONFIG_X86EMU
diff --git a/lrmi/COPYRIGHT b/lrmi/COPYRIGHT
new file mode 100644 (file)
index 0000000..b8d22f4
--- /dev/null
@@ -0,0 +1,22 @@
+Copyright (C) 1998 by Josh Vanderhoof
+Copyright (C) 2005-2006 by Matthew Garrett
+Copyright (C) 2005-2006 by Jonathan McDowell
+
+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.
diff --git a/lrmi/lrmi.c b/lrmi/lrmi.c
new file mode 100644 (file)
index 0000000..1b1c864
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(__linux__) && defined(__i386__)
+
+#include <asm/vm86.h>
+
+#ifdef USE_LIBC_VM86
+#include <sys/vm86.h>
+#endif
+
+#elif defined(__NetBSD__) || defined(__FreeBSD__)
+
+#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__ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "lrmi.h"
+#include "x86-common.h"
+
+#if defined(__linux__)
+#define DEFAULT_VM86_FLAGS     (IF_MASK | IOPL_MASK)
+#elif defined(__NetBSD__) || defined(__FreeBSD__)
+#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
+
+#if defined(__linux__)
+#define CONTEXT_REGS   context.vm.regs
+#define REG(x)                 x
+#elif defined(__NetBSD__)
+#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__)
+       struct vm86_struct vm;
+#elif defined(__FreeBSD__)
+       struct {
+               struct vm86_init_args init;
+               ucontext_t uc;
+       } vm;
+#endif
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+       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)
+{
+       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;
+
+       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__)
+       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);
+}
+
+#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_REGS.REG(edx) & 0xffff;
+       edi = CONTEXT_REGS.REG(edi) & 0xffff;
+       edi += (unsigned int)CONTEXT_REGS.REG(es) << 4;
+
+       if (CONTEXT_REGS.REG(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_REGS.REG(es) << 4;
+
+       CONTEXT_REGS.REG(edi) &= 0xffff0000;
+       CONTEXT_REGS.REG(edi) |= edi & 0xffff;
+}
+
+static void
+em_rep_ins(int size)
+{
+       unsigned int cx;
+
+       cx = CONTEXT_REGS.REG(ecx) & 0xffff;
+
+       while (cx--)
+               em_ins(size);
+
+       CONTEXT_REGS.REG(ecx) &= 0xffff0000;
+}
+
+static void
+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;
+       }
+
+       esi += base << 4;
+
+       if (CONTEXT_REGS.REG(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 -= base << 4;
+
+       CONTEXT_REGS.REG(esi) &= 0xffff0000;
+       CONTEXT_REGS.REG(esi) |= esi & 0xffff;
+}
+
+static void
+em_rep_outs(int size, int seg)
+{
+       unsigned int cx;
+
+       cx = CONTEXT_REGS.REG(ecx) & 0xffff;
+
+       while (cx--)
+               em_outs(size, seg);
+
+       CONTEXT_REGS.REG(ecx) &= 0xffff0000;
+}
+
+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_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_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_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_REGS.REG(eax)),
+        "d" (CONTEXT_REGS.REG(edx)));
+}
+
+static void
+em_outw(void)
+{
+       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_REGS.REG(eax)),
+        "d" (CONTEXT_REGS.REG(edx)));
+}
+
+static int
+emulate(void)
+{
+       unsigned char *insn;
+       struct {
+               unsigned char seg;
+               unsigned int size : 1;
+               unsigned int rep : 1;
+       } prefix = { DSEG, 0, 0 };
+       int i = 0;
+
+       insn = (unsigned char *)((unsigned int)CONTEXT_REGS.REG(cs) << 4);
+       insn += CONTEXT_REGS.REG(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] == 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) {
+                       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, prefix.seg);
+                       else
+                               em_outs(1, prefix.seg);
+                       i++;
+                       break;
+               } else if (insn[i] == 0x6f) {
+                       if (prefix.rep) {
+                               if (prefix.size)
+                                       em_rep_outs(4, prefix.seg);
+                               else
+                                       em_rep_outs(2, prefix.seg);
+                       } else {
+                               if (prefix.size)
+                                       em_outs(4, prefix.seg);
+                               else
+                                       em_outs(2, prefix.seg);
+                       }
+                       i++;
+                       break;
+               } 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) {
+                       if (prefix.size)
+                               em_inl();
+                       else
+                               em_inw();
+                       i++;
+                       break;
+               } 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) {
+                       if (prefix.size)
+                               em_outl();
+                       else
+                               em_outw();
+
+                       i++;
+                       break;
+               } else
+                       return 0;
+       }
+
+       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)
+ 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
+       asm volatile (
+        "int $0x80"
+        : "=a" (r)
+        : "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%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_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) {
+               vret = lrmi_vm86(&context.vm);
+
+               if (VM86_TYPE(vret) == VM86_INTx) {
+                       unsigned int v = VM86_ARG(vret);
+
+                       if (v == RETURN_TO_32_INT)
+                               return 1;
+
+                       /*              fprintf(stderr, "Calling INT 0x%X (%04X:%04X)\n",
+                                       v,
+                                       get_int_seg(v),
+                                       get_int_off(v));
+                       fprintf(stderr, " EAX is 0x%lX\n",
+                                       CONTEXT_REGS.REG(eax));
+                       */
+                       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);
+
+                       continue;
+               }
+
+               if (VM86_TYPE(vret) != VM86_UNKNOWN)
+                       break;
+
+               if (!emulate())
+                       break;
+       }
+
+       debug_info(vret);
+
+       return 0;
+}
+#elif defined(__NetBSD__) || defined(__FreeBSD__)
+#if defined(__NetBSD__)
+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__)
+       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__)
+               (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__)
+       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__ */
+
+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;
+}
diff --git a/lrmi/lrmi.h b/lrmi/lrmi.h
new file mode 100644 (file)
index 0000000..182864f
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+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.
+*/
+
+#ifndef LRMI_H
+#define LRMI_H
+
+#define LRMI_PREFIX LRMI_
+
+struct LRMI_regs {
+       unsigned int edi;
+       unsigned int esi;
+       unsigned int ebp;
+       unsigned int reserved;
+       unsigned int ebx;
+       unsigned int edx;
+       unsigned int ecx;
+       unsigned int eax;
+       unsigned short int flags;
+       unsigned short int es;
+       unsigned short int ds;
+       unsigned short int fs;
+       unsigned short int gs;
+       unsigned short int ip;
+       unsigned short int cs;
+       unsigned short int sp;
+       unsigned short int ss;
+};
+
+#define LRMI_CONCAT2(a, b)     a ## b
+#define LRMI_CONCAT(a, b)      LRMI_CONCAT2(a, b)
+#define LRMI_MAKENAME(a)       LRMI_CONCAT(LRMI_PREFIX, a)
+
+/*
+ Initialize
+ returns 1 if sucessful, 0 for failure
+*/
+#define LRMI_init LRMI_MAKENAME(init)
+int
+LRMI_init(void);
+
+/*
+ Simulate a 16 bit far call
+ returns 1 if sucessful, 0 for failure
+*/
+#define LRMI_call LRMI_MAKENAME(call)
+int
+LRMI_call(struct LRMI_regs *r);
+
+/*
+ Simulate a 16 bit interrupt
+ returns 1 if sucessful, 0 for failure
+*/
+#define LRMI_int LRMI_MAKENAME(int)
+int
+LRMI_int(int interrupt, struct LRMI_regs *r);
+
+/*
+ Allocate real mode memory
+ The returned block is paragraph (16 byte) aligned
+*/
+#define LRMI_alloc_real LRMI_MAKENAME(alloc_real)
+void *
+LRMI_alloc_real(int size);
+
+/*
+ Free real mode memory
+*/
+#define LRMI_free_real LRMI_MAKENAME(free_real)
+void
+LRMI_free_real(void *m);
+
+/*
+ * Get the base address of the real memory address space block.
+ */
+size_t
+LRMI_base_addr(void);
+
+#endif
diff --git a/lrmi/x86-common.c b/lrmi/x86-common.c
new file mode 100644 (file)
index 0000000..508baa6
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#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 *)0x01000)
+#define REAL_MEM_SIZE  0xa0000
+#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;
+
+static int
+real_mem_init(void)
+{
+       void *m;
+       int fd_zero;
+
+       if (mem_info.ready)
+               return 1;
+
+       fd_zero = open("/dev/zero", O_RDWR);
+       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_SHARED, fd_zero, 0);
+
+       if (m == (void *)-1) {
+               perror("mmap /dev/zero");
+               close(fd_zero);
+               return 0;
+       }
+
+       close(fd_zero);
+
+       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
+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;
+
+       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_STACK_SIZE     0x1000
+
+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);
+}
+
+int LRMI_common_init(void)
+{
+       void *m;
+       int fd_mem;
+
+       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) {
+               real_mem_deinit();
+               perror("open /dev/mem");
+               return 0;
+       }
+
+       m = mmap((void *)0, 0x502,
+        PROT_READ | PROT_WRITE | PROT_EXEC,
+        MAP_FIXED | MAP_SHARED, fd_mem, 0);
+
+       if (m == (void *)-1) {
+               close(fd_mem);
+               real_mem_deinit();
+               perror("mmap /dev/mem");
+               return 0;
+       }
+
+       m = mmap((void *)0xa0000, 0x100000 - 0xa0000,
+        PROT_READ | PROT_WRITE | PROT_EXEC,
+        MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000);
+
+       if (m == (void *)-1) {
+               munmap((void *)0, 0x502);
+               close(fd_mem);
+               real_mem_deinit();
+               perror("mmap /dev/mem");
+               return 0;
+       }
+
+       close(fd_mem);
+
+       return 1;
+}
diff --git a/lrmi/x86-common.h b/lrmi/x86-common.h
new file mode 100644 (file)
index 0000000..e6f0ca7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+Common routines for x86emu/lrmi interfaces. Taken from lrmi.c.
+
+Copyright (C) 1998 by Josh Vanderhoof
+Copyright (C) 2005 by Jonathan McDowell <noodles@earth.li>
+
+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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#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  0x40000
+#define REAL_MEM_BLOCKS        0x100
+
+void *LRMI_alloc_real(int size);
+void LRMI_free_real(void *m);
+int LRMI_common_init(void);
diff --git a/v86.c b/v86.c
new file mode 100644 (file)
index 0000000..5e4e69b
--- /dev/null
+++ b/v86.c
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/poll.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <arpa/inet.h>
+
+#include "v86.h"
+
+static int need_exit;
+static __u32 seq;
+
+static int netlink_send(int s, struct cn_msg *msg)
+{
+       struct nlmsghdr *nlh;
+       unsigned int size;
+       int err;
+       char buf[CONNECTOR_MAX_MSG_SIZE];
+       struct cn_msg *m;
+
+       size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
+
+       nlh = (struct nlmsghdr *)buf;
+       nlh->nlmsg_seq = seq++;
+       nlh->nlmsg_pid = getpid();
+       nlh->nlmsg_type = NLMSG_DONE;
+       nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
+       nlh->nlmsg_flags = 0;
+
+       m = NLMSG_DATA(nlh);
+       memcpy(m, msg, sizeof(*m) + msg->len);
+
+       err = send(s, nlh, size, 0);
+       if (err == -1)
+               ulog(LOG_ERR, "Failed to send: %s [%d].\n", strerror(errno), errno);
+
+       return err;
+}
+
+int req_exec(int s, struct cn_msg *msg)
+{
+       struct uvesafb_task *tsk = (struct uvesafb_task*)(msg + 1);
+       u8 *buf = (u8*)tsk + sizeof(struct uvesafb_task);
+
+       if (tsk->flags & TF_EXIT)
+               return 1;
+
+       if (v86_task(tsk, buf))
+               return 2;
+
+       netlink_send(s, msg);
+
+       return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+       char buf[CONNECTOR_MAX_MSG_SIZE];
+       int len, i, err = 0, s;
+       struct nlmsghdr *reply;
+       struct sockaddr_nl l_local;
+       struct cn_msg *data;
+       struct pollfd pfd;
+
+       s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+       if (s == -1) {
+               perror("socket");
+               return -1;
+       }
+
+       l_local.nl_family = AF_NETLINK;
+       l_local.nl_groups = 1 << (CN_IDX_V86D-1); /* bitmask of requested groups */
+       l_local.nl_pid = 0;
+
+       if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
+               perror("bind");
+               close(s);
+               return -1;
+       }
+
+       i = fork();
+       if (i) {
+               exit(0);
+       }
+
+       setsid();
+       chdir("/");
+
+       openlog("v86d", 0, LOG_KERN);
+
+       if (v86_init())
+               return -1;
+
+       memset(buf, 0, sizeof(buf));
+       pfd.fd = s;
+
+       while (!need_exit) {
+               pfd.events = POLLIN;
+               pfd.revents = 0;
+               switch (poll(&pfd, 1, -1)) {
+                       case 0:
+                               need_exit = 1;
+                               continue;
+                       case -1:
+                               if (errno != EINTR) {
+                                       need_exit = 1;
+                                       break;
+                               }
+                               continue;
+               }
+
+               memset(buf, 0, sizeof(buf));
+               len = recv(s, buf, sizeof(buf), 0);
+               if (len == -1) {
+                       perror("recv buf");
+                       err = -1;
+                       goto out;
+               }
+
+               reply = (struct nlmsghdr *)buf;
+
+               switch (reply->nlmsg_type) {
+               case NLMSG_ERROR:
+                       ulog(LOG_ERR, "Error message received.\n");
+                       break;
+
+               case NLMSG_DONE:
+                       data = (struct cn_msg *)NLMSG_DATA(reply);
+                       if (req_exec(s, data))
+                               goto out;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+out:
+       v86_cleanup();
+
+       closelog();
+       close(s);
+       return err;
+}
diff --git a/v86.h b/v86.h
new file mode 100644 (file)
index 0000000..a64b6a2
--- /dev/null
+++ b/v86.h
@@ -0,0 +1,70 @@
+#ifndef __H_V86
+#define __H_V86
+
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <linux/connector.h>
+#include "config.h"
+
+#undef u8
+#undef u16
+#undef u32
+#undef u64
+
+#define u8 __u8
+#define u16 __u16
+#define u32 __u32
+#define u64 __u64
+
+struct completion;
+
+#include <video/uvesafb.h>
+
+//#define ulog(args...)        do {} while (0)
+//#define ulog(args...)                fprintf(stdout, ##args)
+
+#ifdef CONFIG_DEBUG
+       #define MAX_LOG_LEVEL   LOG_DEBUG
+#else
+       #define MAX_LOG_LEVEL   LOG_WARNING
+#endif
+
+/* klibc doesn't provide setlogmask(), so simulate it here */
+#define ulog(level, args...)   if (level <= MAX_LOG_LEVEL) { syslog(level, ##args); }
+
+int v86_init();
+int v86_int(int num, struct v86_regs *regs);
+int v86_task(struct uvesafb_task *tsk, u8 *buf);
+void v86_cleanup();
+
+#define IVTBDA_BASE                    0x00000
+#define IVTBDA_SIZE                    0x01000
+#define DEFAULT_STACK_SIZE     0x02000
+#define REAL_MEM_BASE          0x10000
+#define REAL_MEM_SIZE          (0x30000 - REAL_MEM_BASE)
+#define EBDA_BASE                      0x9fc00
+#define VRAM_BASE                      0xa0000
+#define VRAM_SIZE                      0x20000
+#define SBIOS_SIZE                     0x20000
+#define SBIOS_BASE                     0xe0000
+#define VBIOS_BASE                     0xc0000
+
+u32 v86_mem_alloc(int size);
+void v86_mem_free(u32 m);
+int v86_mem_init(void);
+void v86_mem_cleanup(void);
+
+u8 v_rdb(u32 addr);
+u16 v_rdw(u32 addr);
+u32 v_rdl(u32 addr);
+void v_wrb(u32 addr, u8 val);
+void v_wrw(u32 addr, u16 val);
+void v_wrl(u32 addr, u32 val);
+void *vptr(u32 addr);
+
+extern int iopl (int __level);
+extern int ioperm (unsigned long int __from, unsigned long int __num,
+                                       int __turn_on);
+
+#endif /* __H_V86 */
diff --git a/v86_common.c b/v86_common.c
new file mode 100644 (file)
index 0000000..421b850
--- /dev/null
@@ -0,0 +1,156 @@
+#include <string.h>
+#include "v86.h"
+
+#define addr(t) (((t & 0xffff0000) >> 12) + (t & 0x0000ffff))
+
+#define vbeib_get_string(name)                                 \
+{                                                                                              \
+       int l;                                                                          \
+       t = addr(ib->name);                                                     \
+       if (t < bufend) {                                                       \
+               ib->name = t - lbuf;                                    \
+               l = strnlen((char*)buf + ib->name, bufend-t); \
+               if (buf[ib->name + l] != 0)                             \
+                       buf[ib->name + l] = 0;                          \
+               fsize -= l;                                                             \
+               cbuf += l;                                                              \
+       } else if (t > 0xa0000 && fsize > 0) {          \
+               strncpy((char*)cbuf, vptr(t), fsize);   \
+               l = strnlen((char*)cbuf, fsize);                \
+               if (cbuf[l] != 0)                                               \
+                       cbuf[l] = 0;                                            \
+               ib->name = tsk->buf_len - fsize;                \
+               l++;                                                                    \
+               fsize -= l;                                                             \
+               cbuf += l;                                                              \
+       } else {                                                                        \
+               ib->name = 0;                                                   \
+       }                                                                                       \
+       if (fsize < 0)                                                          \
+               fsize = 0;                                                              \
+}
+
+int v86_task(struct uvesafb_task *tsk, u8 *buf)
+{
+       u32 lbuf = 0;
+
+       ulog(LOG_DEBUG, "task flags: 0x%02x\n", tsk->flags);
+       ulog(LOG_DEBUG, "EAX=0x%08x EBX=0x%08x ECX=0x%08x EDX=0x%08x\n",
+                tsk->regs.eax, tsk->regs.ebx, tsk->regs.ecx, tsk->regs.edx);
+       ulog(LOG_DEBUG, "ESP=0x%08x EBP=0x%08x ESI=0x%08x EDI=0x%08x\n",
+                tsk->regs.esp, tsk->regs.ebp, tsk->regs.esi, tsk->regs.edi);
+
+       /* Get the VBE Info Block */
+       if (tsk->flags & TF_VBEIB) {
+               struct vbe_ib *ib;
+               int fsize;
+               u32 t, bufend;
+               u16 *td;
+               u8 *cbuf;
+
+               lbuf = v86_mem_alloc(tsk->buf_len);
+               if (!lbuf) {
+                       ulog(LOG_ERR, "Memory allocation for a VBE IB buffer failed.");
+                       return -1;
+               }
+               memcpy(vptr(lbuf), buf, tsk->buf_len);
+               tsk->regs.es  = lbuf >> 4;
+               tsk->regs.edi = 0x0000;
+
+               if (v86_int(0x10, &tsk->regs) || (tsk->regs.eax & 0xffff) != 0x004f)
+                       goto out_vbeib;
+
+               ib = (struct vbe_ib*)buf;
+               bufend = lbuf + sizeof(*ib);
+               memcpy(buf, vptr(lbuf), tsk->buf_len);
+
+               /* The original VBE Info Block is 512 bytes long. */
+               fsize = tsk->buf_len - 512;
+               cbuf = buf + 512;
+
+               t = addr(ib->mode_list_ptr);
+               /* Mode list is in the buffer, we're good. */
+               if (t < bufend) {
+                       ulog(LOG_DEBUG, "The mode list is in the buffer at %.8x.", t);
+                       ib->mode_list_ptr = t - lbuf;
+                       td = (u16*) (buf + ib->mode_list_ptr);
+
+                       while (fsize > 2 && *td != 0xffff) {
+                               td++;
+                               t += 2;
+                               fsize -= 2;
+                               cbuf += 2;
+                       }
+
+                       *td = 0xffff;
+                       cbuf += 2;
+                       fsize -= 2;
+
+               /* Mode list is in the ROM. We copy as much of it as we can
+                * to the task buffer. */
+               } else if (t > 0xa0000) {
+                       u16 tmp;
+
+                       ulog(LOG_DEBUG, "The mode list is in the Video ROM at %.8x", t);
+
+                       td = (u16*)cbuf;
+
+                       while (fsize > 2 && (tmp = v_rdw(t)) != 0xffff) {
+                               fsize -= 2;
+                               *td = tmp;
+                               td++;
+                               t += 2;
+                               cbuf += 2;
+                       }
+
+                       ib->mode_list_ptr = 512;
+                       *td = 0xffff;
+                       cbuf += 2;
+                       fsize -= 2;
+
+               /* Mode list is somewhere else. We're seriously screwed. */
+               } else {
+                       ulog(LOG_ERR, "Can't retrieve mode list from %x\n", t);
+                       ib->mode_list_ptr = 0;
+               }
+
+               vbeib_get_string(oem_string_ptr);
+               vbeib_get_string(oem_vendor_name_ptr);
+               vbeib_get_string(oem_product_name_ptr);
+               vbeib_get_string(oem_product_rev_ptr);
+out_vbeib:
+               v86_mem_free(lbuf);
+       } else {
+               if (tsk->buf_len) {
+                       lbuf = v86_mem_alloc(tsk->buf_len);
+                       if (!lbuf) {
+                               ulog(LOG_ERR, "Memory allocation for a v86d task buffer failed.");
+                               return -1;
+                       }
+                       memcpy(vptr(lbuf), buf, tsk->buf_len);
+               }
+
+               if (tsk->flags & TF_BUF_ESDI) {
+                       tsk->regs.es = lbuf >> 4;
+                       tsk->regs.edi = 0x0000;
+               }
+
+               if (tsk->flags & TF_BUF_ESBX) {
+                       tsk->regs.es = lbuf >> 4;
+                       tsk->regs.ebx = 0x0000;
+               }
+
+               if (v86_int(0x10, &tsk->regs) || (tsk->regs.eax & 0xffff) != 0x004f)
+                       goto out;
+
+               if (tsk->buf_len && tsk->flags & TF_BUF_RET) {
+                       memcpy(buf, vptr(lbuf), tsk->buf_len);
+               }
+out:
+               if (tsk->buf_len)
+                       v86_mem_free(lbuf);
+       }
+
+       return 0;
+}
+
diff --git a/v86_lrmi.c b/v86_lrmi.c
new file mode 100644 (file)
index 0000000..61f6bf5
--- /dev/null
@@ -0,0 +1,109 @@
+#include <string.h>
+#include <lrmi.h>
+#include "v86.h"
+
+/* Memory access functions */
+u8 v_rdb(u32 addr) {
+       return *(u8*)(addr);
+}
+
+u16 v_rdw(u32 addr) {
+       return *(u16*)(addr);
+}
+
+u32 v_rdl(u32 addr) {
+       return *(u32*)(addr);
+}
+
+void v_wrb(u32 addr, u8 val) {
+       *(u8*)(addr) = val;
+}
+
+void v_wrw(u32 addr, u16 val) {
+       *(u16*)(addr) = val;
+}
+
+void v_wrl(u32 addr, u32 val) {
+       *(u32*)(addr) = val;
+}
+
+void *vptr(u32 addr) {
+       return (u8*)addr;
+}
+
+void rconv_v86_to_LRMI(struct v86_regs *rs, struct LRMI_regs *rd)
+{
+       memset(rd, 0, sizeof(*rd));
+
+       rd->eax = rs->eax;
+       rd->ebx = rs->ebx;
+       rd->ecx = rs->ecx;
+       rd->edx = rs->edx;
+       rd->edi = rs->edi;
+       rd->esi = rs->esi;
+       rd->ebp = rs->ebp;
+       rd->sp  = rs->esp;
+       rd->flags = rs->eflags;
+       rd->ip  = rs->eip;
+       rd->cs  = rs->cs;
+       rd->ds  = rs->ds;
+       rd->es  = rs->es;
+       rd->fs  = rs->fs;
+       rd->gs  = rs->gs;
+}
+
+void rconv_LRMI_to_v86(struct LRMI_regs *rs, struct v86_regs *rd)
+{
+       rd->eax = rs->eax;
+       rd->ebx = rs->ebx;
+       rd->ecx = rs->ecx;
+       rd->edx = rs->edx;
+       rd->edi = rs->edi;
+       rd->esi = rs->esi;
+       rd->ebp = rs->ebp;
+       rd->esp = rs->sp;
+       rd->eflags = rs->flags;
+       rd->eip = rs->ip;
+       rd->cs  = rs->cs;
+       rd->ds  = rs->ds;
+       rd->es  = rs->es;
+       rd->fs  = rs->fs;
+       rd->gs  = rs->gs;
+}
+
+int v86_init() {
+       int err = LRMI_init();
+
+       ioperm(0, 1024, 1);
+       iopl(3);
+
+       return (err == 1) ? 0 : 1;
+}
+
+void v86_cleanup()
+{
+       /* dummy function */
+}
+
+/*
+ * Perform a simulated interrupt call.
+ */
+int v86_int(int num, struct v86_regs *regs)
+{
+       struct LRMI_regs r;
+       int err;
+
+       rconv_v86_to_LRMI(regs, &r);
+       err = LRMI_int(num, &r);
+       rconv_LRMI_to_v86(&r, regs);
+
+       return (err == 1) ? 0 : 1;
+}
+
+inline void v86_mem_free(u32 m) {
+       LRMI_free_real((void*)m);
+}
+
+inline u32 v86_mem_alloc(int size) {
+       return (u32)LRMI_alloc_real(size);
+}