The bitmap an earlier kernel filled in gets in this one through EFI,
but nothing reads it back yet.

Introduce range_contains_poisoned_memory(), which the page allocator
will use to ask about a block before handing it out.

Signed-off-by: Breno Leitao <[email protected]>
---
 drivers/firmware/efi/poison.c | 29 +++++++++++++++++++++++++++++
 include/linux/mm.h            | 14 ++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/firmware/efi/poison.c b/drivers/firmware/efi/poison.c
index 847592862f01d3..4e5cad0d1b9b65 100644
--- a/drivers/firmware/efi/poison.c
+++ b/drivers/firmware/efi/poison.c
@@ -101,6 +101,35 @@ static struct linux_efi_poisoned_memory 
*efi_poisoned_memory(void)
        return phys_to_virt(efi.poisoned_memory);
 }
 
+/* Does the range cover a unit an earlier kernel recorded as bad? */
+bool range_contains_poisoned_memory(phys_addr_t start, unsigned long size)
+{
+       struct linux_efi_poisoned_memory *pm = efi_poisoned_memory();
+       u64 first, last, nbits;
+       phys_addr_t end;
+
+       if (!pm)
+               return false;
+
+       nbits = pm->size * BITS_PER_BYTE;
+       end = start + size - 1;
+
+       /* Clamp the start into the table, but keep the caller's end. */
+       if (end < pm->phys_base)
+               return false;
+       if (start < pm->phys_base)
+               start = pm->phys_base;
+
+       first = (start - pm->phys_base) / pm->unit_size;
+       if (first >= nbits)
+               return false;
+
+       last = (end - pm->phys_base) / pm->unit_size;
+       last = min(last, nbits - 1);
+
+       return find_next_bit(pm->bitmap, last + 1, first) <= last;
+}
+
 /*
  * A bit is never cleared: it stands for a whole EFI_POISON_UNIT_SIZE, so an
  * unpoison cannot tell whether the unit as a whole is good again.
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 274fa880077c54..b68824fcfbef19 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -5387,6 +5387,20 @@ static inline bool pfn_is_unaccepted_memory(unsigned 
long pfn)
        return range_contains_unaccepted_memory(pfn << PAGE_SHIFT, PAGE_SIZE);
 }
 
+#ifdef CONFIG_EFI_POISONED_MEMORY
+
+bool range_contains_poisoned_memory(phys_addr_t start, unsigned long size);
+
+#else
+
+static inline bool range_contains_poisoned_memory(phys_addr_t start,
+                                                 unsigned long size)
+{
+       return false;
+}
+
+#endif
+
 void vma_pgtable_walk_begin(struct vm_area_struct *vma);
 void vma_pgtable_walk_end(struct vm_area_struct *vma);
 

-- 
2.53.0-Meta


Reply via email to