Created
April 4, 2016 09:33
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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