Skip to content

Commit 262b45a

Browse files
djbwrafaeljw
authored andcommitted
x86/efi: EFI soft reservation to E820 enumeration
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. This patch introduces 2 new concepts at once given the entanglement between early boot enumeration relative to memory that can optionally be reserved from the kernel page allocator by default. The new concepts are: - E820_TYPE_SOFT_RESERVED: Upon detecting the EFI_MEMORY_SP attribute on EFI_CONVENTIONAL memory, update the E820 map with this new type. Only perform this classification if the CONFIG_EFI_SOFT_RESERVE=y policy is enabled, otherwise treat it as typical ram. - IORES_DESC_SOFT_RESERVED: Add a new I/O resource descriptor for a device driver to search iomem resources for application specific memory. Teach the iomem code to identify such ranges as "Soft Reserved". Note that the comment for do_add_efi_memmap() needed refreshing since it seemed to imply that the efi map might overflow the e820 table, but that is not an issue as of commit 7b6e4ba "x86/boot/e820: Clean up the E820_X_MAX definition" that removed the 128 entry limit for e820__range_add(). A follow-on change integrates parsing of the ACPI HMAT to identify the node and sub-range boundaries of EFI_MEMORY_SP designated memory. For now, just identify and reserve memory of this type. Acked-by: Ard Biesheuvel <[email protected]> Reported-by: kbuild test robot <[email protected]> Reviewed-by: Dave Hansen <[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 b617c52 commit 262b45a

File tree

6 files changed

+73
-7
lines changed

6 files changed

+73
-7
lines changed

arch/x86/boot/compressed/eboot.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,11 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s
554554
case EFI_BOOT_SERVICES_CODE:
555555
case EFI_BOOT_SERVICES_DATA:
556556
case EFI_CONVENTIONAL_MEMORY:
557-
e820_type = E820_TYPE_RAM;
557+
if (efi_soft_reserve_enabled() &&
558+
(d->attribute & EFI_MEMORY_SP))
559+
e820_type = E820_TYPE_SOFT_RESERVED;
560+
else
561+
e820_type = E820_TYPE_RAM;
558562
break;
559563

560564
case EFI_ACPI_MEMORY_NVS:

arch/x86/boot/compressed/kaslr.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,10 @@ process_efi_entries(unsigned long minimum, unsigned long image_size)
760760
if (md->type != EFI_CONVENTIONAL_MEMORY)
761761
continue;
762762

763+
if (efi_soft_reserve_enabled() &&
764+
(md->attribute & EFI_MEMORY_SP))
765+
continue;
766+
763767
if (efi_mirror_found &&
764768
!(md->attribute & EFI_MEMORY_MORE_RELIABLE))
765769
continue;

arch/x86/include/asm/e820/types.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ enum e820_type {
2828
*/
2929
E820_TYPE_PRAM = 12,
3030

31+
/*
32+
* Special-purpose memory is indicated to the system via the
33+
* EFI_MEMORY_SP attribute. Define an e820 translation of this
34+
* memory type for the purpose of reserving this range and
35+
* marking it with the IORES_DESC_SOFT_RESERVED designation.
36+
*/
37+
E820_TYPE_SOFT_RESERVED = 0xefffffff,
38+
3139
/*
3240
* Reserved RAM used by the kernel itself if
3341
* CONFIG_INTEL_TXT=y is enabled, memory of this type

arch/x86/kernel/e820.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ static void __init e820_print_type(enum e820_type type)
190190
case E820_TYPE_RAM: /* Fall through: */
191191
case E820_TYPE_RESERVED_KERN: pr_cont("usable"); break;
192192
case E820_TYPE_RESERVED: pr_cont("reserved"); break;
193+
case E820_TYPE_SOFT_RESERVED: pr_cont("soft reserved"); break;
193194
case E820_TYPE_ACPI: pr_cont("ACPI data"); break;
194195
case E820_TYPE_NVS: pr_cont("ACPI NVS"); break;
195196
case E820_TYPE_UNUSABLE: pr_cont("unusable"); break;
@@ -1037,6 +1038,7 @@ static const char *__init e820_type_to_string(struct e820_entry *entry)
10371038
case E820_TYPE_PRAM: return "Persistent Memory (legacy)";
10381039
case E820_TYPE_PMEM: return "Persistent Memory";
10391040
case E820_TYPE_RESERVED: return "Reserved";
1041+
case E820_TYPE_SOFT_RESERVED: return "Soft Reserved";
10401042
default: return "Unknown E820 type";
10411043
}
10421044
}
@@ -1052,6 +1054,7 @@ static unsigned long __init e820_type_to_iomem_type(struct e820_entry *entry)
10521054
case E820_TYPE_PRAM: /* Fall-through: */
10531055
case E820_TYPE_PMEM: /* Fall-through: */
10541056
case E820_TYPE_RESERVED: /* Fall-through: */
1057+
case E820_TYPE_SOFT_RESERVED: /* Fall-through: */
10551058
default: return IORESOURCE_MEM;
10561059
}
10571060
}
@@ -1064,6 +1067,7 @@ static unsigned long __init e820_type_to_iores_desc(struct e820_entry *entry)
10641067
case E820_TYPE_PMEM: return IORES_DESC_PERSISTENT_MEMORY;
10651068
case E820_TYPE_PRAM: return IORES_DESC_PERSISTENT_MEMORY_LEGACY;
10661069
case E820_TYPE_RESERVED: return IORES_DESC_RESERVED;
1070+
case E820_TYPE_SOFT_RESERVED: return IORES_DESC_SOFT_RESERVED;
10671071
case E820_TYPE_RESERVED_KERN: /* Fall-through: */
10681072
case E820_TYPE_RAM: /* Fall-through: */
10691073
case E820_TYPE_UNUSABLE: /* Fall-through: */
@@ -1078,11 +1082,12 @@ static bool __init do_mark_busy(enum e820_type type, struct resource *res)
10781082
return true;
10791083

10801084
/*
1081-
* Treat persistent memory like device memory, i.e. reserve it
1082-
* for exclusive use of a driver
1085+
* Treat persistent memory and other special memory ranges like
1086+
* device memory, i.e. reserve it for exclusive use of a driver
10831087
*/
10841088
switch (type) {
10851089
case E820_TYPE_RESERVED:
1090+
case E820_TYPE_SOFT_RESERVED:
10861091
case E820_TYPE_PRAM:
10871092
case E820_TYPE_PMEM:
10881093
return false;
@@ -1285,6 +1290,9 @@ void __init e820__memblock_setup(void)
12851290
if (end != (resource_size_t)end)
12861291
continue;
12871292

1293+
if (entry->type == E820_TYPE_SOFT_RESERVED)
1294+
memblock_reserve(entry->addr, entry->size);
1295+
12881296
if (entry->type != E820_TYPE_RAM && entry->type != E820_TYPE_RESERVED_KERN)
12891297
continue;
12901298

arch/x86/platform/efi/efi.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,18 @@ void __init efi_find_mirror(void)
148148

149149
/*
150150
* Tell the kernel about the EFI memory map. This might include
151-
* more than the max 128 entries that can fit in the e820 legacy
152-
* (zeropage) memory map.
151+
* more than the max 128 entries that can fit in the passed in e820
152+
* legacy (zeropage) memory map, but the kernel's e820 table can hold
153+
* E820_MAX_ENTRIES.
153154
*/
154155

155156
static void __init do_add_efi_memmap(void)
156157
{
157158
efi_memory_desc_t *md;
158159

160+
if (!efi_enabled(EFI_MEMMAP))
161+
return;
162+
159163
for_each_efi_memory_desc(md) {
160164
unsigned long long start = md->phys_addr;
161165
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -167,7 +171,10 @@ static void __init do_add_efi_memmap(void)
167171
case EFI_BOOT_SERVICES_CODE:
168172
case EFI_BOOT_SERVICES_DATA:
169173
case EFI_CONVENTIONAL_MEMORY:
170-
if (md->attribute & EFI_MEMORY_WB)
174+
if (efi_soft_reserve_enabled()
175+
&& (md->attribute & EFI_MEMORY_SP))
176+
e820_type = E820_TYPE_SOFT_RESERVED;
177+
else if (md->attribute & EFI_MEMORY_WB)
171178
e820_type = E820_TYPE_RAM;
172179
else
173180
e820_type = E820_TYPE_RESERVED;
@@ -193,11 +200,36 @@ static void __init do_add_efi_memmap(void)
193200
e820_type = E820_TYPE_RESERVED;
194201
break;
195202
}
203+
196204
e820__range_add(start, size, e820_type);
197205
}
198206
e820__update_table(e820_table);
199207
}
200208

209+
/*
210+
* Given add_efi_memmap defaults to 0 and there there is no alternative
211+
* e820 mechanism for soft-reserved memory, import the full EFI memory
212+
* map if soft reservations are present and enabled. Otherwise, the
213+
* mechanism to disable the kernel's consideration of EFI_MEMORY_SP is
214+
* the efi=nosoftreserve option.
215+
*/
216+
static bool do_efi_soft_reserve(void)
217+
{
218+
efi_memory_desc_t *md;
219+
220+
if (!efi_enabled(EFI_MEMMAP))
221+
return false;
222+
223+
if (!efi_soft_reserve_enabled())
224+
return false;
225+
226+
for_each_efi_memory_desc(md)
227+
if (md->type == EFI_CONVENTIONAL_MEMORY &&
228+
(md->attribute & EFI_MEMORY_SP))
229+
return true;
230+
return false;
231+
}
232+
201233
int __init efi_memblock_x86_reserve_range(void)
202234
{
203235
struct efi_info *e = &boot_params.efi_info;
@@ -227,7 +259,7 @@ int __init efi_memblock_x86_reserve_range(void)
227259
if (rv)
228260
return rv;
229261

230-
if (add_efi_memmap)
262+
if (add_efi_memmap || do_efi_soft_reserve())
231263
do_add_efi_memmap();
232264

233265
WARN(efi.memmap.desc_version != 1,
@@ -781,6 +813,15 @@ static bool should_map_region(efi_memory_desc_t *md)
781813
if (IS_ENABLED(CONFIG_X86_32))
782814
return false;
783815

816+
/*
817+
* EFI specific purpose memory may be reserved by default
818+
* depending on kernel config and boot options.
819+
*/
820+
if (md->type == EFI_CONVENTIONAL_MEMORY &&
821+
efi_soft_reserve_enabled() &&
822+
(md->attribute & EFI_MEMORY_SP))
823+
return false;
824+
784825
/*
785826
* Map all of RAM so that we can access arguments in the 1:1
786827
* mapping when making EFI runtime calls.

include/linux/ioport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ enum {
134134
IORES_DESC_PERSISTENT_MEMORY_LEGACY = 5,
135135
IORES_DESC_DEVICE_PRIVATE_MEMORY = 6,
136136
IORES_DESC_RESERVED = 7,
137+
IORES_DESC_SOFT_RESERVED = 8,
137138
};
138139

139140
/*

0 commit comments

Comments
 (0)