[coreboot-gerrit] Change in ...coreboot[master]: [WIP] Enable FIT support on RISC-V

Jonathan Neuschäfer (Code Review) gerrit at coreboot.org
Tue Dec 18 15:22:52 CET 2018


Jonathan Neuschäfer has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30292


Change subject: [WIP] Enable FIT support on RISC-V
......................................................................

[WIP] Enable FIT support on RISC-V

WORK IN PROGRESS: This patch has to be cleaned up in a few ways, and it
doesn't make linux boot all the way.

Change-Id: I5ebc6cc2cc9e328f36d70fba13555386bb8c29d6
Signed-off-by: Jonathan Neuschäfer <j.neuschaefer at gmx.net>
---
M Documentation/lib/payloads/fit.md
M payloads/Kconfig
A riscv.its
A spike.dts
M src/arch/riscv/Makefile.inc
M src/arch/riscv/boot.c
A src/arch/riscv/fit_payload.c
M src/arch/riscv/virtual_memory.c
8 files changed, 324 insertions(+), 7 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/92/30292/1

diff --git a/Documentation/lib/payloads/fit.md b/Documentation/lib/payloads/fit.md
index 53be92e..a7e6890 100644
--- a/Documentation/lib/payloads/fit.md
+++ b/Documentation/lib/payloads/fit.md
@@ -6,6 +6,7 @@
 ## Supported architectures
 
 * aarch64
+* riscv
 
 ## Supported FIT sections
 
@@ -24,6 +25,7 @@
 ## Architecture specifics
 
 The FIT parser needs architecure support.
+
 ### aarch64
 The source code can be found in `src/arch/arm64/fit.c`.
 
@@ -31,6 +33,10 @@
 format and it needs a devicetree (a section named 'fdt') to boot.
 The kernel will be placed close to "*DRAMSTART*".
 
+### RISC-V
+ASDFASDF
+
+
 ### Other
 Other architectures aren't supported.
 
diff --git a/payloads/Kconfig b/payloads/Kconfig
index c7a7ba6..0c5ce8f 100644
--- a/payloads/Kconfig
+++ b/payloads/Kconfig
@@ -30,7 +30,7 @@
 
 config PAYLOAD_FIT
 	bool "A FIT payload"
-	depends on ARCH_ARM64
+	depends on ARCH_ARM64 || ARCH_RISCV
 	select PAYLOAD_FIT_SUPPORT
 	help
 	  Select this option if you have a payload image (a FIT file) which
diff --git a/riscv.its b/riscv.its
new file mode 100644
index 0000000..453de1a
--- /dev/null
+++ b/riscv.its
@@ -0,0 +1,59 @@
+/* TODO: move to a better place! */
+
+/dts-v1/;
+
+/ {
+	description = "Simple image with single Linux kernel and FDT blob";
+	#address-cells = <1>;
+
+	images {
+		kernel {
+			description = "Vanilla Linux kernel";
+			data = /incbin/("Image.riscv.lzma");
+			type = "kernel";
+			arch = "riscv";
+			os = "linux";
+			compression = "lzma";
+			load = <0x80000000>;
+			entry = <0x80000000>;
+			hash-1 {
+				algo = "crc32";
+			};
+		};
+		fdt-1 {
+			description = "Flattened Device Tree blob";
+			data = /incbin/("spike.dtb");
+			type = "flat_dt";
+			arch = "arm64";
+			compression = "none";
+			hash-1 {
+				algo = "crc32";
+			};
+		};
+		/*
+		ramdisk-1 {
+			description = "Compressed Initramfs";
+			data = /incbin/("initramfs.cpio.xz");
+			type = "ramdisk";
+			arch = "arm64";
+			os = "linux";
+			compression = "none";
+			load = <00000000>;
+			entry = <00000000>;
+			hash-1 {
+				algo = "sha1";
+			};
+		};
+		*/
+	};
+
+	configurations {
+		default = "conf-1";
+		conf-1 {
+			description = "Boot Linux kernel with FDT blob";
+			kernel = "kernel";
+			fdt = "fdt-1";
+			//ramdisk = "ramdisk-1";
+		};
+	};
+};
diff --git a/spike.dts b/spike.dts
new file mode 100644
index 0000000..f1827d3
--- /dev/null
+++ b/spike.dts
@@ -0,0 +1,59 @@
+/dts-v1/;
+// magic:		0xd00dfeed
+// totalsize:		0x442 (1090)
+// off_dt_struct:	0x38
+// off_dt_strings:	0x370
+// off_mem_rsvmap:	0x28
+// version:		17
+// last_comp_version:	16
+// boot_cpuid_phys:	0x0
+// size_dt_strings:	0xd2
+// size_dt_struct:	0x338
+
+/ {
+    #address-cells = <0x00000002>;
+    #size-cells = <0x00000002>;
+    compatible = "ucbbar,spike-bare-dev";
+    model = "ucbbar,spike-bare";
+    cpus {
+        #address-cells = <0x00000001>;
+        #size-cells = <0x00000000>;
+        timebase-frequency = <10000000>;
+        cpu at 0 {
+            device_type = "cpu";
+            reg = <0x00000000>;
+            status = "okay";
+            compatible = "riscv";
+            riscv,isa = "rv64imafdc";
+            mmu-type = "riscv,sv48";
+            clock-frequency = <1000000000>;
+            interrupt-controller {
+                #interrupt-cells = <0x00000001>;
+                interrupt-controller;
+                compatible = "riscv,cpu-intc";
+                linux,phandle = <0x00000001>;
+                phandle = <0x00000001>;
+            };
+        };
+    };
+    memory at 80000000 {
+        device_type = "memory";
+        reg = <0x00000000 0x80000000 0x00000000 0x40000000>;
+    };
+    soc {
+        #address-cells = <0x00000002>;
+        #size-cells = <0x00000002>;
+        compatible = "ucbbar,spike-bare-soc", "simple-bus";
+        ranges;
+        clint at 2000000 {
+            compatible = "riscv,clint0";
+            interrupts-extended = <0x00000001 0x00000003 0x00000001 0x00000007>;
+            reg = <0x00000000 0x02000000 0x00000000 0x000c0000>;
+        };
+        uart at 2100000 {
+            compatible = "serial";
+            reg = <0x00000000 0x02100000 0x00000000 0x00000008>;
+            reg-shift = <0x00000000>;
+        };
+    };
+};
diff --git a/src/arch/riscv/Makefile.inc b/src/arch/riscv/Makefile.inc
index aee4b3b..36ea047 100644
--- a/src/arch/riscv/Makefile.inc
+++ b/src/arch/riscv/Makefile.inc
@@ -128,6 +128,7 @@
 ramstage-y += tables.c
 ramstage-y += payload.S
 ramstage-y += pmp.c
+ramstage-y += fit_payload.c
 ramstage-y += \
 	$(top)/src/lib/memchr.c \
 	$(top)/src/lib/memcmp.c \
diff --git a/src/arch/riscv/boot.c b/src/arch/riscv/boot.c
index 04fba07..69fb713 100644
--- a/src/arch/riscv/boot.c
+++ b/src/arch/riscv/boot.c
@@ -35,12 +35,18 @@
 	void riscvpayload(const void *fdt, void *payload);
 
 	if (ENV_RAMSTAGE && prog_type(prog) == PROG_PAYLOAD) {
-		/*
-		 * FIXME: This is wrong and will crash. Linux can't (in early
-		 * boot) access memory that's before its own loading address.
-		 * We need to copy the FDT to a place where Linux can access it.
-		 */
-		const void *fdt = rom_fdt;
+		const void *arg = prog_entry_arg(prog);
+		const void *fdt;
+
+		if (arg)
+			fdt = arg;
+		else
+			/*
+			 * FIXME: This is wrong and will crash. Linux can't (in early
+			 * boot) access memory that's before its own loading address.
+			 * We need to copy the FDT to a place where Linux can access it.
+			 */
+			fdt = rom_fdt;
 
 		printk(BIOS_SPEW, "FDT is at %p\n", fdt);
 		printk(BIOS_SPEW, "OK, let's go\n");
diff --git a/src/arch/riscv/fit_payload.c b/src/arch/riscv/fit_payload.c
new file mode 100644
index 0000000..920c922
--- /dev/null
+++ b/src/arch/riscv/fit_payload.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2013 Google Inc.
+ * Copyright 2018 Facebook, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <bootmem.h>
+#include <stdlib.h>
+#include <program_loading.h>
+#include <string.h>
+#include <commonlib/compression.h>
+#include <commonlib/cbfs_serialized.h>
+#include <lib.h>
+#include <fit.h>
+#include <endian.h>
+
+#define MAX_KERNEL_SIZE (64*MiB)
+
+static size_t get_kernel_size(const struct fit_image_node *node)
+{
+	/*
+	 * Since we don't have a way to determine the uncompressed size of the
+	 * kernel, we have to keep as much memory as possible free for use by
+	 * the kernel immediately after the end of the kernel image. The amount
+	 * of space required will vary depending on selected features, and is
+	 * effectively unbound.
+	 */
+
+	printk(BIOS_INFO,
+	       "FIT: Leaving additional %u MiB of free space after kernel.\n",
+	       MAX_KERNEL_SIZE >> 20);
+
+	return node->size + MAX_KERNEL_SIZE;
+}
+
+static bool fit_place_kernel(const struct range_entry *r, void *arg)
+{
+	struct region *region = arg;
+	resource_t start;
+
+	if (range_entry_tag(r) != BM_MEM_RAM)
+		return true;
+
+	/*
+	 * The Image must be placed text_offset bytes from a 2MB aligned base
+	 * address anywhere in usable system RAM and called there. The region
+	 * between the 2 MB aligned base address and the start of the image has
+	 * no special significance to the kernel, and may be used for other
+	 * purposes.
+	 *
+	 * If the reserved memory (BL31 for example) is smaller than text_offset
+	 * we can use the 2 MiB base address, otherwise use the next 2 MiB page.
+	 * It's not mandatory, but wastes less memory below the kernel.
+	 */
+	start = ALIGN_DOWN(range_entry_base(r), 2 * MiB);
+
+	if (start < range_entry_base(r))
+		start += 2 * MiB;
+	/*
+	 * At least image_size bytes from the start of the image must be free
+	 * for use by the kernel.
+	 */
+	if (start + region->size < range_entry_end(r)) {
+		region->offset = (size_t)start;
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * Place the region in free memory range.
+ *
+ * The caller has to set region->offset to the minimum allowed address.
+ * The region->offset is usually 0 on kernel >v4.6 and kernel_base + kernel_size
+ * on kernel <v4.6.
+ */
+static bool fit_place_mem(const struct range_entry *r, void *arg)
+{
+	struct region *region = arg;
+	resource_t start;
+
+	if (range_entry_tag(r) != BM_MEM_RAM)
+		return true;
+
+	/* Linux 4.15 doesn't like 4KiB alignment. Align to 1 MiB for now. */
+	start = ALIGN_UP(MAX(region->offset, range_entry_base(r)), 1 * MiB);
+
+	if (start + region->size < range_entry_end(r)) {
+		region->offset = (size_t)start;
+		return false;
+	}
+
+	return true;
+}
+
+bool fit_payload_arch(struct prog *payload, struct fit_config_node *config,
+		      struct region *kernel,
+		      struct region *fdt,
+		      struct region *initrd)
+{
+	bool place_anywhere;
+	void *arg = NULL;
+
+	if (!config->fdt || !fdt) {
+		printk(BIOS_CRIT, "CRIT: Providing a valid FDT is mandatory to "
+		       "boot a RISC-V kernel!\n");
+		return false;
+		/* TODO: Fall back to the ROM FDT? */
+	}
+
+	/* Update kernel size from image header, if possible */
+	kernel->size = get_kernel_size(config->kernel_node);
+	printk(BIOS_DEBUG, "FIT: Using kernel size of 0x%zx bytes\n",
+	       kernel->size);
+
+	/*
+	 * The code assumes that bootmem_walk provides a sorted list of memory
+	 * regions, starting from the lowest address.
+	 * The order of the calls here doesn't matter, as the placement is
+	 * enforced in the called functions.
+	 * For details check code on top.
+	 */
+
+	if (!bootmem_walk(fit_place_kernel, kernel))
+		return false;
+
+	/* Mark as reserved for future allocations. */
+	bootmem_add_range(kernel->offset, kernel->size, BM_MEM_PAYLOAD);
+
+	/*
+	 * NOTE: versions prior to v4.6 cannot make use of memory below the
+	 * physical offset of the Image so it is recommended that the Image be
+	 * placed as close as possible to the start of system RAM.
+	 *
+	 * For kernel <v4.6 the INITRD and FDT can't be placed below the kernel.
+	 * In that case set region offset to an address on top of kernel.
+	 */
+	place_anywhere = false;
+	printk(BIOS_DEBUG, "FIT: Placing FDT and INITRD %s\n",
+	       place_anywhere ? "anywhere" : "on top of kernel");
+
+	/* Place INITRD */
+	if (config->ramdisk) {
+		if (place_anywhere)
+			initrd->offset = 0;
+		else
+			initrd->offset = kernel->offset + kernel->size;
+
+		if (!bootmem_walk(fit_place_mem, initrd))
+			return false;
+		/* Mark as reserved for future allocations. */
+		bootmem_add_range(initrd->offset, initrd->size, BM_MEM_PAYLOAD);
+	}
+
+	/* Place FDT */
+	if (place_anywhere)
+		fdt->offset = 0;
+	else
+		fdt->offset = kernel->offset + kernel->size;
+
+	if (!bootmem_walk(fit_place_mem, fdt))
+		return false;
+	/* Mark as reserved for future allocations. */
+	bootmem_add_range(fdt->offset, fdt->size, BM_MEM_PAYLOAD);
+
+	/* Kernel expects FDT as argument */
+	arg = (void *)fdt->offset;
+
+	prog_set_entry(payload, (void *)kernel->offset, arg);
+
+	bootmem_dump_ranges();
+
+	return true;
+}
diff --git a/src/arch/riscv/virtual_memory.c b/src/arch/riscv/virtual_memory.c
index d9bae2a..ec0e89a 100644
--- a/src/arch/riscv/virtual_memory.c
+++ b/src/arch/riscv/virtual_memory.c
@@ -16,6 +16,7 @@
 
 #include <arch/cpu.h>
 #include <arch/encoding.h>
+#include <console/console.h>
 #include <stdint.h>
 #include <vm.h>
 

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

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I5ebc6cc2cc9e328f36d70fba13555386bb8c29d6
Gerrit-Change-Number: 30292
Gerrit-PatchSet: 1
Gerrit-Owner: Jonathan Neuschäfer <j.neuschaefer at gmx.net>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20181218/a90344e0/attachment-0001.html>


More information about the coreboot-gerrit mailing list