From: Thomas Horsten Date: Wed, 14 Oct 2009 16:12:30 +0000 (+0100) Subject: [package/vbetool] Add workaround for iGFX I/O bug X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=fe12ac28bdeec0975c17929845293ddeb42cc3fc;p=xenclient%2Fbuild.git [package/vbetool] Add workaround for iGFX I/O bug Translate I/O accesses to write to GTT into corresponding MMIO (cherry picked from commit 4043180ed1fb12e7c8f7f1ccae7d95263cc9355f) --- diff --git a/package/vbetool/vbetool-igfx-io-to-mmio.patch b/package/vbetool/vbetool-igfx-io-to-mmio.patch new file mode 100644 index 0000000..55beb2b --- /dev/null +++ b/package/vbetool/vbetool-igfx-io-to-mmio.patch @@ -0,0 +1,265 @@ +diff --git a/vbetool.c b/vbetool.c +index f6eee59..1a3503b 100644 +--- a/vbetool.c ++++ b/vbetool.c +@@ -8,6 +8,7 @@ This program is released under the terms of the GNU General Public License, + version 2 + */ + ++#include + #include + #include + #include +@@ -24,6 +25,8 @@ version 2 + #include + + #include ++#include "include/xf86int10.h" ++#include "include/x86emu.h" + #include "vbetool.h" + + #define access_ptr_register(reg_frame,reg) (reg_frame -> reg) +@@ -36,14 +39,132 @@ version 2 + #define DPMS_STATE_OFF 0x0400 + #define DPMS_STATE_LOW 0x0800 + ++#define dprintf(arg...) ++//#define dprintf(arg...) printf(arg) ++ ++#define dfflush(arg...) ++ + static struct pci_access *pacc; + ++static struct pci_dev *vga_pci_dev; ++ ++#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) ++ ++ ++typedef u32 (*emu_io_handler)(u16 port, int write, int size, u32 val); ++ ++static u32 igfx_mmio = 0; ++static u32 igfx_index = 0; ++static u32 igfx_ioport = 0; ++ ++u32 emu_io(u16 port, int write, int size, u32 val) ++{ ++ dprintf("emu_io: 0x%08x %s%c 0x%04x 0x%08x\n", ++ cnt++, ++ write?"out":"in", ++ size==1?'b':size==2?'w':'l', ++ port, ++ (int)val); ++ ++ if ( igfx_ioport && write ) { ++ if ( port == igfx_ioport ) ++ { ++ if ((val & 1) && (val < 0x10000)) ++ { ++ igfx_index = val; ++ return 0; ++ } else { ++ igfx_index = 0; ++ } ++ } ++ else if ( port == igfx_ioport+4 && igfx_index ) ++ { ++ dprintf("Real write: 0x%08x -> (0x%08x + 0x200000 + 0x%08x)/0x%08x\n", ++ val, igfx_mmio, igfx_index & ~3, igfx_mmio + 0x200000 + (igfx_index & ~3)); ++ *(volatile unsigned int *)(igfx_mmio + 0x200000 + (igfx_index & ~3)) = val; ++ return 0; ++ } ++ } ++ ++ if ( write ) { ++ switch (size) { ++ case 1: ++ outb_local(port, val); ++ break; ++ case 2: ++ outw_local(port, val); ++ break; ++ case 4: ++ outl_local(port, val); ++ break; ++ } ++ return 0; ++ } else { ++ switch (size) { ++ case 1: ++ return inb_local(port); ++ case 2: ++ return inw_local(port); ++ case 4: ++ return inl_local(port); ++ } ++ } ++ return 0; ++} ++ ++CARD8 ++emu_inb(CARD16 port) ++{ ++ return emu_io(port, 0, 1, 0); ++} ++ ++CARD16 ++emu_inw(CARD16 port) ++{ ++ return emu_io(port, 0, 2, 0); ++} ++ ++CARD32 ++emu_inl(CARD16 port) ++{ ++ return emu_io(port, 0, 4, 0); ++} ++ ++void ++emu_outb(CARD16 port, CARD8 val) ++{ ++ emu_io(port, 1, 1, val); ++} ++ ++void ++emu_outw(CARD16 port, CARD16 val) ++{ ++ emu_io(port, 1, 2, val); ++} ++ ++void emu_outl(CARD16 port, CARD32 val) ++{ ++ emu_io(port, 1, 4, val); ++} ++ ++ + int vbetool_init (void) { + if (!LRMI_init()) { + fprintf(stderr, "Failed to initialise LRMI (Linux Real-Mode Interface).\n"); + exit(1); + } +- ++ + iopl(3); + + pacc = pci_alloc(); +@@ -117,8 +238,8 @@ int main(int argc, char *argv[]) + void *rc; + int romfd = open (argv[2], O_RDWR); + +- munmap(0xc0000, 64*1024); +- rc = mmap(0xc0000, 64*1024, ++ munmap((void*)0xc0000, 64*1024); ++ rc = mmap((void*)0xc0000, 64*1024, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, romfd, 0); + } +@@ -190,12 +311,90 @@ int do_vbe_service(unsigned int AX, unsigned int BX, reg_frame * regs) + return access_ptr_register(regs, ebx); + } + ++ ++void show_size(pciaddr_t x) ++{ ++ if (!x) ++ return; ++ dprintf(" [size="); ++ if (x < 1024) ++ dprintf("%d", (int) x); ++ else if (x < 1048576) ++ dprintf("%dK", (int)(x / 1024)); ++ else if (x < 0x80000000) ++ dprintf("%dM", (int)(x / 1048576)); ++ else ++ dprintf(PCIADDR_T_FMT, x); ++ dprintf("]"); ++} ++ + int do_real_post(unsigned pci_device) + { + int error = 0; ++ int c; + struct LRMI_regs r; + memset(&r, 0, sizeof(r)); + ++ /* Emulate all IO calls */ ++ X86EMU_pioFuncs pioFuncs = { ++ (&emu_inb), ++ (&emu_inw), ++ (&emu_inl), ++ (&emu_outb), ++ (&emu_outw), ++ (&emu_outl) ++ }; ++ X86EMU_setupPioFuncs(&pioFuncs); ++ ++ struct pci_dev *p = vga_pci_dev; ++ pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES); ++ ++ /* Workaround for Intel iGFX bug */ ++ if ( p->vendor_id == 0x8086 && p->device_id == 0x2a42 ) { ++ dprintf("Activating Intel workaround\n"); ++ /* Set up IO regions the BIOS can access */ ++ dprintf("VGA PCI device: 0x%08x\n", pci_device); ++ ++ u32 mmiobase = 0; ++ for (c=0; c<6; c++) { ++ pciaddr_t pos = p->base_addr[c]; ++ pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[c] : 0; ++ u32 flg = pci_read_long(p, PCI_BASE_ADDRESS_0 + 4*c); ++ if (len) { ++ dprintf("PCI base %d: %s at 0x" PCIADDR_T_FMT, ++ c, ++ flg & PCI_BASE_ADDRESS_SPACE_IO ? "I/O" : "memory", ++ pos); ++ show_size(len); ++ dprintf("\n"); ++ if (flg & PCI_BASE_ADDRESS_SPACE_IO) { ++ igfx_ioport = pos; ++ } else if (c == 0 && len == 0x400000) { ++ mmiobase = pos; ++ } ++ } ++ } ++ if (!mmiobase) { ++ fprintf(stderr, "ERROR: No MMIO base\n"); ++ exit(1); ++ } ++ int memfd = open("/dev/mem", O_RDWR | O_SYNC); ++ if (memfd < 0) { ++ fprintf(stderr, "ERROR: Could not open /dev/mem: %s\n", ++ strerror(errno)); ++ exit(1); ++ } ++ igfx_mmio = (u32)mmap(NULL, 0x400000, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED, memfd, mmiobase); ++ if (igfx_mmio == (u32)MAP_FAILED) { ++ fprintf(stderr, "ERROR: Could not map iGFX mmio area: %s\n", ++ strerror(errno)); ++ exit(1); ++ } ++ dprintf("Intel MMIO mapped at %p\n", igfx_mmio); ++ } ++ + /* Several machines seem to want the device that they're POSTing in + here */ + r.eax = pci_device; +@@ -230,6 +429,7 @@ int do_post(void) + for (p = pacc->devices; p; p = p->next) { + c = pci_read_word(p, PCI_CLASS_DEVICE); + if (c == 0x300) { ++ vga_pci_dev = p; + pci_id = + (p->bus << 8) + (p->dev << 3) + + (p->func & 0x7); diff --git a/package/vbetool/vbetool.mk b/package/vbetool/vbetool.mk index aaf5063..74a3136 100644 --- a/package/vbetool/vbetool.mk +++ b/package/vbetool/vbetool.mk @@ -17,6 +17,7 @@ $(VBETOOL_DIR)/.unpacked: $(DL_DIR)/$(VBETOOL_SOURCE) cp package/vbetool/libx86.h $(VBETOOL_DIR) $(SED) 's#-lx86#'$(TARGET_DIR)'/usr/lib/libx86.so.1#g' $(VBETOOL_DIR)/Makefile.am $(SED) 's#-lx86#'$(TARGET_DIR)'/usr/lib/libx86.so.1#g' $(VBETOOL_DIR)/Makefile.in + toolchain/patch-kernel.sh $(VBETOOL_DIR) package/vbetool vbetool-\*.patch touch $(VBETOOL_DIR)/.unpacked $(VBETOOL_DIR)/.configured: $(VBETOOL_DIR)/.unpacked