[coreboot-gerrit] New patch to review for coreboot: Support self-relocatable images.
Vladimir Serbinenko (phcoder@gmail.com)
gerrit at coreboot.org
Sun Feb 21 19:10:52 CET 2016
Vladimir Serbinenko (phcoder at gmail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13762
-gerrit
commit 9cd149655de68e07406aa0ea3bcf8271fdfdee22
Author: Vladimir Serbinenko <phcoder at gmail.com>
Date: Sun Feb 21 19:04:57 2016 +0100
Support self-relocatable images.
On x86 we have 0x0-0x90000 and 0x100000-0xf00000 which are more or less
guaranteed to be RAM. On ARM we don't have such a range. It's possible
to make an image containing only PIC or self-relocatable. Now we need
coreboot to choose a load address itself. As an additional advantage
payload is loaded as high as possible, simplifying payload code when it
needs to load something else.
Change-Id: I27d5825e5b748a2220506005f96eceaef6d94cc2
Signed-off-by: Vladimir Serbinenko <phcoder at gmail.com>
---
Documentation/cbfs.txt | 14 ++++
payloads/libpayload/include/cbfs_core.h | 1 +
src/commonlib/include/commonlib/cbfs_serialized.h | 1 +
src/lib/selfboot.c | 89 +++++++++++++++++------
util/cbfstool/cbfs-mkpayload.c | 18 +++++
util/cbfstool/cbfs.h | 1 +
util/cbfstool/cbfs_image.c | 4 +
util/nvramtool/cbfs.h | 1 +
8 files changed, 108 insertions(+), 21 deletions(-)
diff --git a/Documentation/cbfs.txt b/Documentation/cbfs.txt
index 7ecc901..918353d 100644
--- a/Documentation/cbfs.txt
+++ b/Documentation/cbfs.txt
@@ -385,6 +385,8 @@ PAYLOAD_SEGMENT_PARAMS 0x41524150 The segment contains information for
the payload
PAYLOAD_SEGMENT_ENTRY 0x52544E45 The segment contains the entry point
for the payload
+PAYLOAD_SEGMENT_FLAGS 0x47414c46 The segment contains information for
+ for loader
'compression' is the compression scheme for the segment. Each segment can
be independently compressed. There are three compression types defined by
@@ -405,6 +407,18 @@ component.
The data will located immediately following the last segment.
+Format of FLAGS is following (everything is in native-endian):
+compatible_flags uint32 Flags that can be ignored by older
+ loaders.
+ self-relocatable bit0 Image is self-relocatable relocatable
+ and can be loaded shifted by any offset
+ divisible by align
+incompatible_flags uint32 Flags that loader must abort if it sees
+ an unknown flag. Currently none.
+align uint32 alignment requirement for
+ self-relocatable images
+
+
=== Option ROMS ===
The third specified component type will be Option ROMs. Option ROMS will
diff --git a/payloads/libpayload/include/cbfs_core.h b/payloads/libpayload/include/cbfs_core.h
index 4c59f41..eea63a5 100644
--- a/payloads/libpayload/include/cbfs_core.h
+++ b/payloads/libpayload/include/cbfs_core.h
@@ -216,6 +216,7 @@ struct cbfs_payload {
#define PAYLOAD_SEGMENT_DATA 0x41544144
#define PAYLOAD_SEGMENT_BSS 0x20535342
#define PAYLOAD_SEGMENT_PARAMS 0x41524150
+#define PAYLOAD_SEGMENT_FLAGS 0x47414c46
#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
struct cbfs_optionrom {
diff --git a/src/commonlib/include/commonlib/cbfs_serialized.h b/src/commonlib/include/commonlib/cbfs_serialized.h
index bea5d6b..9d15319 100644
--- a/src/commonlib/include/commonlib/cbfs_serialized.h
+++ b/src/commonlib/include/commonlib/cbfs_serialized.h
@@ -178,6 +178,7 @@ struct cbfs_payload {
#define PAYLOAD_SEGMENT_DATA 0x41544144
#define PAYLOAD_SEGMENT_BSS 0x20535342
#define PAYLOAD_SEGMENT_PARAMS 0x41524150
+#define PAYLOAD_SEGMENT_FLAGS 0x47414c46
#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
struct cbfs_optionrom {
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index f3a1e52..3765c47 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -210,7 +210,8 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
static int build_self_segment_list(
struct segment *head,
- struct cbfs_payload *cbfs_payload, uintptr_t *entry)
+ struct cbfs_payload *cbfs_payload, uintptr_t *entry,
+ uint32_t *align)
{
struct segment *new;
struct segment *ptr;
@@ -218,6 +219,7 @@ static int build_self_segment_list(
memset(head, 0, sizeof(*head));
head->next = head->prev = head;
first_segment = segment = &cbfs_payload->segments;
+ *align = 0;
while(1) {
printk(BIOS_DEBUG, "Loading segment from rom address 0x%p\n", segment);
@@ -227,6 +229,25 @@ static int build_self_segment_list(
segment++;
continue;
+ case PAYLOAD_SEGMENT_FLAGS:
+ printk(BIOS_DEBUG, " flags section\n");
+ uint32_t *flags;
+ flags = (uint32_t *)(((unsigned char *)first_segment)
+ + ntohl(segment->offset));
+ if (flags[1])
+ {
+ printk(BIOS_EMERG, "Unsupported incompatible flags: %x\n", flags[1]);
+ return -1;
+ }
+ if (flags[0] & 1)
+ {
+ printk(BIOS_DEBUG, "Relocatable image align %x\n", flags[2]);
+ *align = flags[2] ? : 1;
+ }
+
+ segment++;
+ continue;
+
case PAYLOAD_SEGMENT_CODE:
case PAYLOAD_SEGMENT_DATA:
printk(BIOS_DEBUG, " %s (compression=%x)\n",
@@ -305,7 +326,9 @@ static int build_self_segment_list(
static int load_self_segments(
struct segment *head,
- struct prog *payload)
+ struct prog *payload,
+ uint32_t align,
+ uintptr_t *entry)
{
struct segment *ptr;
struct segment *last_non_empty;
@@ -318,25 +341,48 @@ static int load_self_segments(
if (ptr->s_filesz != 0)
last_non_empty = ptr;
- 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;
+ if (align) {
+ uintptr_t lowest = ~(uintptr_t)0, highest = 0;
+ uintptr_t offset = 0;
+ void *target;
+ for(ptr = head->next; ptr != head; ptr = ptr->next) {
+ if (lowest > ptr->s_dstaddr)
+ lowest = ptr->s_dstaddr;
+ if (highest < ptr->s_dstaddr + ptr->s_memsz)
+ highest = ptr->s_dstaddr + ptr->s_memsz;
+ }
+ target = bootmem_allocate_buffer(highest - lowest + align - 1);
+ if (!target) {
+ printk(BIOS_ERR, "Unable to allocate 0x%lx bytes\n",
+ highest - lowest + align - 1);
+ return 0;
}
+ offset = ALIGN_UP ((uintptr_t)target - lowest, align);
+ for(ptr = head->next; ptr != head; ptr = ptr->next) {
+ ptr->s_dstaddr += offset;
+ }
+ *entry += offset;
+ } else {
+ for(ptr = head->next; ptr != head; ptr = ptr->next) {
+ if (bootmem_region_targets_usable_ram(ptr->s_dstaddr,
+ ptr->s_memsz))
+ 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;
+ 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) {
@@ -452,6 +498,7 @@ void *selfload(struct prog *payload)
uintptr_t entry = 0;
struct segment head;
void *data;
+ uint32_t align;
data = rdev_mmap_full(prog_rdev(payload));
@@ -459,11 +506,11 @@ void *selfload(struct prog *payload)
return NULL;
/* Preprocess the self segments */
- if (!build_self_segment_list(&head, data, &entry))
+ if (!build_self_segment_list(&head, data, &entry, &align))
goto out;
/* Load the segments */
- if (!load_self_segments(&head, payload))
+ if (!load_self_segments(&head, payload, align, &entry))
goto out;
printk(BIOS_SPEW, "Loaded segments\n");
diff --git a/util/cbfstool/cbfs-mkpayload.c b/util/cbfstool/cbfs-mkpayload.c
index 45d36f4..846cd74 100644
--- a/util/cbfstool/cbfs-mkpayload.c
+++ b/util/cbfstool/cbfs-mkpayload.c
@@ -110,6 +110,10 @@ int parse_elf_to_payload(const struct buffer *input, struct buffer *output,
segments++;
isize += (unsigned int)shdr[i].sh_size;
}
+ if (!strcmp(name, ".coreboot_flags")) {
+ segments++;
+ isize += (unsigned int)shdr[i].sh_size;
+ }
}
/* Now, regular headers - we only care about PT_LOAD headers,
@@ -179,6 +183,20 @@ int parse_elf_to_payload(const struct buffer *input, struct buffer *output,
segments++;
}
+ if (!strcmp(name, ".coreboot_flags")) {
+ segs[segments].type = PAYLOAD_SEGMENT_FLAGS;
+ segs[segments].load_addr = 0;
+ segs[segments].len = (unsigned int)shdr[i].sh_size;
+ segs[segments].offset = doffset;
+
+ memcpy((unsigned long *)(output->data + doffset),
+ &header[shdr[i].sh_offset], shdr[i].sh_size);
+
+ doffset += segs[segments].len;
+ osize += segs[segments].len;
+
+ segments++;
+ }
}
for (i = 0; i < headers; i++) {
diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h
index 641c6a1..6e1dd77 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -152,6 +152,7 @@ struct cbfs_stage {
#define PAYLOAD_SEGMENT_DATA makemagic('D', 'A', 'T', 'A')
#define PAYLOAD_SEGMENT_BSS makemagic('B', 'S', 'S', ' ')
#define PAYLOAD_SEGMENT_PARAMS makemagic('P', 'A', 'R', 'A')
+#define PAYLOAD_SEGMENT_FLAGS makemagic('F', 'L', 'A', 'G')
#define PAYLOAD_SEGMENT_ENTRY makemagic('E', 'N', 'T', 'R')
struct cbfs_payload_segment {
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 95e6f42..9d5441c 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -1093,6 +1093,10 @@ static int cbfs_print_decoded_payload_segment_info(
fprintf(fp, " parameters\n");
break;
+ case PAYLOAD_SEGMENT_FLAGS:
+ fprintf(fp, " flags\n");
+ break;
+
default:
fprintf(fp, " 0x%x (%s compression, offset: 0x%x, "
"load: 0x%" PRIx64 ", length: %d/%d\n",
diff --git a/util/nvramtool/cbfs.h b/util/nvramtool/cbfs.h
index 58ef126..3158a39 100644
--- a/util/nvramtool/cbfs.h
+++ b/util/nvramtool/cbfs.h
@@ -159,6 +159,7 @@ struct cbfs_payload {
#define PAYLOAD_SEGMENT_BSS 0x20535342
#define PAYLOAD_SEGMENT_PARAMS 0x41524150
#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
+#define PAYLOAD_SEGMENT_FLAGS 0x47414c46
struct cbfs_optionrom {
u32 compression;
More information about the coreboot-gerrit
mailing list