aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@dabbelt.com>2018-05-22 16:09:00 -0700
committerGitHub <noreply@github.com>2018-05-22 16:09:00 -0700
commit10bf403ba8887e217bb1619efb92049c47ab8c01 (patch)
tree343a134219be59ee0347343a5ea415707d711ab3
parent9ffedde3d747a9b6f559041cc69478df6d647135 (diff)
parent474ee5a81880dcf60789e7c2a3054b3afb34c3ca (diff)
downloadriscv-pk-10bf403ba8887e217bb1619efb92049c47ab8c01.zip
riscv-pk-10bf403ba8887e217bb1619efb92049c47ab8c01.tar.gz
riscv-pk-10bf403ba8887e217bb1619efb92049c47ab8c01.tar.bz2
Merge pull request #107 from michaeljclark/fdt-firmware-only
RISC-V: Support separate firmware and kernel payload
-rw-r--r--bbl/bbl.ac9
-rw-r--r--bbl/bbl.c16
-rw-r--r--bbl/payload.S8
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure15
-rw-r--r--dummy_payload/dummy_entry.S10
-rw-r--r--machine/fdt.c57
-rw-r--r--machine/fdt.h5
-rw-r--r--machine/minit.c3
9 files changed, 115 insertions, 11 deletions
diff --git a/bbl/bbl.ac b/bbl/bbl.ac
index 80d3b06..55ff50b 100644
--- a/bbl/bbl.ac
+++ b/bbl/bbl.ac
@@ -4,8 +4,13 @@ AS_IF([test "x$enable_logo" == "xyes"], [
])
AC_ARG_WITH([payload], AS_HELP_STRING([--with-payload], [Set ELF payload for bbl]),
- [AC_SUBST([BBL_PAYLOAD], $with_payload, [Kernel payload for bbl])],
- [AC_SUBST([BBL_PAYLOAD], [dummy_payload], [Kernel payload for bbl])])
+ [
+ AC_SUBST([BBL_PAYLOAD], $with_payload, [Kernel payload for bbl])
+ AC_DEFINE(RELAXED_ALIGNMENT,[0],[Use relaxed payload alignment])
+ ], [
+ AC_SUBST([BBL_PAYLOAD], [dummy_payload], [Kernel payload for bbl])
+ AC_DEFINE(RELAXED_ALIGNMENT,[1],[Use relaxed payload alignment])
+ ])
AC_ARG_WITH([logo], AS_HELP_STRING([--with-logo], [Specify a better logo]),
[AC_SUBST([BBL_LOGO_FILE], $with_logo, [Logo for bbl])],
diff --git a/bbl/bbl.c b/bbl/bbl.c
index 1b96a9d..93746ff 100644
--- a/bbl/bbl.c
+++ b/bbl/bbl.c
@@ -7,13 +7,21 @@
#include "fdt.h"
#include <string.h>
+extern char _payload_start, _payload_end; /* internal payload */
static const void* entry_point;
long disabled_hart_mask;
static uintptr_t dtb_output()
{
- extern char _payload_end;
- uintptr_t end = (uintptr_t) &_payload_end;
+ /*
+ * Place DTB after the payload, either the internal payload or a
+ * preloaded external payload specified in device-tree, if present.
+ *
+ * Note: linux kernel calls __va(dtb) to get the device-tree virtual
+ * address. The kernel's virtual mapping begins at its load address,
+ * thus mandating device-tree is in physical memory after the kernel.
+ */
+ uintptr_t end = kernel_end ? (uintptr_t)kernel_end : (uintptr_t)&_payload_end;
return (end + MEGAPAGE_SIZE - 1) / MEGAPAGE_SIZE * MEGAPAGE_SIZE;
}
@@ -53,7 +61,6 @@ void boot_other_hart(uintptr_t unused __attribute__((unused)))
void boot_loader(uintptr_t dtb)
{
- extern char _payload_start;
filter_dtb(dtb);
#ifdef PK_ENABLE_LOGO
print_logo();
@@ -62,6 +69,7 @@ void boot_loader(uintptr_t dtb)
fdt_print(dtb_output());
#endif
mb();
- entry_point = &_payload_start;
+ /* Use optional FDT preloaded external payload if present */
+ entry_point = kernel_start ? kernel_start : &_payload_start;
boot_other_hart(0);
}
diff --git a/bbl/payload.S b/bbl/payload.S
index 6a175aa..b6797aa 100644
--- a/bbl/payload.S
+++ b/bbl/payload.S
@@ -1,7 +1,15 @@
+#include "config.h"
#include "encoding.h"
.section ".payload","a",@progbits
+
+#if RELAXED_ALIGNMENT
+ /* align payload minimally */
+ .align 3
+#else
+ /* align payload to megapage */
.align RISCV_PGSHIFT + RISCV_PGLEVEL_BITS
+#endif
.globl _payload_start, _payload_end
_payload_start:
diff --git a/config.h.in b/config.h.in
index 4674a2e..a350c78 100644
--- a/config.h.in
+++ b/config.h.in
@@ -42,6 +42,9 @@
/* Define if the DTS is to be displayed */
#undef PK_PRINT_DEVICE_TREE
+/* Use relaxed payload alignment */
+#undef RELAXED_ALIGNMENT
+
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef SOFTFLOAT_ENABLED
diff --git a/configure b/configure
index 5af7cee..058eea1 100755
--- a/configure
+++ b/configure
@@ -4092,7 +4092,6 @@ case "${BUILD_32BIT}" in
CFLAGS="$default_CFLAGS"
LDFLAGS=
install_subdir=$host_alias
-
;;
esac
@@ -4251,10 +4250,20 @@ fi
# Check whether --with-payload was given.
if test "${with_payload+set}" = set; then :
- withval=$with_payload; BBL_PAYLOAD=$with_payload
+ withval=$with_payload;
+ BBL_PAYLOAD=$with_payload
+
+
+$as_echo "#define RELAXED_ALIGNMENT 0" >>confdefs.h
+
else
- BBL_PAYLOAD=dummy_payload
+
+ BBL_PAYLOAD=dummy_payload
+
+
+$as_echo "#define RELAXED_ALIGNMENT 1" >>confdefs.h
+
fi
diff --git a/dummy_payload/dummy_entry.S b/dummy_payload/dummy_entry.S
index 92d4652..2473d8c 100644
--- a/dummy_payload/dummy_entry.S
+++ b/dummy_payload/dummy_entry.S
@@ -18,5 +18,11 @@ _start:
.data
str:
- .asciz "This is bbl's dummy_payload. To boot a real kernel, reconfigure\n\
-bbl with the flag --with-payload=PATH, then rebuild bbl.\n"
+ .asciz "This is bbl's dummy_payload. To boot a real kernel, reconfigure bbl
+with the flag --with-payload=PATH, then rebuild bbl. Alternatively,
+bbl can be used in firmware-only mode by adding device-tree nodes
+for an external payload and use QEMU's -bios and -kernel options.\n
+ chosen {
+ riscv,kernel-start = <payload_start>;
+ riscv,kernel-end = <payload_end>;
+ };\n\n"
diff --git a/machine/fdt.c b/machine/fdt.c
index 061b19e..27f5462 100644
--- a/machine/fdt.c
+++ b/machine/fdt.c
@@ -548,6 +548,63 @@ void filter_compat(uintptr_t fdt, const char *compat)
fdt_scan(fdt, &cb);
}
+//////////////////////////////////////////// CHOSEN SCAN ////////////////////////////////////////
+
+struct chosen_scan {
+ const struct fdt_scan_node *chosen;
+ void* kernel_start;
+ void* kernel_end;
+};
+
+static void chosen_open(const struct fdt_scan_node *node, void *extra)
+{
+ struct chosen_scan *scan = (struct chosen_scan *)extra;
+ if (!strcmp(node->name, "chosen")) {
+ scan->chosen = node;
+ }
+}
+
+static int chosen_close(const struct fdt_scan_node *node, void *extra)
+{
+ struct chosen_scan *scan = (struct chosen_scan *)extra;
+ if (scan->chosen && scan->chosen == node) {
+ scan->chosen = NULL;
+ }
+ return 0;
+}
+
+static void chosen_prop(const struct fdt_scan_prop *prop, void *extra)
+{
+ struct chosen_scan *scan = (struct chosen_scan *)extra;
+ uint64_t val;
+ if (!scan->chosen) return;
+ if (!strcmp(prop->name, "riscv,kernel-start")) {
+ fdt_get_address(prop->node->parent, prop->value, &val);
+ scan->kernel_start = (void*)val;
+ } else if (!strcmp(prop->name, "riscv,kernel-end")) {
+ fdt_get_address(prop->node->parent, prop->value, &val);
+ scan->kernel_end = (void*)val;
+ }
+}
+
+void query_chosen(uintptr_t fdt)
+{
+ struct fdt_cb cb;
+ struct chosen_scan chosen;
+
+ memset(&cb, 0, sizeof(cb));
+ cb.open = chosen_open;
+ cb.close = chosen_close;
+ cb.prop = chosen_prop;
+
+ memset(&chosen, 0, sizeof(chosen));
+ cb.extra = &chosen;
+
+ fdt_scan(fdt, &cb);
+ kernel_start = chosen.kernel_start;
+ kernel_end = chosen.kernel_end;
+}
+
//////////////////////////////////////////// HART FILTER ////////////////////////////////////////
struct hart_filter {
diff --git a/machine/fdt.h b/machine/fdt.h
index d436778..6c8a6fe 100644
--- a/machine/fdt.h
+++ b/machine/fdt.h
@@ -59,6 +59,7 @@ void query_mem(uintptr_t fdt);
void query_harts(uintptr_t fdt);
void query_plic(uintptr_t fdt);
void query_clint(uintptr_t fdt);
+void query_chosen(uintptr_t fdt);
// Remove information from FDT
void filter_harts(uintptr_t fdt, long *disabled_hart_mask);
@@ -68,6 +69,10 @@ void filter_compat(uintptr_t fdt, const char *compat);
// The hartids of available harts
extern uint64_t hart_mask;
+// Optional FDT preloaded external payload
+extern void* kernel_start;
+extern void* kernel_end;
+
#ifdef PK_PRINT_DEVICE_TREE
// Prints the device tree to the console as a DTS
void fdt_print(uintptr_t fdt);
diff --git a/machine/minit.c b/machine/minit.c
index 32c6fd7..ceae6b7 100644
--- a/machine/minit.c
+++ b/machine/minit.c
@@ -16,6 +16,8 @@ uintptr_t mem_size;
volatile uint64_t* mtime;
volatile uint32_t* plic_priorities;
size_t plic_ndevs;
+void* kernel_start;
+void* kernel_end;
static void mstatus_init()
{
@@ -162,6 +164,7 @@ void init_first_hart(uintptr_t hartid, uintptr_t dtb)
query_harts(dtb);
query_clint(dtb);
query_plic(dtb);
+ query_chosen(dtb);
wake_harts();