Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save nonakap/6bb824a7410aec45dd080adb782aa495 to your computer and use it in GitHub Desktop.

Select an option

Save nonakap/6bb824a7410aec45dd080adb782aa495 to your computer and use it in GitHub Desktop.
PR/50453: Check overlaid MCHBAR region on PCIEXBAR region. http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50453
From cdb327e33f60d3f230e6a2dec3012afc1d1a6c5e Mon Sep 17 00:00:00 2001
From: NONAKA Kimihiro <[email protected]>
Date: Tue, 2 Feb 2016 20:45:31 +0900
Subject: [PATCH 1/1] PR/50453: Check overlaid MCHBAR region on PCIEXBAR
region.
---
sys/arch/x86/acpi/acpi_machdep.c | 72 ++++++++++++++++++++++++++++++++++++++++
sys/dev/acpi/acpi_mcfg.c | 19 +++++++++++
sys/dev/acpi/acpi_mcfg.h | 7 +++-
3 files changed, 97 insertions(+), 1 deletion(-)
diff --git a/sys/arch/x86/acpi/acpi_machdep.c b/sys/arch/x86/acpi/acpi_machdep.c
index e5b892d..f22065e 100644
--- a/sys/arch/x86/acpi/acpi_machdep.c
+++ b/sys/arch/x86/acpi/acpi_machdep.c
@@ -67,6 +67,7 @@ __KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.12 2016/01/28 23:50:04 htodd Exp
#include <x86/efi.h>
#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
@@ -410,6 +411,76 @@ acpi_md_mcfg_validate(uint64_t addr, int bus_start, int *bus_end)
return false;
}
+static bool
+acpi_md_mcfg_validate_dev(pci_chipset_tag_t pc, pcitag_t tag)
+{
+ uint64_t pciexbar, pciexbar_size, pciexbar_mask;
+ uint64_t mchbar, mchbar_size;
+ uint64_t devoff, baroff;
+ pcitag_t pchb_tag;
+ pcireg_t id;
+ int bus, dev;
+
+ pci_decompose_tag(pc, tag, &bus, &dev, NULL);
+
+ pchb_tag = pci_make_tag(pc, 0, 0, 0);
+ id = pci_conf_read(pc, pchb_tag, PCI_ID_REG);
+ switch (PCI_VENDOR(id)) {
+ case PCI_VENDOR_INTEL:
+ switch (PCI_PRODUCT(id)) {
+ case PCI_PRODUCT_INTEL_PINEVIEW_HB:
+ /* Check overlaid MCHBAR region */
+ pciexbar = pci_conf_read(pc, pchb_tag, 0x60);
+ pciexbar |=
+ (uint64_t)pci_conf_read(pc, pchb_tag, 0x64) << 32;
+ if (!(pciexbar & 1))
+ return false; /* PCIEXBAR is disabled */
+ switch ((pciexbar >> 1) & 3) {
+ case 0:
+ pciexbar_size = 256 * 1024 * 1024;
+ pciexbar_mask = 0xff0000000ULL;
+ break;
+ case 1:
+ pciexbar_size = 128 * 1024 * 1024;
+ pciexbar_mask = 0xff8000000ULL;
+ break;
+ case 2:
+ pciexbar_size = 64 * 1024 * 1024;
+ pciexbar_mask = 0xffc000000ULL;
+ break;
+ default:
+ /* reserved */
+ return false;
+ }
+ pciexbar &= pciexbar_mask;
+
+ mchbar = pci_conf_read(pc, pchb_tag, 0x48);
+ mchbar |=
+ (uint64_t)pci_conf_read(pc, pchb_tag, 0x4c) << 32;
+ if (!(mchbar & 1))
+ break; /* MCHBAR is disabled */
+ mchbar_size = 16 * 1024;
+ mchbar &= ~1;
+
+ if (mchbar < pciexbar &&
+ mchbar + mchbar_size < pciexbar)
+ break;
+ if (mchbar >= pciexbar + pciexbar_size)
+ break;
+
+ baroff = mchbar - pciexbar;
+ devoff = bus * ACPIMCFG_SIZE_PER_BUS +
+ dev * ACPIMCFG_SIZE_PER_DEV;
+ if (baroff >= devoff &&
+ baroff < devoff + ACPIMCFG_SIZE_PER_DEV)
+ return false; /* overlaid */
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
static uint32_t
acpi_md_mcfg_read(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr)
{
@@ -436,6 +507,7 @@ acpi_md_mcfg_write(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr,
static const struct acpimcfg_ops acpi_md_mcfg_ops = {
.ao_validate = acpi_md_mcfg_validate,
+ .ao_validate_dev = acpi_md_mcfg_validate_dev,
.ao_read = acpi_md_mcfg_read,
.ao_write = acpi_md_mcfg_write,
diff --git a/sys/dev/acpi/acpi_mcfg.c b/sys/dev/acpi/acpi_mcfg.c
index 6336c51..c876acf 100644
--- a/sys/dev/acpi/acpi_mcfg.c
+++ b/sys/dev/acpi/acpi_mcfg.c
@@ -74,6 +74,7 @@ static struct acpi_softc *acpi_sc;
static const struct acpimcfg_ops mcfg_default_ops = {
.ao_validate = acpimcfg_default_validate,
+ .ao_validate_dev = acpimcfg_default_validate_dev,
.ao_read = acpimcfg_default_read,
.ao_write = acpimcfg_default_write,
@@ -91,6 +92,14 @@ acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end)
return true;
}
+bool
+acpimcfg_default_validate_dev(pci_chipset_tag_t pc, pcitag_t tag)
+{
+
+ /* Always Ok */
+ return true;
+}
+
uint32_t
acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh,
bus_addr_t addr)
@@ -566,6 +575,16 @@ acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus)
/* Probe extended configuration space of all devices. */
memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs));
+ if (mcfg_ops->ao_validate_dev != NULL) {
+ for (i = 0; i < 32; i++) {
+ if (!mcfg_ops->ao_validate_dev(pc,
+ pci_make_tag(pc, bus, i, 0))) {
+ for (j = 0; j < 8; j++) {
+ EXTCONF_SET_INVALID(mb, i, j);
+ }
+ }
+ }
+ }
mb->valid_ndevs = 0;
mb->last_probed = pci_make_tag(pc, bus, 0, 0);
diff --git a/sys/dev/acpi/acpi_mcfg.h b/sys/dev/acpi/acpi_mcfg.h
index b67c360..98c9352 100644
--- a/sys/dev/acpi/acpi_mcfg.h
+++ b/sys/dev/acpi/acpi_mcfg.h
@@ -40,6 +40,9 @@ struct acpimcfg_ops {
/* validate MCFG memory region */
bool (*ao_validate)(uint64_t, int, int *);
+ /* validate device */
+ bool (*ao_validate_dev)(pci_chipset_tag_t, pcitag_t);
+
/* override default bus_space(9) function */
uint32_t (*ao_read)(bus_space_tag_t, bus_space_handle_t,
bus_addr_t);
@@ -47,9 +50,11 @@ struct acpimcfg_ops {
bus_addr_t, uint32_t);
};
-#define ACPIMCFG_SIZE_PER_BUS (PCI_EXTCONF_SIZE * 32/*dev*/ * 8/*func*/)
+#define ACPIMCFG_SIZE_PER_DEV (PCI_EXTCONF_SIZE * 8/*func*/)
+#define ACPIMCFG_SIZE_PER_BUS (ACPIMCFG_SIZE_PER_DEV * 32/*dev*/)
bool acpimcfg_default_validate(uint64_t, int, int *);
+bool acpimcfg_default_validate_dev(pci_chipset_tag_t, pcitag_t);
uint32_t acpimcfg_default_read(bus_space_tag_t, bus_space_handle_t,
bus_addr_t);
void acpimcfg_default_write(bus_space_tag_t, bus_space_handle_t,
--
2.7.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment