From efd41a453b0f7a6a751091ff3fd0f5d49746e6c5 Mon Sep 17 00:00:00 2001 From: Chih-Wei Huang Date: Mon, 21 Feb 2011 17:44:18 +0800 Subject: [PATCH 1/1] initial import --- AUTHORS | 4 + Android.mk | 26 ++ ChangeLog | 67 +++++ MODULE_LICENSE_GPL | 0 README | 71 +++++ README.android | 13 + config.h | 3 + lrmi/COPYRIGHT | 22 ++ lrmi/lrmi.c | 855 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lrmi/lrmi.h | 100 +++++++ lrmi/x86-common.c | 249 ++++++++++++++++ lrmi/x86-common.h | 43 +++ v86.c | 153 ++++++++++ v86.h | 70 +++++ v86_common.c | 156 ++++++++++ v86_lrmi.c | 109 +++++++ 16 files changed, 1941 insertions(+) create mode 100644 AUTHORS create mode 100644 Android.mk create mode 100644 ChangeLog create mode 100644 MODULE_LICENSE_GPL create mode 100644 README create mode 100644 README.android create mode 100644 config.h create mode 100644 lrmi/COPYRIGHT create mode 100644 lrmi/lrmi.c create mode 100644 lrmi/lrmi.h create mode 100644 lrmi/x86-common.c create mode 100644 lrmi/x86-common.h create mode 100644 v86.c create mode 100644 v86.h create mode 100644 v86_common.c create mode 100644 v86_lrmi.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..a60cb07 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +v86d (c) 2007, Michal Januszewski + +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 index 0000000..a5121bd --- /dev/null +++ b/Android.mk @@ -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 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 ). +- 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 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 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 + diff --git a/README.android b/README.android new file mode 100644 index 0000000..24f951b --- /dev/null +++ b/README.android @@ -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 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 index 0000000..b8d22f4 --- /dev/null +++ b/lrmi/COPYRIGHT @@ -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 index 0000000..1b1c864 --- /dev/null +++ b/lrmi/lrmi.c @@ -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 +#include + +#if defined(__linux__) && defined(__i386__) + +#include + +#ifdef USE_LIBC_VM86 +#include +#endif + +#elif defined(__NetBSD__) || defined(__FreeBSD__) + +#include +#include +#include +#include +#include +#include + +#endif /* __NetBSD__ || __FreeBSD__ */ + +#include +#include +#include +#include +#include + +#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 + . + + 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 index 0000000..182864f --- /dev/null +++ b/lrmi/lrmi.h @@ -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 index 0000000..508baa6 --- /dev/null +++ b/lrmi/x86-common.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 index 0000000..e6f0ca7 --- /dev/null +++ b/lrmi/x86-common.h @@ -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 + +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 +#include +#include +#include +#include +#include +#include + +#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 index 0000000..5e4e69b --- /dev/null +++ b/v86.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#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 index 0000000..a64b6a2 --- /dev/null +++ b/v86.h @@ -0,0 +1,70 @@ +#ifndef __H_V86 +#define __H_V86 + +#include +#include +#include +#include +#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