selfload: check target memory type in selfload_check
Currently, selflock_check() verifies that the binary is loaded in an usable RAM area. Extend its functionality so we can also check that BL31 is loaded in a manually reserved area, and fail early if the range is not protected. Change-Id: Iecdeedd9e8da67f73ac47d2a82e85b306469a626 Signed-off-by: Ting Shen <phoenixshen@google.com> Reviewed-on: https://review.coreboot.org/c/31122 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
parent
ab92f26a13
commit
05532260ae
|
@ -19,6 +19,7 @@
|
||||||
#include <arch/transition.h>
|
#include <arch/transition.h>
|
||||||
#include <arm_tf.h>
|
#include <arm_tf.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <bootmem.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <program_loading.h>
|
#include <program_loading.h>
|
||||||
|
|
||||||
|
|
|
@ -94,8 +94,11 @@ bool bootmem_walk_os_mem(range_action_t action, void *arg);
|
||||||
*/
|
*/
|
||||||
bool bootmem_walk(range_action_t action, void *arg);
|
bool bootmem_walk(range_action_t action, void *arg);
|
||||||
|
|
||||||
/* Return 1 if region targets usable RAM, 0 otherwise. */
|
/* Returns 1 if the requested memory range is all tagged as type dest_type.
|
||||||
int bootmem_region_targets_usable_ram(uint64_t start, uint64_t size);
|
* Otherwise returns 0.
|
||||||
|
*/
|
||||||
|
int bootmem_region_targets_type(uint64_t start, uint64_t size,
|
||||||
|
enum bootmem_type dest_type);
|
||||||
|
|
||||||
/* Allocate a temporary buffer from the unused RAM areas. */
|
/* Allocate a temporary buffer from the unused RAM areas. */
|
||||||
void *bootmem_allocate_buffer(size_t size);
|
void *bootmem_allocate_buffer(size_t size);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#ifndef PROGRAM_LOADING_H
|
#ifndef PROGRAM_LOADING_H
|
||||||
#define PROGRAM_LOADING_H
|
#define PROGRAM_LOADING_H
|
||||||
|
|
||||||
|
#include <bootmem.h>
|
||||||
#include <commonlib/region.h>
|
#include <commonlib/region.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -206,7 +207,7 @@ void mirror_payload(struct prog *payload);
|
||||||
*
|
*
|
||||||
* Defined in src/lib/selfboot.c
|
* Defined in src/lib/selfboot.c
|
||||||
*/
|
*/
|
||||||
bool selfload_check(struct prog *payload);
|
bool selfload_check(struct prog *payload, enum bootmem_type dest_type);
|
||||||
bool selfload(struct prog *payload);
|
bool selfload(struct prog *payload);
|
||||||
|
|
||||||
#endif /* PROGRAM_LOADING_H */
|
#endif /* PROGRAM_LOADING_H */
|
||||||
|
|
|
@ -201,33 +201,25 @@ bool bootmem_walk(range_action_t action, void *arg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bootmem_region_targets_ram(uint64_t start, uint64_t end,
|
int bootmem_region_targets_type(uint64_t start, uint64_t size,
|
||||||
struct memranges *bm)
|
enum bootmem_type dest_type)
|
||||||
{
|
{
|
||||||
const struct range_entry *r;
|
const struct range_entry *r;
|
||||||
|
uint64_t end = start + size;
|
||||||
|
|
||||||
memranges_each_entry(r, bm) {
|
memranges_each_entry(r, &bootmem) {
|
||||||
/* All further bootmem entries are beyond this range. */
|
/* All further bootmem entries are beyond this range. */
|
||||||
if (end <= range_entry_base(r))
|
if (end <= range_entry_base(r))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (start >= range_entry_base(r) && end <= range_entry_end(r)) {
|
if (start >= range_entry_base(r) && end <= range_entry_end(r)) {
|
||||||
if (range_entry_tag(r) == BM_MEM_RAM)
|
if (range_entry_tag(r) == dest_type)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common testcase for loading any segments to bootmem.
|
|
||||||
* Returns 1 if the requested memory range is all tagged as type BM_MEM_RAM.
|
|
||||||
* Otherwise returns 0.
|
|
||||||
*/
|
|
||||||
int bootmem_region_targets_usable_ram(uint64_t start, uint64_t size)
|
|
||||||
{
|
|
||||||
return bootmem_region_targets_ram(start, start + size, &bootmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *bootmem_allocate_buffer(size_t size)
|
void *bootmem_allocate_buffer(size_t size)
|
||||||
{
|
{
|
||||||
const struct range_entry *r;
|
const struct range_entry *r;
|
||||||
|
|
|
@ -182,7 +182,7 @@ void payload_load(void)
|
||||||
|
|
||||||
switch (prog_cbfs_type(payload)) {
|
switch (prog_cbfs_type(payload)) {
|
||||||
case CBFS_TYPE_SELF: /* Simple ELF */
|
case CBFS_TYPE_SELF: /* Simple ELF */
|
||||||
selfload_check(payload);
|
selfload_check(payload, BM_MEM_RAM);
|
||||||
break;
|
break;
|
||||||
case CBFS_TYPE_FIT: /* Flattened image tree */
|
case CBFS_TYPE_FIT: /* Flattened image tree */
|
||||||
if (IS_ENABLED(CONFIG_PAYLOAD_FIT_SUPPORT)) {
|
if (IS_ENABLED(CONFIG_PAYLOAD_FIT_SUPPORT)) {
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include <cbmem.h>
|
#include <cbmem.h>
|
||||||
|
|
||||||
/* The type syntax for C is essentially unparsable. -- Rob Pike */
|
/* The type syntax for C is essentially unparsable. -- Rob Pike */
|
||||||
typedef int (*checker_t)(struct cbfs_payload_segment *cbfssegs);
|
typedef int (*checker_t)(struct cbfs_payload_segment *cbfssegs, void *args);
|
||||||
|
|
||||||
/* Decode a serialized cbfs payload segment
|
/* Decode a serialized cbfs payload segment
|
||||||
* from memory into native endianness.
|
* from memory into native endianness.
|
||||||
|
@ -46,10 +46,11 @@ static void cbfs_decode_payload_segment(struct cbfs_payload_segment *segment,
|
||||||
segment->mem_len = read_be32(&src->mem_len);
|
segment->mem_len = read_be32(&src->mem_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int segment_targets_usable_ram(void *dest, unsigned long memsz)
|
static int segment_targets_type(void *dest, unsigned long memsz,
|
||||||
|
enum bootmem_type dest_type)
|
||||||
{
|
{
|
||||||
uintptr_t d = (uintptr_t) dest;
|
uintptr_t d = (uintptr_t) dest;
|
||||||
if (bootmem_region_targets_usable_ram(d, memsz))
|
if (bootmem_region_targets_type(d, memsz, dest_type))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (payload_arch_usable_ram_quirk(d, memsz))
|
if (payload_arch_usable_ram_quirk(d, memsz))
|
||||||
|
@ -140,11 +141,13 @@ static int last_loadable_segment(struct cbfs_payload_segment *seg)
|
||||||
return read_be32(&(seg + 1)->type) == PAYLOAD_SEGMENT_ENTRY;
|
return read_be32(&(seg + 1)->type) == PAYLOAD_SEGMENT_ENTRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_payload_segments(struct cbfs_payload_segment *cbfssegs)
|
static int check_payload_segments(struct cbfs_payload_segment *cbfssegs,
|
||||||
|
void *args)
|
||||||
{
|
{
|
||||||
uint8_t *dest;
|
uint8_t *dest;
|
||||||
size_t memsz;
|
size_t memsz;
|
||||||
struct cbfs_payload_segment *first_segment, *seg, segment;
|
struct cbfs_payload_segment *first_segment, *seg, segment;
|
||||||
|
enum bootmem_type dest_type = *(enum bootmem_type *)args;
|
||||||
|
|
||||||
for (first_segment = seg = cbfssegs;; ++seg) {
|
for (first_segment = seg = cbfssegs;; ++seg) {
|
||||||
printk(BIOS_DEBUG, "Checking segment from ROM address 0x%p\n", seg);
|
printk(BIOS_DEBUG, "Checking segment from ROM address 0x%p\n", seg);
|
||||||
|
@ -153,7 +156,7 @@ static int check_payload_segments(struct cbfs_payload_segment *cbfssegs)
|
||||||
memsz = segment.mem_len;
|
memsz = segment.mem_len;
|
||||||
if (segment.type == PAYLOAD_SEGMENT_ENTRY)
|
if (segment.type == PAYLOAD_SEGMENT_ENTRY)
|
||||||
break;
|
break;
|
||||||
if (!segment_targets_usable_ram(dest, memsz))
|
if (!segment_targets_type(dest, memsz, dest_type))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -244,7 +247,7 @@ static void *selfprepare(struct prog *payload)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _selfload(struct prog *payload, checker_t f)
|
static bool _selfload(struct prog *payload, checker_t f, void *args)
|
||||||
{
|
{
|
||||||
uintptr_t entry = 0;
|
uintptr_t entry = 0;
|
||||||
struct cbfs_payload_segment *cbfssegs;
|
struct cbfs_payload_segment *cbfssegs;
|
||||||
|
@ -256,7 +259,7 @@ static bool _selfload(struct prog *payload, checker_t f)
|
||||||
|
|
||||||
cbfssegs = &((struct cbfs_payload *)data)->segments;
|
cbfssegs = &((struct cbfs_payload *)data)->segments;
|
||||||
|
|
||||||
if (f && f(cbfssegs))
|
if (f && f(cbfssegs, args))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (load_payload_segments(cbfssegs, &entry))
|
if (load_payload_segments(cbfssegs, &entry))
|
||||||
|
@ -275,12 +278,12 @@ out:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool selfload_check(struct prog *payload)
|
bool selfload_check(struct prog *payload, enum bootmem_type dest_type)
|
||||||
{
|
{
|
||||||
return _selfload(payload, check_payload_segments);
|
return _selfload(payload, check_payload_segments, &dest_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool selfload(struct prog *payload)
|
bool selfload(struct prog *payload)
|
||||||
{
|
{
|
||||||
return _selfload(payload, NULL);
|
return _selfload(payload, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue