/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }