selfboot: use bootmem infrastructure
Instead of packing and unpacking entries in lb_mem use the bootmem infrastructure for performing sanity checks during payload loading. Change-Id: Ica2bee7ebb0f6bf9ded31deac8cb700aa387bc7a Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/5303 Tested-by: build bot (Jenkins) Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com> Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
This commit is contained in:
parent
4904802efc
commit
ceebc0503f
|
@ -58,7 +58,6 @@ struct payload_loader_ops {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Defined in src/lib/selfboot.c */
|
/* Defined in src/lib/selfboot.c */
|
||||||
struct lb_memory;
|
void *selfload(struct payload *payload);
|
||||||
void *selfload(struct lb_memory *mem, struct payload *payload);
|
|
||||||
|
|
||||||
#endif /* PAYLOAD_LOADER_H */
|
#endif /* PAYLOAD_LOADER_H */
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <boot/coreboot_tables.h>
|
|
||||||
#include <fallback.h>
|
#include <fallback.h>
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
#include <payload_loader.h>
|
#include <payload_loader.h>
|
||||||
|
@ -44,7 +43,6 @@ struct payload *payload_load(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
void *entry;
|
void *entry;
|
||||||
struct lb_memory *mem;
|
|
||||||
const struct payload_loader_ops *ops;
|
const struct payload_loader_ops *ops;
|
||||||
struct payload *payload = &global_payload;
|
struct payload *payload = &global_payload;
|
||||||
|
|
||||||
|
@ -64,8 +62,7 @@ struct payload *payload_load(void)
|
||||||
if (i == ARRAY_SIZE(payload_ops))
|
if (i == ARRAY_SIZE(payload_ops))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mem = get_lb_mem();
|
entry = selfload(payload);
|
||||||
entry = selfload(mem, payload);
|
|
||||||
|
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -21,19 +21,14 @@
|
||||||
#include <arch/byteorder.h>
|
#include <arch/byteorder.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
#include <boot/coreboot_tables.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
|
#include <bootmem.h>
|
||||||
#include <payload_loader.h>
|
#include <payload_loader.h>
|
||||||
|
|
||||||
/* Maximum physical address we can use for the coreboot bounce buffer. */
|
|
||||||
#ifndef MAX_ADDR
|
|
||||||
#define MAX_ADDR -1UL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* from coreboot_ram.ld: */
|
/* from coreboot_ram.ld: */
|
||||||
extern unsigned char _ram_seg;
|
extern unsigned char _ram_seg;
|
||||||
extern unsigned char _eram_seg;
|
extern unsigned char _eram_seg;
|
||||||
|
@ -73,12 +68,10 @@ struct segment {
|
||||||
|
|
||||||
static unsigned long bounce_size, bounce_buffer;
|
static unsigned long bounce_size, bounce_buffer;
|
||||||
|
|
||||||
static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size)
|
static void get_bounce_buffer(unsigned long req_size)
|
||||||
{
|
{
|
||||||
unsigned long lb_size;
|
unsigned long lb_size;
|
||||||
unsigned long mem_entries;
|
void *buffer;
|
||||||
unsigned long buffer;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* When the ramstage is relocatable there is no need for a bounce
|
/* When the ramstage is relocatable there is no need for a bounce
|
||||||
* buffer. All payloads should not overlap the ramstage.
|
* buffer. All payloads should not overlap the ramstage.
|
||||||
|
@ -94,93 +87,15 @@ static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size)
|
||||||
* to place a copy to return to.
|
* to place a copy to return to.
|
||||||
*/
|
*/
|
||||||
lb_size = req_size + lb_size;
|
lb_size = req_size + lb_size;
|
||||||
mem_entries = (mem->size - sizeof(*mem)) / sizeof(mem->map[0]);
|
|
||||||
buffer = 0;
|
buffer = bootmem_allocate_buffer(lb_size);
|
||||||
for(i = 0; i < mem_entries; i++) {
|
|
||||||
unsigned long mstart, mend;
|
printk(BIOS_SPEW, "Bounce Buffer at %p, %lu bytes\n", buffer, lb_size);
|
||||||
unsigned long msize;
|
|
||||||
unsigned long tbuffer;
|
bounce_buffer = (uintptr_t)buffer;
|
||||||
if (mem->map[i].type != LB_MEM_RAM)
|
|
||||||
continue;
|
|
||||||
if (unpack_lb64(mem->map[i].start) > MAX_ADDR)
|
|
||||||
continue;
|
|
||||||
if (unpack_lb64(mem->map[i].size) < lb_size)
|
|
||||||
continue;
|
|
||||||
mstart = unpack_lb64(mem->map[i].start);
|
|
||||||
msize = MAX_ADDR - mstart +1;
|
|
||||||
if (msize > unpack_lb64(mem->map[i].size))
|
|
||||||
msize = unpack_lb64(mem->map[i].size);
|
|
||||||
mend = mstart + msize;
|
|
||||||
tbuffer = mend - lb_size;
|
|
||||||
if (tbuffer < buffer)
|
|
||||||
continue;
|
|
||||||
buffer = tbuffer;
|
|
||||||
}
|
|
||||||
bounce_buffer = buffer;
|
|
||||||
bounce_size = req_size;
|
bounce_size = req_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int valid_area(struct lb_memory *mem, unsigned long buffer,
|
|
||||||
unsigned long start, unsigned long len)
|
|
||||||
{
|
|
||||||
/* Check through all of the memory segments and ensure
|
|
||||||
* the segment that was passed in is completely contained
|
|
||||||
* in RAM.
|
|
||||||
*/
|
|
||||||
int i;
|
|
||||||
unsigned long end = start + len;
|
|
||||||
unsigned long mem_entries = (mem->size - sizeof(*mem)) /
|
|
||||||
sizeof(mem->map[0]);
|
|
||||||
|
|
||||||
/* See if I conflict with the bounce buffer */
|
|
||||||
if (end >= buffer) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Walk through the table of valid memory ranges and see if I
|
|
||||||
* have a match.
|
|
||||||
*/
|
|
||||||
for(i = 0; i < mem_entries; i++) {
|
|
||||||
uint64_t mstart, mend;
|
|
||||||
uint32_t mtype;
|
|
||||||
mtype = mem->map[i].type;
|
|
||||||
mstart = unpack_lb64(mem->map[i].start);
|
|
||||||
mend = mstart + unpack_lb64(mem->map[i].size);
|
|
||||||
if ((mtype == LB_MEM_RAM) && (start >= mstart) && (end < mend)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((mtype == LB_MEM_TABLE) && (start >= mstart) && (end < mend)) {
|
|
||||||
printk(BIOS_ERR, "Payload is overwriting coreboot tables.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == mem_entries) {
|
|
||||||
if (start < (1024*1024) && end <=(1024*1024)) {
|
|
||||||
printk(BIOS_DEBUG, "Payload (probably SeaBIOS) loaded"
|
|
||||||
" into a reserved area in the lower 1MB\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printk(BIOS_ERR, "No matching ram area found for range:\n");
|
|
||||||
printk(BIOS_ERR, " [0x%016lx, 0x%016lx)\n", start, end);
|
|
||||||
printk(BIOS_ERR, "Ram areas\n");
|
|
||||||
for(i = 0; i < mem_entries; i++) {
|
|
||||||
uint64_t mstart, mend;
|
|
||||||
uint32_t mtype;
|
|
||||||
mtype = mem->map[i].type;
|
|
||||||
mstart = unpack_lb64(mem->map[i].start);
|
|
||||||
mend = mstart + unpack_lb64(mem->map[i].size);
|
|
||||||
printk(BIOS_ERR, " [0x%016lx, 0x%016lx) %s\n",
|
|
||||||
(unsigned long)mstart,
|
|
||||||
(unsigned long)mend,
|
|
||||||
(mtype == LB_MEM_RAM)?"RAM":"Reserved");
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int overlaps_coreboot(struct segment *seg)
|
static int overlaps_coreboot(struct segment *seg)
|
||||||
{
|
{
|
||||||
unsigned long start, end;
|
unsigned long start, end;
|
||||||
|
@ -299,7 +214,6 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
|
||||||
|
|
||||||
static int build_self_segment_list(
|
static int build_self_segment_list(
|
||||||
struct segment *head,
|
struct segment *head,
|
||||||
struct lb_memory *mem,
|
|
||||||
struct payload *payload, uintptr_t *entry)
|
struct payload *payload, uintptr_t *entry)
|
||||||
{
|
{
|
||||||
struct segment *new;
|
struct segment *new;
|
||||||
|
@ -393,24 +307,48 @@ static int build_self_segment_list(
|
||||||
|
|
||||||
static int load_self_segments(
|
static int load_self_segments(
|
||||||
struct segment *head,
|
struct segment *head,
|
||||||
struct lb_memory *mem,
|
|
||||||
struct payload *payload)
|
struct payload *payload)
|
||||||
{
|
{
|
||||||
struct segment *ptr;
|
struct segment *ptr;
|
||||||
|
const unsigned long one_meg = (1UL << 20);
|
||||||
unsigned long bounce_high = lb_end;
|
unsigned long bounce_high = lb_end;
|
||||||
|
|
||||||
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
||||||
|
if (bootmem_region_targets_usable_ram(ptr->s_dstaddr,
|
||||||
|
ptr->s_memsz))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ptr->s_dstaddr < one_meg &&
|
||||||
|
(ptr->s_dstaddr + ptr->s_memsz) <= one_meg) {
|
||||||
|
printk(BIOS_DEBUG,
|
||||||
|
"Payload being loaded below 1MiB "
|
||||||
|
"without region being marked as RAM usable.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Payload segment not targeting RAM. */
|
||||||
|
printk(BIOS_ERR, "SELF Payload doesn't target RAM:\n");
|
||||||
|
printk(BIOS_ERR, "Failed Segment: 0x%lx, %lu bytes\n",
|
||||||
|
ptr->s_dstaddr, ptr->s_memsz);
|
||||||
|
bootmem_dump_ranges();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
||||||
|
/*
|
||||||
|
* Add segments to bootmem memory map before a bounce buffer is
|
||||||
|
* allocated so that there aren't conflicts with the actual
|
||||||
|
* payload.
|
||||||
|
*/
|
||||||
|
bootmem_add_range(ptr->s_dstaddr, ptr->s_memsz,
|
||||||
|
LB_MEM_UNUSABLE);
|
||||||
|
|
||||||
if (!overlaps_coreboot(ptr))
|
if (!overlaps_coreboot(ptr))
|
||||||
continue;
|
continue;
|
||||||
#if CONFIG_RELOCATABLE_RAMSTAGE
|
|
||||||
/* payloads are required to not overlap ramstage. */
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (ptr->s_dstaddr + ptr->s_memsz > bounce_high)
|
if (ptr->s_dstaddr + ptr->s_memsz > bounce_high)
|
||||||
bounce_high = ptr->s_dstaddr + ptr->s_memsz;
|
bounce_high = ptr->s_dstaddr + ptr->s_memsz;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
get_bounce_buffer(mem, bounce_high - lb_start);
|
get_bounce_buffer(bounce_high - lb_start);
|
||||||
if (!bounce_buffer) {
|
if (!bounce_buffer) {
|
||||||
printk(BIOS_ERR, "Could not find a bounce buffer...\n");
|
printk(BIOS_ERR, "Could not find a bounce buffer...\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -420,11 +358,6 @@ static int load_self_segments(
|
||||||
payload->bounce.data = (void *)(uintptr_t)bounce_buffer;
|
payload->bounce.data = (void *)(uintptr_t)bounce_buffer;
|
||||||
payload->bounce.size = bounce_size;
|
payload->bounce.size = bounce_size;
|
||||||
|
|
||||||
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
|
||||||
/* Verify the memory addresses in the segment are valid */
|
|
||||||
if (!valid_area(mem, bounce_buffer, ptr->s_dstaddr, ptr->s_memsz))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
for(ptr = head->next; ptr != head; ptr = ptr->next) {
|
||||||
unsigned char *dest, *src;
|
unsigned char *dest, *src;
|
||||||
printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
|
printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
|
||||||
|
@ -505,17 +438,17 @@ static int load_self_segments(
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *selfload(struct lb_memory *mem, struct payload *payload)
|
void *selfload(struct payload *payload)
|
||||||
{
|
{
|
||||||
uintptr_t entry = 0;
|
uintptr_t entry = 0;
|
||||||
struct segment head;
|
struct segment head;
|
||||||
|
|
||||||
/* Preprocess the self segments */
|
/* Preprocess the self segments */
|
||||||
if (!build_self_segment_list(&head, mem, payload, &entry))
|
if (!build_self_segment_list(&head, payload, &entry))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Load the segments */
|
/* Load the segments */
|
||||||
if (!load_self_segments(&head, mem, payload))
|
if (!load_self_segments(&head, payload))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
printk(BIOS_SPEW, "Loaded segments\n");
|
printk(BIOS_SPEW, "Loaded segments\n");
|
||||||
|
|
Loading…
Reference in New Issue