|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH for-4.17] x86/pci: allow BARs to be positioned on e820 reserved regions
On Wed, Oct 05, 2022 at 10:53:38AM +0200, Jan Beulich wrote:
> On 05.10.2022 10:37, Roger Pau Monné wrote:
> > On Tue, Oct 04, 2022 at 06:11:50PM +0200, Jan Beulich wrote:
> >> On 04.10.2022 17:36, Roger Pau Monne wrote:
> >>> The EFI memory map contains two memory types (EfiMemoryMappedIO and
> >>> EfiMemoryMappedIOPortSpace) used to describe IO memory areas used by
> >>> EFI firmware.
> >>>
> >>> The current parsing of the EFI memory map is translating
> >>> EfiMemoryMappedIO to E820_RESERVED on x86. This causes issues on some
> >>> boxes as the firmware is relying on using those regions to position
> >>> the BARs of devices being used (possibly during runtime) for the
> >>> firmware.
> >>>
> >>> Xen will disable memory decoding on any device that has BARs
> >>> positioned over any regions on the e820 memory map, hence the firmware
> >>> will malfunction after Xen turning off memory decoding for the
> >>> device(s) that have BARs mapped in EfiMemoryMappedIO regions.
> >>>
> >>> The system under which this was observed has:
> >>>
> >>> EFI memory map:
> >>> [...]
> >>> 00000fd000000-00000fe7fffff type=11 attr=800000000000100d
> >>> [...]
> >>> 0000:00:1f.5 disabled: BAR [0xfe010, 0xfe010] overlaps with memory map
> >>>
> >>> The device behind this BAR is:
> >>>
> >>> 00:1f.5 Serial bus controller [0c80]: Intel Corporation Lewisburg SPI
> >>> Controller (rev 09)
> >>> Subsystem: Super Micro Computer Inc Device 091c
> >>> Flags: fast devsel
> >>> Memory at fe010000 (32-bit, non-prefetchable) [size=4K]well
> >>>
> >>> For the record, the symptom observed in that machine was a hard freeze
> >>> when attempting to set an EFI variable (XEN_EFI_set_variable).
> >>>
> >>> Fix by allowing BARs of PCI devices to be positioned over reserved
> >>> memory regions, but print a warning message about such overlap.
> >>
> >> Somewhat hesitantly I might ack this change, but I'd like to give
> >> others (Andrew in particular) some time to voice their views. As
> >> said during the earlier discussion - I think we're relaxing things
> >> too much by going this route.
> >
> > Another option would be to explicitly check in efi_memmap for
> > EfiMemoryMappedIO regions and BAR overlap and only allow those. That
> > would be more cumbersome code wise AFAICT.
>
> Indeed there's a question of balancing well here, between two outcomes
> neither of which is really desirable.
Hm, I have the following diff attached below which is more limited,
and not so bad I think. Initially I wanted to introduce an
efi_all_mapped() helper, but that would require exposing EFI_MEMORY_TYPE
which is quite intrusive.
Let me know if you think the proposal below is better and I will
formally send a patch with it.
Thanks, Roger.
---
diff --git a/xen/arch/x86/include/asm/pci.h b/xen/arch/x86/include/asm/pci.h
index f4a58c8acf..c8e1a9ecdb 100644
--- a/xen/arch/x86/include/asm/pci.h
+++ b/xen/arch/x86/include/asm/pci.h
@@ -57,14 +57,4 @@ static always_inline bool is_pci_passthrough_enabled(void)
void arch_pci_init_pdev(struct pci_dev *pdev);
-static inline bool pci_check_bar(const struct pci_dev *pdev,
- mfn_t start, mfn_t end)
-{
- /*
- * Check if BAR is not overlapping with any memory region defined
- * in the memory map.
- */
- return is_memory_hole(start, end);
-}
-
#endif /* __X86_PCI_H__ */
diff --git a/xen/arch/x86/pci.c b/xen/arch/x86/pci.c
index 97b792e578..c3737e226d 100644
--- a/xen/arch/x86/pci.c
+++ b/xen/arch/x86/pci.c
@@ -4,6 +4,7 @@
* Architecture-dependent PCI access functions.
*/
+#include <xen/efi.h>
#include <xen/spinlock.h>
#include <xen/pci.h>
#include <asm/io.h>
@@ -98,3 +99,28 @@ int pci_conf_write_intercept(unsigned int seg, unsigned int
bdf,
return rc;
}
+
+bool pci_check_bar(const struct pci_dev *pdev, mfn_t start, mfn_t end)
+{
+ /*
+ * Check if BAR is not overlapping with any memory region defined
+ * in the memory map.
+ */
+ if ( is_memory_hole(start, end) )
+ return true;
+
+ /*
+ * Also allow BARs placed on EfiMemoryMappedIO regions in order to deal
+ * with EFI firmware using those regions to place the BARs of devices that
+ * can be used during runtime. But print a warning when doing so.
+ */
+ if ( !efi_all_runtime_mmio(mfn_to_maddr(start),
+ mfn_to_maddr(mfn_add(end, 1))) )
+ return false;
+
+ printk(XENLOG_WARNING
+ "%pp: BAR [%#" PRI_mfn ", %#" PRI_mfn "] overlaps reserved
region\n",
+ &pdev->sbdf, mfn_x(start), mfn_x(end));
+
+ return true;
+}
diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c
index 13b0975866..b69c710ce3 100644
--- a/xen/common/efi/runtime.c
+++ b/xen/common/efi/runtime.c
@@ -78,6 +78,30 @@ bool efi_enabled(unsigned int feature)
return test_bit(feature, &efi_flags);
}
+/*
+ * This function checks if the entire range [start,end) is contained inside of
+ * a single EfiMemoryMappedIO descriptor with the runtime attribute set.
+ */
+bool efi_all_runtime_mmio(uint64_t start, uint64_t end)
+{
+ unsigned int i;
+
+ for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+ {
+ EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+ uint64_t len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+
+ if ( desc->Type != EfiMemoryMappedIO ||
+ !(desc->Attribute & EFI_MEMORY_RUNTIME) )
+ continue;
+
+ if ( start >= desc->PhysicalStart && end <= desc->PhysicalStart + len )
+ return true;
+ }
+
+ return false;
+}
+
#ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
struct efi_rs_state efi_rs_enter(void)
diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h
index 94a7e547f9..f29ea1a320 100644
--- a/xen/include/xen/efi.h
+++ b/xen/include/xen/efi.h
@@ -45,6 +45,8 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *);
int efi_compat_get_info(uint32_t idx, union compat_pf_efi_info *);
int efi_compat_runtime_call(struct compat_pf_efi_runtime_call *);
+bool efi_all_runtime_mmio(uint64_t start, uint64_t end);
+
#endif /* !__ASSEMBLY__ */
#endif /* __XEN_EFI_H__ */
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index 5975ca2f30..64995fc68d 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -211,6 +211,7 @@ unsigned int pci_size_mem_bar(pci_sbdf_t sbdf, unsigned int
pos,
void pci_intx(const struct pci_dev *, bool enable);
bool_t pcie_aer_get_firmware_first(const struct pci_dev *);
+bool pci_check_bar(const struct pci_dev *pdev, mfn_t start, mfn_t end);
struct pirq;
int msixtbl_pt_register(struct domain *, struct pirq *, uint64_t gtable);
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |