Commit b617c526 authored by Dan Williams's avatar Dan Williams Committed by Rafael J. Wysocki

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: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 6950e31b
...@@ -1168,7 +1168,8 @@ ...@@ -1168,7 +1168,8 @@
Format: {"off" | "on" | "skip[mbr]"} Format: {"off" | "on" | "skip[mbr]"}
efi= [EFI] efi= [EFI]
Format: { "old_map", "nochunk", "noruntime", "debug" } Format: { "old_map", "nochunk", "noruntime", "debug",
"nosoftreserve" }
old_map [X86-64]: switch to the old ioremap-based EFI old_map [X86-64]: switch to the old ioremap-based EFI
runtime services mapping. 32-bit still uses this one by runtime services mapping. 32-bit still uses this one by
default. default.
...@@ -1177,6 +1178,12 @@ ...@@ -1177,6 +1178,12 @@
firmware implementations. firmware implementations.
noruntime : disable EFI runtime services support noruntime : disable EFI runtime services support
debug: enable misc debug output debug: enable misc debug output
nosoftreserve: The EFI_MEMORY_SP (Specific Purpose)
attribute may cause the kernel to reserve the
memory range for a memory mapping driver to
claim. Specify efi=nosoftreserve to disable this
reservation and treat the memory by its base type
(i.e. EFI_CONVENTIONAL_MEMORY / "System RAM").
efi_no_storage_paranoia [EFI; X86] efi_no_storage_paranoia [EFI; X86]
Using this parameter you can use more than 50% of Using this parameter you can use more than 50% of
......
...@@ -75,6 +75,27 @@ config EFI_MAX_FAKE_MEM ...@@ -75,6 +75,27 @@ config EFI_MAX_FAKE_MEM
Ranges can be set up to this value using comma-separated list. Ranges can be set up to this value using comma-separated list.
The default value is 8. The default value is 8.
config EFI_SOFT_RESERVE
bool "Reserve EFI Specific Purpose Memory"
depends on EFI && EFI_STUB && ACPI_HMAT
default ACPI_HMAT
help
On systems that have mixed performance classes of memory EFI
may indicate specific purpose memory with an attribute (See
EFI_MEMORY_SP in UEFI 2.8). A memory range tagged with this
attribute may have unique performance characteristics compared
to the system's general purpose "System RAM" pool. On the
expectation that such memory has application specific usage,
and its base EFI memory type is "conventional" answer Y to
arrange for the kernel to reserve it as a "Soft Reserved"
resource, and set aside for direct-access (device-dax) by
default. The memory range can later be optionally assigned to
the page allocator by system administrator policy via the
device-dax kmem facility. Say N to have the kernel treat this
memory as "System RAM" by default.
If unsure, say Y.
config EFI_PARAMS_FROM_FDT config EFI_PARAMS_FROM_FDT
bool bool
help help
......
...@@ -81,6 +81,11 @@ bool efi_runtime_disabled(void) ...@@ -81,6 +81,11 @@ bool efi_runtime_disabled(void)
return disable_runtime; return disable_runtime;
} }
bool __pure __efi_soft_reserve_enabled(void)
{
return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE);
}
static int __init parse_efi_cmdline(char *str) static int __init parse_efi_cmdline(char *str)
{ {
if (!str) { if (!str) {
...@@ -94,6 +99,9 @@ static int __init parse_efi_cmdline(char *str) ...@@ -94,6 +99,9 @@ static int __init parse_efi_cmdline(char *str)
if (parse_option_str(str, "noruntime")) if (parse_option_str(str, "noruntime"))
disable_runtime = true; disable_runtime = true;
if (parse_option_str(str, "nosoftreserve"))
set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
return 0; return 0;
} }
early_param("efi", parse_efi_cmdline); early_param("efi", parse_efi_cmdline);
......
...@@ -32,6 +32,7 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; ...@@ -32,6 +32,7 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
static int __section(.data) __nokaslr; static int __section(.data) __nokaslr;
static int __section(.data) __quiet; static int __section(.data) __quiet;
static int __section(.data) __novamap; static int __section(.data) __novamap;
static bool __section(.data) efi_nosoftreserve;
int __pure nokaslr(void) int __pure nokaslr(void)
{ {
...@@ -45,6 +46,10 @@ int __pure novamap(void) ...@@ -45,6 +46,10 @@ int __pure novamap(void)
{ {
return __novamap; return __novamap;
} }
bool __pure __efi_soft_reserve_enabled(void)
{
return !efi_nosoftreserve;
}
#define EFI_MMAP_NR_SLACK_SLOTS 8 #define EFI_MMAP_NR_SLACK_SLOTS 8
...@@ -211,6 +216,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, ...@@ -211,6 +216,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
if (desc->type != EFI_CONVENTIONAL_MEMORY) if (desc->type != EFI_CONVENTIONAL_MEMORY)
continue; continue;
if (efi_soft_reserve_enabled() &&
(desc->attribute & EFI_MEMORY_SP))
continue;
if (desc->num_pages < nr_pages) if (desc->num_pages < nr_pages)
continue; continue;
...@@ -305,6 +314,10 @@ efi_status_t efi_low_alloc_above(efi_system_table_t *sys_table_arg, ...@@ -305,6 +314,10 @@ efi_status_t efi_low_alloc_above(efi_system_table_t *sys_table_arg,
if (desc->type != EFI_CONVENTIONAL_MEMORY) if (desc->type != EFI_CONVENTIONAL_MEMORY)
continue; continue;
if (efi_soft_reserve_enabled() &&
(desc->attribute & EFI_MEMORY_SP))
continue;
if (desc->num_pages < nr_pages) if (desc->num_pages < nr_pages)
continue; continue;
...@@ -484,6 +497,12 @@ efi_status_t efi_parse_options(char const *cmdline) ...@@ -484,6 +497,12 @@ efi_status_t efi_parse_options(char const *cmdline)
__novamap = 1; __novamap = 1;
} }
if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
!strncmp(str, "nosoftreserve", 7)) {
str += strlen("nosoftreserve");
efi_nosoftreserve = 1;
}
/* Group words together, delimited by "," */ /* Group words together, delimited by "," */
while (*str && *str != ' ' && *str != ',') while (*str && *str != ' ' && *str != ',')
str++; str++;
......
...@@ -1202,6 +1202,7 @@ extern int __init efi_setup_pcdp_console(char *); ...@@ -1202,6 +1202,7 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_DBG 8 /* Print additional debug info at runtime */ #define EFI_DBG 8 /* Print additional debug info at runtime */
#define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ #define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */
#define EFI_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */ #define EFI_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */
#define EFI_MEM_NO_SOFT_RESERVE 11 /* Is the kernel configured to ignore soft reservations? */
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
/* /*
...@@ -1212,6 +1213,14 @@ static inline bool efi_enabled(int feature) ...@@ -1212,6 +1213,14 @@ static inline bool efi_enabled(int feature)
return test_bit(feature, &efi.flags) != 0; return test_bit(feature, &efi.flags) != 0;
} }
extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused); extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused);
bool __pure __efi_soft_reserve_enabled(void);
static inline bool __pure efi_soft_reserve_enabled(void)
{
return IS_ENABLED(CONFIG_EFI_SOFT_RESERVE)
&& __efi_soft_reserve_enabled();
}
#else #else
static inline bool efi_enabled(int feature) static inline bool efi_enabled(int feature)
{ {
...@@ -1225,6 +1234,11 @@ efi_capsule_pending(int *reset_type) ...@@ -1225,6 +1234,11 @@ efi_capsule_pending(int *reset_type)
{ {
return false; return false;
} }
static inline bool efi_soft_reserve_enabled(void)
{
return false;
}
#endif #endif
extern int efi_status_to_err(efi_status_t status); extern int efi_status_to_err(efi_status_t status);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment