<p>Philipp Deppenwiese <strong>merged</strong> this change.</p><p><a href="https://review.coreboot.org/25019">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  build bot (Jenkins): Verified
  Philipp Deppenwiese: Looks good to me, approved

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

<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I0f27b92a5e074966f893399eb401eb97d784850d </div>
<div style="display:none"> Gerrit-Change-Number: 25019 </div>
<div style="display:none"> Gerrit-PatchSet: 37 </div>
<div style="display:none"> Gerrit-Owner: Patrick Rudolph <patrick.rudolph@9elements.com> </div>
<div style="display:none"> Gerrit-Reviewer: David Hendricks <david.hendricks@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Julius Werner <jwerner@chromium.org> </div>
<div style="display:none"> Gerrit-Reviewer: Patrick Rudolph <patrick.rudolph@9elements.com> </div>
<div style="display:none"> Gerrit-Reviewer: Paul Menzel <paulepanter@users.sourceforge.net> </div>
<div style="display:none"> Gerrit-Reviewer: Philipp Deppenwiese <zaolin.daisuki@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: build bot (Jenkins) <no-reply@coreboot.org> </div>
<div style="display:none"> Gerrit-CC: Aaron Durbin <adurbin@chromium.org> </div>
<div style="display:none"> Gerrit-CC: Nico Huber <nico.h@gmx.de> </div>
<div style="display:none"> Gerrit-CC: Patrick Rudolph </div>