[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