]> xenbits.xensource.com Git - xenclient/build.git/commitdiff
[package/vbetool] Add workaround for iGFX I/O bug
authorThomas Horsten <thomas.horsten@citrix.com>
Wed, 14 Oct 2009 16:12:30 +0000 (17:12 +0100)
committerThomas Horsten <thomas.horsten@citrix.com>
Wed, 14 Oct 2009 16:37:02 +0000 (17:37 +0100)
Translate I/O accesses to write to GTT into corresponding MMIO
(cherry picked from commit 4043180ed1fb12e7c8f7f1ccae7d95263cc9355f)

package/vbetool/vbetool-igfx-io-to-mmio.patch [new file with mode: 0644]
package/vbetool/vbetool.mk

diff --git a/package/vbetool/vbetool-igfx-io-to-mmio.patch b/package/vbetool/vbetool-igfx-io-to-mmio.patch
new file mode 100644 (file)
index 0000000..55beb2b
--- /dev/null
@@ -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 <pci/config.h>
+ #include <pci/pci.h>
+ #include <assert.h>
+ #include <stdio.h>
+@@ -24,6 +25,8 @@ version 2
+ #include <sys/mman.h>
+ #include <libx86.h>
++#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);
index aaf5063d55d8784b663989ab179d6732bd5ad305..74a3136ddbe9a5b446575318983b884a000e42a4 100644 (file)
@@ -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