mirror of
https://github.com/X11Libre/xserver.git
synced 2026-04-14 17:18:09 +00:00
The only consumer of this is the Linux vm86 backend for int10 (which you should not use), and there all it serves to do is make signals generated by the vm86 task non-fatal. In practice this error appears never to happen, and marching ahead with root privileges after arbitrary code has raised a signal seems like a poor plan. Remove the usage in the vm86 code, making this error fatal. Signed-off-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Olivier Fourdan <ofourdan@redhat.com> Reviewed-by: Dave Airlie <airlied@redhat.com>
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
|