diff options
author | Jerome Glisse <jglisse@redhat.com> | 2015-03-23 17:49:23 -0400 |
---|---|---|
committer | Jerome Glisse <jglisse@redhat.com> | 2015-03-23 17:49:23 -0400 |
commit | 958c59b6c14ba182630df2b69adeca2b60b7aae9 (patch) | |
tree | 9606e9a2fdbeb12afc5dbabdb0d0bde58a44b060 /thunk.c |
Tool to trace video bios extension (vbe) execution.
Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
Diffstat (limited to 'thunk.c')
-rw-r--r-- | thunk.c | 426 |
1 files changed, 426 insertions, 0 deletions
@@ -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; +} |