.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Low level x86 E820 memory map handling functions. |
---|
3 | 4 | * |
---|
.. | .. |
---|
9 | 10 | * allocation code routines via a platform independent interface (memblock, etc.). |
---|
10 | 11 | */ |
---|
11 | 12 | #include <linux/crash_dump.h> |
---|
12 | | -#include <linux/bootmem.h> |
---|
| 13 | +#include <linux/memblock.h> |
---|
13 | 14 | #include <linux/suspend.h> |
---|
14 | 15 | #include <linux/acpi.h> |
---|
15 | 16 | #include <linux/firmware-map.h> |
---|
16 | | -#include <linux/memblock.h> |
---|
17 | 17 | #include <linux/sort.h> |
---|
| 18 | +#include <linux/memory_hotplug.h> |
---|
18 | 19 | |
---|
19 | 20 | #include <asm/e820/api.h> |
---|
20 | 21 | #include <asm/setup.h> |
---|
.. | .. |
---|
30 | 31 | * - inform the user about the firmware's notion of memory layout |
---|
31 | 32 | * via /sys/firmware/memmap |
---|
32 | 33 | * |
---|
33 | | - * - the hibernation code uses it to generate a kernel-independent MD5 |
---|
34 | | - * fingerprint of the physical memory layout of a system. |
---|
| 34 | + * - the hibernation code uses it to generate a kernel-independent CRC32 |
---|
| 35 | + * checksum of the physical memory layout of a system. |
---|
35 | 36 | * |
---|
36 | 37 | * - 'e820_table_kexec': a slightly modified (by the kernel) firmware version |
---|
37 | 38 | * passed to us by the bootloader - the major difference between |
---|
.. | .. |
---|
73 | 74 | * This function checks if any part of the range <start,end> is mapped |
---|
74 | 75 | * with type. |
---|
75 | 76 | */ |
---|
76 | | -bool e820__mapped_any(u64 start, u64 end, enum e820_type type) |
---|
| 77 | +static bool _e820__mapped_any(struct e820_table *table, |
---|
| 78 | + u64 start, u64 end, enum e820_type type) |
---|
77 | 79 | { |
---|
78 | 80 | int i; |
---|
79 | 81 | |
---|
80 | | - for (i = 0; i < e820_table->nr_entries; i++) { |
---|
81 | | - struct e820_entry *entry = &e820_table->entries[i]; |
---|
| 82 | + for (i = 0; i < table->nr_entries; i++) { |
---|
| 83 | + struct e820_entry *entry = &table->entries[i]; |
---|
82 | 84 | |
---|
83 | 85 | if (type && entry->type != type) |
---|
84 | 86 | continue; |
---|
85 | 87 | if (entry->addr >= end || entry->addr + entry->size <= start) |
---|
86 | 88 | continue; |
---|
87 | | - return 1; |
---|
| 89 | + return true; |
---|
88 | 90 | } |
---|
89 | | - return 0; |
---|
| 91 | + return false; |
---|
| 92 | +} |
---|
| 93 | + |
---|
| 94 | +bool e820__mapped_raw_any(u64 start, u64 end, enum e820_type type) |
---|
| 95 | +{ |
---|
| 96 | + return _e820__mapped_any(e820_table_firmware, start, end, type); |
---|
| 97 | +} |
---|
| 98 | +EXPORT_SYMBOL_GPL(e820__mapped_raw_any); |
---|
| 99 | + |
---|
| 100 | +bool e820__mapped_any(u64 start, u64 end, enum e820_type type) |
---|
| 101 | +{ |
---|
| 102 | + return _e820__mapped_any(e820_table, start, end, type); |
---|
90 | 103 | } |
---|
91 | 104 | EXPORT_SYMBOL_GPL(e820__mapped_any); |
---|
92 | 105 | |
---|
.. | .. |
---|
177 | 190 | case E820_TYPE_RAM: /* Fall through: */ |
---|
178 | 191 | case E820_TYPE_RESERVED_KERN: pr_cont("usable"); break; |
---|
179 | 192 | case E820_TYPE_RESERVED: pr_cont("reserved"); break; |
---|
| 193 | + case E820_TYPE_SOFT_RESERVED: pr_cont("soft reserved"); break; |
---|
180 | 194 | case E820_TYPE_ACPI: pr_cont("ACPI data"); break; |
---|
181 | 195 | case E820_TYPE_NVS: pr_cont("ACPI NVS"); break; |
---|
182 | 196 | case E820_TYPE_UNUSABLE: pr_cont("unusable"); break; |
---|
.. | .. |
---|
291 | 305 | return (ap->addr != ap->entry->addr) - (bp->addr != bp->entry->addr); |
---|
292 | 306 | } |
---|
293 | 307 | |
---|
| 308 | +static bool e820_nomerge(enum e820_type type) |
---|
| 309 | +{ |
---|
| 310 | + /* |
---|
| 311 | + * These types may indicate distinct platform ranges aligned to |
---|
| 312 | + * numa node, protection domain, performance domain, or other |
---|
| 313 | + * boundaries. Do not merge them. |
---|
| 314 | + */ |
---|
| 315 | + if (type == E820_TYPE_PRAM) |
---|
| 316 | + return true; |
---|
| 317 | + if (type == E820_TYPE_SOFT_RESERVED) |
---|
| 318 | + return true; |
---|
| 319 | + return false; |
---|
| 320 | +} |
---|
| 321 | + |
---|
294 | 322 | int __init e820__update_table(struct e820_table *table) |
---|
295 | 323 | { |
---|
296 | 324 | struct e820_entry *entries = table->entries; |
---|
.. | .. |
---|
366 | 394 | } |
---|
367 | 395 | |
---|
368 | 396 | /* Continue building up new map based on this information: */ |
---|
369 | | - if (current_type != last_type || current_type == E820_TYPE_PRAM) { |
---|
| 397 | + if (current_type != last_type || e820_nomerge(current_type)) { |
---|
370 | 398 | if (last_type != 0) { |
---|
371 | 399 | new_entries[new_nr_entries].size = change_point[chg_idx]->addr - last_addr; |
---|
372 | 400 | /* Move forward only if the new size was non-zero: */ |
---|
.. | .. |
---|
672 | 700 | int size; |
---|
673 | 701 | |
---|
674 | 702 | size = offsetof(struct e820_table, entries) + sizeof(struct e820_entry)*e820_table->nr_entries; |
---|
675 | | - n = kmalloc(size, GFP_KERNEL); |
---|
| 703 | + n = kmemdup(e820_table, size, GFP_KERNEL); |
---|
676 | 704 | BUG_ON(!n); |
---|
677 | | - memcpy(n, e820_table, size); |
---|
678 | 705 | e820_table = n; |
---|
679 | 706 | |
---|
680 | 707 | size = offsetof(struct e820_table, entries) + sizeof(struct e820_entry)*e820_table_kexec->nr_entries; |
---|
681 | | - n = kmalloc(size, GFP_KERNEL); |
---|
| 708 | + n = kmemdup(e820_table_kexec, size, GFP_KERNEL); |
---|
682 | 709 | BUG_ON(!n); |
---|
683 | | - memcpy(n, e820_table_kexec, size); |
---|
684 | 710 | e820_table_kexec = n; |
---|
685 | 711 | |
---|
686 | 712 | size = offsetof(struct e820_table, entries) + sizeof(struct e820_entry)*e820_table_firmware->nr_entries; |
---|
687 | | - n = kmalloc(size, GFP_KERNEL); |
---|
| 713 | + n = kmemdup(e820_table_firmware, size, GFP_KERNEL); |
---|
688 | 714 | BUG_ON(!n); |
---|
689 | | - memcpy(n, e820_table_firmware, size); |
---|
690 | 715 | e820_table_firmware = n; |
---|
691 | 716 | } |
---|
692 | 717 | |
---|
.. | .. |
---|
779 | 804 | { |
---|
780 | 805 | u64 addr; |
---|
781 | 806 | |
---|
782 | | - addr = __memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE); |
---|
| 807 | + addr = memblock_phys_alloc(size, align); |
---|
783 | 808 | if (addr) { |
---|
784 | 809 | e820__range_update_kexec(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED); |
---|
785 | 810 | pr_info("update e820_table_kexec for e820__memblock_alloc_reserved()\n"); |
---|
.. | .. |
---|
882 | 907 | |
---|
883 | 908 | e820__range_remove(mem_size, ULLONG_MAX - mem_size, E820_TYPE_RAM, 1); |
---|
884 | 909 | |
---|
| 910 | +#ifdef CONFIG_MEMORY_HOTPLUG |
---|
| 911 | + max_mem_size = mem_size; |
---|
| 912 | +#endif |
---|
| 913 | + |
---|
885 | 914 | return 0; |
---|
886 | 915 | } |
---|
887 | 916 | early_param("mem", parse_memopt); |
---|
.. | .. |
---|
895 | 924 | return -EINVAL; |
---|
896 | 925 | |
---|
897 | 926 | if (!strncmp(p, "exactmap", 8)) { |
---|
898 | | -#ifdef CONFIG_CRASH_DUMP |
---|
899 | | - /* |
---|
900 | | - * If we are doing a crash dump, we still need to know |
---|
901 | | - * the real memory size before the original memory map is |
---|
902 | | - * reset. |
---|
903 | | - */ |
---|
904 | | - saved_max_pfn = e820__end_of_ram_pfn(); |
---|
905 | | -#endif |
---|
906 | 927 | e820_table->nr_entries = 0; |
---|
907 | 928 | userdef = 1; |
---|
908 | 929 | return 0; |
---|
.. | .. |
---|
974 | 995 | */ |
---|
975 | 996 | void __init e820__reserve_setup_data(void) |
---|
976 | 997 | { |
---|
| 998 | + struct setup_indirect *indirect; |
---|
977 | 999 | struct setup_data *data; |
---|
978 | | - u64 pa_data; |
---|
| 1000 | + u64 pa_data, pa_next; |
---|
| 1001 | + u32 len; |
---|
979 | 1002 | |
---|
980 | 1003 | pa_data = boot_params.hdr.setup_data; |
---|
981 | 1004 | if (!pa_data) |
---|
.. | .. |
---|
983 | 1006 | |
---|
984 | 1007 | while (pa_data) { |
---|
985 | 1008 | data = early_memremap(pa_data, sizeof(*data)); |
---|
| 1009 | + if (!data) { |
---|
| 1010 | + pr_warn("e820: failed to memremap setup_data entry\n"); |
---|
| 1011 | + return; |
---|
| 1012 | + } |
---|
| 1013 | + |
---|
| 1014 | + len = sizeof(*data); |
---|
| 1015 | + pa_next = data->next; |
---|
| 1016 | + |
---|
986 | 1017 | e820__range_update(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); |
---|
987 | | - e820__range_update_kexec(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); |
---|
988 | | - pa_data = data->next; |
---|
989 | | - early_memunmap(data, sizeof(*data)); |
---|
| 1018 | + |
---|
| 1019 | + /* |
---|
| 1020 | + * SETUP_EFI is supplied by kexec and does not need to be |
---|
| 1021 | + * reserved. |
---|
| 1022 | + */ |
---|
| 1023 | + if (data->type != SETUP_EFI) |
---|
| 1024 | + e820__range_update_kexec(pa_data, |
---|
| 1025 | + sizeof(*data) + data->len, |
---|
| 1026 | + E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); |
---|
| 1027 | + |
---|
| 1028 | + if (data->type == SETUP_INDIRECT) { |
---|
| 1029 | + len += data->len; |
---|
| 1030 | + early_memunmap(data, sizeof(*data)); |
---|
| 1031 | + data = early_memremap(pa_data, len); |
---|
| 1032 | + if (!data) { |
---|
| 1033 | + pr_warn("e820: failed to memremap indirect setup_data\n"); |
---|
| 1034 | + return; |
---|
| 1035 | + } |
---|
| 1036 | + |
---|
| 1037 | + indirect = (struct setup_indirect *)data->data; |
---|
| 1038 | + |
---|
| 1039 | + if (indirect->type != SETUP_INDIRECT) { |
---|
| 1040 | + e820__range_update(indirect->addr, indirect->len, |
---|
| 1041 | + E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); |
---|
| 1042 | + e820__range_update_kexec(indirect->addr, indirect->len, |
---|
| 1043 | + E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); |
---|
| 1044 | + } |
---|
| 1045 | + } |
---|
| 1046 | + |
---|
| 1047 | + pa_data = pa_next; |
---|
| 1048 | + early_memunmap(data, len); |
---|
990 | 1049 | } |
---|
991 | 1050 | |
---|
992 | 1051 | e820__update_table(e820_table); |
---|
.. | .. |
---|
1023 | 1082 | case E820_TYPE_PRAM: return "Persistent Memory (legacy)"; |
---|
1024 | 1083 | case E820_TYPE_PMEM: return "Persistent Memory"; |
---|
1025 | 1084 | case E820_TYPE_RESERVED: return "Reserved"; |
---|
| 1085 | + case E820_TYPE_SOFT_RESERVED: return "Soft Reserved"; |
---|
1026 | 1086 | default: return "Unknown E820 type"; |
---|
1027 | 1087 | } |
---|
1028 | 1088 | } |
---|
.. | .. |
---|
1038 | 1098 | case E820_TYPE_PRAM: /* Fall-through: */ |
---|
1039 | 1099 | case E820_TYPE_PMEM: /* Fall-through: */ |
---|
1040 | 1100 | case E820_TYPE_RESERVED: /* Fall-through: */ |
---|
| 1101 | + case E820_TYPE_SOFT_RESERVED: /* Fall-through: */ |
---|
1041 | 1102 | default: return IORESOURCE_MEM; |
---|
1042 | 1103 | } |
---|
1043 | 1104 | } |
---|
.. | .. |
---|
1049 | 1110 | case E820_TYPE_NVS: return IORES_DESC_ACPI_NV_STORAGE; |
---|
1050 | 1111 | case E820_TYPE_PMEM: return IORES_DESC_PERSISTENT_MEMORY; |
---|
1051 | 1112 | case E820_TYPE_PRAM: return IORES_DESC_PERSISTENT_MEMORY_LEGACY; |
---|
| 1113 | + case E820_TYPE_RESERVED: return IORES_DESC_RESERVED; |
---|
| 1114 | + case E820_TYPE_SOFT_RESERVED: return IORES_DESC_SOFT_RESERVED; |
---|
1052 | 1115 | case E820_TYPE_RESERVED_KERN: /* Fall-through: */ |
---|
1053 | 1116 | case E820_TYPE_RAM: /* Fall-through: */ |
---|
1054 | 1117 | case E820_TYPE_UNUSABLE: /* Fall-through: */ |
---|
1055 | | - case E820_TYPE_RESERVED: /* Fall-through: */ |
---|
1056 | 1118 | default: return IORES_DESC_NONE; |
---|
1057 | 1119 | } |
---|
1058 | 1120 | } |
---|
.. | .. |
---|
1064 | 1126 | return true; |
---|
1065 | 1127 | |
---|
1066 | 1128 | /* |
---|
1067 | | - * Treat persistent memory like device memory, i.e. reserve it |
---|
1068 | | - * for exclusive use of a driver |
---|
| 1129 | + * Treat persistent memory and other special memory ranges like |
---|
| 1130 | + * device memory, i.e. reserve it for exclusive use of a driver |
---|
1069 | 1131 | */ |
---|
1070 | 1132 | switch (type) { |
---|
1071 | 1133 | case E820_TYPE_RESERVED: |
---|
| 1134 | + case E820_TYPE_SOFT_RESERVED: |
---|
1072 | 1135 | case E820_TYPE_PRAM: |
---|
1073 | 1136 | case E820_TYPE_PMEM: |
---|
1074 | 1137 | return false; |
---|
.. | .. |
---|
1094 | 1157 | struct resource *res; |
---|
1095 | 1158 | u64 end; |
---|
1096 | 1159 | |
---|
1097 | | - res = alloc_bootmem(sizeof(*res) * e820_table->nr_entries); |
---|
| 1160 | + res = memblock_alloc(sizeof(*res) * e820_table->nr_entries, |
---|
| 1161 | + SMP_CACHE_BYTES); |
---|
| 1162 | + if (!res) |
---|
| 1163 | + panic("%s: Failed to allocate %zu bytes\n", __func__, |
---|
| 1164 | + sizeof(*res) * e820_table->nr_entries); |
---|
1098 | 1165 | e820_res = res; |
---|
1099 | 1166 | |
---|
1100 | 1167 | for (i = 0; i < e820_table->nr_entries; i++) { |
---|
.. | .. |
---|
1267 | 1334 | if (end != (resource_size_t)end) |
---|
1268 | 1335 | continue; |
---|
1269 | 1336 | |
---|
| 1337 | + if (entry->type == E820_TYPE_SOFT_RESERVED) |
---|
| 1338 | + memblock_reserve(entry->addr, entry->size); |
---|
| 1339 | + |
---|
1270 | 1340 | if (entry->type != E820_TYPE_RAM && entry->type != E820_TYPE_RESERVED_KERN) |
---|
1271 | 1341 | continue; |
---|
1272 | 1342 | |
---|