Skip to content

Commit 353d7a8

Browse files
hbathinimpe
authored andcommitted
powerpc/64s/radix/kfence: map __kfence_pool at page granularity
When KFENCE is enabled, total system memory is mapped at page level granularity. But in radix MMU mode, ~3GB additional memory is needed to map 100GB of system memory at page level granularity when compared to using 2MB direct mapping.This is not desired considering KFENCE is designed to be enabled in production kernels [1]. Mapping only the memory allocated for KFENCE pool at page granularity is sufficient to enable KFENCE support. So, allocate __kfence_pool during bootup and map it at page granularity instead of mapping all system memory at page granularity. Without patch: # cat /proc/meminfo MemTotal: 101201920 kB With patch: # cat /proc/meminfo MemTotal: 104483904 kB Note that enabling KFENCE at runtime is disabled for radix MMU for now, as it depends on the ability to split page table mappings and such APIs are not currently implemented for radix MMU. All kfence_test.c testcases passed with this patch. [1] https://lore.kernel.org/all/[email protected]/ Signed-off-by: Hari Bathini <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://msgid.link/[email protected]
1 parent af199e6 commit 353d7a8

File tree

3 files changed

+93
-5
lines changed

3 files changed

+93
-5
lines changed

arch/powerpc/include/asm/kfence.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,19 @@
1515
#define ARCH_FUNC_PREFIX "."
1616
#endif
1717

18+
#ifdef CONFIG_KFENCE
19+
extern bool kfence_disabled;
20+
21+
static inline void disable_kfence(void)
22+
{
23+
kfence_disabled = true;
24+
}
25+
1826
static inline bool arch_kfence_init_pool(void)
1927
{
20-
return true;
28+
return !kfence_disabled;
2129
}
30+
#endif
2231

2332
#ifdef CONFIG_PPC64
2433
static inline bool kfence_protect_page(unsigned long addr, bool protect)

arch/powerpc/mm/book3s64/radix_pgtable.c

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/hugetlb.h>
1818
#include <linux/string_helpers.h>
1919
#include <linux/memory.h>
20+
#include <linux/kfence.h>
2021

2122
#include <asm/pgalloc.h>
2223
#include <asm/mmu_context.h>
@@ -31,6 +32,7 @@
3132
#include <asm/uaccess.h>
3233
#include <asm/ultravisor.h>
3334
#include <asm/set_memory.h>
35+
#include <asm/kfence.h>
3436

3537
#include <trace/events/thp.h>
3638

@@ -293,15 +295,19 @@ static unsigned long next_boundary(unsigned long addr, unsigned long end)
293295

294296
static int __meminit create_physical_mapping(unsigned long start,
295297
unsigned long end,
296-
int nid, pgprot_t _prot)
298+
int nid, pgprot_t _prot,
299+
unsigned long mapping_sz_limit)
297300
{
298301
unsigned long vaddr, addr, mapping_size = 0;
299302
bool prev_exec, exec = false;
300303
pgprot_t prot;
301304
int psize;
302305
unsigned long max_mapping_size = memory_block_size;
303306

304-
if (debug_pagealloc_enabled_or_kfence())
307+
if (mapping_sz_limit < max_mapping_size)
308+
max_mapping_size = mapping_sz_limit;
309+
310+
if (debug_pagealloc_enabled())
305311
max_mapping_size = PAGE_SIZE;
306312

307313
start = ALIGN(start, PAGE_SIZE);
@@ -356,15 +362,83 @@ static int __meminit create_physical_mapping(unsigned long start,
356362
return 0;
357363
}
358364

365+
#ifdef CONFIG_KFENCE
366+
static bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL;
367+
368+
static int __init parse_kfence_early_init(char *arg)
369+
{
370+
int val;
371+
372+
if (get_option(&arg, &val))
373+
kfence_early_init = !!val;
374+
return 0;
375+
}
376+
early_param("kfence.sample_interval", parse_kfence_early_init);
377+
378+
static inline phys_addr_t alloc_kfence_pool(void)
379+
{
380+
phys_addr_t kfence_pool;
381+
382+
/*
383+
* TODO: Support to enable KFENCE after bootup depends on the ability to
384+
* split page table mappings. As such support is not currently
385+
* implemented for radix pagetables, support enabling KFENCE
386+
* only at system startup for now.
387+
*
388+
* After support for splitting mappings is available on radix,
389+
* alloc_kfence_pool() & map_kfence_pool() can be dropped and
390+
* mapping for __kfence_pool memory can be
391+
* split during arch_kfence_init_pool().
392+
*/
393+
if (!kfence_early_init)
394+
goto no_kfence;
395+
396+
kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE);
397+
if (!kfence_pool)
398+
goto no_kfence;
399+
400+
memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE);
401+
return kfence_pool;
402+
403+
no_kfence:
404+
disable_kfence();
405+
return 0;
406+
}
407+
408+
static inline void map_kfence_pool(phys_addr_t kfence_pool)
409+
{
410+
if (!kfence_pool)
411+
return;
412+
413+
if (create_physical_mapping(kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
414+
-1, PAGE_KERNEL, PAGE_SIZE))
415+
goto err;
416+
417+
memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
418+
__kfence_pool = __va(kfence_pool);
419+
return;
420+
421+
err:
422+
memblock_phys_free(kfence_pool, KFENCE_POOL_SIZE);
423+
disable_kfence();
424+
}
425+
#else
426+
static inline phys_addr_t alloc_kfence_pool(void) { return 0; }
427+
static inline void map_kfence_pool(phys_addr_t kfence_pool) { }
428+
#endif
429+
359430
static void __init radix_init_pgtable(void)
360431
{
432+
phys_addr_t kfence_pool;
361433
unsigned long rts_field;
362434
phys_addr_t start, end;
363435
u64 i;
364436

365437
/* We don't support slb for radix */
366438
slb_set_size(0);
367439

440+
kfence_pool = alloc_kfence_pool();
441+
368442
/*
369443
* Create the linear mapping
370444
*/
@@ -381,9 +455,11 @@ static void __init radix_init_pgtable(void)
381455
}
382456

383457
WARN_ON(create_physical_mapping(start, end,
384-
-1, PAGE_KERNEL));
458+
-1, PAGE_KERNEL, ~0UL));
385459
}
386460

461+
map_kfence_pool(kfence_pool);
462+
387463
if (!cpu_has_feature(CPU_FTR_HVMODE) &&
388464
cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) {
389465
/*
@@ -875,7 +951,7 @@ int __meminit radix__create_section_mapping(unsigned long start,
875951
}
876952

877953
return create_physical_mapping(__pa(start), __pa(end),
878-
nid, prot);
954+
nid, prot, ~0UL);
879955
}
880956

881957
int __meminit radix__remove_section_mapping(unsigned long start, unsigned long end)

arch/powerpc/mm/init-common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ EXPORT_SYMBOL_GPL(kernstart_virt_addr);
3131

3232
bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP);
3333
bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP);
34+
#ifdef CONFIG_KFENCE
35+
bool __ro_after_init kfence_disabled;
36+
#endif
3437

3538
static int __init parse_nosmep(char *p)
3639
{

0 commit comments

Comments
 (0)