From 6061612987ebba7ca65835e658b8d969be13a22d Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 11 Jan 2008 11:52:59 -0500 Subject: [PATCH] X86EMU: added blacklist for I/O port in 0-0xFF range Signed-off-by: Bart Trojanowski Work funded by: Symbio Technologies There seems to be an inconsistency between what the x86emu gets from the PCI handling code and by accessing hardware directly. x86emu relies on a set of functions to emulate PCI access. When things goes wrong, the emulator is asked to execute an OUT instruction on port 0x20. I've put together a patch against xserver-xorg package that prevents accesses to BAD registers. This turns a freeze into a segfault in X. http://www.jukie.net/~bart/patches/xorg-server/20080111/0001-X86EMU- added-blacklist-for-I-O-port-in-0-0xFF-range.patch It does not address the DDC not working, I hope that after fixing the bugs in x86emu, things may improve. Anyway, I am continuing to investigate the real cause of the PCI access issue. To find out more read this thread: http://lists.freedesktop.org/archives/xorg/2008-January/031811.html -Bart diff -Nurp xorg-server-1.4.1~git20080118/hw/xfree86/int10/helper_exec.c xorg-server-1.4.1~git20080118-working/hw/xfree86/int10/helper_exec.c --- xorg-server-1.4.1~git20080118/hw/xfree86/int10/helper_exec.c 2008-01-18 13:23:40.000000000 -0800 +++ xorg-server-1.4.1~git20080118-working/hw/xfree86/int10/helper_exec.c 2008-01-22 09:53:27.000000000 -0800 @@ -21,6 +21,8 @@ #define PRINT_PORT 0 #include +#include +#include #include #include "xf86.h" @@ -210,6 +212,72 @@ stack_trace(xf86Int10InfoPtr pInt) xf86ErrorFVerb(3, "\n"); } +enum port_action_e { + PORT_ACTION_PERMIT, + PORT_ACTION_WARN, + PORT_ACTION_BAIL, + PORT_ACTION_MAX +}; + +static const struct port_range { + CARD16 start, end; + enum port_action_e access; +} port_range_table[] = { + // NOTE: port ranges are non overlapping and sorted + { 0x00, 0x1f, PORT_ACTION_BAIL }, // DMA + { 0x20, 0x21, PORT_ACTION_BAIL }, // PIC + { 0x40, 0x47, PORT_ACTION_BAIL }, // PIT 1&2 + { 0x50, 0x53, PORT_ACTION_BAIL }, + { 0x70, 0x77, PORT_ACTION_BAIL }, // CMOS/RTC + { 0x81, 0x8f, PORT_ACTION_BAIL }, // DIAG REGS + { 0xa0, 0xa1, PORT_ACTION_BAIL }, // PIC2 + { 0xc0, 0xdf, PORT_ACTION_BAIL }, // DMA +}; +#define ARRAY_SIZE(X) (sizeof((X)) / (sizeof(*(X)))) +#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)])) + +static void assert_port_access_allowed (CARD16 port, CARD16 width) +{ + CARD16 access_start, access_end; + const struct port_range *pr, *pr_start, *pr_end; + + access_start = port; + access_end = port + width - 1; + + // TODO: if the list gets too long we should do a binary search + // or convert the port list to a bitmap representation + pr_start = port_range_table; + pr_end = ARRAY_END(port_range_table); + + for (pr = pr_start; pr < pr_end; pr++) { + if (access_end < pr->start) + continue; + if (access_start > pr->end) + break; + + // we are in the pr range now + switch (pr->access) { + default: + continue; + case PORT_ACTION_BAIL: + case PORT_ACTION_WARN: + break; + } + + ErrorF("Emulator asked to make a suspect %saccess to " + "port %u (0x%04x)%s\n", + (width == 1) ? "byte " : + (width == 2) ? "word " : + (width == 4) ? "long " : "", + port, port, + (pr->access == PORT_ACTION_BAIL) + ? "; terminating." : "ignoring."); + + if (pr->access == PORT_ACTION_BAIL) + kill(getpid(), SIGSEGV); + } +} + int port_rep_inb(xf86Int10InfoPtr pInt, CARD16 port, CARD32 base, int d_f, CARD32 count) @@ -319,7 +387,7 @@ x_inb(CARD16 port) ErrorF(" inb(%#x) = %2.2x\n", port, val); #ifdef __NOT_YET__ } else if (port < 0x0100) { /* Don't interfere with mainboard */ - val = 0; + val = 0; xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2, "inb 0x%4.4x\n", port); if (xf86GetVerbosity() > 3) { @@ -327,10 +395,14 @@ x_inb(CARD16 port) stack_trace(Int10Current); } #endif /* __NOT_YET__ */ - } else if (!pciCfg1inb(port, &val)) { - val = inb(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inb(%#x) = %2.2x\n", port, val); + } else { + assert_port_access_allowed (port, sizeof(val)); + + if (!pciCfg1inb(port, &val)) { + val = inb(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inb(%#x) = %2.2x\n", port, val); + } } return val; } @@ -349,10 +421,14 @@ x_inw(CARD16 port) */ X_GETTIMEOFDAY(&tv); val = (CARD16)(tv.tv_usec / 3); - } else if (!pciCfg1inw(port, &val)) { - val = inw(Int10Current->ioBase + port); - if (PRINT_PORT && DEBUG_IO_TRACE()) - ErrorF(" inw(%#x) = %4.4x\n", port, val); + } else { + assert_port_access_allowed (port, sizeof(val)); + + if (!pciCfg1inw(port, &val)) { + val = inw(Int10Current->ioBase + port); + if (PRINT_PORT && DEBUG_IO_TRACE()) + ErrorF(" inw(%#x) = %4.4x\n", port, val); + } } return val; } @@ -384,6 +460,8 @@ x_outb(CARD16 port, CARD8 val) } else if (!pciCfg1outb(port, val)) { if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" outb(%#x, %2.2x)\n", port, val); + + assert_port_access_allowed (port, sizeof(val)); outb(Int10Current->ioBase + port, val); } } @@ -404,6 +482,8 @@ x_inl(CARD16 port) { CARD32 val; + assert_port_access_allowed (port, sizeof(val)); + if (!pciCfg1in(port, &val)) { val = inl(Int10Current->ioBase + port); if (PRINT_PORT && DEBUG_IO_TRACE()) @@ -418,6 +498,8 @@ x_outl(CARD16 port, CARD32 val) if (!pciCfg1out(port, val)) { if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" outl(%#x, %8.8x)\n", port, val); + + assert_port_access_allowed (port, sizeof(val)); outl(Int10Current->ioBase + port, val); } }