diff options
Diffstat (limited to 'arch/s390/boot/kaslr.c')
-rw-r--r-- | arch/s390/boot/kaslr.c | 41 |
1 files changed, 33 insertions, 8 deletions
diff --git a/arch/s390/boot/kaslr.c b/arch/s390/boot/kaslr.c index c34a6387ce38..5d12352545c5 100644 --- a/arch/s390/boot/kaslr.c +++ b/arch/s390/boot/kaslr.c @@ -3,6 +3,7 @@ * Copyright IBM Corp. 2019 */ #include <asm/mem_detect.h> +#include <asm/pgtable.h> #include <asm/cpacf.h> #include <asm/timex.h> #include <asm/sclp.h> @@ -90,8 +91,10 @@ static unsigned long get_random(unsigned long limit) unsigned long get_random_base(unsigned long safe_addr) { + unsigned long memory_limit = memory_end_set ? memory_end : 0; unsigned long base, start, end, kernel_size; unsigned long block_sum, offset; + unsigned long kasan_needs; int i; if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE) { @@ -100,14 +103,36 @@ unsigned long get_random_base(unsigned long safe_addr) } safe_addr = ALIGN(safe_addr, THREAD_SIZE); + if ((IS_ENABLED(CONFIG_KASAN))) { + /* + * Estimate kasan memory requirements, which it will reserve + * at the very end of available physical memory. To estimate + * that, we take into account that kasan would require + * 1/8 of available physical memory (for shadow memory) + + * creating page tables for the whole memory + shadow memory + * region (1 + 1/8). To keep page tables estimates simple take + * the double of combined ptes size. + */ + memory_limit = get_mem_detect_end(); + if (memory_end_set && memory_limit > memory_end) + memory_limit = memory_end; + + /* for shadow memory */ + kasan_needs = memory_limit / 8; + /* for paging structures */ + kasan_needs += (memory_limit + kasan_needs) / PAGE_SIZE / + _PAGE_ENTRIES * _PAGE_TABLE_SIZE * 2; + memory_limit -= kasan_needs; + } + kernel_size = vmlinux.image_size + vmlinux.bss_size; block_sum = 0; for_each_mem_detect_block(i, &start, &end) { - if (memory_end_set) { - if (start >= memory_end) + if (memory_limit) { + if (start >= memory_limit) break; - if (end > memory_end) - end = memory_end; + if (end > memory_limit) + end = memory_limit; } if (end - start < kernel_size) continue; @@ -125,11 +150,11 @@ unsigned long get_random_base(unsigned long safe_addr) base = safe_addr; block_sum = offset = 0; for_each_mem_detect_block(i, &start, &end) { - if (memory_end_set) { - if (start >= memory_end) + if (memory_limit) { + if (start >= memory_limit) break; - if (end > memory_end) - end = memory_end; + if (end > memory_limit) + end = memory_limit; } if (end - start < kernel_size) continue; |