aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/platform/efi/efi.c66
-rw-r--r--include/linux/efi.h1
2 files changed, 67 insertions, 0 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 936a488d6cf6..274dfc481849 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -210,6 +210,70 @@ int __init efi_memblock_x86_reserve_range(void)
210 return 0; 210 return 0;
211} 211}
212 212
213#define OVERFLOW_ADDR_SHIFT (64 - EFI_PAGE_SHIFT)
214#define OVERFLOW_ADDR_MASK (U64_MAX << OVERFLOW_ADDR_SHIFT)
215#define U64_HIGH_BIT (~(U64_MAX >> 1))
216
217static bool __init efi_memmap_entry_valid(const efi_memory_desc_t *md, int i)
218{
219 u64 end = (md->num_pages << EFI_PAGE_SHIFT) + md->phys_addr - 1;
220 u64 end_hi = 0;
221 char buf[64];
222
223 if (md->num_pages == 0) {
224 end = 0;
225 } else if (md->num_pages > EFI_PAGES_MAX ||
226 EFI_PAGES_MAX - md->num_pages <
227 (md->phys_addr >> EFI_PAGE_SHIFT)) {
228 end_hi = (md->num_pages & OVERFLOW_ADDR_MASK)
229 >> OVERFLOW_ADDR_SHIFT;
230
231 if ((md->phys_addr & U64_HIGH_BIT) && !(end & U64_HIGH_BIT))
232 end_hi += 1;
233 } else {
234 return true;
235 }
236
237 pr_warn_once(FW_BUG "Invalid EFI memory map entries:\n");
238
239 if (end_hi) {
240 pr_warn("mem%02u: %s range=[0x%016llx-0x%llx%016llx] (invalid)\n",
241 i, efi_md_typeattr_format(buf, sizeof(buf), md),
242 md->phys_addr, end_hi, end);
243 } else {
244 pr_warn("mem%02u: %s range=[0x%016llx-0x%016llx] (invalid)\n",
245 i, efi_md_typeattr_format(buf, sizeof(buf), md),
246 md->phys_addr, end);
247 }
248 return false;
249}
250
251static void __init efi_clean_memmap(void)
252{
253 efi_memory_desc_t *out = efi.memmap.map;
254 const efi_memory_desc_t *in = out;
255 const efi_memory_desc_t *end = efi.memmap.map_end;
256 int i, n_removal;
257
258 for (i = n_removal = 0; in < end; i++) {
259 if (efi_memmap_entry_valid(in, i)) {
260 if (out != in)
261 memcpy(out, in, efi.memmap.desc_size);
262 out = (void *)out + efi.memmap.desc_size;
263 } else {
264 n_removal++;
265 }
266 in = (void *)in + efi.memmap.desc_size;
267 }
268
269 if (n_removal > 0) {
270 u64 size = efi.memmap.nr_map - n_removal;
271
272 pr_warn("Removing %d invalid memory map entries.\n", n_removal);
273 efi_memmap_install(efi.memmap.phys_map, size);
274 }
275}
276
213void __init efi_print_memmap(void) 277void __init efi_print_memmap(void)
214{ 278{
215 efi_memory_desc_t *md; 279 efi_memory_desc_t *md;
@@ -472,6 +536,8 @@ void __init efi_init(void)
472 } 536 }
473 } 537 }
474 538
539 efi_clean_memmap();
540
475 if (efi_enabled(EFI_DBG)) 541 if (efi_enabled(EFI_DBG))
476 efi_print_memmap(); 542 efi_print_memmap();
477} 543}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 2d089487d2da..fda79cdf9f10 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -103,6 +103,7 @@ typedef struct {
103 103
104#define EFI_PAGE_SHIFT 12 104#define EFI_PAGE_SHIFT 12
105#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT) 105#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
106#define EFI_PAGES_MAX (U64_MAX >> EFI_PAGE_SHIFT)
106 107
107typedef struct { 108typedef struct {
108 u32 type; 109 u32 type;