[coreboot-gerrit] Change in coreboot[master]: lib: Add FIT payload support

Philipp Deppenwiese (Code Review) gerrit at coreboot.org
Tue Jun 19 20:10:10 CEST 2018


Philipp Deppenwiese has submitted this change and it was merged. ( https://review.coreboot.org/25019 )

Change subject: lib: Add FIT payload support
......................................................................

lib: Add FIT payload support

* Add support for parsing and booting FIT payloads.
* Build fit loader code from depthcharge.
* Fix coding style.
* Add Kconfig option to add compiletime support for FIT.
* Add support for initrd.
* Add default compat strings
* Apply optional devicetree fixups using dt_apply_fixups

Starting at this point the CBFS payload/ can be either SELF or FIT.

Tested on Cavium SoC: Parses and loads a Linux kernel 4.16.3.
Tested on Cavium SoC: Parses and loads a Linux kernel 4.15.0.
Tested on Cavium SoC: Parses and loads a Linux kernel 4.1.52.

Change-Id: I0f27b92a5e074966f893399eb401eb97d784850d
Signed-off-by: Patrick Rudolph <patrick.rudolph at 9elements.com>
Reviewed-on: https://review.coreboot.org/25019
Tested-by: build bot (Jenkins) <no-reply at coreboot.org>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki at gmail.com>
---
M payloads/Kconfig
M src/arch/arm64/Makefile.inc
A src/arch/arm64/fit_payload.c
M src/include/fit.h
A src/include/fit_payload.h
M src/lib/Makefile.inc
M src/lib/fit.c
A src/lib/fit_payload.c
M src/lib/prog_loaders.c
9 files changed, 840 insertions(+), 261 deletions(-)

Approvals:
  build bot (Jenkins): Verified
  Philipp Deppenwiese: Looks good to me, approved



diff --git a/payloads/Kconfig b/payloads/Kconfig
index 2a329ac..782f3e0 100644
--- a/payloads/Kconfig
+++ b/payloads/Kconfig
@@ -8,6 +8,17 @@
 	default PAYLOAD_NONE if NO_DEFAULT_PAYLOAD || !ARCH_X86
 	default PAYLOAD_SEABIOS if ARCH_X86
 
+config PAYLOAD_FIT
+	bool "A FIT payload"
+	select PAYLOAD_FIT_SUPPORT
+	help
+	  Select this option if you have a payload image (a FIT file) which
+	  coreboot should run as soon as the basic hardware initialization
+	  is completed.
+
+	  You will be able to specify the location and file name of the
+	  payload image later.
+
 config PAYLOAD_NONE
 	bool "None"
 	help
@@ -44,8 +55,9 @@
 
 config PAYLOAD_FILE
 	string "Payload path and filename"
-	depends on PAYLOAD_ELF
-	default "payload.elf"
+	depends on PAYLOAD_ELF || PAYLOAD_FIT
+	default "payload.elf" if PAYLOAD_ELF
+	default "uImage" if PAYLOAD_FIT
 	help
 	  The path and filename of the ELF executable file to use as payload.
 
@@ -82,6 +94,16 @@
 	  Add the payload to cbfs as a flat binary type instead of as an
 	  elf payload
 
+config PAYLOAD_FIT_SUPPORT
+	bool "FIT support"
+	default n
+	default y if PAYLOAD_LINUX && (ARCH_ARM || ARCH_ARM64)
+	select FLATTENED_DEVICE_TREE
+	help
+	  Select this option if your payload is of type FIT.
+	  Enables FIT parser and devicetree patching. The FIT is non
+	  self-extracting and need to have a compatible compression format.
+
 config COMPRESS_SECONDARY_PAYLOAD
 	bool "Use LZMA compression for secondary payloads"
 	default y
diff --git a/src/arch/arm64/Makefile.inc b/src/arch/arm64/Makefile.inc
index f57ef72..3c3cd20 100644
--- a/src/arch/arm64/Makefile.inc
+++ b/src/arch/arm64/Makefile.inc
@@ -136,6 +136,7 @@
 ramstage-y += memmove.S
 ramstage-$(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE) += arm_tf.c
 ramstage-y += transition.c transition_asm.S
+ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) += fit_payload.c
 
 rmodules_arm64-y += memset.S
 rmodules_arm64-y += memcpy.S
diff --git a/src/arch/arm64/fit_payload.c b/src/arch/arm64/fit_payload.c
new file mode 100644
index 0000000..c4bbcee
--- /dev/null
+++ b/src/arch/arm64/fit_payload.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2013 Google Inc.
+ * Copyright 2018 Facebook, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <bootmem.h>
+#include <stdlib.h>
+#include <program_loading.h>
+#include <string.h>
+#include <commonlib/compression.h>
+#include <commonlib/cbfs_serialized.h>
+#include <lib.h>
+#include <fit.h>
+#include <endian.h>
+
+#define MAX_KERNEL_SIZE (64*MiB)
+
+struct arm64_kernel_header {
+	u32 code0;
+	u32 code1;
+	u64 text_offset;
+	u64 image_size;
+	u64 flags;
+	u64 res2;
+	u64 res3;
+	u64 res4;
+	u32 magic;
+#define KERNEL_HEADER_MAGIC  0x644d5241
+	u32 res5;
+};
+
+static struct {
+	union {
+		struct arm64_kernel_header header;
+		u8 raw[sizeof(struct arm64_kernel_header) + 0x100];
+	};
+#define SCRATCH_CANARY_VALUE 0xdeadbeef
+	u32 canary;
+} scratch;
+
+/* Returns true if decompressing was successful and it looks like a kernel. */
+static bool decompress_kernel_header(const struct fit_image_node *node)
+{
+	/* Partially decompress to get text_offset. Can't check for errors. */
+	scratch.canary = SCRATCH_CANARY_VALUE;
+	switch (node->compression) {
+	case CBFS_COMPRESS_NONE:
+		memcpy(scratch.raw, node->data, sizeof(scratch.raw));
+		break;
+	case CBFS_COMPRESS_LZMA:
+		ulzman(node->data, node->size,
+		       scratch.raw, sizeof(scratch.raw));
+		break;
+	case CBFS_COMPRESS_LZ4:
+		ulz4fn(node->data, node->size,
+		       scratch.raw, sizeof(scratch.raw));
+		break;
+	default:
+		printk(BIOS_ERR, "ERROR: Unsupported compression algorithm!\n");
+		return false;
+	}
+
+	/* Should never happen, but if it does we'll want to know. */
+	if (scratch.canary != SCRATCH_CANARY_VALUE)
+		die("ERROR: Partial decompression ran over scratchbuf!\n");
+
+	if (scratch.header.magic != KERNEL_HEADER_MAGIC) {
+		printk(BIOS_ERR,
+		       "ERROR: Invalid kernel magic: %#.8x\n != %#.8x\n",
+		       scratch.header.magic, KERNEL_HEADER_MAGIC);
+		return false;
+	}
+
+	/**
+	 * Prior to v3.17, the endianness of text_offset was not specified.  In
+	 * these cases image_size is zero and text_offset is 0x80000 in the
+	 * endianness of the kernel.  Where image_size is non-zero image_size is
+	 * little-endian and must be respected.  Where image_size is zero,
+	 * text_offset can be assumed to be 0x80000.
+	 */
+	if (!scratch.header.image_size)
+		scratch.header.text_offset = cpu_to_le64(0x80000);
+
+	return true;
+}
+
+static size_t get_kernel_size(const struct fit_image_node *node)
+{
+	if (scratch.header.image_size)
+		return le64_to_cpu(scratch.header.image_size);
+
+	/**
+	 * When image_size is zero, a bootloader should attempt to keep as much
+	 * memory as possible free for use by the kernel immediately after the
+	 * end of the kernel image. The amount of space required will vary
+	 * depending on selected features, and is effectively unbound.
+	 */
+
+	printk(BIOS_WARNING, "FIT: image_size not set in kernel header.\n"
+	       "Leaving additional %u MiB of free space after kernel.\n",
+	       MAX_KERNEL_SIZE >> 20);
+
+	return node->size + MAX_KERNEL_SIZE;
+}
+
+static bool fit_place_kernel(const struct range_entry *r, void *arg)
+{
+	struct region *region = arg;
+	resource_t start;
+
+	if (range_entry_tag(r) != BM_MEM_RAM)
+		return true;
+
+	/**
+	 * The Image must be placed text_offset bytes from a 2MB aligned base
+	 * address anywhere in usable system RAM and called there. The region
+	 * between the 2 MB aligned base address and the start of the image has
+	 * no special significance to the kernel, and may be used for other
+	 * purposes.
+	 *
+	 * If the reserved memory (BL31 for example) is smaller than text_offset
+	 * we can use the 2 MiB base address, otherwise use the next 2 MiB page.
+	 * It's not mandatory, but wastes less memory below the kernel.
+	 */
+	start = ALIGN_DOWN(range_entry_base(r), 2 * MiB) +
+		le64_to_cpu(scratch.header.text_offset);
+
+	if (start < range_entry_base(r))
+		start += 2 * MiB;
+	/**
+	 * At least image_size bytes from the start of the image must be free
+	 * for use by the kernel.
+	 */
+	if (start + region->size < range_entry_end(r)) {
+		region->offset = (size_t)start;
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * Place the region in free memory range.
+ *
+ * The caller has to set region->offset to the minimum allowed address.
+ * The region->offset is usually 0 on kernel >v4.6 and kernel_base + kernel_size
+ * on kernel <v4.6.
+ */
+static bool fit_place_mem(const struct range_entry *r, void *arg)
+{
+	struct region *region = arg;
+	resource_t start;
+
+	if (range_entry_tag(r) != BM_MEM_RAM)
+		return true;
+
+	/* Linux 4.15 doesn't like 4KiB alignment. Align to 1 MiB for now. */
+	start = ALIGN_UP(MAX(region->offset, range_entry_base(r)), 1 * MiB);
+
+	if (start + region->size < range_entry_end(r)) {
+		region->offset = (size_t)start;
+		return false;
+	}
+
+	return true;
+}
+
+bool fit_payload_arch(struct prog *payload, struct fit_config_node *config,
+		      struct region *kernel,
+		      struct region *fdt,
+		      struct region *initrd)
+{
+	bool place_anywhere;
+	void *arg = NULL;
+
+	if (!config->fdt || !fdt) {
+		printk(BIOS_CRIT, "CRIT: Providing a valid FDT is mandatory to "
+		       "boot an ARM64 kernel!\n");
+		return false;
+	}
+
+	if (!decompress_kernel_header(config->kernel_node)) {
+		printk(BIOS_CRIT, "CRIT: Payload doesn't look like an ARM64"
+		       " kernel Image.\n");
+		return false;
+	}
+
+	/* Update kernel size from image header, if possible */
+	kernel->size = get_kernel_size(config->kernel_node);
+	printk(BIOS_DEBUG, "FIT: Using kernel size of 0x%zx bytes\n",
+	       kernel->size);
+
+	/**
+	 * The code assumes that bootmem_walk provides a sorted list of memory
+	 * regions, starting from the lowest address.
+	 * The order of the calls here doesn't matter, as the placement is
+	 * enforced in the called functions.
+	 * For details check code on top.
+	 */
+
+	if (!bootmem_walk(fit_place_kernel, kernel))
+		return false;
+
+	/* Mark as reserved for future allocations. */
+	bootmem_add_range(kernel->offset, kernel->size, BM_MEM_PAYLOAD);
+
+	/**
+	 * NOTE: versions prior to v4.6 cannot make use of memory below the
+	 * physical offset of the Image so it is recommended that the Image be
+	 * placed as close as possible to the start of system RAM.
+	 *
+	 * For kernel <v4.6 the INITRD and FDT can't be placed below the kernel.
+	 * In that case set region offset to an address on top of kernel.
+	 */
+	place_anywhere = !!(le64_to_cpu(scratch.header.flags) & (1 << 3));
+	printk(BIOS_DEBUG, "FIT: Placing FDT and INITRD %s\n",
+	       place_anywhere ? "anywhere" : "on top of kernel");
+
+	/* Place INITRD */
+	if (config->ramdisk) {
+		if (place_anywhere)
+			initrd->offset = 0;
+		else
+			initrd->offset = kernel->offset + kernel->size;
+
+		if (!bootmem_walk(fit_place_mem, initrd))
+			return false;
+		/* Mark as reserved for future allocations. */
+		bootmem_add_range(initrd->offset, initrd->size, BM_MEM_PAYLOAD);
+	}
+
+	/* Place FDT */
+	if (place_anywhere)
+		fdt->offset = 0;
+	else
+		fdt->offset = kernel->offset + kernel->size;
+
+	if (!bootmem_walk(fit_place_mem, fdt))
+		return false;
+	/* Mark as reserved for future allocations. */
+	bootmem_add_range(fdt->offset, fdt->size, BM_MEM_PAYLOAD);
+
+	/* Kernel expects FDT as argument */
+	arg = (void *)fdt->offset;
+
+	prog_set_entry(payload, (void *)kernel->offset, arg);
+
+	bootmem_dump_ranges();
+
+	return true;
+}
diff --git a/src/include/fit.h b/src/include/fit.h
index 1b2f975..eb51b50 100644
--- a/src/include/fit.h
+++ b/src/include/fit.h
@@ -1,8 +1,8 @@
 /*
  * Copyright 2013 Google Inc.
+ * Copyright 2018-present Facebook, Inc.
  *
- * See file CREDITS for list of people who contributed to this
- * project.
+ * Taken from depthcharge: src/boot/fit.h
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -15,64 +15,85 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __BOOT_FIT_H__
-#define __BOOT_FIT_H__
+#ifndef __LIB_FIT_H__
+#define __LIB_FIT_H__
 
 #include <stddef.h>
 #include <stdint.h>
+#include <device_tree.h>
+#include <list.h>
+#include <program_loading.h>
 
-#include "base/device_tree.h"
-#include "base/list.h"
-
-typedef enum CompressionType
-{
-	CompressionInvalid,
-	CompressionNone,
-	CompressionLzma,
-	CompressionLz4,
-} CompressionType;
-
-typedef struct FitImageNode
+struct fit_image_node
 {
 	const char *name;
 	void *data;
 	uint32_t size;
-	CompressionType compression;
+	int compression;
 
-	ListNode list_node;
-} FitImageNode;
+	struct list_node list_node;
+};
 
-typedef struct FitConfigNode
+struct fit_config_node
 {
 	const char *name;
 	const char *kernel;
-	FitImageNode *kernel_node;
+	struct fit_image_node *kernel_node;
 	const char *fdt;
-	FitImageNode *fdt_node;
+	struct fit_image_node *fdt_node;
 	const char *ramdisk;
-	FitImageNode *ramdisk_node;
-	FdtProperty compat;
+	struct fit_image_node *ramdisk_node;
+	struct fdt_property compat;
 	int compat_rank;
 	int compat_pos;
+	const char *compat_string;
 
-	ListNode list_node;
-} FitConfigNode;
+	struct list_node list_node;
+};
+
+/*
+ * Updates the cmdline in the devicetree.
+ */
+void fit_update_chosen(struct device_tree *tree, char *cmd_line);
+
+/*
+ * Add a compat string to the list of supported board ids.
+ * Has to be called before fit_load().
+ * The most common use-case would be to implement it on board level.
+ * Strings that were added first have a higher priority on finding a match.
+ */
+void fit_add_compat_string(const char *str);
+
+/*
+ * Updates the memory section in the devicetree.
+ */
+void fit_update_memory(struct device_tree *tree);
+
+/*
+ * Do architecture specific payload placements and fixups.
+ * Set entrypoint and first argument (if any).
+ * @param payload The payload, to set the entry point
+ * @param config The extracted FIT config
+ * @param kernel out-argument where to place the kernel
+ * @param fdt out-argument where to place the devicetree
+ * @param initrd out-argument where to place the initrd (optional)
+ * @return True if all config nodes could be placed, the corresponding
+ *         regions have been updated and the entry point has been set.
+ *         False on error.
+ */
+bool fit_payload_arch(struct prog *payload, struct fit_config_node *config,
+		      struct region *kernel,
+		      struct region *fdt,
+		      struct region *initrd);
 
 /*
  * Unpack a FIT image into memory, choosing the right configuration through the
- * compatible string set by fit_add_compat() and unflattening the corresponding
- * kernel device tree.
+ * compatible string set by fit_add_compat() and return the selected config
+ * node.
  */
-FitImageNode *fit_load(void *fit, char *cmd_line, DeviceTree **dt);
+struct fit_config_node *fit_load(void *fit);
 
-/*
- * Add a compatible string for the preferred kernel DT to the list for this
- * platform. This should be called before the first fit_load() so it will be
- * ranked as a better match than the default compatible strings. |compat| must
- * stay accessible throughout depthcharge's runtime (i.e. not stack-allocated)!
- */
-void fit_add_compat(const char *compat);
+void fit_add_ramdisk(struct device_tree *tree, void *ramdisk_addr,
+		     size_t ramdisk_size);
 
-void fit_add_ramdisk(DeviceTree *tree, void *ramdisk_addr, size_t ramdisk_size);
-
-#endif /* __BOOT_FIT_H__ */
+#endif /* __LIB_FIT_H__ */
diff --git a/src/include/fit_payload.h b/src/include/fit_payload.h
new file mode 100644
index 0000000..dd66289
--- /dev/null
+++ b/src/include/fit_payload.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __FIT_PAYLOAD_H_
+#define __FIT_PAYLOAD_H_
+
+#include <program_loading.h>
+#include <stdint.h>
+
+void fit_payload(struct prog *payload);
+
+#endif /* __FIT_PAYLOAD_H_ */
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc
index 08ad9b2..4ae80d3 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -150,6 +150,8 @@
 ramstage-$(CONFIG_ACPI_NHLT) += nhlt.c
 ramstage-y += list.c
 ramstage-$(CONFIG_FLATTENED_DEVICE_TREE) += device_tree.c
+ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) += fit.c
+ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) += fit_payload.c
 
 romstage-y += cbmem_common.c
 romstage-y += imd_cbmem.c
diff --git a/src/lib/fit.c b/src/lib/fit.c
index 79af36c..fe8a82e 100644
--- a/src/lib/fit.c
+++ b/src/lib/fit.c
@@ -1,8 +1,8 @@
 /*
  * Copyright 2013 Google Inc.
+ * Copyright 2018-present Facebook, Inc.
  *
- * See file CREDITS for list of people who contributed to this
- * project.
+ * Taken from depthcharge: src/boot/fit.c
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -17,93 +17,99 @@
 
 #include <assert.h>
 #include <endian.h>
-#include <libpayload.h>
 #include <stdint.h>
+#include <bootmem.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cbfs.h>
+#include <program_loading.h>
+#include <timestamp.h>
+#include <memrange.h>
+#include <fit.h>
+#include <boardid.h>
+#include <commonlib/include/commonlib/stdlib.h>
 
-#include "base/ranges.h"
-#include "boot/fit.h"
+static struct list_node image_nodes;
+static struct list_node config_nodes;
+static struct list_node compat_strings;
 
+struct compat_string_entry {
+	const char *compat_string;
+	struct list_node list_node;
+};
 
-
-static ListNode image_nodes;
-static ListNode config_nodes;
-
-static const char *fit_kernel_compat[10] = { NULL };
-static int num_fit_kernel_compat = 0;
-
-void fit_add_compat(const char *compat)
+/* Convert string to lowercase and replace '_' with '-'. */
+static char *clean_compat_string(char *str)
 {
-	assert(num_fit_kernel_compat < ARRAY_SIZE(fit_kernel_compat));
-	fit_kernel_compat[num_fit_kernel_compat++] = compat;
+	for (size_t i = 0; i < strlen(str); i++) {
+		str[i] = tolower(str[i]);
+		if (str[i] == '_')
+			str[i] = '-';
+	}
+
+	return str;
 }
 
-static void fit_add_default_compats(void)
+static void fit_add_default_compat_strings(void)
 {
-	const char pattern[] = "google,%s-rev%u-sku%u";
-	u32 rev = lib_sysinfo.board_id;
-	u32 sku = lib_sysinfo.sku_id;
+	char compat_string[80] = {};
 
-	static int done = 0;
-	if (done)
-		return;
-	done = 1;
+	if ((board_id() != UNDEFINED_STRAPPING_ID) &&
+	    (sku_id() != UNDEFINED_STRAPPING_ID)) {
+		snprintf(compat_string, sizeof(compat_string),
+			 "%s,%s-rev%u-sku%u", CONFIG_MAINBOARD_VENDOR,
+			 CONFIG_MAINBOARD_PART_NUMBER, board_id(), sku_id());
 
-	char *compat = xmalloc(sizeof(pattern) + sizeof(CONFIG_BOARD) + 20);
-	sprintf(compat, pattern, CONFIG_BOARD,
-		lib_sysinfo.board_id, lib_sysinfo.sku_id);
+		fit_add_compat_string(compat_string);
+	}
 
-	char *c;
-	for (c = compat; *c != '\0'; c++)
-		if (*c == '_')
-			*c = '-';
+	if (board_id() != UNDEFINED_STRAPPING_ID) {
+		snprintf(compat_string, sizeof(compat_string), "%s,%s-rev%u",
+			 CONFIG_MAINBOARD_VENDOR, CONFIG_MAINBOARD_PART_NUMBER,
+			 board_id());
 
-	if (sku != UNDEFINED_STRAPPING_ID && rev != UNDEFINED_STRAPPING_ID)
-		fit_add_compat(strdup(compat));
+		fit_add_compat_string(compat_string);
+	}
 
-	*strrchr(compat, '-') = '\0';
-	if (rev != UNDEFINED_STRAPPING_ID)
-		fit_add_compat(strdup(compat));
+	snprintf(compat_string, sizeof(compat_string), "%s,%s",
+		 CONFIG_MAINBOARD_VENDOR, CONFIG_MAINBOARD_PART_NUMBER);
 
-	*strrchr(compat, '-') = '\0';
-	fit_add_compat(compat);
+	fit_add_compat_string(compat_string);
 }
 
-
-
-
-static void image_node(DeviceTreeNode *node)
+static void image_node(struct device_tree_node *node)
 {
-	FitImageNode *image = xzalloc(sizeof(*image));
-	image->compression = CompressionNone;
+	struct fit_image_node *image = xzalloc(sizeof(*image));
 
+	image->compression = CBFS_COMPRESS_NONE;
 	image->name = node->name;
 
-	DeviceTreeProperty *prop;
+	struct device_tree_property *prop;
 	list_for_each(prop, node->properties, list_node) {
 		if (!strcmp("data", prop->prop.name)) {
 			image->data = prop->prop.data;
 			image->size = prop->prop.size;
 		} else if (!strcmp("compression", prop->prop.name)) {
 			if (!strcmp("none", prop->prop.data))
-				image->compression = CompressionNone;
+				image->compression = CBFS_COMPRESS_NONE;
 			else if (!strcmp("lzma", prop->prop.data))
-				image->compression = CompressionLzma;
+				image->compression = CBFS_COMPRESS_LZMA;
 			else if (!strcmp("lz4", prop->prop.data))
-				image->compression = CompressionLz4;
+				image->compression = CBFS_COMPRESS_LZ4;
 			else
-				image->compression = CompressionInvalid;
+				image->compression = -1;
 		}
 	}
 
 	list_insert_after(&image->list_node, &image_nodes);
 }
 
-static void config_node(DeviceTreeNode *node)
+static void config_node(struct device_tree_node *node)
 {
-	FitConfigNode *config = xzalloc(sizeof(*config));
+	struct fit_config_node *config = xzalloc(sizeof(*config));
 	config->name = node->name;
 
-	DeviceTreeProperty *prop;
+	struct device_tree_property *prop;
 	list_for_each(prop, node->properties, list_node) {
 		if (!strcmp("kernel", prop->prop.name))
 			config->kernel = prop->prop.data;
@@ -116,21 +122,20 @@
 	list_insert_after(&config->list_node, &config_nodes);
 }
 
-static void fit_unpack(DeviceTree *tree, const char **default_config)
+static void fit_unpack(struct device_tree *tree, const char **default_config)
 {
 	assert(tree && tree->root);
 
-	DeviceTreeNode *top;
+	struct device_tree_node *top;
 	list_for_each(top, tree->root->children, list_node) {
-		DeviceTreeNode *child;
+		struct device_tree_node *child;
 		if (!strcmp("images", top->name)) {
 
 			list_for_each(child, top->children, list_node)
 				image_node(child);
 
 		} else if (!strcmp("configurations", top->name)) {
-
-			DeviceTreeProperty *prop;
+			struct device_tree_property *prop;
 			list_for_each(prop, top->properties, list_node) {
 				if (!strcmp("default", prop->prop.name) &&
 						default_config)
@@ -143,9 +148,9 @@
 	}
 }
 
-static FitImageNode *find_image(const char *name)
+static struct fit_image_node *find_image(const char *name)
 {
-	FitImageNode *image;
+	struct fit_image_node *image;
 	list_for_each(image, image_nodes, list_node) {
 		if (!strcmp(image->name, name))
 			return image;
@@ -153,7 +158,8 @@
 	return NULL;
 }
 
-static int fdt_find_compat(void *blob, uint32_t start_offset, FdtProperty *prop)
+static int fdt_find_compat(void *blob, uint32_t start_offset,
+			   struct fdt_property *prop)
 {
 	int offset = start_offset;
 	int size;
@@ -174,7 +180,8 @@
 	return -1;
 }
 
-static int fit_check_compat(FdtProperty *compat_prop, const char *compat_name)
+static int fit_check_compat(struct fdt_property *compat_prop,
+			    const char *compat_name)
 {
 	int bytes = compat_prop->size;
 	const char *compat_str = compat_prop->data;
@@ -189,18 +196,21 @@
 	return -1;
 }
 
-static void update_chosen(DeviceTree *tree, char *cmd_line)
+void fit_update_chosen(struct device_tree *tree, char *cmd_line)
 {
 	const char *path[] = { "chosen", NULL };
-	DeviceTreeNode *node = dt_find_node(tree->root, path, NULL, NULL, 1);
+	struct device_tree_node *node;
+	node = dt_find_node(tree->root, path, NULL, NULL, 1);
 
 	dt_add_string_prop(node, "bootargs", cmd_line);
 }
 
-void fit_add_ramdisk(DeviceTree *tree, void *ramdisk_addr, size_t ramdisk_size)
+void fit_add_ramdisk(struct device_tree *tree, void *ramdisk_addr,
+		     size_t ramdisk_size)
 {
 	const char *path[] = { "chosen", NULL };
-	DeviceTreeNode *node = dt_find_node(tree->root, path, NULL, NULL, 1);
+	struct device_tree_node *node;
+	node = dt_find_node(tree->root, path, NULL, NULL, 1);
 
 	/* Warning: this assumes the ramdisk is currently located below 4GiB. */
 	u32 start = (uintptr_t)ramdisk_addr;
@@ -210,49 +220,40 @@
 	dt_add_u32_prop(node, "linux,initrd-end", end);
 }
 
-static void update_reserve_map(uint64_t start, uint64_t end, void *data)
+static void update_reserve_map(uint64_t start, uint64_t end,
+			       struct device_tree *tree)
 {
-	DeviceTree *tree = (DeviceTree *)data;
+	struct device_tree_reserve_map_entry *entry = xzalloc(sizeof(*entry));
 
-	DeviceTreeReserveMapEntry *entry = xzalloc(sizeof(*entry));
 	entry->start = start;
 	entry->size = end - start;
 
 	list_insert_after(&entry->list_node, &tree->reserve_map);
 }
 
-typedef struct EntryParams
-{
+struct entry_params {
 	unsigned addr_cells;
 	unsigned size_cells;
 	void *data;
-} EntryParams;
+};
 
 static uint64_t max_range(unsigned size_cells)
 {
-	// Split up ranges who's sizes are too large to fit in #size-cells.
-	// The largest value we can store isn't a power of two, so we'll round
-	// down to make the math easier.
+	/*
+	 * Split up ranges who's sizes are too large to fit in #size-cells.
+	 * The largest value we can store isn't a power of two, so we'll round
+	 * down to make the math easier.
+	 */
 	return 0x1ULL << (size_cells * 32 - 1);
 }
 
-static void count_entries(u64 start, u64 end, void *pdata)
+static void update_mem_property(u64 start, u64 end, struct entry_params *params)
 {
-	EntryParams *params = (EntryParams *)pdata;
-	unsigned *count = (unsigned *)params->data;
-	u64 size = end - start;
-	u64 max_size = max_range(params->size_cells);
-	*count += ALIGN_UP(size, max_size) / max_size;
-}
-
-static void update_mem_property(u64 start, u64 end, void *pdata)
-{
-	EntryParams *params = (EntryParams *)pdata;
 	u8 *data = (u8 *)params->data;
 	u64 full_size = end - start;
 	while (full_size) {
 		const u64 max_size = max_range(params->size_cells);
-		const u32 size = MIN(max_size, full_size);
+		const u64 size = MIN(max_size, full_size);
 
 		dt_write_int(data, start, params->addr_cells * sizeof(u32));
 		data += params->addr_cells * sizeof(uint32_t);
@@ -265,109 +266,189 @@
 	params->data = data;
 }
 
-static void update_memory(DeviceTree *tree)
+struct mem_map {
+	struct memranges mem;
+	struct memranges reserved;
+};
+
+static bool walk_memory_table(const struct range_entry *r, void *arg)
 {
-	Ranges mem;
-	Ranges reserved;
-	DeviceTreeNode *node;
+	struct mem_map *arg_map = arg;
+
+	/*
+	 * Kernel likes its available memory areas at least 1MB
+	 * aligned, let's trim the regions such that unaligned padding
+	 * is added to reserved memory.
+	 */
+	if (range_entry_tag(r) == BM_MEM_RAM) {
+		uint64_t new_start = ALIGN_UP(range_entry_base(r), 1 * MiB);
+		uint64_t new_end = ALIGN_DOWN(range_entry_end(r), 1 * MiB);
+
+		if (new_start != range_entry_base(r))
+			memranges_insert(&arg_map->reserved,
+					 range_entry_base(r),
+					 new_start - range_entry_base(r),
+					 BM_MEM_RESERVED);
+
+		if (new_start != new_end)
+			memranges_insert(&arg_map->mem, new_start,
+					 new_end - new_start, BM_MEM_RAM);
+
+		if (new_end != range_entry_end(r))
+			memranges_insert(&arg_map->reserved, new_end,
+					 range_entry_end(r) - new_end,
+					 BM_MEM_RESERVED);
+	} else
+		memranges_insert(&arg_map->reserved, range_entry_base(r),
+				 range_entry_size(r),
+				 BM_MEM_RESERVED);
+
+	return true;
+}
+
+void fit_add_compat_string(const char *str)
+{
+	struct compat_string_entry *compat_node;
+
+	compat_node = xzalloc(sizeof(*compat_node));
+	compat_node->compat_string = strdup(str);
+
+	clean_compat_string((char *)compat_node->compat_string);
+
+	list_insert_after(&compat_node->list_node, &compat_strings);
+}
+
+void fit_update_memory(struct device_tree *tree)
+{
+	const struct range_entry *r;
+	struct device_tree_node *node;
 	u32 addr_cells = 1, size_cells = 1;
+	struct mem_map map;
+
+	printk(BIOS_INFO, "FIT: Updating devicetree memory entries\n");
+
 	dt_read_cell_props(tree->root, &addr_cells, &size_cells);
 
-	// First remove all existing device_type="memory" nodes, then add ours.
+	/*
+	 * First remove all existing device_type="memory" nodes, then add ours.
+	 */
 	list_for_each(node, tree->root->children, list_node) {
 		const char *devtype = dt_find_string_prop(node, "device_type");
 		if (devtype && !strcmp(devtype, "memory"))
 			list_remove(&node->list_node);
 	}
+
 	node = xzalloc(sizeof(*node));
+
 	node->name = "memory";
 	list_insert_after(&node->list_node, &tree->root->children);
-	dt_add_string_prop(node, "device_type", "memory");
+	dt_add_string_prop(node, "device_type", (char *)"memory");
 
-	// Read memory info from coreboot (ranges are merged automatically).
-	ranges_init(&mem);
-	ranges_init(&reserved);
+	memranges_init_empty(&map.mem, NULL, 0);
+	memranges_init_empty(&map.reserved, NULL, 0);
 
-#define MEMORY_ALIGNMENT (1 << 20)
-	for (int i = 0; i < lib_sysinfo.n_memranges; i++) {
-		struct memrange *range = &lib_sysinfo.memrange[i];
-		uint64_t start = range->base;
-		uint64_t end = range->base + range->size;
+	bootmem_walk_os_mem(walk_memory_table, &map);
 
-		/*
-		 * Kernel likes its availabe memory areas at least 1MB
-		 * aligned, let's trim the regions such that unaligned padding
-		 * is added to reserved memory.
-		 */
-		if (range->type == CB_MEM_RAM) {
-			uint64_t new_start = ALIGN_UP(start, MEMORY_ALIGNMENT);
-			uint64_t new_end = ALIGN_DOWN(end, MEMORY_ALIGNMENT);
-
-			if (new_start != start)
-				ranges_add(&reserved, start, new_start);
-
-			if (new_start != new_end)
-				ranges_add(&mem, new_start, new_end);
-
-			if (new_end != end)
-				ranges_add(&reserved, new_end, end);
-		} else {
-			ranges_add(&reserved, start, end);
-		}
+	/* CBMEM regions are both carved out and explicitly reserved. */
+	memranges_each_entry(r, &map.reserved) {
+		update_reserve_map(range_entry_base(r), range_entry_end(r),
+				   tree);
 	}
 
-	// CBMEM regions are both carved out and explicitly reserved.
-	ranges_for_each(&reserved, &update_reserve_map, tree);
+	/*
+	 * Count the amount of 'reg' entries we need (account for size limits).
+	 */
+	size_t count = 0;
+	memranges_each_entry(r, &map.mem) {
+		uint64_t size = range_entry_size(r);
+		uint64_t max_size = max_range(size_cells);
+		count += DIV_ROUND_UP(size, max_size);
+	}
 
-	// Count the amount of 'reg' entries we need (account for size limits).
-	unsigned count = 0;
-	EntryParams count_params = { addr_cells, size_cells, &count };
-	ranges_for_each(&mem, &count_entries, &count_params);
-
-	// Allocate the right amount of space and fill up the entries.
+	/* Allocate the right amount of space and fill up the entries. */
 	size_t length = count * (addr_cells + size_cells) * sizeof(u32);
-	void *data = xmalloc(length);
-	EntryParams add_params = { addr_cells, size_cells, data };
-	ranges_for_each(&mem, &update_mem_property, &add_params);
+
+	void *data = xzalloc(length);
+
+	struct entry_params add_params = { addr_cells, size_cells, data };
+	memranges_each_entry(r, &map.mem) {
+		update_mem_property(range_entry_base(r), range_entry_end(r),
+				    &add_params);
+	}
 	assert(add_params.data - data == length);
 
-	// Assemble the final property and add it to the device tree.
+	/* Assemble the final property and add it to the device tree. */
 	dt_add_bin_prop(node, "reg", data, length);
+
+	memranges_teardown(&map.mem);
+	memranges_teardown(&map.reserved);
 }
 
-FitImageNode *fit_load(void *fit, char *cmd_line, DeviceTree **dt)
+/*
+ * Finds a compat string and updates the compat position and rank.
+ * @param fdt_blob Pointer to FDT
+ * @param config The current config node to operate on
+ */
+static void fit_update_compat(void *fdt_blob, struct fit_config_node *config)
 {
-	FdtHeader *header = (FdtHeader *)fit;
-	FitImageNode *image;
-	FitConfigNode *config;
-	int i;
+	struct compat_string_entry *compat_node;
+	struct fdt_header *fdt_header = (struct fdt_header *)fdt_blob;
+	uint32_t fdt_offset = be32_to_cpu(fdt_header->structure_offset);
+	size_t i = 0;
 
-	printf("Loading FIT.\n");
+	if (!fdt_find_compat(fdt_blob, fdt_offset, &config->compat)) {
+		list_for_each(compat_node, compat_strings, list_node) {
+			int pos = fit_check_compat(&config->compat,
+						   compat_node->compat_string);
+			if (pos >= 0) {
+				config->compat_pos = pos;
+				config->compat_rank = i;
+				config->compat_string =
+					compat_node->compat_string;
+				break;
+			}
+			i++;
+		}
+	}
+}
 
-	if (betohl(header->magic) != FdtMagic) {
-		printf("Bad FIT header magic value 0x%08x.\n",
-			betohl(header->magic));
+struct fit_config_node *fit_load(void *fit)
+{
+	struct fdt_header *header = (struct fdt_header *)fit;
+	struct fit_image_node *image;
+	struct fit_config_node *config;
+	struct compat_string_entry *compat_node;
+
+	printk(BIOS_DEBUG, "FIT: Loading FIT from %p\n", fit);
+
+	if (be32toh(header->magic) != FDT_HEADER_MAGIC) {
+		printk(BIOS_ERR, "FIT: Bad header magic value 0x%08x.\n",
+		       be32toh(header->magic));
 		return NULL;
 	}
-
-	DeviceTree *tree = fdt_unflatten(fit);
+	struct device_tree *tree = fdt_unflatten(fit);
 
 	const char *default_config_name = NULL;
-	FitConfigNode *default_config = NULL;
-	FitConfigNode *compat_config = NULL;
+	struct fit_config_node *default_config = NULL;
+	struct fit_config_node *compat_config = NULL;
 
 	fit_unpack(tree, &default_config_name);
 
-	// List the images we found.
+	/* List the images we found. */
 	list_for_each(image, image_nodes, list_node)
-		printf("Image %s has %d bytes.\n", image->name, image->size);
+		printk(BIOS_DEBUG, "FIT: Image %s has %d bytes.\n", image->name,
+		       image->size);
 
-	fit_add_default_compats();
-	printf("Compat preference:");
-	for (i = 0; i < num_fit_kernel_compat; i++)
-		printf(" %s", fit_kernel_compat[i]);
-	printf("\n");
-	// Process and list the configs.
+	fit_add_default_compat_strings();
+
+	printk(BIOS_DEBUG, "FIT: Compat preference "
+	       "(lowest to highest priority) :");
+
+	list_for_each(compat_node, compat_strings, list_node) {
+		printk(BIOS_DEBUG, " %s", compat_node->compat_string);
+	}
+	printk(BIOS_DEBUG, "\n");
+	/* Process and list the configs. */
 	list_for_each(config, config_nodes, list_node) {
 		if (config->kernel)
 			config->kernel_node = find_image(config->kernel);
@@ -376,112 +457,82 @@
 		if (config->ramdisk)
 			config->ramdisk_node = find_image(config->ramdisk);
 
+		if (config->ramdisk_node &&
+		    config->ramdisk_node->compression < 0) {
+			printk(BIOS_WARNING, "WARN: Ramdisk is compressed with "
+			       "an unsupported algorithm, discarding config %s."
+			       "\n", config->name);
+			list_remove(&config->list_node);
+			continue;
+		}
+
 		if (!config->kernel_node ||
-				(config->fdt && !config->fdt_node)) {
-			printf("Missing image, discarding config %s.\n",
-				config->name);
+		    (config->fdt && !config->fdt_node)) {
+			printk(BIOS_DEBUG, "FIT: Missing image, discarding "
+			       "config %s.\n", config->name);
 			list_remove(&config->list_node);
 			continue;
 		}
 
 		if (config->fdt_node) {
-			if (config->fdt_node->compression != CompressionNone) {
-				printf("FDT compression not yet supported, "
-				       "skipping config %s.\n", config->name);
+			if (config->fdt_node->compression !=
+			    CBFS_COMPRESS_NONE) {
+				printk(BIOS_DEBUG,
+				       "FIT: FDT compression not yet supported,"
+				       " skipping config %s.\n", config->name);
 				list_remove(&config->list_node);
 				continue;
 			}
 
-			void *fdt_blob = config->fdt_node->data;
-			FdtHeader *fdt_header = (FdtHeader *)fdt_blob;
-			uint32_t fdt_offset =
-				betohl(fdt_header->structure_offset);
 			config->compat_pos = -1;
 			config->compat_rank = -1;
-			if (!fdt_find_compat(fdt_blob, fdt_offset,
-					    &config->compat)) {
-				for (i = 0; i < num_fit_kernel_compat; i++) {
-					int pos = fit_check_compat(
-							&config->compat,
-							fit_kernel_compat[i]);
-					if (pos >= 0) {
-						config->compat_pos = pos;
-						config->compat_rank = i;
-						break;
-					}
-				}
-			}
-		}
 
-		printf("Config %s", config->name);
+			fit_update_compat(config->fdt_node->data, config);
+		}
+		printk(BIOS_DEBUG, "FIT: config %s", config->name);
 		if (default_config_name &&
-				!strcmp(config->name, default_config_name)) {
-			printf(" (default)");
+		    !strcmp(config->name, default_config_name)) {
+			printk(BIOS_DEBUG, " (default)");
 			default_config = config;
 		}
-		printf(", kernel %s", config->kernel);
 		if (config->fdt)
-			printf(", fdt %s", config->fdt);
+			printk(BIOS_DEBUG, ", fdt %s", config->fdt);
 		if (config->ramdisk)
-			printf(", ramdisk %s", config->ramdisk);
+			printk(BIOS_DEBUG, ", ramdisk %s", config->ramdisk);
 		if (config->compat.name) {
-			printf(", compat");
+			printk(BIOS_DEBUG, ", compat");
 			int bytes = config->compat.size;
 			const char *compat_str = config->compat.data;
 			for (int pos = 0; bytes && compat_str[0]; pos++) {
-				printf(" %s", compat_str);
+				printk(BIOS_DEBUG, " %s", compat_str);
 				if (pos == config->compat_pos)
-					printf(" (match)");
+					printk(BIOS_DEBUG, " (match)");
 				int len = strlen(compat_str) + 1;
 				compat_str += len;
 				bytes -= len;
 			}
 
 			if (config->compat_rank >= 0 && (!compat_config ||
-			    config->compat_rank < compat_config->compat_rank))
+			    config->compat_rank > compat_config->compat_rank))
 				compat_config = config;
 		}
-		printf("\n");
+		printk(BIOS_DEBUG, "\n");
 	}
 
-	FitConfigNode *to_boot = NULL;
+	struct fit_config_node *to_boot = NULL;
 	if (compat_config) {
 		to_boot = compat_config;
-		printf("Choosing best match %s for compat %s.\n",
-		       to_boot->name, fit_kernel_compat[to_boot->compat_rank]);
+		printk(BIOS_INFO, "FIT: Choosing best match %s for compat "
+		       "%s.\n", to_boot->name, to_boot->compat_string);
 	} else if (default_config) {
 		to_boot = default_config;
-		printf("No match, choosing default %s.\n", to_boot->name);
+		printk(BIOS_INFO, "FIT: No match, choosing default %s.\n",
+		       to_boot->name);
 	} else {
-		printf("No compatible or default configs. Giving up.\n");
-		// We're leaking memory here, but at this point we're beyond
-		// saving anyway.
+		printk(BIOS_ERR, "FIT: No compatible or default configs. "
+		       "Giving up.\n");
 		return NULL;
 	}
 
-	if (to_boot->fdt_node) {
-		*dt = fdt_unflatten(to_boot->fdt_node->data);
-		if (!*dt) {
-			printf("Failed to unflatten the kernel's fdt.\n");
-			return NULL;
-		}
-
-		/* Update only if non-NULL cmd line */
-		if (cmd_line)
-			update_chosen(*dt, cmd_line);
-
-		update_memory(*dt);
-
-		if (to_boot->ramdisk_node) {
-			if (to_boot->ramdisk_node->compression
-					!= CompressionNone) {
-				printf("Ramdisk compression not supported.\n");
-				return NULL;
-			}
-			fit_add_ramdisk(*dt, to_boot->ramdisk_node->data,
-					to_boot->ramdisk_node->size);
-		}
-	}
-
-	return to_boot->kernel_node;
+	return to_boot;
 }
diff --git a/src/lib/fit_payload.c b/src/lib/fit_payload.c
new file mode 100644
index 0000000..ada22e8
--- /dev/null
+++ b/src/lib/fit_payload.c
@@ -0,0 +1,181 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003-2004 Eric Biederman
+ * Copyright (C) 2005-2010 coresystems GmbH
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <bootmem.h>
+#include <cbmem.h>
+#include <device/resource.h>
+#include <stdlib.h>
+#include <commonlib/region.h>
+#include <fit.h>
+#include <program_loading.h>
+#include <timestamp.h>
+#include <cbfs.h>
+#include <string.h>
+#include <commonlib/compression.h>
+#include <lib.h>
+#include <fit_payload.h>
+
+/* Pack the device_tree and place it at given position. */
+static void pack_fdt(struct region *fdt, struct device_tree *dt)
+{
+	printk(BIOS_INFO, "FIT: Flattening FDT to %p\n",
+	       (void *)fdt->offset);
+
+	dt_flatten(dt, (void *)fdt->offset);
+	prog_segment_loaded(fdt->offset, fdt->size, 0);
+}
+
+/**
+ * Extract a node to given regions.
+ * Returns true on error, false on success.
+ */
+static bool extract(struct region *region, struct fit_image_node *node)
+{
+	void *dst = (void *)region->offset;
+	const char *comp_name;
+	size_t true_size = 0;
+
+	switch (node->compression) {
+	case CBFS_COMPRESS_NONE:
+		comp_name = "Relocating uncompressed";
+		break;
+	case CBFS_COMPRESS_LZMA:
+		comp_name = "Decompressing LZMA";
+		break;
+	case CBFS_COMPRESS_LZ4:
+		comp_name = "Decompressing LZ4";
+		break;
+	default:
+		printk(BIOS_ERR, "ERROR: Unsupported compression\n");
+		return true;
+	}
+
+	printk(BIOS_INFO, "FIT: %s %s to %p\n", comp_name, node->name, dst);
+
+	switch (node->compression) {
+	case CBFS_COMPRESS_NONE:
+		memcpy(dst, node->data, node->size);
+		true_size = node->size;
+		break;
+	case CBFS_COMPRESS_LZMA:
+		timestamp_add_now(TS_START_ULZMA);
+		true_size = ulzman(node->data, node->size, dst, region->size);
+		timestamp_add_now(TS_END_ULZMA);
+		break;
+	case CBFS_COMPRESS_LZ4:
+		timestamp_add_now(TS_START_ULZ4F);
+		true_size = ulz4fn(node->data, node->size, dst, region->size);
+		timestamp_add_now(TS_END_ULZ4F);
+		break;
+	default:
+		return true;
+	}
+
+	if (!true_size) {
+		printk(BIOS_ERR, "ERROR: %s node failed!\n", comp_name);
+		return true;
+	}
+
+	prog_segment_loaded(region->offset, true_size, 0);
+
+	return false;
+}
+
+/*
+ * Parse the uImage FIT, choose a configuration and extract images.
+ */
+void fit_payload(struct prog *payload)
+{
+	struct device_tree *dt = NULL;
+	struct region kernel = {0}, fdt = {0}, initrd = {0};
+	void *data;
+
+	data = rdev_mmap_full(prog_rdev(payload));
+
+	if (data == NULL)
+		return;
+
+	printk(BIOS_INFO, "FIT: Examine payload %s\n", payload->name);
+
+	struct fit_config_node *config = fit_load(data);
+
+	if (!config || !config->kernel_node) {
+		printk(BIOS_ERR, "ERROR: Could not load FIT\n");
+		rdev_munmap(prog_rdev(payload), data);
+		return;
+	}
+
+	if (config->fdt_node) {
+		dt = fdt_unflatten(config->fdt_node->data);
+		if (!dt) {
+			printk(BIOS_ERR,
+			       "ERROR: Failed to unflatten the FDT.\n");
+			rdev_munmap(prog_rdev(payload), data);
+			return;
+		}
+
+		dt_apply_fixups(dt);
+
+		/* Update device_tree */
+#if defined(CONFIG_LINUX_COMMAND_LINE)
+		fit_update_chosen(dt, (char *)CONFIG_LINUX_COMMAND_LINE);
+#endif
+		fit_update_memory(dt);
+	}
+
+	/* Collect infos for fit_payload_arch */
+	kernel.size = config->kernel_node->size;
+	fdt.size = dt ? dt_flat_size(dt) : 0;
+	initrd.size = config->ramdisk_node ? config->ramdisk_node->size : 0;
+
+	/* Invoke arch specific payload placement and fixups */
+	if (!fit_payload_arch(payload, config, &kernel, &fdt, &initrd)) {
+		printk(BIOS_ERR, "ERROR: Failed to find free memory region\n");
+		bootmem_dump_ranges();
+		rdev_munmap(prog_rdev(payload), data);
+		return;
+	}
+
+	/* Load the images to given position */
+	if (config->fdt_node) {
+		/* Update device_tree */
+		if (config->ramdisk_node)
+			fit_add_ramdisk(dt, (void *)initrd.offset, initrd.size);
+
+		pack_fdt(&fdt, dt);
+	}
+
+	if (config->ramdisk_node &&
+	    extract(&initrd, config->ramdisk_node)) {
+		printk(BIOS_ERR, "ERROR: Failed to extract initrd\n");
+		rdev_munmap(prog_rdev(payload), data);
+		return;
+	}
+
+	timestamp_add_now(TS_KERNEL_DECOMPRESSION);
+
+	if (extract(&kernel, config->kernel_node)) {
+		printk(BIOS_ERR, "ERROR: Failed to extract kernel\n");
+		rdev_munmap(prog_rdev(payload), data);
+		return;
+	}
+
+	timestamp_add_now(TS_START_KERNEL);
+
+	rdev_munmap(prog_rdev(payload), data);
+}
diff --git a/src/lib/prog_loaders.c b/src/lib/prog_loaders.c
index 6811eb0..02b6590 100644
--- a/src/lib/prog_loaders.c
+++ b/src/lib/prog_loaders.c
@@ -31,6 +31,7 @@
 #include <symbols.h>
 #include <timestamp.h>
 #include <cbfs.h>
+#include <fit_payload.h>
 
 /* Only can represent up to 1 byte less than size_t. */
 const struct mem_region_device addrspace_32bit =
@@ -183,7 +184,19 @@
 
 	mirror_payload(payload);
 
-	selfload(payload, true);
+	switch (prog_cbfs_type(payload)) {
+	case CBFS_TYPE_SELF: /* Simple ELF */
+		selfload(payload, true);
+		break;
+	case CBFS_TYPE_FIT: /* Flattened image tree */
+		if (IS_ENABLED(CONFIG_PAYLOAD_FIT_SUPPORT)) {
+			fit_payload(payload);
+			break;
+		} /* else fall-through */
+	default:
+		die("Unsupported payload type.\n");
+		break;
+	}
 
 out:
 	if (prog_entry(payload) == NULL)

-- 
To view, visit https://review.coreboot.org/25019
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I0f27b92a5e074966f893399eb401eb97d784850d
Gerrit-Change-Number: 25019
Gerrit-PatchSet: 37
Gerrit-Owner: Patrick Rudolph <patrick.rudolph at 9elements.com>
Gerrit-Reviewer: David Hendricks <david.hendricks at gmail.com>
Gerrit-Reviewer: Julius Werner <jwerner at chromium.org>
Gerrit-Reviewer: Patrick Rudolph <patrick.rudolph at 9elements.com>
Gerrit-Reviewer: Paul Menzel <paulepanter at users.sourceforge.net>
Gerrit-Reviewer: Philipp Deppenwiese <zaolin.daisuki at gmail.com>
Gerrit-Reviewer: build bot (Jenkins) <no-reply at coreboot.org>
Gerrit-CC: Aaron Durbin <adurbin at chromium.org>
Gerrit-CC: Nico Huber <nico.h at gmx.de>
Gerrit-CC: Patrick Rudolph
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20180619/330d7b66/attachment.html>


More information about the coreboot-gerrit mailing list