Skip to content
Permalink
Browse files
x86/boot/compressed: Handle unaccepted memory
Firmware is responsible for accepting memory where compressed kernel
image and initrd land. But kernel has to accept memory for decompression
buffer: accept memory just before decompression starts.

KASLR is allowed to use unaccepted memory for the output buffer.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
  • Loading branch information
kiryl committed Jan 10, 2022
1 parent c1d3539 commit 38bb454722407639d0570dd216f8cf65e7f93b84
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 2 deletions.
@@ -2,6 +2,48 @@
/* Taken from lib/string.c */

#include <linux/bitmap.h>
#include <linux/math.h>
#include <linux/minmax.h>

unsigned long _find_next_bit(const unsigned long *addr1,
const unsigned long *addr2, unsigned long nbits,
unsigned long start, unsigned long invert, unsigned long le)
{
unsigned long tmp, mask;

if (unlikely(start >= nbits))
return nbits;

tmp = addr1[start / BITS_PER_LONG];
if (addr2)
tmp &= addr2[start / BITS_PER_LONG];
tmp ^= invert;

/* Handle 1st word. */
mask = BITMAP_FIRST_WORD_MASK(start);
if (le)
mask = swab(mask);

tmp &= mask;

start = round_down(start, BITS_PER_LONG);

while (!tmp) {
start += BITS_PER_LONG;
if (start >= nbits)
return nbits;

tmp = addr1[start / BITS_PER_LONG];
if (addr2)
tmp &= addr2[start / BITS_PER_LONG];
tmp ^= invert;
}

if (le)
tmp = swab(tmp);

return min(start + __ffs(tmp), nbits);
}

void __bitmap_set(unsigned long *map, unsigned int start, int len)
{
@@ -22,3 +64,23 @@ void __bitmap_set(unsigned long *map, unsigned int start, int len)
*p |= mask_to_set;
}
}

void __bitmap_clear(unsigned long *map, unsigned int start, int len)
{
unsigned long *p = map + BIT_WORD(start);
const unsigned int size = start + len;
int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);

while (len - bits_to_clear >= 0) {
*p &= ~mask_to_clear;
len -= bits_to_clear;
bits_to_clear = BITS_PER_LONG;
mask_to_clear = ~0UL;
p++;
}
if (len) {
mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
*p &= ~mask_to_clear;
}
}
@@ -725,10 +725,20 @@ process_efi_entries(unsigned long minimum, unsigned long image_size)
* but in practice there's firmware where using that memory leads
* to crashes.
*
* Only EFI_CONVENTIONAL_MEMORY is guaranteed to be free.
* Only EFI_CONVENTIONAL_MEMORY and EFI_UNACCEPTED_MEMORY (if
* supported) are guaranteed to be free.
*/
if (md->type != EFI_CONVENTIONAL_MEMORY)

switch (md->type) {
case EFI_CONVENTIONAL_MEMORY:
break;
case EFI_UNACCEPTED_MEMORY:
if (IS_ENABLED(CONFIG_UNACCEPTED_MEMORY))
break;
continue;
default:
continue;
}

if (efi_soft_reserve_enabled() &&
(md->attribute & EFI_MEMORY_SP))
@@ -18,6 +18,7 @@
#include "../string.h"
#include "../voffset.h"
#include <asm/bootparam_utils.h>
#include <asm/unaccepted_memory.h>

/*
* WARNING!!
@@ -446,6 +447,14 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
#endif

debug_putstr("\nDecompressing Linux... ");

if (IS_ENABLED(CONFIG_UNACCEPTED_MEMORY) &&
boot_params->unaccepted_memory) {
debug_putstr("Accepting memory... ");
accept_memory((phys_addr_t)output,
(phys_addr_t)output + needed_size);
}

__decompress(input_data, input_len, NULL, NULL, output, output_len,
NULL, error);
parse_elf(output);
@@ -43,3 +43,16 @@ void mark_unaccepted(struct boot_params *params, u64 start, u64 end)
bitmap_set((unsigned long *)params->unaccepted_memory,
start / PMD_SIZE, (end - start) / PMD_SIZE);
}

void accept_memory(phys_addr_t start, phys_addr_t end)
{
unsigned long *unaccepted_memory;
unsigned int rs, re;

unaccepted_memory = (unsigned long *)boot_params->unaccepted_memory;
bitmap_for_each_set_region(unaccepted_memory, rs, re,
start / PMD_SIZE, end / PMD_SIZE) {
__accept_memory(rs * PMD_SIZE, re * PMD_SIZE);
bitmap_clear(unaccepted_memory, rs, re - rs);
}
}
@@ -9,4 +9,6 @@ struct boot_params;

void mark_unaccepted(struct boot_params *params, u64 start, u64 num);

void accept_memory(phys_addr_t start, phys_addr_t end);

#endif

0 comments on commit 38bb454

Please sign in to comment.