Skip to content

Commit b617c52

Browse files
djbwrafaeljw
authored andcommitted
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 <[email protected]> Signed-off-by: Dan Williams <[email protected]> Acked-by: Thomas Gleixner <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 6950e31 commit b617c52

File tree

5 files changed

+70
-1
lines changed

5 files changed

+70
-1
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,8 @@
11681168
Format: {"off" | "on" | "skip[mbr]"}
11691169

11701170
efi= [EFI]
1171-
Format: { "old_map", "nochunk", "noruntime", "debug" }
1171+
Format: { "old_map", "nochunk", "noruntime", "debug",
1172+
"nosoftreserve" }
11721173
old_map [X86-64]: switch to the old ioremap-based EFI
11731174
runtime services mapping. 32-bit still uses this one by
11741175
default.
@@ -1177,6 +1178,12 @@
11771178
firmware implementations.
11781179
noruntime : disable EFI runtime services support
11791180
debug: enable misc debug output
1181+
nosoftreserve: The EFI_MEMORY_SP (Specific Purpose)
1182+
attribute may cause the kernel to reserve the
1183+
memory range for a memory mapping driver to
1184+
claim. Specify efi=nosoftreserve to disable this
1185+
reservation and treat the memory by its base type
1186+
(i.e. EFI_CONVENTIONAL_MEMORY / "System RAM").
11801187

11811188
efi_no_storage_paranoia [EFI; X86]
11821189
Using this parameter you can use more than 50% of

drivers/firmware/efi/Kconfig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,27 @@ config EFI_MAX_FAKE_MEM
7575
Ranges can be set up to this value using comma-separated list.
7676
The default value is 8.
7777

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+
7899
config EFI_PARAMS_FROM_FDT
79100
bool
80101
help

drivers/firmware/efi/efi.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ bool efi_runtime_disabled(void)
8181
return disable_runtime;
8282
}
8383

84+
bool __pure __efi_soft_reserve_enabled(void)
85+
{
86+
return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE);
87+
}
88+
8489
static int __init parse_efi_cmdline(char *str)
8590
{
8691
if (!str) {
@@ -94,6 +99,9 @@ static int __init parse_efi_cmdline(char *str)
9499
if (parse_option_str(str, "noruntime"))
95100
disable_runtime = true;
96101

102+
if (parse_option_str(str, "nosoftreserve"))
103+
set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
104+
97105
return 0;
98106
}
99107
early_param("efi", parse_efi_cmdline);

drivers/firmware/efi/libstub/efi-stub-helper.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
3232
static int __section(.data) __nokaslr;
3333
static int __section(.data) __quiet;
3434
static int __section(.data) __novamap;
35+
static bool __section(.data) efi_nosoftreserve;
3536

3637
int __pure nokaslr(void)
3738
{
@@ -45,6 +46,10 @@ int __pure novamap(void)
4546
{
4647
return __novamap;
4748
}
49+
bool __pure __efi_soft_reserve_enabled(void)
50+
{
51+
return !efi_nosoftreserve;
52+
}
4853

4954
#define EFI_MMAP_NR_SLACK_SLOTS 8
5055

@@ -211,6 +216,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
211216
if (desc->type != EFI_CONVENTIONAL_MEMORY)
212217
continue;
213218

219+
if (efi_soft_reserve_enabled() &&
220+
(desc->attribute & EFI_MEMORY_SP))
221+
continue;
222+
214223
if (desc->num_pages < nr_pages)
215224
continue;
216225

@@ -305,6 +314,10 @@ efi_status_t efi_low_alloc_above(efi_system_table_t *sys_table_arg,
305314
if (desc->type != EFI_CONVENTIONAL_MEMORY)
306315
continue;
307316

317+
if (efi_soft_reserve_enabled() &&
318+
(desc->attribute & EFI_MEMORY_SP))
319+
continue;
320+
308321
if (desc->num_pages < nr_pages)
309322
continue;
310323

@@ -484,6 +497,12 @@ efi_status_t efi_parse_options(char const *cmdline)
484497
__novamap = 1;
485498
}
486499

500+
if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
501+
!strncmp(str, "nosoftreserve", 7)) {
502+
str += strlen("nosoftreserve");
503+
efi_nosoftreserve = 1;
504+
}
505+
487506
/* Group words together, delimited by "," */
488507
while (*str && *str != ' ' && *str != ',')
489508
str++;

include/linux/efi.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,7 @@ extern int __init efi_setup_pcdp_console(char *);
12021202
#define EFI_DBG 8 /* Print additional debug info at runtime */
12031203
#define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */
12041204
#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? */
12051206

12061207
#ifdef CONFIG_EFI
12071208
/*
@@ -1212,6 +1213,14 @@ static inline bool efi_enabled(int feature)
12121213
return test_bit(feature, &efi.flags) != 0;
12131214
}
12141215
extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused);
1216+
1217+
bool __pure __efi_soft_reserve_enabled(void);
1218+
1219+
static inline bool __pure efi_soft_reserve_enabled(void)
1220+
{
1221+
return IS_ENABLED(CONFIG_EFI_SOFT_RESERVE)
1222+
&& __efi_soft_reserve_enabled();
1223+
}
12151224
#else
12161225
static inline bool efi_enabled(int feature)
12171226
{
@@ -1225,6 +1234,11 @@ efi_capsule_pending(int *reset_type)
12251234
{
12261235
return false;
12271236
}
1237+
1238+
static inline bool efi_soft_reserve_enabled(void)
1239+
{
1240+
return false;
1241+
}
12281242
#endif
12291243

12301244
extern int efi_status_to_err(efi_status_t status);

0 commit comments

Comments
 (0)