summaryrefslogtreecommitdiff
path: root/thunk.c
diff options
context:
space:
mode:
Diffstat (limited to 'thunk.c')
-rw-r--r--thunk.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/thunk.c b/thunk.c
new file mode 100644
index 0000000..919f2e9
--- /dev/null
+++ b/thunk.c
@@ -0,0 +1,426 @@
+/*
+ * 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.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/io.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#define SHMERRORPTR (pointer)(-1)
+
+#define _INT10_PRIVATE
+#include "x86emu/include/xf86int10.h"
+#include "x86emu/include/x86emu.h"
+#include "x86emu/include/xf86x86emu.h"
+#include "lrmi.h"
+#include "x86-common.h"
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+#define ALLOC_ENTRIES(x) (V_RAM - 1)
+#define TRUE 1
+#define FALSE 0
+
+#define __BUILDIO(bwl,bw,type) \
+ static inline void out##bwl##_local(unsigned long port, unsigned type value)\
+ {\
+ __asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port));\
+ }\
+ static inline unsigned type in##bwl##_local(unsigned long port)\
+ {\
+ unsigned type value;\
+ __asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port));\
+ return value;\
+ }
+
+__BUILDIO(b,b,char)
+__BUILDIO(w,w,short)
+__BUILDIO(l,,int)
+
+char *mmap_addr = SHMERRORPTR;
+struct LRMI_regs *regs;
+static void *stack;
+
+unsigned long GPU_IOPORT = -1;
+unsigned long GPU_IOSIZE = 0;
+
+void printk(const char *fmt, ...)
+{
+ va_list argptr;
+ va_start(argptr, fmt);
+
+ fprintf(stderr, fmt, argptr);
+ va_end(argptr);
+}
+
+static unsigned _radeon_reg_idx = -1;
+static unsigned _radeon_pll_idx = -1;
+
+u8 read_b(int addr)
+{
+ return *((char *)mmap_addr + addr);
+}
+
+u8 x_inb(X86EMU_pioAddr port)
+{
+ unsigned val;
+ val = inb_local(port);
+#if 0
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ fprintf(stderr, "if ((tmp = RIO8(gpu->io, 0x%04lx)) != 0x%08x) "
+ "{ printf(\"RIO8 FAILED %%4d got 0x%%08x expected 0x%08x\\n\", __LINE__, tmp); }\n",
+ port - GPU_IOPORT, val, val);
+ }
+#else
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ unsigned dport = port - GPU_IOPORT;
+ if (dport >= 0x4 && dport <= 0x7) {
+ fprintf(stderr, "if ((tmp = RREG8(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RREG8(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ _radeon_reg_idx + dport - 0x4, (unsigned)val,
+ _radeon_reg_idx + dport - 0x4, (unsigned)val);
+ } else if (dport >= 0xc && dport <= 0xf) {
+ fprintf(stderr, "if ((tmp = RPLL8(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RPLL8(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ _radeon_pll_idx + dport - 0xc, (unsigned)val,
+ _radeon_pll_idx + dport - 0xc, (unsigned)val);
+ } else {
+ fprintf(stderr, "if ((tmp = RREG8(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RREG8(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ dport, (unsigned)val,
+ dport, (unsigned)val);
+ }
+ }
+#endif
+ return val;
+}
+
+u16 x_inw(X86EMU_pioAddr port)
+{
+ unsigned val;
+ val = inw_local(port);
+#if 0
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ fprintf(stderr, "if ((tmp = RIO8(gpu->io, 0x%04lx)) != 0x%08x) "
+ "{ printf(\"RIO16 FAILED %%4d got 0x%%08x expected 0x%08x\\n\", __LINE__, tmp); }\n",
+ port - GPU_IOPORT, val, val);
+ }
+#else
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ unsigned dport = port - GPU_IOPORT;
+ if (dport >= 0x4 && dport <= 0x7) {
+ fprintf(stderr, "if ((tmp = RREG16(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RREG16(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ _radeon_reg_idx + dport - 0x4, (unsigned)val,
+ _radeon_reg_idx + dport - 0x4, (unsigned)val);
+ } else if (dport >= 0xc && dport <= 0xf) {
+ fprintf(stderr, "if ((tmp = RPLL16(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RPLL16(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ _radeon_pll_idx + dport - 0xc, (unsigned)val,
+ _radeon_pll_idx + dport - 0xc, (unsigned)val);
+ } else {
+ fprintf(stderr, "if ((tmp = RREG16(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RREG16(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ dport, (unsigned)val,
+ dport, (unsigned)val);
+ }
+ }
+#endif
+ return val;
+}
+
+u32 x_inl(X86EMU_pioAddr port)
+{
+ unsigned val;
+ val = inl_local(port);
+#if 0
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ fprintf(stderr, "if ((tmp = RIO8(gpu->io, 0x%04lx)) != 0x%08x) "
+ "{ printf(\"RIO32 FAILED %%4d got 0x%%08x expected 0x%08x\\n\", __LINE__, tmp); }\n",
+ port - GPU_IOPORT, val, val);
+ }
+#else
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ unsigned dport = port - GPU_IOPORT;
+ if (dport == 0x4) {
+ fprintf(stderr, "if ((tmp = RREG32(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RREG32(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ _radeon_reg_idx + dport - 0x4, (unsigned)val,
+ _radeon_reg_idx + dport - 0x4, (unsigned)val);
+ } else if (dport == 0xc) {
+ fprintf(stderr, "if ((tmp = RPLL32(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RPLL32(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ _radeon_pll_idx + dport - 0xc, (unsigned)val,
+ _radeon_pll_idx + dport - 0xc, (unsigned)val);
+ } else {
+ fprintf(stderr, "if ((tmp = RREG32(0x%08x)) != 0x%08x) "
+ "{ printf(\"(RREG32(0x%08x) == 0x%%08x) != 0x%08x [%%d]\\n\", tmp, __LINE__); }\n",
+ dport, (unsigned)val,
+ dport, (unsigned)val);
+ }
+ }
+#endif
+ return val;
+}
+
+void x_outb(X86EMU_pioAddr port, u8 val)
+{
+#if 0
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ fprintf(stderr, "WIO8(gpu->io, 0x%04lx, 0x%08x);\n", port - GPU_IOPORT, (unsigned)val);
+ }
+#else
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ unsigned dport = port - GPU_IOPORT;
+ if (dport >= 0x4 && dport <= 0x7) {
+ fprintf(stderr, "WREG8(0x%08x, 0x%08x);\n",
+ _radeon_reg_idx + dport - 0x4, (unsigned)val);
+ } else if (dport >= 0xc && dport <= 0xf) {
+ fprintf(stderr, "WPLL8(0x%08x, 0x%08x);\n",
+ _radeon_pll_idx + dport - 0xc, (unsigned)val);
+ } else if (dport == 0x8) {
+ _radeon_pll_idx = val;
+ } else {
+ fprintf(stderr, "WREG8(0x%08x, 0x%08x);\n",
+ dport, (unsigned)val);
+ }
+ }
+#endif
+ outb_local(port, val);
+}
+
+void x_outw(X86EMU_pioAddr port, u16 val)
+{
+#if 0
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ fprintf(stderr, "WIO16(gpu->io, 0x%04lx, 0x%08x);\n", port - GPU_IOPORT, (unsigned)val);
+ }
+#else
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ unsigned dport = port - GPU_IOPORT;
+ if (dport >= 0x4 && dport <= 0x7) {
+ fprintf(stderr, "WREG16(0x%08x, 0x%08x);\n",
+ _radeon_reg_idx + dport - 0x4, (unsigned)val);
+ } else if (dport >= 0xc && dport <= 0xf) {
+ fprintf(stderr, "WPLL16(0x%08x, 0x%08x);\n",
+ _radeon_pll_idx + dport - 0xc, (unsigned)val);
+ } else {
+ fprintf(stderr, "WREG16(0x%08x, 0x%08x);\n",
+ dport, (unsigned)val);
+ }
+ }
+#endif
+ outw_local(port, val);
+}
+
+void x_outl(X86EMU_pioAddr port, u32 val)
+{
+#if 0
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ fprintf(stderr, "WIO32(gpu->io, 0x%04lx, 0x%08x);\n", port - GPU_IOPORT, (unsigned)val);
+ }
+#else
+ if (port >= GPU_IOPORT && port < (GPU_IOPORT + GPU_IOSIZE)) {
+ unsigned dport = port - GPU_IOPORT;
+ if (dport == 0x4) {
+ fprintf(stderr, "WREG32(0x%08x, 0x%08x);\n",
+ _radeon_reg_idx, (unsigned)val);
+ } else if (dport == 0xc) {
+ fprintf(stderr, "WPLL32(0x%08x, 0x%08x);\n",
+ _radeon_pll_idx, (unsigned)val);
+ } else if (dport == 0x0) {
+ _radeon_reg_idx = val;
+ } else if (dport == 0x8) {
+ _radeon_pll_idx = val;
+ } else {
+ fprintf(stderr, "WREG32(0x%08x, 0x%08x);\n",
+ dport, (unsigned)val);
+ }
+ }
+#endif
+ outl_local(port, val);
+}
+
+void pushw(u16 val)
+{
+ X86_ESP -= 2;
+ MEM_WW(((u32) X86_SS << 4) + X86_SP, val);
+}
+
+static void x86emu_do_int(int num)
+{
+ u32 eflags;
+
+#if 0
+ fprintf(stderr, "Calling INT 0x%X (%04X:%04X)\n", num,
+ (read_b((num << 2) + 3) << 8) + read_b((num << 2) + 2),
+ (read_b((num << 2) + 1) << 8) + read_b((num << 2)));
+ fprintf(stderr, " EAX is %X\n", (int) X86_EAX);
+#endif
+
+ eflags = X86_EFLAGS;
+ eflags = eflags | X86_IF_MASK;
+ pushw(eflags);
+ pushw(X86_CS);
+ pushw(X86_IP);
+ X86_EFLAGS = X86_EFLAGS & ~(X86_VIF_MASK | X86_TF_MASK);
+ X86_CS = (read_b((num << 2) + 3) << 8) + read_b((num << 2) + 2);
+ X86_IP = (read_b((num << 2) + 1) << 8) + read_b((num << 2));
+
+#if 0
+ fprintf(stderr, "Leaving interrupt call.\n");
+#endif
+}
+
+int LRMI_init(void)
+{
+ int i;
+ X86EMU_intrFuncs intFuncs[256];
+
+ if (!LRMI_common_init())
+ return 0;
+
+ mmap_addr = 0;
+
+ X86EMU_pioFuncs pioFuncs = {
+ (&x_inb),
+ (&x_inw),
+ (&x_inl),
+ (&x_outb),
+ (&x_outw),
+ (&x_outl)
+ };
+
+ X86EMU_setupPioFuncs(&pioFuncs);
+
+ for (i=0;i<256;i++)
+ intFuncs[i] = x86emu_do_int;
+ X86EMU_setupIntrFuncs(intFuncs);
+
+ X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK;
+
+ /*
+ * Allocate a 64k stack.
+ */
+ stack = LRMI_alloc_real(64 * 1024);
+ X86_SS = ((unsigned long)stack) >> 4;
+ X86_ESP = 0xFFF9;
+ memset (stack, 0, 64*1024);
+
+ /* Make sure that we end up jumping back to a halt instruction */
+ *((char *)0) = 0x4f;
+
+ M.mem_base = 0;
+ M.mem_size = 1024*1024;
+
+ return 1;
+}
+
+int real_call(struct LRMI_regs *registers)
+{
+ regs = registers;
+
+ X86_EAX = registers->eax;
+ X86_EBX = registers->ebx;
+ X86_ECX = registers->ecx;
+ X86_EDX = registers->edx;
+ X86_ESI = registers->esi;
+ X86_EDI = registers->edi;
+ X86_EBP = registers->ebp;
+ X86_EIP = registers->ip;
+ X86_ES = registers->es;
+ X86_FS = registers->fs;
+ X86_GS = registers->gs;
+ X86_CS = registers->cs;
+
+ if (registers->ss != 0) {
+ X86_SS = registers->ss;
+ } else {
+ X86_SS = ((unsigned long)stack) >> 4;
+ }
+
+ if (registers->ds != 0) {
+ X86_DS = registers->ds;
+ }
+
+ if (registers->sp != 0) {
+ X86_ESP = registers->sp;
+ } else {
+ X86_ESP = 0xFFF9;
+ }
+
+ M.x86.debug |= DEBUG_DECODE_F;
+
+ memset (stack, 0, 64*1024);
+
+ X86EMU_exec();
+
+ registers->eax = X86_EAX;
+ registers->ebx = X86_EBX;
+ registers->ecx = X86_ECX;
+ registers->edx = X86_EDX;
+ registers->esi = X86_ESI;
+ registers->edi = X86_EDI;
+ registers->ebp = X86_EBP;
+ registers->es = X86_ES;
+
+ return 1;
+}
+
+int LRMI_int(int num, struct LRMI_regs *registers)
+{
+ u32 eflags;
+ eflags = X86_EFLAGS;
+ eflags = eflags | X86_IF_MASK;
+ X86_EFLAGS = X86_EFLAGS & ~(X86_VIF_MASK | X86_TF_MASK | X86_IF_MASK | X86_NT_MASK);
+
+ registers->cs = (read_b((num << 2) + 3) << 8) + read_b((num << 2) + 2);
+ registers->ip = (read_b((num << 2) + 1) << 8) + read_b((num << 2));
+ regs = registers;
+ return real_call(registers);
+}
+
+int LRMI_call(struct LRMI_regs *registers)
+{
+ return real_call(registers);
+}
+
+size_t LRMI_base_addr(void)
+{
+ return (size_t)mmap_addr;
+}