Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

efi: Common enable/disable infrastructure for EFI soft reservation

UEFI 2.8 defines an EFI_MEMORY_SP attribute bit to augment the
interpretation of the EFI Memory Types as "reserved for a specific
purpose".

The proposed Linux behavior for specific purpose memory is that it is
reserved for direct-access (device-dax) by default and not available for
any kernel usage, not even as an OOM fallback. Later, through udev
scripts or another init mechanism, these device-dax claimed ranges can
be reconfigured and hot-added to the available System-RAM with a unique
node identifier. This device-dax management scheme implements "soft" in
the "soft reserved" designation by allowing some or all of the
reservation to be recovered as typical memory. This policy can be
disabled at compile-time with CONFIG_EFI_SOFT_RESERVE=n, or runtime with
efi=nosoftreserve.

As for this patch, define the common helpers to determine if the
EFI_MEMORY_SP attribute should be honored. The determination needs to be
made early to prevent the kernel from being loaded into soft-reserved
memory, or otherwise allowing early allocations to land there. Follow-on
changes are needed per architecture to leverage these helpers in their
respective mem-init paths.

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Dan Williams and committed by
Rafael J. Wysocki
b617c526 6950e31b

+70 -1
+8 -1
Documentation/admin-guide/kernel-parameters.txt
··· 1168 1168 Format: {"off" | "on" | "skip[mbr]"} 1169 1169 1170 1170 efi= [EFI] 1171 - Format: { "old_map", "nochunk", "noruntime", "debug" } 1171 + Format: { "old_map", "nochunk", "noruntime", "debug", 1172 + "nosoftreserve" } 1172 1173 old_map [X86-64]: switch to the old ioremap-based EFI 1173 1174 runtime services mapping. 32-bit still uses this one by 1174 1175 default. ··· 1178 1177 firmware implementations. 1179 1178 noruntime : disable EFI runtime services support 1180 1179 debug: enable misc debug output 1180 + nosoftreserve: The EFI_MEMORY_SP (Specific Purpose) 1181 + attribute may cause the kernel to reserve the 1182 + memory range for a memory mapping driver to 1183 + claim. Specify efi=nosoftreserve to disable this 1184 + reservation and treat the memory by its base type 1185 + (i.e. EFI_CONVENTIONAL_MEMORY / "System RAM"). 1181 1186 1182 1187 efi_no_storage_paranoia [EFI; X86] 1183 1188 Using this parameter you can use more than 50% of
+21
drivers/firmware/efi/Kconfig
··· 75 75 Ranges can be set up to this value using comma-separated list. 76 76 The default value is 8. 77 77 78 + config EFI_SOFT_RESERVE 79 + bool "Reserve EFI Specific Purpose Memory" 80 + depends on EFI && EFI_STUB && ACPI_HMAT 81 + default ACPI_HMAT 82 + help 83 + On systems that have mixed performance classes of memory EFI 84 + may indicate specific purpose memory with an attribute (See 85 + EFI_MEMORY_SP in UEFI 2.8). A memory range tagged with this 86 + attribute may have unique performance characteristics compared 87 + to the system's general purpose "System RAM" pool. On the 88 + expectation that such memory has application specific usage, 89 + and its base EFI memory type is "conventional" answer Y to 90 + arrange for the kernel to reserve it as a "Soft Reserved" 91 + resource, and set aside for direct-access (device-dax) by 92 + default. The memory range can later be optionally assigned to 93 + the page allocator by system administrator policy via the 94 + device-dax kmem facility. Say N to have the kernel treat this 95 + memory as "System RAM" by default. 96 + 97 + If unsure, say Y. 98 + 78 99 config EFI_PARAMS_FROM_FDT 79 100 bool 80 101 help
+8
drivers/firmware/efi/efi.c
··· 81 81 return disable_runtime; 82 82 } 83 83 84 + bool __pure __efi_soft_reserve_enabled(void) 85 + { 86 + return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE); 87 + } 88 + 84 89 static int __init parse_efi_cmdline(char *str) 85 90 { 86 91 if (!str) { ··· 98 93 99 94 if (parse_option_str(str, "noruntime")) 100 95 disable_runtime = true; 96 + 97 + if (parse_option_str(str, "nosoftreserve")) 98 + set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags); 101 99 102 100 return 0; 103 101 }
+19
drivers/firmware/efi/libstub/efi-stub-helper.c
··· 32 32 static int __section(.data) __nokaslr; 33 33 static int __section(.data) __quiet; 34 34 static int __section(.data) __novamap; 35 + static bool __section(.data) efi_nosoftreserve; 35 36 36 37 int __pure nokaslr(void) 37 38 { ··· 45 44 int __pure novamap(void) 46 45 { 47 46 return __novamap; 47 + } 48 + bool __pure __efi_soft_reserve_enabled(void) 49 + { 50 + return !efi_nosoftreserve; 48 51 } 49 52 50 53 #define EFI_MMAP_NR_SLACK_SLOTS 8 ··· 216 211 if (desc->type != EFI_CONVENTIONAL_MEMORY) 217 212 continue; 218 213 214 + if (efi_soft_reserve_enabled() && 215 + (desc->attribute & EFI_MEMORY_SP)) 216 + continue; 217 + 219 218 if (desc->num_pages < nr_pages) 220 219 continue; 221 220 ··· 312 303 desc = efi_early_memdesc_ptr(m, desc_size, i); 313 304 314 305 if (desc->type != EFI_CONVENTIONAL_MEMORY) 306 + continue; 307 + 308 + if (efi_soft_reserve_enabled() && 309 + (desc->attribute & EFI_MEMORY_SP)) 315 310 continue; 316 311 317 312 if (desc->num_pages < nr_pages) ··· 495 482 if (!strncmp(str, "novamap", 7)) { 496 483 str += strlen("novamap"); 497 484 __novamap = 1; 485 + } 486 + 487 + if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) && 488 + !strncmp(str, "nosoftreserve", 7)) { 489 + str += strlen("nosoftreserve"); 490 + efi_nosoftreserve = 1; 498 491 } 499 492 500 493 /* Group words together, delimited by "," */
+14
include/linux/efi.h
··· 1202 1202 #define EFI_DBG 8 /* Print additional debug info at runtime */ 1203 1203 #define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ 1204 1204 #define EFI_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */ 1205 + #define EFI_MEM_NO_SOFT_RESERVE 11 /* Is the kernel configured to ignore soft reservations? */ 1205 1206 1206 1207 #ifdef CONFIG_EFI 1207 1208 /* ··· 1213 1212 return test_bit(feature, &efi.flags) != 0; 1214 1213 } 1215 1214 extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused); 1215 + 1216 + bool __pure __efi_soft_reserve_enabled(void); 1217 + 1218 + static inline bool __pure efi_soft_reserve_enabled(void) 1219 + { 1220 + return IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) 1221 + && __efi_soft_reserve_enabled(); 1222 + } 1216 1223 #else 1217 1224 static inline bool efi_enabled(int feature) 1218 1225 { ··· 1231 1222 1232 1223 static inline bool 1233 1224 efi_capsule_pending(int *reset_type) 1225 + { 1226 + return false; 1227 + } 1228 + 1229 + static inline bool efi_soft_reserve_enabled(void) 1234 1230 { 1235 1231 return false; 1236 1232 }