<div dir="ltr">hw/pci-host/q35.c<div><br></div><div>this patch adds:</div><div>* redirect some PCI config reads/writes to host</div><div>* memory map BSDM, BGSM, TSEG</div><div><br></div><div><div>patch</div><div>---------------------</div></div><div><br></div><div><div>diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c</div><div>index a0a3068..05348ac 100644</div><div>--- a/hw/pci-host/q35.c</div><div>+++ b/hw/pci-host/q35.c</div><div>@@ -6,6 +6,7 @@</div><div>  *               Isaku Yamahata <yamahata at valinux co jp></div><div>  *               VA Linux Systems Japan K.K.</div><div>  * Copyright (C) 2012 Jason Baron <<a href="mailto:jbaron@redhat.com">jbaron@redhat.com</a>></div><div>+ *               2014 Andrew barnes <<a href="mailto:andy@outsideglobe.com">andy@outsideglobe.com</a>> IGD Support</div><div>  *</div><div>  * This is based on piix_pci.c, but heavily modified.</div><div>  *</div><div>@@ -30,11 +31,26 @@</div><div> #include "hw/hw.h"</div><div> #include "hw/pci-host/q35.h"</div><div> #include "qapi/visitor.h"</div><div>+#include "hw/pci/pci.h"</div><div>+#include <sys/mman.h> /* memory map functions */</div><div>+</div><div>+/* #define DEBUG_Q35 */</div><div>+#ifdef DEBUG_Q35</div><div>+# define Q35_DPRINTF(format, ...)       printf("Q35: " format, ## __VA_ARGS__)</div><div>+#else</div><div>+# define Q35_DPRINTF(format, ...)       do { } while (0)</div><div>+#endif</div><div>+</div><div>+/* for intel-spec conforming config */</div><div>+/* #define CORRECT_CONFIG */</div><div> </div><div> /****************************************************************************</div><div>  * Q35 host</div><div>  */</div><div> </div><div>+/* BEWARE: only set this if you are passing IGD through */</div><div>+static bool IGD_PASSTHROUGH = true;</div><div>+</div><div> static void q35_host_realize(DeviceState *dev, Error **errp)</div><div> {</div><div>     PCIHostState *pci = PCI_HOST_BRIDGE(dev);</div><div>@@ -284,11 +300,193 @@ static void mch_set_smm(int smm, void *arg)</div><div>     memory_region_transaction_commit();</div><div> }</div><div> </div><div>-static void mch_write_config(PCIDevice *d,</div><div>+/* TODO: Move these variables/defines to be consistent with Q35 coding style */</div><div>+MemoryRegion bdsm;</div><div>+uint32_t bdsm_host;</div><div>+MemoryRegion bgsm;</div><div>+uint32_t bgsm_host;</div><div>+MemoryRegion tseg;</div><div>+uint32_t tseg_host;</div><div>+#define MCH_CONFIG_BDSM 0xb0</div><div>+#define MCH_CONFIG_BGSM 0xb4</div><div>+#define MCH_CONFIG_TSEG 0xb8</div><div>+#define MCH_CONFIG_GMCH 0x50</div><div>+</div><div>+/* Setup memory map for Stolen Memory */</div><div>+static void mch_setup_bdsm(PCIDevice *d)</div><div>+{</div><div>+    int fd;</div><div>+    char name[64];</div><div>+    void *map;</div><div>+    bdsm_host = host_pci_read_config(0,PCI_SLOT(d->devfn),PCI_FUNC(d->devfn),MCH_CONFIG_BDSM,4);</div><div>+    int dsm_size;</div><div>+    uint16_t gmch_host = host_pci_read_config(0,PCI_SLOT(d->devfn),PCI_FUNC(d->devfn),MCH_CONFIG_GMCH,2);</div><div>+    uint16_t gmch_dsm = (gmch_host & 0xF8) >> 3;</div><div>+    MCHPCIState *mch = MCH_PCI_DEVICE(d);</div><div>+</div><div>+    Q35_DPRINTF("%s Setup BDSM: %x\n",__func__,bdsm_host);</div><div>+</div><div>+    snprintf(name, sizeof(name), "MCH-BDSM-mmap");</div><div>+    fd = open("/dev/mem", O_RDWR);</div><div>+</div><div>+    switch (gmch_dsm)</div><div>+    {</div><div>+      case 0x0: dsm_size = 0; break;</div><div>+      case 0x1: dsm_size = 32; break;</div><div>+      case 0x2: dsm_size = 64; break;</div><div>+      case 0x3: dsm_size = 96; break;</div><div>+      case 0x4: dsm_size = 128; break;</div><div>+      case 0x5: dsm_size = 160; break;</div><div>+      case 0x6: dsm_size = 192; break;</div><div>+      case 0x7: dsm_size = 224; break;</div><div>+      case 0x8: dsm_size = 256; break;</div><div>+      case 0x9: dsm_size = 288; break;</div><div>+      case 0xa: dsm_size = 320; break;</div><div>+      case 0xb: dsm_size = 352; break;</div><div>+      case 0xc: dsm_size = 384; break;</div><div>+      case 0xd: dsm_size = 416; break;</div><div>+      case 0xe: dsm_size = 448; break;</div><div>+      case 0xf: dsm_size = 480; break;</div><div>+      case 0x10: dsm_size = 512; break;</div><div>+     // default: /* panic */</div><div>+    }</div><div>+</div><div>+    dsm_size = dsm_size * 1024 * 1024;</div><div>+    map = mmap(NULL,dsm_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(bdsm_host & 0xFFF00000));</div><div>+</div><div>+    if (map == MAP_FAILED)</div><div>+    {</div><div>+        map = NULL;</div><div>+        Q35_DPRINTF("%s Setup BDSM: MAP_FAILED\n",__func__);</div><div>+    }</div><div>+</div><div>+    memory_region_init_ram_ptr(&bdsm, OBJECT(mch), name, dsm_size, map);</div><div>+}</div><div>+</div><div>+/* this function memory maps the region of host memory assigned to Stolen memory</div><div>+ * to the guest location provided by seabios. */</div><div>+static void mch_map_bdsm(PCIDevice *d, uint32_t bdsm_new)</div><div>+{</div><div>+    MemoryRegion *guest_memory = get_system_memory();</div><div>+    uint32_t bdsm_current = pci_default_read_config(d,MCH_CONFIG_BDSM,4);</div><div>+</div><div>+    if ( bdsm_current != bdsm_host && bdsm_current != 0 )</div><div>+    {</div><div>+        // remap</div><div>+        Q35_DPRINTF("%s Delete BDSM mapping: %x\n",__func__,(bdsm_current & 0xFFF00000));</div><div>+        memory_region_del_subregion(guest_memory, &bdsm);</div><div>+    }</div><div>+    Q35_DPRINTF("%s Add BDSM mapping: %x -> %x\n",__func__,bdsm_host,bdsm_new);</div><div>+    memory_region_add_subregion(guest_memory, (bdsm_new & 0xFFF00000), &bdsm);</div><div>+}</div><div>+</div><div>+/* Setup memory map for GTT Stolen Memory */</div><div>+static void mch_setup_bgsm(PCIDevice *d)</div><div>+{</div><div>+    int fd;</div><div>+    char name[64];</div><div>+    void *map;</div><div>+    bgsm_host = host_pci_read_config(0,PCI_SLOT(d->devfn),PCI_FUNC(d->devfn),MCH_CONFIG_BGSM,4);</div><div>+    int gsm_size;</div><div>+    uint16_t gmch_host = host_pci_read_config(0,PCI_SLOT(d->devfn),PCI_FUNC(d->devfn),MCH_CONFIG_GMCH,2);</div><div>+    uint16_t gmch_gsm = (gmch_host & 0x300) >> 8;</div><div>+    MCHPCIState *mch = MCH_PCI_DEVICE(d);</div><div>+</div><div>+    Q35_DPRINTF("%s Setup BGSM: %x\n",__func__,bgsm_host);</div><div>+</div><div>+    snprintf(name, sizeof(name), "MCH %04x:%02x:%02x.%x BGSM mmap",</div><div>+             0, 0, 0, 0);</div><div>+</div><div>+    fd = open("/dev/mem", O_RDWR);</div><div>+</div><div>+    switch (gmch_gsm)</div><div>+    {</div><div>+      case 0x2: gsm_size = 2; break;</div><div>+      case 0x1: gsm_size = 1; break;</div><div>+      case 0x0: gsm_size = 0; break;</div><div>+     // default: /* panic */</div><div>+    }</div><div>+</div><div>+    gsm_size = gsm_size * 1024 * 1024;</div><div>+</div><div>+    map = mmap(NULL,gsm_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(bgsm_host & 0xFFF00000));</div><div>+    if (map == MAP_FAILED)</div><div>+    {</div><div>+        map = NULL;</div><div>+        Q35_DPRINTF("%s Setup BGSM: MAP_FAILED\n",__func__);</div><div>+    }</div><div>+</div><div>+    memory_region_init_ram_ptr(&bgsm, OBJECT(mch), name, gsm_size, map);</div><div>+}</div><div>+</div><div>+/* this function memory maps the region of host memory assigned to GTT Stolen memory</div><div>+ * to the guest location provided by seabios. */</div><div>+static void mch_map_bgsm(PCIDevice *d, uint32_t bgsm_new)</div><div>+{</div><div>+    MemoryRegion *guest_memory = get_system_memory();</div><div>+    uint32_t bgsm_current = pci_default_read_config(d,MCH_CONFIG_BGSM,4);</div><div>+</div><div>+    if ( bgsm_current != bgsm_host && bgsm_current != 0)</div><div>+    {</div><div>+        // remap</div><div>+        Q35_DPRINTF("%s Delete BGSM mapping: %x\n",__func__,(bgsm_current & 0xFFF00000));</div><div>+        memory_region_del_subregion(guest_memory, &bgsm);</div><div>+    }</div><div>+    Q35_DPRINTF("%s Add BGSM mapping: %x -> %x\n",__func__,bgsm_host,bgsm_new);</div><div>+    memory_region_add_subregion(guest_memory, (bgsm_new & 0xFFF00000), &bgsm);</div><div>+}</div><div>+</div><div>+/* Setup memory map for TSEG */</div><div>+static void mch_setup_tseg(PCIDevice *d)</div><div>+{</div><div>+    int fd;</div><div>+    char name[64];</div><div>+    void *map;</div><div>+    tseg_host = host_pci_read_config(0,PCI_SLOT(d->devfn),PCI_FUNC(d->devfn),MCH_CONFIG_TSEG,4);</div><div>+    int tseg_size = 8 * 1024 * 1024;</div><div>+    MCHPCIState *mch = MCH_PCI_DEVICE(d);</div><div>+</div><div>+    Q35_DPRINTF("%s Setup TSEG: %x\n",__func__,tseg_host);</div><div>+</div><div>+    snprintf(name, sizeof(name), "MCH-TSEG-mmap");</div><div>+</div><div>+    fd = open("/dev/mem", O_RDWR);</div><div>+</div><div>+    map = mmap(NULL,tseg_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(tseg_host & 0xFFF00000));</div><div>+    if (map == MAP_FAILED)</div><div>+    {</div><div>+        map = NULL;</div><div>+        Q35_DPRINTF("%s Setup TSEG: MAP_FAILED\n",__func__);</div><div>+    }</div><div>+</div><div>+    memory_region_init_ram_ptr(&tseg, OBJECT(mch), name, tseg_size, map);</div><div>+}</div><div>+</div><div>+/* this function memory maps the region of host memory assigned to TSEG</div><div>+ * to the guest location provided by seabios. */</div><div>+static void mch_map_tseg(PCIDevice *d, uint32_t tseg_new)</div><div>+{</div><div>+    MemoryRegion *guest_memory = get_system_memory();</div><div>+    uint32_t tseg_current = pci_default_read_config(d,MCH_CONFIG_TSEG,4);</div><div>+</div><div>+    if ( tseg_current != tseg_host && tseg_current != 0)</div><div>+    {</div><div>+        // remap</div><div>+        Q35_DPRINTF("%s Delete TSEG mapping: %x\n",__func__,(tseg_current & 0xFFF00000));</div><div>+        memory_region_del_subregion(guest_memory, &tseg);</div><div>+    }</div><div>+    Q35_DPRINTF("%s Add TSEG mapping: %x -> %x\n",__func__,tseg_host,tseg_new);</div><div>+    memory_region_add_subregion(guest_memory, (tseg_new & 0xFFF00000), &tseg);</div><div>+}</div><div>+</div><div>+static void mch_write_config_default(PCIDevice *d,</div><div>                               uint32_t address, uint32_t val, int len)</div><div> {</div><div>     MCHPCIState *mch = MCH_PCI_DEVICE(d);</div><div> </div><div>+    Q35_DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,</div><div>+                0000, 00, PCI_SLOT(d->devfn),PCI_FUNC(d->devfn), address, len, val);</div><div>+</div><div>     /* XXX: implement SMRAM.D_LOCK */</div><div>     pci_default_write_config(d, address, val, len);</div><div> </div><div>@@ -308,6 +506,73 @@ static void mch_write_config(PCIDevice *d,</div><div>     }</div><div> }</div><div> </div><div>+static void mch_write_config(PCIDevice *d,</div><div>+                             uint32_t address, uint32_t val, int len)</div><div>+{</div><div>+    Q35_DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,</div><div>+                0000, 00, PCI_SLOT(d->devfn),PCI_FUNC(d->devfn), address, len, val);</div><div>+</div><div>+    /* PAVPC - Protected Audio Video Path Control */</div><div>+    if (IGD_PASSTHROUGH && ranges_overlap(address, len, 0x58, 4))</div><div>+    {</div><div>+        host_pci_write_config(0,PCI_SLOT(d->devfn),PCI_FUNC(d->devfn),address,len,val);</div><div>+    }</div><div>+    /* BDSM - */</div><div>+    else if (IGD_PASSTHROUGH && ranges_overlap(address, len, MCH_CONFIG_BDSM, 4))</div><div>+    {</div><div>+        mch_map_bdsm(d,val);</div><div>+        mch_write_config_default(d,address,val,len);</div><div>+    }</div><div>+    /* BGSM - */</div><div>+    else if (IGD_PASSTHROUGH && ranges_overlap(address, len, MCH_CONFIG_BGSM, 4))</div><div>+    {</div><div>+        mch_map_bgsm(d,val);</div><div>+        mch_write_config_default(d,address,val,len);</div><div>+    }</div><div>+    /* TSEG - */</div><div>+    else if (IGD_PASSTHROUGH && ranges_overlap(address, len, MCH_CONFIG_TSEG, 4))</div><div>+    {</div><div>+        mch_map_tseg(d,val);</div><div>+        mch_write_config_default(d,address,val,len);</div><div>+    }</div><div>+    else</div><div>+    {</div><div>+        mch_write_config_default(d,address,val,len);</div><div>+    }</div><div>+}</div><div>+</div><div>+static uint32_t mch_read_config(PCIDevice *d,</div><div>+                                uint32_t address, int len)</div><div>+{</div><div>+    uint32_t val;</div><div>+</div><div>+    if (IGD_PASSTHROUGH)</div><div>+    {</div><div>+        if (ranges_overlap(address, len, 0x2c, 2) || /* SVID - Subsystem Vendor Identification */</div><div>+            ranges_overlap(address, len, 0x2e, 2) || /* SID - Subsystem Identification */</div><div>+            ranges_overlap(address, len, 0x50, 2) || /* GMCH - SNB Graphics Control Register */</div><div>+            ranges_overlap(address, len, 0x58, 4))   /* PAVPC - Protected Audio Video Path Control  */</div><div>+        {</div><div>+            val = host_pci_read_config(0,PCI_SLOT(d->devfn),PCI_FUNC(d->devfn),address,len);</div><div>+        }</div><div>+        else</div><div>+        {</div><div>+            goto defaultread;</div><div>+        }</div><div>+    }</div><div>+    else</div><div>+    {</div><div>+defaultread:</div><div>+        val = pci_default_read_config(d,address,len);</div><div>+    }</div><div>+</div><div>+    Q35_DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,</div><div>+                0000, 00, PCI_SLOT(d->devfn),PCI_FUNC(d->devfn), address, len, val);</div><div>+</div><div>+    return val;</div><div>+</div><div>+}</div><div>+</div><div> static void mch_update(MCHPCIState *mch)</div><div> {</div><div>     mch_update_pciexbar(mch);</div><div>@@ -370,6 +635,69 @@ static int mch_init(PCIDevice *d)</div><div>                  &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,</div><div>                  PAM_EXPAN_SIZE);</div><div>     }</div><div>+</div><div>+    mch_setup_bdsm(d);</div><div>+    mch_setup_bgsm(d);</div><div>+    mch_setup_tseg(d);</div><div>+</div><div>+    /* Unsure if this is important. but the following is as per INTEL spec</div><div>+     * which otherwise is non-conforming. */</div><div>+#ifdef CORRECT_CONFIG</div><div>+    /* PCICMD Register */</div><div>+    pci_set_word(d->wmask + D0F0_PCICMD,(D0F0_PCICMD_SERR | D0F0_PCICMD_PERR)); // set writable</div><div>+    pci_set_word(d->config + D0F0_PCICMD,(D0F0_PCICMD_MAE | D0F0_PCICMD_BME)); // set 1</div><div>+</div><div>+    /* PCISTS Register */</div><div>+    pci_set_word(d->w1cmask + D0F0_PCISTS,(D0F0_PCISTS_DPE | D0F0_PCISTS_SSE | D0F0_PCISTS_RMAS |</div><div>+                  D0F0_PCISTS_RTAS | D0F0_PCISTS_DPD));</div><div>+    pci_set_word(d->config + D0F0_PCISTS,(D0F0_PCISTS_CLIST | D0F0_PCISTS_FB2B));</div><div>+</div><div>+    /* CC Register */</div><div>+    /* No RW Registers */</div><div>+    //pci_set_byte(d->config + D0F0_CC + D0F0_CC_BCC, 0x06); /* indicating a bridge device */</div><div>+</div><div>+    /* HDR Register */</div><div>+    /* No RW Registers */</div><div>+    /* !nnz */</div><div>+</div><div>+    /* SVID and SID need not be changed */</div><div>+</div><div>+    /* PXPEPBAR - TODO? */</div><div>+    pci_set_quad(d->wmask + D0F0_PXPEPBAR, (D0F0_PXPEPBAR_PXPEPBAR | D0F0_PXPEPBAR_PXPEPBAREN)); // set writable</div><div>+</div><div>+    /* MCHBAR - TODO? */</div><div>+    pci_set_quad(d->wmask + D0F0_MCHBAR, (D0F0_MCHBAR_MCHBAR | D0F0_MCHBAR_MCHBAREN)); // set writable</div><div>+</div><div>+    /* GGC-GMCH */</div><div>+    /* RW Registers can be locked by GCCLCK - TODO, assumed RO */</div><div>+    //pci_set_word(d->config + D0F0_GGC, (data & (D0F0_GGC_VAMEN | D0F0_GGC_GGMS | D0F0_GGC_GMS | D0F0_GGC_GGCLCK)));</div><div>+</div><div>+    /* DEVEN */</div><div>+    pci_set_long(d->wmask + D0F0_DEVEN, D0F0_DEVEN_D0EN);</div><div>+    pci_set_long(d->config + D0F0_DEVEN, D0F0_DEVEN_D2EN);</div><div>+</div><div>+    /* DMIBAR */</div><div>+    pci_set_quad(d->wmask + D0F0_DMIBAR, (D0F0_DMIBAR_DMIBAR | D0F0_DMIBAR_DMIBAREN)); // set writable</div><div>+</div><div>+    /* TOM - Top Of Memory Register */</div><div>+    pci_set_quad(d->wmask + D0F0_TOM, (D0F0_TOM_TOM | D0F0_TOM_LOCK ));</div><div>+</div><div>+    /* TOUUD - Top Of Upper Usable DRAM Register */</div><div>+    pci_set_quad(d->wmask + D0F0_TOUUD, (D0F0_TOUUD_TOUUD | D0F0_TOUUD_LOCK ));</div><div>+</div><div>+    /* BDSM - Base Data of Stolen Memory Register */</div><div>+    pci_set_long(d->wmask + D0F0_BDSM, (D0F0_BDSM_BDSM | D0F0_BDSM_LOCK));</div><div>+</div><div>+    /* BGSM - Base of GTT Stolen Memory Register */</div><div>+    pci_set_long(d->wmask + D0F0_BGSM, (D0F0_BGSM_BGSM | D0F0_BGSM_LOCK));</div><div>+</div><div>+    /* TSEG - G Memory Base Register */</div><div>+    pci_set_long(d->wmask + D0F0_TSEG, (D0F0_TSEG_TSEGMB | D0F0_TSEG_LOCK));</div><div>+</div><div>+    /* TOLUD - Top of Low Usable DRAM */</div><div>+    pci_set_long(d->wmask + D0F0_TOLUD, (D0F0_TOLUD_TOLUD | D0F0_TOLUD_LOCK));</div><div>+#endif</div><div>+</div><div>     return 0;</div><div> }</div><div> </div><div>@@ -390,6 +718,7 @@ static void mch_class_init(ObjectClass *klass, void *data)</div><div> </div><div>     k->init = mch_init;</div><div>     k->config_write = mch_write_config;</div><div>+    k->config_read = mch_read_config;</div><div>     dc->reset = mch_reset;</div><div>     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);</div><div>     dc->desc = "Host bridge";</div><div>@@ -403,6 +732,16 @@ static void mch_class_init(ObjectClass *klass, void *data)</div><div>      * host-facing part, which can't be device_add'ed, yet.</div><div>      */</div><div>     dc->cannot_instantiate_with_device_add_yet = true;</div><div>+</div><div>+    /* XEN code suggests these values should match the host.</div><div>+     * However, it's not that simple because currently seabios expects</div><div>+     * either PII3X or Q35.</div><div>+     * Further more, I have only found reason for the LPC to match the host</div><div>+     * for the PCH identification. No mention about the host-bridge. */</div><div>+</div><div>+//    k->vendor_id = host_pci_read_config(0,0,0,0x00,2);</div><div>+//    k->device_id = host_pci_read_config(0,0,0,0x02,2);</div><div>+//    k->revision = host_pci_read_config(0,0,0,0x08,1);</div><div> }</div><div> </div><div> static const TypeInfo mch_info = {</div></div></div>