Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/25383
Change subject: lib/bootmem: Extend bootmem_allocate_buffer ......................................................................
lib/bootmem: Extend bootmem_allocate_buffer
Extend bootmem_allocate_buffer to return either memory at bottom of DRAM or at top of DRAM. Also pass the alignment as optional argument.
Protect the current executable, to prevent the loader from overwriting it. Introduce new weak functions to guard other in use memory regions. For example: TTB, CBFS cache, ATF region, ...
To be used by FIT image loading. Tested on Cavium SoC.
Change-Id: I0c983ce43616147c519a43edee3b61d54eadbb9a Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/cpu/x86/mirror_payload.c M src/include/bootmem.h M src/lib/bootmem.c M src/lib/prog_loaders.c M src/lib/selfboot.c 5 files changed, 72 insertions(+), 13 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/83/25383/1
diff --git a/src/cpu/x86/mirror_payload.c b/src/cpu/x86/mirror_payload.c index 5f0493a..d921a26 100644 --- a/src/cpu/x86/mirror_payload.c +++ b/src/cpu/x86/mirror_payload.c @@ -46,7 +46,7 @@
printk(BIOS_DEBUG, "Payload aligned size: 0x%zx\n", size);
- buffer = bootmem_allocate_buffer(size); + buffer = bootmem_allocate_buffer(size, 0, 0);
if (buffer == NULL) { printk(BIOS_DEBUG, "No buffer for mirroring payload.\n"); diff --git a/src/include/bootmem.h b/src/include/bootmem.h index 10c8d51..4235317 100644 --- a/src/include/bootmem.h +++ b/src/include/bootmem.h @@ -41,7 +41,16 @@ /* Return 1 if region targets usable RAM, 0 otherwise. */ int bootmem_region_targets_usable_ram(uint64_t start, uint64_t size);
+void bootmem_prepare_payload(void); +void bootmem_prepare_payload_arch(void); +void bootmem_prepare_payload_platform(void); + /* Allocate a temporary buffer from the unused RAM areas. */ -void *bootmem_allocate_buffer(size_t size); +void *bootmem_allocate_buffer(const size_t size, const size_t align, + const size_t prefer_low_addr); + +/* Helper to mark region as in use */ +#define BOOTMEM_RESERVED(x) bootmem_add_range((uintptr_t)_##x, _##x##_size, \ + LB_MEM_RESERVED);
#endif /* BOOTMEM_H */ diff --git a/src/lib/bootmem.c b/src/lib/bootmem.c index ea02a16..6f4bb04 100644 --- a/src/lib/bootmem.c +++ b/src/lib/bootmem.c @@ -20,6 +20,7 @@ #include <cbmem.h> #include <device/resource.h> #include <stdlib.h> +#include <symbols.h>
static struct memranges bootmem;
@@ -126,7 +127,44 @@ return 0; }
-void *bootmem_allocate_buffer(size_t size) +/** + * Overwrite on arch level to guard against overwriting in use memory regions. + * Possible regions: TTB + */ +void __attribute__((weak)) bootmem_prepare_payload_arch(void) +{ +} + +/** + * Overwrite on platform level to guard against overwriting in use memory + * regions. + * Possible regions: TIMESTAMPS + */ +void __attribute__((weak)) bootmem_prepare_payload_platform(void) +{ +} + +void bootmem_prepare_payload(void) +{ + /* Mark current program as reserved. */ + BOOTMEM_RESERVED(program) + BOOTMEM_RESERVED(stack) +} + +/** + * Allocate a slice of memory for payload related operations. + * The returned buffer doesn't overlap with anything in use and targets + * usable DRAM. + * @size: Size of buffer to allocate in bytes. + * @align: Alignment of buffer in bytes. Set to 0 if not used. + * @prefer_low_addr: Set to 1 to get a buffer from start of DRAM. + * + * Returns a buffer with given alignment in 32bit address space. + * + * Returns NULL on error. + */ +void *bootmem_allocate_buffer(const size_t size, const size_t align, + const size_t prefer_low_addr) { const struct range_entry *r; const struct range_entry *region; @@ -136,10 +174,10 @@ resource_t end;
/* 4KiB alignment. */ - size = ALIGN(size, 4096); + const size_t real_size = ALIGN(size, MAX(4096, align)); region = NULL; memranges_each_entry(r, &bootmem) { - if (range_entry_size(r) < size) + if (range_entry_size(r) < real_size) continue;
if (range_entry_tag(r) != LB_MEM_RAM) @@ -152,24 +190,32 @@ if (end > max_addr) end = max_addr;
- if ((end - range_entry_base(r)) < size) + if ((end - range_entry_base(r)) < real_size) continue;
region = r; + if (prefer_low_addr) + break; }
if (region == NULL) return NULL;
- /* region now points to the highest usable region for the given size. */ + /* + * region now points to either the lowest or to the highest usable + * region for the given size. + */ begin = range_entry_base(region); end = range_entry_end(region); - if (end > max_addr) - end = max_addr; - begin = end - size; + + if (!prefer_low_addr) { + if (end > max_addr) + end = max_addr; + begin = end - real_size; + }
/* Mark buffer as unusuable for future buffer use. */ - bootmem_add_range(begin, size, LB_MEM_UNUSABLE); + bootmem_add_range(begin, real_size, LB_MEM_UNUSABLE);
- return (void *)(uintptr_t)begin; + return (void *)((uintptr_t)ALIGN_UP(begin, align)); } diff --git a/src/lib/prog_loaders.c b/src/lib/prog_loaders.c index 128869b..0aa415a 100644 --- a/src/lib/prog_loaders.c +++ b/src/lib/prog_loaders.c @@ -29,6 +29,7 @@ #include <stage_cache.h> #include <symbols.h> #include <timestamp.h> +#include <bootmem.h>
/* Only can represent up to 1 byte less than size_t. */ const struct mem_region_device addrspace_32bit = @@ -178,6 +179,9 @@ goto out;
mirror_payload(payload); + bootmem_prepare_payload(); + bootmem_prepare_payload_arch(); + bootmem_prepare_payload_platform();
/* Pass cbtables to payload if architecture desires it. */ prog_set_entry(payload, selfload(payload, true), diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c index 160e8f5..9b97f9d 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -101,7 +101,7 @@ */ lb_size = req_size + lb_size;
- buffer = bootmem_allocate_buffer(lb_size); + buffer = bootmem_allocate_buffer(lb_size, 0, 0);
printk(BIOS_SPEW, "Bounce Buffer at %p, %lu bytes\n", buffer, lb_size);