324 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
#ifdef HAVE_XORG_CONFIG_H
 | 
						|
#include <xorg-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include "xf86.h"
 | 
						|
#include "xf86_OSproc.h"
 | 
						|
#include "xf86Pci.h"
 | 
						|
#include "compiler.h"
 | 
						|
#define _INT10_PRIVATE
 | 
						|
#include "xf86int10.h"
 | 
						|
 | 
						|
#define REG pInt
 | 
						|
 | 
						|
#ifdef _VM86_LINUX
 | 
						|
#include "int10Defines.h"
 | 
						|
 | 
						|
static int vm86_rep(struct vm86_struct *ptr);
 | 
						|
static struct vm86_struct vm86_s;
 | 
						|
 | 
						|
Bool
 | 
						|
xf86Int10ExecSetup(xf86Int10InfoPtr pInt)
 | 
						|
{
 | 
						|
#define VM86S ((struct vm86_struct *)pInt->cpuRegs)
 | 
						|
 | 
						|
    pInt->cpuRegs = &vm86_s;
 | 
						|
    VM86S->flags = 0;
 | 
						|
    VM86S->screen_bitmap = 0;
 | 
						|
    VM86S->cpu_type = CPU_586;
 | 
						|
    memset(&VM86S->int_revectored, 0xff, sizeof(VM86S->int_revectored));
 | 
						|
    memset(&VM86S->int21_revectored, 0xff, sizeof(VM86S->int21_revectored));
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* get the linear address */
 | 
						|
#define LIN_PREF_SI ((pref_seg << 4) + X86_SI)
 | 
						|
#define LWECX       ((prefix66 ^ prefix67) ? X86_ECX : X86_CX)
 | 
						|
#define LWECX_ZERO  {if (prefix66 ^ prefix67) X86_ECX = 0; else X86_CX = 0;}
 | 
						|
#define DF (1 << 10)
 | 
						|
 | 
						|
/* vm86 fault handling */
 | 
						|
static Bool
 | 
						|
vm86_GP_fault(xf86Int10InfoPtr pInt)
 | 
						|
{
 | 
						|
    unsigned char *csp, *lina;
 | 
						|
    CARD32 org_eip;
 | 
						|
    int pref_seg;
 | 
						|
    int done, is_rep, prefix66, prefix67;
 | 
						|
 | 
						|
    csp = lina = SEG_ADR((unsigned char *), X86_CS, IP);
 | 
						|
 | 
						|
    is_rep = 0;
 | 
						|
    prefix66 = prefix67 = 0;
 | 
						|
    pref_seg = -1;
 | 
						|
 | 
						|
    /* eat up prefixes */
 | 
						|
    done = 0;
 | 
						|
    do {
 | 
						|
        switch (MEM_RB(pInt, (int) csp++)) {
 | 
						|
        case 0x66:             /* operand prefix */
 | 
						|
            prefix66 = 1;
 | 
						|
            break;
 | 
						|
        case 0x67:             /* address prefix */
 | 
						|
            prefix67 = 1;
 | 
						|
            break;
 | 
						|
        case 0x2e:             /* CS */
 | 
						|
            pref_seg = X86_CS;
 | 
						|
            break;
 | 
						|
        case 0x3e:             /* DS */
 | 
						|
            pref_seg = X86_DS;
 | 
						|
            break;
 | 
						|
        case 0x26:             /* ES */
 | 
						|
            pref_seg = X86_ES;
 | 
						|
            break;
 | 
						|
        case 0x36:             /* SS */
 | 
						|
            pref_seg = X86_SS;
 | 
						|
            break;
 | 
						|
        case 0x65:             /* GS */
 | 
						|
            pref_seg = X86_GS;
 | 
						|
            break;
 | 
						|
        case 0x64:             /* FS */
 | 
						|
            pref_seg = X86_FS;
 | 
						|
            break;
 | 
						|
        case 0xf0:             /* lock */
 | 
						|
            break;
 | 
						|
        case 0xf2:             /* repnz */
 | 
						|
        case 0xf3:             /* rep */
 | 
						|
            is_rep = 1;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            done = 1;
 | 
						|
        }
 | 
						|
    } while (!done);
 | 
						|
    csp--;                      /* oops one too many */
 | 
						|
    org_eip = X86_EIP;
 | 
						|
    X86_IP += (csp - lina);
 | 
						|
 | 
						|
    switch (MEM_RB(pInt, (int) csp)) {
 | 
						|
    case 0x6c:                 /* insb */
 | 
						|
        /* NOTE: ES can't be overwritten; prefixes 66,67 should use esi,edi,ecx
 | 
						|
         * but is anyone using extended regs in real mode? */
 | 
						|
        /* WARNING: no test for DI wrapping! */
 | 
						|
        X86_EDI += port_rep_inb(pInt, X86_DX, SEG_EADR((CARD32), X86_ES, DI),
 | 
						|
                                X86_FLAGS & DF, is_rep ? LWECX : 1);
 | 
						|
        if (is_rep)
 | 
						|
            LWECX_ZERO;
 | 
						|
        X86_IP++;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0x6d:                 /* (rep) insw / insd */
 | 
						|
        /* NOTE: ES can't be overwritten */
 | 
						|
        /* WARNING: no test for _DI wrapping! */
 | 
						|
        if (prefix66) {
 | 
						|
            X86_DI += port_rep_inl(pInt, X86_DX, SEG_ADR((CARD32), X86_ES, DI),
 | 
						|
                                   X86_EFLAGS & DF, is_rep ? LWECX : 1);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            X86_DI += port_rep_inw(pInt, X86_DX, SEG_ADR((CARD32), X86_ES, DI),
 | 
						|
                                   X86_FLAGS & DF, is_rep ? LWECX : 1);
 | 
						|
        }
 | 
						|
        if (is_rep)
 | 
						|
            LWECX_ZERO;
 | 
						|
        X86_IP++;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0x6e:                 /* (rep) outsb */
 | 
						|
        if (pref_seg < 0)
 | 
						|
            pref_seg = X86_DS;
 | 
						|
        /* WARNING: no test for _SI wrapping! */
 | 
						|
        X86_SI += port_rep_outb(pInt, X86_DX, (CARD32) LIN_PREF_SI,
 | 
						|
                                X86_FLAGS & DF, is_rep ? LWECX : 1);
 | 
						|
        if (is_rep)
 | 
						|
            LWECX_ZERO;
 | 
						|
        X86_IP++;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0x6f:                 /* (rep) outsw / outsd */
 | 
						|
        if (pref_seg < 0)
 | 
						|
            pref_seg = X86_DS;
 | 
						|
        /* WARNING: no test for _SI wrapping! */
 | 
						|
        if (prefix66) {
 | 
						|
            X86_SI += port_rep_outl(pInt, X86_DX, (CARD32) LIN_PREF_SI,
 | 
						|
                                    X86_EFLAGS & DF, is_rep ? LWECX : 1);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            X86_SI += port_rep_outw(pInt, X86_DX, (CARD32) LIN_PREF_SI,
 | 
						|
                                    X86_FLAGS & DF, is_rep ? LWECX : 1);
 | 
						|
        }
 | 
						|
        if (is_rep)
 | 
						|
            LWECX_ZERO;
 | 
						|
        X86_IP++;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xe5:                 /* inw xx, inl xx */
 | 
						|
        if (prefix66)
 | 
						|
            X86_EAX = x_inl(csp[1]);
 | 
						|
        else
 | 
						|
            X86_AX = x_inw(csp[1]);
 | 
						|
        X86_IP += 2;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xe4:                 /* inb xx */
 | 
						|
        X86_AL = x_inb(csp[1]);
 | 
						|
        X86_IP += 2;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xed:                 /* inw dx, inl dx */
 | 
						|
        if (prefix66)
 | 
						|
            X86_EAX = x_inl(X86_DX);
 | 
						|
        else
 | 
						|
            X86_AX = x_inw(X86_DX);
 | 
						|
        X86_IP += 1;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xec:                 /* inb dx */
 | 
						|
        X86_AL = x_inb(X86_DX);
 | 
						|
        X86_IP += 1;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xe7:                 /* outw xx */
 | 
						|
        if (prefix66)
 | 
						|
            x_outl(csp[1], X86_EAX);
 | 
						|
        else
 | 
						|
            x_outw(csp[1], X86_AX);
 | 
						|
        X86_IP += 2;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xe6:                 /* outb xx */
 | 
						|
        x_outb(csp[1], X86_AL);
 | 
						|
        X86_IP += 2;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xef:                 /* outw dx */
 | 
						|
        if (prefix66)
 | 
						|
            x_outl(X86_DX, X86_EAX);
 | 
						|
        else
 | 
						|
            x_outw(X86_DX, X86_AX);
 | 
						|
        X86_IP += 1;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xee:                 /* outb dx */
 | 
						|
        x_outb(X86_DX, X86_AL);
 | 
						|
        X86_IP += 1;
 | 
						|
        break;
 | 
						|
 | 
						|
    case 0xf4:
 | 
						|
        DebugF("hlt at %p\n", lina);
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    case 0x0f:
 | 
						|
        xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
 | 
						|
                   "CPU 0x0f Trap at CS:EIP=0x%4.4x:0x%8.8lx\n", X86_CS,
 | 
						|
                   X86_EIP);
 | 
						|
        goto op0ferr;
 | 
						|
 | 
						|
    default:
 | 
						|
        xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "unknown reason for exception\n");
 | 
						|
 | 
						|
 op0ferr:
 | 
						|
        dump_registers(pInt);
 | 
						|
        stack_trace(pInt);
 | 
						|
        dump_code(pInt);
 | 
						|
        xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "cannot continue\n");
 | 
						|
        return FALSE;
 | 
						|
    }                           /* end of switch() */
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
do_vm86(xf86Int10InfoPtr pInt)
 | 
						|
{
 | 
						|
    int retval;
 | 
						|
 | 
						|
    retval = vm86_rep(VM86S);
 | 
						|
 | 
						|
    switch (VM86_TYPE(retval)) {
 | 
						|
    case VM86_UNKNOWN:
 | 
						|
        if (!vm86_GP_fault(pInt))
 | 
						|
            return 0;
 | 
						|
        break;
 | 
						|
    case VM86_STI:
 | 
						|
        xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "vm86_sti :-((\n");
 | 
						|
        dump_registers(pInt);
 | 
						|
        dump_code(pInt);
 | 
						|
        stack_trace(pInt);
 | 
						|
        return 0;
 | 
						|
    case VM86_INTx:
 | 
						|
        pInt->num = VM86_ARG(retval);
 | 
						|
        if (!int_handler(pInt)) {
 | 
						|
            xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR,
 | 
						|
                       "Unknown vm86_int: 0x%X\n\n", VM86_ARG(retval));
 | 
						|
            dump_registers(pInt);
 | 
						|
            dump_code(pInt);
 | 
						|
            stack_trace(pInt);
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        /* I'm not sure yet what to do if we can handle ints */
 | 
						|
        break;
 | 
						|
    case VM86_SIGNAL:
 | 
						|
        return 1;
 | 
						|
        /*
 | 
						|
         * we used to warn here and bail out - but now the sigio stuff
 | 
						|
         * always fires signals at us. So we just ignore them for now.
 | 
						|
         */
 | 
						|
        xf86DrvMsg(pInt->pScrn->scrnIndex, X_WARNING, "received signal\n");
 | 
						|
        return 0;
 | 
						|
    default:
 | 
						|
        xf86DrvMsg(pInt->pScrn->scrnIndex, X_ERROR, "unknown type(0x%x)=0x%x\n",
 | 
						|
                   VM86_ARG(retval), VM86_TYPE(retval));
 | 
						|
        dump_registers(pInt);
 | 
						|
        dump_code(pInt);
 | 
						|
        stack_trace(pInt);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xf86ExecX86int10(xf86Int10InfoPtr pInt)
 | 
						|
{
 | 
						|
    int sig = setup_int(pInt);
 | 
						|
 | 
						|
    if (int_handler(pInt))
 | 
						|
        while (do_vm86(pInt)) {
 | 
						|
        };
 | 
						|
 | 
						|
    finish_int(pInt, sig);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
vm86_rep(struct vm86_struct *ptr)
 | 
						|
{
 | 
						|
    int __res;
 | 
						|
 | 
						|
#ifdef __PIC__
 | 
						|
    /* When compiling with -fPIC, we can't use asm constraint "b" because
 | 
						|
       %ebx is already taken by gcc. */
 | 
						|
    __asm__ __volatile__("pushl %%ebx\n\t"
 | 
						|
                         "push %%gs\n\t"
 | 
						|
                         "movl %2,%%ebx\n\t"
 | 
						|
                         "movl %1,%%eax\n\t"
 | 
						|
                         "int $0x80\n\t" "pop %%gs\n\t" "popl %%ebx":"=a"(__res)
 | 
						|
                         :"n"((int) 113), "r"((struct vm86_struct *) ptr));
 | 
						|
#else
 | 
						|
    __asm__ __volatile__("push %%gs\n\t"
 | 
						|
                         "int $0x80\n\t"
 | 
						|
                         "pop %%gs":"=a"(__res):"a"((int) 113),
 | 
						|
                         "b"((struct vm86_struct *) ptr));
 | 
						|
#endif
 | 
						|
 | 
						|
    if (__res < 0) {
 | 
						|
        errno = -__res;
 | 
						|
        __res = -1;
 | 
						|
    }
 | 
						|
    else
 | 
						|
        errno = 0;
 | 
						|
    return __res;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |