diff options
-rw-r--r-- | arch/x86/platform/efi/efi.c | 66 | ||||
-rw-r--r-- | include/linux/efi.h | 1 |
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 | |||
217 | static 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 | |||
251 | static 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 | |||
213 | void __init efi_print_memmap(void) | 277 | void __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 | ||
107 | typedef struct { | 108 | typedef struct { |
108 | u32 type; | 109 | u32 type; |